Skip to content

Commit

Permalink
Merge pull request #4516 from kwvanderlinde/feature/4448-beam-width
Browse files Browse the repository at this point in the history
Change BEAM lights and sights to accept width instead of arc
  • Loading branch information
cwisniew authored Dec 23, 2023
2 parents 6e2d801 + 374af69 commit 894a298
Show file tree
Hide file tree
Showing 14 changed files with 206 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -399,16 +399,25 @@ private static Light parseLightJson(JsonObject lightDef, LightSource.Type lightS
lightDef.has("shape")
? ShapeType.valueOf(lightDef.get("shape").getAsString())
: ShapeType.CIRCLE;
// Cones permit the fields arc and offset, but no other shape accepts them.
// Beams permit the field "width", cones permit the field "arc", and both permit "offset".
// But no other shape permits these fields.
if (shape != ShapeType.BEAM) {
if (lightDef.has("width")) {
throw new ParserException(I18N.getText("Width provided but the shape is not a beam"));
}
}
if (shape != ShapeType.CONE) {
if (lightDef.has("arc")) {
throw new ParserException(I18N.getText("Arc provided but the shape is not a cone"));
}
}
if (shape != ShapeType.CONE && shape != ShapeType.BEAM) {
if (lightDef.has("offset")) {
throw new ParserException(
I18N.getText("Facing offset provided but the shape is not a cone"));
}
if (lightDef.has("arc")) {
throw new ParserException(I18N.getText("Arc provided but the shape is not a cone"));
}
}
final var width = lightDef.has("width") ? lightDef.get("width").getAsDouble() : 0;
final var offset = lightDef.has("offset") ? lightDef.get("offset").getAsDouble() : 0;
final var arc = lightDef.has("arc") ? lightDef.get("arc").getAsDouble() : 0;

Expand Down Expand Up @@ -444,7 +453,7 @@ private static Light parseLightJson(JsonObject lightDef, LightSource.Type lightS
throw new ParserException(I18N.getText("Lumens must be non-zero."));
}

return new Light(shape, offset, range, arc, colorPaint, lumens, gmOnly, ownerOnly);
return new Light(shape, offset, range, width, arc, colorPaint, lumens, gmOnly, ownerOnly);
}

