diff --git a/core/assets-raw/sprites/blocks/power/neoplasia-reactor-bottom.png b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-bottom.png new file mode 100644 index 0000000000..c3eeda8e4c Binary files /dev/null and b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-bottom.png differ diff --git a/core/assets-raw/sprites/blocks/power/neoplasia-reactor-center.png b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-center.png new file mode 100644 index 0000000000..e26c3c877d Binary files /dev/null and b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-center.png differ diff --git a/core/assets-raw/sprites/blocks/power/neoplasia-reactor-glow.png b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-glow.png new file mode 100644 index 0000000000..88336542e8 Binary files /dev/null and b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-glow.png differ diff --git a/core/assets-raw/sprites/blocks/power/neoplasia-reactor-heat.png b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-heat.png new file mode 100644 index 0000000000..a5da4dbe49 Binary files /dev/null and b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-heat.png differ diff --git a/core/assets-raw/sprites/blocks/power/neoplasia-reactor-middle.png b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-middle.png new file mode 100644 index 0000000000..3b1e8154c6 Binary files /dev/null and b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-middle.png differ diff --git a/core/assets-raw/sprites/blocks/power/neoplasia-reactor-top1.png b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-top1.png new file mode 100644 index 0000000000..3d713dd948 Binary files /dev/null and b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-top1.png differ diff --git a/core/assets-raw/sprites/blocks/power/neoplasia-reactor-top2.png b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-top2.png new file mode 100644 index 0000000000..fe644e7923 Binary files /dev/null and b/core/assets-raw/sprites/blocks/power/neoplasia-reactor-top2.png differ diff --git a/core/assets-raw/sprites/blocks/power/neoplasia-reactor.png b/core/assets-raw/sprites/blocks/power/neoplasia-reactor.png new file mode 100644 index 0000000000..d13908e222 Binary files /dev/null and b/core/assets-raw/sprites/blocks/power/neoplasia-reactor.png differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 761d4926be..e1c7a888ee 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1673,6 +1673,7 @@ block.basic-assembler-module.name = Basic Assembler Module block.smite.name = Smite block.malign.name = Malign block.flux-reactor.name = Flux Reactor +block.neoplasia-reactor.name = Neoplasia Reactor block.switch.name = Switch block.micro-processor.name = Micro Processor diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index f590226e0b..27696878c3 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -578,3 +578,4 @@ 63106=shockwave-tower|block-shockwave-tower-ui 63105=heat-source|block-heat-source-ui 63104=flux-reactor|block-flux-reactor-ui +63103=neoplasia-reactor|block-neoplasia-reactor-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index c94f7ca2d0..d0aa922655 100644 Binary files a/core/assets/logicids.dat and b/core/assets/logicids.dat differ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 7dfa38d5a6..0a947143f8 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -36,6 +36,7 @@ import mindustry.world.consumers.*; import mindustry.world.draw.*; import mindustry.world.meta.*; +import static mindustry.Vars.*; import static mindustry.type.ItemStack.*; public class Blocks{ @@ -119,7 +120,7 @@ public class Blocks{ impactReactor, battery, batteryLarge, powerNode, powerNodeLarge, surgeTower, diode, //power - erekir - turbineCondenser, ventCondenser, chemicalCombustionChamber, pyrolysisGenerator, fluxReactor, + turbineCondenser, ventCondenser, chemicalCombustionChamber, pyrolysisGenerator, fluxReactor, neoplasiaReactor, beamNode, beamTower, beamLink, //production @@ -2374,7 +2375,6 @@ public class Blocks{ heating = 0.02f; consumeItem(Items.thorium); - //TODO how to non update consumeLiquid(Liquids.cryofluid, heating / coolantPower).update(false); }}; @@ -2507,6 +2507,7 @@ public class Blocks{ consumeLiquid(Liquids.cyanogen, 9f / 60f); liquidCapacity = 30f; + explosionMinWarmup = 0.5f; size = 5; @@ -2529,6 +2530,70 @@ public class Blocks{ ); }}; + //TODO stats + neoplasiaReactor = new HeaterGenerator("neoplasia-reactor"){{ + requirements(Category.power, with(Items.tungsten, 1000, Items.carbide, 300, Items.oxide, 150, Items.silicon, 500, Items.phaseFabric, 300, Items.surgeAlloy, 200)); + + size = 5; + liquidCapacity = 80f; + outputLiquid = new LiquidStack(Liquids.neoplasm, 20f / 60f); + explodeOnFull = true; + + heatOutput = 60f; + + //TODO arkycite, or nitrogen? both? Decide. + consumeLiquid(Liquids.arkycite, 80f / 60f); + consumeLiquid(Liquids.water, 10f / 60f); + consumeItem(Items.phaseFabric); + + itemDuration = 60f * 3f; + itemCapacity = 10; + + explosionRadius = 5; + explosionDamage = 500; + explodeEffect = new MultiEffect(Fx.bigShockwave, new WrapEffect(Fx.titanSmoke, Liquids.neoplasm.color), Fx.neoplasmSplat); + explodeSound = Sounds.explosionbig; + + powerProduction = 100f; + rebuildable = false; + + explosionPuddles = 80; + explosionPuddleRange = tilesize * 7f; + explosionPuddleLiquid = Liquids.neoplasm; + explosionPuddleAmount = 200f; + explosionMinWarmup = 0.5f; + + consumeEffect = new RadialEffect(Fx.neoplasiaSmoke, 4, 90f, 54f / 4f); + + drawer = new DrawMulti( + new DrawRegion("-bottom"), + new DrawLiquidTile(Liquids.arkycite, 3f), + new DrawCircles(){{ + color = Color.valueOf("feb380").a(0.8f); + strokeMax = 3.25f; + radius = 65f / 4f; + amount = 5; + timeScl = 200f; + }}, + + new DrawRegion("-center"), + + new DrawCells(){{ + color = Color.valueOf("c33e2b"); + particleColorFrom = Color.valueOf("e8803f"); + particleColorTo = Color.valueOf("8c1225"); + particles = 50; + range = 4f; + }}, + new DrawDefault(), + new DrawHeatOutput(), + new DrawGlowRegion("-glow"){{ + color = Color.valueOf("70170b"); + alpha = 0.7f; + }} + ); + }}; + //endregion power //region production diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index b04505be68..1b84922fec 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -470,6 +470,26 @@ public class Fx{ } }).layer(Layer.bullet - 1f), + neoplasmSplat = new Effect(400f, 300f, b -> { + float intensity = 3f; + + color(Pal.neoplasm1); + for(int i = 0; i < 4; i++){ + rand.setSeed(b.id*2 + i); + float lenScl = rand.random(0.5f, 1f); + int fi = i; + b.scaled(b.lifetime * lenScl, e -> { + randLenVectors(e.id + fi - 1, e.fin(Interp.pow10Out), (int)(5f * intensity), 22f * intensity, (x, y, in, out) -> { + float fout = e.fout(Interp.pow5Out) * rand.random(0.5f, 1f); + float rad = fout * ((2f + intensity) * 1.35f); + + Fill.circle(e.x + x, e.y + y, rad); + Drawf.light(e.x + x, e.y + y, rad * 2.5f, b.color, 0.5f); + }); + }); + } + }).layer(Layer.bullet - 2f), + scatheExplosion = new Effect(60f, 160f, e -> { color(e.color); stroke(e.fout() * 5f); @@ -1698,6 +1718,21 @@ public class Fx{ } }), + neoplasiaSmoke = new Effect(280f, e -> { + color(Pal.neoplasmMid); + alpha(0.6f); + + rand.setSeed(e.id); + for(int i = 0; i < 6; i++){ + float len = rand.random(10f), rot = rand.range(120f) + e.rotation; + + e.scaled(e.lifetime * rand.random(0.3f, 1f), b -> { + v.trns(rot, len * b.finpow()); + Fill.circle(e.x + v.x, e.y + v.y, 3.3f * b.fslope() + 0.2f); + }); + } + }), + heatReactorSmoke = new Effect(180f, e -> { color(Color.gray); diff --git a/core/src/mindustry/content/Liquids.java b/core/src/mindustry/content/Liquids.java index 90c194294a..d0189e9a9a 100644 --- a/core/src/mindustry/content/Liquids.java +++ b/core/src/mindustry/content/Liquids.java @@ -50,9 +50,9 @@ public class Liquids{ viscosity = 0.85f; flammability = 0f; capPuddles = false; - hidden = true; spreadTarget = Liquids.water; moveThroughBlocks = true; + incinerable = true; colorFrom = Color.valueOf("e8803f"); colorTo = Color.valueOf("8c1225"); diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 3e33b3231c..0f3a658652 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -47,7 +47,7 @@ public class Rules{ public boolean schematicsAllowed = true; /** Whether friendly explosions can occur and set fire/damage other blocks. */ public boolean damageExplosions = true; - /** Whether fire is enabled. */ + /** Whether fire (and neoplasm spread) is enabled. */ public boolean fire = true; /** Whether units use and require ammo. */ public boolean unitAmmo = false; diff --git a/core/src/mindustry/graphics/Pal.java b/core/src/mindustry/graphics/Pal.java index b10065fa90..2929741cf1 100644 --- a/core/src/mindustry/graphics/Pal.java +++ b/core/src/mindustry/graphics/Pal.java @@ -112,6 +112,7 @@ public class Pal{ neoplasmOutline = Color.valueOf("2e191d"), neoplasm1 = Color.valueOf("f98f4a"), + neoplasmMid = Color.valueOf("e05438"), neoplasm2 = Color.valueOf("9e172c"), logicBlocks = Color.valueOf("d4816b"), diff --git a/core/src/mindustry/type/CellLiquid.java b/core/src/mindustry/type/CellLiquid.java index 220953c3c0..0eb19b01fd 100644 --- a/core/src/mindustry/type/CellLiquid.java +++ b/core/src/mindustry/type/CellLiquid.java @@ -5,6 +5,7 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.util.*; +import mindustry.*; import mindustry.entities.*; import mindustry.gen.*; import mindustry.graphics.*; @@ -18,7 +19,7 @@ public class CellLiquid extends Liquid{ public int cells = 8; public @Nullable Liquid spreadTarget; - public float maxSpread = 0.5f, spreadConversion = 0.5f, spreadDamage = 0.1f; + public float maxSpread = 0.5f, spreadConversion = 1f, spreadDamage = 0.1f, removeScaling = 0.25f; public CellLiquid(String name, Color color){ super(name, color); @@ -30,20 +31,32 @@ public class CellLiquid extends Liquid{ @Override public void update(Puddle puddle){ + if(!Vars.state.rules.fire) return; + if(spreadTarget != null){ float scaling = Mathf.pow(Mathf.clamp(puddle.amount / maxLiquid), 2f); for(var point : Geometry.d4c){ Tile tile = puddle.tile.nearby(point); - if(tile != null && tile.build != null && tile.build.liquids != null && tile.build.liquids.get(spreadTarget) > 0){ + if(tile != null && tile.build != null && tile.build.liquids != null && tile.build.liquids.get(spreadTarget) > 0.0001f){ float amount = Math.min(tile.build.liquids.get(spreadTarget), maxSpread * Time.delta * scaling); - tile.build.liquids.remove(spreadTarget, amount); + tile.build.liquids.remove(spreadTarget, amount * removeScaling); Puddles.deposit(tile, this, amount * spreadConversion); } } //damage thing it is on - if(spreadDamage > 0 && puddle.tile.build != null && puddle.tile.build.liquids != null && puddle.tile.build.liquids.get(spreadTarget) > 0){ + if(spreadDamage > 0 && puddle.tile.build != null && puddle.tile.build.liquids != null && puddle.tile.build.liquids.get(spreadTarget) > 0.0001f){ + + //spread in 4 adjacent directions around thing it is on + float amountSpread = Math.min(puddle.tile.build.liquids.get(spreadTarget) * spreadConversion, maxSpread * Time.delta) / 2f; + for(var dir : Geometry.d4){ + Tile other = puddle.tile.nearby(dir); + if(other != null){ + Puddles.deposit(puddle.tile, other, puddle.liquid, amountSpread); + } + } + puddle.tile.build.damage(spreadDamage * Time.delta * scaling); } @@ -79,7 +92,7 @@ public class CellLiquid extends Liquid{ public void drawPuddle(Puddle puddle){ super.drawPuddle(puddle); - float baseLayer = puddle.tile != null && puddle.tile.build != null ? Layer.blockOver : Layer.debris - 0.5f; + float baseLayer = puddle.tile != null && puddle.tile.block().solid || puddle.tile.build != null ? Layer.blockOver : Layer.debris - 0.5f; int id = puddle.id; float amount = puddle.amount, x = puddle.x, y = puddle.y; diff --git a/core/src/mindustry/type/Liquid.java b/core/src/mindustry/type/Liquid.java index b76a595dda..9fb9259b64 100644 --- a/core/src/mindustry/type/Liquid.java +++ b/core/src/mindustry/type/Liquid.java @@ -47,6 +47,8 @@ public class Liquid extends UnlockableContent implements Senseable{ public boolean coolant = true; /** if true, this liquid can move through blocks as a puddle. */ public boolean moveThroughBlocks = false; + /** if true, this liquid can be incinerated in the incinerator block. */ + public boolean incinerable = true; /** The associated status effect. */ public StatusEffect effect = StatusEffects.none; /** Effect shown in puddles. */ diff --git a/core/src/mindustry/world/blocks/power/HeaterGenerator.java b/core/src/mindustry/world/blocks/power/HeaterGenerator.java new file mode 100644 index 0000000000..53350f9fd5 --- /dev/null +++ b/core/src/mindustry/world/blocks/power/HeaterGenerator.java @@ -0,0 +1,77 @@ +package mindustry.world.blocks.power; + +import arc.math.*; +import arc.util.io.*; +import mindustry.graphics.*; +import mindustry.ui.*; +import mindustry.world.blocks.heat.*; +import mindustry.world.draw.*; +import mindustry.world.meta.*; + +public class HeaterGenerator extends ConsumeGenerator{ + public float heatOutput = 10f; + public float warmupRate = 0.15f; + + public HeaterGenerator(String name){ + super(name); + + drawer = new DrawMulti(new DrawDefault(), new DrawHeatOutput()); + rotateDraw = false; + rotate = true; + canOverdrive = false; + drawArrow = true; + } + + @Override + public void setStats(){ + super.setStats(); + + stats.add(Stat.output, heatOutput, StatUnit.heatUnits); + } + + @Override + public boolean rotatedOutput(int x, int y){ + return false; + } + + @Override + public void setBars(){ + super.setBars(); + + addBar("heat", (HeaterGeneratorBuild entity) -> new Bar("bar.heat", Pal.lightOrange, () -> entity.heat / heatOutput)); + } + + public class HeaterGeneratorBuild extends ConsumeGeneratorBuild implements HeatBlock{ + public float heat; + + @Override + public void updateTile(){ + super.updateTile(); + + //heat approaches target at the same speed regardless of efficiency + heat = Mathf.approachDelta(heat, heatOutput * efficiency, warmupRate * delta()); + } + + @Override + public float heatFrac(){ + return heat / heatOutput; + } + + @Override + public float heat(){ + return heat; + } + + @Override + public void write(Writes write){ + super.write(write); + write.f(heat); + } + + @Override + public void read(Reads read, byte revision){ + super.read(read, revision); + heat = read.f(); + } + } +} diff --git a/core/src/mindustry/world/blocks/power/PowerGenerator.java b/core/src/mindustry/world/blocks/power/PowerGenerator.java index 9500de8030..4b23baae9f 100644 --- a/core/src/mindustry/world/blocks/power/PowerGenerator.java +++ b/core/src/mindustry/world/blocks/power/PowerGenerator.java @@ -35,6 +35,7 @@ public class PowerGenerator extends PowerDistributor{ public float explosionPuddleRange = tilesize * 2f; public float explosionPuddleAmount = 100f; public @Nullable Liquid explosionPuddleLiquid; + public float explosionMinWarmup = 0f; public float explosionShake = 0f, explosionShakeDuration = 6f; @@ -110,23 +111,25 @@ public class PowerGenerator extends PowerDistributor{ } public void createExplosion(){ - if(explosionDamage > 0){ - Damage.damage(x, y, explosionRadius * tilesize, explosionDamage); - } - - explodeEffect.at(this); - explodeSound.at(this); - - if(explosionPuddleLiquid != null){ - for(int i = 0; i < explosionPuddles; i++){ - Tmp.v1.trns(Mathf.random(360f), Mathf.random(explosionPuddleRange)); - Tile tile = world.tileWorld(x + Tmp.v1.x, y + Tmp.v1.y); - Puddles.deposit(tile, explosionPuddleLiquid, explosionPuddleAmount); + if(warmup() >= explosionMinWarmup){ + if(explosionDamage > 0){ + Damage.damage(x, y, explosionRadius * tilesize, explosionDamage); } - } - if(explosionShake > 0){ - Effect.shake(explosionShake, explosionShakeDuration, this); + explodeEffect.at(this); + explodeSound.at(this); + + if(explosionPuddleLiquid != null){ + for(int i = 0; i < explosionPuddles; i++){ + Tmp.v1.trns(Mathf.random(360f), Mathf.random(explosionPuddleRange)); + Tile tile = world.tileWorld(x + Tmp.v1.x, y + Tmp.v1.y); + Puddles.deposit(tile, explosionPuddleLiquid, explosionPuddleAmount); + } + } + + if(explosionShake > 0){ + Effect.shake(explosionShake, explosionShakeDuration, this); + } } } diff --git a/core/src/mindustry/world/blocks/production/Incinerator.java b/core/src/mindustry/world/blocks/production/Incinerator.java index 84b2a144f5..62f8fc573e 100644 --- a/core/src/mindustry/world/blocks/production/Incinerator.java +++ b/core/src/mindustry/world/blocks/production/Incinerator.java @@ -76,7 +76,7 @@ public class Incinerator extends Block{ @Override public boolean acceptLiquid(Building source, Liquid liquid){ - return heat > 0.5f; + return heat > 0.5f && liquid.incinerable; } } } diff --git a/core/src/mindustry/world/draw/DrawCells.java b/core/src/mindustry/world/draw/DrawCells.java index 9b08604c72..28e6b4078c 100644 --- a/core/src/mindustry/world/draw/DrawCells.java +++ b/core/src/mindustry/world/draw/DrawCells.java @@ -11,9 +11,10 @@ import mindustry.world.*; public class DrawCells extends DrawBlock{ public TextureRegion middle; + public Color color = Color.white.cpy(), particleColorFrom = Color.black.cpy(), particleColorTo = Color.black.cpy(); public int particles = 12; - public float range = 4f, recurrence = 6f, radius = 3f, lifetime = 60f; + public float range = 4f, recurrence = 2f, radius = 1.8f, lifetime = 60f * 3f; @Override public void draw(Building build){ @@ -38,7 +39,6 @@ public class DrawCells extends DrawBlock{ } Draw.color(); - Draw.rect(build.block.region, build.x, build.y); } @Override