diff --git a/core/assets-raw/sprites/blocks/turrets/horde.png b/core/assets-raw/sprites/blocks/turrets/horde.png new file mode 100644 index 0000000000..b871ef644c Binary files /dev/null and b/core/assets-raw/sprites/blocks/turrets/horde.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/titan/titan-barrel.png b/core/assets-raw/sprites/blocks/turrets/titan/titan-barrel.png index f9c7a4f554..a04e3afd07 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/titan/titan-barrel.png and b/core/assets-raw/sprites/blocks/turrets/titan/titan-barrel.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/titan/titan-preview.png b/core/assets-raw/sprites/blocks/turrets/titan/titan-preview.png index f293f3dba7..2c6c40911a 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/titan/titan-preview.png and b/core/assets-raw/sprites/blocks/turrets/titan/titan-preview.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/titan/titan-side1.png b/core/assets-raw/sprites/blocks/turrets/titan/titan-side1.png index cb18619f71..9da1210170 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/titan/titan-side1.png and b/core/assets-raw/sprites/blocks/turrets/titan/titan-side1.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/titan/titan-side2.png b/core/assets-raw/sprites/blocks/turrets/titan/titan-side2.png index 69082ddedf..8830ec81b9 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/titan/titan-side2.png and b/core/assets-raw/sprites/blocks/turrets/titan/titan-side2.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/titan/titan.png b/core/assets-raw/sprites/blocks/turrets/titan/titan.png index 6afc336be4..58b4fad36c 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/titan/titan.png and b/core/assets-raw/sprites/blocks/turrets/titan/titan.png differ diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index a52d7d830c..8dade2a87d 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -474,3 +474,4 @@ 63232=wall-ore-tungsten|block-wall-ore-tungsten-ui 63231=regen-projector|block-regen-projector-ui 63230=titan|block-titan-ui +63229=horde|block-horde-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index d315bbe103..fae5966c56 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 df0c1cb334..396ee9fcdb 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -119,7 +119,7 @@ public class Blocks{ duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, foreshadow, spectre, meltdown, segment, parallax, tsunami, //turrets - erekir - breach, fracture, sublimate, titan, + breach, fracture, horde, sublimate, titan, //units commandCenter, @@ -128,6 +128,7 @@ public class Blocks{ repairPoint, repairTurret, //payloads + //TODO small deconstructor payloadConveyor, payloadRouter, payloadPropulsionTower, deconstructor, constructor, largeConstructor, payloadLoader, payloadUnloader, //logic @@ -2799,7 +2800,7 @@ public class Blocks{ Items.beryllium, new BasicBulletType(7f, 32){{ width = 8f; height = 14f; - shootEffect = Fx.berylSpark; + shootEffect = Fx.colorSpark; smokeEffect = Fx.shootBigSmoke; ammoMultiplier = 1; pierce = true; @@ -2853,7 +2854,7 @@ public class Blocks{ velocityInaccuracy = 0.2f; width = 6f; height = 12f; - shootEffect = Fx.berylSpark; + shootEffect = Fx.colorSpark; smokeEffect = Fx.shootBigSmoke; ammoMultiplier = 2; pierce = true; @@ -2888,10 +2889,64 @@ public class Blocks{ limitRange(); }}; + //TODO implementation, better name + horde = new ItemTurret("horde"){{ + requirements(Category.turret, with(Items.tungsten, 35, Items.silicon, 35)); + ammo( + Items.scrap, new MissileBulletType(4.2f, 15){{ + velocityInaccuracy = 0.2f; + shootEffect = Fx.colorSpark; + smokeEffect = Fx.shootBigSmoke; + ammoMultiplier = 1; + hitColor = backColor = trailColor = Color.valueOf("ea8878"); + frontColor = Color.valueOf("feb380"); + trailWidth = 2f; + trailLength = 12; + + splashDamage = 15f; + splashDamageRadius = 30f; + + weaveMag = 5; + weaveScale = 4; + velocityInaccuracy = 0.1f; + ammoMultiplier = 3f; + + //TODO different effect? + hitEffect = despawnEffect = Fx.blastExplosion; + }} + ); + + acceptCoolant = false; + //TODO + consumes.liquid(Liquids.hydrogen, 1.5f / 60f); + shots = 9; + burstSpacing = 2f; + + //TODO this works but looks bad + spread = 0f; + shootLength = 6.5f; + xRand = 13f; + recoilAmount = 0f; + + draw = new DrawTurret("reinforced-"); + outlineColor = Pal.darkOutline; + size = 3; + envEnabled |= Env.space; + reloadTime = 60f * 1.5f; + range = 190; + shootCone = 15f; + inaccuracy = 20f; + health = 300 * size * size; + rotateSpeed = 3f; + + //??? + //limitRange(); + }}; + //TODO bad name sublimate = new ContinuousTurret("sublimate"){{ //TODO requirements - requirements(Category.turret, with(Items.tungsten, 35, Items.silicon, 35)); + requirements(Category.turret, with(Items.tungsten, 50, Items.silicon, 60, Items.oxide, 30, Items.carbide, 40)); draw = new DrawTurret("reinforced-"){{ liquidDraw = Liquids.ozone; @@ -2942,13 +2997,11 @@ public class Blocks{ }}; titan = new ItemTurret("titan"){{ - //TODO requirements requirements(Category.turret, with(Items.carbide, 120, Items.surgeAlloy, 80, Items.silicon, 80, Items.beryllium, 120)); ammo( - //TODO ammo types to be defined later + //TODO 1 more ammo type, decide on base type Items.fissileMatter, new ArtilleryBulletType(2.5f, 40, "shell"){{ - //TODO FX; smoke, shockwave, not green bomb hitEffect = new MultiEffect(Fx.titanExplosion, Fx.titanSmoke); despawnEffect = Fx.none; knockback = 1.5f; @@ -2957,8 +3010,8 @@ public class Blocks{ width = 14.2f; splashDamageRadius = 60f; splashDamage = 100f; - backColor = hitColor = trailColor = Pal.berylShot; - frontColor = Color.valueOf("f0ffde"); + backColor = hitColor = trailColor = Color.valueOf("5b6b82"); + frontColor = Color.valueOf("a0b0c8"); ammoMultiplier = 1f; status = StatusEffects.blasted; @@ -2971,11 +3024,9 @@ public class Blocks{ trailColor = backColor; despawnShake = 7f; - //TODO better shoot shootEffect = Fx.shootTitan; smokeEffect = Fx.shootSmokeTitan; - //does the trail need to shrink? trailInterp = v -> Math.max(Mathf.slope(v), 0.8f); shrinkX = 0.2f; shrinkY = 0.1f; @@ -2992,27 +3043,23 @@ public class Blocks{ acceptCoolant = false; draw = new DrawTurret("reinforced-"){{ - Color heatc = Color.valueOf("f03b0e"); - Interp in = Interp.pow2In; - parts.addAll( new RegionPart("-barrel"){{ moveY = -5f; - heatColor = heatc; + heatColor = Color.valueOf("f03b0e"); mirror = false; - interp = in; + interp = Interp.pow2In; }}, new RegionPart("-side"){{ + moveX = 2f; moveY = -1f; rotMove = -40f; - moveX = 2f; useReload = false; under = true; - heatColor = Pal.berylShot.cpy().mul(1.1f); + heatColor = Color.valueOf("768a9a"); useProgressHeat = true; interp = Interp.pow2Out; - }} - ); + }}); }}; restitution = 0.02f; diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 6c28dc1ff9..e9dbada86d 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -340,7 +340,7 @@ public class Fx{ }), titanExplosion = new Effect(30f, 160f, e -> { - color(Pal.berylShot); + color(e.color); stroke(e.fout() * 3f); float circleRad = 6f + e.finpow() * 60f; Lines.circle(e.x, e.y, circleRad); @@ -356,7 +356,7 @@ public class Fx{ titanSmoke = new Effect(300f, 300f, b -> { float intensity = 3f; - color(Pal.berylShot, 0.7f); + color(b.color, 0.7f); for(int i = 0; i < 4; i++){ rand.setSeed(b.id*2 + i); float lenScl = rand.random(0.5f, 1f); @@ -1372,7 +1372,7 @@ public class Fx{ }), shootTitan = new Effect(10, e -> { - color(Pal.lightOrange, Pal.berylShot, e.fin()); + color(Pal.lightOrange, e.color, e.fin()); float w = 1.3f + 10 * e.fout(); Drawf.tri(e.x, e.y, w, 35f * e.fout(), e.rotation); Drawf.tri(e.x, e.y, w, 6f * e.fout(), e.rotation + 180f); @@ -1399,7 +1399,7 @@ public class Fx{ for(int i = 0; i < 13; i++){ v.trns(e.rotation + rand.range(30f), rand.random(e.finpow() * 40f)); e.scaled(e.lifetime * rand.random(0.3f, 1f), b -> { - color(Pal.berylShot, Pal.lightishGray, b.fin()); + color(e.color, Pal.lightishGray, b.fin()); Fill.circle(e.x + v.x, e.y + v.y, b.fout() * 3.4f + 0.3f); }); } @@ -1441,8 +1441,8 @@ public class Fx{ } }), - berylSpark = new Effect(21f, e -> { - color(Color.white, Pal.berylShot, e.fin()); + colorSpark = new Effect(21f, e -> { + color(Color.white, e.color, e.fin()); stroke(e.fout() * 1.1f + 0.5f); randLenVectors(e.id, 5, 27f * e.fin(), e.rotation, 9f, (x, y) -> { diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index 31a56f0623..b40cd4aa09 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -350,6 +350,8 @@ public class Weapon implements Cloneable{ BulletType ammo = bullet; float lifeScl = ammo.scaleVelocity ? Mathf.clamp(Mathf.dst(shootX, shootY, aimX, aimY) / ammo.range()) : 1f; + //TODO far too complicated and similar to Turret + sequenceNum = 0; if(delay){ Angles.shotgun(shots, spacing, rotation, f -> { @@ -396,8 +398,8 @@ public class Weapon implements Cloneable{ } ejectEffect.at(mountX, mountY, rotation * side); - ammo.shootEffect.at(shootX, shootY, rotation, parentize ? unit : null); - ammo.smokeEffect.at(shootX, shootY, rotation, parentize ? unit : null); + ammo.shootEffect.at(shootX, shootY, rotation, ammo.hitColor, parentize ? unit : null); + ammo.smokeEffect.at(shootX, shootY, rotation, ammo.hitColor, parentize ? unit : null); unit.apply(shootStatus, shootStatusDuration); } diff --git a/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java b/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java index ea04cf0b88..f8013c677f 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java @@ -16,6 +16,7 @@ public class BaseTurret extends Block{ public float range = 80f; public float rotateSpeed = 5; + public float coolantUsage = 0.2f; public boolean acceptCoolant = true; /** Effect displayed when coolant is used. */ public Effect coolEffect = Fx.fuelburn; @@ -38,7 +39,7 @@ public class BaseTurret extends Block{ public void init(){ if(acceptCoolant && !consumes.has(ConsumeType.liquid)){ hasLiquids = true; - consumes.add(new ConsumeCoolant(0.2f)).update(false).boost(); + consumes.add(new ConsumeCoolant(coolantUsage)).update(false).boost(); } super.init(); diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 3aca805667..fb47b45758 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -23,7 +23,6 @@ import mindustry.graphics.*; import mindustry.logic.*; import mindustry.type.*; import mindustry.world.blocks.*; -import mindustry.world.consumers.*; import mindustry.world.draw.*; import mindustry.world.meta.*; @@ -42,54 +41,74 @@ public class Turret extends ReloadTurret{ public Effect ammoUseEffect = Fx.none; public Sound shootSound = Sounds.shoot; - //general info - public int maxAmmo = 30; - public int ammoPerShot = 1; + public Effect chargeEffect = Fx.none; + public Effect chargeBeginEffect = Fx.none; + public Sound chargeSound = Sounds.none; + + //visuals public float ammoEjectBack = 1f; - public float inaccuracy = 0f; - public float velocityInaccuracy = 0f; public float shootWarmupSpeed = 0.1f; - public int shots = 1; - public float spread = 4f; public float recoilAmount = 1f; public float restitution = 0.02f; public float cooldown = 0.02f; - public float coolantUsage = 0.2f; - public float shootCone = 8f; + public float elevation = -1f; public float shootShake = 0f; + + public int maxAmmo = 30; + public int ammoPerShot = 1; + + //TODO all the fields below should be deprecated and moved into a ShootPattern class or similar + //TODO ...however, it would be nice to unify the weapon and turret systems into one. + + // below + /** Bullet angle randomness in degrees. */ + public float inaccuracy = 0f; + /** Fraction of bullet velocity that is random. */ + public float velocityInaccuracy = 0f; + /** Number of bullets fired per volley. */ + public int shots = 1; + /** + * Spread between bullets in degrees. + * For some dumb reason, this is also used for the "alternation width", and it's too late to change anything. + * */ + public float spread = 4f; + /** Maximum angle difference in degrees at which turret will still try to shoot. */ + public float shootCone = 8f; + /** Length of turret shoot point. */ public float shootLength = -1; + /** Random spread of projectile across width. This looks stupid. */ public float xRand = 0f; /** Currently used for artillery only. */ public float minRange = 0f; + /** Ticks between shots if shots > 1. */ public float burstSpacing = 0; + /** An inflexible and terrible idea. */ public boolean alternate = false; /** If true, this turret will accurately target moving targets with respect to charge time. */ public boolean accurateDelay = false; - public boolean targetAir = true; - public boolean targetGround = true; - public boolean targetHealing = false; - public boolean playerControllable = true; - public boolean displayAmmoMultiplier = true; //charging public float chargeTime = -1f; public int chargeEffects = 5; public float chargeMaxDelay = 10f; - public Effect chargeEffect = Fx.none; - public Effect chargeBeginEffect = Fx.none; - public Sound chargeSound = Sounds.none; + //see above + + public boolean targetAir = true; + public boolean targetGround = true; + public boolean targetHealing = false; + public boolean playerControllable = true; + public boolean displayAmmoMultiplier = true; public Sortf unitSort = UnitSorts.closest; - /** @deprecated loaded in {@link #draw} instead, unused */ - public @Deprecated @Load(value = "@-base", fallback = "block-@size") TextureRegion baseRegion; - /** @deprecated loaded in {@link #draw} instead, unused */ - public @Deprecated @Load("@-heat") TextureRegion heatRegion; - - public float elevation = -1f; - public DrawBlock draw = new DrawTurret(); + /** @deprecated loaded in {@link #draw} instead, unused */ + @Deprecated + public @Load(value = "@-base", fallback = "block-@size") TextureRegion baseRegion; + /** @deprecated loaded in {@link #draw} instead, unused */ + @Deprecated + public @Load("@-heat") TextureRegion heatRegion; /** @deprecated use bulletOffset; this will always be zero. **/ @Deprecated protected Vec2 tr = new Vec2(); @@ -128,11 +147,6 @@ public class Turret extends ReloadTurret{ @Override public void init(){ - if(acceptCoolant && !consumes.has(ConsumeType.liquid)){ - hasLiquids = true; - consumes.add(new ConsumeCoolant(coolantUsage)).update(false).boost(); - } - if(shootLength < 0) shootLength = size * tilesize / 2f; if(elevation < 0) elevation = size / 2f; @@ -436,6 +450,7 @@ public class Turret extends ReloadTurret{ } protected void shoot(BulletType type){ + //TODO absolute disaster here, combining shot patterns fails in unpredictable ways and I don't want to touch anything in case it breaks mods //when charging is enabled, use the charge shoot pattern if(chargeTime > 0){ @@ -470,6 +485,7 @@ public class Turret extends ReloadTurret{ int ii = i; Time.run(burstSpacing * i, () -> { if(dead || !hasAmmo()) return; + bulletOffset.trns(rotation, shootLength, Mathf.range(xRand)); bullet(type, rotation + Mathf.range(inaccuracy + type.inaccuracy) + (ii - (int)(shots / 2f)) * spread); effects(); @@ -485,7 +501,7 @@ public class Turret extends ReloadTurret{ if(alternate){ float i = (shotCounter % shots) - (shots-1)/2f; - bulletOffset.trns(rotation - 90, spread * i + Mathf.range(xRand), shootLength); + bulletOffset.trns(rotation - 90, (spread) * i + Mathf.range(xRand), shootLength); bullet(type, rotation + Mathf.range(inaccuracy + type.inaccuracy)); }else{ bulletOffset.trns(rotation, shootLength, Mathf.range(xRand)); @@ -511,11 +527,13 @@ public class Turret extends ReloadTurret{ } protected void effects(){ - Effect fshootEffect = shootEffect == Fx.none ? peekAmmo().shootEffect : shootEffect; - Effect fsmokeEffect = smokeEffect == Fx.none ? peekAmmo().smokeEffect : smokeEffect; + var bullet = peekAmmo(); + //TODO "shoot" and "smoke" should just be MultiEffects there's no reason to have them separate + Effect fshootEffect = shootEffect == Fx.none ? bullet.shootEffect : shootEffect; + Effect fsmokeEffect = smokeEffect == Fx.none ? bullet.smokeEffect : smokeEffect; - fshootEffect.at(x + bulletOffset.x, y + bulletOffset.y, rotation); - fsmokeEffect.at(x + bulletOffset.x, y + bulletOffset.y, rotation); + fshootEffect.at(x + bulletOffset.x, y + bulletOffset.y, rotation, bullet.hitColor); + fsmokeEffect.at(x + bulletOffset.x, y + bulletOffset.y, rotation, bullet.hitColor); shootSound.at(x + bulletOffset.x, y + bulletOffset.y, Mathf.random(0.9f, 1.1f)); if(shootShake > 0){