T4/5 support mechs

This commit is contained in:
Anuken
2020-09-21 23:32:30 -04:00
parent 1d8f837fb1
commit 87032c82b1
43 changed files with 5652 additions and 4913 deletions

View File

@@ -3,6 +3,7 @@
alpha=0 alpha=0
atrax=1 atrax=1
block=2 block=2
corvus=24
flare=3 flare=3
mace=4 mace=4
mega=5 mega=5
@@ -24,3 +25,4 @@ pulsar=19
quad=23 quad=23
risso=20 risso=20
spiroct=21 spiroct=21
vela=25

View File

@@ -0,0 +1 @@
{fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:deactivated,type:boolean,size:1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -0,0 +1 @@
{fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:deactivated,type:boolean,size:1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -316,3 +316,5 @@
63428=sei|unit-sei-medium 63428=sei|unit-sei-medium
63427=quad|unit-quad-medium 63427=quad|unit-quad-medium
63426=oct|unit-oct-medium 63426=oct|unit-oct-medium
63425=vela|unit-vela-medium
63424=corvus|unit-corvus-medium

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 557 KiB

After

Width:  |  Height:  |  Size: 554 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 661 KiB

After

Width:  |  Height:  |  Size: 664 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 942 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 KiB

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -1806,6 +1806,7 @@ public class Blocks implements ContentList{
{UnitTypes.fortress, UnitTypes.scepter}, {UnitTypes.fortress, UnitTypes.scepter},
{UnitTypes.bryde, UnitTypes.sei}, {UnitTypes.bryde, UnitTypes.sei},
{UnitTypes.mega, UnitTypes.quad}, {UnitTypes.mega, UnitTypes.quad},
{UnitTypes.quasar, UnitTypes.vela},
}; };
}}; }};
@@ -1825,7 +1826,8 @@ public class Blocks implements ContentList{
{UnitTypes.arkyid, UnitTypes.toxopid}, {UnitTypes.arkyid, UnitTypes.toxopid},
{UnitTypes.scepter, UnitTypes.reign}, {UnitTypes.scepter, UnitTypes.reign},
{UnitTypes.sei, UnitTypes.omura}, {UnitTypes.sei, UnitTypes.omura},
{UnitTypes.quad, UnitTypes.oct} {UnitTypes.quad, UnitTypes.oct},
{UnitTypes.vela, UnitTypes.corvus}
}; };
}}; }};

View File

