Turret pattern rewrite
This commit is contained in:
@@ -8,6 +8,7 @@ import mindustry.entities.*;
|
|||||||
import mindustry.entities.bullet.*;
|
import mindustry.entities.bullet.*;
|
||||||
import mindustry.entities.effect.*;
|
import mindustry.entities.effect.*;
|
||||||
import mindustry.entities.part.*;
|
import mindustry.entities.part.*;
|
||||||
|
import mindustry.entities.pattern.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.graphics.*;
|
import mindustry.graphics.*;
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
@@ -2725,9 +2726,11 @@ public class Blocks{
|
|||||||
Items.silicon, Bullets.standardHoming
|
Items.silicon, Bullets.standardHoming
|
||||||
);
|
);
|
||||||
|
|
||||||
spread = 4f;
|
shoot = new ShootAlternate(){{
|
||||||
shots = 2;
|
spread = 3.5f;
|
||||||
alternate = true;
|
}};
|
||||||
|
|
||||||
|
shootY = 3f;
|
||||||
reloadTime = 20f;
|
reloadTime = 20f;
|
||||||
restitution = 0.03f;
|
restitution = 0.03f;
|
||||||
range = 110;
|
range = 110;
|
||||||
@@ -2751,10 +2754,11 @@ public class Blocks{
|
|||||||
reloadTime = 18f;
|
reloadTime = 18f;
|
||||||
range = 220f;
|
range = 220f;
|
||||||
size = 2;
|
size = 2;
|
||||||
burstSpacing = 5f;
|
|
||||||
shots = 2;
|
|
||||||
targetGround = false;
|
targetGround = false;
|
||||||
|
|
||||||
|
shoot.shotDelay = 5f;
|
||||||
|
shoot.shots = 2;
|
||||||
|
|
||||||
recoilAmount = 2f;
|
recoilAmount = 2f;
|
||||||
rotateSpeed = 15f;
|
rotateSpeed = 15f;
|
||||||
inaccuracy = 17f;
|
inaccuracy = 17f;
|
||||||
@@ -2828,17 +2832,15 @@ public class Blocks{
|
|||||||
lancer = new PowerTurret("lancer"){{
|
lancer = new PowerTurret("lancer"){{
|
||||||
requirements(Category.turret, with(Items.copper, 60, Items.lead, 70, Items.silicon, 50));
|
requirements(Category.turret, with(Items.copper, 60, Items.lead, 70, Items.silicon, 50));
|
||||||
range = 165f;
|
range = 165f;
|
||||||
chargeTime = 40f;
|
|
||||||
chargeMaxDelay = 30f;
|
shoot.firstShotDelay = 40f;
|
||||||
chargeEffects = 7;
|
|
||||||
recoilAmount = 2f;
|
recoilAmount = 2f;
|
||||||
reloadTime = 80f;
|
reloadTime = 80f;
|
||||||
cooldown = 0.03f;
|
cooldown = 0.03f;
|
||||||
shootShake = 2f;
|
shootShake = 2f;
|
||||||
shootEffect = Fx.lancerLaserShoot;
|
shootEffect = Fx.lancerLaserShoot;
|
||||||
smokeEffect = Fx.none;
|
smokeEffect = Fx.none;
|
||||||
chargeEffect = Fx.lancerLaserCharge;
|
|
||||||
chargeBeginEffect = Fx.lancerLaserChargeBegin;
|
|
||||||
heatColor = Color.red;
|
heatColor = Color.red;
|
||||||
size = 2;
|
size = 2;
|
||||||
scaledHealth = 280;
|
scaledHealth = 280;
|
||||||
@@ -2850,6 +2852,9 @@ public class Blocks{
|
|||||||
|
|
||||||
shootType = new LaserBulletType(140){{
|
shootType = new LaserBulletType(140){{
|
||||||
colors = new Color[]{Pal.lancerLaser.cpy().a(0.4f), Pal.lancerLaser, Color.white};
|
colors = new Color[]{Pal.lancerLaser.cpy().a(0.4f), Pal.lancerLaser, Color.white};
|
||||||
|
//TODO merge
|
||||||
|
chargeEffect = new MultiEffect(Fx.lancerLaserCharge, Fx.lancerLaserChargeBegin);
|
||||||
|
|
||||||
hitEffect = Fx.hitLancer;
|
hitEffect = Fx.hitLancer;
|
||||||
hitSize = 4;
|
hitSize = 4;
|
||||||
lifetime = 16f;
|
lifetime = 16f;
|
||||||
@@ -2905,12 +2910,16 @@ public class Blocks{
|
|||||||
Items.pyratite, Bullets.missileIncendiary,
|
Items.pyratite, Bullets.missileIncendiary,
|
||||||
Items.surgeAlloy, Bullets.missileSurge
|
Items.surgeAlloy, Bullets.missileSurge
|
||||||
);
|
);
|
||||||
reloadTime = 30f;
|
|
||||||
|
shoot = new ShootAlternate(){{
|
||||||
shots = 4;
|
shots = 4;
|
||||||
burstSpacing = 5;
|
spread = 3.5f;
|
||||||
|
shotDelay = 5f;
|
||||||
|
}};
|
||||||
|
|
||||||
|
reloadTime = 30f;
|
||||||
inaccuracy = 10f;
|
inaccuracy = 10f;
|
||||||
range = 240f;
|
range = 240f;
|
||||||
xRand = 6f;
|
|
||||||
size = 2;
|
size = 2;
|
||||||
scaledHealth = 300;
|
scaledHealth = 300;
|
||||||
shootSound = Sounds.missile;
|
shootSound = Sounds.missile;
|
||||||
@@ -2938,9 +2947,9 @@ public class Blocks{
|
|||||||
cooldown = 0.03f;
|
cooldown = 0.03f;
|
||||||
recoilAmount = 3f;
|
recoilAmount = 3f;
|
||||||
shootShake = 1f;
|
shootShake = 1f;
|
||||||
burstSpacing = 3f;
|
shoot.shots = 4;
|
||||||
spread = 0f;
|
shoot.shotDelay = 3f;
|
||||||
shots = 4;
|
|
||||||
ammoUseEffect = Fx.casing2;
|
ammoUseEffect = Fx.casing2;
|
||||||
scaledHealth = 240;
|
scaledHealth = 240;
|
||||||
shootSound = Sounds.shootBig;
|
shootSound = Sounds.shootBig;
|
||||||
@@ -2973,7 +2982,7 @@ public class Blocks{
|
|||||||
);
|
);
|
||||||
size = 3;
|
size = 3;
|
||||||
reloadTime = 3f;
|
reloadTime = 3f;
|
||||||
shots = 2;
|
shoot.shots = 2;
|
||||||
velocityInaccuracy = 0.1f;
|
velocityInaccuracy = 0.1f;
|
||||||
inaccuracy = 4f;
|
inaccuracy = 4f;
|
||||||
recoilAmount = 1f;
|
recoilAmount = 1f;
|
||||||
@@ -2993,8 +3002,12 @@ public class Blocks{
|
|||||||
shootShake = 4f;
|
shootShake = 4f;
|
||||||
range = 90f;
|
range = 90f;
|
||||||
recoilAmount = 5f;
|
recoilAmount = 5f;
|
||||||
|
|
||||||
|
shoot = new ShootSpread(){{
|
||||||
shots = 3;
|
shots = 3;
|
||||||
spread = 20f;
|
spread = 20f;
|
||||||
|
}};
|
||||||
|
|
||||||
restitution = 0.1f;
|
restitution = 0.1f;
|
||||||
shootCone = 30;
|
shootCone = 30;
|
||||||
size = 3;
|
size = 3;
|
||||||
@@ -3036,7 +3049,7 @@ public class Blocks{
|
|||||||
|
|
||||||
targetAir = false;
|
targetAir = false;
|
||||||
size = 3;
|
size = 3;
|
||||||
shots = 4;
|
shoot.shots = 4;
|
||||||
inaccuracy = 12f;
|
inaccuracy = 12f;
|
||||||
reloadTime = 60f;
|
reloadTime = 60f;
|
||||||
ammoEjectBack = 5f;
|
ammoEjectBack = 5f;
|
||||||
@@ -3063,7 +3076,14 @@ public class Blocks{
|
|||||||
Items.plastanium, Bullets.fragPlastic,
|
Items.plastanium, Bullets.fragPlastic,
|
||||||
Items.surgeAlloy, Bullets.fragSurge
|
Items.surgeAlloy, Bullets.fragSurge
|
||||||
);
|
);
|
||||||
xRand = 4f;
|
shootY = 8.75f;
|
||||||
|
shoot = new ShootBarrel(){{
|
||||||
|
barrels = new float[]{
|
||||||
|
0f, 1f, 0f,
|
||||||
|
3f, 0f, 0f,
|
||||||
|
-3f, 0f, 0f,
|
||||||
|
};
|
||||||
|
}};
|
||||||
reloadTime = 8f;
|
reloadTime = 8f;
|
||||||
range = 200f;
|
range = 200f;
|
||||||
size = 3;
|
size = 3;
|
||||||
@@ -3107,7 +3127,6 @@ public class Blocks{
|
|||||||
restitution = 0.009f;
|
restitution = 0.009f;
|
||||||
cooldown = 0.009f;
|
cooldown = 0.009f;
|
||||||
shootShake = 4f;
|
shootShake = 4f;
|
||||||
shots = 1;
|
|
||||||
size = 4;
|
size = 4;
|
||||||
shootCone = 2f;
|
shootCone = 2f;
|
||||||
shootSound = Sounds.railgun;
|
shootSound = Sounds.railgun;
|
||||||
@@ -3135,10 +3154,10 @@ public class Blocks{
|
|||||||
range = 260f;
|
range = 260f;
|
||||||
inaccuracy = 3f;
|
inaccuracy = 3f;
|
||||||
recoilAmount = 3f;
|
recoilAmount = 3f;
|
||||||
|
shoot = new ShootAlternate(){{
|
||||||
spread = 8f;
|
spread = 8f;
|
||||||
alternate = true;
|
}};
|
||||||
shootShake = 2f;
|
shootShake = 2f;
|
||||||
shots = 2;
|
|
||||||
size = 4;
|
size = 4;
|
||||||
shootCone = 24f;
|
shootCone = 24f;
|
||||||
shootSound = Sounds.shootBig;
|
shootSound = Sounds.shootBig;
|
||||||
@@ -3165,6 +3184,11 @@ public class Blocks{
|
|||||||
loopSoundVolume = 2f;
|
loopSoundVolume = 2f;
|
||||||
envEnabled |= Env.space;
|
envEnabled |= Env.space;
|
||||||
|
|
||||||
|
shoot = new ShootSpread(){{
|
||||||
|
shots = 3;
|
||||||
|
spread = 10f;
|
||||||
|
}};
|
||||||
|
|
||||||
shootType = new ContinuousLaserBulletType(78){{
|
shootType = new ContinuousLaserBulletType(78){{
|
||||||
length = 200f;
|
length = 200f;
|
||||||
hitEffect = Fx.hitMeltdown;
|
hitEffect = Fx.hitMeltdown;
|
||||||
@@ -3227,7 +3251,7 @@ public class Blocks{
|
|||||||
shootShake = 1f;
|
shootShake = 1f;
|
||||||
ammoPerShot = 5;
|
ammoPerShot = 5;
|
||||||
draw = new DrawTurret("reinforced-");
|
draw = new DrawTurret("reinforced-");
|
||||||
shootLength = -2;
|
shootY = -2;
|
||||||
outlineColor = Pal.darkOutline;
|
outlineColor = Pal.darkOutline;
|
||||||
size = 3;
|
size = 3;
|
||||||
envEnabled |= Env.space;
|
envEnabled |= Env.space;
|
||||||
@@ -3287,13 +3311,13 @@ public class Blocks{
|
|||||||
|
|
||||||
liquidConsumed = 4f / 60f;
|
liquidConsumed = 4f / 60f;
|
||||||
|
|
||||||
range = 130f;
|
float r = range = 130f;
|
||||||
|
|
||||||
//TODO balance, set up, where is liquid/sec displayed? status effects maybe?
|
//TODO balance, set up, where is liquid/sec displayed? status effects maybe?
|
||||||
ammo(
|
ammo(
|
||||||
Liquids.ozone, new ContinuousFlameBulletType(){{
|
Liquids.ozone, new ContinuousFlameBulletType(){{
|
||||||
damage = 90f;
|
damage = 90f;
|
||||||
length = range;
|
length = r;
|
||||||
knockback = 1f;
|
knockback = 1f;
|
||||||
|
|
||||||
colors = new Color[]{Color.valueOf("eb7abe").a(0.55f), Color.valueOf("e189f5").a(0.7f), Color.valueOf("907ef7").a(0.8f), Color.valueOf("91a4ff"), Color.white};
|
colors = new Color[]{Color.valueOf("eb7abe").a(0.55f), Color.valueOf("e189f5").a(0.7f), Color.valueOf("907ef7").a(0.8f), Color.valueOf("91a4ff"), Color.white};
|
||||||
@@ -3301,7 +3325,7 @@ public class Blocks{
|
|||||||
Liquids.cyanogen, new ContinuousFlameBulletType(){{
|
Liquids.cyanogen, new ContinuousFlameBulletType(){{
|
||||||
damage = 200f;
|
damage = 200f;
|
||||||
rangeChange = 70f;
|
rangeChange = 70f;
|
||||||
length = range + rangeChange;
|
length = r + rangeChange;
|
||||||
knockback = 2f;
|
knockback = 2f;
|
||||||
|
|
||||||
colors = new Color[]{Color.valueOf("465ab8").a(0.55f), Color.valueOf("66a6d2").a(0.7f), Color.valueOf("89e8b6").a(0.8f), Color.valueOf("cafcbe"), Color.white};
|
colors = new Color[]{Color.valueOf("465ab8").a(0.55f), Color.valueOf("66a6d2").a(0.7f), Color.valueOf("89e8b6").a(0.8f), Color.valueOf("cafcbe"), Color.white};
|
||||||
@@ -3312,7 +3336,7 @@ public class Blocks{
|
|||||||
);
|
);
|
||||||
|
|
||||||
scaledHealth = 330;
|
scaledHealth = 330;
|
||||||
shootLength = 7f;
|
shootY = 7f;
|
||||||
size = 3;
|
size = 3;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -3359,7 +3383,7 @@ public class Blocks{
|
|||||||
shootShake = 4f;
|
shootShake = 4f;
|
||||||
recoilAmount = 1f;
|
recoilAmount = 1f;
|
||||||
reloadTime = 60f * 2.3f;
|
reloadTime = 60f * 2.3f;
|
||||||
shootLength = 7f;
|
shootY = 7f;
|
||||||
rotateSpeed = 1.4f;
|
rotateSpeed = 1.4f;
|
||||||
minWarmup = 0.85f;
|
minWarmup = 0.85f;
|
||||||
shootWarmupSpeed = 0.07f;
|
shootWarmupSpeed = 0.07f;
|
||||||
@@ -3432,7 +3456,7 @@ public class Blocks{
|
|||||||
|
|
||||||
|
|
||||||
reloadTime = 9f;
|
reloadTime = 9f;
|
||||||
shootLength = 15f;
|
shootY = 15f;
|
||||||
rotateSpeed = 5f;
|
rotateSpeed = 5f;
|
||||||
shootCone = 30f;
|
shootCone = 30f;
|
||||||
|
|
||||||
@@ -3469,11 +3493,14 @@ public class Blocks{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
unitFilter = u -> !u.spawnedByCore;
|
unitFilter = u -> !u.spawnedByCore;
|
||||||
shots = 4;
|
|
||||||
alternate = true;
|
shoot = new ShootAlternate(){{
|
||||||
widthSpread = true;
|
|
||||||
targetGround = false;
|
|
||||||
spread = 4.7f;
|
spread = 4.7f;
|
||||||
|
shots = 4;
|
||||||
|
barrels = 4;
|
||||||
|
}};
|
||||||
|
|
||||||
|
targetGround = false;
|
||||||
inaccuracy = 8f;
|
inaccuracy = 8f;
|
||||||
|
|
||||||
restitution = 0.11f;
|
restitution = 0.11f;
|
||||||
|
|||||||
@@ -1820,7 +1820,7 @@ public class Fx{
|
|||||||
lancerLaserCharge = new Effect(38f, e -> {
|
lancerLaserCharge = new Effect(38f, e -> {
|
||||||
color(Pal.lancerLaser);
|
color(Pal.lancerLaser);
|
||||||
|
|
||||||
randLenVectors(e.id, 2, 1f + 20f * e.fout(), e.rotation, 120f, (x, y) -> {
|
randLenVectors(e.id, 14, 1f + 20f * e.fout(), e.rotation, 120f, (x, y) -> {
|
||||||
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 3f + 1f);
|
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 3f + 1f);
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -874,7 +874,7 @@ public class UnitTypes{
|
|||||||
shadow = 12f;
|
shadow = 12f;
|
||||||
recoil = 3f;
|
recoil = 3f;
|
||||||
|
|
||||||
shoot = new SpreadPattern(){{
|
shoot = new ShootSpread(){{
|
||||||
shots = 2;
|
shots = 2;
|
||||||
spread = 17f;
|
spread = 17f;
|
||||||
}};
|
}};
|
||||||
@@ -1695,7 +1695,7 @@ public class UnitTypes{
|
|||||||
shake = 1f;
|
shake = 1f;
|
||||||
shootSound = Sounds.missile;
|
shootSound = Sounds.missile;
|
||||||
|
|
||||||
shoot = new AlternatePattern(){{
|
shoot = new ShootAlternate(){{
|
||||||
shots = 6;
|
shots = 6;
|
||||||
shotDelay = 1.5f;
|
shotDelay = 1.5f;
|
||||||
spread = 4f;
|
spread = 4f;
|
||||||
@@ -2406,7 +2406,7 @@ public class UnitTypes{
|
|||||||
reload = 15f;
|
reload = 15f;
|
||||||
x = 1f;
|
x = 1f;
|
||||||
y = 2f;
|
y = 2f;
|
||||||
shoot = new SpreadPattern(){{
|
shoot = new ShootSpread(){{
|
||||||
shots = 2;
|
shots = 2;
|
||||||
shotDelay = 3f;
|
shotDelay = 3f;
|
||||||
spread = 2f;
|
spread = 2f;
|
||||||
@@ -2484,8 +2484,8 @@ public class UnitTypes{
|
|||||||
|
|
||||||
weapons.add(new Weapon("locus-weapon"){{
|
weapons.add(new Weapon("locus-weapon"){{
|
||||||
layerOffset = 0.0001f;
|
layerOffset = 0.0001f;
|
||||||
reload = 70f;
|
reload = 30f;
|
||||||
shootY = 8f;
|
shootY = 9.3f;
|
||||||
recoil = 1f;
|
recoil = 1f;
|
||||||
rotate = true;
|
rotate = true;
|
||||||
rotateSpeed = 1.4f;
|
rotateSpeed = 1.4f;
|
||||||
@@ -2495,8 +2495,9 @@ public class UnitTypes{
|
|||||||
heatColor = Color.valueOf("f9350f");
|
heatColor = Color.valueOf("f9350f");
|
||||||
cooldownTime = 30f;
|
cooldownTime = 30f;
|
||||||
|
|
||||||
//TODO alternating double pattern
|
shoot = new ShootAlternate(){{
|
||||||
shoot.shots = 2;
|
spread = 3.5f;
|
||||||
|
}};
|
||||||
|
|
||||||
bullet = new BasicBulletType(5f, 50){{
|
bullet = new BasicBulletType(5f, 50){{
|
||||||
sprite = "missile-large";
|
sprite = "missile-large";
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public class LiquidBulletType extends BulletType{
|
|||||||
if(liquid != null){
|
if(liquid != null){
|
||||||
this.liquid = liquid;
|
this.liquid = liquid;
|
||||||
this.status = liquid.effect;
|
this.status = liquid.effect;
|
||||||
|
hitColor = liquid.color;
|
||||||
lightColor = liquid.lightColor;
|
lightColor = liquid.lightColor;
|
||||||
lightOpacity = liquid.lightColor.a;
|
lightOpacity = liquid.lightColor.a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package mindustry.entities.pattern;
|
package mindustry.entities.pattern;
|
||||||
|
|
||||||
public class AlternatePattern extends ShotPattern{
|
public class ShootAlternate extends ShootPattern{
|
||||||
/** number of barrels used for shooting. */
|
/** number of barrels used for shooting. */
|
||||||
public int barrels = 2;
|
public int barrels = 2;
|
||||||
/** spread between barrels, in world units - not degrees. */
|
/** spread between barrels, in world units - not degrees. */
|
||||||
16
core/src/mindustry/entities/pattern/ShootBarrel.java
Normal file
16
core/src/mindustry/entities/pattern/ShootBarrel.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package mindustry.entities.pattern;
|
||||||
|
|
||||||
|
public class ShootBarrel extends ShootPattern{
|
||||||
|
/** barrels [in x, y, rotation] format. */
|
||||||
|
public float[] barrels = {0f, 0f, 0f};
|
||||||
|
/** offset of barrel to start on */
|
||||||
|
public int barrelOffset = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shoot(int totalShots, BulletHandler handler){
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
package mindustry.entities.pattern;
|
package mindustry.entities.pattern;
|
||||||
|
|
||||||
public class MultiPattern extends ShotPattern{
|
public class ShootMulti extends ShootPattern{
|
||||||
public ShotPattern source;
|
public ShootPattern source;
|
||||||
public ShotPattern[] dest = {};
|
public ShootPattern[] dest = {};
|
||||||
|
|
||||||
public MultiPattern(ShotPattern source, ShotPattern... dest){
|
public ShootMulti(ShootPattern source, ShootPattern... dest){
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.dest = dest;
|
this.dest = dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MultiPattern(){
|
public ShootMulti(){
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package mindustry.entities.pattern;
|
package mindustry.entities.pattern;
|
||||||
|
|
||||||
/** Handles different types of bullet patterns for shooting. */
|
/** Handles different types of bullet patterns for shooting. */
|
||||||
public class ShotPattern{
|
public class ShootPattern{
|
||||||
/** amount of shots per "trigger pull" */
|
/** amount of shots per "trigger pull" */
|
||||||
public int shots = 1;
|
public int shots = 1;
|
||||||
/** delay in ticks before first shot */
|
/** delay in ticks before first shot */
|
||||||
@@ -2,18 +2,18 @@ package mindustry.entities.pattern;
|
|||||||
|
|
||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
|
|
||||||
public class SinePattern extends ShotPattern{
|
public class ShootSine extends ShootPattern{
|
||||||
/** scaling applied to bullet index */
|
/** scaling applied to bullet index */
|
||||||
public float scl = 4f;
|
public float scl = 4f;
|
||||||
/** magnitude of sine curve for position displacement */
|
/** magnitude of sine curve for position displacement */
|
||||||
public float mag = 20f;
|
public float mag = 20f;
|
||||||
|
|
||||||
public SinePattern(float scl, float mag){
|
public ShootSine(float scl, float mag){
|
||||||
this.scl = scl;
|
this.scl = scl;
|
||||||
this.mag = mag;
|
this.mag = mag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SinePattern(){
|
public ShootSine(){
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package mindustry.entities.pattern;
|
package mindustry.entities.pattern;
|
||||||
|
|
||||||
public class SpreadPattern extends ShotPattern{
|
public class ShootSpread extends ShootPattern{
|
||||||
/** spread between bullets, in degrees. */
|
/** spread between bullets, in degrees. */
|
||||||
public float spread = 5f;
|
public float spread = 5f;
|
||||||
|
|
||||||
@@ -64,12 +64,13 @@ public class ClassMap{
|
|||||||
classes.put("SeqEffect", mindustry.entities.effect.SeqEffect.class);
|
classes.put("SeqEffect", mindustry.entities.effect.SeqEffect.class);
|
||||||
classes.put("WaveEffect", mindustry.entities.effect.WaveEffect.class);
|
classes.put("WaveEffect", mindustry.entities.effect.WaveEffect.class);
|
||||||
classes.put("WrapEffect", mindustry.entities.effect.WrapEffect.class);
|
classes.put("WrapEffect", mindustry.entities.effect.WrapEffect.class);
|
||||||
classes.put("AlternatePattern", mindustry.entities.pattern.AlternatePattern.class);
|
classes.put("ShootAlternate", mindustry.entities.pattern.ShootAlternate.class);
|
||||||
classes.put("MultiPattern", mindustry.entities.pattern.MultiPattern.class);
|
classes.put("ShootBarrel", mindustry.entities.pattern.ShootBarrel.class);
|
||||||
classes.put("ShotPattern", mindustry.entities.pattern.ShotPattern.class);
|
classes.put("ShootMulti", mindustry.entities.pattern.ShootMulti.class);
|
||||||
classes.put("BulletHandler", mindustry.entities.pattern.ShotPattern.BulletHandler.class);
|
classes.put("ShootPattern", mindustry.entities.pattern.ShootPattern.class);
|
||||||
classes.put("SinePattern", mindustry.entities.pattern.SinePattern.class);
|
classes.put("BulletHandler", mindustry.entities.pattern.ShootPattern.BulletHandler.class);
|
||||||
classes.put("SpreadPattern", mindustry.entities.pattern.SpreadPattern.class);
|
classes.put("ShootSine", mindustry.entities.pattern.ShootSine.class);
|
||||||
|
classes.put("ShootSpread", mindustry.entities.pattern.ShootSpread.class);
|
||||||
classes.put("Objectives", mindustry.game.Objectives.class);
|
classes.put("Objectives", mindustry.game.Objectives.class);
|
||||||
classes.put("Objective", mindustry.game.Objectives.Objective.class);
|
classes.put("Objective", mindustry.game.Objectives.Objective.class);
|
||||||
classes.put("OnPlanet", mindustry.game.Objectives.OnPlanet.class);
|
classes.put("OnPlanet", mindustry.game.Objectives.OnPlanet.class);
|
||||||
@@ -175,6 +176,7 @@ public class ClassMap{
|
|||||||
classes.put("TractorBeamBuild", mindustry.world.blocks.defense.turrets.TractorBeamTurret.TractorBeamBuild.class);
|
classes.put("TractorBeamBuild", mindustry.world.blocks.defense.turrets.TractorBeamTurret.TractorBeamBuild.class);
|
||||||
classes.put("Turret", mindustry.world.blocks.defense.turrets.Turret.class);
|
classes.put("Turret", mindustry.world.blocks.defense.turrets.Turret.class);
|
||||||
classes.put("AmmoEntry", mindustry.world.blocks.defense.turrets.Turret.AmmoEntry.class);
|
classes.put("AmmoEntry", mindustry.world.blocks.defense.turrets.Turret.AmmoEntry.class);
|
||||||
|
classes.put("BulletEntry", mindustry.world.blocks.defense.turrets.Turret.BulletEntry.class);
|
||||||
classes.put("TurretBuild", mindustry.world.blocks.defense.turrets.Turret.TurretBuild.class);
|
classes.put("TurretBuild", mindustry.world.blocks.defense.turrets.Turret.TurretBuild.class);
|
||||||
classes.put("ArmoredConveyor", mindustry.world.blocks.distribution.ArmoredConveyor.class);
|
classes.put("ArmoredConveyor", mindustry.world.blocks.distribution.ArmoredConveyor.class);
|
||||||
classes.put("ArmoredConveyorBuild", mindustry.world.blocks.distribution.ArmoredConveyor.ArmoredConveyorBuild.class);
|
classes.put("ArmoredConveyorBuild", mindustry.world.blocks.distribution.ArmoredConveyor.ArmoredConveyorBuild.class);
|
||||||
|
|||||||
@@ -137,8 +137,8 @@ public class ContentParser{
|
|||||||
readFields(result, data);
|
readFields(result, data);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
put(ShotPattern.class, (type, data) -> {
|
put(ShootPattern.class, (type, data) -> {
|
||||||
var bc = resolve(data.getString("type", ""), ShotPattern.class);
|
var bc = resolve(data.getString("type", ""), ShootPattern.class);
|
||||||
data.remove("type");
|
data.remove("type");
|
||||||
var result = make(bc);
|
var result = make(bc);
|
||||||
readFields(result, data);
|
readFields(result, data);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class Weapon implements Cloneable{
|
|||||||
/** offsets of weapon position on unit */
|
/** offsets of weapon position on unit */
|
||||||
public float x = 5f, y = 0f;
|
public float x = 5f, y = 0f;
|
||||||
/** pattern used for bullets */
|
/** pattern used for bullets */
|
||||||
public ShotPattern shoot = new ShotPattern();
|
public ShootPattern shoot = new ShootPattern();
|
||||||
/** radius of shadow drawn under the weapon; <0 to disable */
|
/** radius of shadow drawn under the weapon; <0 to disable */
|
||||||
public float shadow = -1f;
|
public float shadow = -1f;
|
||||||
/** fraction of velocity that is random */
|
/** fraction of velocity that is random */
|
||||||
@@ -385,8 +385,8 @@ public class Weapon implements Cloneable{
|
|||||||
weaponRotation = unit.rotation - 90 + (rotate ? mount.rotation : 0),
|
weaponRotation = unit.rotation - 90 + (rotate ? mount.rotation : 0),
|
||||||
mountX = unit.x + Angles.trnsx(unit.rotation - 90, x, y),
|
mountX = unit.x + Angles.trnsx(unit.rotation - 90, x, y),
|
||||||
mountY = unit.y + Angles.trnsy(unit.rotation - 90, x, y),
|
mountY = unit.y + Angles.trnsy(unit.rotation - 90, x, y),
|
||||||
bulletX = mountX + Angles.trnsx(weaponRotation, this.shootX, this.shootY) + Angles.trnsx(weaponRotation, xOffset, yOffset),
|
bulletX = mountX + Angles.trnsx(weaponRotation, this.shootX + xOffset, this.shootY + yOffset),
|
||||||
bulletY = mountY + Angles.trnsy(weaponRotation, this.shootX, this.shootY) + Angles.trnsy(weaponRotation, xOffset, yOffset),
|
bulletY = mountY + Angles.trnsy(weaponRotation, this.shootX + xOffset, this.shootY + yOffset),
|
||||||
shootAngle = bulletRotation(unit, mount, bulletX, bulletY) + angleOffset,
|
shootAngle = bulletRotation(unit, mount, bulletX, bulletY) + angleOffset,
|
||||||
lifeScl = bullet.scaleVelocity ? Mathf.clamp(Mathf.dst(shootX, shootY, mount.aimX, mount.aimY) / bullet.range) : 1f;
|
lifeScl = bullet.scaleVelocity ? Mathf.clamp(Mathf.dst(shootX, shootY, mount.aimX, mount.aimY) / bullet.range) : 1f;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import arc.util.*;
|
|||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
import mindustry.entities.bullet.*;
|
import mindustry.entities.bullet.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.logic.*;
|
|
||||||
import mindustry.world.consumers.*;
|
import mindustry.world.consumers.*;
|
||||||
import mindustry.world.meta.*;
|
import mindustry.world.meta.*;
|
||||||
|
|
||||||
@@ -31,8 +30,9 @@ public class ContinuousTurret extends Turret{
|
|||||||
stats.remove(Stat.inaccuracy);
|
stats.remove(Stat.inaccuracy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO LaserTurret shared code
|
||||||
public class ContinuousTurretBuild extends TurretBuild{
|
public class ContinuousTurretBuild extends TurretBuild{
|
||||||
public @Nullable Bullet bullet;
|
public Seq<BulletEntry> bullets = new Seq<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateCooling(){
|
protected void updateCooling(){
|
||||||
@@ -68,29 +68,27 @@ public class ContinuousTurret extends Turret{
|
|||||||
|
|
||||||
unit.ammo(unit.type().ammoCapacity * ammoFract);
|
unit.ammo(unit.type().ammoCapacity * ammoFract);
|
||||||
|
|
||||||
if(bullet != null){
|
bullets.removeAll(b -> !b.bullet.isAdded() || b.bullet.type == null || b.bullet.owner != this);
|
||||||
//check to see if bullet despawned
|
|
||||||
if(bullet.owner != this || !bullet.isAdded() || bullet.type == null){
|
if(bullets.any()){
|
||||||
bullet = null;
|
for(var entry : bullets){
|
||||||
}else{
|
float
|
||||||
wasShooting = true;
|
bulletX = x + Angles.trnsx(rotation - 90, shootX + entry.x, shootY + entry.y),
|
||||||
bullet.rotation(rotation);
|
bulletY = y + Angles.trnsy(rotation - 90, shootX + entry.x, shootY + entry.y),
|
||||||
bullet.set(x + bulletOffset.x, y + bulletOffset.y);
|
angle = rotation + entry.rotation;
|
||||||
heat = 1f;
|
|
||||||
recoil = recoilAmount;
|
entry.bullet.rotation(angle);
|
||||||
|
entry.bullet.set(bulletX, bulletY);
|
||||||
|
|
||||||
if(isShooting() && hasAmmo()){
|
if(isShooting() && hasAmmo()){
|
||||||
bullet.time = bullet.lifetime * bullet.type.optimalLifeFract * shootWarmup;
|
entry.bullet.time = entry.bullet.lifetime * entry.bullet.type.optimalLifeFract * shootWarmup;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
wasShooting = true;
|
||||||
public double sense(LAccess sensor){
|
heat = 1f;
|
||||||
//no concept of reload here
|
recoil = recoilAmount;
|
||||||
if(sensor == LAccess.progress) return bullet == null ? 0f : 1f;
|
}
|
||||||
return super.sense(sensor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -100,11 +98,11 @@ public class ContinuousTurret extends Turret{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateShooting(){
|
protected void updateShooting(){
|
||||||
if(bullet != null){
|
if(bullets.any()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(canConsume() && !charging && shootWarmup >= minWarmup){
|
if(canConsume() && !charging() && shootWarmup >= minWarmup){
|
||||||
shoot(peekAmmo());
|
shoot(peekAmmo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,13 +113,15 @@ public class ContinuousTurret extends Turret{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleBullet(@Nullable Bullet bullet){
|
protected void handleBullet(@Nullable Bullet bullet, float offsetX, float offsetY, float angleOffset){
|
||||||
this.bullet = bullet;
|
if(bullet != null){
|
||||||
|
bullets.add(new BulletEntry(bullet, offsetX, offsetY, angleOffset, 0f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldActiveSound(){
|
public boolean shouldActiveSound(){
|
||||||
return bullet != null;
|
return bullets.any();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package mindustry.world.blocks.defense.turrets;
|
package mindustry.world.blocks.defense.turrets;
|
||||||
|
|
||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
import mindustry.entities.bullet.*;
|
import mindustry.entities.bullet.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
@@ -29,8 +30,7 @@ public class LaserTurret extends PowerTurret{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class LaserTurretBuild extends PowerTurretBuild{
|
public class LaserTurretBuild extends PowerTurretBuild{
|
||||||
public @Nullable Bullet bullet;
|
public Seq<BulletEntry> bullets = new Seq<>();
|
||||||
public float bulletLife;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateCooling(){
|
protected void updateCooling(){
|
||||||
@@ -40,28 +40,32 @@ public class LaserTurret extends PowerTurret{
|
|||||||
@Override
|
@Override
|
||||||
public boolean shouldConsume(){
|
public boolean shouldConsume(){
|
||||||
//still consumes power when bullet is around
|
//still consumes power when bullet is around
|
||||||
return bullet != null || isActive();
|
return bullets.any() || isActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateTile(){
|
public void updateTile(){
|
||||||
super.updateTile();
|
super.updateTile();
|
||||||
|
|
||||||
if(bullet != null && (!bullet.isAdded() || bullet.type == null)){
|
bullets.removeAll(b -> !b.bullet.isAdded() || b.bullet.type == null || b.life <= 0f || b.bullet.owner != this);
|
||||||
bullet = null;
|
|
||||||
|
if(bullets.any()){
|
||||||
|
|
||||||
|
for(var entry : bullets){
|
||||||
|
float
|
||||||
|
bulletX = x + Angles.trnsx(rotation - 90, shootX + entry.x, shootY + entry.y),
|
||||||
|
bulletY = y + Angles.trnsy(rotation - 90, shootX + entry.x, shootY + entry.y),
|
||||||
|
angle = rotation + entry.rotation;
|
||||||
|
|
||||||
|
entry.bullet.rotation(angle);
|
||||||
|
entry.bullet.set(bulletX, bulletY);
|
||||||
|
entry.bullet.time = entry.bullet.type.lifetime * entry.bullet.type.optimalLifeFract;
|
||||||
|
entry.life -= Time.delta / Math.max(efficiency, 0.00001f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bulletLife > 0 && bullet != null){
|
|
||||||
wasShooting = true;
|
wasShooting = true;
|
||||||
bullet.rotation(rotation);
|
|
||||||
bullet.set(x + bulletOffset.x, y + bulletOffset.y);
|
|
||||||
bullet.time = bullet.type.lifetime * bullet.type.optimalLifeFract;
|
|
||||||
heat = 1f;
|
heat = 1f;
|
||||||
recoil = recoilAmount;
|
recoil = recoilAmount;
|
||||||
bulletLife -= Time.delta / Math.max(efficiency, 0.00001f);
|
|
||||||
if(bulletLife <= 0f){
|
|
||||||
bullet = null;
|
|
||||||
}
|
|
||||||
}else if(reload > 0){
|
}else if(reload > 0){
|
||||||
wasShooting = true;
|
wasShooting = true;
|
||||||
//TODO does not handle multi liquid req?
|
//TODO does not handle multi liquid req?
|
||||||
@@ -89,11 +93,11 @@ public class LaserTurret extends PowerTurret{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateShooting(){
|
protected void updateShooting(){
|
||||||
if(bulletLife > 0 && bullet != null){
|
if(bullets.any()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(reload <= 0 && efficiency > 0 && !charging && shootWarmup >= minWarmup){
|
if(reload <= 0 && efficiency > 0 && !charging() && shootWarmup >= minWarmup){
|
||||||
BulletType type = peekAmmo();
|
BulletType type = peekAmmo();
|
||||||
|
|
||||||
shoot(type);
|
shoot(type);
|
||||||
@@ -104,18 +108,19 @@ public class LaserTurret extends PowerTurret{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void turnToTarget(float targetRot){
|
protected void turnToTarget(float targetRot){
|
||||||
rotation = Angles.moveToward(rotation, targetRot, efficiency * rotateSpeed * delta() * (bulletLife > 0f ? firingMoveFract : 1f));
|
rotation = Angles.moveToward(rotation, targetRot, efficiency * rotateSpeed * delta() * (bullets.any() ? firingMoveFract : 1f));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleBullet(@Nullable Bullet bullet){
|
protected void handleBullet(@Nullable Bullet bullet, float offsetX, float offsetY, float angleOffset){
|
||||||
this.bullet = bullet;
|
if(bullet != null){
|
||||||
bulletLife = shootDuration;
|
bullets.add(new BulletEntry(bullet, offsetX, offsetY, angleOffset, shootDuration));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldActiveSound(){
|
public boolean shouldActiveSound(){
|
||||||
return bulletLife > 0 && bullet != null;
|
return bullets.any();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ public class PayloadTurret extends Turret{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BulletType useAmmo(){
|
public BulletType useAmmo(){
|
||||||
ejectEffects();
|
|
||||||
for(var block : ammoKeys){
|
for(var block : ammoKeys){
|
||||||
if(payloads.contains(block)){
|
if(payloads.contains(block)){
|
||||||
payloads.remove(block);
|
payloads.remove(block);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import mindustry.core.*;
|
|||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.entities.Units.*;
|
import mindustry.entities.Units.*;
|
||||||
import mindustry.entities.bullet.*;
|
import mindustry.entities.bullet.*;
|
||||||
|
import mindustry.entities.pattern.*;
|
||||||
import mindustry.game.EventType.*;
|
import mindustry.game.EventType.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
@@ -40,10 +41,8 @@ public class Turret extends ReloadTurret{
|
|||||||
public Effect smokeEffect = Fx.none;
|
public Effect smokeEffect = Fx.none;
|
||||||
public Effect ammoUseEffect = Fx.none;
|
public Effect ammoUseEffect = Fx.none;
|
||||||
public Sound shootSound = Sounds.shoot;
|
public Sound shootSound = Sounds.shoot;
|
||||||
|
|
||||||
public Effect chargeEffect = Fx.none;
|
|
||||||
public Effect chargeBeginEffect = Fx.none;
|
|
||||||
public Sound chargeSound = Sounds.none;
|
public Sound chargeSound = Sounds.none;
|
||||||
|
public float soundPitchMin = 0.9f, soundPitchMax = 1.1f;
|
||||||
|
|
||||||
//visuals
|
//visuals
|
||||||
public float ammoEjectBack = 1f;
|
public float ammoEjectBack = 1f;
|
||||||
@@ -60,44 +59,24 @@ public class Turret extends ReloadTurret{
|
|||||||
public float heatRequirement = -1f;
|
public float heatRequirement = -1f;
|
||||||
public float maxHeatEfficiency = 3f;
|
public float maxHeatEfficiency = 3f;
|
||||||
|
|
||||||
//TODO all the fields below should be deprecated and moved into a ShootPattern class or similar
|
//TODO clean all of this up + weapon consistency
|
||||||
//TODO ...however, it would be nice to unify the weapon and turret systems into one.
|
|
||||||
|
|
||||||
// below
|
|
||||||
/** Bullet angle randomness in degrees. */
|
/** Bullet angle randomness in degrees. */
|
||||||
public float inaccuracy = 0f;
|
public float inaccuracy = 0f;
|
||||||
/** Fraction of bullet velocity that is random. */
|
/** Fraction of bullet velocity that is random. */
|
||||||
public float velocityInaccuracy = 0f;
|
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. */
|
/** Maximum angle difference in degrees at which turret will still try to shoot. */
|
||||||
public float shootCone = 8f;
|
public float shootCone = 8f;
|
||||||
/** Length of turret shoot point. */
|
/** Turret shoot point. */
|
||||||
public float shootLength = Float.NEGATIVE_INFINITY;
|
public float shootX = 0f, shootY = Float.NEGATIVE_INFINITY;
|
||||||
/** Random spread of projectile across width. This looks stupid. */
|
|
||||||
public float xRand = 0f;
|
|
||||||
/** Currently used for artillery only. */
|
/** Currently used for artillery only. */
|
||||||
public float minRange = 0f;
|
public float minRange = 0f;
|
||||||
/** Minimum warmup needed to fire. */
|
/** Minimum warmup needed to fire. */
|
||||||
public float minWarmup = 0f;
|
public float minWarmup = 0f;
|
||||||
/** Ticks between shots if shots > 1. */
|
|
||||||
public float burstSpacing = 0;
|
|
||||||
/** An inflexible and terrible idea. */
|
|
||||||
public boolean alternate = false, widthSpread = false;
|
|
||||||
/** If true, this turret will accurately target moving targets with respect to charge time. */
|
/** If true, this turret will accurately target moving targets with respect to charge time. */
|
||||||
public boolean accurateDelay = false;
|
public boolean accurateDelay = false;
|
||||||
|
/** pattern used for bullets */
|
||||||
//charging
|
public ShootPattern shoot = new ShootPattern();
|
||||||
public float chargeTime = -1f;
|
|
||||||
public int chargeEffects = 5;
|
|
||||||
public float chargeMaxDelay = 10f;
|
|
||||||
|
|
||||||
//see above
|
|
||||||
|
|
||||||
public boolean targetAir = true;
|
public boolean targetAir = true;
|
||||||
public boolean targetGround = true;
|
public boolean targetGround = true;
|
||||||
@@ -126,7 +105,7 @@ public class Turret extends ReloadTurret{
|
|||||||
super.setStats();
|
super.setStats();
|
||||||
|
|
||||||
stats.add(Stat.inaccuracy, (int)inaccuracy, StatUnit.degrees);
|
stats.add(Stat.inaccuracy, (int)inaccuracy, StatUnit.degrees);
|
||||||
stats.add(Stat.reload, 60f / (reloadTime) * (alternate ? 1 : shots), StatUnit.perSecond);
|
stats.add(Stat.reload, 60f / (reloadTime) * shoot.shots, StatUnit.perSecond);
|
||||||
stats.add(Stat.targetsAir, targetAir);
|
stats.add(Stat.targetsAir, targetAir);
|
||||||
stats.add(Stat.targetsGround, targetGround);
|
stats.add(Stat.targetsGround, targetGround);
|
||||||
if(ammoPerShot != 1) stats.add(Stat.ammoUse, ammoPerShot, StatUnit.perShot);
|
if(ammoPerShot != 1) stats.add(Stat.ammoUse, ammoPerShot, StatUnit.perShot);
|
||||||
@@ -148,7 +127,7 @@ public class Turret extends ReloadTurret{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(){
|
public void init(){
|
||||||
if(shootLength == Float.NEGATIVE_INFINITY) shootLength = size * tilesize / 2f;
|
if(shootY == Float.NEGATIVE_INFINITY) shootY = size * tilesize / 2f;
|
||||||
if(elevation < 0) elevation = size / 2f;
|
if(elevation < 0) elevation = size / 2f;
|
||||||
|
|
||||||
super.init();
|
super.init();
|
||||||
@@ -181,26 +160,25 @@ public class Turret extends ReloadTurret{
|
|||||||
//TODO storing these as instance variables is horrible design
|
//TODO storing these as instance variables is horrible design
|
||||||
/** Turret sprite offset, based on recoil. Updated every frame. */
|
/** Turret sprite offset, based on recoil. Updated every frame. */
|
||||||
public Vec2 recoilOffset = new Vec2();
|
public Vec2 recoilOffset = new Vec2();
|
||||||
/** Turret bullet position offset. Updated every frame. */
|
|
||||||
public Vec2 bulletOffset = new Vec2();
|
|
||||||
|
|
||||||
public Seq<AmmoEntry> ammo = new Seq<>();
|
public Seq<AmmoEntry> ammo = new Seq<>();
|
||||||
public int totalAmmo;
|
public int totalAmmo;
|
||||||
public float recoil, heat, logicControlTime = -1;
|
public float recoil, heat, logicControlTime = -1;
|
||||||
public float shootWarmup;
|
public float shootWarmup;
|
||||||
public int shotCounter;
|
public int totalShots;
|
||||||
public boolean logicShooting = false;
|
public boolean logicShooting = false;
|
||||||
public @Nullable Posc target;
|
public @Nullable Posc target;
|
||||||
public Vec2 targetPos = new Vec2();
|
public Vec2 targetPos = new Vec2();
|
||||||
public BlockUnitc unit = (BlockUnitc)UnitTypes.block.create(team);
|
public BlockUnitc unit = (BlockUnitc)UnitTypes.block.create(team);
|
||||||
public boolean wasShooting, charging;
|
public boolean wasShooting;
|
||||||
|
public int queuedBullets = 0;
|
||||||
|
|
||||||
public float heatReq;
|
public float heatReq;
|
||||||
public float[] sideHeat = new float[4];
|
public float[] sideHeat = new float[4];
|
||||||
|
|
||||||
public float estimateDps(){
|
public float estimateDps(){
|
||||||
if(!hasAmmo()) return 0f;
|
if(!hasAmmo()) return 0f;
|
||||||
return shots / reloadTime * 60f * peekAmmo().estimateDPS() * efficiency * timeScale;
|
return shoot.shots / reloadTime * 60f * peekAmmo().estimateDPS() * efficiency * timeScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -303,7 +281,7 @@ public class Turret extends ReloadTurret{
|
|||||||
|
|
||||||
//when delay is accurate, assume unit has moved by chargeTime already
|
//when delay is accurate, assume unit has moved by chargeTime already
|
||||||
if(accurateDelay && pos instanceof Hitboxc h){
|
if(accurateDelay && pos instanceof Hitboxc h){
|
||||||
offset.set(h.deltaX(), h.deltaY()).scl(chargeTime / Time.delta);
|
offset.set(h.deltaX(), h.deltaY()).scl(shoot.firstShotDelay / Time.delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetPos.set(Predict.intercept(this, pos, offset.x, offset.y, bullet.speed <= 0.01f ? 99999999f : bullet.speed));
|
targetPos.set(Predict.intercept(this, pos, offset.x, offset.y, bullet.speed <= 0.01f ? 99999999f : bullet.speed));
|
||||||
@@ -339,7 +317,6 @@ public class Turret extends ReloadTurret{
|
|||||||
unit.rotation(rotation);
|
unit.rotation(rotation);
|
||||||
unit.team(team);
|
unit.team(team);
|
||||||
recoilOffset.trns(rotation, -recoil);
|
recoilOffset.trns(rotation, -recoil);
|
||||||
bulletOffset.trns(rotation, shootLength);
|
|
||||||
|
|
||||||
if(logicControlTime > 0){
|
if(logicControlTime > 0){
|
||||||
logicControlTime -= Time.delta;
|
logicControlTime -= Time.delta;
|
||||||
@@ -427,7 +404,7 @@ public class Turret extends ReloadTurret{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldTurn(){
|
public boolean shouldTurn(){
|
||||||
return !charging;
|
return !charging();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -446,13 +423,12 @@ public class Turret extends ReloadTurret{
|
|||||||
if(entry.amount <= 0) ammo.pop();
|
if(entry.amount <= 0) ammo.pop();
|
||||||
totalAmmo -= ammoPerShot;
|
totalAmmo -= ammoPerShot;
|
||||||
totalAmmo = Math.max(totalAmmo, 0);
|
totalAmmo = Math.max(totalAmmo, 0);
|
||||||
ejectEffects();
|
|
||||||
return entry.type();
|
return entry.type();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the ammo type that will be returned if useAmmo is called. */
|
/** @return the ammo type that will be returned if useAmmo is called. */
|
||||||
public BulletType peekAmmo(){
|
public @Nullable BulletType peekAmmo(){
|
||||||
return ammo.peek().type();
|
return ammo.size == 0 ? null : ammo.peek().type();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return whether the turret has ammo. */
|
/** @return whether the turret has ammo. */
|
||||||
@@ -467,6 +443,10 @@ public class Turret extends ReloadTurret{
|
|||||||
return ammo.size > 0 && ammo.peek().amount >= ammoPerShot;
|
return ammo.size > 0 && ammo.peek().amount >= ammoPerShot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean charging(){
|
||||||
|
return queuedBullets > 0;
|
||||||
|
}
|
||||||
|
|
||||||
protected void updateReload(){
|
protected void updateReload(){
|
||||||
float multiplier = hasAmmo() ? peekAmmo().reloadMultiplier : 1f;
|
float multiplier = hasAmmo() ? peekAmmo().reloadMultiplier : 1f;
|
||||||
reload += delta() * multiplier * baseReloadSpeed();
|
reload += delta() * multiplier * baseReloadSpeed();
|
||||||
@@ -477,7 +457,7 @@ public class Turret extends ReloadTurret{
|
|||||||
|
|
||||||
protected void updateShooting(){
|
protected void updateShooting(){
|
||||||
|
|
||||||
if(reload >= reloadTime && !charging && shootWarmup >= minWarmup){
|
if(reload >= reloadTime && !charging() && shootWarmup >= minWarmup){
|
||||||
BulletType type = peekAmmo();
|
BulletType type = peekAmmo();
|
||||||
|
|
||||||
shoot(type);
|
shoot(type);
|
||||||
@@ -487,111 +467,66 @@ public class Turret extends ReloadTurret{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void shoot(BulletType type){
|
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
|
float
|
||||||
|
bulletX = x + Angles.trnsx(rotation - 90, shootX, shootY),
|
||||||
|
bulletY = y + Angles.trnsy(rotation - 90, shootX, shootY);
|
||||||
|
|
||||||
//when charging is enabled, use the charge shoot pattern
|
if(shoot.firstShotDelay > 0){
|
||||||
if(chargeTime > 0){
|
chargeSound.at(bulletX, bulletY, Mathf.random(soundPitchMin, soundPitchMax));
|
||||||
useAmmo();
|
type.chargeEffect.at(bulletX, bulletY, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
chargeBeginEffect.at(x + bulletOffset.x, y + bulletOffset.y, rotation);
|
shoot.shoot(totalShots, (xOffset, yOffset, angle, delay) -> {
|
||||||
chargeSound.at(x + bulletOffset.x, y + bulletOffset.y, 1);
|
queuedBullets ++;
|
||||||
|
if(delay > 0f){
|
||||||
for(int i = 0; i < chargeEffects; i++){
|
Time.run(delay, () -> bullet(type, xOffset, yOffset, angle));
|
||||||
Time.run(Mathf.random(chargeMaxDelay), () -> {
|
}else{
|
||||||
if(dead) return;
|
bullet(type, xOffset, yOffset, angle);
|
||||||
bulletOffset.trns(rotation, shootLength);
|
}
|
||||||
chargeEffect.at(x + bulletOffset.x, y + bulletOffset.y, rotation);
|
totalShots ++;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
charging = true;
|
protected void bullet(BulletType type, float xOffset, float yOffset, float angleOffset){
|
||||||
|
queuedBullets --;
|
||||||
|
|
||||||
Time.run(chargeTime, () -> {
|
|
||||||
if(dead) return;
|
|
||||||
bulletOffset.trns(rotation, shootLength);
|
|
||||||
recoil = recoilAmount;
|
|
||||||
heat = 1f;
|
|
||||||
bullet(type, rotation + Mathf.range(inaccuracy + type.inaccuracy));
|
|
||||||
charging = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
//when burst spacing is enabled, use the burst pattern
|
|
||||||
}else if(burstSpacing > 0.0001f){
|
|
||||||
for(int i = 0; i < shots; i++){
|
|
||||||
int ii = i;
|
|
||||||
Time.run(burstSpacing * i, () -> {
|
|
||||||
if(dead || !hasAmmo()) return;
|
if(dead || !hasAmmo()) return;
|
||||||
|
|
||||||
bulletOffset.trns(rotation, shootLength, Mathf.range(xRand));
|
float
|
||||||
bullet(peekAmmo(), rotation + Mathf.range(inaccuracy + peekAmmo().inaccuracy) + (ii - (int)(shots / 2f)) * spread);
|
bulletX = x + Angles.trnsx(rotation - 90, shootX + xOffset, shootY + yOffset),
|
||||||
useAmmo();
|
bulletY = y + Angles.trnsy(rotation - 90, shootX + xOffset, shootY + yOffset),
|
||||||
recoil = recoilAmount;
|
shootAngle = rotation + angleOffset + Mathf.range(inaccuracy);
|
||||||
heat = 1f;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}else{
|
|
||||||
//otherwise, use the normal shot pattern(s)
|
|
||||||
|
|
||||||
if(alternate || widthSpread){
|
|
||||||
int count = !widthSpread ? 1 : shots;
|
|
||||||
|
|
||||||
for(int c = 0; c < count; c++){
|
|
||||||
float i = (shotCounter % shots) - (shots-1)/2f;
|
|
||||||
bulletOffset.trns(rotation - 90, (spread) * i + Mathf.range(xRand), shootLength);
|
|
||||||
|
|
||||||
bullet(type, rotation + Mathf.range(inaccuracy + type.inaccuracy));
|
|
||||||
shotCounter ++;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
bulletOffset.trns(rotation, shootLength, Mathf.range(xRand));
|
|
||||||
|
|
||||||
for(int i = 0; i < shots; i++){
|
|
||||||
bullet(type, rotation + Mathf.range(inaccuracy + type.inaccuracy) + (i - (int)(shots / 2f)) * spread);
|
|
||||||
shotCounter ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
recoil = recoilAmount;
|
|
||||||
heat = 1f;
|
|
||||||
useAmmo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void bullet(BulletType type, float angle){
|
|
||||||
float bulletX = x + bulletOffset.x, bulletY = y + bulletOffset.y;
|
|
||||||
float lifeScl = type.scaleVelocity ? Mathf.clamp(Mathf.dst(bulletX, bulletY, targetPos.x, targetPos.y) / type.range, minRange / type.range, range() / type.range) : 1f;
|
float lifeScl = type.scaleVelocity ? Mathf.clamp(Mathf.dst(bulletX, bulletY, targetPos.x, targetPos.y) / type.range, minRange / type.range, range() / type.range) : 1f;
|
||||||
|
|
||||||
handleBullet(type.create(this, team, bulletX, bulletY, angle, 1f + Mathf.range(velocityInaccuracy), lifeScl));
|
handleBullet(type.create(this, team, bulletX, bulletY, shootAngle, 1f + Mathf.range(velocityInaccuracy), lifeScl), xOffset, yOffset, angleOffset);
|
||||||
|
|
||||||
//TODO "shoot" and "smoke" should just be MultiEffects there's no reason to have them separate
|
//TODO "shoot" and "smoke" should just be MultiEffects there's no reason to have them separate
|
||||||
Effect fshootEffect = shootEffect == Fx.none ? type.shootEffect : shootEffect;
|
|
||||||
Effect fsmokeEffect = smokeEffect == Fx.none ? type.smokeEffect : smokeEffect;
|
|
||||||
|
|
||||||
fshootEffect.at(bulletX, bulletY, rotation, type.hitColor);
|
(shootEffect == Fx.none ? type.shootEffect : shootEffect).at(bulletX, bulletY, rotation, type.hitColor);
|
||||||
fsmokeEffect.at(bulletX, bulletY, rotation, type.hitColor);
|
(smokeEffect == Fx.none ? type.smokeEffect : smokeEffect).at(bulletX, bulletY, rotation, type.hitColor);
|
||||||
shootSound.at(bulletX, bulletY, Mathf.random(0.9f, 1.1f));
|
shootSound.at(bulletX, bulletY, Mathf.random(soundPitchMin, soundPitchMax));
|
||||||
|
|
||||||
|
ammoUseEffect.at(
|
||||||
|
x - Angles.trnsx(rotation, ammoEjectBack),
|
||||||
|
y - Angles.trnsy(rotation, ammoEjectBack),
|
||||||
|
rotation * (shoot.shots == 1 && shoot instanceof ShootAlternate && totalShots % 2 == 1 ? -1f : 1f)
|
||||||
|
);
|
||||||
|
|
||||||
if(shootShake > 0){
|
if(shootShake > 0){
|
||||||
Effect.shake(shootShake, shootShake, this);
|
Effect.shake(shootShake, shootShake, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
recoil = recoilAmount;
|
recoil = recoilAmount;
|
||||||
|
heat = 1f;
|
||||||
|
|
||||||
|
useAmmo();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleBullet(@Nullable Bullet bullet){
|
protected void handleBullet(@Nullable Bullet bullet, float offsetX, float offsetY, float angleOffset){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ejectEffects(){
|
|
||||||
if(dead) return;
|
|
||||||
|
|
||||||
//alternate sides when using a double turret
|
|
||||||
float scl = (shots == 2 && alternate && shotCounter % 2 == 1 ? -1f : 1f);
|
|
||||||
|
|
||||||
ammoUseEffect.at(x - Angles.trnsx(rotation, ammoEjectBack), y - Angles.trnsy(rotation, ammoEjectBack), rotation * scl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(Writes write){
|
public void write(Writes write){
|
||||||
super.write(write);
|
super.write(write);
|
||||||
@@ -614,4 +549,17 @@ public class Turret extends ReloadTurret{
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class BulletEntry{
|
||||||
|
public Bullet bullet;
|
||||||
|
public float x, y, rotation, life;
|
||||||
|
|
||||||
|
public BulletEntry(Bullet bullet, float x, float y, float rotation, float life){
|
||||||
|
this.bullet = bullet;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.rotation = rotation;
|
||||||
|
this.life = life;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user