diff --git a/core/src/mindustry/entities/units/WeaponMount.java b/core/src/mindustry/entities/units/WeaponMount.java index 8254c8ca2f..bd8b5d73e4 100644 --- a/core/src/mindustry/entities/units/WeaponMount.java +++ b/core/src/mindustry/entities/units/WeaponMount.java @@ -12,6 +12,8 @@ public class WeaponMount{ public float reload; /** rotation relative to the unit this mount is on */ public float rotation; + /** weapon recoil */ + public float recoil; /** destination rotation; do not modify! */ public float targetRotation; /** current heat, 0 to 1*/ diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 7d7357b871..f9fcf6b078 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -375,6 +375,7 @@ public class UnitType extends UnlockableContent{ //add mirrored weapon variants Seq mapped = new Seq<>(); for(Weapon w : weapons){ + if(w.recoilTime < 0) w.recoilTime = w.reload; mapped.add(w); //mirrors are copies with X values negated @@ -385,7 +386,9 @@ public class UnitType extends UnlockableContent{ copy.flipSprite = !copy.flipSprite; mapped.add(copy); - //since there are now two weapons, the reload time must be doubled + //since there are now two weapons, the reload and recoil time must be doubled + w.recoilTime *= 2f; + copy.recoilTime *= 2f; w.reload *= 2f; copy.reload *= 2f; diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index c96482d15d..f472f7a03a 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -67,6 +67,8 @@ public class Weapon implements Cloneable{ public float shake = 0f; /** visual weapon knockback. */ public float recoil = 1.5f; + /** the time it returns back to its original position in ticks. uses reload time by default */ + public float recoilTime = -1f; /** projectile/effect offsets from center of weapon */ public float shootX = 0f, shootY = 3f; /** offsets of weapon position on unit */ @@ -144,9 +146,8 @@ public class Weapon implements Cloneable{ float rotation = unit.rotation - 90, weaponRotation = rotation + (rotate ? mount.rotation : 0), - recoil = -((mount.reload) / reload * this.recoil), - wx = unit.x + Angles.trnsx(rotation, x, y) + Angles.trnsx(weaponRotation, 0, recoil), - wy = unit.y + Angles.trnsy(rotation, x, y) + Angles.trnsy(weaponRotation, 0, recoil); + wx = unit.x + Angles.trnsx(rotation, x, y) + Angles.trnsx(weaponRotation, 0, -mount.recoil), + wy = unit.y + Angles.trnsy(rotation, x, y) + Angles.trnsy(weaponRotation, 0, -mount.recoil); if(outlineRegion.found()){ Draw.rect(outlineRegion, @@ -161,9 +162,8 @@ public class Weapon implements Cloneable{ float rotation = unit.rotation - 90, weaponRotation = rotation + (rotate ? mount.rotation : 0), - recoil = -((mount.reload) / reload * this.recoil), - wx = unit.x + Angles.trnsx(rotation, x, y) + Angles.trnsx(weaponRotation, 0, recoil), - wy = unit.y + Angles.trnsy(rotation, x, y) + Angles.trnsy(weaponRotation, 0, recoil); + wx = unit.x + Angles.trnsx(rotation, x, y) + Angles.trnsx(weaponRotation, 0, -mount.recoil), + wy = unit.y + Angles.trnsy(rotation, x, y) + Angles.trnsy(weaponRotation, 0, -mount.recoil); if(shadow > 0){ Drawf.shadow(wx, wy, shadow); @@ -198,7 +198,9 @@ public class Weapon implements Cloneable{ public void update(Unit unit, WeaponMount mount){ boolean can = unit.canShoot(); + float lastReload = mount.reload; mount.reload = Math.max(mount.reload - Time.delta * unit.reloadMultiplier, 0); + mount.recoil = Math.max(mount.recoil - (Time.delta * recoil * unit.reloadMultiplier) / recoilTime, 0); //rotate if applicable if(rotate && (mount.rotate || mount.shoot) && can){ @@ -260,6 +262,7 @@ public class Weapon implements Cloneable{ mount.bullet.rotation(weaponRotation + 90); mount.bullet.set(bulletX, bulletY); mount.reload = reload; + mount.recoil = recoil; unit.vel.add(Tmp.v1.trns(unit.rotation + 180f, mount.bullet.type.recoil)); if(shootSound != Sounds.none && !headless){ if(mount.sound == null) mount.sound = new SoundLoop(shootSound, 1f); @@ -275,9 +278,9 @@ public class Weapon implements Cloneable{ } } - //flip weapon shoot side for alternating weapons at half reload - if(otherSide != -1 && alternate && mount.side == flipSprite && - mount.reload + Time.delta * unit.reloadMultiplier > reload/2f && mount.reload <= reload/2f){ + //flip weapon shoot side for alternating weapons + boolean wasFlipped = mount.side; + if(otherSide != -1 && alternate && mount.side == flipSprite && mount.reload <= reload / 2f && lastReload > reload / 2f){ unit.mounts[otherSide].side = !unit.mounts[otherSide].side; mount.side = !mount.side; } @@ -286,7 +289,7 @@ public class Weapon implements Cloneable{ if(mount.shoot && //must be shooting can && //must be able to shoot (!useAmmo || unit.ammo > 0 || !state.rules.unitAmmo || unit.team.rules().infiniteAmmo) && //check ammo - (!alternate || mount.side == flipSprite) && + (!alternate || wasFlipped == flipSprite) && unit.vel.len() >= minShootVelocity && //check velocity requirements mount.reload <= 0.0001f && //reload has to be 0 Angles.within(rotate ? mount.rotation : unit.rotation, mount.targetRotation, shootCone) //has to be within the cone @@ -354,6 +357,7 @@ public class Weapon implements Cloneable{ mount.heat = 1f; } + mount.recoil = recoil; ejectEffect.at(mountX, mountY, rotation * side); ammo.shootEffect.at(shootX, shootY, rotation, parentize ? unit : null); ammo.smokeEffect.at(shootX, shootY, rotation, parentize ? unit : null);