@@ -145,7 +145,7 @@ public class Fx{
int i = 0; int i = 0;
for(Vec2 p : lines){ for(Vec2 p : lines){
Fill.square(p.x, p.y, (5f - (float)i++ / lines.size * 2f) * e.fout(), 45); Fill.circle(p.x, p.y, Lines.getStroke() / 2f);
} }
}), }),
@@ -290,7 +290,7 @@ public class Fx{
Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6); Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6);
}), }),
healBomb = new Effect(40f, 100f, e -> { greenBomb = new Effect(40f, 100f, e -> {
color(Pal.heal); color(Pal.heal);
stroke(e.fout() * 2f); stroke(e.fout() * 2f);
Lines.circle(e.x, e.y, 4f + e.finpow() * 65f); Lines.circle(e.x, e.y, 4f + e.finpow() * 65f);
@@ -306,6 +306,28 @@ public class Fx{
} }
}), }),
greenLaserCharge = new Effect(80f, 100f, e -> {
color(Pal.heal);
stroke(e.fin() * 2f);
Lines.circle(e.x, e.y, 4f + e.fout() * 100f);
Fill.circle(e.x, e.y, e.fin() * 20);
randLenVectors(e.id, 20, 40f * e.fout(), (x, y) -> {
Fill.circle(e.x + x, e.y + y, e.fin() * 5f);
});
color();
Fill.circle(e.x, e.y, e.fin() * 10);
}),
greenLaserChargeSmall = new Effect(40f, 100f, e -> {
color(Pal.heal);
stroke(e.fin() * 2f);
Lines.circle(e.x, e.y, e.fout() * 50f);
}),
healWaveDynamic = new Effect(22, e -> { healWaveDynamic = new Effect(22, e -> {
color(Pal.heal); color(Pal.heal);
stroke(e.fout() * 2f); stroke(e.fout() * 2f);
@@ -422,6 +444,17 @@ public class Fx{
}), }),
hitMeltHeal = new Effect(12, e -> {
color(Pal.heal);
stroke(e.fout() * 2f);
randLenVectors(e.id, 6, e.finpow() * 18f, e.rotation, 360f, (x, y) -> {
float ang = Mathf.angle(x, y);
lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f);
});
}),
hitLaser = new Effect(8, e -> { hitLaser = new Effect(8, e -> {
color(Color.white, Pal.heal, e.fin()); color(Color.white, Pal.heal, e.fin());
stroke(0.5f + e.fout()); stroke(0.5f + e.fout());
@@ -1252,6 +1285,14 @@ public class Fx{
}); });
}), }),
smokeCloud = new Effect(70, e -> {
randLenVectors(e.id, e.fin(), 30, 30f, (x, y, fin, fout) -> {
color(Color.gray);
alpha((0.5f - Math.abs(fin - 0.5f)) * 2f);
Fill.circle(e.x + x, e.y + y, 0.5f + fout * 4f);
});
}),
smeltsmoke = new Effect(15, e -> { smeltsmoke = new Effect(15, e -> {
randLenVectors(e.id, 6, 4f + e.fin() * 5f, (x, y) -> { randLenVectors(e.id, 6, 4f + e.fin() * 5f, (x, y) -> {
color(Color.white, e.color, e.fin()); color(Color.white, e.color, e.fin());

View File

@@ -9,7 +9,7 @@ import mindustry.type.StatusEffect;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class StatusEffects implements ContentList{ public class StatusEffects implements ContentList{
public static StatusEffect none, burning, freezing, wet, muddy, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed; public static StatusEffect none, burning, freezing, unmoving, slow, wet, muddy, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed;
@Override @Override
public void load(){ public void load(){
@@ -45,6 +45,14 @@ public class StatusEffects implements ContentList{
}); });
}}; }};
unmoving = new StatusEffect("unmoving"){{
speedMultiplier = 0.001f;
}};
slow = new StatusEffect("slow"){{
speedMultiplier = 0.4f;
}};
wet = new StatusEffect("wet"){{ wet = new StatusEffect("wet"){{
color = Color.royal; color = Color.royal;
speedMultiplier = 0.94f; speedMultiplier = 0.94f;

View File

@@ -14,12 +14,18 @@ import mindustry.type.*;
public class UnitTypes implements ContentList{ public class UnitTypes implements ContentList{
//region definitions //region definitions
//ground //mech
public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign; public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign;
//ground + builder + miner + commander //mech + builder + miner + commander
public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class, Commanderc.class}) UnitType nova, pulsar, quasar; public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class, Commanderc.class}) UnitType nova, pulsar, quasar;
//mech + commander
public static @EntityDef({Unitc.class, Mechc.class, Commanderc.class}) UnitType vela;
//legs + commander
public static @EntityDef({Unitc.class, Legsc.class, Commanderc.class}) UnitType corvus;
//legs //legs
public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax; public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax;
@@ -365,6 +371,134 @@ public class UnitTypes implements ContentList{
}}); }});
}}; }};
vela = new UnitType("vela"){{
hitsize = 23f;
rotateSpeed = 1.6f;
canDrown = false;
mechFrontSway = 1f;
mechStepParticles = true;
mechStepShake = 0.15f;
speed = 0.35f;
boostMultiplier = 1.5f;
engineOffset = 12f;
engineSize = 6f;
health = 6000f;
armor = 7f;
canBoost = true;
landShake = 4f;
commandLimit = 32;
weapons.add(new Weapon("vela-weapon"){{
mirror = false;
top = false;
shake = 4f;
shootY = 13f;
x = y = 0f;
firstShotDelay = Fx.greenLaserChargeSmall.lifetime - 1f;
reload = 320f;
recoil = 0f;
shootSound = Sounds.laser;
continuous = true;
cooldownTime = 200f;
bullet = new ContinuousLaserBulletType(16){{
length = 150f;
hitEffect = Fx.hitMeltHeal;
drawSize = 420f;
lifetime = 160f;
shake = 1f;
despawnEffect = Fx.smokeCloud;
smokeEffect = Fx.none;
shootEffect = Fx.greenLaserChargeSmall;
incendChance = 0.02f;
incendSpread = 5f;
incendAmount = 1;
colors = new Color[]{Pal.heal.cpy().a(.2f), Pal.heal.cpy().a(.5f), Pal.heal.cpy().mul(1.2f), Color.white};
}};
shootStatus = StatusEffects.slow;
shootStatusDuration = bullet.lifetime + firstShotDelay;
}});
}};
corvus = new UnitType("corvus"){{
mineTier = 1;
hitsize = 29f;
itemCapacity = 80;
health = 19000f;
buildSpeed = 1.7f;
armor = 9f;
landShake = 1.5f;
commandLimit = 24;
legCount = 4;
legLength = 14f;
legBaseOffset = 10f;
legMoveSpace = 1.5f;
legTrns = 0.58f;
hovering = true;
visualElevation = 0.2f;
allowLegStep = true;
speed = 0.3f;
mineTier = 2;
mineSpeed = 7f;
drawShields = false;
weapons.add(new Weapon("corvus-weapon"){{
top = false;
mirror = false;
shake = 14f;
shootY = 5f;
x = y = 0;
reload = 350f;
recoil = 0f;
shootSound = Sounds.laser;
cooldownTime = 350f;
shootStatusDuration = 60f * 2f;
shootStatus = StatusEffects.unmoving;
firstShotDelay = Fx.greenLaserCharge.lifetime;
bullet = new LaserBulletType(){{
length = 500f;
damage = 520f;
width = 75f;
lifetime = 65f;
lightningSpacing = 35f;
lightningLength = 5;
lightningDelay = 1.1f;
lightningLengthRand = 15;
lightningDamage = 50;
lightningAngleRand = 40f;
largeHit = true;
lightColor = lightningColor = Pal.heal;
shootEffect = Fx.greenLaserCharge;
sideAngle = 15f;
sideWidth = 0f;
sideLength = 0f;
colors = new Color[]{Pal.heal.cpy().a(0.4f), Pal.heal, Color.white};
}};
}});
}};
//endregion //endregion
//region ground legs //region ground legs
@@ -405,6 +539,7 @@ public class UnitTypes implements ContentList{
targetAir = false; targetAir = false;
health = 600; health = 600;
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting); immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
legCount = 4; legCount = 4;
legLength = 9f; legLength = 9f;
legTrns = 0.6f; legTrns = 0.6f;
@@ -603,8 +738,8 @@ public class UnitTypes implements ContentList{
drag = 0.1f; drag = 0.1f;
speed = 0.5f; speed = 0.5f;
hitsize = 21f; hitsize = 21f;
health = 23000; health = 22000;
armor = 14f; armor = 13f;
rotateSpeed = 1.9f; rotateSpeed = 1.9f;
@@ -1121,7 +1256,7 @@ public class UnitTypes implements ContentList{
lifetime = 70f; lifetime = 70f;
despawnEffect = Fx.healBomb; despawnEffect = Fx.greenBomb;
hitEffect = Fx.massiveExplosion; hitEffect = Fx.massiveExplosion;
keepVelocity = false; keepVelocity = false;
spin = 2f; spin = 2f;
@@ -1139,7 +1274,7 @@ public class UnitTypes implements ContentList{
oct = new UnitType("oct"){{ oct = new UnitType("oct"){{
armor = 16f; armor = 16f;
health = 23000; health = 24000;
speed = 0.6f; speed = 0.6f;
rotateSpeed = 1f; rotateSpeed = 1f;
accel = 0.04f; accel = 0.04f;
@@ -1149,10 +1284,11 @@ public class UnitTypes implements ContentList{
engineSize = 7.8f; engineSize = 7.8f;
rotateShooting = false; rotateShooting = false;
hitsize = 60f; hitsize = 60f;
payloadCapacity = (4.5f * 4.5f) * (8 * 8); payloadCapacity = (5.2f * 5.2f) * (8 * 8);
buildSpeed = 3.5f; buildSpeed = 4f;
drawShields = false;
abilities.add(new ForceFieldAbility(140f, 4f, 6000f, 60f * 8), new HealFieldAbility(130f, 60f * 2, 140f)); abilities.add(new ForceFieldAbility(140f, 4f, 7000f, 60f * 8), new HealFieldAbility(130f, 60f * 2, 140f));
}}; }};
//endregion //endregion

View File

@@ -77,8 +77,7 @@ public class Damage{
} }
} }
/** Collides a bullet with blocks in a laser, taking into account absorption blocks. Resulting length is stored in the bullet's fdata. */ public static float findLaserLength(Bullet b, float length){
public static float collideLaser(Bullet b, float length){
Tmp.v1.trns(b.rotation(), length); Tmp.v1.trns(b.rotation(), length);
furthest = null; furthest = null;
@@ -86,9 +85,15 @@ public class Damage{
world.raycast(b.tileX(), b.tileY(), world.toTile(b.x + Tmp.v1.x), world.toTile(b.y + Tmp.v1.y), world.raycast(b.tileX(), b.tileY(), world.toTile(b.x + Tmp.v1.x), world.toTile(b.y + Tmp.v1.y),
(x, y) -> (furthest = world.tile(x, y)) != null && furthest.team() != b.team && furthest.block().absorbLasers); (x, y) -> (furthest = world.tile(x, y)) != null && furthest.team() != b.team && furthest.block().absorbLasers);
float resultLength = furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length; return furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length;
}
/** Collides a bullet with blocks in a laser, taking into account absorption blocks. Resulting length is stored in the bullet's fdata. */
public static float collideLaser(Bullet b, float length, boolean large){
float resultLength = findLaserLength(b, length);
collideLine(b, b.team, b.type.hitEffect, b.x, b.y, b.rotation(), resultLength, large);
Damage.collideLine(b, b.team, b.type.hitEffect, b.x, b.y, b.rotation(), resultLength);
b.fdata = furthest != null ? resultLength : length; b.fdata = furthest != null ? resultLength : length;
return resultLength; return resultLength;
@@ -103,6 +108,8 @@ public class Damage{
* Only enemies of the specified team are damaged. * Only enemies of the specified team are damaged.
*/ */
public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length, boolean large){ public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length, boolean large){
length = findLaserLength(hitter, length);
collidedBlocks.clear(); collidedBlocks.clear();
tr.trns(angle, length); tr.trns(angle, length);
Intc2 collider = (cx, cy) -> { Intc2 collider = (cx, cy) -> {

View File

@@ -96,7 +96,7 @@ public abstract class BulletType extends Content{
public Color lightningColor = Pal.surge; public Color lightningColor = Pal.surge;
public int lightning; public int lightning;
public int lightningLength = 5; public int lightningLength = 5, lightningLengthRand = 0;
/** Use a negative value to use default bullet damage. */ /** Use a negative value to use default bullet damage. */
public float lightningDamage = -1; public float lightningDamage = -1;
@@ -179,7 +179,7 @@ public abstract class BulletType extends Content{
} }
for(int i = 0; i < lightning; i++){ for(int i = 0; i < lightning; i++){
Lightning.create(b, lightningColor, lightningDamage < 0 ? damage : lightningDamage, b.x, b.y, Mathf.random(360f), lightningLength); Lightning.create(b, lightningColor, lightningDamage < 0 ? damage : lightningDamage, b.x, b.y, Mathf.random(360f), lightningLength + Mathf.random(lightningLengthRand));
} }
} }

View File

@@ -12,10 +12,13 @@ import mindustry.graphics.*;
public class ContinuousLaserBulletType extends BulletType{ public class ContinuousLaserBulletType extends BulletType{
public float length = 220f; public float length = 220f;
public float shake = 1f; public float shake = 1f;
public float fadeTime = 16f;
public Color[] colors = {Color.valueOf("ec745855"), Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white}; public Color[] colors = {Color.valueOf("ec745855"), Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white};
public float[] tscales = {1f, 0.7f, 0.5f, 0.2f}; public float[] tscales = {1f, 0.7f, 0.5f, 0.2f};
public float[] strokes = {2f, 1.5f, 1f, 0.3f}; public float[] strokes = {2f, 1.5f, 1f, 0.3f};
public float[] lenscales = {1f, 1.12f, 1.15f, 1.17f}; public float[] lenscales = {1f, 1.12f, 1.15f, 1.17f};
public float width = 9f, oscScl = 0.8f, oscMag = 1.5f;
public boolean largeHit = true;
public ContinuousLaserBulletType(float damage){ public ContinuousLaserBulletType(float damage){
super(0.001f, damage); super(0.001f, damage);
@@ -25,6 +28,7 @@ public class ContinuousLaserBulletType extends BulletType{
hitSize = 4; hitSize = 4;
drawSize = 420f; drawSize = 420f;
lifetime = 16f; lifetime = 16f;
keepVelocity = false;
pierce = true; pierce = true;
hittable = false; hittable = false;
hitColor = colors[2]; hitColor = colors[2];
@@ -32,6 +36,7 @@ public class ContinuousLaserBulletType extends BulletType{
incendAmount = 1; incendAmount = 1;
incendSpread = 5; incendSpread = 5;
incendChance = 0.4f; incendChance = 0.4f;
lightColor = Color.orange;
} }
protected ContinuousLaserBulletType(){ protected ContinuousLaserBulletType(){
@@ -43,13 +48,20 @@ public class ContinuousLaserBulletType extends BulletType{
return length; return length;
} }
@Override
public void init(){
super.init();
drawSize = Math.max(drawSize, length*2f);
}
@Override @Override
public void update(Bullet b){ public void update(Bullet b){
//TODO possible laser absorption from blocks //TODO possible laser absorption from blocks
//damage every 5 ticks //damage every 5 ticks
if(b.timer(1, 5f)){ if(b.timer(1, 5f)){
Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length, true); Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length, largeHit);
} }
if(shake > 0){ if(shake > 0){
@@ -59,21 +71,23 @@ public class ContinuousLaserBulletType extends BulletType{
@Override @Override
public void draw(Bullet b){ public void draw(Bullet b){
float baseLen = length * b.fout(); float realLength = Damage.findLaserLength(b, length);
float fout = Mathf.clamp(b.time > b.lifetime - fadeTime ? 1f - (b.time - (lifetime - fadeTime)) / fadeTime : 1f);
float baseLen = realLength * fout;
Lines.lineAngle(b.x, b.y, b.rotation(), baseLen); Lines.lineAngle(b.x, b.y, b.rotation(), baseLen);
for(int s = 0; s < colors.length; s++){ for(int s = 0; s < colors.length; s++){
Draw.color(Tmp.c1.set(colors[s]).mul(1f + Mathf.absin(Time.time(), 1f, 0.1f))); Draw.color(Tmp.c1.set(colors[s]).mul(1f + Mathf.absin(Time.time(), 1f, 0.1f)));
for(int i = 0; i < tscales.length; i++){ for(int i = 0; i < tscales.length; i++){
Tmp.v1.trns(b.rotation() + 180f, (lenscales[i] - 1f) * 35f); Tmp.v1.trns(b.rotation() + 180f, (lenscales[i] - 1f) * 35f);
Lines.stroke((9f + Mathf.absin(Time.time(), 0.8f, 1.5f)) * b.fout() * strokes[s] * tscales[i]); Lines.stroke((width + Mathf.absin(Time.time(), oscScl, oscMag)) * fout * strokes[s] * tscales[i]);
Lines.lineAngle(b.x + Tmp.v1.x, b.y + Tmp.v1.y, b.rotation(), baseLen * lenscales[i], false); Lines.lineAngle(b.x + Tmp.v1.x, b.y + Tmp.v1.y, b.rotation(), baseLen * lenscales[i], false);
} }
} }
Tmp.v1.trns(b.rotation(), baseLen * 1.1f); Tmp.v1.trns(b.rotation(), baseLen * 1.1f);
Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, 40, Color.orange, 0.7f); Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, 40, lightColor, 0.7f);
Draw.reset(); Draw.reset();
} }

View File

@@ -8,18 +8,17 @@ import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.world.*;
public class LaserBulletType extends BulletType{ public class LaserBulletType extends BulletType{
protected static Tile furthest; public Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white};
public Effect laserEffect = Fx.lancerLaserShootSmoke;
protected Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white}; public float length = 160f;
protected Effect laserEffect = Fx.lancerLaserShootSmoke; public float width = 15f;
protected float length = 160f; public float lengthFalloff = 0.5f;
protected float width = 15f; public float sideLength = 29f, sideWidth = 0.7f;
protected float lengthFalloff = 0.5f; public float sideAngle = 90f;
protected float sideLength = 29f, sideWidth = 0.7f; public float lightningSpacing = -1, lightningDelay = 0.1f, lightningAngleRand;
protected float sideAngle = 90f; public boolean largeHit = false;
public LaserBulletType(float damage){ public LaserBulletType(float damage){
super(0.01f, damage); super(0.01f, damage);
@@ -40,6 +39,13 @@ public class LaserBulletType extends BulletType{
this(1f); this(1f);
} }
@Override
public void init(){
super.init();
drawSize = Math.max(drawSize, length*2f);
}
@Override @Override
public float range(){ public float range(){
return length; return length;
@@ -47,8 +53,28 @@ public class LaserBulletType extends BulletType{
@Override @Override
public void init(Bullet b){ public void init(Bullet b){
float resultLength = Damage.collideLaser(b, length); float resultLength = Damage.collideLaser(b, length, largeHit), rot = b.rotation();
laserEffect.at(b.x, b.y, b.rotation(), resultLength * 0.75f);
laserEffect.at(b.x, b.y, rot, resultLength * 0.75f);
if(lightningSpacing > 0){
int idx = 0;
for(float i = 0; i <= resultLength; i += lightningSpacing){
float cx = b.x + Angles.trnsx(rot, i),
cy = b.y + Angles.trnsy(rot, i);
int f = idx++;
for(int s : Mathf.signs){
Time.run(f * lightningDelay, () ->
Lightning.create(b, lightningColor,
lightningDamage < 0 ? damage : lightningDamage,
cx, cy, rot + 90*s + Mathf.range(lightningAngleRand),
lightningLength + Mathf.random(lightningLengthRand))
);
}
}
}
} }
@Override @Override

View File

@@ -13,6 +13,7 @@ public class ShrapnelBulletType extends BulletType{
public float length = 100f; public float length = 100f;
public float width = 20f; public float width = 20f;
public Color fromColor = Color.white, toColor = Pal.lancerLaser; public Color fromColor = Color.white, toColor = Pal.lancerLaser;
public boolean hitLarge = false;
public int serrations = 7; public int serrations = 7;
public float serrationLenScl = 10f, serrationWidth = 4f, serrationSpacing = 8f, serrationSpaceOffset = 80f, serrationFadeOffset = 0.5f; public float serrationLenScl = 10f, serrationWidth = 4f, serrationSpacing = 8f, serrationSpaceOffset = 80f, serrationFadeOffset = 0.5f;
@@ -30,7 +31,14 @@ public class ShrapnelBulletType extends BulletType{
@Override @Override
public void init(Bullet b){ public void init(Bullet b){
Damage.collideLaser(b, length); Damage.collideLaser(b, length, hitLarge);
}
@Override
public void init(){
super.init();
drawSize = Math.max(drawSize, length*2f);
} }
@Override @Override

View File

@@ -150,7 +150,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
} }
public void lookAt(float angle){ public void lookAt(float angle){
rotation = Angles.moveToward(rotation, angle, type.rotateSpeed * Time.delta); rotation = Angles.moveToward(rotation, angle, type.rotateSpeed * Time.delta * speedMultiplier());
} }
public void lookAt(Position pos){ public void lookAt(Position pos){

View File

@@ -13,7 +13,7 @@ import mindustry.type.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@Component @Component
abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
@Import float x, y, rotation, reloadMultiplier; @Import float x, y, rotation, reloadMultiplier;
@Import Vec2 vel; @Import Vec2 vel;
@Import UnitType type; @Import UnitType type;
@@ -93,7 +93,27 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
for(WeaponMount mount : mounts){ for(WeaponMount mount : mounts){
Weapon weapon = mount.weapon; Weapon weapon = mount.weapon;
mount.reload = Math.max(mount.reload - Time.delta * reloadMultiplier, 0); mount.reload = Math.max(mount.reload - Time.delta * reloadMultiplier, 0);
mount.heat = Math.max(mount.heat - Time.delta * reloadMultiplier / mount.weapon.cooldownTime, 0);
float weaponRotation = this.rotation - 90 + (weapon.rotate ? mount.rotation : 0);
float mountX = this.x + Angles.trnsx(this.rotation - 90, weapon.x, weapon.y),
mountY = this.y + Angles.trnsy(this.rotation - 90, weapon.x, weapon.y);
float shootX = mountX + Angles.trnsx(weaponRotation, weapon.shootX, weapon.shootY),
shootY = mountY + Angles.trnsy(weaponRotation, weapon.shootX, weapon.shootY);
float shootAngle = weapon.rotate ? weaponRotation + 90 : Angles.angle(shootX, shootY, mount.aimX, mount.aimY) + (this.rotation - angleTo(mount.aimX, mount.aimY));
//update continuous state
if(weapon.continuous && mount.bullet != null){
if(!mount.bullet.isAdded() || mount.bullet.time >= mount.bullet.lifetime){
mount.bullet = null;
}else{
mount.bullet.rotation(shootAngle);
mount.bullet.set(shootX, shootY);
vel.add(Tmp.v1.trns(rotation + 180f, mount.bullet.type.recoil));
}
}else{
//heat decreases when not firing
mount.heat = Math.max(mount.heat - Time.delta * reloadMultiplier / mount.weapon.cooldownTime, 0);
}
//flip weapon shoot side for alternating weapons at half reload //flip weapon shoot side for alternating weapons at half reload
if(weapon.otherSide != -1 && weapon.alternate && mount.side == weapon.flipSprite && if(weapon.otherSide != -1 && weapon.alternate && mount.side == weapon.flipSprite &&
@@ -104,10 +124,10 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
//rotate if applicable //rotate if applicable
if(weapon.rotate && (mount.rotate || mount.shoot) && can){ if(weapon.rotate && (mount.rotate || mount.shoot) && can){
float axisX = this.x + Angles.trnsx(rotation - 90, weapon.x, weapon.y), float axisX = this.x + Angles.trnsx(this.rotation - 90, weapon.x, weapon.y),
axisY = this.y + Angles.trnsy(rotation - 90, weapon.x, weapon.y); axisY = this.y + Angles.trnsy(this.rotation - 90, weapon.x, weapon.y);
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - rotation; mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - this.rotation;
mount.rotation = Angles.moveToward(mount.rotation, mount.targetRotation, weapon.rotateSpeed * Time.delta); mount.rotation = Angles.moveToward(mount.rotation, mount.targetRotation, weapon.rotateSpeed * Time.delta);
}else if(!weapon.rotate){ }else if(!weapon.rotate){
mount.rotation = 0; mount.rotation = 0;
@@ -124,21 +144,9 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
mount.reload <= 0.0001f && //reload has to be 0 mount.reload <= 0.0001f && //reload has to be 0
Angles.within(weapon.rotate ? mount.rotation : this.rotation, mount.targetRotation, mount.weapon.shootCone) //has to be within the cone Angles.within(weapon.rotate ? mount.rotation : this.rotation, mount.targetRotation, mount.weapon.shootCone) //has to be within the cone
){ ){
shoot(mount, shootX, shootY, mount.aimX, mount.aimY, shootAngle, Mathf.sign(weapon.x));
float rotation = this.rotation - 90;
float weaponRotation = rotation + (weapon.rotate ? mount.rotation : 0);
float mountX = this.x + Angles.trnsx(rotation, weapon.x, weapon.y),
mountY = this.y + Angles.trnsy(rotation, weapon.x, weapon.y);
float shootX = mountX + Angles.trnsx(weaponRotation, weapon.shootX, weapon.shootY),
shootY = mountY + Angles.trnsy(weaponRotation, weapon.shootX, weapon.shootY);
float shootAngle = weapon.rotate ? weaponRotation + 90 : Angles.angle(shootX, shootY, mount.aimX, mount.aimY) + (this.rotation - angleTo(mount.aimX, mount.aimY));
shoot(weapon, shootX, shootY, mount.aimX, mount.aimY, shootAngle, Mathf.sign(weapon.x));
mount.reload = weapon.reload; mount.reload = weapon.reload;
mount.heat = 1f;
ammo--; ammo--;
if(ammo < 0) ammo = 0; if(ammo < 0) ammo = 0;
@@ -146,7 +154,8 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
} }
} }
private void shoot(Weapon weapon, float x, float y, float aimX, float aimY, float rotation, int side){ private void shoot(WeaponMount mount, float x, float y, float aimX, float aimY, float rotation, int side){
Weapon weapon = mount.weapon;
float baseX = this.x, baseY = this.y; float baseX = this.x, baseY = this.y;
@@ -156,29 +165,39 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
float lifeScl = ammo.scaleVelocity ? Mathf.clamp(Mathf.dst(x, y, aimX, aimY) / ammo.range()) : 1f; float lifeScl = ammo.scaleVelocity ? Mathf.clamp(Mathf.dst(x, y, aimX, aimY) / ammo.range()) : 1f;
sequenceNum = 0; sequenceNum = 0;
if(weapon.shotDelay > 0.01f){ if(weapon.shotDelay + weapon.firstShotDelay > 0.01f){
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> { Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> {
Time.run(sequenceNum * weapon.shotDelay, () -> bullet(weapon, x + this.x - baseX, y + this.y - baseY, f + Mathf.range(weapon.inaccuracy), lifeScl)); Time.run(sequenceNum * weapon.shotDelay + weapon.firstShotDelay, () -> mount.bullet = bullet(weapon, x + this.x - baseX, y + this.y - baseY, f + Mathf.range(weapon.inaccuracy), lifeScl));
sequenceNum++; sequenceNum++;
}); });
}else{ }else{
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> bullet(weapon, x, y, f + Mathf.range(weapon.inaccuracy), lifeScl)); Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> mount.bullet = bullet(weapon, x, y, f + Mathf.range(weapon.inaccuracy), lifeScl));
} }
vel().add(Tmp.v1.trns(rotation + 180f, ammo.recoil));
boolean parentize = ammo.keepVelocity; boolean parentize = ammo.keepVelocity;
Effect.shake(weapon.shake, weapon.shake, x, y); if(weapon.firstShotDelay > 0){
Time.run(weapon.firstShotDelay, () -> {
vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil));
Effect.shake(weapon.shake, weapon.shake, x, y);
mount.heat = 1f;
});
}else{
vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil));
Effect.shake(weapon.shake, weapon.shake, x, y);
mount.heat = 1f;
}
weapon.ejectEffect.at(x, y, rotation * side); weapon.ejectEffect.at(x, y, rotation * side);
ammo.shootEffect.at(x, y, rotation, parentize ? this : null); ammo.shootEffect.at(x, y, rotation, parentize ? this : null);
ammo.smokeEffect.at(x, y, rotation, parentize ? this : null); ammo.smokeEffect.at(x, y, rotation, parentize ? this : null);
apply(weapon.shootStatus, weapon.shootStatusDuration);
} }
private void bullet(Weapon weapon, float x, float y, float angle, float lifescl){ private Bullet bullet(Weapon weapon, float x, float y, float angle, float lifescl){
float xr = Mathf.range(weapon.xRand); float xr = Mathf.range(weapon.xRand);
weapon.bullet.create(this, team(), return weapon.bullet.create(this, team(),
x + Angles.trnsx(angle, 0, xr), x + Angles.trnsx(angle, 0, xr),
y + Angles.trnsy(angle, 0, xr), y + Angles.trnsy(angle, 0, xr),
angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd), lifescl); angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd), lifescl);

View File

@@ -1,5 +1,7 @@
package mindustry.entities.units; package mindustry.entities.units;
import arc.util.ArcAnnotate.*;
import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
public class WeaponMount{ public class WeaponMount{
@@ -21,6 +23,8 @@ public class WeaponMount{
public boolean rotate = false; public boolean rotate = false;
/** extra state for alternating weapons */ /** extra state for alternating weapons */
public boolean side; public boolean side;
/** current bullet for continuous weapons */
public @Nullable Bullet bullet;
public WeaponMount(Weapon weapon){ public WeaponMount(Weapon weapon){
this.weapon = weapon; this.weapon = weapon;

View File

@@ -135,7 +135,7 @@ public class UnitType extends UnlockableContent{
public void update(Unit unit){ public void update(Unit unit){
if(unit instanceof Mechc){ if(unit instanceof Mechc && !unit.isFlying()){
updateMechEffects(unit); updateMechEffects(unit);
} }
} }
@@ -526,7 +526,6 @@ public class UnitType extends UnlockableContent{
float rotation = unit.rotation - 90; float rotation = unit.rotation - 90;
float weaponRotation = rotation + (weapon.rotate ? mount.rotation : 0); float weaponRotation = rotation + (weapon.rotate ? mount.rotation : 0);
float width = weapon.region.width;
float recoil = -((mount.reload) / weapon.reload * weapon.recoil); float recoil = -((mount.reload) / weapon.reload * weapon.recoil);
float wx = unit.x + Angles.trnsx(rotation, weapon.x, weapon.y) + Angles.trnsx(weaponRotation, 0, recoil), float wx = unit.x + Angles.trnsx(rotation, weapon.x, weapon.y) + Angles.trnsx(weaponRotation, 0, recoil),
wy = unit.y + Angles.trnsy(rotation, weapon.x, weapon.y) + Angles.trnsy(weaponRotation, 0, recoil); wy = unit.y + Angles.trnsy(rotation, weapon.x, weapon.y) + Angles.trnsy(weaponRotation, 0, recoil);
@@ -541,17 +540,16 @@ public class UnitType extends UnlockableContent{
Draw.rect(weapon.outlineRegion, Draw.rect(weapon.outlineRegion,
wx, wy, wx, wy,
width * Draw.scl * -Mathf.sign(weapon.flipSprite), weapon.outlineRegion.width * Draw.scl * -Mathf.sign(weapon.flipSprite),
weapon.region.height * Draw.scl, weapon.region.height * Draw.scl,
weaponRotation); weaponRotation);
Draw.z(z); Draw.z(z);
} }
Draw.rect(weapon.region, Draw.rect(weapon.region,
wx, wy, wx, wy,
width * Draw.scl * -Mathf.sign(weapon.flipSprite), weapon.region.width * Draw.scl * -Mathf.sign(weapon.flipSprite),
weapon.region.height * Draw.scl, weapon.region.height * Draw.scl,
weaponRotation); weaponRotation);
@@ -560,8 +558,8 @@ public class UnitType extends UnlockableContent{
Draw.blend(Blending.additive); Draw.blend(Blending.additive);
Draw.rect(weapon.heatRegion, Draw.rect(weapon.heatRegion,
wx, wy, wx, wy,
width * Draw.scl * -Mathf.sign(weapon.flipSprite), weapon.heatRegion.width * Draw.scl * -Mathf.sign(weapon.flipSprite),
weapon.region.height * Draw.scl, weapon.heatRegion.height * Draw.scl,
weaponRotation); weaponRotation);
Draw.blend(); Draw.blend();
Draw.color(); Draw.color();

View File

@@ -29,6 +29,8 @@ public class Weapon{
public boolean rotate = false; public boolean rotate = false;
/** whether to draw the outline on top. */ /** whether to draw the outline on top. */
public boolean top = true; public boolean top = true;
/** whether to hold the bullet in place while firing */
public boolean continuous;
/** rotation speed of weapon when rotation is enabled, in degrees/t*/ /** rotation speed of weapon when rotation is enabled, in degrees/t*/
public float rotateSpeed = 20f; public float rotateSpeed = 20f;
/** weapon reload in frames */ /** weapon reload in frames */
@@ -54,6 +56,8 @@ public class Weapon{
/** fraction of velocity that is random */ /** fraction of velocity that is random */
public float velocityRnd = 0f; public float velocityRnd = 0f;
/** delay in ticks between shots */ /** delay in ticks between shots */
public float firstShotDelay = 0;
/** delay in ticks between shots */
public float shotDelay = 0; public float shotDelay = 0;
/** The half-radius of the cone in which shooting will start. */ /** The half-radius of the cone in which shooting will start. */
public float shootCone = 5f; public float shootCone = 5f;
@@ -77,6 +81,10 @@ public class Weapon{
public TextureRegion outlineRegion; public TextureRegion outlineRegion;
/** heat region tint */ /** heat region tint */
public Color heatColor = Pal.turretHeat; public Color heatColor = Pal.turretHeat;
/** status effect applied when shooting */
public StatusEffect shootStatus = StatusEffects.none;
/** status effect duration when shot */
public float shootStatusDuration = 60f * 5f;
public Weapon(String name){ public Weapon(String name){
this.name = name; this.name = name;

View File

@@ -56,7 +56,7 @@ public class DatabaseDialog extends BaseDialog{
for(int i = 0; i < array.size; i++){ for(int i = 0; i < array.size; i++){
UnlockableContent unlock = (UnlockableContent)array.get(i); UnlockableContent unlock = (UnlockableContent)array.get(i);
Image image = unlocked(unlock) ? new Image(unlock.icon(Cicon.medium)).setScaling(Scaling.bounded) : new Image(Icon.lock, Pal.gray); Image image = unlocked(unlock) ? new Image(unlock.icon(Cicon.medium)).setScaling(Scaling.fit) : new Image(Icon.lock, Pal.gray);
list.add(image).size(8*4).pad(3); list.add(image).size(8*4).pad(3);
ClickListener listener = new ClickListener(); ClickListener listener = new ClickListener();
image.addListener(listener); image.addListener(listener);