mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-01-27 06:51:30 -08:00
Multi shotgun fix (#8460)
* Multi-barrel shotgun fix * multi-recoil support * @Nullable for everything
This commit is contained in:
parent
2075a226e1
commit
6d71bcd2eb
13 changed files with 73 additions and 20 deletions
|
|
@ -14,6 +14,8 @@ public abstract class DrawPart{
|
|||
public boolean under = false;
|
||||
/** For units, this is the index of the weapon this part gets its progress for. */
|
||||
public int weaponIndex = 0;
|
||||
/** Which recoil counter to use. < 0 to use base recoil. */
|
||||
public int recoilIndex = -1;
|
||||
|
||||
public abstract void draw(PartParams params);
|
||||
public abstract void load(String name);
|
||||
|
|
@ -41,6 +43,11 @@ public abstract class DrawPart{
|
|||
this.sideMultiplier = 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PartParams setRecoil(float recoils){
|
||||
this.recoil = recoils;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PartMove{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package mindustry.entities.pattern;
|
||||
|
||||
import arc.util.*;
|
||||
|
||||
public class ShootAlternate extends ShootPattern{
|
||||
/** number of barrels used for shooting. */
|
||||
public int barrels = 2;
|
||||
|
|
@ -16,10 +18,11 @@ public class ShootAlternate extends ShootPattern{
|
|||
}
|
||||
|
||||
@Override
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
public void shoot(int totalShots, BulletHandler handler, @Nullable Runnable barrelIncrementer){
|
||||
for(int i = 0; i < shots; i++){
|
||||
float index = ((totalShots + i + barrelOffset) % barrels) - (barrels-1)/2f;
|
||||
handler.shoot(index * spread, 0, 0f, firstShotDelay + shotDelay * i);
|
||||
if(barrelIncrementer != null) barrelIncrementer.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package mindustry.entities.pattern;
|
||||
|
||||
import arc.util.*;
|
||||
|
||||
public class ShootBarrel extends ShootPattern{
|
||||
/** barrels [in x, y, rotation] format. */
|
||||
public float[] barrels = {0f, 0f, 0f};
|
||||
|
|
@ -16,10 +18,11 @@ public class ShootBarrel extends ShootPattern{
|
|||
}
|
||||
|
||||
@Override
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
public void shoot(int totalShots, BulletHandler handler, @Nullable Runnable barrelIncrementer){
|
||||
for(int i = 0; i < shots; i++){
|
||||
int index = ((i + totalShots + barrelOffset) % (barrels.length / 3)) * 3;
|
||||
handler.shoot(barrels[index], barrels[index + 1], barrels[index + 2], firstShotDelay + shotDelay * i);
|
||||
if(barrelIncrementer != null) barrelIncrementer.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
package mindustry.entities.pattern;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
|
||||
public class ShootHelix extends ShootPattern{
|
||||
public float scl = 2f, mag = 1.5f, offset = Mathf.PI * 1.25f;
|
||||
|
||||
@Override
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
public void shoot(int totalShots, BulletHandler handler, @Nullable Runnable barrelIncrementer){
|
||||
for(int i = 0; i < shots; i++){
|
||||
for(int sign : Mathf.signs){
|
||||
handler.shoot(0, 0, 0, firstShotDelay + shotDelay * i,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package mindustry.entities.pattern;
|
||||
|
||||
import arc.util.*;
|
||||
|
||||
public class ShootMulti extends ShootPattern{
|
||||
public ShootPattern source;
|
||||
public ShootPattern[] dest = {};
|
||||
|
|
@ -25,7 +27,7 @@ public class ShootMulti extends ShootPattern{
|
|||
}
|
||||
|
||||
@Override
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
public void shoot(int totalShots, BulletHandler handler, @Nullable Runnable barrelIncrementer){
|
||||
source.shoot(totalShots, (x, y, rotation, delay, move) -> {
|
||||
for(var pattern : dest){
|
||||
pattern.shoot(totalShots, (x2, y2, rot2, delay2, mover) -> {
|
||||
|
|
@ -35,6 +37,6 @@ public class ShootMulti extends ShootPattern{
|
|||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}, barrelIncrementer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package mindustry.entities.pattern;
|
||||
|
||||
import arc.util.*;
|
||||
import mindustry.entities.*;
|
||||
|
||||
/** Handles different types of bullet patterns for shooting. */
|
||||
|
|
@ -12,12 +13,17 @@ public class ShootPattern implements Cloneable{
|
|||
public float shotDelay = 0;
|
||||
|
||||
/** Called on a single "trigger pull". This function should call the handler with any bullets that result. */
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
public void shoot(int totalShots, BulletHandler handler, @Nullable Runnable barrelIncrementer){
|
||||
for(int i = 0; i < shots; i++){
|
||||
handler.shoot(0, 0, 0, firstShotDelay + shotDelay * i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Called on a single "trigger pull". This function should call the handler with any bullets that result. */
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
shoot(totalShots, handler, null);
|
||||
}
|
||||
|
||||
/** Subclasses should override this to flip its sides. */
|
||||
public void flip(){
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package mindustry.entities.pattern;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
|
||||
public class ShootSine extends ShootPattern{
|
||||
/** scaling applied to bullet index */
|
||||
|
|
@ -17,7 +18,7 @@ public class ShootSine extends ShootPattern{
|
|||
}
|
||||
|
||||
@Override
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
public void shoot(int totalShots, BulletHandler handler, @Nullable Runnable barrelIncrementer){
|
||||
for(int i = 0; i < shots; i++){
|
||||
float angleOffset = Mathf.sin(i + totalShots, scl, mag);
|
||||
handler.shoot(0, 0, angleOffset, firstShotDelay + shotDelay * i);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package mindustry.entities.pattern;
|
||||
|
||||
import arc.util.*;
|
||||
|
||||
public class ShootSpread extends ShootPattern{
|
||||
/** spread between bullets, in degrees. */
|
||||
public float spread = 5f;
|
||||
|
|
@ -13,7 +15,7 @@ public class ShootSpread extends ShootPattern{
|
|||
}
|
||||
|
||||
@Override
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
public void shoot(int totalShots, BulletHandler handler, @Nullable Runnable barrelIncrementer){
|
||||
for(int i = 0; i < shots; i++){
|
||||
float angleOffset = i * spread - (shots - 1) * spread / 2f;
|
||||
handler.shoot(0, 0, angleOffset, firstShotDelay + shotDelay * i);
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ public class ShootSummon extends ShootPattern{
|
|||
}
|
||||
|
||||
@Override
|
||||
public void shoot(int totalShots, BulletHandler handler){
|
||||
|
||||
|
||||
public void shoot(int totalShots, BulletHandler handler, @Nullable Runnable barrelIncrementer){
|
||||
for(int i = 0; i < shots; i++){
|
||||
Tmp.v1.trns(Mathf.random(360f), Mathf.random(radius));
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ public class WeaponMount{
|
|||
public float rotation;
|
||||
/** weapon recoil */
|
||||
public float recoil;
|
||||
/** weapon barrel recoil */
|
||||
public @Nullable float[] recoils;
|
||||
/** destination rotation; do not modify! */
|
||||
public float targetRotation;
|
||||
/** current heat, 0 to 1*/
|
||||
|
|
@ -34,8 +36,10 @@ public class WeaponMount{
|
|||
public boolean rotate = false;
|
||||
/** extra state for alternating weapons */
|
||||
public boolean side;
|
||||
/** total bullets fired from this mount; used for alternating patterns */
|
||||
/** total bullets fired from this mount */
|
||||
public int totalShots;
|
||||
/** counter for which barrel bullets have been fired from; used for alternating patterns */
|
||||
public int barrelCounter;
|
||||
/** current bullet for continuous weapons */
|
||||
public @Nullable Bullet bullet;
|
||||
/** sound loop for continuous weapons */
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ public class Weapon implements Cloneable{
|
|||
public float shake = 0f;
|
||||
/** visual weapon knockback. */
|
||||
public float recoil = 1.5f;
|
||||
/** Number of additional counters for recoil. */
|
||||
public int recoils = -1;
|
||||
/** time taken for weapon to return to starting position in ticks. uses reload time by default */
|
||||
public float recoilTime = -1f;
|
||||
/** power curve applied to visual recoil */
|
||||
|
|
@ -219,6 +221,7 @@ public class Weapon implements Cloneable{
|
|||
|
||||
for(int i = 0; i < parts.size; i++){
|
||||
var part = parts.get(i);
|
||||
DrawPart.params.setRecoil(part.recoilIndex >= 0 ? mount.recoils[part.recoilIndex] : mount.recoil);
|
||||
if(part.under){
|
||||
part.draw(DrawPart.params);
|
||||
}
|
||||
|
|
@ -250,6 +253,7 @@ public class Weapon implements Cloneable{
|
|||
//TODO does it need an outline?
|
||||
for(int i = 0; i < parts.size; i++){
|
||||
var part = parts.get(i);
|
||||
DrawPart.params.setRecoil(part.recoilIndex >= 0 ? mount.recoils[part.recoilIndex] : mount.recoil);
|
||||
if(!part.under){
|
||||
part.draw(DrawPart.params);
|
||||
}
|
||||
|
|
@ -270,6 +274,12 @@ 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, unit.reloadMultiplier / recoilTime);
|
||||
if(recoils > 0){
|
||||
if(mount.recoils == null) mount.recoils = new float[recoils];
|
||||
for(int i = 0; i < recoils; i++){
|
||||
mount.recoils[i] = Mathf.approachDelta(mount.recoils[i], 0, unit.reloadMultiplier / recoilTime);
|
||||
}
|
||||
}
|
||||
mount.smoothReload = Mathf.lerpDelta(mount.smoothReload, mount.reload / reload, smoothReloadSpeed);
|
||||
mount.charge = mount.charging && shoot.firstShotDelay > 0 ? Mathf.approachDelta(mount.charge, 1, 1 / shoot.firstShotDelay) : 0;
|
||||
|
||||
|
|
@ -420,14 +430,13 @@ public class Weapon implements Cloneable{
|
|||
bullet.chargeEffect.at(shootX, shootY, rotation, bullet.keepVelocity || parentizeEffects ? unit : null);
|
||||
}
|
||||
|
||||
shoot.shoot(mount.totalShots, (xOffset, yOffset, angle, delay, mover) -> {
|
||||
mount.totalShots++;
|
||||
shoot.shoot(mount.barrelCounter, (xOffset, yOffset, angle, delay, mover) -> {
|
||||
if(delay > 0f){
|
||||
Time.run(delay, () -> bullet(unit, mount, xOffset, yOffset, angle, mover));
|
||||
}else{
|
||||
bullet(unit, mount, xOffset, yOffset, angle, mover);
|
||||
}
|
||||
});
|
||||
}, () -> mount.barrelCounter++);
|
||||
}
|
||||
|
||||
protected void bullet(Unit unit, WeaponMount mount, float xOffset, float yOffset, float angleOffset, Mover mover){
|
||||
|
|
@ -459,7 +468,11 @@ public class Weapon implements Cloneable{
|
|||
unit.vel.add(Tmp.v1.trns(shootAngle + 180f, bullet.recoil));
|
||||
Effect.shake(shake, shake, bulletX, bulletY);
|
||||
mount.recoil = 1f;
|
||||
if(recoils > 0){
|
||||
mount.recoils[mount.barrelCounter % recoils] = 1f;
|
||||
}
|
||||
mount.heat = 1f;
|
||||
mount.totalShots++;
|
||||
}
|
||||
|
||||
//override to do special things to a bullet after spawning
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ public class Turret extends ReloadTurret{
|
|||
public boolean linearWarmup = false;
|
||||
/** Visual amount by which the turret recoils back per shot. */
|
||||
public float recoil = 1f;
|
||||
/** Number of additional counters for recoil. */
|
||||
public int recoils = -1;
|
||||
/** ticks taken for turret to return to starting position in ticks. uses reload time by default */
|
||||
public float recoilTime = -1f;
|
||||
/** power curve applied to visual recoil */
|
||||
|
|
@ -210,8 +212,9 @@ public class Turret extends ReloadTurret{
|
|||
public Seq<AmmoEntry> ammo = new Seq<>();
|
||||
public int totalAmmo;
|
||||
public float curRecoil, heat, logicControlTime = -1;
|
||||
public @Nullable float[] curRecoils;
|
||||
public float shootWarmup, charge, warmupHold = 0f;
|
||||
public int totalShots;
|
||||
public int totalShots, barrelCounter;
|
||||
public boolean logicShooting = false;
|
||||
public @Nullable Posc target;
|
||||
public Vec2 targetPos = new Vec2();
|
||||
|
|
@ -365,6 +368,12 @@ public class Turret extends ReloadTurret{
|
|||
wasShooting = false;
|
||||
|
||||
curRecoil = Mathf.approachDelta(curRecoil, 0, 1 / recoilTime);
|
||||
if(recoils > 0){
|
||||
if(curRecoils == null) curRecoils = new float[recoils];
|
||||
for(int i = 0; i < recoils; i++){
|
||||
curRecoils[i] = Mathf.approachDelta(curRecoils[i], 0, 1 / recoilTime);
|
||||
}
|
||||
}
|
||||
heat = Mathf.approachDelta(heat, 0, 1 / cooldownTime);
|
||||
charge = charging() ? Mathf.approachDelta(charge, 1, 1 / shoot.firstShotDelay) : 0;
|
||||
|
||||
|
|
@ -537,15 +546,14 @@ public class Turret extends ReloadTurret{
|
|||
type.chargeEffect.at(bulletX, bulletY, rotation);
|
||||
}
|
||||
|
||||
shoot.shoot(totalShots, (xOffset, yOffset, angle, delay, mover) -> {
|
||||
queuedBullets ++;
|
||||
shoot.shoot(barrelCounter, (xOffset, yOffset, angle, delay, mover) -> {
|
||||
queuedBullets++;
|
||||
if(delay > 0f){
|
||||
Time.run(delay, () -> bullet(type, xOffset, yOffset, angle, mover));
|
||||
}else{
|
||||
bullet(type, xOffset, yOffset, angle, mover);
|
||||
}
|
||||
totalShots ++;
|
||||
});
|
||||
}, () -> barrelCounter++);
|
||||
|
||||
if(consumeAmmoOnce){
|
||||
useAmmo();
|
||||
|
|
@ -583,7 +591,11 @@ public class Turret extends ReloadTurret{
|
|||
}
|
||||
|
||||
curRecoil = 1f;
|
||||
if(recoils > 0){
|
||||
curRecoils[barrelCounter % recoils] = 1f;
|
||||
}
|
||||
heat = 1f;
|
||||
totalShots++;
|
||||
|
||||
if(!consumeAmmoOnce){
|
||||
useAmmo();
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ public class DrawTurret extends DrawBlock{
|
|||
var params = DrawPart.params.set(build.warmup(), 1f - progress, 1f - progress, tb.heat, tb.curRecoil, tb.charge, tb.x + tb.recoilOffset.x, tb.y + tb.recoilOffset.y, tb.rotation);
|
||||
|
||||
for(var part : parts){
|
||||
params.setRecoil(part.recoilIndex >= 0 ? tb.curRecoils[part.recoilIndex] : tb.curRecoil);
|
||||
part.draw(params);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue