diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 4613532a31..677fd1ee88 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1438,8 +1438,10 @@ rules.title.unit = Units rules.title.experimental = Experimental rules.title.environment = Environment rules.title.teams = Teams +rules.title.light = Lighting rules.title.planet = Planet rules.lighting = Lighting +rules.lighting.unitlight = Unit Lighting rules.fog = Fog of War rules.invasions = Enemy Sector Invasions rules.legacylaunchpads = Legacy Launch Pad Mechanics diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 00fb77bfaf..b7b8d3243e 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -320,6 +320,37 @@ public class Renderer implements ApplicationListener{ } } + //draw objective markers + float scaleFactor = 4f / renderer.getDisplayScale(); + state.rules.objectives.eachRunning(obj -> { + for(var marker : obj.markers){ + if(marker.world != -1){ + marker.draw(marker.autoscale ? scaleFactor : 1); + } + } + }); + + for(var marker : state.markers.worldMarkers){ + marker.draw(marker.autoscale ? scaleFactor : 1); + } + Draw.reset(); + + lights.add(() -> { + state.rules.objectives.eachRunning(obj -> { + for(var marker : obj.markers){ + if(marker.light != -1){ + marker.drawLight(marker.autoscale ? scaleFactor : 1); + } + } + }); + + for(var marker : state.markers.lightMarkers){ + marker.drawLight(marker.autoscale ? scaleFactor : 1); + } + + Draw.reset(); + }); + if(state.rules.lighting && drawLight){ Draw.draw(Layer.light, lights::draw); } @@ -353,23 +384,6 @@ public class Renderer implements ApplicationListener{ }); } - float scaleFactor = 4f / renderer.getDisplayScale(); - - //draw objective markers - state.rules.objectives.eachRunning(obj -> { - for(var marker : obj.markers){ - if(marker.world){ - marker.draw(marker.autoscale ? scaleFactor : 1); - } - } - }); - - for(var marker : state.markers){ - if(marker.world){ - marker.draw(marker.autoscale ? scaleFactor : 1); - } - } - Draw.reset(); Draw.draw(Layer.overlayUI, overlays::drawTop); diff --git a/core/src/mindustry/editor/MapObjectivesDialog.java b/core/src/mindustry/editor/MapObjectivesDialog.java index c8f021f214..fd1d60cb11 100644 --- a/core/src/mindustry/editor/MapObjectivesDialog.java +++ b/core/src/mindustry/editor/MapObjectivesDialog.java @@ -302,6 +302,11 @@ public class MapObjectivesDialog extends BaseDialog{ }).growX().fillY(); }); + + setInterpreter(IndexBool.class, int.class, (cont, name, type, field, remover, indexer, get, set) -> { + getInterpreter(Boolean.class).build(cont, name, type, field, remover, indexer, () -> get.get() != -1, v -> set.get(v ? +1 : -1)); + }); + // Special data structure interpreters. // Instantiate default `Seq`s with a reflectively allocated array. setProvider(Seq.class, (type, cons) -> cons.get(new Seq<>(type.element.raw))); diff --git a/core/src/mindustry/game/MapMarkers.java b/core/src/mindustry/game/MapMarkers.java index 3afb6895ee..4bd4193cea 100644 --- a/core/src/mindustry/game/MapMarkers.java +++ b/core/src/mindustry/game/MapMarkers.java @@ -1,42 +1,37 @@ package mindustry.game; +import arc.func.*; import arc.struct.*; import arc.util.*; import mindustry.game.MapObjectives.*; import mindustry.io.*; import java.io.*; -import java.util.*; -public class MapMarkers implements Iterable{ +public class MapMarkers{ /** Maps marker unique ID to marker. */ private IntMap map = new IntMap<>(); - /** Sequential list of markers. This allows for faster iteration than a map. */ - private Seq all = new Seq<>(false); + + public Seq worldMarkers = new Seq<>(false); + public Seq mapMarkers = new Seq<>(false); + public Seq lightMarkers = new Seq<>(false); public void add(int id, ObjectiveMarker marker){ if(marker == null) return; - var prev = map.put(id, marker); - if(prev != null){ - all.set(prev.arrayIndex, marker); - }else{ - all.add(marker); - marker.arrayIndex = all.size - 1; - } + + setMarker(worldMarkers, marker, prev, m -> m.world, (m, i) -> m.world = i); + setMarker(mapMarkers, marker, prev, m -> m.minimap, (m, i) -> m.minimap = i); + setMarker(lightMarkers, marker, prev, m -> m.light, (m, i) -> m.light = i); } public void remove(int id){ var prev = map.remove(id); + if(prev != null){ - if(all.size > prev.arrayIndex + 1){ //there needs to be something above the index to replace it with - all.remove(prev.arrayIndex); - //update its index - all.get(prev.arrayIndex).arrayIndex = prev.arrayIndex; - }else{ - //no sense updating the index of the replaced element when it was not replaced - all.remove(prev.arrayIndex); - } + remove(worldMarkers, prev.world, (m, i) -> m.world = i); + remove(mapMarkers, prev.minimap, (m, i) -> m.minimap = i); + remove(lightMarkers, prev.light, (m, i) -> m.light = i); } } @@ -49,7 +44,7 @@ public class MapMarkers implements Iterable{ } public int size(){ - return all.size; + return map.size; } public void write(DataOutput stream) throws IOException{ @@ -57,16 +52,64 @@ public class MapMarkers implements Iterable{ } public void read(DataInput stream) throws IOException{ - all.clear(); + worldMarkers.clear(); + mapMarkers.clear(); + lightMarkers.clear(); map = JsonIO.readBytes(IntMap.class, ObjectiveMarker.class, (DataInputStream)stream); + for(var entry : map.entries()){ - all.add(entry.value); - entry.value.arrayIndex = all.size - 1; + var marker = entry.value; + + if(marker.world != -1) marker.world = worldMarkers.add(marker).size - 1; + if(marker.minimap != -1) marker.minimap = mapMarkers.add(marker).size - 1; + if(marker.light != -1) marker.light = lightMarkers.add(marker).size - 1; } } - @Override - public Iterator iterator(){ - return all.iterator(); + public interface MarkerSetter{ + void set(ObjectiveMarker marker, int index); } + + public void updateMarker(Seq markers, ObjectiveMarker marker, boolean visible, Intf getter, MarkerSetter setter){ + if((getter.get(marker) != -1) == visible) return; // nothing to change + + if(!visible){ + setter.set(markers.peek(), getter.get(marker)); + markers.remove(getter.get(marker)); + setter.set(marker, -1); + }else{ + setter.set(marker, markers.size); + markers.add(marker); + } + } + + private void setMarker(Seq markers, ObjectiveMarker curr, ObjectiveMarker prev, Intf getter, MarkerSetter setter){ + int currIndex = getter.get(curr); + + if(prev != null && getter.get(prev) != -1){ + int prevIndex = getter.get(prev); + if(currIndex != -1){ + // both markers visible, replace previous with current + setter.set(curr, prevIndex); + markers.set(prevIndex, curr); + }else{ + // previous marker visible but not current + setter.set(markers.peek(), prevIndex); + markers.remove(prevIndex); + } + }else{ + if(currIndex != -1){ + setter.set(curr, markers.size); + markers.add(curr); + } + } + } + + private void remove(Seq markers, int index, MarkerSetter setter){ + if(index != -1){ + setter.set(markers.peek(), index); + markers.remove(index); + } + } + } diff --git a/core/src/mindustry/game/MapObjectives.java b/core/src/mindustry/game/MapObjectives.java index 7f158b264a..144b61bc73 100644 --- a/core/src/mindustry/game/MapObjectives.java +++ b/core/src/mindustry/game/MapObjectives.java @@ -65,7 +65,8 @@ public class MapObjectives implements Iterable, Eachable, Eachable, Eachable world = !Mathf.equal((float)p1, 0f); - case minimap -> minimap = !Mathf.equal((float)p1, 0f); + case world -> state.markers.updateMarker(state.markers.worldMarkers, this, !Mathf.equal((float)p1, 0f), m -> m.world, (m, i) -> m.world = i); + case minimap -> state.markers.updateMarker(state.markers.mapMarkers, this, !Mathf.equal((float)p1, 0f), m -> m.minimap, (m, i) -> m.minimap = i); + case light -> state.markers.updateMarker(state.markers.lightMarkers, this, !Mathf.equal((float)p1, 0f), m -> m.light, (m, i) -> m.light = i); case autoscale -> autoscale = !Mathf.equal((float)p1, 0f); case drawLayer -> drawLayer = (float)p1; } @@ -842,8 +847,13 @@ public class MapObjectives implements Iterable, Eachable, Eachable, Eachable, Eachable radius = (float)p1; + case color -> color.fromDouble(p1); + } + } + } + } + private static void lookupRegion(String name, TextureRegion out){ TextureRegion region = Core.atlas.find(name); if(region.found()){ @@ -1275,6 +1330,11 @@ public class MapObjectives implements Iterable, Eachable { for(var marker : obj.markers){ - if(marker.minimap){ + if(marker.minimap != -1){ marker.draw(1); } } }); - - for(var marker : state.markers){ - if(marker.minimap){ - marker.draw(1); - } + for(var marker : state.markers.mapMarkers){ + marker.draw(1); } + Draw.reset(); Draw.trans(Tmp.m2); } diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 1ba96cc93a..10b7f05b0c 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -1548,6 +1548,7 @@ public class LExecutor{ } } case ambientLight -> state.rules.ambientLight.fromDouble(value.num()); + case unitLight -> state.rules.unitLight = value.bool(); case solarMultiplier -> state.rules.solarMultiplier = Math.max(value.numf(), 0f); case dragMultiplier -> state.rules.dragMultiplier = Math.max(value.numf(), 0f); case ban -> { diff --git a/core/src/mindustry/logic/LMarkerControl.java b/core/src/mindustry/logic/LMarkerControl.java index c24775af02..4ea274563b 100644 --- a/core/src/mindustry/logic/LMarkerControl.java +++ b/core/src/mindustry/logic/LMarkerControl.java @@ -4,6 +4,7 @@ public enum LMarkerControl{ remove, world("true/false"), minimap("true/false"), + light("true/false"), autoscale("true/false"), pos("x", "y"), endPos("x", "y"), diff --git a/core/src/mindustry/logic/LogicRule.java b/core/src/mindustry/logic/LogicRule.java index b6ca757bb7..f532af6441 100644 --- a/core/src/mindustry/logic/LogicRule.java +++ b/core/src/mindustry/logic/LogicRule.java @@ -15,6 +15,7 @@ public enum LogicRule{ lighting, canGameOver, ambientLight, + unitLight, solarMultiplier, dragMultiplier, ban, diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 68513a7f58..11fcb1c4b3 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -1547,7 +1547,7 @@ public class UnitType extends UnlockableContent implements Senseable{ } public void drawLight(Unit unit){ - if(lightRadius > 0){ + if(lightRadius > 0 && state.rules.unitLight){ Drawf.light(unit.x, unit.y, lightRadius, lightColor, lightOpacity); } } diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index 8c9e1a16c5..3c1c9b0ccc 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -221,6 +221,11 @@ public class CustomRulesDialog extends BaseDialog{ number("@rules.solarmultiplier", f -> rules.solarMultiplier = f, () -> rules.solarMultiplier); + if(Core.bundle.get("rules.weather").toLowerCase().contains(ruleSearch)){ + current.button("@rules.weather", this::weatherDialog).width(250f).left().row(); + } + + category("light"); if(Core.bundle.get("rules.ambientlight").toLowerCase().contains(ruleSearch)){ current.button(b -> { b.left(); @@ -232,11 +237,7 @@ public class CustomRulesDialog extends BaseDialog{ b.add("@rules.ambientlight"); }, () -> ui.picker.show(rules.ambientLight, rules.ambientLight::set)).left().width(250f).row(); } - - if(Core.bundle.get("rules.weather").toLowerCase().contains(ruleSearch)){ - current.button("@rules.weather", this::weatherDialog).width(250f).left().row(); - } - + check("@rules.lighting.unitlight", b -> rules.unitLight = b, () -> rules.unitLight); category("planet"); if(Core.bundle.get("rules.title.planet").toLowerCase().contains(ruleSearch)){