Multi-legged unit implementations
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 464 B After Width: | Height: | Size: 455 B |
|
Before Width: | Height: | Size: 1018 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 182 KiB |
@@ -266,6 +266,7 @@ public class UnitTypes implements ContentList{
|
|||||||
legLength = 9f;
|
legLength = 9f;
|
||||||
legTrns = 0.6f;
|
legTrns = 0.6f;
|
||||||
legMoveSpace = 1.4f;
|
legMoveSpace = 1.4f;
|
||||||
|
hovering = true;
|
||||||
|
|
||||||
weapons.add(new Weapon("eruption"){{
|
weapons.add(new Weapon("eruption"){{
|
||||||
shootY = 3f;
|
shootY = 3f;
|
||||||
@@ -281,37 +282,61 @@ public class UnitTypes implements ContentList{
|
|||||||
drag = 0.01f;
|
drag = 0.01f;
|
||||||
shootEffect = Fx.shootSmall;
|
shootEffect = Fx.shootSmall;
|
||||||
lifetime = 56f;
|
lifetime = 56f;
|
||||||
|
collidesAir = false;
|
||||||
}};
|
}};
|
||||||
}});
|
}});
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//TODO this is just a clone
|
|
||||||
spiroct = new UnitType("spiroct"){{
|
spiroct = new UnitType("spiroct"){{
|
||||||
speed = 0.4f;
|
speed = 0.4f;
|
||||||
drag = 0.4f;
|
drag = 0.4f;
|
||||||
hitsize = 10f;
|
hitsize = 10f;
|
||||||
rotateSpeed = 3f;
|
rotateSpeed = 3f;
|
||||||
targetAir = false;
|
|
||||||
health = 600;
|
health = 600;
|
||||||
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
|
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
|
||||||
legCount = 6;
|
legCount = 6;
|
||||||
legLength = 11f;
|
legLength = 13f;
|
||||||
legTrns = 0.6f;
|
legTrns = 0.7f;
|
||||||
legMoveSpace = 1.4f;
|
legMoveSpace = 1.4f;
|
||||||
|
legBaseOffset = 2f;
|
||||||
|
hovering = true;
|
||||||
|
|
||||||
weapons.add(new Weapon("eruption"){{
|
weapons.add(new Weapon("spiroct-weapon"){{
|
||||||
shootY = 3f;
|
shootY = 4f;
|
||||||
reload = 10f;
|
reload = 15f;
|
||||||
ejectEffect = Fx.none;
|
ejectEffect = Fx.none;
|
||||||
recoil = 1f;
|
recoil = 2f;
|
||||||
x = 7f;
|
rotate = true;
|
||||||
shootSound = Sounds.flame;
|
shootSound = Sounds.flame;
|
||||||
|
|
||||||
bullet = new LiquidBulletType(Liquids.slag){{
|
x = 8.5f;
|
||||||
damage = 11;
|
y = -1.5f;
|
||||||
speed = 2.3f;
|
|
||||||
drag = 0.02f;
|
bullet = new SapBulletType(){{
|
||||||
|
length = 75f;
|
||||||
|
damage = 14;
|
||||||
shootEffect = Fx.shootSmall;
|
shootEffect = Fx.shootSmall;
|
||||||
|
hitColor = color = Color.valueOf("bf92f9");
|
||||||
|
despawnEffect = Fx.none;
|
||||||
|
width = 0.54f;
|
||||||
|
lifetime = 35f;
|
||||||
|
}};
|
||||||
|
}});
|
||||||
|
|
||||||
|
weapons.add(new Weapon("mount-purple-weapon"){{
|
||||||
|
reload = 20f;
|
||||||
|
rotate = true;
|
||||||
|
x = 4f;
|
||||||
|
y = 3f;
|
||||||
|
|
||||||
|
bullet = new SapBulletType(){{
|
||||||
|
length = 40f;
|
||||||
|
damage = 9;
|
||||||
|
shootEffect = Fx.shootSmall;
|
||||||
|
hitColor = color = Color.valueOf("bf92f9");
|
||||||
|
despawnEffect = Fx.none;
|
||||||
|
width = 0.4f;
|
||||||
|
lifetime = 25f;
|
||||||
}};
|
}};
|
||||||
}});
|
}});
|
||||||
}};
|
}};
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ public class Damage{
|
|||||||
private static GridBits bits = new GridBits(30, 30);
|
private static GridBits bits = new GridBits(30, 30);
|
||||||
private static IntQueue propagation = new IntQueue();
|
private static IntQueue propagation = new IntQueue();
|
||||||
private static IntSet collidedBlocks = new IntSet();
|
private static IntSet collidedBlocks = new IntSet();
|
||||||
|
private static Building tmpBuilding;
|
||||||
|
private static Unit tmpUnit;
|
||||||
|
|
||||||
/** Creates a dynamic explosion based on specified parameters. */
|
/** Creates a dynamic explosion based on specified parameters. */
|
||||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){
|
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){
|
||||||
@@ -88,7 +90,7 @@ public class Damage{
|
|||||||
if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.team() != team && tile.collide(hitter)){
|
if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.team() != team && tile.collide(hitter)){
|
||||||
tile.collision(hitter);
|
tile.collision(hitter);
|
||||||
collidedBlocks.add(tile.pos());
|
collidedBlocks.add(tile.pos());
|
||||||
hitter.type().hit(hitter, tile.x, tile.y);
|
hitter.type.hit(hitter, tile.x, tile.y);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -146,6 +148,73 @@ public class Damage{
|
|||||||
Units.nearbyEnemies(team, rect, cons);
|
Units.nearbyEnemies(team, rect, cons);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts forward in a line.
|
||||||
|
* @return the first encountered object.
|
||||||
|
*/
|
||||||
|
public static Healthc linecast(Bullet hitter, float x, float y, float angle, float length){
|
||||||
|
tr.trns(angle, length);
|
||||||
|
|
||||||
|
if(hitter.type.collidesGround){
|
||||||
|
tmpBuilding = null;
|
||||||
|
|
||||||
|
world.raycastEachWorld(x, y, x + tr.x, y + tr.y, (cx, cy) -> {
|
||||||
|
Building tile = world.ent(cx, cy);
|
||||||
|
if(tile != null && tile.team != hitter.team){
|
||||||
|
tmpBuilding = tile;
|
||||||
|
//TODO return tile
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(tmpBuilding != null) return tmpBuilding;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.setPosition(x, y).setSize(tr.x, tr.y);
|
||||||
|
float x2 = tr.x + x, y2 = tr.y + y;
|
||||||
|
|
||||||
|
if(rect.width < 0){
|
||||||
|
rect.x += rect.width;
|
||||||
|
rect.width *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rect.height < 0){
|
||||||
|
rect.y += rect.height;
|
||||||
|
rect.height *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float expand = 3f;
|
||||||
|
|
||||||
|
rect.y -= expand;
|
||||||
|
rect.x -= expand;
|
||||||
|
rect.width += expand * 2;
|
||||||
|
rect.height += expand * 2;
|
||||||
|
|
||||||
|
tmpUnit = null;
|
||||||
|
|
||||||
|
Cons<Unit> cons = e -> {
|
||||||
|
if((tmpUnit != null && e.dst2(x, y) > tmpUnit.dst2(x, y)) || !e.checkTarget(hitter.type.collidesAir, hitter.type.collidesGround)) return;
|
||||||
|
|
||||||
|
e.hitbox(hitrect);
|
||||||
|
Rect other = hitrect;
|
||||||
|
other.y -= expand;
|
||||||
|
other.x -= expand;
|
||||||
|
other.width += expand * 2;
|
||||||
|
other.height += expand * 2;
|
||||||
|
|
||||||
|
Vec2 vec = Geometry.raycastRect(x, y, x2, y2, other);
|
||||||
|
|
||||||
|
if(vec != null){
|
||||||
|
tmpUnit = e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Units.nearbyEnemies(hitter.team, rect, cons);
|
||||||
|
|
||||||
|
return tmpUnit;
|
||||||
|
}
|
||||||
|
|
||||||
/** Damages all entities and blocks in a radius that are enemies of the team. */
|
/** Damages all entities and blocks in a radius that are enemies of the team. */
|
||||||
public static void damageUnits(Team team, float x, float y, float size, float damage, Boolf<Unit> predicate, Cons<Unit> acceptor){
|
public static void damageUnits(Team team, float x, float y, float size, float damage, Boolf<Unit> predicate, Cons<Unit> acceptor){
|
||||||
Cons<Unit> cons = entity -> {
|
Cons<Unit> cons = entity -> {
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public abstract class BulletType extends Content{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void despawned(Bullet b){
|
public void despawned(Bullet b){
|
||||||
despawnEffect.at(b.x, b.y, b.rotation());
|
despawnEffect.at(b.x, b.y, b.rotation(), hitColor);
|
||||||
hitSound.at(b);
|
hitSound.at(b);
|
||||||
|
|
||||||
if(fragBullet != null || splashDamageRadius > 0 || lightning > 0){
|
if(fragBullet != null || splashDamageRadius > 0 || lightning > 0){
|
||||||
@@ -237,16 +237,16 @@ public abstract class BulletType extends Content{
|
|||||||
|
|
||||||
public Bullet create(@Nullable Entityc owner, Team team, float x, float y, float angle, float damage, float velocityScl, float lifetimeScl, Object data){
|
public Bullet create(@Nullable Entityc owner, Team team, float x, float y, float angle, float damage, float velocityScl, float lifetimeScl, Object data){
|
||||||
Bullet bullet = Bullet.create();
|
Bullet bullet = Bullet.create();
|
||||||
bullet.type(this);
|
bullet.type = this;
|
||||||
bullet.owner(owner);
|
bullet.owner = owner;
|
||||||
bullet.team(team);
|
bullet.team = team;
|
||||||
bullet.vel.trns(angle, speed * velocityScl);
|
bullet.vel.trns(angle, speed * velocityScl);
|
||||||
bullet.set(x - bullet.vel.x * Time.delta(), y - bullet.vel.y * Time.delta());
|
bullet.set(x - bullet.vel.x * Time.delta(), y - bullet.vel.y * Time.delta());
|
||||||
bullet.lifetime(lifetime * lifetimeScl);
|
bullet.lifetime = lifetime * lifetimeScl;
|
||||||
bullet.data(data);
|
bullet.data = data;
|
||||||
bullet.drag(drag);
|
bullet.drag = drag;
|
||||||
bullet.hitSize(hitSize);
|
bullet.hitSize = hitSize;
|
||||||
bullet.damage(damage < 0 ? this.damage : damage);
|
bullet.damage = damage < 0 ? this.damage : damage;
|
||||||
bullet.add();
|
bullet.add();
|
||||||
|
|
||||||
if(keepVelocity && owner instanceof Hitboxc) bullet.vel.add(((Hitboxc)owner).deltaX(), ((Hitboxc)owner).deltaY());
|
if(keepVelocity && owner instanceof Hitboxc) bullet.vel.add(((Hitboxc)owner).deltaX(), ((Hitboxc)owner).deltaY());
|
||||||
|
|||||||
80
core/src/mindustry/entities/bullet/SapBulletType.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package mindustry.entities.bullet;
|
||||||
|
|
||||||
|
import arc.*;
|
||||||
|
import arc.graphics.*;
|
||||||
|
import arc.graphics.g2d.*;
|
||||||
|
import arc.math.geom.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import mindustry.content.*;
|
||||||
|
import mindustry.entities.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
import mindustry.graphics.*;
|
||||||
|
|
||||||
|
public class SapBulletType extends BulletType{
|
||||||
|
public float length = 100f;
|
||||||
|
public float sapStrength = 0.5f;
|
||||||
|
public Color color = Color.white.cpy();
|
||||||
|
public float width = 0.4f;
|
||||||
|
|
||||||
|
public SapBulletType(){
|
||||||
|
speed = 0.0001f;
|
||||||
|
despawnEffect = Fx.none;
|
||||||
|
pierce = true;
|
||||||
|
hitSize = 0f;
|
||||||
|
hittable = false;
|
||||||
|
hitEffect = Fx.hitLiquid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Bullet b){
|
||||||
|
if(b.data instanceof Position){
|
||||||
|
Position data = (Position)b.data;
|
||||||
|
Tmp.v1.set(data).lerp(b, b.fin());
|
||||||
|
|
||||||
|
Draw.color(color);
|
||||||
|
Drawf.laser(b.team, Core.atlas.find("laser"), Core.atlas.find("laser-end"),
|
||||||
|
b.x, b.y, Tmp.v1.x, Tmp.v1.y, width * b.fout());
|
||||||
|
|
||||||
|
Draw.reset();
|
||||||
|
|
||||||
|
Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, 15f * b.fout(), lightColor, 0.6f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float range(){
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Bullet b){
|
||||||
|
super.init(b);
|
||||||
|
|
||||||
|
Healthc target = Damage.linecast(b, b.x, b.y, b.rotation(), length);
|
||||||
|
b.data = target;
|
||||||
|
|
||||||
|
if(target != null){
|
||||||
|
float result = Math.min(target.health(), damage);
|
||||||
|
|
||||||
|
if(b.owner instanceof Healthc){
|
||||||
|
((Healthc)b.owner).heal(result * sapStrength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target instanceof Hitboxc){
|
||||||
|
Hitboxc hit = (Hitboxc)target;
|
||||||
|
|
||||||
|
hit.collision(b, hit.x(), hit.y());
|
||||||
|
b.collision(hit, hit.x(), hit.y());
|
||||||
|
}else if(target instanceof Building){
|
||||||
|
Building tile = (Building)target;
|
||||||
|
|
||||||
|
if(tile.collide(b)){
|
||||||
|
tile.collision(b);
|
||||||
|
hit(b, tile.x, tile.y);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
b.data = new Vec2().trns(b.rotation(), length).add(b.x, b.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
|||||||
|
|
||||||
@SyncLocal float elevation;
|
@SyncLocal float elevation;
|
||||||
private transient boolean wasFlying;
|
private transient boolean wasFlying;
|
||||||
|
transient boolean hovering;
|
||||||
transient float drownTime;
|
transient float drownTime;
|
||||||
transient float splashTimer;
|
transient float splashTimer;
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean canDrown(){
|
boolean canDrown(){
|
||||||
return isGrounded();
|
return isGrounded() && !hovering;
|
||||||
}
|
}
|
||||||
|
|
||||||
void landed(){
|
void landed(){
|
||||||
@@ -54,7 +55,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
|||||||
}
|
}
|
||||||
|
|
||||||
float floorSpeedMultiplier(){
|
float floorSpeedMultiplier(){
|
||||||
Floor on = isFlying() ? Blocks.air.asFloor() : floorOn();
|
Floor on = isFlying() || hovering ? Blocks.air.asFloor() : floorOn();
|
||||||
return on.speedMultiplier;
|
return on.speedMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
|||||||
wasFlying = isFlying();
|
wasFlying = isFlying();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isGrounded() && floor.isLiquid){
|
if(!hovering && isGrounded() && floor.isLiquid){
|
||||||
if((splashTimer += Mathf.dst(deltaX(), deltaY())) >= 7f){
|
if((splashTimer += Mathf.dst(deltaX(), deltaY())) >= 7f){
|
||||||
floor.walkEffect.at(x, y, 1f, floor.mapColor);
|
floor.walkEffect.at(x, y, 1f, floor.mapColor);
|
||||||
splashTimer = 0f;
|
splashTimer = 0f;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import static mindustry.Vars.*;
|
|||||||
@Component(base = true)
|
@Component(base = true)
|
||||||
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable{
|
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable{
|
||||||
|
|
||||||
|
@Import boolean hovering;
|
||||||
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health;
|
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health;
|
||||||
@Import boolean dead;
|
@Import boolean dead;
|
||||||
@Import Team team;
|
@Import Team team;
|
||||||
@@ -124,6 +125,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
this.elevation = type.flying ? 1f : type.baseElevation;
|
this.elevation = type.flying ? 1f : type.baseElevation;
|
||||||
this.armor = type.armor;
|
this.armor = type.armor;
|
||||||
this.hitSize = type.hitsize;
|
this.hitSize = type.hitsize;
|
||||||
|
this.hovering = type.hovering;
|
||||||
|
|
||||||
if(controller == null) controller(type.createController());
|
if(controller == null) controller(type.createController());
|
||||||
if(mounts().length != type.weapons.size) setupWeapons(type);
|
if(mounts().length != type.weapons.size) setupWeapons(type);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{
|
|||||||
@Import float x, y, rotation;
|
@Import float x, y, rotation;
|
||||||
|
|
||||||
/** minimum cursor distance from unit, fixes 'cross-eyed' shooting */
|
/** minimum cursor distance from unit, fixes 'cross-eyed' shooting */
|
||||||
static final float minAimDst = 20f;
|
static final float minAimDst = 18f;
|
||||||
/** temporary weapon sequence number */
|
/** temporary weapon sequence number */
|
||||||
static int sequenceNum = 0;
|
static int sequenceNum = 0;
|
||||||
|
|
||||||
@@ -93,11 +93,10 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{
|
|||||||
|
|
||||||
//rotate if applicable
|
//rotate if applicable
|
||||||
if(weapon.rotate && (mount.rotate || mount.shoot)){
|
if(weapon.rotate && (mount.rotate || mount.shoot)){
|
||||||
float axisXOffset = weapon.x;
|
float axisX = this.x + Angles.trnsx(rotation - 90, weapon.x, weapon.y),
|
||||||
float axisX = this.x + Angles.trnsx(rotation, axisXOffset, weapon.y),
|
axisY = this.y + Angles.trnsy(rotation - 90, weapon.x, weapon.y);
|
||||||
axisY = this.y + Angles.trnsy(rotation, axisXOffset, weapon.y);
|
|
||||||
|
|
||||||
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - rotation();
|
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - 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{
|
}else{
|
||||||
mount.rotation = 0;
|
mount.rotation = 0;
|
||||||
|
|||||||
@@ -572,7 +572,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
boolean boosted = (unit instanceof Mechc && unit.isFlying());
|
boolean boosted = (unit instanceof Mechc && unit.isFlying());
|
||||||
|
|
||||||
movement.set(xa, ya).nor().scl(speed);
|
movement.set(xa, ya).nor().scl(speed);
|
||||||
float mouseAngle = Angles.mouseAngle(unit.x(), unit.y());
|
float mouseAngle = Angles.mouseAngle(unit.x, unit.y);
|
||||||
boolean aimCursor = omni && player.shooting && unit.type().hasWeapons() && unit.type().faceTarget && !boosted && unit.type().rotateShooting;
|
boolean aimCursor = omni && player.shooting && unit.type().hasWeapons() && unit.type().faceTarget && !boosted && unit.type().rotateShooting;
|
||||||
|
|
||||||
if(aimCursor){
|
if(aimCursor){
|
||||||
@@ -586,7 +586,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
if(omni){
|
if(omni){
|
||||||
unit.moveAt(movement);
|
unit.moveAt(movement);
|
||||||
}else{
|
}else{
|
||||||
unit.moveAt(Tmp.v2.trns(unit.rotation(), movement.len()));
|
unit.moveAt(Tmp.v2.trns(unit.rotation, movement.len()));
|
||||||
if(!movement.isZero() && legs){
|
if(!movement.isZero() && legs){
|
||||||
unit.vel().rotateTo(movement.angle(), unit.type().rotateSpeed * Time.delta());
|
unit.vel().rotateTo(movement.angle(), unit.type().rotateSpeed * Time.delta());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class UnitType extends UnlockableContent{
|
|||||||
public int commandLimit = 24;
|
public int commandLimit = 24;
|
||||||
public float baseElevation = 0f;
|
public float baseElevation = 0f;
|
||||||
public float deathShake = 2f;
|
public float deathShake = 2f;
|
||||||
|
public boolean hovering = false;
|
||||||
public Effect fallEffect = Fx.fallSmoke;
|
public Effect fallEffect = Fx.fallSmoke;
|
||||||
public Effect fallThrusterEffect = Fx.fallSmoke;
|
public Effect fallThrusterEffect = Fx.fallSmoke;
|
||||||
public Seq<mindustry.entities.abilities.Ability> abilities = new Seq<>();
|
public Seq<mindustry.entities.abilities.Ability> abilities = new Seq<>();
|
||||||
|
|||||||