diff --git a/core/assets-raw/sprites/blocks/defense/shockwave-tower-heat.png b/core/assets-raw/sprites/blocks/defense/shockwave-tower-heat.png new file mode 100644 index 0000000000..f949af1f2d Binary files /dev/null and b/core/assets-raw/sprites/blocks/defense/shockwave-tower-heat.png differ diff --git a/core/assets-raw/sprites/blocks/defense/shockwave-tower.png b/core/assets-raw/sprites/blocks/defense/shockwave-tower.png new file mode 100644 index 0000000000..dff1d43118 Binary files /dev/null and b/core/assets-raw/sprites/blocks/defense/shockwave-tower.png differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index c4f0726835..83a22a0561 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1563,6 +1563,7 @@ block.shielded-wall.name = Shielded Wall block.radar.name = Radar block.build-tower.name = Build Tower block.regen-projector.name = Regen Projector +block.shockwave-tower.name = Shockwave Tower block.shield-projector.name = Shield Projector block.large-shield-projector.name = Large Shield Projector block.armored-duct.name = Armored Duct diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index baa9a70758..b4df3089f8 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -575,3 +575,4 @@ 63109=underflow-duct|block-underflow-duct-ui 63108=malign|block-malign-ui 63107=smite|block-smite-ui +63106=shockwave-tower|block-shockwave-tower-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index a3f5da8dc8..d568dc3947 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 22bf2960f8..1f91e6c36f 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -92,7 +92,7 @@ public class Blocks{ //defense - erekir radar, buildTower, - regenProjector, barrierProjector, + regenProjector, barrierProjector, shockwaveTower, //campaign only shieldProjector, largeShieldProjector, @@ -1826,6 +1826,13 @@ public class Blocks{ consumePower(4f); }}; + shockwaveTower = new ShockwaveTower("shockwave-tower"){{ + requirements(Category.effect, with(Items.surgeAlloy, 50, Items.silicon, 150, Items.oxide, 30, Items.tungsten, 100)); + size = 3; + consumeLiquids(LiquidStack.with(Liquids.cyanogen, 1f / 60f)); + consumePower(80f / 60f); + }}; + //TODO 5x5?? shieldProjector = new BaseShield("shield-projector"){{ requirements(Category.effect, BuildVisibility.editorOnly, with()); diff --git a/core/src/mindustry/content/ErekirTechTree.java b/core/src/mindustry/content/ErekirTechTree.java index 759fb8e3e2..23c8c06d7a 100644 --- a/core/src/mindustry/content/ErekirTechTree.java +++ b/core/src/mindustry/content/ErekirTechTree.java @@ -161,7 +161,9 @@ public class ErekirTechTree{ node(regenProjector, () -> { //TODO more tiers of build tower or "support" structures like overdrive projectors node(buildTower, Seq.with(new OnSector(four)), () -> { + node(shockwaveTower, () -> { + }); }); }); }); diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index c1b50d78af..3a5ee1ed08 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -198,6 +198,14 @@ public class Fx{ rect(block.fullIcon, e.x, e.y); }).layer(Layer.turret - 5f), + pointShockwave = new Effect(20, e -> { + color(e.color); + stroke(e.fout() * 2f); + Lines.circle(e.x, e.y, e.finpow() * e.rotation); + randLenVectors(e.id + 1, 8, 1f + 23f * e.finpow(), (x, y) -> + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f)); + }), + moveCommand = new Effect(20, e -> { color(Pal.command); stroke(e.fout() * 5f); diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index a6df7dcac6..cb10027821 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -11,7 +11,6 @@ import mindustry.*; import mindustry.annotations.Annotations.*; import mindustry.ctype.*; import mindustry.gen.*; -import mindustry.graphics.*; import mindustry.logic.LCanvas.*; import mindustry.logic.LExecutor.*; import mindustry.type.*; @@ -1264,7 +1263,7 @@ public class LStatements{ fields(table, unit, str -> unit = str); - if(!clear){ + if(!clear && !(content.statusEffect(effect) != null && content.statusEffect(effect).permanent)){ table.add(" for "); diff --git a/core/src/mindustry/world/blocks/defense/ShockwaveTower.java b/core/src/mindustry/world/blocks/defense/ShockwaveTower.java new file mode 100644 index 0000000000..ec93ed7de6 --- /dev/null +++ b/core/src/mindustry/world/blocks/defense/ShockwaveTower.java @@ -0,0 +1,118 @@ +package mindustry.world.blocks.defense; + +import arc.math.*; +import arc.util.*; +import arc.struct.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.audio.*; +import mindustry.content.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.world.meta.*; +import mindustry.world.*; +import mindustry.entities.*; +import mindustry.annotations.Annotations.Load; + +import static mindustry.Vars.*; + +public class ShockwaveTower extends Block{ + public int timerCheck = timers ++; + + public float range = 90f; + public float reload = 60f * 2f; + public float bulletDamage = 150; + public float falloffCount = 20f; + public float shake = 2f; + //checking for bullets every frame is costly, so only do it at intervals even when ready. + public float checkInterval = 8f; + public Sound shootSound = Sounds.bang; + public Color waveColor = Pal.accent, heatColor = Pal.turretHeat, shapeColor = Color.valueOf("f29c83"); + public float cooldownMultiplier = 1f; + public Effect waveEffect = Fx.pointShockwave; + + public float shapeRotateSpeed = 1f, shapeRadius = 6f; + public int shapeSides = 4; + + public @Load("@-heat") TextureRegion heatRegion; + + public ShockwaveTower(String name){ + super(name); + update = true; + solid = true; + } + + @Override + public void setStats(){ + super.setStats(); + + stats.add(Stat.damage, bulletDamage, StatUnit.none); + stats.add(Stat.range, range / tilesize, StatUnit.blocks); + stats.add(Stat.reload, 60f / reload, StatUnit.perSecond); + } + + @Override + public void drawPlace(int x, int y, int rotation, boolean valid){ + super.drawPlace(x, y, rotation, valid); + + Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, waveColor); + } + + public class ShockwaveTowerBuild extends Building{ + public float reloadCounter = Mathf.random(reload); + public float heat = 0f; + public Seq targets = new Seq<>(); + + @Override + public void updateTile(){ + if(potentialEfficiency > 0 && (reloadCounter += Time.delta) >= reload && timer(timerCheck, checkInterval)){ + targets.clear(); + Groups.bullet.intersect(x - range, y - range, range * 2, range * 2, b -> { + if(b.team != team && b.type.hittable){ + targets.add(b); + } + }); + + if(targets.size > 0){ + heat = 1f; + reloadCounter = 0f; + waveEffect.at(x, y, range, waveColor); + shootSound.at(this); + Effect.shake(shake, shake, this); + float waveDamage = Math.min(bulletDamage, bulletDamage * falloffCount / targets.size); + + for(var target : targets){ + if(target.damage > waveDamage){ + target.damage -= waveDamage; + }else{ + target.remove(); + } + } + } + } + + heat = Mathf.clamp(heat - Time.delta / reload * cooldownMultiplier); + } + + @Override + public float warmup(){ + return heat; + } + + @Override + public boolean shouldConsume(){ + return targets.size != 0; + } + + @Override + public void draw(){ + super.draw(); + Drawf.additive(heatRegion, heatColor, heat, x, y, 0f, Layer.blockAdditive); + + Draw.z(Layer.effect); + Draw.color(shapeColor, waveColor, Mathf.pow(heat, 2f)); + Fill.poly(x, y, shapeSides, shapeRadius * potentialEfficiency, Time.time * shapeRotateSpeed); + Draw.color(); + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 1ecdb11d3e..77ed3793fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=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=29a4391826 +archash=b1b88883e2 diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index b5702a9945..c15bf06a22 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -382,7 +382,7 @@ public class Generators{ save(image, "../editor/" + block.name + "-icon-editor"); if(block.buildVisibility != BuildVisibility.hidden){ - saveScaled(image, block.name + "-icon-logic", logicIconSize); + saveScaled(image, block.name + "-icon-logic", Math.min(32 * 3, image.width)); } saveScaled(image, "../ui/block-" + block.name + "-ui", Math.min(image.width, maxUiIcon));