diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 439f15ddd2..c1d591f83f 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -2303,7 +2303,7 @@ lst.setprop = Sets a property of a unit or building. lst.effect = Create a particle effect. lst.sync = Sync a variable across the network.\nLimited to 20 times a second per variable. lst.makemarker = Create a new logic marker in the world.\nAn ID to identify this marker must be provided.\nMarkers currently limited to 20,000 per world. -lst.setmarker = Set a property for a marker.\nThe ID used must be the same as in the Make Marker instruction. +lst.setmarker = Set a property for a marker.\nThe ID used must be the same as in the Make Marker instruction.\n[accent]null []values are being ignored instead of converting to 0. logic.nounitbuild = [red]Unit building logic is not allowed here. @@ -2458,6 +2458,5 @@ lenum.within = Check if unit is near a position. lenum.boost = Start/stop boosting. lenum.texture = Texture name straight from game's texture atlas (using kebab-case naming style).\nSecond and third arguments are additional suffixes added using "-" separator.\nIf additional arguments are not strings, nothing is added to first string. -lenum.texturewidth = Width of texture in tiles. Zero value scales marker width to original texture's size. -lenum.textureheight = Height of texture in tiles. Zero value scales marker height to original texture's size. +lenum.texturesize = Size of texture in tiles. Zero value scales marker width to original texture's size. lenum.autoscale = Whether to scale marker corresponding to player's zoom level. diff --git a/core/src/mindustry/game/MapObjectives.java b/core/src/mindustry/game/MapObjectives.java index 9e074f2ff4..98ddd24bc2 100644 --- a/core/src/mindustry/game/MapObjectives.java +++ b/core/src/mindustry/game/MapObjectives.java @@ -630,8 +630,9 @@ public class MapObjectives implements Iterable, Eachable hidden = Mathf.equal((float)p1, 0f); case drawLayer -> drawLayer = (float)p1; @@ -757,21 +758,38 @@ public class MapObjectives implements Iterable, Eachable pos.x = (float)p1 * tilesize; - case y -> pos.y = (float)p1 * tilesize; - case pos -> pos.set((float)p1 * tilesize, (float)p2 * tilesize); - case fontSize -> fontSize = (float)p1; - case textHeight -> textHeight = (float)p1; - case labelFlags -> { - flags = (!Mathf.equal((float)p1, 0f) ? WorldLabel.flagBackground : 0); - if(!Mathf.equal((float)p2, 0f)) flags |= WorldLabel.flagOutline; + if(!Double.isNaN(p1)){ + switch(type){ + case pos -> pos.x = (float)p1 * tilesize; + case fontSize -> fontSize = (float)p1; + case textHeight -> textHeight = (float)p1; + case labelFlags -> { + if(!Mathf.equal((float)p1, 0f)){ + flags |= WorldLabel.flagBackground; + }else{ + flags &= ~WorldLabel.flagBackground; + } + } + case radius -> radius = (float)p1; + case rotation -> rotation = (float)p1; + case color -> color.set(Tmp.c1.fromDouble(p1)); + case shape -> sides = (int)p1; + default -> super.control(type, p1, p2, p3); + } + } + + if(!Double.isNaN(p2)){ + switch(type){ + case pos -> pos.y = (float)p2 * tilesize; + case labelFlags -> { + if(!Mathf.equal((float)p2, 0f)){ + flags |= WorldLabel.flagOutline; + }else{ + flags &= ~WorldLabel.flagOutline; + } + } + default -> super.control(type, p1, p2, p3); } - case radius -> radius = (float)p1; - case rotation -> rotation = (float)p1; - case shapeSides -> sides = (int)p1; - case color -> color.set(Tmp.c1.fromDouble(p1)); - default -> super.control(type, p1, p2, p3); } } @@ -828,14 +846,22 @@ public class MapObjectives implements Iterable, Eachable pos.x = (int)p1; - case y -> pos.y = (int)p1; - case pos -> pos.set((int)p1, (int)p2); - case radius -> radius = (float)p1; - case stroke -> stroke = (float)p1; - case color -> color.set(Tmp.c1.fromDouble(p1)); - default -> super.control(type, p1, p2, p3); + if(!Double.isNaN(p1)){ + switch(type){ + case pos -> pos.x = (int)p1; + case radius -> radius = (float)p1; + case stroke -> stroke = (float)p1; + case color -> color.set(Tmp.c1.fromDouble(p1)); + default -> super.control(type, p1, p2, p3); + } + } + + if(!Double.isNaN(p2)){ + if(type == LMarkerControl.pos){ + pos.y = (int)p2; + }else{ + super.control(type, p1, p2, p3); + } } } } @@ -916,23 +942,32 @@ public class MapObjectives implements Iterable, Eachable pos.x = (float)p1 * tilesize; - case y -> pos.y = (float)p1 * tilesize; - case pos -> pos.set((float)p1 * tilesize, (float)p2 * tilesize); - case radius -> radius = (float)p1; - case rotation -> rotation = (float)p1; - case stroke -> stroke = (float)p1; - case shapeSides -> sides = (int)p1; - case shapeFill -> fill = !Mathf.equal((float)p1, 0f); - case shapeOutline -> outline = !Mathf.equal((float)p1, 0f); - case shape -> { - sides = (int)p1; - fill = !Mathf.equal((float)p2, 0f); + if(!Double.isNaN(p1)){ + switch(type){ + case pos -> pos.x = (float)p1 * tilesize; + case radius -> radius = (float)p1; + case stroke -> stroke = (float)p1; + case rotation -> rotation = (float)p1; + case color -> color.set(Tmp.c1.fromDouble(p1)); + case shape -> sides = (int)p1; + default -> super.control(type, p1, p2, p3); + } + } + + if(!Double.isNaN(p2)){ + switch(type){ + case pos -> pos.y = (float)p2 * tilesize; + case shape -> fill = !Mathf.equal((float)p2, 0f); + default -> super.control(type, p1, p2, p3); + } + } + + if(!Double.isNaN(p3)){ + if(type == LMarkerControl.shape){ outline = !Mathf.equal((float)p3, 0f); + }else{ + super.control(type, p1, p2, p3); } - case color -> color.set(Tmp.c1.fromDouble(p1)); - default -> super.control(type, p1, p2, p3); } } } @@ -994,16 +1029,33 @@ public class MapObjectives implements Iterable, Eachable pos.x = (float)p1 * tilesize; - case y -> pos.y = (float)p1 * tilesize; - case pos -> pos.set((float)p1 * tilesize, (float)p2 * tilesize); - case fontSize -> fontSize = (float)p1; - case labelFlags -> { - flags = (!Mathf.equal((float)p1, 0f) ? WorldLabel.flagBackground : 0); - if(!Mathf.equal((float)p2, 0f)) flags |= WorldLabel.flagOutline; + if(!Double.isNaN(p1)){ + switch(type){ + case pos -> pos.x = (float)p1 * tilesize; + case fontSize -> fontSize = (float)p1; + case labelFlags -> { + if(!Mathf.equal((float)p1, 0f)){ + flags |= WorldLabel.flagBackground; + }else{ + flags &= ~WorldLabel.flagBackground; + } + } + default -> super.control(type, p1, p2, p3); + } + } + + if(!Double.isNaN(p2)){ + switch(type){ + case pos -> pos.y = (float)p2 * tilesize; + case labelFlags -> { + if(!Mathf.equal((float)p2, 0f)){ + flags |= WorldLabel.flagOutline; + }else{ + flags &= ~WorldLabel.flagOutline; + } + } + default -> super.control(type, p1, p2, p3); } - default -> super.control(type, p1, p2, p3); } } @@ -1073,17 +1125,22 @@ public class MapObjectives implements Iterable, Eachable pos1.x = (float)p1 * tilesize; - case y -> pos1.y = (float)p1 * tilesize; - case pos -> pos1.set((float)p1 * tilesize, (float)p2 * tilesize); - case endX -> pos2.x = (float)p1 * tilesize; - case endY -> pos2.y = (float)p1 * tilesize; - case endPos -> pos2.set((float)p1 * tilesize, (float)p2 * tilesize); - case stroke -> stroke = (float)p1; - case shapeOutline -> outline = !Mathf.equal((float)p1, 0f); - case color -> color.set(Tmp.c1.fromDouble(p1)); - default -> super.control(type, p1, p2, p3); + if(!Double.isNaN(p1)){ + switch(type){ + case pos -> pos1.x = (float)p1 * tilesize; + case endPos -> pos2.x = (float)p1 * tilesize; + case stroke -> stroke = (float)p1; + case color -> color.set(Tmp.c1.fromDouble(p1)); + default -> super.control(type, p1, p2, p3); + } + } + + if(!Double.isNaN(p2)){ + switch(type){ + case pos -> pos1.y = (float)p2 * tilesize; + case endPos -> pos2.y = (float)p2 * tilesize; + default -> super.control(type, p1, p2, p3); + } } } } @@ -1106,19 +1163,22 @@ public class MapObjectives implements Iterable, Eachable pos.x = (float)p1 * tilesize; - case y -> pos.y = (float)p1 * tilesize; - case pos -> pos.set((float)p1 * tilesize, (float)p2 * tilesize); - case rotation -> rotation = (float)p1; - case textureWidth -> width = (float)p1 * tilesize; - case textureHeight -> height = (float)p1 * tilesize; - case textureSize -> { - width = (float)p1 * tilesize; - height = (float)p2 * tilesize; + if(!Double.isNaN(p1)){ + switch(type){ + case pos -> pos.x = (float)p1 * tilesize; + case rotation -> rotation = (float)p1; + case textureSize -> width = (float)p1 * tilesize; + case color -> color.set(Tmp.c1.fromDouble(p1)); + default -> super.control(type, p1, p2, p3); + } + } + + if(!Double.isNaN(p2)){ + switch(type){ + case pos -> pos.y = (float)p2 * tilesize; + case textureSize -> height = (float)p2 * tilesize; + default -> super.control(type, p1, p2, p3); } - case color -> color.set(Tmp.c1.fromDouble(p1)); - default -> super.control(type, p1, p2, p3); } } diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index e59156502f..7318e0837d 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -157,18 +157,29 @@ public class LExecutor{ return v.isobj ? v.objval != null : Math.abs(v.numval) >= 0.00001; } - public double num(int index){ + @Nullable + public double num(int index, boolean nullToNan){ Var v = var(index); - return v.isobj ? v.objval != null ? 1 : 0 : invalid(v.numval) ? 0 : v.numval; + return v.isobj ? v.objval != null ? 1 : nullToNan ? Double.NaN : 0: invalid(v.numval) ? 0 : v.numval; + } + + public double num(int index){ + return num(index, false); + } + + @Nullable + public float numf(int index, boolean nullToNan){ + Var v = var(index); + return v.isobj ? v.objval != null ? 1 : nullToNan ? Float.NaN : 0: invalid(v.numval) ? 0 : (float)v.numval; } public float numf(int index){ - Var v = var(index); - return v.isobj ? v.objval != null ? 1 : 0 : invalid(v.numval) ? 0 : (float)v.numval; + return numf(index, false); } + @Nullable public int numi(int index){ - return (int)num(index); + return (int)num(index, true); } public void setbool(int index, boolean value){ @@ -254,7 +265,7 @@ public class LExecutor{ //bind to the next unit exec.setconst(varUnit, seq.get(exec.binds[type.id])); } - exec.binds[type.id] ++; + exec.binds[type.id]++; }else{ //no units of this type found exec.setconst(varUnit, null); @@ -334,9 +345,9 @@ public class LExecutor{ cache.found = false; exec.setnum(outFound, 0); } - - if(res != null && res.build != null && - (unit.within(res.build.x, res.build.y, Math.max(unit.range(), buildingRange)) || res.build.team == exec.team)){ + + if(res != null && res.build != null && + (unit.within(res.build.x, res.build.y, Math.max(unit.range(), buildingRange)) || res.build.team == exec.team)){ cache.build = res.build; exec.setobj(outBuild, res.build); }else{ @@ -501,7 +512,7 @@ public class LExecutor{ } case build -> { if((state.rules.logicUnitBuild || exec.privileged) && unit.canBuild() && exec.obj(p3) instanceof Block block && block.canBeBuilt() && (block.unlockedNow() || unit.team.isAI())){ - int x = World.toTile(x1 - block.offset/tilesize), y = World.toTile(y1 - block.offset/tilesize); + int x = World.toTile(x1 - block.offset / tilesize), y = World.toTile(y1 - block.offset / tilesize); int rot = Mathf.mod(exec.numi(p4), 4); //reset state of last request when necessary @@ -559,7 +570,7 @@ public class LExecutor{ }else{ Building build = exec.building(p1); int dropped = Math.min(unit.stack.amount, exec.numi(p2)); - if(build != null && build.team == unit.team && build.isValid() && dropped > 0 && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){ + if(build != null && build.team == unit.team && build.isValid() && dropped > 0 && unit.within(build, logicItemTransferRange + build.block.size * tilesize / 2f)){ int accepted = build.acceptStack(unit.item(), dropped, unit); if(accepted > 0){ Call.transferItemTo(unit, unit.item(), accepted, unit.x, unit.y, build); @@ -575,7 +586,7 @@ public class LExecutor{ int amount = exec.numi(p3); if(build != null && build.team == unit.team && build.isValid() && build.items != null && - exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){ + exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange + build.block.size * tilesize / 2f)){ int taken = Math.min(build.items.get(item), Math.min(amount, unit.maxAccepted(item))); if(taken > 0){ @@ -584,7 +595,8 @@ public class LExecutor{ } } } - default -> {} + default -> { + } } } } @@ -605,7 +617,8 @@ public class LExecutor{ this.p4 = p4; } - ControlI(){} + ControlI(){ + } @Override public void run(LExecutor exec){ @@ -773,7 +786,7 @@ public class LExecutor{ LogicAI ai = null; if(base instanceof Ranged r && (exec.privileged || r.team() == exec.team) && - (base instanceof Building || (ai = UnitControlI.checkLogicAI(exec, base)) != null)){ //must be a building or a controllable unit + (base instanceof Building || (ai = UnitControlI.checkLogicAI(exec, base)) != null)){ //must be a building or a controllable unit float range = r.range(); Healthc targeted; @@ -829,9 +842,9 @@ public class LExecutor{ if(!u.within(b, range) || !u.targetable(team) || b == u) return; boolean valid = - target1.func.get(b.team(), u) && - target2.func.get(b.team(), u) && - target3.func.get(b.team(), u); + target1.func.get(b.team(), u) && + target2.func.get(b.team(), u) && + target3.func.get(b.team(), u); if(!valid) return; @@ -852,7 +865,8 @@ public class LExecutor{ this.to = to; } - SetI(){} + SetI(){ + } @Override public void run(LExecutor exec){ @@ -884,7 +898,8 @@ public class LExecutor{ this.dest = dest; } - OpI(){} + OpI(){ + } @Override public void run(LExecutor exec){ @@ -919,7 +934,8 @@ public class LExecutor{ public static class NoopI implements LInstruction{ @Override - public void run(LExecutor exec){} + public void run(LExecutor exec){ + } } public static class DrawI implements LInstruction{ @@ -973,9 +989,9 @@ public class LExecutor{ if(next == '\n'){ maxWidth = Math.max(maxWidth, lineWidth); lineWidth = 0; - lines ++; + lines++; }else{ - lineWidth ++; + lineWidth++; } } maxWidth = Math.max(maxWidth, lineWidth); @@ -983,8 +999,8 @@ public class LExecutor{ float width = maxWidth * advance, height = lines * lineHeight, - ha = ((Align.isLeft(align) ? -1f : 0f) + 1f + (Align.isRight(align) ? 1f : 0f))/2f, - va = ((Align.isBottom(align) ? -1f : 0f) + 1f + (Align.isTop(align) ? 1f : 0f))/2f; + ha = ((Align.isLeft(align) ? -1f : 0f) + 1f + (Align.isRight(align) ? 1f : 0f)) / 2f, + va = ((Align.isBottom(align) ? -1f : 0f) + 1f + (Align.isTop(align) ? 1f : 0f)) / 2f; xOffset = -(int)(width * ha); yOffset = -(int)(height * va) + (lines - 1) * lineHeight; @@ -1061,7 +1077,8 @@ public class LExecutor{ this.value = value; } - PrintI(){} + PrintI(){ + } @Override public void run(LExecutor exec){ @@ -1086,16 +1103,16 @@ public class LExecutor{ public static String toString(Object obj){ return - obj == null ? "null" : - obj instanceof String s ? s : - obj == Blocks.stoneWall ? "solid" : //special alias - obj instanceof MappableContent content ? content.name : - obj instanceof Content ? "[content]" : - obj instanceof Building build ? build.block.name : - obj instanceof Unit unit ? unit.type.name : - obj instanceof Enum e ? e.name() : - obj instanceof Team team ? team.name : - "[object]"; + obj == null ? "null" : + obj instanceof String s ? s : + obj == Blocks.stoneWall ? "solid" : //special alias + obj instanceof MappableContent content ? content.name : + obj instanceof Content ? "[content]" : + obj instanceof Building build ? build.block.name : + obj instanceof Unit unit ? unit.type.name : + obj instanceof Enum e ? e.name() : + obj instanceof Team team ? team.name : + "[object]"; } } @@ -1179,7 +1196,7 @@ public class LExecutor{ curTime = 0f; }else{ //skip back to self. - exec.var(varCounter).numval --; + exec.var(varCounter).numval--; exec.yield = true; } @@ -1195,7 +1212,7 @@ public class LExecutor{ @Override public void run(LExecutor exec){ //skip back to self. - exec.var(varCounter).numval --; + exec.var(varCounter).numval--; exec.yield = true; } } @@ -1609,15 +1626,15 @@ public class LExecutor{ public void run(LExecutor exec){ //set default to success exec.setnum(outSuccess, 1); - if(headless && type != MessageType.mission) { + if(headless && type != MessageType.mission){ exec.textBuffer.setLength(0); return; } if( - type == MessageType.announce && ui.hasAnnouncement() || - type == MessageType.notify && ui.hudfrag.hasToast() || - type == MessageType.toast && ui.hasAnnouncement() + type == MessageType.announce && ui.hasAnnouncement() || + type == MessageType.notify && ui.hudfrag.hasToast() || + type == MessageType.toast && ui.hasAnnouncement() ){ //set outSuccess=false to let user retry. exec.setnum(outSuccess, 0); @@ -1666,7 +1683,7 @@ public class LExecutor{ double col = exec.num(color); //limit size so people don't create lag with ridiculous numbers (some explosions scale with size) float rot = type.rotate ? exec.numf(rotation) : - Math.min(exec.numf(rotation), 1000f); + Math.min(exec.numf(rotation), 1000f); type.effect.at(World.unconv(exec.numf(x)), World.unconv(exec.numf(y)), rot, Tmp.c1.fromDouble(col), exec.obj(data)); } @@ -1850,8 +1867,8 @@ public class LExecutor{ } float - spawnX = World.unconv(exec.numf(x)), - spawnY = World.unconv(exec.numf(y)); + spawnX = World.unconv(exec.numf(x)), + spawnY = World.unconv(exec.numf(y)); int packed = Point2.pack(exec.numi(x), exec.numi(y)); for(SpawnGroup group : state.rules.spawns){ @@ -1904,7 +1921,7 @@ public class LExecutor{ } public static class SetMarkerI implements LInstruction{ - public LMarkerControl type = LMarkerControl.x; + public LMarkerControl type = LMarkerControl.pos; public int id, p1, p2, p3; public SetMarkerI(LMarkerControl type, int id, int p1, int p2, int p3){ @@ -1939,7 +1956,7 @@ public class LExecutor{ marker.setTexture(res.toString()); } }else{ - marker.control(type, exec.num(p1), exec.num(p2), exec.num(p3)); + marker.control(type, exec.num(p1, true), exec.num(p2, true), exec.num(p3, true)); } } } @@ -1971,7 +1988,7 @@ public class LExecutor{ int mid = exec.numi(id); if(exec.bool(replace) || !state.markers.containsKey(mid)){ var marker = cons.get(); - marker.control(LMarkerControl.pos, exec.num(x), exec.num(y), 0); + marker.control(LMarkerControl.pos, exec.num(x, true), exec.num(y, true), 0); state.markers.put(mid, marker); } } diff --git a/core/src/mindustry/logic/LMarkerControl.java b/core/src/mindustry/logic/LMarkerControl.java index b98d3fd8f6..8d96dd00cd 100644 --- a/core/src/mindustry/logic/LMarkerControl.java +++ b/core/src/mindustry/logic/LMarkerControl.java @@ -5,20 +5,13 @@ public enum LMarkerControl{ visibility("true/false"), minimap("true/false"), autoscale("true/false"), - x("x"), - y("y"), pos("x", "y"), - endX("x"), - endY("y"), endPos("x", "y"), drawLayer("layer"), color("color"), radius("radius"), stroke("stroke"), rotation("rotation"), - shapeSides("sides"), - shapeFill("true/false"), - shapeOutline("true/false"), shape("sides", "fill", "outline"), text("text"), flushText, @@ -26,8 +19,6 @@ public enum LMarkerControl{ textHeight("height"), labelFlags("background", "outline"), texture("name", "-", "-"), - textureWidth("width"), - textureHeight("height"), textureSize("width", "height"); public final String[] params; diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 92b09605b7..ade3579391 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -1945,7 +1945,7 @@ public class LStatements{ @RegisterStatement("setmarker") public static class SetMarkerStatement extends LStatement{ - public LMarkerControl type = LMarkerControl.x; + public LMarkerControl type = LMarkerControl.pos; public String id = "0", p1 = "0", p2 = "0", p3 = "0"; @Override