diff --git a/annotations/src/main/java/mindustry/annotations/Annotations.java b/annotations/src/main/java/mindustry/annotations/Annotations.java index 6441cacf2f..b5533616ec 100644 --- a/annotations/src/main/java/mindustry/annotations/Annotations.java +++ b/annotations/src/main/java/mindustry/annotations/Annotations.java @@ -8,8 +8,9 @@ public class Annotations{ /** Indicates multiple inheritance on a component type. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) - public @interface Depends{ - Class[] value(); + public @interface Component{ + /** Dependencies. */ + Class[] value() default {}; } /** Indicates that a component def is present on all entities. */ diff --git a/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java index ab1ef61b7b..af31bcb432 100644 --- a/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java +++ b/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java @@ -45,7 +45,7 @@ public class EntityProcess extends BaseProcessor{ } //add all components w/ dependencies - allComponents.addAll(types(Depends.class).map(s -> Array.withArrays(getDependencies(s), s)).flatten()); + allComponents.addAll(types(Component.class).map(s -> Array.withArrays(getDependencies(s), s)).flatten()); //add component imports for(Stype comp : allComponents){ @@ -77,6 +77,9 @@ public class EntityProcess extends BaseProcessor{ //add utility methods to interface for(Smethod method : component.methods()){ + //skip private methods, those are for internal use. + if(method.is(Modifier.PRIVATE)) continue; + inter.addMethod(MethodSpec.methodBuilder(method.name()) .addExceptions(method.thrownt()) .addTypeVariables(method.typeVariables().map(TypeVariableName::get)) @@ -107,6 +110,11 @@ public class EntityProcess extends BaseProcessor{ for(Svar f : fields){ VariableTree tree = f.tree(); FieldSpec.Builder fbuilder = FieldSpec.builder(f.tname(), f.name()); + //keep statics/finals + if(f.is(Modifier.STATIC)){ + fbuilder.addModifiers(Modifier.STATIC); + if(f.is(Modifier.FINAL)) fbuilder.addModifiers(Modifier.FINAL); + } //add initializer if it exists if(tree.getInitializer() != null){ fbuilder.initializer(tree.getInitializer().toString()); @@ -125,7 +133,7 @@ public class EntityProcess extends BaseProcessor{ //representative method Smethod first = entry.value.first(); //build method using same params/returns - MethodSpec.Builder mbuilder = MethodSpec.methodBuilder(first.name()).addModifiers(Modifier.PUBLIC, Modifier.FINAL); + MethodSpec.Builder mbuilder = MethodSpec.methodBuilder(first.name()).addModifiers(first.is(Modifier.PRIVATE) ? Modifier.PRIVATE : Modifier.PUBLIC, Modifier.FINAL); mbuilder.addTypeVariables(first.typeVariables().map(TypeVariableName::get)); mbuilder.returns(first.retn()); mbuilder.addExceptions(first.thrownt()); @@ -191,6 +199,11 @@ public class EntityProcess extends BaseProcessor{ for(Stype comp : components){ //implement the interface Stype inter = interfaces.find(i -> i.name().equals(interfaceName(comp))); + if(inter == null){ + err("Failed to generate interface for component. Interfaces are " + interfaces + "\nComponent", comp); + return; + } + def.builder.addSuperinterface(inter.tname()); //generate getter/setter for each method @@ -251,9 +264,9 @@ public class EntityProcess extends BaseProcessor{ out.addAll(component.superclasses()); //get dependency classes - if(component.annotation(Depends.class) != null){ + if(component.annotation(Component.class) != null){ try{ - component.annotation(Depends.class).value(); + component.annotation(Component.class).value(); }catch(MirroredTypesException e){ out.addAll(Array.with(e.getTypeMirrors()).map(Stype::of)); } diff --git a/annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java b/annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java index 10d822dd59..f1b24f3a11 100644 --- a/annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java +++ b/annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java @@ -146,8 +146,12 @@ public class RemoteWriteGenerator{ VariableElement var = elem.getParameters().get(i); - //add parameter to method - method.addParameter(TypeName.get(var.asType()), var.getSimpleName().toString()); + try{ + //add parameter to method + method.addParameter(TypeName.get(var.asType()), var.getSimpleName().toString()); + }catch(Throwable t){ + throw new RuntimeException("Error parsing method " + methodEntry.targetMethod); + } //name of parameter String varName = var.getSimpleName().toString(); diff --git a/core/assets-raw/sprites/blocks/mechs/alpha-mech-pad.png b/core/assets-raw/sprites/blocks/mechs/alpha-mech-pad.png new file mode 100644 index 0000000000..e5a90abb4b Binary files /dev/null and b/core/assets-raw/sprites/blocks/mechs/alpha-mech-pad.png differ diff --git a/core/assets-raw/sprites/blocks/mechs/dart-mech-pad.png b/core/assets-raw/sprites/blocks/mechs/dart-ship-pad.png similarity index 100% rename from core/assets-raw/sprites/blocks/mechs/dart-mech-pad.png rename to core/assets-raw/sprites/blocks/mechs/dart-ship-pad.png diff --git a/core/assets-raw/sprites/mechs/mechs/alpha-mech-base.png b/core/assets-raw/sprites/mechs/mechs/alpha-mech-base.png index 703f86e430..61fb31cf47 100644 Binary files a/core/assets-raw/sprites/mechs/mechs/alpha-mech-base.png and b/core/assets-raw/sprites/mechs/mechs/alpha-mech-base.png differ diff --git a/core/assets-raw/sprites/mechs/mechs/alpha-mech-leg.png b/core/assets-raw/sprites/mechs/mechs/alpha-mech-leg.png index d60217a0bc..3be6f210e2 100644 Binary files a/core/assets-raw/sprites/mechs/mechs/alpha-mech-leg.png and b/core/assets-raw/sprites/mechs/mechs/alpha-mech-leg.png differ diff --git a/core/assets-raw/sprites/mechs/mechs/alpha-mech.png b/core/assets-raw/sprites/mechs/mechs/alpha-mech.png index 623b8e7791..a01baf8e22 100644 Binary files a/core/assets-raw/sprites/mechs/mechs/alpha-mech.png and b/core/assets-raw/sprites/mechs/mechs/alpha-mech.png differ diff --git a/core/assets-raw/sprites/mechs/ships/dart-ship.png b/core/assets-raw/sprites/mechs/ships/dart-ship.png index e9567d8ecd..12f4d9c924 100644 Binary files a/core/assets-raw/sprites/mechs/ships/dart-ship.png and b/core/assets-raw/sprites/mechs/ships/dart-ship.png differ diff --git a/core/assets-raw/sprites/mechs/ships/vanguard-ship.png b/core/assets-raw/sprites/mechs/ships/vanguard-ship.png new file mode 100644 index 0000000000..f4ac2a3210 Binary files /dev/null and b/core/assets-raw/sprites/mechs/ships/vanguard-ship.png differ diff --git a/core/assets-raw/sprites/weapons/shockgun-equip.png b/core/assets-raw/sprites/weapons/shockgun-equip.png index c53587d7ee..6e1993212b 100644 Binary files a/core/assets-raw/sprites/weapons/shockgun-equip.png and b/core/assets-raw/sprites/weapons/shockgun-equip.png differ diff --git a/core/assets-raw/sprites/weapons/vanguard-blaster-equip.png b/core/assets-raw/sprites/weapons/vanguard-blaster-equip.png new file mode 100644 index 0000000000..7d1e246dd4 Binary files /dev/null and b/core/assets-raw/sprites/weapons/vanguard-blaster-equip.png differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index de9a945104..8d7cd69fc5 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -974,7 +974,8 @@ block.pneumatic-drill.name = Pneumatic Drill block.laser-drill.name = Laser Drill block.water-extractor.name = Water Extractor block.cultivator.name = Cultivator -block.dart-mech-pad.name = Alpha Mech Pad +block.dart-ship-pad.name = Dart Ship Pad +block.alpha-mech-pad.name = Alpha Mech Pad block.delta-mech-pad.name = Delta Mech Pad block.javelin-ship-pad.name = Javelin Ship Pad block.trident-ship-pad.name = Trident Ship Pad @@ -1249,7 +1250,6 @@ block.crawler-factory.description = Produces fast self-destructing swarm units. block.titan-factory.description = Produces advanced, armored ground units. block.fortress-factory.description = Produces heavy artillery ground units. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.dart-mech-pad.description = Provides transformation into a basic attack mech.\nUse by tapping while standing on it. block.delta-mech-pad.description = Provides transformation into a lightly armored hit-and-run attack mech.\nUse by tapping while standing on it. block.tau-mech-pad.description = Provides transformation into an advanced support mech.\nUse by tapping while standing on it. block.omega-mech-pad.description = Provides transformation into a heavily-armored missile mech.\nUse by tapping while standing on it. diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index ff17679630..050d73da19 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -7,6 +7,7 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; +import mindustry.entities.traits.*; import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; @@ -25,6 +26,7 @@ public class BlockIndexer{ /** Set of all ores that are being scanned. */ private final ObjectSet scanOres = new ObjectSet<>(); + private final IntSet intSet = new IntSet(); private final ObjectSet itemSet = new ObjectSet<>(); /** Stores all ore quadtrants on the map. */ private ObjectMap> ores = new ObjectMap<>(); @@ -162,6 +164,39 @@ public class BlockIndexer{ return flagMap[team.id][type.ordinal()]; } + public boolean eachBlock(TeamTrait trait, float range, Boolf pred, Cons cons){ + return eachBlock(trait.getTeam(), trait.getX(), trait.getY(), range, pred, cons); + } + + public boolean eachBlock(Team team, float wx, float wy, float range, Boolf pred, Cons cons){ + intSet.clear(); + + int tx = world.toTile(wx); + int ty = world.toTile(wy); + + int tileRange = (int)(range / tilesize + 1); + intSet.clear(); + boolean any = false; + + for(int x = -tileRange + tx; x <= tileRange + tx; x++){ + for(int y = -tileRange + ty; y <= tileRange + ty; y++){ + if(!Mathf.within(x * tilesize, y * tilesize, wx, wy, range)) continue; + + Tile other = world.ltile(x, y); + + if(other == null) continue; + + if(other.getTeam() == team && !intSet.contains(other.pos()) && other.entity != null && pred.get(other)){ + cons.get(other); + any = true; + intSet.add(other.pos()); + } + } + } + + return any; + } + /** Get all enemy blocks with a flag. */ public Array getEnemy(Team team, BlockFlag type){ returnArray.clear(); diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 35ba8d6261..a4644312c4 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -80,7 +80,7 @@ public class Blocks implements ContentList{ fortressFactory, repairPoint, //upgrades - dartPad, deltaPad, tauPad, omegaPad, javelinPad, tridentPad, glaivePad; + dartPad, alphaPad, deltaPad, tauPad, omegaPad, javelinPad, tridentPad, glaivePad; @Override public void load(){ @@ -258,9 +258,7 @@ public class Blocks implements ContentList{ }}; ice = new Floor("ice"){{ - //TODO fix drag/speed - dragMultiplier = 1f; - speedMultiplier = 1f; + dragMultiplier = 0.6f; attributes.set(Attribute.water, 0.4f); }}; @@ -1273,6 +1271,7 @@ public class Blocks implements ContentList{ health = 1100; itemCapacity = 4000; size = 3; + mech = Mechs.vanguard; }}; coreFoundation = new CoreBlock("core-foundation"){{ @@ -1281,6 +1280,7 @@ public class Blocks implements ContentList{ health = 2000; itemCapacity = 9000; size = 4; + mech = Mechs.vanguard; }}; coreNucleus = new CoreBlock("core-nucleus"){{ @@ -1289,6 +1289,7 @@ public class Blocks implements ContentList{ health = 4000; itemCapacity = 13000; size = 5; + mech = Mechs.vanguard; }}; vault = new Vault("vault"){{ @@ -1707,6 +1708,7 @@ public class Blocks implements ContentList{ unitType = UnitTypes.ghoul; produceTime = 1150; size = 3; + maxSpawn = 2; consumes.power(1.2f); consumes.items(new ItemStack(Items.silicon, 15), new ItemStack(Items.titanium, 10)); }}; @@ -1716,6 +1718,7 @@ public class Blocks implements ContentList{ unitType = UnitTypes.revenant; produceTime = 2000; size = 4; + maxSpawn = 2; consumes.power(3f); consumes.items(new ItemStack(Items.silicon, 40), new ItemStack(Items.titanium, 30)); }}; @@ -1768,7 +1771,14 @@ public class Blocks implements ContentList{ //endregion //region upgrades - dartPad = new MechPad("dart-mech-pad"){{ + dartPad = new MechPad("dart-ship-pad"){{ + requirements(Category.upgrade, ItemStack.with(Items.lead, 100, Items.graphite, 50, Items.copper, 75)); + mech = Mechs.dart; + size = 2; + consumes.power(0.5f); + }}; + + alphaPad = new MechPad("alpha-mech-pad"){{ requirements(Category.upgrade, ItemStack.with(Items.lead, 100, Items.graphite, 50, Items.copper, 75)); mech = Mechs.alpha; size = 2; diff --git a/core/src/mindustry/content/Bullets.java b/core/src/mindustry/content/Bullets.java index 017798731c..fe2fe7e9a3 100644 --- a/core/src/mindustry/content/Bullets.java +++ b/core/src/mindustry/content/Bullets.java @@ -452,6 +452,7 @@ public class Bullets implements ContentList{ hitEffect = Fx.hitFlameSmall; despawnEffect = Fx.none; status = StatusEffects.burning; + keepVelocity = false; } @Override @@ -483,46 +484,13 @@ public class Bullets implements ContentList{ } }; - lancerLaser = new BulletType(0.001f, 140){ - Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white}; - float[] tscales = {1f, 0.7f, 0.5f, 0.2f}; - float[] lenscales = {1f, 1.1f, 1.13f, 1.14f}; - float length = 160f; - - { - hitEffect = Fx.hitLancer; - despawnEffect = Fx.none; - hitSize = 4; - lifetime = 16f; - pierce = true; - } - - @Override - public float range(){ - return length; - } - - @Override - public void init(Bullet b){ - Damage.collideLine(b, b.getTeam(), hitEffect, b.x, b.y, b.rot(), length); - } - - @Override - public void draw(Bullet b){ - float f = Mathf.curve(b.fin(), 0f, 0.2f); - float baseLen = length * f; - - Lines.lineAngle(b.x, b.y, b.rot(), baseLen); - for(int s = 0; s < 3; s++){ - Draw.color(colors[s]); - for(int i = 0; i < tscales.length; i++){ - Lines.stroke(7f * b.fout() * (s == 0 ? 1.5f : s == 1 ? 1f : 0.3f) * tscales[i]); - Lines.lineAngle(b.x, b.y, b.rot(), baseLen * lenscales[i]); - } - } - Draw.reset(); - } - }; + lancerLaser = new LaserBulletType(140){{ + colors = new Color[]{Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white}; + hitEffect = Fx.hitLancer; + despawnEffect = Fx.none; + hitSize = 4; + lifetime = 16f; + }}; meltdownLaser = new BulletType(0.001f, 70){ Color tmpColor = new Color(); @@ -622,22 +590,10 @@ public class Bullets implements ContentList{ } }; - arc = new BulletType(0.001f, 21){ - { - lifetime = 1; - despawnEffect = Fx.none; - hitEffect = Fx.hitLancer; - } - - @Override - public void draw(Bullet b){ - } - - @Override - public void init(Bullet b){ - Lightning.create(b.getTeam(), Pal.lancerLaser, damage, b.x, b.y, b.rot(), 25); - } - }; + arc = new LightningBulletType(){{ + damage = 21; + lightningLength = 25; + }}; driverBolt = new MassDriverBolt(); diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index a116034e1a..6303280e92 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -24,10 +24,10 @@ public class Fx implements ContentList{ producesmoke, smeltsmoke, formsmoke, blastsmoke, lava, doorclose, dooropen, dooropenlarge, doorcloselarge, purify, purifyoil, purifystone, generate, mine, mineBig, mineHuge, smelt, teleportActivate, teleport, teleportOut, ripple, bubble, launch, healBlock, healBlockFull, healWaveMend, overdriveWave, overdriveBlockFull, shieldBreak, hitBulletSmall, hitFuse, - hitBulletBig, hitFlameSmall, hitLiquid, hitLaser, hitLancer, hitMeltdown, despawn, flakExplosion, blastExplosion, + hitBulletBig, hitFlameSmall, hitLiquid, hitLaser, hitYellowLaser, hitLancer, hitMeltdown, despawn, flakExplosion, blastExplosion, plasticExplosion, artilleryTrail, incendTrail, missileTrail, absorb, flakExplosionBig, plasticExplosionFlak, burning, fire, fireSmoke, steam, fireballsmoke, ballfire, freezing, melting, wet, oily, overdriven, dropItem, shockwave, - bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke, shootSmall, shootHeal, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke, + bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke, shootSmall, shootHeal, shootHealYellow, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke, shootBigSmoke2, shootSmallFlame, shootPyraFlame, shootLiquid, shellEjectSmall, shellEjectMedium, shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot, unitSpawn, spawnShockwave, magmasmoke, impactShockwave, impactcloud, impactsmoke, dynamicExplosion, padlaunch, commandSend, coreLand; @@ -158,7 +158,6 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, 2f + e.finpow() * 7f); }); - hitBulletSmall = new Effect(14, e -> { Draw.color(Color.white, Pal.lightOrange, e.fin()); @@ -254,6 +253,13 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, e.fin() * 5f); }); + hitYellowLaser = new Effect(8, e -> { + Draw.color(Color.white, Pal.lightTrail, e.fin()); + Lines.stroke(0.5f + e.fout()); + Lines.circle(e.x, e.y, e.fin() * 5f); + Draw.reset(); + }); + despawn = new Effect(12, e -> { Draw.color(Pal.lighterOrange, Color.gray, e.fin()); Lines.stroke(e.fout()); @@ -635,6 +641,14 @@ public class Fx implements ContentList{ Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f); }); + shootHealYellow = new Effect(8, e -> { + Draw.color(Pal.lightTrail); + float w = 1f + 5 * e.fout(); + Drawf.tri(e.x, e.y, w, 17f * e.fout(), e.rotation); + Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f); + Draw.reset(); + }); + shootSmallSmoke = new Effect(20f, e -> { Draw.color(Pal.lighterOrange, Color.lightGray, Color.gray, e.fin()); @@ -774,9 +788,9 @@ public class Fx implements ContentList{ }); lancerLaserShootSmoke = new Effect(26f, e -> { - Draw.color(Pal.lancerLaser); + Draw.color(Color.white); - Angles.randLenVectors(e.id, 7, 80f, e.rotation, 0f, (x, y) -> { + Angles.randLenVectors(e.id, 7, 70f, e.rotation, 0f, (x, y) -> { Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f); }); @@ -791,7 +805,7 @@ public class Fx implements ContentList{ }); - lancerLaserChargeBegin = new Effect(71f, e -> { + lancerLaserChargeBegin = new Effect(60f, e -> { Draw.color(Pal.lancerLaser); Fill.circle(e.x, e.y, e.fin() * 3f); diff --git a/core/src/mindustry/content/Mechs.java b/core/src/mindustry/content/Mechs.java index 9bbb67d51a..31cd76a4ad 100644 --- a/core/src/mindustry/content/Mechs.java +++ b/core/src/mindustry/content/Mechs.java @@ -6,7 +6,7 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.util.*; import mindustry.*; -import mindustry.ctype.ContentList; +import mindustry.ctype.*; import mindustry.entities.*; import mindustry.entities.bullet.*; import mindustry.entities.effect.*; @@ -15,15 +15,115 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; -public class Mechs implements ContentList{ - public static Mech alpha, delta, tau, omega, dart, javelin, trident, glaive; +import static mindustry.Vars.indexer; - public static Mech starter; +public class Mechs implements ContentList{ + public static UnitDef vanguard, alpha, delta, tau, omega, dart, javelin, trident, glaive; + + public static UnitDef starter; @Override public void load(){ - alpha = new Mech("alpha-mech", false){ + vanguard = new UnitDef("vanguard-ship"){ + float healRange = 60f; + float healReload = 200f; + float healPercent = 10f; + + { + flying = true; + drillTier = 1; + minePower = 4f; + speed = 0.49f; + drag = 0.09f; + health = 200f; + weaponOffsetX = -1; + engineSize = 2.3f; + weaponOffsetY = -1; + engineColor = Pal.lightTrail; + cellTrnsY = 1f; + buildPower = 1.2f; + weapon = new Weapon("vanguard-blaster"){{ + length = 1.5f; + reload = 30f; + alternate = true; + inaccuracy = 6f; + velocityRnd = 0.1f; + ejectEffect = Fx.none; + bullet = new HealBulletType(){{ + healPercent = 3f; + backColor = engineColor; + homingPower = 20f; + bulletHeight = 4f; + bulletWidth = 1.5f; + damage = 3f; + speed = 4f; + lifetime = 40f; + shootEffect = Fx.shootHealYellow; + smokeEffect = hitEffect = despawnEffect = Fx.hitYellowLaser; + }}; + }}; + } + + @Override + public boolean alwaysUnlocked(){ + return true; + } + + @Override + public void update(Player player){ + if(player.timer.get(Player.timerAbility, healReload)){ + if(indexer.eachBlock(player, healRange, other -> other.entity.damaged(), other -> { + other.entity.healBy(other.entity.maxHealth() * healPercent / 100f); + Effects.effect(Fx.healBlockFull, Pal.heal, other.drawx(), other.drawy(), other.block().size); + })){ + Effects.effect(Fx.healWave, player); + } + } + } + }; + + alpha = new UnitDef("alpha-mech", false){ + { + drillTier = -1; + speed = 0.5f; + boostSpeed = 0.95f; + itemCapacity = 15; + mass = 0.9f; + health = 150f; + buildPower = 0.9f; + weaponOffsetX = 1; + weaponOffsetY = -1; + engineColor = Pal.heal; + + weapon = new Weapon("shockgun"){{ + shake = 2f; + length = 0.5f; + reload = 70f; + alternate = true; + recoil = 4f; + width = 5f; + shootSound = Sounds.laser; + + bullet = new LaserBulletType(){{ + damage = 20f; + recoil = 1f; + sideAngle = 45f; + sideWidth = 1f; + sideLength = 70f; + colors = new Color[]{Pal.heal.cpy().a(0.4f), Pal.heal, Color.white}; + }}; + }}; + } + + @Override + public void update(Player player){ + player.healBy(Time.delta() * 0.09f); + } + + }; + + delta = new UnitDef("delta-mech", false){ { drillPower = 1; mineSpeed = 1.5f; @@ -34,65 +134,26 @@ public class Mechs implements ContentList{ buildPower = 1.2f; engineColor = Color.valueOf("ffd37f"); health = 250f; + weaponOffsetX = 4f; - weapon = new Weapon("blaster"){{ + weapon = new Weapon("flamethrower"){{ length = 1.5f; - reload = 14f; + reload = 30f; + width = 4f; alternate = true; - ejectEffect = Fx.shellEjectSmall; - bullet = Bullets.standardMechSmall; - }}; - } - - @Override - public void updateAlt(Player player){ - player.healBy(Time.delta() * 0.09f); - } - - }; - - delta = new Mech("delta-mech", false){ - float cooldown = 120; - - { - drillPower = -1; - speed = 0.75f; - boostSpeed = 0.95f; - itemCapacity = 15; - mass = 0.9f; - health = 150f; - buildPower = 0.9f; - weaponOffsetX = -1; - weaponOffsetY = -1; - engineColor = Color.valueOf("d3ddff"); - - weapon = new Weapon("shockgun"){{ - shake = 2f; - length = 1f; - reload = 55f; - shotDelay = 3f; - alternate = true; - shots = 2; - inaccuracy = 0f; - ejectEffect = Fx.none; - bullet = Bullets.lightning; + shots = 3; + inaccuracy = 40f; shootSound = Sounds.spark; + bullet = new LightningBulletType(){{ + damage = 5; + lightningLength = 10; + lightningColor = Pal.lightFlame; + }}; }}; } - - @Override - public void onLand(Player player){ - if(player.timer.get(Player.timerAbility, cooldown)){ - Effects.shake(1f, 1f, player); - Effects.effect(Fx.landShock, player); - for(int i = 0; i < 8; i++){ - Time.run(Mathf.random(8f), () -> Lightning.create(player.getTeam(), Pal.lancerLaser, 17f * Vars.state.rules.playerDamageMultiplier, player.x, player.y, Mathf.random(360f), 14)); - } - } - } }; - tau = new Mech("tau-mech", false){ + tau = new UnitDef("tau-mech", false){ float healRange = 60f; float healAmount = 10f; float healReload = 160f; @@ -125,7 +186,7 @@ public class Mechs implements ContentList{ } @Override - public void updateAlt(Player player){ + public void update(Player player){ if(player.timer.get(Player.timerAbility, healReload)){ wasHealed = false; @@ -145,7 +206,7 @@ public class Mechs implements ContentList{ } }; - omega = new Mech("omega-mech", false){ + omega = new UnitDef("omega-mech", false){ protected TextureRegion armorRegion; { @@ -193,7 +254,7 @@ public class Mechs implements ContentList{ } @Override - public void updateAlt(Player player){ + public void update(Player player){ float scl = 1f - player.shootHeat / 2f*Time.delta(); player.velocity().scl(scl); } @@ -217,10 +278,15 @@ public class Mechs implements ContentList{ } }; - dart = new Mech("dart-ship", true){ + dart = new UnitDef("dart-ship"){ + float effectRange = 60f; + float effectReload = 60f * 5; + float effectDuration = 60f * 10f; + { + flying = true; drillPower = 1; - mineSpeed = 3f; + mineSpeed = 2f; speed = 0.5f; drag = 0.09f; health = 200f; @@ -239,17 +305,32 @@ public class Mechs implements ContentList{ } @Override - public boolean alwaysUnlocked(){ - return true; + public void update(Player player){ + super.update(player); + + if(player.timer.get(Player.timerAbility, effectReload)){ + + Units.nearby(player.getTeam(), player.x, player.y, effectRange, unit -> { + //unit.applyEffect(StatusEffects.overdrive, effectDuration); + }); + + indexer.eachBlock(player, effectRange, other -> other.entity.damaged(), other -> { + other.entity.applyBoost(1.5f, effectDuration); + Effects.effect(Fx.healBlockFull, Pal.heal, other.drawx(), other.drawy(), other.block().size); + }); + + Effects.effect(Fx.overdriveWave, player); + } } }; - javelin = new Mech("javelin-ship", true){ + javelin = new UnitDef("javelin-ship"){ float minV = 3.6f; float maxV = 6f; TextureRegion shield; { + flying = true; drillPower = -1; speed = 0.11f; drag = 0.01f; @@ -283,7 +364,7 @@ public class Mechs implements ContentList{ } @Override - public void updateAlt(Player player){ + public void update(Player player){ float scl = scld(player); if(Mathf.chance(Time.delta() * (0.15 * scl))){ Effects.effect(Fx.hitLancer, Pal.lancerLaser, player.x, player.y); @@ -308,8 +389,9 @@ public class Mechs implements ContentList{ } }; - trident = new Mech("trident-ship", true){ + trident = new UnitDef("trident-ship"){ { + flying = true; drillPower = 2; speed = 0.15f; drag = 0.034f; @@ -349,8 +431,9 @@ public class Mechs implements ContentList{ } }; - glaive = new Mech("glaive-ship", true){ + glaive = new UnitDef("glaive-ship"){ { + flying = true; drillPower = 4; mineSpeed = 1.3f; speed = 0.32f; @@ -373,6 +456,6 @@ public class Mechs implements ContentList{ } }; - starter = dart; + starter = vanguard; } } diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 5159f8e7c5..9c97dc9475 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -8,14 +8,14 @@ import mindustry.gen.*; import mindustry.type.*; public class UnitTypes implements ContentList{ - public static UnitType + public static UnitDef draug, spirit, phantom, wraith, ghoul, revenant, lich, reaper, dagger, crawler, titan, fortress, eruptor, chaosArray, eradicator; @Override public void load(){ - draug = new UnitType("draug", MinerDrone::new){{ + draug = new UnitDef("draug", MinerDrone::new){{ flying = true; drag = 0.01f; speed = 0.3f; @@ -25,12 +25,9 @@ public class UnitTypes implements ContentList{ minePower = 0.9f; engineSize = 1.8f; engineOffset = 5.7f; - weapon = new Weapon("you have incurred my wrath. prepare to die."){{ - bullet = Bullets.lancerLaser; - }}; }}; - spirit = new UnitType("spirit", RepairDrone::new){{ + spirit = new UnitDef("spirit", RepairDrone::new){{ flying = true; drag = 0.01f; speed = 0.42f; @@ -51,7 +48,7 @@ public class UnitTypes implements ContentList{ }}; }}; - phantom = new UnitType("phantom", BuilderDrone::new){{ + phantom = new UnitDef("phantom", BuilderDrone::new){{ flying = true; drag = 0.01f; mass = 2f; @@ -74,7 +71,7 @@ public class UnitTypes implements ContentList{ }}; }}; - dagger = new UnitType("dagger", GroundUnit::new){{ + dagger = new UnitDef("dagger", GroundUnit::new){{ maxVelocity = 1.1f; speed = 0.2f; drag = 0.4f; @@ -90,7 +87,7 @@ public class UnitTypes implements ContentList{ }}; }}; - crawler = new UnitType("crawler", GroundUnit::new){{ + crawler = new UnitDef("crawler", GroundUnit::new){{ maxVelocity = 1.27f; speed = 0.285f; drag = 0.4f; @@ -113,7 +110,7 @@ public class UnitTypes implements ContentList{ }}; }}; - titan = new UnitType("titan", GroundUnit::new){{ + titan = new UnitDef("titan", GroundUnit::new){{ maxVelocity = 0.8f; speed = 0.22f; drag = 0.4f; @@ -134,7 +131,7 @@ public class UnitTypes implements ContentList{ }}; }}; - fortress = new UnitType("fortress", GroundUnit::new){{ + fortress = new UnitDef("fortress", GroundUnit::new){{ maxVelocity = 0.78f; speed = 0.15f; drag = 0.4f; @@ -156,7 +153,7 @@ public class UnitTypes implements ContentList{ }}; }}; - eruptor = new UnitType("eruptor", GroundUnit::new){{ + eruptor = new UnitDef("eruptor", GroundUnit::new){{ maxVelocity = 0.81f; speed = 0.16f; drag = 0.4f; @@ -178,7 +175,7 @@ public class UnitTypes implements ContentList{ }}; }}; - chaosArray = new UnitType("chaos-array", GroundUnit::new){{ + chaosArray = new UnitDef("chaos-array", GroundUnit::new){{ maxVelocity = 0.68f; speed = 0.12f; drag = 0.4f; @@ -202,7 +199,7 @@ public class UnitTypes implements ContentList{ }}; }}; - eradicator = new UnitType("eradicator", GroundUnit::new){{ + eradicator = new UnitDef("eradicator", GroundUnit::new){{ maxVelocity = 0.68f; speed = 0.12f; drag = 0.4f; @@ -227,7 +224,7 @@ public class UnitTypes implements ContentList{ }}; }}; - wraith = new UnitType("wraith", FlyingUnit::new){{ + wraith = new UnitDef("wraith", FlyingUnit::new){{ speed = 0.3f; maxVelocity = 1.9f; drag = 0.01f; @@ -246,7 +243,7 @@ public class UnitTypes implements ContentList{ }}; }}; - ghoul = new UnitType("ghoul", FlyingUnit::new){{ + ghoul = new UnitDef("ghoul", FlyingUnit::new){{ health = 220; speed = 0.2f; maxVelocity = 1.4f; @@ -270,7 +267,7 @@ public class UnitTypes implements ContentList{ }}; }}; - revenant = new UnitType("revenant", HoverUnit::new){{ + revenant = new UnitDef("revenant", HoverUnit::new){{ health = 1000; mass = 5f; hitsize = 20f; @@ -301,7 +298,7 @@ public class UnitTypes implements ContentList{ }}; }}; - lich = new UnitType("lich", HoverUnit::new){{ + lich = new UnitDef("lich", HoverUnit::new){{ health = 6000; mass = 20f; hitsize = 40f; @@ -334,7 +331,7 @@ public class UnitTypes implements ContentList{ }}; }}; - reaper = new UnitType("reaper", HoverUnit::new){{ + reaper = new UnitDef("reaper", HoverUnit::new){{ health = 11000; mass = 30f; hitsize = 56f; diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index 5261560399..3e23ac146d 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -11,7 +11,7 @@ import mindustry.ui.Cicon; /** Base interface for an unlockable content type. */ public abstract class UnlockableContent extends MappableContent{ - /** Localized, formal name. Never null. Set to block name if not found in bundle. */ + /** Localized, formal name. Never null. Set to internal name if not found in bundle. */ public String localizedName; /** Localized description. May be null. */ public @Nullable String description; diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java index 8e197bf42e..ba931a54cd 100644 --- a/core/src/mindustry/editor/EditorTool.java +++ b/core/src/mindustry/editor/EditorTool.java @@ -166,33 +166,42 @@ public enum EditorTool{ stack.clear(); stack.add(Pos.get(x, y)); - while(stack.size > 0){ - int popped = stack.pop(); - x = Pos.x(popped); - y = Pos.y(popped); + try{ + while(stack.size > 0 && stack.size < width*height){ + int popped = stack.pop(); + x = Pos.x(popped); + y = Pos.y(popped); - x1 = x; - while(x1 >= 0 && tester.get(editor.tile(x1, y))) x1--; - x1++; - boolean spanAbove = false, spanBelow = false; - while(x1 < width && tester.get(editor.tile(x1, y))){ - filler.get(editor.tile(x1, y)); - - if(!spanAbove && y > 0 && tester.get(editor.tile(x1, y - 1))){ - stack.add(Pos.get(x1, y - 1)); - spanAbove = true; - }else if(spanAbove && !tester.get(editor.tile(x1, y - 1))){ - spanAbove = false; - } - - if(!spanBelow && y < height - 1 && tester.get(editor.tile(x1, y + 1))){ - stack.add(Pos.get(x1, y + 1)); - spanBelow = true; - }else if(spanBelow && y < height - 1 && !tester.get(editor.tile(x1, y + 1))){ - spanBelow = false; - } + x1 = x; + while(x1 >= 0 && tester.get(editor.tile(x1, y))) x1--; x1++; + boolean spanAbove = false, spanBelow = false; + while(x1 < width && tester.get(editor.tile(x1, y))){ + filler.get(editor.tile(x1, y)); + + if(!spanAbove && y > 0 && tester.get(editor.tile(x1, y - 1))){ + stack.add(Pos.get(x1, y - 1)); + spanAbove = true; + }else if(spanAbove && !tester.get(editor.tile(x1, y - 1))){ + spanAbove = false; + } + + if(!spanBelow && y < height - 1 && tester.get(editor.tile(x1, y + 1))){ + stack.add(Pos.get(x1, y + 1)); + spanBelow = true; + }else if(spanBelow && y < height - 1 && !tester.get(editor.tile(x1, y + 1))){ + spanBelow = false; + } + x1++; + } } + stack.clear(); + }catch(OutOfMemoryError e){ + //hack + stack = null; + System.gc(); + e.printStackTrace(); + stack = new IntArray(); } } } diff --git a/core/src/mindustry/entities/EntityCollisions.java b/core/src/mindustry/entities/EntityCollisions.java index 72e177d71e..1130b3f5d3 100644 --- a/core/src/mindustry/entities/EntityCollisions.java +++ b/core/src/mindustry/entities/EntityCollisions.java @@ -4,7 +4,6 @@ import arc.struct.Array; import arc.math.Mathf; import arc.math.geom.*; import mindustry.entities.traits.Entity; -import mindustry.entities.traits.SolidTrait; import mindustry.world.Tile; import static mindustry.Vars.tilesize; diff --git a/core/src/mindustry/entities/bullet/HealBulletType.java b/core/src/mindustry/entities/bullet/HealBulletType.java index 4ff0b9fefd..36ce31d254 100644 --- a/core/src/mindustry/entities/bullet/HealBulletType.java +++ b/core/src/mindustry/entities/bullet/HealBulletType.java @@ -11,6 +11,8 @@ import mindustry.world.blocks.*; public class HealBulletType extends BulletType{ protected float healPercent = 3f; + protected float bulletHeight = 7f, bulletWidth = 2f; + protected Color backColor = Pal.heal, frontColor = Color.white; public HealBulletType(float speed, float damage){ super(speed, damage); @@ -33,11 +35,11 @@ public class HealBulletType extends BulletType{ @Override public void draw(Bullet b){ - Draw.color(Pal.heal); - Lines.stroke(2f); - Lines.lineAngleCenter(b.x, b.y, b.rot(), 7f); - Draw.color(Color.white); - Lines.lineAngleCenter(b.x, b.y, b.rot(), 3f); + Draw.color(backColor); + Lines.stroke(bulletWidth); + Lines.lineAngleCenter(b.x, b.y, b.rot(), bulletHeight); + Draw.color(frontColor); + Lines.lineAngleCenter(b.x, b.y, b.rot(), bulletHeight / 2f); Draw.reset(); } diff --git a/core/src/mindustry/entities/bullet/LaserBulletType.java b/core/src/mindustry/entities/bullet/LaserBulletType.java new file mode 100644 index 0000000000..72358543cf --- /dev/null +++ b/core/src/mindustry/entities/bullet/LaserBulletType.java @@ -0,0 +1,73 @@ +package mindustry.entities.bullet; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.entities.type.*; +import mindustry.graphics.*; + +public class LaserBulletType extends BulletType{ + protected Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white}; + protected float length = 160f; + protected float width = 15f; + protected float lengthFalloff = 0.5f; + protected float sideLength = 29f, sideWidth = 0.7f; + protected float sideAngle = 90f; + + public LaserBulletType(float damage){ + super(0.01f, damage); + + keepVelocity = false; + hitEffect = Fx.hitLancer; + despawnEffect = Fx.none; + shootEffect = Fx.hitLancer; + smokeEffect = Fx.lancerLaserShootSmoke; + hitSize = 4; + lifetime = 16f; + pierce = true; + } + + public LaserBulletType(){ + this(1f); + } + + @Override + public float range(){ + return length; + } + + @Override + public void init(Bullet b){ + Damage.collideLine(b, b.getTeam(), hitEffect, b.x, b.y, b.rot(), length); + } + + @Override + public void draw(Bullet b){ + float f = Mathf.curve(b.fin(), 0f, 0.2f); + float baseLen = length * f; + float cwidth = width; + float compound = 1f; + + Lines.lineAngle(b.x, b.y, b.rot(), baseLen); + Lines.precise(true); + for(Color color : colors){ + Draw.color(color); + Lines.stroke((cwidth *= lengthFalloff) * b.fout()); + Lines.lineAngle(b.x, b.y, b.rot(), baseLen, CapStyle.none); + Tmp.v1.trns(b.rot(), baseLen); + Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, Lines.getStroke() * 1.22f, cwidth * 2f + width / 2f, b.rot()); + + Fill.circle(b.x, b.y, 1f * cwidth * b.fout()); + for(int i : Mathf.signs){ + Drawf.tri(b.x, b.y, sideWidth * b.fout() * cwidth, sideLength * compound, b.rot() + sideAngle * i); + } + + compound *= lengthFalloff; + } + Lines.precise(false); + Draw.reset(); + } +} diff --git a/core/src/mindustry/entities/bullet/LightningBulletType.java b/core/src/mindustry/entities/bullet/LightningBulletType.java new file mode 100644 index 0000000000..3edbed8b96 --- /dev/null +++ b/core/src/mindustry/entities/bullet/LightningBulletType.java @@ -0,0 +1,30 @@ +package mindustry.entities.bullet; + +import arc.graphics.*; +import mindustry.content.*; +import mindustry.entities.effect.*; +import mindustry.entities.type.*; +import mindustry.graphics.*; + +public class LightningBulletType extends BulletType{ + protected Color lightningColor = Pal.lancerLaser; + protected int lightningLength = 25; + + public LightningBulletType(){ + super(0.0001f, 1f); + + lifetime = 1; + despawnEffect = Fx.none; + hitEffect = Fx.hitLancer; + keepVelocity = false; + } + + @Override + public void draw(Bullet b){ + } + + @Override + public void init(Bullet b){ + Lightning.create(b.getTeam(), lightningColor, damage, b.x, b.y, b.rot(), lightningLength); + } +} diff --git a/core/src/mindustry/entities/def/EntityComps.java b/core/src/mindustry/entities/def/EntityComps.java index 9264be9f6c..fb5a58309e 100644 --- a/core/src/mindustry/entities/def/EntityComps.java +++ b/core/src/mindustry/entities/def/EntityComps.java @@ -1,16 +1,22 @@ package mindustry.entities.def; import arc.graphics.*; +import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.struct.Bits; import arc.struct.*; import arc.util.*; import arc.util.pooling.*; +import mindustry.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.ctype.*; +import mindustry.entities.*; +import mindustry.entities.Effects.*; import mindustry.entities.bullet.*; +import mindustry.entities.traits.*; +import mindustry.entities.type.*; import mindustry.entities.units.*; import mindustry.game.*; import mindustry.gen.*; @@ -23,19 +29,23 @@ import static mindustry.Vars.content; public class EntityComps{ - @Depends({HealthComp.class, VelComp.class, StatusComp.class, TeamComp.class, ItemsComp.class}) + @Component({HealthComp.class, VelComp.class, StatusComp.class, TeamComp.class, ItemsComp.class}) class UnitComp{ - //UnitDef type; + UnitDef type; } class OwnerComp{ Entityc owner; } - @Depends({TimedComp.class}) + @Component({TimedComp.class, DamageComp.class, Hitboxc.class}) class BulletComp{ BulletType bullet; + float getDamage(){ + return bullet.damage; + } + void init(){ //TODO bullet.init(null); @@ -47,6 +57,12 @@ public class EntityComps{ } } + @Component + abstract class DamageComp{ + abstract float getDamage(); + } + + @Component abstract class TimedComp extends EntityComp implements Scaled{ float time, lifetime; @@ -64,79 +80,339 @@ public class EntityComps{ } } + @Component class HealthComp{ - float health, maxHealth; + float health, maxHealth, hitTime; boolean dead; float healthf(){ return health / maxHealth; } + + void update(){ + hitTime -= Time.delta() / 9f; + } + + void killed(){ + //implement by other components + } + + void kill(){ + health = 0; + dead = true; + } + + void heal(){ + dead = false; + health = maxHealth; + } + + boolean damaged(){ + return health <= maxHealth - 0.0001f; + } + + void damage(float amount){ + health -= amount; + if(health <= 0 && !dead){ + dead = true; + killed(); + } + } + + void clampHealth(){ + health = Mathf.clamp(health, 0, maxHealth); + } + + void heal(float amount){ + health += amount; + clampHealth(); + } } + @Component class FlyingComp{ boolean flying; } + @Component class LegsComp{ - + float baseRotation; + float drownTime; } + @Component class RotComp{ float rotation; } + @Component class TeamComp{ Team team = Team.sharded; } - @Depends(PosComp.class) - class SyncComp{ - Interpolator interpolator; + @Component({RotComp.class, PosComp.class}) + static class WeaponsComp{ + transient float x, y, rotation; + + /** 1 */ + static final int[] one = {1}; + /** minimum cursor distance from player, fixes 'cross-eyed' shooting */ + static final float minAimDst = 20f; + /** temporary weapon sequence number */ + static int sequenceNum = 0; + + /** weapon mount array, never null */ + WeaponMount[] mounts = {}; + + public void init(UnitDef def){ + mounts = new WeaponMount[def.weapons.size]; + for(int i = 0; i < mounts.length; i++){ + mounts[i] = new WeaponMount(def.weapons.get(i)); + } + } + + /** Aim at something. This will make all mounts point at it. */ + public void aim(Unit unit, float x, float y){ + Tmp.v1.set(x, y).sub(unit.x, unit.y); + if(Tmp.v1.len() < minAimDst) Tmp.v1.setLength(minAimDst); + + x = Tmp.v1.x + unit.x; + y = Tmp.v1.y + unit.y; + + for(WeaponMount mount : mounts){ + mount.aimX = x; + mount.aimY = y; + } + } + + /** Update shooting and rotation for this unit. */ + public void update(Unit unit){ + for(WeaponMount mount : mounts){ + Weapon weapon = mount.weapon; + mount.reload -= Time.delta(); + + float rotation = unit.rotation - 90; + + //rotate if applicable + if(weapon.rotate){ + float axisXOffset = weapon.mirror ? 0f : weapon.x; + float axisX = unit.x + Angles.trnsx(rotation, axisXOffset, weapon.y), + axisY = unit.y + Angles.trnsy(rotation, axisXOffset, weapon.y); + + mount.rotation = Angles.moveToward(mount.rotation, Angles.angle(axisX, axisY, mount.aimX, mount.aimY), weapon.rotateSpeed); + } + + //shoot if applicable + //TODO only shoot if angle is reached, don't shoot inaccurately + if(mount.reload <= 0){ + for(int i : (weapon.mirror && !weapon.alternate ? Mathf.signs : one)){ + i *= Mathf.sign(weapon.flipped) * Mathf.sign(mount.side); + + //m a t h + float weaponRotation = rotation + (weapon.rotate ? mount.rotation : 0); + float mountX = unit.x + Angles.trnsx(rotation, weapon.x * i, weapon.y), + mountY = unit.y + Angles.trnsy(rotation, weapon.x * i, weapon.y); + float shootX = mountX + Angles.trnsx(weaponRotation, weapon.shootX * i, weapon.shootY), + shootY = mountY + Angles.trnsy(weaponRotation, weapon.shootX * i, weapon.shootY); + float shootAngle = weapon.rotate ? weaponRotation : Angles.angle(shootX, shootY, mount.aimX, mount.aimY); + + shoot(unit, weapon, shootX, shootY, shootAngle); + } + + mount.side = !mount.side; + mount.reload = weapon.reload; + } + } + } + + /** Draw weapon mounts. */ + void draw(){ + for(WeaponMount mount : mounts){ + Weapon weapon = mount.weapon; + + for(int i : (weapon.mirror ? Mathf.signs : one)){ + i *= Mathf.sign(weapon.flipped); + + float rotation = this.rotation - 90 + (weapon.rotate ? mount.rotation : 0); + float trY = weapon.y - (mount.reload / weapon.reload * weapon.recoil) * (weapon.alternate ? Mathf.num(i == Mathf.sign(mount.side)) : 1); + float width = i > 0 ? -weapon.region.getWidth() : weapon.region.getWidth(); + + Draw.rect(weapon.region, + x + Angles.trnsx(rotation, weapon.x * i, trY), + y + Angles.trnsy(rotation, weapon.x * i, trY), + width * Draw.scl, + weapon.region.getHeight() * Draw.scl, + rotation - 90); + } + } + } + + private void shoot(ShooterTrait shooter, Weapon weapon, float x, float y, float rotation){ + float baseX = shooter.getX(), baseY = shooter.getY(); + + weapon.shootSound.at(x, y, Mathf.random(0.8f, 1.0f)); + + sequenceNum = 0; + if(weapon.shotDelay > 0.01f){ + Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> { + Time.run(sequenceNum * weapon.shotDelay, () -> bullet(shooter, weapon, x + shooter.getX() - baseX, y + shooter.getY() - baseY, f + Mathf.range(weapon.inaccuracy))); + sequenceNum++; + }); + }else{ + Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> bullet(shooter, weapon, x, y, f + Mathf.range(weapon.inaccuracy))); + } + + BulletType ammo = weapon.bullet; + + Tmp.v1.trns(rotation + 180f, ammo.recoil); + + shooter.velocity().add(Tmp.v1); + + Tmp.v1.trns(rotation, 3f); + boolean parentize = ammo.keepVelocity; + + Effects.shake(weapon.shake, weapon.shake, x, y); + Effects.effect(weapon.ejectEffect, x, y, rotation); + Effects.effect(ammo.shootEffect, x + Tmp.v1.x, y + Tmp.v1.y, rotation, parentize ? shooter : null); + Effects.effect(ammo.smokeEffect, x + Tmp.v1.x, y + Tmp.v1.y, rotation, parentize ? shooter : null); + } + + private void bullet(ShooterTrait owner, Weapon weapon, float x, float y, float angle){ + Tmp.v1.trns(angle, 3f); + Bullet.create(weapon.bullet, owner, owner.getTeam(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd)); + } } - abstract class PosComp implements Position{ + @Component + abstract class DrawComp{ + //TODO ponder. + + abstract float drawSize(); + + void draw(){ + + } + } + + @Component(PosComp.class) + abstract class SyncComp extends PosComp{ + Interpolator interpolator = new Interpolator(); + + void setNet(float x, float y){ + set(x, y); + + //TODO change interpolator API + if(interpolator != null){ + interpolator.target.set(x, y); + interpolator.last.set(x, y); + interpolator.pos.set(0, 0); + interpolator.updateSpacing = 16; + interpolator.lastUpdated = 0; + } + } + + void update(){ + if(Vars.net.client() && !isLocal()){ + interpolate(); + } + } + + void interpolate(){ + interpolator.update(); + x = interpolator.pos.x; + y = interpolator.pos.y; + } + } + + @Component + abstract class PosComp extends EntityComp implements Position{ float x, y; void set(float x, float y){ this.x = x; this.y = y; } + + void trns(float x, float y){ + set(this.x + x, this.y + y); + } } - abstract class DamageComp{ - abstract float getDamage(); - } - + @Component class MinerComp{ } + @Component class BuilderComp{ } + @Component class ItemsComp{ ItemStack item = new ItemStack(); } - @Depends(PosComp.class) - class VelComp{ - transient float x, y; + @Component(VelComp.class) + class MassComp{ + float mass; + } + @Component({PosComp.class, DrawComp.class, TimedComp.class}) + class EffectComp extends EntityComp{ + Effect effect; + Color color = new Color(Color.white); + Object data; + float rotation = 0f; + + void draw(){ + + } + + void update(){ + //TODO fix effects, make everything poolable + } + } + + @Component + abstract class VelComp extends PosComp{ final Vec2 vel = new Vec2(); + float drag = 0f; void update(){ x += vel.x; y += vel.y; - vel.scl(0.9f); + vel.scl(1f - drag * Time.delta()); } } - @Depends(PosComp.class) + @Component(PosComp.class) class HitboxComp{ transient float x, y; float hitSize; + float lastX, lastY; + + void update(){ + + } + + void updateLastPosition(){ + lastX = x; + lastY = y; + } + + void collision(Hitboxc other){ + + } + + float getDeltaX(){ + return x - lastX; + } + + float getDeltaY(){ + return y - lastY; + } boolean collides(Hitboxc other){ return Intersector.overlapsRect(x - hitSize/2f, y - hitSize/2f, hitSize, hitSize, @@ -144,7 +420,7 @@ public class EntityComps{ } } - @Depends(PosComp.class) + @Component(PosComp.class) class StatusComp{ private Array statuses = new Array<>(); private Bits applied = new Bits(content.getBy(ContentType.status).size); @@ -258,6 +534,7 @@ public class EntityComps{ } } + @Component @BaseComponent class EntityComp{ int id; @@ -268,6 +545,11 @@ public class EntityComps{ void remove(){} + boolean isLocal(){ + //TODO fix + return this == (Object)Vars.player; + } + T as(Class type){ return (T)this; } diff --git a/core/src/mindustry/entities/effect/Decal.java b/core/src/mindustry/entities/effect/Decal.java index cbe0e8edb2..bc63493c6a 100644 --- a/core/src/mindustry/entities/effect/Decal.java +++ b/core/src/mindustry/entities/effect/Decal.java @@ -5,7 +5,6 @@ import arc.math.Mathf; import mindustry.entities.EntityGroup; import mindustry.entities.type.TimedEntity; import mindustry.entities.traits.BelowLiquidTrait; -import mindustry.entities.traits.DrawTrait; import mindustry.graphics.Pal; import static mindustry.Vars.groundEffectGroup; diff --git a/core/src/mindustry/entities/effect/ItemTransfer.java b/core/src/mindustry/entities/effect/ItemTransfer.java index 2018d15a69..cacb8e267e 100644 --- a/core/src/mindustry/entities/effect/ItemTransfer.java +++ b/core/src/mindustry/entities/effect/ItemTransfer.java @@ -11,7 +11,6 @@ import arc.util.Time; import arc.util.pooling.Pools; import mindustry.entities.*; import mindustry.entities.type.TimedEntity; -import mindustry.entities.traits.DrawTrait; import mindustry.entities.type.Unit; import mindustry.graphics.Pal; import mindustry.type.Item; diff --git a/core/src/mindustry/entities/effect/Lightning.java b/core/src/mindustry/entities/effect/Lightning.java index e4658cd1ff..9a1e51d0a3 100644 --- a/core/src/mindustry/entities/effect/Lightning.java +++ b/core/src/mindustry/entities/effect/Lightning.java @@ -14,8 +14,6 @@ import mindustry.entities.EntityGroup; import mindustry.entities.Units; import mindustry.entities.type.Bullet; import mindustry.entities.type.TimedEntity; -import mindustry.entities.traits.DrawTrait; -import mindustry.entities.traits.TimeTrait; import mindustry.entities.type.Unit; import mindustry.game.Team; import mindustry.gen.Call; diff --git a/core/src/mindustry/entities/traits/BuilderTrait.java b/core/src/mindustry/entities/traits/BuilderTrait.java index a05fc685ec..570f5eabf9 100644 --- a/core/src/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/mindustry/entities/traits/BuilderTrait.java @@ -67,9 +67,9 @@ public interface BuilderTrait extends Entity, TeamTrait{ if(!(tile.block() instanceof BuildBlock)){ if(!current.initialized && canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){ - Call.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation); + Build.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation); }else if(!current.initialized && canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){ - Call.beginBreak(getTeam(), current.x, current.y); + Build.beginBreak(getTeam(), current.x, current.y); }else{ buildQueue().removeFirst(); return; diff --git a/core/src/mindustry/entities/traits/DamageTrait.java b/core/src/mindustry/entities/traits/DamageTrait.java deleted file mode 100644 index 13feb85e6e..0000000000 --- a/core/src/mindustry/entities/traits/DamageTrait.java +++ /dev/null @@ -1,9 +0,0 @@ -package mindustry.entities.traits; - -public interface DamageTrait{ - float damage(); - - default void killed(Entity other){ - - } -} diff --git a/core/src/mindustry/entities/traits/DrawTrait.java b/core/src/mindustry/entities/traits/DrawTrait.java deleted file mode 100644 index 472b582c75..0000000000 --- a/core/src/mindustry/entities/traits/DrawTrait.java +++ /dev/null @@ -1,10 +0,0 @@ -package mindustry.entities.traits; - -public interface DrawTrait extends Entity{ - - default float drawSize(){ - return 20f; - } - - void draw(); -} diff --git a/core/src/mindustry/entities/traits/Entity.java b/core/src/mindustry/entities/traits/Entity.java index 5b0416b69f..6e545aa962 100644 --- a/core/src/mindustry/entities/traits/Entity.java +++ b/core/src/mindustry/entities/traits/Entity.java @@ -1,6 +1,7 @@ package mindustry.entities.traits; -import mindustry.entities.EntityGroup; +import mindustry.*; +import mindustry.entities.*; public interface Entity extends MoveTrait{ @@ -14,6 +15,14 @@ public interface Entity extends MoveTrait{ default void added(){} + default int tileX(){ + return Vars.world.toTile(getX()); + } + + default int tileY(){ + return Vars.world.toTile(getY()); + } + EntityGroup targetGroup(); @SuppressWarnings("unchecked") diff --git a/core/src/mindustry/entities/traits/HealthTrait.java b/core/src/mindustry/entities/traits/HealthTrait.java deleted file mode 100644 index 8eb4cff2bd..0000000000 --- a/core/src/mindustry/entities/traits/HealthTrait.java +++ /dev/null @@ -1,57 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.Mathf; - -public interface HealthTrait{ - - void health(float health); - - float health(); - - float maxHealth(); - - boolean isDead(); - - void setDead(boolean dead); - - default void kill(){ - health(-1); - damage(1); - } - - default void onHit(SolidTrait entity){ - } - - default void onDeath(){ - } - - default boolean damaged(){ - return health() < maxHealth() - 0.0001f; - } - - default void damage(float amount){ - health(health() - amount); - if(health() <= 0 && !isDead()){ - onDeath(); - setDead(true); - } - } - - default void clampHealth(){ - health(Mathf.clamp(health(), 0, maxHealth())); - } - - default float healthf(){ - return health() / maxHealth(); - } - - default void healBy(float amount){ - health(health() + amount); - clampHealth(); - } - - default void heal(){ - health(maxHealth()); - setDead(false); - } -} diff --git a/core/src/mindustry/entities/traits/KillerTrait.java b/core/src/mindustry/entities/traits/KillerTrait.java deleted file mode 100644 index 7be5f42882..0000000000 --- a/core/src/mindustry/entities/traits/KillerTrait.java +++ /dev/null @@ -1,5 +0,0 @@ -package mindustry.entities.traits; - -public interface KillerTrait{ - void killed(Entity other); -} diff --git a/core/src/mindustry/entities/traits/MoveTrait.java b/core/src/mindustry/entities/traits/MoveTrait.java deleted file mode 100644 index f34abba24f..0000000000 --- a/core/src/mindustry/entities/traits/MoveTrait.java +++ /dev/null @@ -1,20 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.geom.Position; - -public interface MoveTrait extends Position{ - - void setX(float x); - - void setY(float y); - - default void moveBy(float x, float y){ - setX(getX() + x); - setY(getY() + y); - } - - default void set(float x, float y){ - setX(x); - setY(y); - } -} diff --git a/core/src/mindustry/entities/traits/ShooterTrait.java b/core/src/mindustry/entities/traits/ShooterTrait.java deleted file mode 100644 index bb20ccc83c..0000000000 --- a/core/src/mindustry/entities/traits/ShooterTrait.java +++ /dev/null @@ -1,13 +0,0 @@ -package mindustry.entities.traits; - -import arc.util.Interval; -import mindustry.type.Weapon; - -public interface ShooterTrait extends VelocityTrait, TeamTrait{ - - Interval getTimer(); - - int getShootTimer(boolean left); - - Weapon getWeapon(); -} diff --git a/core/src/mindustry/entities/traits/SolidTrait.java b/core/src/mindustry/entities/traits/SolidTrait.java deleted file mode 100644 index afa2efd6b0..0000000000 --- a/core/src/mindustry/entities/traits/SolidTrait.java +++ /dev/null @@ -1,38 +0,0 @@ -package mindustry.entities.traits; - - -import arc.math.geom.*; -import arc.math.geom.QuadTree.QuadTreeObject; -import mindustry.Vars; - -public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, Entity, Position{ - - void hitbox(Rect rect); - - void hitboxTile(Rect rect); - - Vec2 lastPosition(); - - default boolean collidesGrid(int x, int y){ - return true; - } - - default float getDeltaX(){ - return getX() - lastPosition().x; - } - - default float getDeltaY(){ - return getY() - lastPosition().y; - } - - default boolean collides(SolidTrait other){ - return true; - } - - default void collision(SolidTrait other, float x, float y){ - } - - default void move(float x, float y){ - Vars.collisions.move(this, x, y); - } -} diff --git a/core/src/mindustry/entities/traits/SyncTrait.java b/core/src/mindustry/entities/traits/SyncTrait.java deleted file mode 100644 index b0c6f31628..0000000000 --- a/core/src/mindustry/entities/traits/SyncTrait.java +++ /dev/null @@ -1,43 +0,0 @@ -package mindustry.entities.traits; - -import mindustry.net.Interpolator; - -import java.io.*; - -public interface SyncTrait extends Entity, TypeTrait{ - - /** Sets the position of this entity and updated the interpolator. */ - default void setNet(float x, float y){ - set(x, y); - - if(getInterpolator() != null){ - getInterpolator().target.set(x, y); - getInterpolator().last.set(x, y); - getInterpolator().pos.set(0, 0); - getInterpolator().updateSpacing = 16; - getInterpolator().lastUpdated = 0; - } - } - - /** Interpolate entity position only. Override if you need to interpolate rotations or other values. */ - default void interpolate(){ - if(getInterpolator() == null){ - throw new RuntimeException("This entity must have an interpolator to interpolate()!"); - } - - getInterpolator().update(); - - setX(getInterpolator().pos.x); - setY(getInterpolator().pos.y); - } - - /** Return the interpolator used for smoothing the position. Optional. */ - default Interpolator getInterpolator(){ - return null; - } - - //Read and write sync data, usually position - void write(DataOutput data) throws IOException; - - void read(DataInput data) throws IOException; -} diff --git a/core/src/mindustry/entities/traits/TargetTrait.java b/core/src/mindustry/entities/traits/TargetTrait.java deleted file mode 100644 index 1544b8d057..0000000000 --- a/core/src/mindustry/entities/traits/TargetTrait.java +++ /dev/null @@ -1,35 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.geom.Position; -import mindustry.game.Team; - -/** - * Base interface for targetable entities. - */ -public interface TargetTrait extends Position, VelocityTrait{ - - boolean isDead(); - - Team getTeam(); - - default float getTargetVelocityX(){ - if(this instanceof SolidTrait){ - return ((SolidTrait)this).getDeltaX(); - } - return velocity().x; - } - - default float getTargetVelocityY(){ - if(this instanceof SolidTrait){ - return ((SolidTrait)this).getDeltaY(); - } - return velocity().y; - } - - /** - * Whether this entity is a valid target. - */ - default boolean isValid(){ - return !isDead(); - } -} diff --git a/core/src/mindustry/entities/traits/TeamTrait.java b/core/src/mindustry/entities/traits/TeamTrait.java deleted file mode 100644 index f4424149af..0000000000 --- a/core/src/mindustry/entities/traits/TeamTrait.java +++ /dev/null @@ -1,7 +0,0 @@ -package mindustry.entities.traits; - -import mindustry.game.Team; - -public interface TeamTrait extends Entity{ - Team getTeam(); -} diff --git a/core/src/mindustry/entities/traits/TimeTrait.java b/core/src/mindustry/entities/traits/TimeTrait.java deleted file mode 100644 index f6c3938e3d..0000000000 --- a/core/src/mindustry/entities/traits/TimeTrait.java +++ /dev/null @@ -1,23 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.*; -import arc.util.Time; - -public interface TimeTrait extends Scaled, Entity{ - - float lifetime(); - - void time(float time); - - float time(); - - default void updateTime(){ - time(Mathf.clamp(time() + Time.delta(), 0, lifetime())); - - if(time() >= lifetime()){ - remove(); - } - } - - //fin() is not implemented due to compiler issues with iOS/RoboVM -} diff --git a/core/src/mindustry/entities/traits/TypeTrait.java b/core/src/mindustry/entities/traits/TypeTrait.java deleted file mode 100644 index 00917194fc..0000000000 --- a/core/src/mindustry/entities/traits/TypeTrait.java +++ /dev/null @@ -1,45 +0,0 @@ -package mindustry.entities.traits; - -import mindustry.type.TypeID; - -public interface TypeTrait{ - - TypeID getTypeID(); - /* - int[] lastRegisteredID = {0}; - Array> registeredTypes = new Array<>(); - ObjectIntMap> typeToID = new ObjectIntMap<>(); - - /** - * Register and return a type ID. The supplier should return a fresh instace of that type. - - static void registerType(Class type, Supplier supplier){ - if(typeToID.get(type, -1) != -1){ - return; //already registered - } - - registeredTypes.add(supplier); - int result = lastRegisteredID[0]; - typeToID.put(type, result); - lastRegisteredID[0]++; - } - - /**Gets a syncable type by ID. - static Supplier getTypeByID(int id){ - if(id == -1){ - throw new IllegalArgumentException("Attempt to retrieve invalid entity type ID! Did you forget to set it in ContentLoader.registerTypes()?"); - } - return registeredTypes.get(id); - } - - /** - * Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX. - * Do not override! - - default int getTypeID(){ - int id = typeToID.get(getClass(), -1); - if(id == -1) - throw new RuntimeException("Class of type '" + getClass() + "' is not registered! Did you forget to register it in ContentLoader#registerTypes()?"); - return id; - }*/ -} diff --git a/core/src/mindustry/entities/traits/VelocityTrait.java b/core/src/mindustry/entities/traits/VelocityTrait.java deleted file mode 100644 index 6eb42254d7..0000000000 --- a/core/src/mindustry/entities/traits/VelocityTrait.java +++ /dev/null @@ -1,36 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.geom.Vec2; -import arc.util.Time; - -public interface VelocityTrait extends MoveTrait{ - - Vec2 velocity(); - - default void applyImpulse(float x, float y){ - velocity().x += x / mass(); - velocity().y += y / mass(); - } - - default float maxVelocity(){ - return Float.MAX_VALUE; - } - - default float mass(){ - return 1f; - } - - default float drag(){ - return 0f; - } - - default void updateVelocity(){ - velocity().scl(1f - drag() * Time.delta()); - - if(this instanceof SolidTrait){ - ((SolidTrait)this).move(velocity().x * Time.delta(), velocity().y * Time.delta()); - }else{ - moveBy(velocity().x * Time.delta(), velocity().y * Time.delta()); - } - } -} diff --git a/core/src/mindustry/entities/type/BaseEntity.java b/core/src/mindustry/entities/type/BaseEntity.java index 6aa4f0f8b7..f0478f02ba 100755 --- a/core/src/mindustry/entities/type/BaseEntity.java +++ b/core/src/mindustry/entities/type/BaseEntity.java @@ -15,14 +15,6 @@ public abstract class BaseEntity implements Entity{ id = lastid++; } - public int tileX(){ - return Vars.world.toTile(x); - } - - public int tileY(){ - return Vars.world.toTile(y); - } - @Override public int getID(){ return id; diff --git a/core/src/mindustry/entities/type/BaseUnit.java b/core/src/mindustry/entities/type/BaseUnit.java index 6062662e9b..e96dc64f4c 100644 --- a/core/src/mindustry/entities/type/BaseUnit.java +++ b/core/src/mindustry/entities/type/BaseUnit.java @@ -36,11 +36,9 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ protected static final int timerTarget = timerIndex++; protected static final int timerTarget2 = timerIndex++; - protected static final int timerShootLeft = timerIndex++; - protected static final int timerShootRight = timerIndex++; protected boolean loaded; - protected UnitType type; + protected UnitDef type; protected Interval timer = new Interval(5); protected StateMachine state = new StateMachine(); protected TargetTrait target; @@ -76,11 +74,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ Core.app.post(unit::remove); } - @Override - public float drag(){ - return type.drag; - } - @Override public TypeID getTypeID(){ return type.typeID; @@ -119,7 +112,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } /** Initialize the type and team of this unit. Only call once! */ - public void init(UnitType type, Team team){ + public void init(UnitDef type, Team team){ if(this.type != null) throw new RuntimeException("This unit is already initialized!"); this.type = type; @@ -131,16 +124,12 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ return true; } - public UnitType getType(){ - return type; - } - public void setSpawner(Tile tile){ this.spawner = tile.pos(); } public void rotate(float angle){ - rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed); + rotation = Mathf.slerpDelta(rotation, angle, type.rotateSpeed); } public boolean targetHasFlag(BlockFlag flag){ @@ -179,7 +168,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } public void targetClosest(){ - TargetTrait newTarget = Units.closestTarget(team, x, y, Math.max(getWeapon().bullet.range(), type.range), u -> type.targetAir || !u.isFlying()); + TargetTrait newTarget = Units.closestTarget(team, x, y, type.range, u -> type.targetAir || !u.isFlying()); if(newTarget != null){ target = newTarget; } @@ -210,41 +199,11 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ return status.getDamageMultiplier() * Vars.state.rules.unitDamageMultiplier; } - @Override - public boolean isImmune(StatusEffect effect){ - return type.immunities.contains(effect); - } - - @Override - public boolean isValid(){ - return super.isValid() && isAdded(); - } - - @Override - public Interval getTimer(){ - return timer; - } - - @Override - public int getShootTimer(boolean left){ - return left ? timerShootLeft : timerShootRight; - } - - @Override - public Weapon getWeapon(){ - return type.weapon; - } - @Override public TextureRegion getIconRegion(){ return type.icon(Cicon.full); } - @Override - public int getItemCapacity(){ - return type.itemCapacity; - } - @Override public void interpolate(){ super.interpolate(); @@ -259,16 +218,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ return type.health * Vars.state.rules.unitHealthMultiplier; } - @Override - public float mass(){ - return type.mass; - } - - @Override - public boolean isFlying(){ - return type.flying; - } - @Override public void update(){ if(isDead()){ @@ -312,11 +261,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } - @Override - public float maxVelocity(){ - return type.maxVelocity; - } - @Override public void removed(){ super.removed(); @@ -351,16 +295,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ } } - @Override - public void hitbox(Rect rect){ - rect.setSize(type.hitsize).setCenter(x, y); - } - - @Override - public void hitboxTile(Rect rect){ - rect.setSize(type.hitsizeTile).setCenter(x, y); - } - @Override public EntityGroup targetGroup(){ return unitGroup; diff --git a/core/src/mindustry/entities/type/DestructibleEntity.java b/core/src/mindustry/entities/type/DestructibleEntity.java deleted file mode 100644 index 99efe3b00c..0000000000 --- a/core/src/mindustry/entities/type/DestructibleEntity.java +++ /dev/null @@ -1,47 +0,0 @@ -package mindustry.entities.type; - - -import mindustry.entities.traits.*; - -public abstract class DestructibleEntity extends SolidEntity implements HealthTrait{ - public transient boolean dead; - public float health; - - @Override - public boolean collides(SolidTrait other){ - return other instanceof DamageTrait; - } - - @Override - public void collision(SolidTrait other, float x, float y){ - if(other instanceof DamageTrait){ - boolean wasDead = isDead(); - onHit(other); - damage(((DamageTrait)other).damage()); - if(!wasDead && isDead()){ - ((DamageTrait)other).killed(this); - } - } - } - - @Override - public void health(float health){ - this.health = health; - } - - @Override - public float health(){ - return health; - } - - @Override - public boolean isDead(){ - return dead; - } - - @Override - public void setDead(boolean dead){ - this.dead = dead; - } - -} diff --git a/core/src/mindustry/entities/type/EffectEntity.java b/core/src/mindustry/entities/type/EffectEntity.java index 95f40d8100..7c3a196935 100644 --- a/core/src/mindustry/entities/type/EffectEntity.java +++ b/core/src/mindustry/entities/type/EffectEntity.java @@ -1,13 +1,11 @@ package mindustry.entities.type; -import arc.graphics.Color; -import arc.util.pooling.Pool.Poolable; -import arc.util.pooling.Pools; -import mindustry.entities.Effects; -import mindustry.entities.Effects.Effect; -import mindustry.entities.EntityGroup; -import mindustry.entities.traits.DrawTrait; -import mindustry.entities.traits.Entity; +import arc.graphics.*; +import arc.util.pooling.Pool.*; +import arc.util.pooling.*; +import mindustry.entities.*; +import mindustry.entities.Effects.*; +import mindustry.entities.traits.*; import static mindustry.Vars.effectGroup; diff --git a/core/src/mindustry/entities/type/Player.java b/core/src/mindustry/entities/type/Player.java index 34ce3fcbe3..57bfa5bebd 100644 --- a/core/src/mindustry/entities/type/Player.java +++ b/core/src/mindustry/entities/type/Player.java @@ -36,8 +36,6 @@ import static mindustry.Vars.*; public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ public static final int timerSync = 2; public static final int timerAbility = 3; - private static final int timerShootLeft = 0; - private static final int timerShootRight = 1; private static final float liftoffBoost = 0.2f; private static final Rect rect = new Rect(); @@ -53,7 +51,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ public float boostHeat, shootHeat, destructTime; public boolean achievedFlight; public Color color = new Color(); - public Mech mech = Mechs.starter; + public UnitDef mech = Mechs.starter; public SpawnerTrait spawner, lastSpawner; public int respawns; @@ -90,16 +88,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ return status.getDamageMultiplier() * state.rules.playerDamageMultiplier; } - @Override - public void hitbox(Rect rect){ - rect.setSize(mech.hitsize).setCenter(x, y); - } - - @Override - public void hitboxTile(Rect rect){ - rect.setSize(mech.hitsize * 2f / 3f).setCenter(x, y); - } - @Override public void onRespawn(Tile tile){ velocity.setZero(); @@ -127,6 +115,16 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ return TypeIDs.player; } + @Override + public UnitDef type(){ + return mech; + } + + @Override + public Weapons getWeapons(){ + return null; + } + @Override public void move(float x, float y){ if(!mech.flying){ @@ -136,29 +134,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ } } - @Override - public float drag(){ - return mech.drag; - } - - @Override - public Interval getTimer(){ - return timer; - } - - @Override - public int getShootTimer(boolean left){ - return left ? timerShootLeft : timerShootRight; - } - - @Override - public Weapon getWeapon(){ - return mech.weapon; - } - @Override public float getMinePower(){ - return mech.mineSpeed; + return mech.minePower; } @Override @@ -166,11 +144,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ return mech.icon(Cicon.full); } - @Override - public int getItemCapacity(){ - return mech.itemCapacity; - } - @Override public void interpolate(){ super.interpolate(); @@ -206,7 +179,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ @Override public boolean canMine(Item item){ - return item.hardness <= mech.drillPower; + return item.hardness <= mech.drillTier; } @Override @@ -247,11 +220,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ this.y = y; } - @Override - public float maxVelocity(){ - return mech.maxSpeed; - } - @Override public Queue buildQueue(){ return placeQueue; @@ -312,7 +280,10 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ float boostTrnsX = boostHeat * 3f; float boostAng = boostHeat * 40f; + float light = 0.2f; + for(int i : Mathf.signs){ + Draw.colorl(1f-light + Mathf.clamp(ft * i, 0, 1) *light); Draw.rect(mech.legRegion, x + Angles.trnsx(baseRotation, ft * i + boostTrnsY, -boostTrnsX * i), y + Angles.trnsy(baseRotation, ft * i + boostTrnsY, -boostTrnsX * i), @@ -320,6 +291,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ (mech.legRegion.getHeight() - Mathf.clamp(ft * i, 0, 2)) * Draw.scl, baseRotation - 90 + boostAng * i); } + Draw.color(); Draw.rect(mech.baseRegion, x, y, baseRotation - 90); } @@ -333,18 +305,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ Draw.rect(mech.region, x, y, rotation - 90); mech.draw(this); - - for(int i : Mathf.signs){ - float tra = rotation - 90, trY = -mech.weapon.getRecoil(this, i > 0) + mech.weaponOffsetY; - float w = i > 0 ? -mech.weapon.region.getWidth() : mech.weapon.region.getWidth(); - Draw.rect(mech.weapon.region, - x + Angles.trnsx(tra, (mech.weaponOffsetX + mech.spreadX(this)) * i, trY), - y + Angles.trnsy(tra, (mech.weaponOffsetX + mech.spreadX(this)) * i, trY), - w * Draw.scl, - mech.weapon.region.getHeight() * Draw.scl, - rotation - 90); - } - + weapons.draw(this); Draw.reset(); } @@ -522,7 +483,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ boostHeat = Mathf.lerpDelta(boostHeat, (tile != null && tile.solid()) || (isBoosting && ((!movement.isZero() && moved) || !isLocal)) ? 1f : 0f, 0.08f); shootHeat = Mathf.lerpDelta(shootHeat, isShooting() ? 1f : 0f, 0.06f); - mech.updateAlt(this); //updated regardless + mech.update(this); //updated regardless if(boostHeat > liftoffBoost + 0.1f){ achievedFlight = true; @@ -530,9 +491,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ if(boostHeat <= liftoffBoost + 0.05f && achievedFlight && !mech.flying){ if(tile != null){ - if(mech.shake > 1f){ - Effects.shake(mech.shake, mech.shake, this); - } Effects.effect(Fx.unitLand, tile.floor().color, x, y, tile.floor().isLiquid ? 1f : 0.5f); } mech.onLand(this); @@ -620,7 +578,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ if(canMove){ float baseLerp = mech.getRotationAlpha(this); - if(!isShooting() || !mech.turnCursor){ + if(!isShooting() || !mech.faceTarget){ if(!movement.isZero()){ rotation = Mathf.slerpDelta(rotation, mech.flying ? velocity.angle() : movement.angle(), 0.13f * baseLerp); } @@ -633,18 +591,19 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ protected void updateShooting(){ if(!state.isEditor() && isShooting() && mech.canShoot(this)){ - if(!mech.turnCursor){ + weapons.update(this); + //if(!mech.turnCursor){ //shoot forward ignoring cursor - mech.weapon.update(this, x + Angles.trnsx(rotation, mech.weapon.targetDistance), y + Angles.trnsy(rotation, mech.weapon.targetDistance)); - }else{ - mech.weapon.update(this, pointerX, pointerY); - } + //mech.weapon.update(this, x + Angles.trnsx(rotation, mech.weapon.targetDistance), y + Angles.trnsy(rotation, mech.weapon.targetDistance)); + //}else{ + //mech.weapon.update(this, pointerX, pointerY); + //} } } protected void updateTouch(){ if(Units.invalidateTarget(target, this) && - !(target instanceof TileEntity && ((TileEntity)target).damaged() && target.isValid() && target.getTeam() == team && mech.canHeal && dst(target) < getWeapon().bullet.range() && !(((TileEntity)target).block instanceof BuildBlock))){ + !(target instanceof TileEntity && ((TileEntity)target).damaged() && target.isValid() && target.getTeam() == team && mech.canHeal && dst(target) < mech.range && !(((TileEntity)target).block instanceof BuildBlock))){ target = null; } @@ -720,11 +679,11 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ if(target == null){ isShooting = false; if(Core.settings.getBool("autotarget")){ - target = Units.closestTarget(team, x, y, getWeapon().bullet.range(), u -> u.getTeam() != Team.derelict, u -> u.getTeam() != Team.derelict); + target = Units.closestTarget(team, x, y, mech.range, u -> u.getTeam() != Team.derelict, u -> u.getTeam() != Team.derelict); if(mech.canHeal && target == null){ target = Geometry.findClosest(x, y, indexer.getDamaged(Team.sharded)); - if(target != null && dst(target) > getWeapon().bullet.range()){ + if(target != null && dst(target) > mech.range){ target = null; }else if(target != null){ target = ((Tile)target).entity; @@ -735,10 +694,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ setMineTile(null); } } - }else if(target.isValid() || (target instanceof TileEntity && ((TileEntity)target).damaged() && target.getTeam() == team && - mech.canHeal && dst(target) < getWeapon().bullet.range())){ + }else if(target.isValid() || (target instanceof TileEntity && ((TileEntity)target).damaged() && target.getTeam() == team && mech.canHeal && dst(target) < mech.range)){ //rotate toward and shoot the target - if(mech.turnCursor){ + if(mech.faceTarget){ rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f); } diff --git a/core/src/mindustry/entities/type/SolidEntity.java b/core/src/mindustry/entities/type/SolidEntity.java deleted file mode 100644 index d3d0685f3f..0000000000 --- a/core/src/mindustry/entities/type/SolidEntity.java +++ /dev/null @@ -1,19 +0,0 @@ -package mindustry.entities.type; - -import arc.math.geom.Vec2; -import mindustry.entities.traits.SolidTrait; - -public abstract class SolidEntity extends BaseEntity implements SolidTrait{ - protected transient Vec2 velocity = new Vec2(0f, 0.0001f); - private transient Vec2 lastPosition = new Vec2(); - - @Override - public Vec2 lastPosition(){ - return lastPosition; - } - - @Override - public Vec2 velocity(){ - return velocity; - } -} diff --git a/core/src/mindustry/entities/type/TileEntity.java b/core/src/mindustry/entities/type/TileEntity.java index d83c038e70..63c1e2087e 100644 --- a/core/src/mindustry/entities/type/TileEntity.java +++ b/core/src/mindustry/entities/type/TileEntity.java @@ -10,8 +10,6 @@ import arc.math.geom.Vec2; import arc.util.*; import arc.util.ArcAnnotate.*; import mindustry.entities.EntityGroup; -import mindustry.entities.traits.HealthTrait; -import mindustry.entities.traits.TargetTrait; import mindustry.game.*; import mindustry.game.EventType.BlockDestroyEvent; import mindustry.gen.*; diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java index 8b8a5c3ac8..359efbb280 100644 --- a/core/src/mindustry/entities/type/Unit.java +++ b/core/src/mindustry/entities/type/Unit.java @@ -28,7 +28,7 @@ import java.io.*; import static mindustry.Vars.*; -public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait{ +public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, ShooterTrait{ /** Total duration of hit flash effect */ public static final float hitDuration = 9f; /** Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks. */ @@ -42,11 +42,29 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ public float rotation; protected final Interpolator interpolator = new Interpolator(); + /** status effects */ protected final Statuses status = new Statuses(); + /** current item held */ protected final ItemStack item = new ItemStack(content.item(0), 0); + /** holds weapon aiming positions and angles */ + protected final Weapons weapons = new Weapons(); + /** team; can be changed at any time */ protected Team team = Team.sharded; + /** timers for drowning and getting hit */ protected float drownTime, hitTime; + /** this unit's type; do not change internally without calling setType(...) */ + protected UnitDef type; + + public void setType(UnitDef type){ + this.type = type; + clampHealth(); + weapons.init(this); + } + + public UnitDef type(){ + return type; + } @Override public boolean collidesGrid(int x, int y){ @@ -58,6 +76,11 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ return team; } + @Override + public Weapons getWeapons(){ + return weapons; + } + @Override public void interpolate(){ interpolator.update(); @@ -134,6 +157,22 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ return !isDead() && isAdded(); } + @Override + public void hitbox(Rect rect){ + rect.setSize(type.hitsize).setCenter(x, y); + } + + @Override + public void hitboxTile(Rect rect){ + rect.setSize(type.hitsizeTile).setCenter(x, y); + } + + + @Override + public float drag(){ + return type.drag; + } + @Override public void writeSave(DataOutput stream) throws IOException{ writeSave(stream, false); @@ -186,7 +225,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public boolean isImmune(StatusEffect effect){ - return false; + return type.immunities.contains(effect); } public boolean isOutOfBounds(){ @@ -253,7 +292,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ status.update(this); item.amount = Mathf.clamp(this.item.amount, 0, getItemCapacity()); - velocity.limit(maxVelocity()).scl(1f + (status.getSpeedMultiplier() - 1f) * Time.delta()); + //velocity.limit(maxVelocity()).scl(1f + (status.getSpeedMultiplier() - 1f) * Time.delta()); if(x < -finalWorldBounds || y < -finalWorldBounds || x >= world.width() * tilesize + finalWorldBounds || y >= world.height() * tilesize + finalWorldBounds){ kill(); @@ -277,7 +316,6 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ if(x > world.unitWidth()) velocity.x -= (x - world.unitWidth())/warpDst; if(y > world.unitHeight()) velocity.y -= (y - world.unitHeight())/warpDst; - if(isFlying()){ drownTime = 0f; move(velocity.x * Time.delta(), velocity.y * Time.delta()); @@ -327,7 +365,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ if(Math.abs(py - y) <= 0.0001f) velocity.y = 0f; } - velocity.scl(Mathf.clamp(1f - drag() * (isFlying() ? 1f : floor.dragMultiplier) * Time.delta())); + //velocity.scl(Mathf.clamp(1f - drag() * (isFlying() ? 1f : floor.dragMultiplier) * Time.delta())); } public boolean acceptsItem(Item item){ @@ -392,7 +430,9 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public void drawLight(){ - renderer.lights.add(x, y, 50f, Pal.powerLight, 0.6f); + if(type.lightRadius > 0){ + renderer.lights.add(x, y, type.lightRadius, type.lightColor, 0.6f); + } } public void drawBackItems(float itemtime, boolean number){ @@ -449,11 +489,16 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ public abstract TextureRegion getIconRegion(); - public abstract Weapon getWeapon(); + public final int getItemCapacity(){ + return type.itemCapacity; + } - public abstract int getItemCapacity(); + @Override + public float mass(){ + return type.mass; + } - public abstract float mass(); - - public abstract boolean isFlying(); + public boolean isFlying(){ + return type.flying; + } } diff --git a/core/src/mindustry/entities/type/base/BaseDrone.java b/core/src/mindustry/entities/type/base/BaseDrone.java index 02a8fd9d32..9eaa586cca 100644 --- a/core/src/mindustry/entities/type/base/BaseDrone.java +++ b/core/src/mindustry/entities/type/base/BaseDrone.java @@ -32,6 +32,7 @@ public abstract class BaseDrone extends FlyingUnit{ } }; + @Override public boolean countsAsEnemy(){ return false; } diff --git a/core/src/mindustry/entities/type/base/GroundUnit.java b/core/src/mindustry/entities/type/base/GroundUnit.java index bf400dd24a..5ffa40f359 100644 --- a/core/src/mindustry/entities/type/base/GroundUnit.java +++ b/core/src/mindustry/entities/type/base/GroundUnit.java @@ -119,11 +119,6 @@ public class GroundUnit extends BaseUnit{ } } - @Override - public Weapon getWeapon(){ - return type.weapon; - } - @Override public void draw(){ Draw.mixcol(Color.white, hitTime / hitDuration); diff --git a/core/src/mindustry/entities/units/WeaponMount.java b/core/src/mindustry/entities/units/WeaponMount.java new file mode 100644 index 0000000000..a39e1b9394 --- /dev/null +++ b/core/src/mindustry/entities/units/WeaponMount.java @@ -0,0 +1,20 @@ +package mindustry.entities.units; + +import mindustry.type.*; + +public class WeaponMount{ + /** weapon associated with this mount */ + public final Weapon weapon; + /** reload in frames; 0 means ready to fire */ + public float reload; + /** rotation relative to the unit this mount is on */ + public float rotation; + /** aiming position in world coordinates */ + public float aimX, aimY; + /** side that's being shot - only valid for mirrors */ + public boolean side; + + public WeaponMount(Weapon weapon){ + this.weapon = weapon; + } +} diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 365e8f2b7c..9eed10da2e 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -321,11 +321,12 @@ public class EventType{ } + //TODO rename public static class MechChangeEvent{ public final Player player; - public final Mech mech; + public final UnitDef mech; - public MechChangeEvent(Player player, Mech mech){ + public MechChangeEvent(Player player, UnitDef mech){ this.player = player; this.mech = mech; } diff --git a/core/src/mindustry/graphics/MenuRenderer.java b/core/src/mindustry/graphics/MenuRenderer.java index 099604bd6b..3519edc31f 100644 --- a/core/src/mindustry/graphics/MenuRenderer.java +++ b/core/src/mindustry/graphics/MenuRenderer.java @@ -14,7 +14,6 @@ import arc.util.noise.RidgedPerlin; import arc.util.noise.Simplex; import mindustry.content.Blocks; import mindustry.content.UnitTypes; -import mindustry.type.UnitType; import mindustry.ui.Cicon; import mindustry.world.*; import mindustry.world.blocks.Floor; diff --git a/core/src/mindustry/io/SaveFileReader.java b/core/src/mindustry/io/SaveFileReader.java index c324e78fdb..2cc2e27a90 100644 --- a/core/src/mindustry/io/SaveFileReader.java +++ b/core/src/mindustry/io/SaveFileReader.java @@ -14,7 +14,9 @@ public abstract class SaveFileReader{ protected final DataOutputStream dataBytes = new DataOutputStream(byteOutput); protected final ReusableByteOutStream byteOutputSmall = new ReusableByteOutStream(); protected final DataOutputStream dataBytesSmall = new DataOutputStream(byteOutputSmall); - protected final ObjectMap fallback = ObjectMap.of(); + protected final ObjectMap fallback = ObjectMap.of( + "dart-mech-pad", "dart-ship-pad" + ); protected void region(String name, DataInput stream, CounterInputStream counter, IORunner cons) throws IOException{ counter.resetCount(); diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 5095ce396a..e2d7e8c56b 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -9,7 +9,6 @@ import mindustry.entities.Effects.Effect; import mindustry.entities.type.Bullet; import mindustry.entities.bullet.BulletType; import mindustry.entities.traits.BuilderTrait.BuildRequest; -import mindustry.entities.traits.ShooterTrait; import mindustry.entities.type.*; import mindustry.entities.units.*; import mindustry.game.*; @@ -232,13 +231,13 @@ public class TypeIO{ return Effects.getEffect(buffer.getShort()); } - @WriteClass(UnitType.class) - public static void writeUnitType(ByteBuffer buffer, UnitType effect){ + @WriteClass(UnitDef.class) + public static void writeUnitDef(ByteBuffer buffer, UnitDef effect){ buffer.putShort(effect.id); } - @ReadClass(UnitType.class) - public static UnitType readUnitType(ByteBuffer buffer){ + @ReadClass(UnitDef.class) + public static UnitDef readUnitDef(ByteBuffer buffer){ return content.getByID(ContentType.unit, buffer.getShort()); } @@ -252,16 +251,6 @@ public class TypeIO{ return new Color(buffer.getInt()); } - @WriteClass(Mech.class) - public static void writeMech(ByteBuffer buffer, Mech mech){ - buffer.put((byte)mech.id); - } - - @ReadClass(Mech.class) - public static Mech readMech(ByteBuffer buffer){ - return content.getByID(ContentType.mech, buffer.get()); - } - @WriteClass(Liquid.class) public static void writeLiquid(ByteBuffer buffer, Liquid liquid){ buffer.putShort(liquid == null ? -1 : liquid.id); diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index aa6048d833..4fa73994b7 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -281,7 +281,7 @@ public class ContentParser{ UnitType unit; if(locate(ContentType.unit, name) == null){ Class type = resolve(legacyUnitMap.get(Strings.capitalize(getType(value)), getType(value)), "mindustry.entities.type.base"); - unit = new UnitType(mod + "-" + name, supply(type)); + unit = new UnitDef(mod + "-" + name, supply(type)); }else{ unit = locate(ContentType.unit, name); } diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index 8ddd3c3300..1ef88311c5 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -78,7 +78,7 @@ public class Mods implements Loadable{ public void importMod(Fi file) throws IOException{ Fi dest = modDirectory.child(file.name()); if(dest.exists()){ - throw new IOException("A mod with the same filename already exists!"); + throw new IOException("A file with the same name already exists in the mod folder!"); } file.copyTo(dest); diff --git a/core/src/mindustry/type/Mech.java b/core/src/mindustry/type/Mech.java deleted file mode 100644 index d9ac986df2..0000000000 --- a/core/src/mindustry/type/Mech.java +++ /dev/null @@ -1,141 +0,0 @@ -package mindustry.type; - -import arc.Core; -import arc.graphics.Color; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.scene.ui.layout.Table; -import arc.util.ArcAnnotate.*; -import arc.util.Time; -import mindustry.ctype.ContentType; -import mindustry.entities.type.Player; -import mindustry.ctype.UnlockableContent; -import mindustry.graphics.Pal; -import mindustry.ui.ContentDisplay; - -public class Mech extends UnlockableContent{ - public boolean flying; - public float speed = 1.1f; - public float maxSpeed = 10f; - public float boostSpeed = 0.75f; - public float drag = 0.4f; - public float mass = 1f; - public float shake = 0f; - public float health = 200f; - - public float hitsize = 6f; - public float cellTrnsY = 0f; - public float mineSpeed = 1f; - public int drillPower = -1; - public float buildPower = 1f; - public Color engineColor = Pal.boostTo; - public int itemCapacity = 30; - public boolean turnCursor = true; - public boolean canHeal = false; - public float compoundSpeed, compoundSpeedBoost; - - /** draw the health and team indicator */ - public boolean drawCell = true; - /** draw the items on its back */ - public boolean drawItems = true; - /** draw the engine light if it's flying/boosting */ - public boolean drawLight = true; - - public float weaponOffsetX, weaponOffsetY, engineOffset = 5f, engineSize = 2.5f; - public @NonNull Weapon weapon; - - public TextureRegion baseRegion, legRegion, region; - - public Mech(String name, boolean flying){ - super(name); - this.flying = flying; - } - - public Mech(String name){ - this(name, false); - } - - public void updateAlt(Player player){ - } - - public void draw(Player player){ - } - - public void drawStats(Player player){ - if(drawCell){ - float health = player.healthf(); - Draw.color(Color.black, player.getTeam().color, health + Mathf.absin(Time.time(), health * 5f, 1f - health)); - Draw.rect(player.getPowerCellRegion(), - player.x + Angles.trnsx(player.rotation, cellTrnsY, 0f), - player.y + Angles.trnsy(player.rotation, cellTrnsY, 0f), - player.rotation - 90); - Draw.reset(); - } - if(drawItems){ - player.drawBackItems(); - } - if(drawLight){ - player.drawLight(); - } - } - - public float getExtraArmor(Player player){ - return 0f; - } - - public float spreadX(Player player){ - return 0f; - } - - public float getRotationAlpha(Player player){ - return 1f; - } - - public boolean canShoot(Player player){ - return true; - } - - public void onLand(Player player){ - } - - @Override - public void init(){ - super.init(); - - for(int i = 0; i < 500; i++){ - compoundSpeed *= (1f - drag); - compoundSpeed += speed; - } - - for(int i = 0; i < 500; i++){ - compoundSpeedBoost *= (1f - drag); - compoundSpeedBoost += boostSpeed; - } - } - - @Override - public void displayInfo(Table table){ - ContentDisplay.displayMech(table, this); - } - - @Override - public ContentType getContentType(){ - return ContentType.mech; - } - - @Override - public void load(){ - weapon.load(); - if(!flying){ - legRegion = Core.atlas.find(name + "-leg"); - baseRegion = Core.atlas.find(name + "-base"); - } - - region = Core.atlas.find(name); - } - - @Override - public String toString(){ - return localizedName; - } -} diff --git a/core/src/mindustry/type/UnitDef.java b/core/src/mindustry/type/UnitDef.java new file mode 100644 index 0000000000..f4f64c188c --- /dev/null +++ b/core/src/mindustry/type/UnitDef.java @@ -0,0 +1,142 @@ +package mindustry.type; + +import arc.*; +import arc.audio.*; +import arc.func.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.scene.ui.layout.*; +import arc.struct.*; +import arc.util.ArcAnnotate.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.ctype.*; +import mindustry.entities.type.*; +import mindustry.entities.type.base.*; +import mindustry.game.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.ui.*; + +//TODO change to UnitType or Shell or something +public class UnitDef extends UnlockableContent{ + //TODO implement + public @NonNull Prov constructor = () -> this.flying ? new FlyingUnit() : new GroundUnit(); + public TypeID typeID; + + public boolean flying; + public float speed = 1.1f, boostSpeed = 0.75f, rotateSpeed = 0.2f, baseRotateSpeed = 0.1f; + public float drag = 0.3f, mass = 1f, accel = 0.1f; + public float health = 200f, range = -1; + public boolean targetAir = false, targetGround = false; + public boolean faceTarget = true; //equivalent to turnCursor + + public int itemCapacity = 30; + public int drillTier = -1; + public float buildPower = 1f, minePower = 1f; + + public Color engineColor = Pal.boostTo; + public float engineOffset = 5f, engineSize = 2.5f; + + public float hitsize = 6f, hitsizeTile = 4f; + public float cellOffsetX = 0f, cellOffsetY = 0f; + public float lightRadius = 60f; + public Color lightColor = Pal.powerLight; + public boolean drawCell = true, drawItems = true; + + public ObjectSet immunities = new ObjectSet<>(); + public Sound deathSound = Sounds.bang; + + public Array weapons = new Array<>(); + public TextureRegion baseRegion, legRegion, region; + + public UnitDef(String name){ + super(name); + + //TODO replace with the sane constructor + typeID = new TypeID(name, constructor); + } + + public BaseUnit create(Team team){ + BaseUnit unit = constructor.get(); + unit.init(this, team); + return unit; + } + + @Override + public void displayInfo(Table table){ + ContentDisplay.displayUnit(table, this); + } + + @CallSuper + @Override + public void init(){ + //set up default range + if(range < 0){ + for(Weapon weapon : weapons){ + range = Math.max(range, weapon.bullet.range()); + } + } + } + + @CallSuper + @Override + public void load(){ + weapons.each(Weapon::load); + region = Core.atlas.find(name); + legRegion = Core.atlas.find(name + "-leg"); + baseRegion = Core.atlas.find(name + "-base"); + } + + @Override + public ContentType getContentType(){ + return ContentType.unit; + } + + //TODO remove methods below! + + public void update(Unit player){ + } + + public void draw(Unit player){ + } + + public void drawStats(Unit player){ + if(drawCell){ + float health = player.healthf(); + Draw.color(Color.black, player.getTeam().color, health + Mathf.absin(Time.time(), health * 5f, 1f - health)); + Draw.rect(player.getPowerCellRegion(), + player.x + Angles.trnsx(player.rotation, cellOffsetY, cellOffsetX), + player.y + Angles.trnsy(player.rotation, cellOffsetY, cellOffsetX), + player.rotation - 90); + Draw.reset(); + } + + if(drawItems){ + //player.drawBackItems(0f, true); + } + } + + public float getExtraArmor(Unit player){ + return 0f; + } + + //TODO remove + public float spreadX(Unit player){ + return 0f; + } + + //TODO remove + public float getRotationAlpha(Unit player){ + return 1f; + } + + public boolean canShoot(Unit player){ + return true; + } + + public void onLand(Unit player){ + } + +} diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java deleted file mode 100644 index af0e8d5746..0000000000 --- a/core/src/mindustry/type/UnitType.java +++ /dev/null @@ -1,85 +0,0 @@ -package mindustry.type; - -import arc.*; -import arc.audio.*; -import arc.struct.*; -import arc.func.*; -import arc.graphics.g2d.*; -import arc.scene.ui.layout.*; -import arc.util.ArcAnnotate.*; -import mindustry.content.*; -import mindustry.ctype.ContentType; -import mindustry.ctype.UnlockableContent; -import mindustry.entities.type.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.ui.*; - -public class UnitType extends UnlockableContent{ - public @NonNull TypeID typeID; - public @NonNull Prov constructor; - - public float health = 60; - public float hitsize = 7f; - public float hitsizeTile = 4f; - public float speed = 0.4f; - public float range = 0, attackLength = 150f; - public float rotatespeed = 0.2f; - public float baseRotateSpeed = 0.1f; - public float shootCone = 15f; - public float mass = 1f; - public boolean flying; - public boolean targetAir = true; - public boolean rotateWeapon = false; - public float drag = 0.1f; - public float maxVelocity = 5f; - public float retreatPercent = 0.6f; - public int itemCapacity = 30; - public ObjectSet toMine = ObjectSet.with(Items.lead, Items.copper); - public float buildPower = 0.3f, minePower = 0.7f; - public @NonNull Weapon weapon; - public float weaponOffsetY, engineOffset = 6f, engineSize = 2f; - public ObjectSet immunities = new ObjectSet<>(); - public Sound deathSound = Sounds.bang; - - public TextureRegion legRegion, baseRegion, region; - - public UnitType(String name, Prov mainConstructor){ - this(name); - create(mainConstructor); - } - - public UnitType(String name){ - super(name); - } - - public void create(Prov mainConstructor){ - this.constructor = mainConstructor; - this.description = Core.bundle.getOrNull("unit." + name + ".description"); - this.typeID = new TypeID(name, mainConstructor); - } - - @Override - public void displayInfo(Table table){ - ContentDisplay.displayUnit(table, this); - } - - @Override - public void load(){ - weapon.load(); - region = Core.atlas.find(name); - legRegion = Core.atlas.find(name + "-leg"); - baseRegion = Core.atlas.find(name + "-base"); - } - - @Override - public ContentType getContentType(){ - return ContentType.unit; - } - - public BaseUnit create(Team team){ - BaseUnit unit = constructor.get(); - unit.init(this, team); - return unit; - } -} diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index 175abd1d24..a24142a725 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -20,15 +20,22 @@ import mindustry.gen.*; import static mindustry.Vars.net; public class Weapon{ + /** displayed weapon region */ public String name; - - /** minimum cursor distance from player, fixes 'cross-eyed' shooting. */ - protected static float minPlayerDist = 20f; - protected static int sequenceNum = 0; /** bullet shot */ public @NonNull BulletType bullet; /** shell ejection effect */ public Effect ejectEffect = Fx.none; + /** whether to mirror the weapon (draw two of them, which is the default) */ + public boolean mirror = true; + /** whether to flip the weapon's position/side on the ship (only valid when mirror is false) */ + public boolean flipped = false; + /** whether to shoot the weapons in different arms one after another, rather than all at once; only valid when mirror = true */ + public boolean alternate = false; + /** whether to rotate toward the target independently of unit */ + public boolean rotate = false; + /** rotation speed of weapon when rotation is enabled, in degrees/t*/ + public float rotateSpeed = 2f; /** weapon reload in frames */ public float reload; /** amount of shots per fire */ @@ -41,14 +48,12 @@ public class Weapon{ public float shake = 0f; /** visual weapon knockback. */ public float recoil = 1.5f; - /** shoot barrel y offset */ - public float length = 3f; - /** shoot barrel x offset. */ - public float width = 4f; + /** projectile/effect offsets from center of weapon */ + public float shootX = 0f, shootY = 3f; + /** offsets of weapon position on unit */ + public float x = 5f, y = 0f; /** fraction of velocity that is random */ public float velocityRnd = 0f; - /** whether to shoot the weapons in different arms one after another, rather than all at once */ - public boolean alternate = false; /** randomization of shot length */ public float lengthRand = 0f; /** delay in ticks between shots */ @@ -57,124 +62,21 @@ public class Weapon{ public boolean ignoreRotation = false; /** if turnCursor is false for a mech, how far away will the weapon target. */ public float targetDistance = 1f; - + /** sound used for shooting */ public Sound shootSound = Sounds.pew; - + /** displayed region (autoloaded) */ public TextureRegion region; - protected Weapon(String name){ + public Weapon(String name){ this.name = name; } public Weapon(){ - //no region - this.name = ""; - } - - @Remote(targets = Loc.server, called = Loc.both, unreliable = true) - public static void onPlayerShootWeapon(Player player, float x, float y, float rotation, boolean left){ - - if(player == null) return; - //clients do not see their own shoot events: they are simulated completely clientside to prevent laggy visuals - //messing with the firerate or any other stats does not affect the server (take that, script kiddies!) - if(net.client() && player == Vars.player){ - return; - } - - shootDirect(player, x, y, rotation, left); - } - - @Remote(targets = Loc.server, called = Loc.both, unreliable = true) - public static void onGenericShootWeapon(ShooterTrait shooter, float x, float y, float rotation, boolean left){ - if(shooter == null) return; - shootDirect(shooter, x, y, rotation, left); - } - - public static void shootDirect(ShooterTrait shooter, float offsetX, float offsetY, float rotation, boolean left){ - float x = shooter.getX() + offsetX; - float y = shooter.getY() + offsetY; - float baseX = shooter.getX(), baseY = shooter.getY(); - - Weapon weapon = shooter.getWeapon(); - weapon.shootSound.at(x, y, Mathf.random(0.8f, 1.0f)); - - sequenceNum = 0; - if(weapon.shotDelay > 0.01f){ - Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> { - Time.run(sequenceNum * weapon.shotDelay, () -> weapon.bullet(shooter, x + shooter.getX() - baseX, y + shooter.getY() - baseY, f + Mathf.range(weapon.inaccuracy))); - sequenceNum++; - }); - }else{ - Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> weapon.bullet(shooter, x, y, f + Mathf.range(weapon.inaccuracy))); - } - - BulletType ammo = weapon.bullet; - - Tmp.v1.trns(rotation + 180f, ammo.recoil); - - shooter.velocity().add(Tmp.v1); - - Tmp.v1.trns(rotation, 3f); - - Effects.shake(weapon.shake, weapon.shake, x, y); - Effects.effect(weapon.ejectEffect, x, y, rotation * -Mathf.sign(left)); - Effects.effect(ammo.shootEffect, x + Tmp.v1.x, y + Tmp.v1.y, rotation, shooter); - Effects.effect(ammo.smokeEffect, x + Tmp.v1.x, y + Tmp.v1.y, rotation, shooter); - - //reset timer for remote players - shooter.getTimer().get(shooter.getShootTimer(left), weapon.reload); + this(""); } public void load(){ region = Core.atlas.find(name + "-equip", Core.atlas.find(name, Core.atlas.find("clear"))); } - public void update(ShooterTrait shooter, float pointerX, float pointerY){ - for(boolean left : Mathf.booleans){ - Tmp.v1.set(pointerX, pointerY).sub(shooter.getX(), shooter.getY()); - if(Tmp.v1.len() < minPlayerDist) Tmp.v1.setLength(minPlayerDist); - - float cx = Tmp.v1.x + shooter.getX(), cy = Tmp.v1.y + shooter.getY(); - - float ang = Tmp.v1.angle(); - Tmp.v1.trns(ang - 90, width * Mathf.sign(left), length + Mathf.range(lengthRand)); - - update(shooter, shooter.getX() + Tmp.v1.x, shooter.getY() + Tmp.v1.y, Angles.angle(shooter.getX() + Tmp.v1.x, shooter.getY() + Tmp.v1.y, cx, cy), left); - } - } - - public void update(ShooterTrait shooter, float mountX, float mountY, float angle, boolean left){ - if(shooter.getTimer().get(shooter.getShootTimer(left), reload)){ - if(alternate){ - shooter.getTimer().reset(shooter.getShootTimer(!left), reload / 2f); - } - - shoot(shooter, mountX - shooter.getX(), mountY - shooter.getY(), angle, left); - } - } - - public float getRecoil(ShooterTrait player, boolean left){ - return (1f - Mathf.clamp(player.getTimer().getTime(player.getShootTimer(left)) / reload)) * recoil; - } - - public void shoot(ShooterTrait p, float x, float y, float angle, boolean left){ - if(net.client()){ - //call it directly, don't invoke on server - shootDirect(p, x, y, angle, left); - }else{ - if(p instanceof Player){ //players need special weapon handling logic - Call.onPlayerShootWeapon((Player)p, x, y, angle, left); - }else{ - Call.onGenericShootWeapon(p, x, y, angle, left); - } - } - } - - void bullet(ShooterTrait owner, float x, float y, float angle){ - if(owner == null) return; - - Tmp.v1.trns(angle, 3f); - Bullet.create(bullet, - owner, owner.getTeam(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - velocityRnd) + Mathf.random(velocityRnd)); - } } diff --git a/core/src/mindustry/ui/ContentDisplay.java b/core/src/mindustry/ui/ContentDisplay.java index 4f4f800ec7..771dccbb08 100644 --- a/core/src/mindustry/ui/ContentDisplay.java +++ b/core/src/mindustry/ui/ContentDisplay.java @@ -131,6 +131,8 @@ public class ContentDisplay{ table.row(); } + //TODO implement later + /* public static void displayMech(Table table, Mech mech){ table.table(title -> { title.addImage(mech.icon(Cicon.xlarge)).size(8 * 6); @@ -177,9 +179,9 @@ public class ContentDisplay{ table.add(Core.bundle.format("mech.minepower", mech.drillPower)); table.row(); } - } + }*/ - public static void displayUnit(Table table, UnitType unit){ + public static void displayUnit(Table table, UnitDef unit){ table.table(title -> { title.addImage(unit.icon(Cicon.xlarge)).size(8 * 6); title.add("[accent]" + unit.localizedName).padLeft(5); diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 429b27f5fb..afe3d30093 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -144,16 +144,16 @@ public class JoinDialog extends FloatingDialog{ } } - }).margin(3f).padTop(6f).top().right(); + }).margin(3f).pad(2).padTop(6f).top().right(); inner.addImageButton(Icon.refresh, Styles.emptyi, () -> { refreshServer(server); - }).margin(3f).padTop(6f).top().right(); + }).margin(3f).pad(2).padTop(6f).top().right(); inner.addImageButton(Icon.pencil, Styles.emptyi, () -> { renaming = server; add.show(); - }).margin(3f).padTop(6f).top().right(); + }).margin(3f).pad(2).padTop(6f).top().right(); inner.addImageButton(Icon.trash, Styles.emptyi, () -> { ui.showConfirm("$confirm", "$server.delete", () -> { @@ -162,7 +162,7 @@ public class JoinDialog extends FloatingDialog{ setupRemote(); refreshRemote(); }); - }).margin(3f).pad(6).top().right(); + }).margin(3f).pad(2).pad(6).top().right(); button.row(); diff --git a/core/src/mindustry/world/blocks/defense/MendProjector.java b/core/src/mindustry/world/blocks/defense/MendProjector.java index 30ea5fbda7..e033af0bc0 100644 --- a/core/src/mindustry/world/blocks/defense/MendProjector.java +++ b/core/src/mindustry/world/blocks/defense/MendProjector.java @@ -78,24 +78,10 @@ public class MendProjector extends Block{ float realRange = range + entity.phaseHeat * phaseRangeBoost; entity.charge = 0f; - int tileRange = (int)(realRange / tilesize + 1); - healed.clear(); - - for(int x = -tileRange + tile.x; x <= tileRange + tile.x; x++){ - for(int y = -tileRange + tile.y; y <= tileRange + tile.y; y++){ - if(!Mathf.within(x * tilesize, y * tilesize, tile.drawx(), tile.drawy(), realRange)) continue; - - Tile other = world.ltile(x, y); - - if(other == null) continue; - - if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.pos()) && other.entity != null && other.entity.health < other.entity.maxHealth()){ - other.entity.healBy(other.entity.maxHealth() * (healPercent + entity.phaseHeat * phaseBoost) / 100f * entity.efficiency()); - Effects.effect(Fx.healBlockFull, Tmp.c1.set(baseColor).lerp(phaseColor, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size); - healed.add(other.pos()); - } - } - } + indexer.eachBlock(entity, realRange, other -> other.entity.damaged(), other -> { + other.entity.healBy(other.entity.maxHealth() * (healPercent + entity.phaseHeat * phaseBoost) / 100f * entity.efficiency()); + Effects.effect(Fx.healBlockFull, Tmp.c1.set(baseColor).lerp(phaseColor, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size); + }); } } @@ -121,9 +107,7 @@ public class MendProjector extends Block{ Draw.color(baseColor, phaseColor, entity.phaseHeat); Draw.alpha(entity.heat * Mathf.absin(Time.time(), 10f, 1f) * 0.5f); - //Draw.blend(Blending.additive); Draw.rect(topRegion, tile.drawx(), tile.drawy()); - //Draw.blend(); Draw.alpha(1f); Lines.stroke((2f * f + 0.2f) * entity.heat); diff --git a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java index 945aeb3602..fd18e2662e 100644 --- a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java +++ b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java @@ -89,27 +89,7 @@ public class OverdriveProjector extends Block{ float realBoost = (speedBoost + entity.phaseHeat * speedBoostPhase) * entity.efficiency(); entity.charge = 0f; - - int tileRange = (int)(realRange / tilesize + 1); - healed.clear(); - - for(int x = -tileRange + tile.x; x <= tileRange + tile.x; x++){ - for(int y = -tileRange + tile.y; y <= tileRange + tile.y; y++){ - if(!Mathf.within(x * tilesize, y * tilesize, tile.drawx(), tile.drawy(), realRange)) continue; - - Tile other = world.ltile(x, y); - - if(other == null) continue; - - if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.pos()) && other.entity != null){ - if(other.entity.timeScale <= realBoost){ - other.entity.timeScaleDuration = Math.max(other.entity.timeScaleDuration, reload + 1f); - other.entity.timeScale = Math.max(other.entity.timeScale, realBoost); - } - healed.add(other.pos()); - } - } - } + indexer.eachBlock(entity, realRange, other -> other.entity.timeScale <= realBoost, other -> other.entity.applyBoost(realBoost, reload + 1f)); } } diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 75ca4bcf2d..eac262e4b2 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -17,7 +17,6 @@ import mindustry.entities.*; import mindustry.entities.Effects.Effect; import mindustry.entities.type.Bullet; import mindustry.entities.bullet.BulletType; -import mindustry.entities.traits.TargetTrait; import mindustry.entities.type.TileEntity; import mindustry.gen.*; import mindustry.graphics.*; @@ -25,6 +24,8 @@ import mindustry.world.Block; import mindustry.world.Tile; import mindustry.world.meta.*; +import java.io.*; + import static mindustry.Vars.tilesize; public abstract class Turret extends Block{ @@ -320,5 +321,26 @@ public abstract class Turret extends Block{ public float heat; public int shots; public TargetTrait target; + + @Override + public void write(DataOutput stream) throws IOException{ + super.write(stream); + stream.writeFloat(reload); + stream.writeFloat(rotation); + } + + @Override + public void read(DataInput stream, byte revision) throws IOException{ + super.read(stream, revision); + if(revision == 1){ + reload = stream.readFloat(); + rotation = stream.readFloat(); + } + } + + @Override + public byte version(){ + return 1; + } } }