From bece87c79042d249035166adb124be564f551ecf Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 16 Apr 2018 17:32:35 -0400 Subject: [PATCH] Implemented puddles of liquid --- core/assets/version.properties | 4 +- .../io/anuke/mindustry/content/Liquids.java | 6 +- .../content/bullets/TurretBullets.java | 16 ++ .../mindustry/content/fx/EnvironmentFx.java | 10 ++ .../anuke/mindustry/entities/effect/Fire.java | 21 ++- .../mindustry/entities/effect/Puddle.java | 163 ++++++++++++++++++ .../io/anuke/mindustry/resource/Liquid.java | 4 + .../io/anuke/mindustry/world/BaseBlock.java | 7 +- .../blocks/types/distribution/Conduit.java | 2 +- .../types/distribution/LiquidBridge.java | 2 +- .../distribution/LiquidExtendingBridge.java | 2 +- 11 files changed, 227 insertions(+), 10 deletions(-) create mode 100644 core/src/io/anuke/mindustry/entities/effect/Puddle.java diff --git a/core/assets/version.properties b/core/assets/version.properties index acb9ef8dd5..58fcb54a5c 100644 --- a/core/assets/version.properties +++ b/core/assets/version.properties @@ -1,7 +1,7 @@ #Autogenerated file. Do not modify. -#Sun Apr 15 22:39:16 EDT 2018 +#Mon Apr 16 17:31:30 EDT 2018 version=release -androidBuildCode=927 +androidBuildCode=928 name=Mindustry code=3.5 build=custom build diff --git a/core/src/io/anuke/mindustry/content/Liquids.java b/core/src/io/anuke/mindustry/content/Liquids.java index 1920495cca..f841d6bfce 100644 --- a/core/src/io/anuke/mindustry/content/Liquids.java +++ b/core/src/io/anuke/mindustry/content/Liquids.java @@ -11,12 +11,14 @@ public class Liquids { water = new Liquid("water", Color.valueOf("486acd")) { { heatCapacity = 0.4f; + effect = StatusEffects.wet; } }, lava = new Liquid("lava", Color.valueOf("e37341")) { { - temperature = 0.7f; + temperature = 0.8f; viscosity = 0.8f; + effect = StatusEffects.melting; } }, oil = new Liquid("oil", Color.valueOf("313131")) { @@ -24,12 +26,14 @@ public class Liquids { viscosity = 0.7f; flammability = 0.6f; explosiveness = 0.6f; + effect = StatusEffects.oiled; } }, cryofluid = new Liquid("cryofluid", Color.SKY) { { heatCapacity = 0.75f; temperature = 0.5f; + effect = StatusEffects.freezing; } }; } diff --git a/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java b/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java index 53064e2a37..1f4d4d74c2 100644 --- a/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java +++ b/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java @@ -1,6 +1,7 @@ package io.anuke.mindustry.content.bullets; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.GridPoint2; import io.anuke.mindustry.content.Liquids; import io.anuke.mindustry.content.StatusEffects; import io.anuke.mindustry.content.fx.BulletFx; @@ -8,7 +9,9 @@ import io.anuke.mindustry.content.fx.Fx; import io.anuke.mindustry.entities.Bullet; import io.anuke.mindustry.entities.BulletType; import io.anuke.mindustry.entities.effect.DamageArea; +import io.anuke.mindustry.entities.effect.Fire; import io.anuke.mindustry.entities.effect.Lightning; +import io.anuke.mindustry.entities.effect.Puddle; import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.resource.Liquid; import io.anuke.ucore.core.Effects; @@ -16,8 +19,12 @@ import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Fill; import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Angles; +import io.anuke.ucore.util.Geometry; import io.anuke.ucore.util.Mathf; +import static io.anuke.mindustry.Vars.tilesize; +import static io.anuke.mindustry.Vars.world; + public class TurretBullets { public static final BulletType @@ -220,6 +227,15 @@ public class TurretBullets { @Override public void hit(Bullet b, float hitx, float hity) { Effects.effect(hiteffect, liquid.color, hitx, hity); + Puddle.deposit(world.tileWorld(hitx, hity), liquid, 5f); + + if(liquid.temperature <= 0.5f && liquid.flammability < 0.3f){ + float intensity = 400f; + Fire.extinguish(world.tileWorld(hitx, hity), intensity); + for(GridPoint2 p : Geometry.d4){ + Fire.extinguish(world.tileWorld(hitx + p.x*tilesize, hity + p.y*tilesize), intensity); + } + } } } } diff --git a/core/src/io/anuke/mindustry/content/fx/EnvironmentFx.java b/core/src/io/anuke/mindustry/content/fx/EnvironmentFx.java index 383eaa534b..d513637067 100644 --- a/core/src/io/anuke/mindustry/content/fx/EnvironmentFx.java +++ b/core/src/io/anuke/mindustry/content/fx/EnvironmentFx.java @@ -43,6 +43,16 @@ public class EnvironmentFx { Draw.color(); }), + steam = new Effect(35f, e -> { + Draw.color(Color.LIGHT_GRAY); + + Angles.randLenVectors(e.id, 2, 2f + e.fin()*7f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); + }); + + Draw.color(); + }), + fireballsmoke = new Effect(25f, e -> { Draw.color(Color.GRAY); diff --git a/core/src/io/anuke/mindustry/entities/effect/Fire.java b/core/src/io/anuke/mindustry/entities/effect/Fire.java index 2b9ce29f07..36902ce329 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Fire.java +++ b/core/src/io/anuke/mindustry/entities/effect/Fire.java @@ -18,7 +18,7 @@ public class Fire extends TimedEntity { private static GridMap map = new GridMap<>(); private Tile tile; - private float flammability = -1; + private float baseFlammability = -1, puddleFlammability; public static void create(Tile tile){ if(!map.containsKey(tile.x, tile.y)){ @@ -26,6 +26,12 @@ public class Fire extends TimedEntity { } } + public static void extinguish(Tile tile, float intensity){ + if(map.containsKey(tile.x, tile.y)){ + map.get(tile.x, tile.y).time += intensity * Timers.delta(); + } + } + private Fire(Tile tile){ this.tile = tile; lifetime = 1000f; @@ -38,12 +44,14 @@ public class Fire extends TimedEntity { TileEntity entity = tile.target().entity; boolean damage = entity != null; + float flammability = baseFlammability + puddleFlammability; + if(!damage && flammability <= 0){ time += Timers.delta()*8; } - if (flammability < 0){ - flammability = tile.block().getFlammability(tile); + if (baseFlammability < 0){ + baseFlammability = tile.block().getFlammability(tile); } if(damage) { @@ -59,6 +67,13 @@ public class Fire extends TimedEntity { if(Mathf.chance(0.1 * Timers.delta())){ Effects.effect(EnvironmentFx.fire, tile.worldx() + Mathf.range(4f), tile.worldy() + Mathf.range(4f)); + Puddle p = Puddle.getPuddle(tile); + if(p != null){ + puddleFlammability = p.getFlammability()/3f; + }else{ + puddleFlammability = 0; + } + if(damage){ entity.damage(0.4f); } diff --git a/core/src/io/anuke/mindustry/entities/effect/Puddle.java b/core/src/io/anuke/mindustry/entities/effect/Puddle.java new file mode 100644 index 0000000000..722341da38 --- /dev/null +++ b/core/src/io/anuke/mindustry/entities/effect/Puddle.java @@ -0,0 +1,163 @@ +package io.anuke.mindustry.entities.effect; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.GridPoint2; +import com.badlogic.gdx.math.Rectangle; +import io.anuke.mindustry.Vars; +import io.anuke.mindustry.content.blocks.Blocks; +import io.anuke.mindustry.content.fx.BlockFx; +import io.anuke.mindustry.content.fx.EnvironmentFx; +import io.anuke.mindustry.entities.Units; +import io.anuke.mindustry.resource.Liquid; +import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Effects; +import io.anuke.ucore.core.Timers; +import io.anuke.ucore.entities.Entity; +import io.anuke.ucore.graphics.Draw; +import io.anuke.ucore.graphics.Fill; +import io.anuke.ucore.graphics.Hue; +import io.anuke.ucore.util.Angles; +import io.anuke.ucore.util.Geometry; +import io.anuke.ucore.util.GridMap; +import io.anuke.ucore.util.Mathf; + +import static io.anuke.mindustry.Vars.world; + +public class Puddle extends Entity { + private static final GridMap map = new GridMap<>(); + private static final float maxLiquid = 70f; + private static final int maxGeneration = 2; + private static final Color tmp = new Color(); + private static final Rectangle rect = new Rectangle(); + + private Tile tile; + private Liquid liquid; + private float amount; + private int generation; + private float accepting; + + public static void deposit(Tile tile, Tile source, Liquid liquid, float amount){ + deposit(tile, source, liquid, amount, 0); + } + + public static void deposit(Tile tile, Liquid liquid, float amount){ + deposit(tile, tile, liquid, amount, 0); + } + + public static Puddle getPuddle(Tile tile){ + return map.get(tile.x, tile.y); + } + + private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){ + Puddle p = map.get(tile.x, tile.y); + if(p == null){ + Puddle puddle = new Puddle(tile, source, liquid, amount, generation).add(); + map.put(tile.x, tile.y, puddle); + }else if(p.liquid == liquid){ + p.accepting = Math.max(amount, p.accepting); + + if(generation == 0 && Timers.get(p, "ripple", 50) && p.amount >= maxLiquid/2f){ + Effects.effect(BlockFx.ripple, p.liquid.color, (tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f); + } + }else{ + reactPuddle(p, liquid, amount); + } + } + + private static void reactPuddle(Puddle p, Liquid liquid, float amount){ + if((p.liquid.flammability > 0.3f && liquid.temperature > 0.7f) || + liquid.flammability > 0.3f && p.liquid.temperature > 0.7f){ //flammable liquid + hot liquid + Fire.create(p.tile); + if(Mathf.chance(0.006 * amount)){ + new Fireball(p.x, p.y, p.liquid.flameColor, Mathf.random(360f)).add(); + } + }else if(p.liquid.temperature > 0.7f && liquid.temperature < 0.55f){ //cold liquid poured onto hot puddle + if(Mathf.chance(0.5f * amount)){ + Effects.effect(EnvironmentFx.steam, p.x, p.y); + } + p.amount -= 0.1f * amount; + }else if(liquid.temperature > 0.7f && p.liquid.temperature < 0.55f){ //hot liquid poured onto cold puddle + if(Mathf.chance(0.8f * amount)){ + Effects.effect(EnvironmentFx.steam, p.x, p.y); + } + p.amount -= 0.4f * amount; + } + } + + private Puddle(Tile tile, Tile source, Liquid liquid, float amount, int generation) { + this.tile = tile; + this.liquid = liquid; + this.amount = amount; + this.generation = generation; + set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f); + } + + public float getFlammability(){ + return liquid.flammability * amount; + } + + @Override + public void update() { + float addSpeed = accepting > 0 ? 3f : 0f; + + amount -= Timers.delta() * (1f - liquid.viscosity) /(5f+addSpeed); + + amount += accepting; + accepting = 0f; + + if(amount >= maxLiquid/1.5f && generation < maxGeneration){ + float deposited = Math.min((amount - maxLiquid/1.5f)/4f, 0.3f) * Timers.delta(); + for(GridPoint2 point : Geometry.d4){ + Tile other = world.tile(tile.x + point.x, tile.y + point.y); + if(other.block() == Blocks.air){ + deposit(other, tile, liquid, deposited, generation + 1); + amount -= deposited/4f; + } + } + } + + if(amount >= maxLiquid/2f && Timers.get(this, "update", 20)){ + Units.getNearby(rect.setSize(Mathf.clamp(amount/(maxLiquid/1.5f))*10f).setCenter(tile.worldx(), tile.worldy()), unit -> { + Rectangle o = unit.hitbox.getRect(unit.x, unit.y); + if(!rect.overlaps(o)) return; + + unit.applyEffect(liquid.effect, 0.5f); + if(unit.velocity.len() > 0.4) { + Effects.effect(BlockFx.ripple, liquid.color, unit.x, unit.y); + } + }); + + if(liquid.temperature > 0.7f && tile.entity != null && Mathf.chance(0.3 * Timers.delta())){ + Fire.create(tile); + } + } + + amount = Mathf.clamp(amount, 0, maxLiquid); + + if(amount <= 0f){ + remove(); + } + } + + @Override + public void draw() { + float f = Mathf.clamp(amount/(maxLiquid/1.5f)); + + Draw.color(Hue.shift(tmp.set(liquid.color), 2, -0.05f)); + Fill.circle(x, y, f * 8f); + Angles.randLenVectors(id, 3, f * 6f, (ex, ey) -> { + Fill.circle(x + ex, y + ey, f * 5f); + }); + Draw.color(); + } + + @Override + public void removed() { + map.remove(tile.x, tile.y); + } + + @Override + public Puddle add() { + return add(Vars.groundEffectGroup); + } +} diff --git a/core/src/io/anuke/mindustry/resource/Liquid.java b/core/src/io/anuke/mindustry/resource/Liquid.java index ade5e84141..605888b735 100644 --- a/core/src/io/anuke/mindustry/resource/Liquid.java +++ b/core/src/io/anuke/mindustry/resource/Liquid.java @@ -2,6 +2,8 @@ package io.anuke.mindustry.resource; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.content.StatusEffects; +import io.anuke.mindustry.entities.StatusEffect; import io.anuke.ucore.util.Bundles; public class Liquid { @@ -24,6 +26,8 @@ public class Liquid { public float explosiveness; /**the burning color of this liquid*/ public Color flameColor = Color.valueOf("ffb763"); + /**The associated status effect.*/ + public StatusEffect effect = StatusEffects.none; public Liquid(String name, Color color) { this.name = name; diff --git a/core/src/io/anuke/mindustry/world/BaseBlock.java b/core/src/io/anuke/mindustry/world/BaseBlock.java index 26114b1bfa..5e1ed1e2a8 100644 --- a/core/src/io/anuke/mindustry/world/BaseBlock.java +++ b/core/src/io/anuke/mindustry/world/BaseBlock.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.world; import com.badlogic.gdx.math.GridPoint2; import io.anuke.mindustry.entities.Unit; +import io.anuke.mindustry.entities.effect.Puddle; import io.anuke.mindustry.resource.Item; import io.anuke.mindustry.resource.Liquid; import io.anuke.ucore.util.Mathf; @@ -108,7 +109,7 @@ public abstract class BaseBlock { } } - public float tryMoveLiquid(Tile tile, Tile next){ + public float tryMoveLiquid(Tile tile, Tile next, boolean leak){ if(next == null) return 0; next = next.target(); @@ -132,6 +133,10 @@ public abstract class BaseBlock { tile.entity.liquid.amount -= amount; return flow; } + }else if(leak && !next.block().solid && !next.block().hasLiquids){ + float leakAmount = Math.min(tile.entity.liquid.amount, tile.entity.liquid.amount/1.5f); + Puddle.deposit(next, tile, tile.entity.liquid.liquid, leakAmount); + tile.entity.liquid.amount -= leakAmount; } return 0; } diff --git a/core/src/io/anuke/mindustry/world/blocks/types/distribution/Conduit.java b/core/src/io/anuke/mindustry/world/blocks/types/distribution/Conduit.java index bf795f065c..2635afdb7f 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/distribution/Conduit.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/distribution/Conduit.java @@ -46,7 +46,7 @@ public class Conduit extends LiquidBlock { entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquid.amount/liquidCapacity, 0.05f); if(tile.entity.liquid.amount > 0.001f && tile.entity.timer.get(timerFlow, 1)){ - tryMoveLiquid(tile, tile.getNearby(tile.getRotation())); + tryMoveLiquid(tile, tile.getNearby(tile.getRotation()), true); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/types/distribution/LiquidBridge.java b/core/src/io/anuke/mindustry/world/blocks/types/distribution/LiquidBridge.java index 494a265f8e..3a7f027270 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/distribution/LiquidBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/distribution/LiquidBridge.java @@ -37,7 +37,7 @@ public class LiquidBridge extends ItemBridge { if(entity.uptime >= 0.5f){ - if(tryMoveLiquid(tile, other) > 0.1f){ + if(tryMoveLiquid(tile, other, false) > 0.1f){ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f); diff --git a/core/src/io/anuke/mindustry/world/blocks/types/distribution/LiquidExtendingBridge.java b/core/src/io/anuke/mindustry/world/blocks/types/distribution/LiquidExtendingBridge.java index 7d8977867a..156aec32d7 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/distribution/LiquidExtendingBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/distribution/LiquidExtendingBridge.java @@ -37,7 +37,7 @@ public class LiquidExtendingBridge extends ExtendingItemBridge { if(entity.uptime >= 0.5f){ - if(tryMoveLiquid(tile, other) > 0.1f){ + if(tryMoveLiquid(tile, other, false) > 0.1f){ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f);