private static JsonObject lightSourceToJson(LightSource source) {
Expand All @@ -467,7 +476,7 @@ private static JsonObject lightToJson(LightSource source, Light light) {

if (light.getShape() == ShapeType.BEAM) {
lightDef.addProperty("offset", light.getFacingOffset());
lightDef.addProperty("arc", light.getArcAngle());
lightDef.addProperty("width", light.getWidth());
}

if (light.getShape() == ShapeType.CONE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import net.rptools.maptool.model.Light;
import net.rptools.maptool.model.LightSource;
import net.rptools.maptool.model.LookupTable;
import net.rptools.maptool.model.ShapeType;
import net.rptools.maptool.model.SightType;
import net.rptools.maptool.model.Token;
import net.rptools.maptool.model.Zone;
Expand Down Expand Up @@ -377,7 +378,7 @@ private JsonObject getCampaignInfo() throws ParserException {
JsonObject linfo = new JsonObject();
linfo.addProperty("name", ls.getName());
linfo.addProperty("max range", ls.getMaxRange());
linfo.addProperty("type", ls.getType().toString());
linfo.addProperty("type", ls.getType().name());
linfo.addProperty("scale", ls.isScaleWithToken());
// List<Light> lights = new ArrayList<Light>();
// for (Light light : ls.getLightList()) {
Expand Down Expand Up @@ -439,11 +440,28 @@ private JsonObject getCampaignInfo() throws ParserException {
JsonObject sightInfo = new JsonObject();
for (SightType sightType : c.getSightTypeMap().values()) {
JsonObject si = new JsonObject();
si.addProperty("arc", sightType.getArc());
si.addProperty("distance", sightType.getArc());
if (sightType.getShape() == ShapeType.BEAM) {
si.addProperty("width", sightType.getWidth());
si.addProperty("offset", sightType.getOffset());
}
if (sightType.getShape() == ShapeType.CONE) {
si.addProperty("arc", sightType.getArc());
si.addProperty("offset", sightType.getOffset());
}
si.addProperty("distance", sightType.getDistance());
si.addProperty("multiplier", sightType.getMultiplier());
si.addProperty("shape", sightType.getShape().toString());
si.addProperty("type", sightType.getOffset());
si.addProperty("shape", sightType.getShape().name());
si.addProperty("scale", sightType.isScaleWithToken());

JsonArray lightList = null;
if (sightType.getPersonalLightSource() != null) {
lightList = new JsonArray();
for (Light light : sightType.getPersonalLightSource().getLightList()) {
lightList.add(gson.toJsonTree(light));
}
}
si.add("personal lights", lightList);

sightInfo.add(sightType.getName(), si);
}
cinfo.add("sight", sightInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ private Illumination getIllumination(IlluminationKey illuminationKey) {
personalLights.addAll(calculateLitAreas(token, sight.getMultiplier()));
}

if (sight.hasPersonalLightSource()) {
if (sight.getPersonalLightSource() != null) {
// Calculate the personal light area here.
// Note that a personal light is affected by its own sight's magnification, but that's it.
// Since each token is only aware of its own personal light, of course we don't want a
Expand Down
60 changes: 26 additions & 34 deletions src/main/java/net/rptools/maptool/model/CampaignProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -297,44 +297,36 @@ public String getDefaultSightType() {
return defaultSightType;
}

// @formatter:off
private static final Object[][] starter =
new Object[][] {
// Sight Type Name Dist Mult Arc LtSrc Shape Scale
{"Normal", 0.0, 1.0, 0, null, null, false},
{"Lowlight", 0.0, 2.0, 0, null, null, false},
{"Grid Vision", 0.0, 1.0, 0, null, ShapeType.GRID, true},
{"Square Vision", 0.0, 1.0, 0, null, ShapeType.SQUARE, false},
{"Normal Vision - Short Range", 10.0, 1.0, 0, null, ShapeType.CIRCLE, true},
{"Conic Vision", 0.0, 1.0, 120, null, ShapeType.CONE, false},
{"Darkvision", 0.0, 1.0, 0, null, null, true},
};

// @formatter:on

private void initSightTypeMap() {
sightTypeMap.clear();
for (Object[] row : starter) {
SightType st =

final var types =
new SightType[] {
new SightType("Normal", 0, 1.0, ShapeType.CIRCLE, 0, 0, 0, false, null),
new SightType("Lowlight", 0, 2.0, ShapeType.CIRCLE, 0, 0, 0, false, null),
new SightType("Grid Vision", 0, 1, ShapeType.GRID, 0, 0, 0, true, null),
new SightType("Square Vision", 0, 1, ShapeType.SQUARE, 0, 0, 0, false, null),
new SightType(
(String) row[0],
(Double) row[2],
(LightSource) row[4],
(ShapeType) row[5],
(Integer) row[3],
(boolean) row[6]);
st.setDistance(((Double) row[1]).floatValue());
sightTypeMap.put((String) row[0], st);
}
SightType dv = sightTypeMap.get("Darkvision");
try {
dv.setPersonalLightSource(LightSource.getDefaultLightSources().get("Generic").get(5));
// sightTypeMap.put("Darkvision & Lowlight", new SightType("Darkvision", 2,
// LightSource.getDefaultLightSources().get("Generic").get(4)));
} catch (IOException e) {
MapTool.showError("CampaignProperties.error.noGenericLight", e);
"Normal Vision - Short Range", 10, 1.0, ShapeType.CIRCLE, 0, 0, 0, true, null),
new SightType("Conic Vision", 0, 1.0, ShapeType.CONE, 0, 120, 0, false, null),
new SightType(
"Darkvision",
0,
1.0,
ShapeType.CIRCLE,
0,
0,
0,
true,
LightSource.createPersonal(
true,
List.of(new Light(ShapeType.CIRCLE, 0, 60, 0, 0, null, 100, false, false)))),
};

for (SightType st : types) {
sightTypeMap.put(st.getName(), st);
}
defaultSightType = (String) starter[0][0];
defaultSightType = types[0].getName();
}

private void initTokenTypeMap() {
Expand Down
10 changes: 4 additions & 6 deletions src/main/java/net/rptools/maptool/model/Grid.java
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ public Area getShapedArea(
ShapeType shape,
Token token,
double range,
double width,
double arcAngle,
int offsetAngle,
boolean scaleWithToken) {
Expand Down Expand Up @@ -400,12 +401,9 @@ public Area getShapedArea(
if (token.getFacing() == null) {
token.setFacing(0);
}
Shape lineShape =
new Rectangle2D.Double(
0,
getSize() / -2d * Math.sin(Math.toRadians(arcAngle / 2d)),
visionRange,
getSize() * Math.sin(Math.toRadians(arcAngle / 2d)));
// Make at least 1 pixel on each side, so it's at least visible at 100% zoom.
var pixelWidth = Math.max(2, width * getSize() / zone.getUnitsPerCell());
Shape lineShape = new Rectangle2D.Double(0, -pixelWidth / 2, visionRange, pixelWidth);
Shape visibleShape = new GeneralPath(lineShape);

visibleArea =
Expand Down
9 changes: 3 additions & 6 deletions src/main/java/net/rptools/maptool/model/IsometricGrid.java
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ public Area getShapedArea(
ShapeType shape,
Token token,
double range,
double width,
double arcAngle,
int offsetAngle,
boolean scaleWithToken) {
Expand Down Expand Up @@ -349,12 +350,8 @@ public Area getShapedArea(
if (token.getFacing() == null) {
token.setFacing(0);
}
Shape visibleShape =
new Rectangle2D.Double(
0,
getSize() / -2d * Math.sin(Math.toRadians(arcAngle / 2.0)),
visionRange,
getSize() * Math.sin(Math.toRadians(arcAngle / 2.0)));
var pixelWidth = Math.max(2, width * getSize() / getZone().getUnitsPerCell());
Shape visibleShape = new Rectangle2D.Double(0, -pixelWidth / 2, visionRange, pixelWidth);

// new angle, corrected for isometric view
double theta = Math.toRadians(offsetAngle) + Math.toRadians(token.getFacing());
Expand Down
18 changes: 17 additions & 1 deletion src/main/java/net/rptools/maptool/model/Light.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public final class Light implements Serializable {
private final @Nonnull ShapeType shape;
private final double facingOffset;
private final double radius;
private final double width;
private final double arcAngle;
private final @Nullable DrawablePaint paint;
private final int lumens;
Expand All @@ -37,6 +38,7 @@ public Light(
@Nonnull ShapeType shape,
double facingOffset,
double radius,
double width,
double arcAngle,
@Nullable DrawablePaint paint,
int lumens,
Expand All @@ -45,6 +47,7 @@ public Light(
this.shape = shape;
this.facingOffset = facingOffset;
this.radius = radius;
this.width = width;
this.arcAngle = (arcAngle == 0) ? 90 : arcAngle;
this.paint = paint;
this.lumens = lumens;
Expand All @@ -61,6 +64,7 @@ public Light(
shape == null ? ShapeType.CIRCLE : shape,
facingOffset,
radius,
width,
arcAngle,
paint,
lumens == 0 ? 100 : lumens,
Expand All @@ -84,6 +88,10 @@ public double getRadius() {
return radius;
}

public double getWidth() {
return width;
}

public double getArcAngle() {
return arcAngle;
}
Expand All @@ -95,7 +103,13 @@ public double getArcAngle() {
public @Nonnull Area getArea(@Nonnull Token token, @Nonnull Zone zone, boolean scaleWithToken) {
return zone.getGrid()
.getShapedArea(
getShape(), token, getRadius(), getArcAngle(), (int) getFacingOffset(), scaleWithToken);
getShape(),
token,
getRadius(),
getWidth(),
getArcAngle(),
(int) getFacingOffset(),
scaleWithToken);
}

public boolean isGM() {
Expand All @@ -111,6 +125,7 @@ public boolean isOwnerOnly() {
ShapeType.valueOf(dto.getShape().name()),
dto.getFacingOffset(),
dto.getRadius(),
dto.getWidth(),
dto.getArcAngle(),
dto.hasPaint() ? DrawablePaint.fromDto(dto.getPaint()) : null,
dto.getLumens(),
Expand All @@ -125,6 +140,7 @@ public boolean isOwnerOnly() {
}
dto.setFacingOffset(facingOffset);
dto.setRadius(radius);
dto.setWidth(width);
dto.setArcAngle(arcAngle);
dto.setShape(ShapeTypeDto.valueOf(shape.name()));
dto.setIsGm(isGM);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/net/rptools/maptool/model/LightSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ public Object writeReplace() {
light.getShape(),
light.getFacingOffset(),
light.getRadius(),
light.getWidth(),
light.getArcAngle(),
light.getPaint(),
lumens == 0 ? 100 : lumens,
Expand Down
Loading

0 comments on commit 894a298

Please sign in to comment.