From 427d43039b1798125c13c3d1bb6143e038db2553 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 16 Feb 2022 12:45:48 -0500 Subject: [PATCH] World play area rule --- .../blocks/environment/ore-wall-thorium1.png | Bin 271 -> 277 bytes core/assets/bundles/bundle.properties | 1 + core/src/mindustry/content/Fx.java | 6 +- core/src/mindustry/core/Renderer.java | 5 ++ core/src/mindustry/core/World.java | 20 +++-- .../mindustry/entities/comp/BoundedComp.java | 26 +++++-- core/src/mindustry/game/Rules.java | 4 + .../src/mindustry/graphics/BlockRenderer.java | 69 +++++++++++------- core/src/mindustry/graphics/Pal.java | 3 +- core/src/mindustry/logic/LExecutor.java | 59 ++++++++++++++- core/src/mindustry/logic/LStatements.java | 28 ++++++- core/src/mindustry/logic/LogicRule.java | 1 + .../ui/dialogs/CustomRulesDialog.java | 25 +++++-- .../blocks/defense/turrets/LaserTurret.java | 1 - gradle.properties | 2 +- 15 files changed, 196 insertions(+), 54 deletions(-) diff --git a/core/assets-raw/sprites/blocks/environment/ore-wall-thorium1.png b/core/assets-raw/sprites/blocks/environment/ore-wall-thorium1.png index 474c51942caec9a08d1112d248a4d2496cec2bbf..a01a034745112d69d396cee35dbb35bc19cf52d1 100644 GIT binary patch delta 113 zcmeBYn#wf6kn#LPqq@|>HiliPKXjI>oPOln@}I|o+qC|`qRQ9?{nthY0fy3(l3r>^ur5vz;n8AX@YxV?a-lcp76t|e N22WQ%mvv4FO#nr5CGh|N diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 970d26f24a..8b3e4f1361 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1071,6 +1071,7 @@ rules.unithealthmultiplier = Unit Health Multiplier rules.unitdamagemultiplier = Unit Damage Multiplier rules.unitcapvariable = Cores Contribute To Unit Cap rules.unitcap = Base Unit Cap +rules.limitarea = Limit Map Area rules.enemycorebuildradius = Enemy Core No-Build Radius:[lightgray] (tiles) rules.wavespacing = Wave Spacing:[lightgray] (sec) rules.initialwavespacing = Initial Wave Spacing:[lightgray] (sec) diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index f6de457863..b7c21f6d27 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -1079,7 +1079,9 @@ public class Fx{ }), ventSteam = new Effect(140f, e -> { - color(e.color, e.fslope() * 0.85f); + color(e.color, Pal.vent2, e.fin()); + + alpha(e.fslope() * 0.78f); float length = 3f + e.finpow() * 10f; rand.setSeed(e.id); @@ -1087,7 +1089,7 @@ public class Fx{ v.trns(rand.random(360f), rand.random(length)); Fill.circle(e.x + v.x, e.y + v.y, rand.random(1.2f, 3.5f) + e.fslope() * 1.1f); } - }), + }).layer(Layer.darkness - 1), drillSteam = new Effect(220f, e -> { diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 3cbe634081..56043a4f78 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -223,6 +223,11 @@ public class Renderer implements ApplicationListener{ } } + public void updateAllDarkness(){ + blocks.updateDarkness(); + minimap.updateAll(); + } + /** @return whether a launch/land cutscene is playing. */ public boolean isCutscene(){ return landTime > 0; diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 1ca1bcd1d3..1564f0bffa 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -231,7 +231,7 @@ public class World{ } public Rect getQuadBounds(Rect in){ - return in.set(-finalWorldBounds, -finalWorldBounds, world.width() * tilesize + finalWorldBounds * 2, world.height() * tilesize + finalWorldBounds * 2); + return in.set(-finalWorldBounds, -finalWorldBounds, width() * tilesize + finalWorldBounds * 2, height() * tilesize + finalWorldBounds * 2); } public void setGenerating(boolean gen){ @@ -295,8 +295,8 @@ public class World{ ObjectSet content = new ObjectSet<>(); //TODO duplicate code? - for(Tile tile : world.tiles){ - if(world.getDarkness(tile.x, tile.y) >= 3){ + for(Tile tile : tiles){ + if(getDarkness(tile.x, tile.y) >= 3){ continue; } @@ -499,7 +499,17 @@ public class World{ if(Vars.state.rules.borderDarkness){ int edgeBlend = 2; - int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (tiles.width - 1)), Math.abs(y - (tiles.height - 1))))); + int edgeDst; + + if(!state.rules.limitMapArea){ + edgeDst = Math.min(x, Math.min(y, Math.min(-(x - (tiles.width - 1)), -(y - (tiles.height - 1))))); + }else{ + edgeDst = + Math.min(x - state.rules.limitX, + Math.min(y - state.rules.limitY, + Math.min(-(x - (state.rules.limitX + state.rules.limitWidth - 1)), -(y - (state.rules.limitY + state.rules.limitHeight - 1))))); + } + if(edgeDst <= edgeBlend){ dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark); } @@ -529,7 +539,7 @@ public class World{ } } - Tile tile = world.tile(x, y); + Tile tile = tile(x, y); if(tile != null && tile.isDarkened()){ dark = Math.max(dark, tile.data); } diff --git a/core/src/mindustry/entities/comp/BoundedComp.java b/core/src/mindustry/entities/comp/BoundedComp.java index fa7d860db2..79996d0adc 100644 --- a/core/src/mindustry/entities/comp/BoundedComp.java +++ b/core/src/mindustry/entities/comp/BoundedComp.java @@ -3,6 +3,7 @@ package mindustry.entities.comp; import arc.math.*; import arc.util.*; import mindustry.annotations.Annotations.*; +import mindustry.game.*; import mindustry.gen.*; import static mindustry.Vars.*; @@ -12,30 +13,41 @@ abstract class BoundedComp implements Velc, Posc, Healthc, Flyingc{ static final float warpDst = 30f; @Import float x, y; + @Import Team team; @Override public void update(){ + float bot = 0f, left = 0f, top = world.unitHeight(), right = world.unitWidth(); + + //TODO hidden map rules only apply to player teams? should they? + if(state.rules.borderDarkness && !team.isAI()){ + bot = state.rules.limitY * tilesize; + left = state.rules.limitX * tilesize; + top = state.rules.limitHeight * tilesize + bot; + right = state.rules.limitWidth * tilesize + left; + } + if(!net.client() || isLocal()){ float dx = 0f, dy = 0f; //repel unit out of bounds - if(x < 0) dx += (-x/warpDst); - if(y < 0) dy += (-y/warpDst); - if(x > world.unitWidth()) dx -= (x - world.unitWidth())/warpDst; - if(y > world.unitHeight()) dy -= (y - world.unitHeight())/warpDst; + if(x < left) dx += (-(x - left)/warpDst); + if(y < bot) dy += (-(y - bot)/warpDst); + if(x > right) dx -= (x - right)/warpDst; + if(y > top) dy -= (y - top)/warpDst; velAddNet(dx * Time.delta, dy * Time.delta); } //clamp position if not flying if(isGrounded()){ - x = Mathf.clamp(x, 0, world.width() * tilesize - tilesize); - y = Mathf.clamp(y, 0, world.height() * tilesize - tilesize); + x = Mathf.clamp(x, left, right - tilesize); + y = Mathf.clamp(y, bot, top - tilesize); } //kill when out of bounds - if(x < -finalWorldBounds || y < -finalWorldBounds || x >= world.width() * tilesize + finalWorldBounds || y >= world.height() * tilesize + finalWorldBounds){ + if(x < -finalWorldBounds + left || y < -finalWorldBounds + bot || x >= right + finalWorldBounds || y >= top + finalWorldBounds){ kill(); } } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index bdf082beb6..edfb10387d 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -134,6 +134,10 @@ public class Rules{ public boolean coreIncinerates = false; /** If false, borders fade out into darkness. Only use with custom backgrounds!*/ public boolean borderDarkness = true; + /** If true, the map play area is cropped based on the rectangle below. */ + public boolean limitMapArea = false; + /** Map area limit rectangle. */ + public int limitX, limitY, limitWidth = 1, limitHeight = 1; /** special tags for additional info. */ public StringMap tags = new StringMap(); /** Name of callback to call for background rendering in mods; see Renderer#addCustomBackground. Runs last. */ diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 9a6880e01d..78417abadf 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -63,6 +63,7 @@ public class BlockRenderer{ blockTree = new BlockQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight())); floorTree = new FloorQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight())); shadowEvents.clear(); + updateFloors.clear(); lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated shadows.getTexture().setFilter(TextureFilter.linear, TextureFilter.linear); @@ -74,6 +75,12 @@ public class BlockRenderer{ Draw.color(blendShadowColor); for(Tile tile : world.tiles){ + recordIndex(tile); + + if(tile.floor().updateRender(tile)){ + updateFloors.add(new UpdateRenderState(tile, tile.floor())); + } + if(tile.block().hasShadow){ Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); } @@ -83,31 +90,7 @@ public class BlockRenderer{ Draw.color(); shadows.end(); - updateFloors.clear(); - dark.getTexture().setFilter(TextureFilter.linear); - dark.resize(world.width(), world.height()); - dark.begin(); - Core.graphics.clear(Color.white); - Draw.proj().setOrtho(0, 0, dark.getWidth(), dark.getHeight()); - - for(Tile tile : world.tiles){ - recordIndex(tile); - - if(tile.floor().updateRender(tile)){ - updateFloors.add(new UpdateRenderState(tile, tile.floor())); - } - - float darkness = world.getDarkness(tile.x, tile.y); - - if(darkness > 0){ - Draw.colorl(1f - Math.min((darkness + 0.5f) / 4f, 1f)); - Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); - } - } - - Draw.flush(); - Draw.color(); - dark.end(); + updateDarkness(); }); Events.on(TilePreChangeEvent.class, event -> { @@ -132,6 +115,42 @@ public class BlockRenderer{ }); } + public void updateDarkness(){ + darkEvents.clear(); + dark.getTexture().setFilter(TextureFilter.linear); + dark.resize(world.width(), world.height()); + dark.begin(); + + //fill darkness with black when map area is limited + Core.graphics.clear(state.rules.limitMapArea ? Color.black : Color.white); + Draw.proj().setOrtho(0, 0, dark.getWidth(), dark.getHeight()); + + //clear out initial starting area + if(state.rules.limitMapArea){ + Draw.color(Color.white); + Fill.crect(state.rules.limitX, state.rules.limitY, state.rules.limitWidth, state.rules.limitHeight); + } + + for(Tile tile : world.tiles){ + //skip lighting outside rect + if(state.rules.limitMapArea && !Rect.contains(state.rules.limitX, state.rules.limitY, state.rules.limitWidth - 1, state.rules.limitHeight - 1, tile.x, tile.y)){ + continue; + } + + float darkness = world.getDarkness(tile.x, tile.y); + + if(darkness > 0){ + float dark = 1f - Math.min((darkness + 0.5f) / 4f, 1f); + Draw.colorl(dark); + Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); + } + } + + Draw.flush(); + Draw.color(); + dark.end(); + } + public void invalidateTile(Tile tile){ int avgx = (int)(camera.position.x / tilesize); int avgy = (int)(camera.position.y / tilesize); diff --git a/core/src/mindustry/graphics/Pal.java b/core/src/mindustry/graphics/Pal.java index 73f8ccfe99..1780680b9d 100644 --- a/core/src/mindustry/graphics/Pal.java +++ b/core/src/mindustry/graphics/Pal.java @@ -132,5 +132,6 @@ public class Pal{ slagOrange = Color.valueOf("ffa166"), techBlue = Color.valueOf("8ca9e8"), - vent = Color.valueOf("6b4e4e"); + vent = Color.valueOf("6b4e4e"), + vent2 = Color.valueOf("261d1d"); } diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 1080fb1834..7c19944f7e 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -1269,11 +1269,15 @@ public class LExecutor{ public static class SetRuleI implements LInstruction{ public LogicRule rule = LogicRule.waveSpacing; - public int value; + public int value, p1, p2, p3, p4; - public SetRuleI(LogicRule rule, int value){ + public SetRuleI(LogicRule rule, int value, int p1, int p2, int p3, int p4){ this.rule = rule; this.value = value; + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + this.p4 = p4; } public SetRuleI(){ @@ -1291,11 +1295,62 @@ public class LExecutor{ case dropZoneRadius -> state.rules.dropZoneRadius = exec.numf(value) * 8f; case unitCap -> state.rules.unitCap = exec.numi(value); case lighting -> state.rules.lighting = exec.bool(value); + case mapArea -> { + int x = exec.numi(p1), y = exec.numi(p2), w = exec.numi(p3), h = exec.numi(p4); + if(!checkMapArea(x, y, w, h, false)){ + Call.setMapArea(x, y, w, h); + } + } case ambientLight -> state.rules.ambientLight.fromDouble(exec.num(value)); } } } + /** @return whether the map area is already set to this value. */ + static boolean checkMapArea(int x, int y, int w, int h, boolean set){ + x = Math.max(x, 0); + y = Math.max(y, 0); + w = Math.min(world.width(), w); + h = Math.min(world.height(), h); + boolean full = x == 0 && y == 0 && w == world.width() && h == world.height(); + + if(state.rules.limitMapArea){ + if(state.rules.limitX == x && state.rules.limitY == y && state.rules.limitWidth == w && state.rules.limitHeight == h){ + return true; + }else if(full){ + //disable the rule, covers the whole map + if(set){ + state.rules.limitMapArea = false; + if(!headless){ + renderer.updateAllDarkness(); + } + return false; + } + } + }else if(full){ //was already disabled, no need to change anything + return true; + } + + if(set){ + state.rules.limitMapArea = true; + state.rules.limitX = x; + state.rules.limitY = y; + state.rules.limitWidth = w; + state.rules.limitHeight = h; + + if(!headless){ + renderer.updateAllDarkness(); + } + } + + return false; + } + + @Remote(called = Loc.server) + public static void setMapArea(int x, int y, int w, int h){ + checkMapArea(x, y, w, h, true); + } + public static class FlushMessageI implements LInstruction{ public MessageType type = MessageType.announce; public int duration; diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 0375cfcedb..6472ece84f 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -1237,18 +1237,38 @@ public class LStatements{ @RegisterStatement("setrule") public static class SetRuleStatement extends LStatement{ public LogicRule rule = LogicRule.waveSpacing; - public String value = "100"; + public String value = "100", p1 = "0", p2 = "0", p3 = "100", p4 = "100"; @Override public void build(Table table){ + rebuild(table); + } + + void rebuild(Table table){ + table.clearChildren(); + table.button(b -> { b.label(() -> rule.name()).growX().wrap().labelAlign(Align.center); - b.clicked(() -> showSelect(b, LogicRule.all, rule, o -> rule = o, 2, c -> c.width(150f))); + b.clicked(() -> showSelect(b, LogicRule.all, rule, o -> { + rule = o; + rebuild(table); + }, 2, c -> c.width(150f))); }, Styles.logict, () -> {}).size(160f, 40f).pad(4f).color(table.color); table.add(" = "); - field(table, value, s -> value = s); + switch(rule){ + case mapArea -> { + fields(table, "x", p1, s -> p1 = s); + fields(table, "y", p2, s -> p2 = s); + row(table); + fields(table, "w", p3, s -> p3 = s); + fields(table, "h", p4, s -> p4 = s); + } + default -> { + field(table, value, s -> value = s); + } + } } @Override @@ -1263,7 +1283,7 @@ public class LStatements{ @Override public LInstruction build(LAssembler builder){ - return new SetRuleI(rule, builder.var(value)); + return new SetRuleI(rule, builder.var(value), builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4)); } } diff --git a/core/src/mindustry/logic/LogicRule.java b/core/src/mindustry/logic/LogicRule.java index d78aa9bc93..05ba622c34 100644 --- a/core/src/mindustry/logic/LogicRule.java +++ b/core/src/mindustry/logic/LogicRule.java @@ -9,6 +9,7 @@ public enum LogicRule{ enemyCoreBuildRadius, dropZoneRadius, unitCap, + mapArea, lighting, ambientLight; diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index 8d52f06252..e6322771db 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -173,7 +173,7 @@ public class CustomRulesDialog extends BaseDialog{ title("@rules.title.unit"); check("@rules.unitammo", b -> rules.unitAmmo = b, () -> rules.unitAmmo); check("@rules.unitcapvariable", b -> rules.unitCapVariable = b, () -> rules.unitCapVariable); - number("@rules.unitcap", true, f -> rules.unitCap = f, () -> rules.unitCap, -999, 999); + numberi("@rules.unitcap", f -> rules.unitCap = f, () -> rules.unitCap, -999, 999); number("@rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier); number("@rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier, 0.001f, 50f); @@ -194,6 +194,14 @@ public class CustomRulesDialog extends BaseDialog{ check("@rules.lighting", b -> rules.lighting = b, () -> rules.lighting); check("@rules.enemyLights", b -> rules.enemyLights = b, () -> rules.enemyLights); + if(experimental){ + check("@rules.limitarea", b -> rules.limitMapArea = b, () -> rules.limitMapArea); + numberi("x", x -> state.rules.limitX = x, () -> state.rules.limitX, () -> state.rules.limitMapArea, 0, 10000); + numberi("y", y -> state.rules.limitY = y, () -> state.rules.limitY, () -> state.rules.limitMapArea, 0, 10000); + numberi("w", w -> state.rules.limitWidth = w, () -> state.rules.limitWidth, () -> state.rules.limitMapArea, 0, 10000); + numberi("h", h -> state.rules.limitHeight = h, () -> state.rules.limitHeight, () -> state.rules.limitMapArea, 0, 10000); + } + main.button(b -> { b.left(); b.table(Tex.pane, in -> { @@ -270,14 +278,19 @@ public class CustomRulesDialog extends BaseDialog{ number(text, false, cons, prov, condition, 0, Float.MAX_VALUE); } - //TODO integer param unused - void number(String text, boolean integer, Intc cons, Intp prov, int min, int max){ + void numberi(String text, Intc cons, Intp prov, int min, int max){ + numberi(text, cons, prov, () -> true, min, max); + } + + void numberi(String text, Intc cons, Intp prov, Boolp condition, int min, int max){ main.table(t -> { t.left(); - t.add(text).left().padRight(5); + t.add(text).left().padRight(5) + .update(a -> a.setColor(condition.get() ? Color.white : Color.gray)); t.field((prov.get()) + "", s -> cons.get(Strings.parseInt(s))) - .padRight(100f) - .valid(f -> Strings.parseInt(f) >= min && Strings.parseInt(f) <= max).width(120f).left(); + .update(a -> a.setDisabled(!condition.get())) + .padRight(100f) + .valid(f -> Strings.parseInt(f) >= min && Strings.parseInt(f) <= max).width(120f).left(); }).padTop(0).row(); } diff --git a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java index 4210f9b915..4ad70944fd 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java @@ -10,7 +10,6 @@ import mindustry.world.meta.*; import static mindustry.Vars.*; /** A turret that fires a continuous beam with a delay between shots. Liquid coolant is required. Yes, this class name is awful. NEEDS RENAME */ -@Deprecated public class LaserTurret extends PowerTurret{ public float firingMoveFract = 0.25f; public float shootDuration = 100f; diff --git a/gradle.properties b/gradle.properties index 35fa9b9452..461ef6c3be 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,4 +24,4 @@ android.useAndroidX=true #used for slow jitpack builds; TODO see if this actually works org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 -archash=4775df2392 +archash=ea5e9c0c40