diff --git a/core/assets-raw/sprites/units/weapons/conquer-weapon-sinks-heat.png b/core/assets-raw/sprites/units/weapons/conquer-weapon-sinks-heat.png new file mode 100644 index 0000000000..55a717060d Binary files /dev/null and b/core/assets-raw/sprites/units/weapons/conquer-weapon-sinks-heat.png differ diff --git a/core/assets-raw/sprites/units/weapons/conquer-weapon-sinks.png b/core/assets-raw/sprites/units/weapons/conquer-weapon-sinks.png new file mode 100644 index 0000000000..a41a37c05a Binary files /dev/null and b/core/assets-raw/sprites/units/weapons/conquer-weapon-sinks.png differ diff --git a/core/assets-raw/sprites/units/weapons/conquer-weapon.png b/core/assets-raw/sprites/units/weapons/conquer-weapon.png index 32aad4fecd..79cc1bdcec 100644 Binary files a/core/assets-raw/sprites/units/weapons/conquer-weapon.png and b/core/assets-raw/sprites/units/weapons/conquer-weapon.png differ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 8348aea868..10ec9edd43 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -3116,6 +3116,7 @@ public class Blocks{ parts.addAll( new RegionPart("-back"){{ useReload = false; + mirror = true; rotMove = 40f; x = 22 / 4f; y = -1f / 4f; @@ -3125,6 +3126,7 @@ public class Blocks{ }}, new RegionPart("-front"){{ useReload = false; + mirror = true; rotMove = 40f; x = 20 / 4f; y = 17f / 4f; @@ -3135,6 +3137,7 @@ public class Blocks{ }}, new RegionPart("-nozzle"){{ useReload = false; + mirror = true; moveX = 8f / 4f; heatColor = Color.valueOf("f03b0e"); }}); @@ -3228,6 +3231,7 @@ public class Blocks{ interp = Interp.pow2In; }}, new RegionPart("-side"){{ + mirror = true; moveX = 2f * 4f / 3f; moveY = -0.5f; rotMove = -40f; diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index f47f4049b5..4bf6235628 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -979,6 +979,7 @@ public class UnitTypes{ commandLimit = 4; circleTarget = true; hitSize = 7; + itemCapacity = 15; weapons.add(new Weapon(){{ y = 0f; @@ -2513,7 +2514,7 @@ public class UnitTypes{ //TODO maybe different sprite, weapon impl weapons.add(new Weapon("conquer-weapon"){{ - layerOffset = 0.0001f; + layerOffset = 0.1f; reload = 120f; shootY = 32.5f; shake = 5f; @@ -2527,11 +2528,22 @@ public class UnitTypes{ heatColor = Color.valueOf("f9350f"); cooldownTime = 80f; - parts.add(new RegionPart("-glow"){{ + parts.add( + new RegionPart("-glow"){{ color = Color.red; blending = Blending.additive; outline = mirror = false; - }}); + }}, + new RegionPart("-sinks"){{ + useReload = false; + mirror = true; + under = true; + moveX = 15f / 4f; + moveY = -13f / 4f; + x = 34 / 4f; + y = -36 / 4f; + }} + ); bullet = new BasicBulletType(8f, 110){{ sprite = "missile-large"; @@ -2660,7 +2672,7 @@ public class UnitTypes{ krepost = new UnitType("krepost"){{ drag = 0.1f; - speed = 1f; + speed = 1.1f; hitSize = 44f; health = 18000; armor = 8f; diff --git a/core/src/mindustry/entities/part/RegionPart.java b/core/src/mindustry/entities/part/RegionPart.java index b0a9e834b0..f85179bf9b 100644 --- a/core/src/mindustry/entities/part/RegionPart.java +++ b/core/src/mindustry/entities/part/RegionPart.java @@ -17,10 +17,10 @@ public class RegionPart extends WeaponPart{ /** If true, turret reload is used as the measure of progress. Otherwise, warmup is used. */ public boolean useReload = true; /** If true, parts are mirrored across the turret. Requires -1 and -2 regions. */ - public boolean mirror = true; + public boolean mirror = false; /** If true, an outline is drawn under the part. */ public boolean outline = true; - /** If true, the layer is overridden to be under the turret itself. */ + /** If true, the layer is overridden to be under the weapon/turret itself. */ public boolean under = false; /** If true, the base + outline regions are drawn. Set to false for heat-only regions. */ public boolean drawRegion = true; @@ -35,7 +35,7 @@ public class RegionPart extends WeaponPart{ public float x, y, moveX, moveY; public float oscMag = 0f, oscScl = 7f; public boolean oscAbs = false; - public @Nullable Color color; + public @Nullable Color color, colorTo; public Color heatColor = Pal.turretHeat.cpy(); public RegionPart(String region){ @@ -48,10 +48,10 @@ public class RegionPart extends WeaponPart{ @Override public void draw(PartParams params){ float z = Draw.z(); - if(layer > 0){ - Draw.z(layer); - } - float prevZ = layer > 0 ? layer : z; + if(layer > 0) Draw.z(layer); + if(under) Draw.z(z - 0.0001f); + + float prevZ = Draw.z(); float progress = useReload ? 1f - params.reload : params.warmup; if(oscMag > 0) progress += oscAbs ? Mathf.absin(oscScl, oscMag) : Mathf.sin(oscScl, oscMag); @@ -75,12 +75,16 @@ public class RegionPart extends WeaponPart{ if(outline && drawRegion){ Draw.z(prevZ + outlineLayerOffset); - Draw.rect(outlines[i], rx, ry, rot); + Draw.rect(outlines[Math.min(i, regions.length - 1)], rx, ry, rot); Draw.z(prevZ); } if(drawRegion && region.found()){ - if(color != null) Draw.color(color); + if(color != null && colorTo != null){ + Draw.color(color, colorTo, progress); + }else if(color != null){ + Draw.color(color); + } Draw.blend(blending); Draw.rect(region, rx, ry, rot); Draw.blend(); @@ -88,7 +92,7 @@ public class RegionPart extends WeaponPart{ } if(heat.found()){ - Drawf.additive(heat, heatColor.write(Tmp.c1).a((useProgressHeat ? params.warmup : params.heat) * heatColor.a), rx, ry, rot, Layer.turretHeat); + Drawf.additive(heat, heatColor.write(Tmp.c1).a((useProgressHeat ? params.warmup : params.heat) * heatColor.a), rx, ry, rot, turretShading ? Layer.turretHeat : z + 1f); } Draw.xscl = 1f; @@ -99,8 +103,6 @@ public class RegionPart extends WeaponPart{ @Override public void load(String name){ - if(under) layer = Layer.turret - 0.0001f; - if(drawRegion){ //TODO l/r if(mirror && turretShading){ diff --git a/core/src/mindustry/entities/units/WeaponMount.java b/core/src/mindustry/entities/units/WeaponMount.java index bd8b5d73e4..a0e5219bcf 100644 --- a/core/src/mindustry/entities/units/WeaponMount.java +++ b/core/src/mindustry/entities/units/WeaponMount.java @@ -18,6 +18,8 @@ public class WeaponMount{ public float targetRotation; /** current heat, 0 to 1*/ public float heat; + /** lerps to 1 when shooting, 0 when not */ + public float warmup; /** aiming position in world coordinates */ public float aimX, aimY; /** whether to shoot right now */ diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index d886dce04c..5d85325d1d 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -107,6 +107,17 @@ public class TypeIO{ }else if(object instanceof UnitBox u){ write.b(17); write.i(u.id); + }else if(object instanceof Vec2[] vecs){ + write.b(18); + write.s(vecs.length); + for(Vec2 v : vecs){ + write.f(v.x); + write.f(v.y); + } + }else if(object instanceof Vec2 v){ + write.b((byte)19); + write.f(v.x); + write.f(v.y); }else{ throw new IllegalArgumentException("Unknown object type: " + object.getClass()); } @@ -121,27 +132,53 @@ public class TypeIO{ @Nullable public static Object readObjectBoxed(Reads read, boolean box){ byte type = read.b(); - switch(type){ - case 0: return null; - case 1: return read.i(); - case 2: return read.l(); - case 3: return read.f(); - case 4: return readString(read); - case 5: return content.getByID(ContentType.all[read.b()], read.s()); - case 6: short length = read.s(); IntSeq arr = new IntSeq(); for(int i = 0; i < length; i ++) arr.add(read.i()); return arr; - case 7: return new Point2(read.i(), read.i()); - case 8: byte len = read.b(); Point2[] out = new Point2[len]; for(int i = 0; i < len; i ++) out[i] = Point2.unpack(read.i()); return out; - case 9: return content.getByID(ContentType.all[read.b()], read.s()).techNode; - case 10: return read.bool(); - case 11: return read.d(); - case 12: return !box ? world.build(read.i()) : new BuildingBox(read.i()); - case 13: return LAccess.all[read.s()]; - case 14: int blen = read.i(); byte[] bytes = new byte[blen]; read.b(bytes); return bytes; - case 15: return UnitCommand.all[read.b()]; - case 16: int boollen = read.i(); boolean[] bools = new boolean[boollen]; for(int i = 0; i < boollen; i ++) bools[i] = read.bool(); return bools; - case 17: return !box ? Groups.unit.getByID(read.i()) : new UnitBox(read.i()); - default: throw new IllegalArgumentException("Unknown object type: " + type); - } + return switch(type){ + case 0 -> null; + case 1 -> read.i(); + case 2 -> read.l(); + case 3 -> read.f(); + case 4 -> readString(read); + case 5 -> content.getByID(ContentType.all[read.b()], read.s()); + case 6 -> { + short length = read.s(); + IntSeq arr = new IntSeq(); for(int i = 0; i < length; i ++) arr.add(read.i()); + yield arr; + } + case 7 -> new Point2(read.i(), read.i()); + case 8 -> { + byte len = read.b(); + Point2[] out = new Point2[len]; + for(int i = 0; i < len; i ++) out[i] = Point2.unpack(read.i()); + yield out; + } + case 9 -> content.getByID(ContentType.all[read.b()], read.s()).techNode; + case 10 -> read.bool(); + case 11 -> read.d(); + case 12 -> !box ? world.build(read.i()) : new BuildingBox(read.i()); + case 13 -> LAccess.all[read.s()]; + case 14 -> { + int blen = read.i(); + byte[] bytes = new byte[blen]; + read.b(bytes); + yield bytes; + } + case 15 -> UnitCommand.all[read.b()]; + case 16 -> { + int boollen = read.i(); + boolean[] bools = new boolean[boollen]; + for(int i = 0; i < boollen; i ++) bools[i] = read.bool(); + yield bools; + } + case 17 -> !box ? Groups.unit.getByID(read.i()) : new UnitBox(read.i()); + case 18 -> { + int len = read.s(); + Vec2[] out = new Vec2[len]; + for(int i = 0; i < len; i ++) out[i] = new Vec2(read.f(), read.f()); + yield out; + } + case 19 -> new Vec2(read.f(), read.f()); + default -> throw new IllegalArgumentException("Unknown object type: " + type); + }; } public static void writePayload(Writes writes, Payload payload){ diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index c5cd032830..c0e74370fb 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -92,6 +92,8 @@ public class Weapon implements Cloneable{ public float rotationLimit = 361f; /** ticks to cool down the heat region */ public float cooldownTime = 20f; + /** lerp speed for shoot warmup, only used for parts */ + public float shootWarmupSpeed = 0.1f; /** random sound pitch range */ public float soundPitchMin = 0.8f, soundPitchMax = 1f; /** whether shooter rotation is ignored when shooting. */ @@ -216,7 +218,7 @@ public class Weapon implements Cloneable{ Draw.z(Layer.turret); }*/ - var params = WeaponPart.params.set(0f, Mathf.clamp(mount.reload / reload), mount.heat, wx, wy, weaponRotation + 90); + var params = WeaponPart.params.set(mount.warmup, 1f - Mathf.clamp(mount.reload / reload), mount.heat, wx, wy, weaponRotation + 90); for(var part : parts){ part.draw(params); @@ -237,6 +239,7 @@ public class Weapon implements Cloneable{ float lastReload = mount.reload; mount.reload = Math.max(mount.reload - Time.delta * unit.reloadMultiplier, 0); mount.recoil = Mathf.approachDelta(mount.recoil, 0, (Math.abs(recoil) * unit.reloadMultiplier) / recoilTime); + mount.warmup = Mathf.lerpDelta(mount.warmup, can && mount.shoot ? 1f : 0f, shootWarmupSpeed); //rotate if applicable if(rotate && (mount.rotate || mount.shoot) && can){