From 0483e3f900e397b05572b57ac4f663f0c605b6e2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 30 Sep 2021 18:22:50 -0400 Subject: [PATCH] Serpulo naval wave support --- core/src/mindustry/game/Waves.java | 12 ++ .../maps/planet/SerpuloPlanetGenerator.java | 148 +++++++++++++++--- core/src/mindustry/type/UnitType.java | 3 +- .../world/blocks/environment/Floor.java | 2 + .../blocks/environment/ShallowLiquid.java | 1 + 5 files changed, 139 insertions(+), 27 deletions(-) diff --git a/core/src/mindustry/game/Waves.java b/core/src/mindustry/game/Waves.java index 8e7bf7a63c..848b4ecf96 100644 --- a/core/src/mindustry/game/Waves.java +++ b/core/src/mindustry/game/Waves.java @@ -265,10 +265,16 @@ public class Waves{ } public static Seq generate(float difficulty, Rand rand, boolean attack, boolean airOnly){ + return generate(difficulty, rand, attack, airOnly, false); + } + + public static Seq generate(float difficulty, Rand rand, boolean attack, boolean airOnly, boolean naval){ UnitType[][] species = { {dagger, mace, fortress, scepter, reign}, {nova, pulsar, quasar, vela, corvus}, {crawler, atrax, spiroct, arkyid, toxopid}, + {risso, minke, bryde, sei, omura}, + {risso, oxynoe, cyerce, aegires, navanax}, //retusa intentionally left out as it cannot damage the core properly {flare, horizon, zenith, rand.chance(0.5) ? quad : antumbra, rand.chance(0.1) ? quad : eclipse} }; @@ -276,6 +282,12 @@ public class Waves{ species = Structs.filter(UnitType[].class, species, v -> v[0].flying); } + if(naval){ + species = Structs.filter(UnitType[].class, species, v -> v[0].flying || v[0].naval); + }else{ + species = Structs.filter(UnitType[].class, species, v -> v[0].flying && !v[0].naval); + } + UnitType[][] fspec = species; //required progression: diff --git a/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java b/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java index adcc67c603..23047fd503 100644 --- a/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java +++ b/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java @@ -14,6 +14,7 @@ import mindustry.graphics.g3d.PlanetGrid.*; import mindustry.maps.generators.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; @@ -165,14 +166,14 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ connected.add(this); } - void con(int x1, int y1, int x2, int y2){ + void join(int x1, int y1, int x2, int y2){ float nscl = rand.random(100f, 140f) * 6f; int stroke = rand.random(3, 9); brush(pathfind(x1, y1, x2, y2, tile -> (tile.solid() ? 50f : 0f) + noise(tile.x, tile.y, 2, 0.4f, 1f / nscl) * 500, Astar.manhattan), stroke); } void connect(Room to){ - if(!connected.add(to)) return; + if(!connected.add(to) || to == this) return; Vec2 midpoint = Tmp.v1.set(to.x, to.y).add(x, y).scl(0.5f); rand.nextFloat(); @@ -188,8 +189,52 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ int mx = (int)midpoint.x, my = (int)midpoint.y; - con(x, y, mx, my); - con(mx, my, to.x, to.y); + join(x, y, mx, my); + join(mx, my, to.x, to.y); + } + + void joinLiquid(int x1, int y1, int x2, int y2){ + float nscl = rand.random(100f, 140f) * 6f; + int rad = rand.random(5, 10); + int avoid = 2 + rad; + var path = pathfind(x1, y1, x2, y2, tile -> (tile.solid() || !tile.floor().isLiquid ? 70f : 0f) + noise(tile.x, tile.y, 2, 0.4f, 1f / nscl) * 500, Astar.manhattan); + path.each(t -> { + //don't place liquid paths near the core + if(Mathf.dst2(t.x, t.y, x2, y2) <= avoid * avoid){ + return; + } + + for(int x = -rad; x <= rad; x++){ + for(int y = -rad; y <= rad; y++){ + int wx = t.x + x, wy = t.y + y; + if(Structs.inBounds(wx, wy, width, height) && Mathf.within(x, y, rad)){ + Tile other = tiles.getn(wx, wy); + other.setBlock(Blocks.air); + if(Mathf.within(x, y, rad - 1) && !other.floor().isLiquid){ + Floor floor = other.floor(); + //TODO does not respect tainted floors + other.setFloor((Floor)(floor == Blocks.sand || floor == Blocks.salt ? Blocks.sandWater : Blocks.darksandTaintedWater)); + } + } + } + } + }); + } + + void connectLiquid(Room to){ + if(to == this) return; + + Vec2 midpoint = Tmp.v1.set(to.x, to.y).add(x, y).scl(0.5f); + rand.nextFloat(); + + //add randomized offset to avoid straight lines + midpoint.add(Tmp.v2.setToRandomDirection(rand).scl(Tmp.v1.dst(x, y))); + midpoint.sub(width/2f, height/2f).limit(width / 2f / Mathf.sqrt3).add(width/2f, height/2f); + + int mx = (int)midpoint.x, my = (int)midpoint.y; + + joinLiquid(x, y, mx, my); + joinLiquid(mx, my, to.x, to.y); } } @@ -250,10 +295,12 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ } } + //clear radius around each room for(Room room : roomseq){ erase(room.x, room.y, room.radius); } + //randomly connect rooms together int connections = rand.random(Math.max(rooms - 1, 1), rooms + 3); for(int i = 0; i < connections; i++){ roomseq.random(rand).connect(roomseq.random(rand)); @@ -267,30 +314,29 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ cells(1); - //shoreline setup - int deepRadius = 4; + int tlen = tiles.width * tiles.height; + int total = 0, waters = 0; - pass((x, y) -> { - if(floor.asFloor().isLiquid && !floor.asFloor().isDeep()){ - - for(int cx = -deepRadius; cx <= deepRadius; cx++){ - for(int cy = -deepRadius; cy <= deepRadius; cy++){ - - if((cx) * (cx) + (cy) * (cy) <= deepRadius * deepRadius){ - int wx = cx + x, wy = cy + y; - - Tile tile = tiles.get(wx, wy); - if(tile != null && (!tile.floor().isLiquid || tile.block() != Blocks.air)){ - //found something solid, skip replacing anything - return; - } - } - } + for(int i = 0; i < tlen; i++){ + Tile tile = tiles.geti(i); + if(tile.block() == Blocks.air){ + total ++; + if(tile.floor().liquidDrop == Liquids.water){ + waters ++; } - - floor = floor == Blocks.darksandTaintedWater ? Blocks.taintedWater : Blocks.water; } - }); + } + + boolean naval = (float)waters / total >= 0.28f; + + Log.info(waters + " " + total ); + + //create water pathway if the map is flooded + if(naval){ + for(Room room : enemies){ + room.connectLiquid(spawn); + } + } distort(10f, 6f); @@ -318,6 +364,56 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ } }); + //shoreline setup + pass((x, y) -> { + int deepRadius = 3; + + if(floor.asFloor().isLiquid && floor.asFloor().shallow){ + + for(int cx = -deepRadius; cx <= deepRadius; cx++){ + for(int cy = -deepRadius; cy <= deepRadius; cy++){ + if((cx) * (cx) + (cy) * (cy) <= deepRadius * deepRadius){ + int wx = cx + x, wy = cy + y; + + Tile tile = tiles.get(wx, wy); + if(tile != null && (!tile.floor().isLiquid || tile.block() != Blocks.air)){ + //found something solid, skip replacing anything + return; + } + } + } + } + + floor = floor == Blocks.darksandTaintedWater ? Blocks.taintedWater : Blocks.water; + } + }); + + if(naval){ + int deepRadius = 2; + + //TODO code is very similar, but annoying to extract into a separate function + pass((x, y) -> { + if(floor.asFloor().isLiquid && !floor.asFloor().isDeep() && !floor.asFloor().shallow){ + + for(int cx = -deepRadius; cx <= deepRadius; cx++){ + for(int cy = -deepRadius; cy <= deepRadius; cy++){ + if((cx) * (cx) + (cy) * (cy) <= deepRadius * deepRadius){ + int wx = cx + x, wy = cy + y; + + Tile tile = tiles.get(wx, wy); + if(tile != null && (tile.floor().shallow || !tile.floor().isLiquid)){ + //found something shallow, skip replacing anything + return; + } + } + } + } + + floor = floor == Blocks.water ? Blocks.deepwater : Blocks.deepTaintedWater; + } + }); + } + Seq ores = Seq.with(Blocks.oreCopper, Blocks.oreLead); float poles = Math.abs(sector.tile.v.y); float nmag = 0.5f; @@ -555,7 +651,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ state.rules.enemyCoreBuildRadius = 600f; //spawn air only when spawn is blocked - state.rules.spawns = Waves.generate(difficulty, new Rand(sector.id), state.rules.attackMode, state.rules.attackMode && spawner.countGroundSpawns() == 0); + state.rules.spawns = Waves.generate(difficulty, new Rand(sector.id), state.rules.attackMode, state.rules.attackMode && spawner.countGroundSpawns() == 0, naval); } @Override diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index f9fcf6b078..895fcc1f15 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -111,7 +111,7 @@ public class UnitType extends UnlockableContent{ /** This is a VERY ROUGH estimate of unit DPS. */ public float dpsEstimate = -1; public float clipSize = -1; - public boolean canDrown = true; + public boolean canDrown = true, naval = false; public float engineOffset = 5f, engineSize = 2.5f; public float strafePenalty = 0.5f; public float hitSize = 6f; @@ -314,6 +314,7 @@ public class UnitType extends UnlockableContent{ //water preset if(example instanceof WaterMovec){ + naval = true; canDrown = false; omniMovement = false; immunities.add(StatusEffects.wet); diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index c2fa4c1165..ddad7804b3 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -48,6 +48,8 @@ public class Floor extends Block{ public float liquidMultiplier = 1f; /** whether this block is liquid. */ public boolean isLiquid; + /** shallow water flag used for generation */ + public boolean shallow = false; /** if true, this block cannot be mined by players. useful for annoying things like sand. */ public boolean playerUnmineable = false; /** Group of blocks that this block does not draw edges on. */ diff --git a/core/src/mindustry/world/blocks/environment/ShallowLiquid.java b/core/src/mindustry/world/blocks/environment/ShallowLiquid.java index bea6797f37..4ab54e1086 100644 --- a/core/src/mindustry/world/blocks/environment/ShallowLiquid.java +++ b/core/src/mindustry/world/blocks/environment/ShallowLiquid.java @@ -24,5 +24,6 @@ public class ShallowLiquid extends Floor{ status = liquidBase.status; liquidDrop = liquidBase.liquidDrop; cacheLayer = liquidBase.cacheLayer; + shallow = true; } }