From 75946b9d143de2f0da78d61d998a6385384a9ec4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 3 Apr 2019 09:39:11 -0400 Subject: [PATCH] Explosion propagation --- .../io/anuke/mindustry/ai/WaveSpawner.java | 2 +- .../src/io/anuke/mindustry/core/Renderer.java | 9 +- .../io/anuke/mindustry/entities/Damage.java | 88 ++++++++++++++++--- 3 files changed, 82 insertions(+), 17 deletions(-) diff --git a/core/src/io/anuke/mindustry/ai/WaveSpawner.java b/core/src/io/anuke/mindustry/ai/WaveSpawner.java index f4aa3557ba..119c867403 100644 --- a/core/src/io/anuke/mindustry/ai/WaveSpawner.java +++ b/core/src/io/anuke/mindustry/ai/WaveSpawner.java @@ -97,7 +97,7 @@ public class WaveSpawner{ } Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawn.x * tilesize, spawn.y * tilesize)); //would be interesting to see player structures survive this without hacks - Time.run(40f, () -> Damage.damage(waveTeam, spawn.x * tilesize, spawn.y * tilesize, shockwaveBase + Mathf.random(shockwaveRand), 99999999f)); + Time.run(40f, () -> Damage.damage(waveTeam, spawn.x * tilesize, spawn.y * tilesize, shockwaveBase + Mathf.random(shockwaveRand), 99999999f, true)); } } } diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index 0bd9e89709..41a37cb3a5 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -331,8 +331,10 @@ public class Renderer implements ApplicationListener{ int w = world.width()*tilesize, h = world.height()*tilesize; - boolean isWater = settings.getBool("animatedwater"); - settings.put("animatedwater", false); + boolean hadShields = Core.settings.getBool("animatedshields"); + boolean hadWater = Core.settings.getBool("animatedwater"); + Core.settings.put("animatedwater", false); + Core.settings.put("animatedshields", false); FrameBuffer buffer = new FrameBuffer(w, h); @@ -366,7 +368,8 @@ public class Renderer implements ApplicationListener{ buffer.dispose(); - settings.put("animatedwater", isWater); + Core.settings.put("animatedwater", hadWater); + Core.settings.put("animatedshields", hadShields); } } diff --git a/core/src/io/anuke/mindustry/entities/Damage.java b/core/src/io/anuke/mindustry/entities/Damage.java index 6d78dc494b..8fe4eb0eff 100644 --- a/core/src/io/anuke/mindustry/entities/Damage.java +++ b/core/src/io/anuke/mindustry/entities/Damage.java @@ -1,22 +1,27 @@ package io.anuke.mindustry.entities; -import io.anuke.mindustry.entities.Effects.Effect; +import io.anuke.annotations.Annotations.Struct; +import io.anuke.arc.collection.GridBits; +import io.anuke.arc.collection.IntQueue; import io.anuke.arc.function.Consumer; import io.anuke.arc.function.Predicate; import io.anuke.arc.graphics.Color; import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.Geometry; +import io.anuke.arc.math.geom.Point2; import io.anuke.arc.math.geom.Rectangle; import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.util.Time; import io.anuke.mindustry.content.Bullets; import io.anuke.mindustry.content.Fx; +import io.anuke.mindustry.entities.Effects.Effect; import io.anuke.mindustry.entities.bullet.Bullet; import io.anuke.mindustry.entities.effect.Fire; import io.anuke.mindustry.entities.effect.Lightning; import io.anuke.mindustry.entities.type.Unit; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.gen.Call; +import io.anuke.mindustry.gen.PropCell; import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.world.Tile; @@ -27,6 +32,8 @@ public class Damage{ private static Rectangle rect = new Rectangle(); private static Rectangle hitrect = new Rectangle(); private static Vector2 tr = new Vector2(); + private static GridBits bits = new GridBits(30, 30); + private static IntQueue propagation = new IntQueue(); /**Creates a dynamic explosion based on specified parameters.*/ public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){ @@ -152,11 +159,16 @@ public class Damage{ /**Damages everything in a radius.*/ public static void damage(float x, float y, float radius, float damage){ - damage(null, x, y, radius, damage); + damage(null, x, y, radius, damage, false); } /**Damages all entities and blocks in a radius that are enemies of the team.*/ public static void damage(Team team, float x, float y, float radius, float damage){ + damage(team, x, y, radius, damage, false); + } + + /**Damages all entities and blocks in a radius that are enemies of the team.*/ + public static void damage(Team team, float x, float y, float radius, float damage, boolean complete){ Consumer cons = entity -> { if(entity.getTeam() == team || entity.dst(x, y) > radius){ return; @@ -175,25 +187,68 @@ public class Damage{ Units.getNearby(rect, cons); } - int trad = (int) (radius / tilesize); - Tile tile = world.tileWorld(x, y); - if(tile != null){ - tileDamage(tile.x, tile.y, trad); + if(!complete){ + int trad = (int)(radius / tilesize); + Tile tile = world.tileWorld(x, y); + if(tile != null){ + tileDamage(team, tile.x, tile.y, trad, damage); + } + }else{ + completeDamage(team, x, y, radius, damage); } - } - private static void tileDamage(int x, int y, int radius){ - /* + public static void tileDamage(Team team, int startx, int starty, int radius, float baseDamage){ + bits.clear(); + propagation.clear(); + int bitOffset = bits.width()/2; + + propagation.addFirst(PropCell.get((byte)0, (byte)0, (short)baseDamage)); + //clamp radius to fit bits + radius = Math.min(radius, bits.width()/2); + + while(!propagation.isEmpty()){ + int prop = propagation.removeLast(); + int x = PropCell.x(prop); + int y = PropCell.y(prop); + int damage = PropCell.damage(prop); + //manhattan distance used for calculating falloff, results in a diamond pattern + int dst = Math.abs(x) + Math.abs(y); + + int scaledDamage = (int)(damage * (1f - (float)dst / radius)); + + bits.set(bitOffset + x, bitOffset + y); + Tile tile = world.tile(startx + x, starty + y); + + if(scaledDamage <= 0 || tile == null) continue; + + //apply damage to entity if needed + if(tile.entity != null && tile.getTeam() != team){ + int health = (int)tile.entity.health; + tile.entity.damage(scaledDamage); + scaledDamage -= health; + + if(scaledDamage <= 0) continue; + } + + for(Point2 p : Geometry.d4){ + if(!bits.get(bitOffset + x + p.x, bitOffset + y + p.y)){ + propagation.addFirst(PropCell.get((byte)(x + p.x), (byte)(y + p.y), (short)scaledDamage)); + } + } + } + } + + private static void completeDamage(Team team, float x, float y, float radius, float damage){ + int trad = (int) (radius / tilesize); for(int dx = -trad; dx <= trad; dx++){ for(int dy = -trad; dy <= trad; dy++){ Tile tile = world.tile(Math.round(x / tilesize) + dx, Math.round(y / tilesize) + dy); - if(tile != null && tile.entity != null && (team == null || state.teams.areEnemies(team, tile.getTeam())) && Mathf.dst(dx, dy, 0, 0) <= trad){ - float amount = calculateDamage(x, y, tile.worldx(), tile.worldy(), radius, damage); - tile.entity.damage(amount); + if(tile != null && tile.entity != null && (team == null || state.teams.areEnemies(team, tile.getTeam())) && Mathf.dst(dx, dy) <= trad){ + tile.entity.damage(damage); } } - }*/ + } } private static float calculateDamage(float x, float y, float tx, float ty, float radius, float damage){ @@ -202,4 +257,11 @@ public class Damage{ float scaled = Mathf.lerp(1f - dist / radius, 1f, falloff); return damage * scaled; } + + @Struct + class PropCellStruct{ + byte x; + byte y; + short damage; + } }