diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 0180e4b1c5..b005736a58 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -965,6 +965,7 @@ status.overdrive.name = Overdrive status.overclock.name = Overclock status.shocked.name = Shocked status.blasted.name = Blasted +status.corroded.name = Corroded status.unmoving.name = Unmoving status.boss.name = Guardian diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 18b24eefca..eadd6bd72e 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -4392,7 +4392,7 @@ public class Blocks{ hitEffect = despawnEffect = Fx.hitSquaresColor; buildingDamageMultiplier = 0.2f; }}, - Items.oxide, new BasicBulletType(8f, 120){{ + Items.oxide, new BasicBulletType(8f, 90){{ knockback = 3f; width = 25f; hitSize = 7f; @@ -4655,15 +4655,13 @@ public class Blocks{ reloadMultiplier = 0.65f; splashDamageRadius = 110f; rangeChange = 8f; - splashDamage = 300f; + splashDamage = 150f; scaledSplashDamage = true; hitColor = backColor = trailColor = Color.valueOf("a0b380"); frontColor = Color.valueOf("e4ffd6"); ammoMultiplier = 1f; hitSound = Sounds.titanExplosion; - status = StatusEffects.blasted; - trailLength = 32; trailWidth = 3.35f; trailSinScl = 2.5f; @@ -4679,23 +4677,8 @@ public class Blocks{ shrinkX = 0.2f; shrinkY = 0.1f; buildingDamageMultiplier = 0.25f; - - fragBullets = 1; - fragBullet = new EmptyBulletType(){{ - lifetime = 60f * 2.5f; - bulletInterval = 20f; - intervalBullet = new EmptyBulletType(){{ - splashDamage = 30f; - collidesGround = true; - collidesAir = false; - collides = false; - hitEffect = Fx.none; - pierce = true; - instantDisappear = true; - splashDamageRadius = 90f; - buildingDamageMultiplier = 0.2f; - }}; - }}; + status = StatusEffects.corroded; + statusDuration = 300f; }} ); @@ -4932,8 +4915,8 @@ public class Blocks{ }}; afflict = new PowerTurret("afflict"){{ - requirements(Category.turret, with(Items.surgeAlloy, 125, Items.silicon, 200, Items.graphite, 250, Items.oxide, 40)); - buildCostMultiplier = 1.5f; + requirements(Category.turret, with(Items.surgeAlloy, 100, Items.silicon, 200, Items.graphite, 250, Items.oxide, 40)); + buildCostMultiplier = 1f; shootType = new BasicBulletType(){{ shootEffect = new MultiEffect(Fx.shootTitan, new WaveEffect(){{ diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 29a2f0c66b..6ab1d3e377 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -458,7 +458,7 @@ public class Fx{ Lines.lineAngle(e.x, e.y, angle, e.foutpow() * 50f * rand.random(1f, 0.6f) + 2f, e.finpow() * 100f * lenRand + 6f); } }), - + titanExplosionSmall = new Effect(22f, 120f, e -> { color(e.color); stroke(e.fout() * 3f); @@ -1398,6 +1398,15 @@ public class Fx{ }); }).layer(Layer.bullet - 1f), + corrosionVapor = new Effect(50f, e -> { + color(e.color); + alpha(Interp.pow2Out.apply(e.fslope()) * 0.5f); + + randLenVectors(e.id, 2, 8f + e.finpow() * 3f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 3f); + }); + }), + vapor = new Effect(110f, e -> { color(e.color); alpha(e.fout()); diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index 1ccaabc80f..7e9466f2d6 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -191,8 +191,12 @@ public class StatusEffects{ }}; corroded = new StatusEffect("corroded"){{ - color = Pal.plastanium; - damage = 0.1f; + color = Color.valueOf("e4ffd6"); + intervalDamage = 25f; + intervalDamageTime = 30f; + + effectChance = 0.1f; + effect = Fx.corrosionVapor; }}; disarmed = new StatusEffect("disarmed"){{ diff --git a/core/src/mindustry/entities/comp/StatusComp.java b/core/src/mindustry/entities/comp/StatusComp.java index a361ce68a8..404c65d1ad 100644 --- a/core/src/mindustry/entities/comp/StatusComp.java +++ b/core/src/mindustry/entities/comp/StatusComp.java @@ -61,6 +61,7 @@ abstract class StatusComp implements Posc{ if(!effect.reactive){ //otherwise, no opposites found, add direct effect StatusEntry entry = Pools.obtain(StatusEntry.class, StatusEntry::new); + entry.damageTime = 0f; entry.set(effect, duration); applied.set(effect.id); statuses.add(entry); @@ -228,7 +229,7 @@ abstract class StatusComp implements Posc{ disarmed |= entry.effect.disarm; - entry.effect.update(self(), entry.time); + entry.effect.update(self(), entry); } } } diff --git a/core/src/mindustry/entities/units/StatusEntry.java b/core/src/mindustry/entities/units/StatusEntry.java index 4d405a40b6..e7ce756094 100644 --- a/core/src/mindustry/entities/units/StatusEntry.java +++ b/core/src/mindustry/entities/units/StatusEntry.java @@ -5,6 +5,8 @@ import mindustry.type.*; public class StatusEntry{ public StatusEffect effect; public float time; + //for interval damage + public float damageTime; //all of these are for the dynamic effect only! public float damageMultiplier = 1f, healthMultiplier = 1f, speedMultiplier = 1f, reloadMultiplier = 1f, buildSpeedMultiplier = 1f, dragMultiplier = 1f, armorOverride = -1f; diff --git a/core/src/mindustry/type/StatusEffect.java b/core/src/mindustry/type/StatusEffect.java index 05dc34595d..cd996a1f0d 100644 --- a/core/src/mindustry/type/StatusEffect.java +++ b/core/src/mindustry/type/StatusEffect.java @@ -33,6 +33,12 @@ public class StatusEffect extends UnlockableContent{ public boolean disarm = false; /** Damage per frame. */ public float damage; + /** Spacing (in ticks) between interval damage. <=0 to disable. */ + public float intervalDamageTime; + /** Damage dealt by interval damage. */ + public float intervalDamage; + /** If true, interval damage is armor piercing. */ + public boolean intervalDamagePierce = false; /** Chance of effect appearing. */ public float effectChance = 0.15f; /** Should the effect be given a parent. */ @@ -98,6 +104,11 @@ public class StatusEffect extends UnlockableContent{ if(damage > 0) stats.add(Stat.damage, damage * 60f, StatUnit.perSecond); if(damage < 0) stats.add(Stat.healing, -damage * 60f, StatUnit.perSecond); + if(intervalDamageTime > 0f && intervalDamage > 0){ + stats.add(Stat.damage, intervalDamage); + stats.add(Stat.damage, 60f / intervalDamageTime, StatUnit.perSecond); + } + boolean reacts = false; for(var e : opposites.toSeq().sort()){ @@ -131,14 +142,26 @@ public class StatusEffect extends UnlockableContent{ } /** Runs every tick on the affected unit while time is greater than 0. */ - public void update(Unit unit, float time){ + public void update(Unit unit, StatusEntry entry){ if(damage > 0){ unit.damageContinuousPierce(damage); }else if(damage < 0){ //heal unit unit.heal(-1f * damage * Time.delta); } - if(effect != Fx.none && Mathf.chanceDelta(effectChance)){ + if(intervalDamageTime > 0){ + entry.damageTime += Time.delta; + if(entry.damageTime >= intervalDamageTime){ + entry.damageTime %= intervalDamageTime; + if(intervalDamagePierce){ + unit.damagePierce(intervalDamage); + }else{ + unit.damage(intervalDamage); + } + } + } + + if(!Vars.headless && effect != Fx.none && Mathf.chanceDelta(effectChance) && !unit.inFogTo(Vars.player.team())){ Tmp.v1.rnd(Mathf.range(unit.type.hitSize/2f)); effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y, 0, color, parentizeEffect ? unit : null); }