From 60621520eed7676900a66f6d04a09571c664418c Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 4 Feb 2022 15:37:51 -0500 Subject: [PATCH] WIP Disrupt missiles --- .../assets-raw/sprites/units/conquer.aseprite | Bin 8411 -> 0 bytes .../sprites/units/weapons/disrupt-missile.png | Bin 0 -> 502 bytes .../units/weapons/disrupt-weapon-blade.png | Bin 0 -> 886 bytes .../sprites/units/weapons/disrupt-weapon.png | Bin 0 -> 815 bytes .../sprites/units/weapons/quell-weapon.png | Bin 839 -> 844 bytes core/assets/icons/icons.properties | 1 + core/src/mindustry/ai/types/MissileAI.java | 16 ++-- core/src/mindustry/content/Blocks.java | 4 +- core/src/mindustry/content/UnitTypes.java | 70 +++++++++++------- core/src/mindustry/entities/Damage.java | 13 +++- .../mindustry/entities/bullet/BulletType.java | 11 ++- .../entities/bullet/ExplosionBulletType.java | 28 +++++++ .../src/mindustry/entities/comp/UnitComp.java | 6 +- .../part/{WeaponPart.java => DrawPart.java} | 11 ++- .../mindustry/entities/part/RegionPart.java | 30 +++++--- .../mindustry/entities/units/UnitDecal.java | 36 --------- core/src/mindustry/mod/ContentParser.java | 7 +- core/src/mindustry/type/UnitType.java | 41 +++++----- core/src/mindustry/type/Weapon.java | 46 ++++++------ .../mindustry/type/unit/MissileUnitType.java | 5 +- .../mindustry/ui/dialogs/PlanetDialog.java | 2 +- core/src/mindustry/world/draw/DrawTurret.java | 4 +- 22 files changed, 188 insertions(+), 143 deletions(-) delete mode 100644 core/assets-raw/sprites/units/conquer.aseprite create mode 100644 core/assets-raw/sprites/units/weapons/disrupt-missile.png create mode 100644 core/assets-raw/sprites/units/weapons/disrupt-weapon-blade.png create mode 100644 core/assets-raw/sprites/units/weapons/disrupt-weapon.png create mode 100644 core/src/mindustry/entities/bullet/ExplosionBulletType.java rename core/src/mindustry/entities/part/{WeaponPart.java => DrawPart.java} (85%) delete mode 100644 core/src/mindustry/entities/units/UnitDecal.java diff --git a/core/assets-raw/sprites/units/conquer.aseprite b/core/assets-raw/sprites/units/conquer.aseprite deleted file mode 100644 index e1a86d06503499e562449e3114fe7e224d8d4fb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8411 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 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/units/weapons/disrupt-weapon.png b/core/assets-raw/sprites/units/weapons/disrupt-weapon.png new file mode 100644 index 0000000000000000000000000000000000000000..8dabc8df95408d0a532269936abab55555968914 GIT binary patch literal 815 zcmeAS@N?(olHy`uVBq!ia0y~yU;yDl4mJh`1~-u}%nS?+jKx9jP7LeL$-HD>V0!84 z;uumf=k2Y%S)z^-4G;Y{ZV=UBcIxmwa4lM3k;cJO3A*BoT z$M4OllRe8mLF!_r?B$;UC*o#-X-A8tS5WM%lh7o z_?F7{Oqu(h)!i>Lj%W8~-nt>4UUlh4$Mfgn%ieC^zCForvD|vqWmShS8K055*x9>s zY46HgE3S9=@f(Vpzp!0&*(&Yg@;r@8N4Kw6QrcAb{N#)O@iupYWq*Holkny9)2p2w z9XWUFAKXD)}VO?kprWv|}wn|^HbN$h-)b}2yP%ANGf$y0h>7HfZJ zT+V#=ZjJT5gy59_C3|Z0*ZW}t2YzMFrde7;ZAt;-!s*O_@-MP}|# zxNme`u+U=J&ZYL{x?&dDNDr5!)x$fVcs3sM>3q?0 zOhWpyOptWoXDQ*L-|zZw)@!yUpOU>Sa>+_KIk_!vmGk`8Grg+mKBXsaXzmv&e)lqW zYe~-K*BvGZm2qNh$yg43tv zznJa4&hX67Pd_LB-Tm!SU-1^^)0V>7y@@N2KC(3`KQl?tyVvougY3y&XM&gLyuGtU z*z@m|ZRgI^H$I)^`+nm8V4v4p#W*KFHhU0#&vII6Cud+z+tiMm*)9_g)o+?)oOWK& zRqM}N|Fg?$JzoB>@Q$dN-)78&qol`;+0GvXH AumAu6 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/units/weapons/quell-weapon.png b/core/assets-raw/sprites/units/weapons/quell-weapon.png index 15aaca767625350da6b3ba3000e74be40edfac40..44f39f794f85a6d332aa7faf94940b26396b2ed8 100644 GIT binary patch delta 808 zcmX@kc7|<&VLh9ti(^Pe?55`~Qa4 z`bO7XA(NiXQWjH`;Z&KRm5`Yz%+Vs#w71@&>FDMOjitu+<l zTg!dn%9SmXtnTl9dwj8H{H1c6Szn&--tJnfdAGY@lG+ni@7wP6jiJtgoe>9DlnEw; z22Au;yOe+8Q?#irPgZTRw@mKYxWxf0%JsMX|9w_+~=&^ z^??bC*5A+RdV3*{^|OYEmVf;O=F{`tn_C?VJD)PhWT@Qu%b_0SbSuc`ug%`d=(+x1 zeO&eDa@2fa~F&90=TyRwxrF7DjwH>Mwb z1Ew67zyEK;Tf;=X!n5aoZf{x{x`AzqzNgm3b<(rm&Z=i<;D0=E#`cUY=LFcMxz+D` z-L@+B^L#I+WZrwK<`qA>w?>wJ{w-Wu&mY1Jf2?JSHZ{$> zUw7xVjqTs0q`0MjcU<0*Ze5tWZ)dU=qrSvdyYH{>%HI`bWt*_i|IB)QpM6WpUhGdf ztgkhBiNlYBuFTH6zcen}(xkcW?}|mn{vfZ{2Pc@i=0;3C*IU7NpmEvX?A2dhIX}Ak zfT6EHZH=wHLfPF3x%-Q^<=O>!73J=mvcYRXnuFH_CTY7$Hiq)kYJTg^iZ5+^n(EJ$ zCizi>r!hb(B5-EQqXRpv^6F|IMmZgK-)!xm!MA4B0@tSr(+*ux?ziXVIPl|}w`?VU z`BtyTk@XD>J;qbx_7`}withXqG=IhA$$B$1qP}}gO$%fNrgJ)uA1e+JbOTp&Fa>(2FBK#t>5oR`hR!t&ABu0zuU9@ z^E<|n(9pF@-u2DjeX`=#(=&5>mfyYmvG`hy*Ls^dM>r!7KKd9}pKvrFL@CN3YYuya z;FR=}6~9U~_lE}O2kfr?{U~es8`Yv#s~d8Ezt8rTi9i0?>*>B=%?yLEmS)AyJ6OZ>m`Djl2s^7+d0SHDl5DPcJGyj!W-vqn_p z>4)#<>)-sCU@*Pn)VZJ6n^bo{5E0Px)VjDW_sX{^^$ZQ`CvTjwJ>$x|01lnCHMi@{ zJgZOD>u~m%MtJ9a_{N`o`PIw!R@s{yR?3SAT{!rSqfNR!Dtt+sbo-;|4I=X1yhm-% zJ$5NN_^485##0MJ*?l(*r#6W8NcI1XI`3ZWF39AubW_Ei@Sl^8vHrJYuM3;4!pc>@ zW66Q0*k8?R+nZ0m`@3S9u={pF0tGDW+na)QqJ= unit.type.homingDelay && shooter != null){ + unit.lookAt(shooter.aimX, shooter.aimY); } //move forward forever @@ -26,8 +29,7 @@ public class MissileAI extends AIController{ } @Override - public boolean retarget(){ - //more frequent retarget. TODO won't this lag? - return timer.get(timerTarget, 10f); + public void updateTargeting(){ + //no } } diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 9b0a534038..3862b910f6 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -2529,7 +2529,7 @@ public class Blocks{ thrusterLength = 40/4f; armor = 10f; - unitCapModifier = 12; + unitCapModifier = 10; researchCostMultiplier = 0.11f; }}; @@ -2544,7 +2544,7 @@ public class Blocks{ thrusterLength = 48/4f; armor = 15f; - unitCapModifier = 16; + unitCapModifier = 14; researchCostMultiplier = 0.11f; }}; diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index e080706a70..869502cf83 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -12,7 +12,6 @@ import mindustry.entities.abilities.*; import mindustry.entities.bullet.*; import mindustry.entities.effect.*; import mindustry.entities.part.*; -import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -2503,7 +2502,7 @@ public class UnitTypes{ }}; conquer = new TankUnitType("conquer"){{ - hitSize = 44f; + hitSize = 46f; treadPullOffset = 1; speed = 0.48f; health = 20000; @@ -2664,7 +2663,12 @@ public class UnitTypes{ }}; }}); - decals.add(new UnitDecal("conquer-glow", Color.red, Blending.additive, -1f)); + parts.add(new RegionPart("-glow"){{ + color = Color.red; + blending = Blending.additive; + layer = -1f; + outline = false; + }}); }}; //endregion @@ -2919,13 +2923,8 @@ public class UnitTypes{ mirror = false; reload = 1f; shootOnDeath = true; - bullet = new BulletType(){{ - rangeOverride = 20f; + bullet = new ExplosionBulletType(120f, 30f){{ shootEffect = Fx.massiveExplosion; - killShooter = true; - //TODO status? - splashDamageRadius = 30f; - splashDamage = 120f; }}; }}); }}; @@ -2946,7 +2945,7 @@ public class UnitTypes{ flying = true; drag = 0.07f; speed = 1f; - rotateSpeed = 2.5f; + rotateSpeed = 2f; accel = 0.1f; health = 10000f; armor = 7f; @@ -2979,16 +2978,36 @@ public class UnitTypes{ } //TODO needs weapons! cool missiles or something - if(false) - weapons.add(new Weapon("quell-weapon"){{ - x = 51 / 4f; - y = 5 / 4f; + weapons.add(new Weapon("disrupt-weapon"){{ + x = 78f / 4f; + y = -10f / 4f; + mirror = true; rotate = true; - rotateSpeed = 2f; - reload = 70f; - layerOffset = -0.001f; + rotateSpeed = 0.4f; + reload = 60f; + layerOffset = -20f; recoil = 1f; - rotationLimit = 60f; + rotationLimit = 22f; + minWarmup = 0.95f; + shootWarmupSpeed = 0.1f; + shootY = 2f; + shootCone = 40f; + shots = 3; + shotDelay = 5f; + inaccuracy = 28f; + + parts.add(new RegionPart("-blade"){{ + heatProgress = PartProgress.warmup; + progress = PartProgress.warmup.blend(PartProgress.reload, 0.15f); + heatColor = Color.valueOf("9c50ff"); + x = 5 / 4f; + y = 0f; + rotMove = -33f; + moveY = -1f; + moveX = -1f; + under = true; + mirror = true; + }}); bullet = new BulletType(){{ shootEffect = Fx.shootBig; @@ -2998,24 +3017,20 @@ public class UnitTypes{ keepVelocity = false; }}; - unitSpawned = new MissileUnitType("quell-missile"){{ - speed = 3.8f; + unitSpawned = new MissileUnitType("disrupt-missile"){{ + speed = 4.5f; maxRange = 80f; outlineColor = Pal.darkOutline; health = 45; + homingDelay = 10f; weapons.add(new Weapon(){{ shootCone = 360f; mirror = false; reload = 1f; shootOnDeath = true; - bullet = new BulletType(){{ - rangeOverride = 20f; + bullet = new ExplosionBulletType(120f, 30f){{ shootEffect = Fx.massiveExplosion; - killShooter = true; - //TODO status? - splashDamageRadius = 30f; - splashDamage = 120f; }}; }}); }}; @@ -3107,7 +3122,8 @@ public class UnitTypes{ shootEffect = Fx.colorSpark; hitEffect = smokeEffect = despawnEffect = Fx.hitLaserColor; - damage = 1; + //TODO 0, or 1? + damage = 0; }}; }}); }}; diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 0ab16352f9..21006bddd6 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -387,11 +387,17 @@ public class Damage{ /** 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, boolean air, boolean ground){ + damage(team, x, y, radius, damage, complete, air, ground, 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, boolean air, boolean ground, boolean scaled){ Cons cons = entity -> { - if(entity.team == team || !entity.within(x, y, radius) || (entity.isFlying() && !air) || (entity.isGrounded() && !ground)){ + if(entity.team == team || !entity.within(x, y, radius + (scaled ? entity.hitSize / 2f : 0f)) || (entity.isFlying() && !air) || (entity.isGrounded() && !ground)){ return; } - float amount = calculateDamage(x, y, entity.getX(), entity.getY(), radius, damage); + + float amount = calculateDamage(scaled ? Math.max(0, entity.dst(x, y) - entity.type.hitSize/2) : entity.dst(x, y), radius, damage); entity.damage(amount); //TODO better velocity displacement float dst = tr.set(entity.getX() - x, entity.getY() - y).len(); @@ -504,8 +510,7 @@ public class Damage{ } } - private static float calculateDamage(float x, float y, float tx, float ty, float radius, float damage){ - float dist = Mathf.dst(x, y, tx, ty); + private static float calculateDamage(float dist, float radius, float damage){ float falloff = 0.4f; float scaled = Mathf.lerp(1f - dist / radius, 1f, falloff); return damage * scaled; diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 0ee7e4e2d9..81441e4ac8 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -80,6 +80,8 @@ public class BulletType extends Content implements Cloneable{ public boolean instantDisappear; /** Damage dealt in splash. 0 to disable.*/ public float splashDamage = 0f; + /** If true, splash damage is "correctly" affected by unit hitbox size. Used for projectiles that do not collide / have splash as their main source of damage. */ + public boolean scaledSplashDamage = false; /** Knockback in velocity. */ public float knockback; /** Should knockback follow the bullet's direction */ @@ -142,6 +144,7 @@ public class BulletType extends Content implements Cloneable{ public @Nullable BulletType fragBullet = null; public Color hitColor = Color.white; public Color healColor = Pal.heal; + public Effect healEffect = Fx.healBlockFull; /** Bullets spawned when this bullet is created. Rarely necessary, used for visuals. */ public Seq spawnBullets = new Seq<>(); @@ -249,7 +252,7 @@ public class BulletType extends Content implements Cloneable{ } if(heals()&& build.team == b.team && !(build.block instanceof ConstructBlock)){ - Fx.healBlockFull.at(build.x, build.y, build.block.size, healColor); + healEffect.at(build.x, build.y, build.block.size, healColor); build.heal(healPercent / 100f * build.maxHealth + healAmount); }else if(build.team != b.team && direct){ hit(b); @@ -308,7 +311,7 @@ public class BulletType extends Content implements Cloneable{ } if(splashDamageRadius > 0 && !b.absorbed){ - Damage.damage(b.team, x, y, splashDamageRadius, splashDamage * b.damageMultiplier(), collidesAir, collidesGround); + Damage.damage(b.team, x, y, splashDamageRadius, splashDamage * b.damageMultiplier(), false, collidesAir, collidesGround, scaledSplashDamage); if(status != StatusEffects.none){ Damage.status(b.team, x, y, splashDamageRadius, status, statusDuration, collidesAir, collidesGround); @@ -316,7 +319,7 @@ public class BulletType extends Content implements Cloneable{ if(heals()){ indexer.eachBlock(b.team, x, y, splashDamageRadius, Building::damaged, other -> { - Fx.healBlockFull.at(other.x, other.y, other.block.size, healColor); + healEffect.at(other.x, other.y, other.block.size, healColor); other.heal(healPercent / 100f * other.maxHealth() + healAmount); }); } @@ -375,7 +378,7 @@ public class BulletType extends Content implements Cloneable{ } if(instantDisappear){ - b.time = lifetime; + b.time = lifetime + 1f; } if(spawnBullets.size > 0){ diff --git a/core/src/mindustry/entities/bullet/ExplosionBulletType.java b/core/src/mindustry/entities/bullet/ExplosionBulletType.java new file mode 100644 index 0000000000..0ad13fdb88 --- /dev/null +++ b/core/src/mindustry/entities/bullet/ExplosionBulletType.java @@ -0,0 +1,28 @@ +package mindustry.entities.bullet; + +import mindustry.content.*; + +public class ExplosionBulletType extends BulletType{ + + public ExplosionBulletType(float splashDamage, float splashDamageRadius){ + this.splashDamage = splashDamage; + this.splashDamageRadius = splashDamageRadius; + rangeOverride = Math.max(rangeOverride, splashDamageRadius * 2f / 3f); + } + + public ExplosionBulletType(){ + } + + { + hittable = false; + lifetime = 1f; + speed = 0f; + rangeOverride = 20f; + shootEffect = Fx.massiveExplosion; + instantDisappear = true; + scaledSplashDamage = true; + killShooter = true; + collides = false; + keepVelocity = false; + } +} diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 8c5f626906..83bba188c5 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -513,7 +513,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I float shake = hitSize / 3f; - Effect.scorch(x, y, (int)(hitSize / 5)); + if(type.createScorch){ + Effect.scorch(x, y, (int)(hitSize / 5)); + } Effect.shake(shake, shake, this); type.deathSound.at(this); @@ -536,7 +538,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I Damage.damage(team, x, y, Mathf.pow(hitSize, 0.94f) * 1.25f, Mathf.pow(hitSize, 0.75f) * type.crashDamageMultiplier * 5f, true, false, true); } - if(!headless){ + if(!headless && type.createScorch){ for(int i = 0; i < type.wreckRegions.length; i++){ if(type.wreckRegions[i].found()){ float range = type.hitSize /4f; diff --git a/core/src/mindustry/entities/part/WeaponPart.java b/core/src/mindustry/entities/part/DrawPart.java similarity index 85% rename from core/src/mindustry/entities/part/WeaponPart.java rename to core/src/mindustry/entities/part/DrawPart.java index b529aa1d88..00e465e07e 100644 --- a/core/src/mindustry/entities/part/WeaponPart.java +++ b/core/src/mindustry/entities/part/DrawPart.java @@ -4,7 +4,7 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.struct.*; -public abstract class WeaponPart{ +public abstract class DrawPart{ public static final PartParams params = new PartParams(); /** If true, turret shading is used. Don't touch this, it is set up in unit/block init()! */ @@ -37,11 +37,14 @@ public abstract class WeaponPart{ } public interface PartProgress{ + /** Reload of the weapon - 1 right after shooting, 0 when ready to fire*/ PartProgress - reload = p -> p.reload, + /** Reload, but smoothed out, so there is no sudden jump between 0-1. */ smoothReload = p -> p.smoothReload, + /** Weapon warmup, 0 when not firing, 1 when actively shooting. Not equivalent to heat. */ warmup = p -> p.warmup, + /** Weapon heat, 1 when just fired, 0, when it has cooled down (duration depends on weapon) */ heat = p -> p.heat; float get(PartParams p); @@ -74,6 +77,10 @@ public abstract class WeaponPart{ return p -> get(p) * other.get(p); } + default PartProgress mul(float amount){ + return p -> get(p) * amount; + } + default PartProgress min(PartProgress other){ return p -> Math.min(get(p), other.get(p)); } diff --git a/core/src/mindustry/entities/part/RegionPart.java b/core/src/mindustry/entities/part/RegionPart.java index 98ecfbd7ff..37d3a5d905 100644 --- a/core/src/mindustry/entities/part/RegionPart.java +++ b/core/src/mindustry/entities/part/RegionPart.java @@ -8,10 +8,13 @@ import arc.struct.*; import arc.util.*; import mindustry.graphics.*; -public class RegionPart extends WeaponPart{ +public class RegionPart extends DrawPart{ protected PartParams childParam = new PartParams(); + /** Appended to unit/weapon/block name and drawn. */ public String suffix = ""; + /** Overrides suffix if set. */ + public @Nullable String name; public TextureRegion heat; public TextureRegion[] regions = {}; public TextureRegion[] outlines = {}; @@ -34,12 +37,19 @@ public class RegionPart extends WeaponPart{ public float x, y, moveX, moveY; public @Nullable Color color, colorTo; public Color heatColor = Pal.turretHeat.cpy(); - public Seq children = new Seq<>(); + public Seq children = new Seq<>(); public RegionPart(String region){ this.suffix = region; } + public RegionPart(String region, Blending blending, Color color){ + this.suffix = region; + this.blending = blending; + this.color = color; + outline = false; + } + public RegionPart(){ } @@ -119,25 +129,27 @@ public class RegionPart extends WeaponPart{ @Override public void load(String name){ + String realName = this.name == null ? name + suffix : this.name; + if(drawRegion){ //TODO l/r if(mirror && turretShading){ regions = new TextureRegion[]{ - Core.atlas.find(name + suffix + "1"), - Core.atlas.find(name + suffix + "2") + Core.atlas.find(realName + "1"), + Core.atlas.find(realName + "2") }; outlines = new TextureRegion[]{ - Core.atlas.find(name + suffix + "1-outline"), - Core.atlas.find(name + suffix + "2-outline") + Core.atlas.find(realName + "1-outline"), + Core.atlas.find(realName + "2-outline") }; }else{ - regions = new TextureRegion[]{Core.atlas.find(name + suffix)}; - outlines = new TextureRegion[]{Core.atlas.find(name + suffix + "-outline")}; + regions = new TextureRegion[]{Core.atlas.find(realName)}; + outlines = new TextureRegion[]{Core.atlas.find(realName + "-outline")}; } } - heat = Core.atlas.find(name + suffix + "-heat"); + heat = Core.atlas.find(realName + "-heat"); for(var child : children){ child.load(name); } diff --git a/core/src/mindustry/entities/units/UnitDecal.java b/core/src/mindustry/entities/units/UnitDecal.java deleted file mode 100644 index cdd488d6fe..0000000000 --- a/core/src/mindustry/entities/units/UnitDecal.java +++ /dev/null @@ -1,36 +0,0 @@ -package mindustry.entities.units; - -import arc.graphics.*; -import arc.graphics.g2d.*; -import mindustry.graphics.*; - -/** A sprite drawn in addition to the base unit sprites. */ -public class UnitDecal{ - public String region = "error"; - public float x, y, rotation; - public float layer = Layer.flyingUnit + 1f; - public float xScale = 1f, yScale = 1f; - public Blending blending = Blending.normal; - public Color color = Color.white; - - public TextureRegion loadedRegion; - - public UnitDecal(String region, float x, float y, float rotation, float layer, Color color){ - this.region = region; - this.x = x; - this.y = y; - this.rotation = rotation; - this.layer = layer; - this.color = color; - } - - public UnitDecal(String region, Color color, Blending blending, float layer){ - this.region = region; - this.color = color; - this.layer = layer; - this.blending = blending; - } - - public UnitDecal(){ - } -} diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index 6a077d6bc8..19b4553eb7 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -25,7 +25,7 @@ import mindustry.entities.abilities.*; import mindustry.entities.bullet.*; import mindustry.entities.effect.*; import mindustry.entities.part.*; -import mindustry.entities.part.WeaponPart.*; +import mindustry.entities.part.DrawPart.*; import mindustry.game.*; import mindustry.game.Objectives.*; import mindustry.gen.*; @@ -130,13 +130,14 @@ public class ContentParser{ readFields(result, data); return result; }); - put(WeaponPart.class, (type, data) -> { + put(DrawPart.class, (type, data) -> { var bc = resolve(data.getString("type", ""), RegionPart.class); data.remove("type"); var result = make(bc); readFields(result, data); return result; }); + //TODO this is untested put(PartProgress.class, (type, data) -> { //simple case: it's a string or number constant if(data.isString()) return field(PartProgress.class, data.asString()); @@ -166,7 +167,7 @@ public class ContentParser{ case "mul" -> base.mul(parser.readValue(PartProgress.class, data.get("other"))); case "min" -> base.min(parser.readValue(PartProgress.class, data.get("other"))); case "sin" -> base.sin(data.getFloat("scl"), data.getFloat("mag")); - case "absin" -> base.sin(data.getFloat("scl"), data.getFloat("mag")); + case "absin" -> base.absin(data.getFloat("scl"), data.getFloat("mag")); case "curve" -> base.curve(parser.readValue(Interp.class, data.get("interp"))); default -> throw new RuntimeException("Unknown operation '" + op + "', check PartProgress class for a list of methods."); }; diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index c368b3118e..370c810e46 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -20,6 +20,7 @@ import mindustry.core.*; import mindustry.ctype.*; import mindustry.entities.*; import mindustry.entities.abilities.*; +import mindustry.entities.part.*; import mindustry.entities.units.*; import mindustry.game.*; import mindustry.gen.*; @@ -59,7 +60,6 @@ public class UnitType extends UnlockableContent{ public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f; public float drag = 0.3f, accel = 0.5f, landShake = 0f, rippleScale = 1f, riseSpeed = 0.08f, fallSpeed = 0.018f; public float health = 200f, range = -1, miningRange = 70f, armor = 0f, maxRange = -1f, buildRange = Vars.buildingRange; - public float lifetime = 60f * 5f; //for missiles only public float crashDamageMultiplier = 1f; public boolean targetAir = true, targetGround = true; public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false, circleTarget = false; @@ -68,6 +68,7 @@ public class UnitType extends UnlockableContent{ public boolean playerControllable = true; public boolean allowedInPayloads = true; public boolean createWreck = true; + public boolean createScorch = true; public boolean useUnitCap = true; public boolean destructibleWreck = true; /** If true, this modded unit always has a -outline region generated for its base. Normally, outlines are ignored if there are no top = false weapons. */ @@ -94,8 +95,8 @@ public class UnitType extends UnlockableContent{ public Effect fallThrusterEffect = Fx.fallSmoke; public Effect deathExplosionEffect = Fx.dynamicExplosion; public @Nullable Effect treadEffect; - /** Additional sprites that are drawn with the unit. */ - public Seq decals = new Seq<>(); + /** Extra (usually animated) parts */ + public Seq parts = new Seq<>(DrawPart.class); public Seq abilities = new Seq<>(); /** Flags to target based on priority. Null indicates that the closest target should be found. The closest enemy core is used as a fallback. */ public BlockFlag[] targetFlags = {null}; @@ -138,6 +139,10 @@ public class UnitType extends UnlockableContent{ public Sound mineSound = Sounds.minebeam; public float mineSoundVolume = 0.6f; + //missiles only! + public float lifetime = 60f * 5f; + public float homingDelay = 10f; + /** This is a VERY ROUGH estimate of unit DPS. */ public float dpsEstimate = -1; public float clipSize = -1; @@ -522,6 +527,9 @@ public class UnitType extends UnlockableContent{ public void load(){ super.load(); + for(var part : parts){ + part.load(name); + } weapons.each(Weapon::load); region = Core.atlas.find(name); legRegion = Core.atlas.find(name + "-leg"); @@ -562,10 +570,6 @@ public class UnitType extends UnlockableContent{ segmentOutlineRegions[i] = Core.atlas.find(name + "-segment-outline" + i); } - for(var decal : decals){ - decal.loadedRegion = Core.atlas.find(decal.region); - } - clipSize = Math.max(region.width * 2f, clipSize); } @@ -798,18 +802,19 @@ public class UnitType extends UnlockableContent{ unit.trns(-legOffset.x, -legOffset.y); } - if(decals.size > 0){ - float base = unit.rotation - 90; - for(var d : decals){ - Draw.blend(d.blending); - Draw.z(d.layer <= 0f ? z : d.layer); - Draw.scl(d.xScale, d.yScale); - Draw.color(d.color); - Draw.rect(d.loadedRegion, unit.x + Angles.trnsx(base, d.x, d.y), unit.y + Angles.trnsy(base, d.x, d.y), base + d.rotation); - Draw.blend(); + //TODO how/where do I draw under? + if(parts.size > 0){ + //TODO does it need an outline? + WeaponMount first = unit.mounts.length > 0 ? unit.mounts[0] : null; + if(unit.mounts.length > 0){ + DrawPart.params.set(first.warmup, first.reload / weapons.first().reload, first.smoothReload, first.heat, unit.x, unit.y, unit.rotation); + }else{ + DrawPart.params.set(0f, 0f, 0f, 0f, unit.x, unit.y, unit.rotation); + } + for(int i = 0; i < parts.size; i++){ + var part = parts.items[i]; + part.draw(DrawPart.params); } - Draw.reset(); - Draw.z(z); } for(Ability a : unit.abilities){ diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index 7f47e61784..c1e5d9e8d2 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -10,6 +10,7 @@ import arc.math.geom.*; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; +import mindustry.ai.types.*; import mindustry.audio.*; import mindustry.content.*; import mindustry.entities.*; @@ -131,7 +132,7 @@ public class Weapon implements Cloneable{ /** whether this weapon should fire when its owner dies */ public boolean shootOnDeath = false; /** extra animated parts */ - public Seq parts = new Seq<>(WeaponPart.class); + public Seq parts = new Seq<>(DrawPart.class); public Weapon(String name){ this.name = name; @@ -195,12 +196,12 @@ public class Weapon implements Cloneable{ Draw.xscl = -Mathf.sign(flipSprite); if(parts.size > 0){ - WeaponPart.params.set(mount.warmup, mount.reload / reload, mount.smoothReload, mount.heat, wx, wy, weaponRotation + 90); + DrawPart.params.set(mount.warmup, mount.reload / reload, mount.smoothReload, mount.heat, wx, wy, weaponRotation + 90); for(int i = 0; i < parts.size; i++){ var part = parts.items[i]; if(part.under){ - part.draw(WeaponPart.params); + part.draw(DrawPart.params); } } } @@ -217,18 +218,10 @@ public class Weapon implements Cloneable{ if(parts.size > 0){ //TODO does it need an outline? - /* - if(outline.found()){ - //draw outline under everything when parts are involved - Draw.z(Layer.turret - 0.01f); - Draw.rect(outline, build.x + tb.recoilOffset.x, build.y + tb.recoilOffset.y, tb.drawrot()); - Draw.z(Layer.turret); - }*/ - for(int i = 0; i < parts.size; i++){ var part = parts.items[i]; if(!part.under){ - part.draw(WeaponPart.params); + part.draw(DrawPart.params); } } } @@ -380,10 +373,8 @@ public class Weapon implements Cloneable{ float baseX = offset.x, baseY = offset.y, baseRot = unit.rotation + mount.rotation; boolean delay = firstShotDelay + shotDelay > 0f; - (delay ? chargeSound : continuous ? Sounds.none : shootSound).at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax)); - - BulletType ammo = bullet; - float lifeScl = ammo.scaleVelocity ? Mathf.clamp(Mathf.dst(shootX, shootY, aimX, aimY) / ammo.range()) : 1f; + float lifeScl = bullet.scaleVelocity ? Mathf.clamp(Mathf.dst(shootX, shootY, aimX, aimY) / bullet.range()) : 1f; + Unit parent = bullet.keepVelocity || parentizeEffects ? unit : null; //TODO far too complicated and similar to Turret @@ -393,6 +384,7 @@ public class Weapon implements Cloneable{ Time.run(sequenceNum * shotDelay + firstShotDelay, () -> { if(!unit.isAdded()) return; + //TODO this is a flawed system, recalculate everything instead. getShootPos(unit, mount, offset).sub(baseX, baseY); float rotOffset = unit.rotation + mount.rotation - baseRot; @@ -407,13 +399,11 @@ public class Weapon implements Cloneable{ Angles.shotgun(shots, spacing, rotation, f -> mount.bullet = bullet(unit, shootX, shootY, f + Mathf.range(inaccuracy), lifeScl)); } - boolean parentize = ammo.keepVelocity || parentizeEffects; - if(delay){ Time.run(firstShotDelay, () -> { if(!unit.isAdded()) return; - unit.vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil)); + unit.vel.add(Tmp.v1.trns(rotation + 180f, bullet.recoil)); Effect.shake(shake, shake, shootX, shootY); mount.recoil = recoil; mount.heat = 1f; @@ -423,21 +413,26 @@ public class Weapon implements Cloneable{ getShootPos(unit, mount, offset).sub(baseX, baseY); - ammo.chargeShootEffect.at(shootX + offset.x, shootY + offset.y, rotation, parentize ? unit : null); + bullet.chargeShootEffect.at(shootX + offset.x, shootY + offset.y, rotation, parent); }); }else{ - unit.vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil)); + unit.vel.add(Tmp.v1.trns(rotation + 180f, bullet.recoil)); Effect.shake(shake, shake, shootX, shootY); mount.recoil = recoil; mount.heat = 1f; } - ejectEffect.at(mountX, mountY, rotation * side); - ammo.shootEffect.at(shootX, shootY, rotation, ammo.hitColor, parentize ? unit : null); - ammo.smokeEffect.at(shootX, shootY, rotation, ammo.hitColor, parentize ? unit : null); + (delay ? chargeSound : continuous ? Sounds.none : shootSound).at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax)); + effects(parent, mountX, mountY, shootX, shootY, rotation, side); unit.apply(shootStatus, shootStatusDuration); } + protected void effects(Unit parent, float mountX, float mountY, float shootX, float shootY, float rotation, int side){ + ejectEffect.at(mountX, mountY, rotation * side); + bullet.shootEffect.at(shootX, shootY, rotation, bullet.hitColor, parent); + bullet.smokeEffect.at(shootX, shootY, rotation, bullet.hitColor, parent); + } + protected @Nullable Bullet bullet(Unit unit, float shootX, float shootY, float angle, float lifescl){ float xr = Mathf.range(xRand), @@ -452,6 +447,9 @@ public class Weapon implements Cloneable{ spawned.rotation = angle; //immediately spawn at top speed, since it was launched spawned.vel.trns(angle, unitSpawned.speed); + if(spawned.controller() instanceof MissileAI ai){ + ai.shooter = unit; + } spawned.add(); //TODO assign AI target here? return null; diff --git a/core/src/mindustry/type/unit/MissileUnitType.java b/core/src/mindustry/type/unit/MissileUnitType.java index b70382b0dc..6610f36149 100644 --- a/core/src/mindustry/type/unit/MissileUnitType.java +++ b/core/src/mindustry/type/unit/MissileUnitType.java @@ -13,6 +13,7 @@ public class MissileUnitType extends UnitType{ playerControllable = false; createWreck = false; + createScorch = false; logicControllable = false; isCounted = false; useUnitCap = false; @@ -26,8 +27,8 @@ public class MissileUnitType extends UnitType{ trailLength = 7; hidden = true; speed = 4f; - lifetime = 60f * 3f; - rotateSpeed = 3f; + lifetime = 60f * 1.6f; + rotateSpeed = 2.5f; range = 30f; //TODO weapons, etc } diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index 52b2fc6382..0673db5990 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -1077,7 +1077,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ //make sure there are no under-attack sectors (other than this one) //TODO abandon button? for(Planet planet : content.planets()){ - if(!planet.allowWaveSimulation){ + if(!planet.allowWaveSimulation && !debugSelect){ int attackedCount = planet.sectors.count(s -> s.isAttacked() && s != sector); //if there are two or more attacked sectors... something went wrong, don't show the dialog to prevent softlock diff --git a/core/src/mindustry/world/draw/DrawTurret.java b/core/src/mindustry/world/draw/DrawTurret.java index 5a26148ac7..6d18c66ddc 100644 --- a/core/src/mindustry/world/draw/DrawTurret.java +++ b/core/src/mindustry/world/draw/DrawTurret.java @@ -17,7 +17,7 @@ import mindustry.world.blocks.defense.turrets.Turret.*; public class DrawTurret extends DrawBlock{ protected static final Rand rand = new Rand(); - public Seq parts = new Seq<>(); + public Seq parts = new Seq<>(); public String basePrefix = ""; /** Overrides the liquid to draw in the liquid region. */ public @Nullable Liquid liquidDraw; @@ -66,7 +66,7 @@ public class DrawTurret extends DrawBlock{ } //TODO no smooth reload - var params = WeaponPart.params.set(build.warmup(), 1f - tb.progress(), 1f - tb.progress(), tb.heat, tb.x + tb.recoilOffset.x, tb.y + tb.recoilOffset.y, tb.rotation); + var params = DrawPart.params.set(build.warmup(), 1f - tb.progress(), 1f - tb.progress(), tb.heat, tb.x + tb.recoilOffset.x, tb.y + tb.recoilOffset.y, tb.rotation); for(var part : parts){ part.draw(params);