diff --git a/annotations/src/main/resources/revisions/BlockUnitUnit/1.json b/annotations/src/main/resources/revisions/BlockUnitUnit/1.json new file mode 100644 index 0000000000..dd8fdb2784 --- /dev/null +++ b/annotations/src/main/resources/revisions/BlockUnitUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/1.json b/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/1.json new file mode 100644 index 0000000000..6ed4e60191 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:plans,type:arc.struct.Queue,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderLegsUnit/1.json b/annotations/src/main/resources/revisions/BuilderLegsUnit/1.json new file mode 100644 index 0000000000..885ef84f29 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderLegsUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:plans,type:arc.struct.Queue,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/1.json b/annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/1.json new file mode 100644 index 0000000000..de89770ab4 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:payloads,type:arc.struct.Seq,size:-1},{name:plans,type:arc.struct.Queue,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMinerUnit/1.json b/annotations/src/main/resources/revisions/BuilderMinerUnit/1.json new file mode 100644 index 0000000000..3a92a12856 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderMinerUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:plans,type:arc.struct.Queue,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderPayloadUnit/1.json b/annotations/src/main/resources/revisions/BuilderPayloadUnit/1.json new file mode 100644 index 0000000000..8ca4ac4388 --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderPayloadUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:payloads,type:arc.struct.Seq,size:-1},{name:plans,type:arc.struct.Queue,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderLegsUnit/1.json b/annotations/src/main/resources/revisions/CommanderLegsUnit/1.json new file mode 100644 index 0000000000..dd8fdb2784 --- /dev/null +++ b/annotations/src/main/resources/revisions/CommanderLegsUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderMechUnit/1.json b/annotations/src/main/resources/revisions/CommanderMechUnit/1.json new file mode 100644 index 0000000000..66897ee06f --- /dev/null +++ b/annotations/src/main/resources/revisions/CommanderMechUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderUnitWaterMove/1.json b/annotations/src/main/resources/revisions/CommanderUnitWaterMove/1.json new file mode 100644 index 0000000000..dd8fdb2784 --- /dev/null +++ b/annotations/src/main/resources/revisions/CommanderUnitWaterMove/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/LegsUnit/1.json b/annotations/src/main/resources/revisions/LegsUnit/1.json new file mode 100644 index 0000000000..dd8fdb2784 --- /dev/null +++ b/annotations/src/main/resources/revisions/LegsUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/MechUnit/1.json b/annotations/src/main/resources/revisions/MechUnit/1.json new file mode 100644 index 0000000000..66897ee06f --- /dev/null +++ b/annotations/src/main/resources/revisions/MechUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/MinerUnit/1.json b/annotations/src/main/resources/revisions/MinerUnit/1.json new file mode 100644 index 0000000000..9d58b6775a --- /dev/null +++ b/annotations/src/main/resources/revisions/MinerUnit/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/UnitEntity/1.json b/annotations/src/main/resources/revisions/UnitEntity/1.json new file mode 100644 index 0000000000..dd8fdb2784 --- /dev/null +++ b/annotations/src/main/resources/revisions/UnitEntity/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index c2b8c3f947..66d7ad4839 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -932,6 +932,8 @@ unit.beta.name = Beta unit.gamma.name = Gamma unit.scepter.name = Scepter unit.reign.name = Reign +unit.vela.name = Vela +unit.corvus.name = Corvus block.resupply-point.name = Resupply Point block.parallax.name = Parallax diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java index 74e8893ed5..25192ca490 100644 --- a/core/src/mindustry/ai/types/GroundAI.java +++ b/core/src/mindustry/ai/types/GroundAI.java @@ -74,15 +74,12 @@ public class GroundAI extends AIController{ }*/ } - protected void moveTo(int pathType){ - int costType = - unit instanceof Legsc ? Pathfinder.costLegs : - unit instanceof WaterMovec ? Pathfinder.costWater : - Pathfinder.costGround; + protected void moveTo(int pathTarget){ + int costType = unit.pathType(); Tile tile = unit.tileOn(); if(tile == null) return; - Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathType)); + Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathTarget)); if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return; diff --git a/core/src/mindustry/async/TeamIndexProcess.java b/core/src/mindustry/async/TeamIndexProcess.java index cb1edfa242..13a234bbbc 100644 --- a/core/src/mindustry/async/TeamIndexProcess.java +++ b/core/src/mindustry/async/TeamIndexProcess.java @@ -14,7 +14,6 @@ public class TeamIndexProcess implements AsyncProcess{ private QuadTree[] trees = new QuadTree[Team.all.length]; private int[] counts = new int[Team.all.length]; private int[][] typeCounts = new int[Team.all.length][0]; - private int[][] activeCounts = new int[Team.all.length][0]; public QuadTree tree(Team team){ if(trees[team.id] == null) trees[team.id] = new QuadTree<>(Vars.world.getQuadBounds(new Rect())); @@ -30,10 +29,6 @@ public class TeamIndexProcess implements AsyncProcess{ return typeCounts[team.id].length <= type.id ? 0 : typeCounts[team.id][type.id]; } - public int countActive(Team team, UnitType type){ - return activeCounts[team.id].length <= type.id ? 0 : activeCounts[team.id][type.id]; - } - public void updateCount(Team team, UnitType type, int amount){ counts[team.id] += amount; if(typeCounts[team.id].length <= type.id){ @@ -42,16 +37,8 @@ public class TeamIndexProcess implements AsyncProcess{ typeCounts[team.id][type.id] += amount; } - public void updateActiveCount(Team team, UnitType type, int amount){ - if(activeCounts[team.id].length <= type.id){ - activeCounts[team.id] = new int[Vars.content.units().size]; - } - activeCounts[team.id][type.id] += amount; - } - private void count(Unit unit){ updateCount(unit.team, unit.type(), 1); - if(!unit.deactivated) updateActiveCount(unit.team, unit.type(), 1); if(unit instanceof Payloadc){ ((Payloadc)unit).payloads().each(p -> { @@ -77,7 +64,6 @@ public class TeamIndexProcess implements AsyncProcess{ } Arrays.fill(typeCounts[team.id], 0); - Arrays.fill(activeCounts[team.id], 0); } Arrays.fill(counts, 0); diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index b96e250a99..63ed6b5e20 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -1306,7 +1306,6 @@ public class UnitTypes implements ContentList{ health = 280; accel = 0.4f; rotateSpeed = 3.3f; - immunities = ObjectSet.with(StatusEffects.wet); trailLength = 20; rotateShooting = false; @@ -1358,7 +1357,6 @@ public class UnitTypes implements ContentList{ armor = 4f; accel = 0.3f; rotateSpeed = 2.6f; - immunities = ObjectSet.with(StatusEffects.wet); rotateShooting = false; trailLength = 20; @@ -1400,7 +1398,6 @@ public class UnitTypes implements ContentList{ drag = 0.17f; hitsize = 16f; armor = 7f; - immunities = ObjectSet.with(StatusEffects.wet); rotateShooting = false; trailLength = 22; @@ -1495,7 +1492,6 @@ public class UnitTypes implements ContentList{ hitsize = 39f; accel = 0.2f; rotateSpeed = 1.3f; - immunities = ObjectSet.with(StatusEffects.wet); rotateShooting = false; trailLength = 50; @@ -1580,10 +1576,9 @@ public class UnitTypes implements ContentList{ armor = 16f; accel = 0.19f; rotateSpeed = 0.9f; - immunities = ObjectSet.with(StatusEffects.wet); rotateShooting = false; - float spawnTime = 60f * 25f; + float spawnTime = 60f * 15f; abilities.add(new UnitSpawnAbility(flare, spawnTime, 19.25f, -31.75f), new UnitSpawnAbility(flare, spawnTime, -19.25f, -31.75f)); diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 95ca278bbd..82827c6530 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -24,7 +24,7 @@ public class Units{ if(unit != null){ unit.dead = true; Fx.unitCapKill.at(unit); - Core.app.post(() -> Call.unitDeath(unit.id)); + Core.app.post(() -> Call.unitDestroy(unit.id)); } } @@ -42,6 +42,21 @@ public class Units{ } } + //destroys immediately + @Remote(called = Loc.server) + public static void unitDestroy(int uid){ + Unit unit = Groups.unit.getByID(uid); + + //if there's no unit don't add it later and get it stuck as a ghost + if(netClient != null){ + netClient.addRemovedEntity(uid); + } + + if(unit != null){ + unit.destroy(); + } + } + @Remote(called = Loc.server) public static void unitDespawn(Unit unit){ Fx.unitDespawn.at(unit.x, unit.y, 0, unit); diff --git a/core/src/mindustry/entities/bullet/RailBulletType.java b/core/src/mindustry/entities/bullet/RailBulletType.java index 7eb64c0c0f..9d043538b1 100644 --- a/core/src/mindustry/entities/bullet/RailBulletType.java +++ b/core/src/mindustry/entities/bullet/RailBulletType.java @@ -4,6 +4,12 @@ import mindustry.content.*; import mindustry.entities.*; import mindustry.gen.*; +//TODO this class is bad for multiple reasons, remove/replace it. +//- effects unreliable +//- not really hitscan but works like it +//- buggy trails +//- looks bad +//- generally unreliable public class RailBulletType extends BulletType{ public Effect pierceEffect = Fx.hitBulletSmall, updateEffect = Fx.none; /** Multiplier of damage decreased per health pierced. */ diff --git a/core/src/mindustry/entities/comp/ElevationMoveComp.java b/core/src/mindustry/entities/comp/ElevationMoveComp.java index 07eae31a6c..f87bc1de0f 100644 --- a/core/src/mindustry/entities/comp/ElevationMoveComp.java +++ b/core/src/mindustry/entities/comp/ElevationMoveComp.java @@ -1,23 +1,18 @@ package mindustry.entities.comp; import mindustry.annotations.Annotations.*; +import mindustry.entities.*; +import mindustry.entities.EntityCollisions.*; import mindustry.gen.*; -import static mindustry.Vars.*; - @Component abstract class ElevationMoveComp implements Velc, Posc, Flyingc, Hitboxc{ @Import float x, y; @Replace @Override - public void move(float cx, float cy){ - if(isFlying()){ - x += cx; - y += cy; - }else{ - collisions.move(this, cx, cy); - } + public SolidPred solidity(){ + return isFlying() ? null : EntityCollisions::solid; } } diff --git a/core/src/mindustry/entities/comp/LegsComp.java b/core/src/mindustry/entities/comp/LegsComp.java index 68c0de5f00..e6022ed91e 100644 --- a/core/src/mindustry/entities/comp/LegsComp.java +++ b/core/src/mindustry/entities/comp/LegsComp.java @@ -4,16 +4,16 @@ import arc.math.*; import arc.math.geom.*; import arc.util.*; import mindustry.*; +import mindustry.ai.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; +import mindustry.entities.EntityCollisions.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.blocks.environment.*; -import static mindustry.Vars.*; - @Component abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ @Import float x, y; @@ -26,8 +26,14 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ @Replace @Override - public void move(float cx, float cy){ - collisions.moveCheck(this, cx, cy, !type.allowLegStep ? EntityCollisions::solid : EntityCollisions::legsSolid); + public SolidPred solidity(){ + return !type.allowLegStep ? EntityCollisions::solid : EntityCollisions::legsSolid; + } + + @Override + @Replace + public int pathType(){ + return Pathfinder.costLegs; } @Override diff --git a/core/src/mindustry/entities/comp/MechComp.java b/core/src/mindustry/entities/comp/MechComp.java index 407b256136..c76eec4d78 100644 --- a/core/src/mindustry/entities/comp/MechComp.java +++ b/core/src/mindustry/entities/comp/MechComp.java @@ -1,6 +1,7 @@ package mindustry.entities.comp; import arc.math.*; +import arc.math.geom.*; import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.gen.*; @@ -9,11 +10,23 @@ import mindustry.gen.*; abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, ElevationMovec{ @SyncField(false) @SyncLocal float baseRotation; transient float walkTime, walkExtension; + transient private boolean walked; @Override public void update(){ - float len = deltaLen(); - baseRotation = Angles.moveToward(baseRotation, deltaAngle(), type().baseRotateSpeed * Mathf.clamp(len / type().speed / Time.delta) * Time.delta); - walkTime += len; + //trigger animation only when walking manually + if(walked){ + float len = deltaLen(); + baseRotation = Angles.moveToward(baseRotation, deltaAngle(), type().baseRotateSpeed * Mathf.clamp(len / type().speed / Time.delta) * Time.delta); + walkTime += len; + walked = false; + } + } + + @Override + public void moveAt(Vec2 vector, float acceleration){ + if(!vector.isZero()){ + walked = true; + } } } diff --git a/core/src/mindustry/entities/comp/PayloadComp.java b/core/src/mindustry/entities/comp/PayloadComp.java index 72829cea81..3948976b6e 100644 --- a/core/src/mindustry/entities/comp/PayloadComp.java +++ b/core/src/mindustry/entities/comp/PayloadComp.java @@ -98,11 +98,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{ Unit u = payload.unit; //can't drop ground units - //TODO bad code, solidity should not be handled this way - if( - ((tileOn() == null || tileOn().solid()) && u.elevation < 0.1f && !u.type().allowLegStep) || - (!floorOn().isLiquid && u instanceof WaterMovec) || - (u.type().allowLegStep && EntityCollisions.legsSolid(u.tileX(), u.tileY()))){ + if(!u.canPassOn()){ return false; } diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index d7db961bb1..208c41c6ff 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -8,6 +8,7 @@ import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; +import mindustry.ai.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.ctype.*; @@ -37,7 +38,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I private UnitController controller; private UnitType type; - boolean spawnedByCore, deactivated; //TODO remove deactivation boolean + boolean spawnedByCore; transient Seq abilities = new Seq<>(0); @@ -103,7 +104,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Override @Replace public boolean canDrown(){ - return isGrounded() && !hovering && type.canDrown && !(this instanceof WaterMovec); + return isGrounded() && !hovering && type.canDrown; } @Override @@ -149,6 +150,11 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I return type; } + /** @return pathfinder path type for calculating costs */ + public int pathType(){ + return Pathfinder.costGround; + } + public void lookAt(float angle){ rotation = Angles.moveToward(rotation, angle, type.rotateSpeed * Time.delta * speedMultiplier()); } @@ -206,12 +212,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I public void add(){ //check if over unit cap - if(count() > cap() && !spawnedByCore){ - deactivated = true; - - if(!dead){ - Call.unitCapDeath(self()); - } + if(count() > cap() && !spawnedByCore && !dead){ + Call.unitCapDeath(self()); + teamIndex.updateCount(team, type, -1); } } @@ -232,22 +235,13 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Override public void update(){ - //activate the unit when possible - if(!net.client() && deactivated && teamIndex.countActive(team, type) < Units.getCap(team)){ - teamIndex.updateActiveCount(team, type, 1); - deactivated = false; - } - if(!deactivated){ - type.update(self()); + type.update(self()); - if(abilities.size > 0){ - for(Ability a : abilities){ - a.update(self()); - } + if(abilities.size > 0){ + for(Ability a : abilities){ + a.update(self()); } - }else if(!dead){ - Call.unitCapDeath(self()); } drag = type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f); @@ -305,18 +299,20 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I if(floor.damageTaken > 0f){ damageContinuous(floor.damageTaken); } + } - if(tile.solid()){ - if(type.canBoost){ - elevation = 1f; - }else if(!net.client()){ - kill(); - } + //kill entities on tiles that are solid to them + if(tile != null && !canPassOn()){ + //boost if possible + if(type.canBoost){ + elevation = 1f; + }else if(!net.client()){ + kill(); } } //AI only updates on the server - if(!net.client() && !dead && !deactivated){ + if(!net.client() && !dead){ controller.updateUnit(); } @@ -325,11 +321,6 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I resetController(); } - //do not control anything when deactivated - if(deactivated){ - controlWeapons(false, false); - } - //remove units spawned by the core if(spawnedByCore && !isPlayer()){ Call.unitDespawn(self()); diff --git a/core/src/mindustry/entities/comp/VelComp.java b/core/src/mindustry/entities/comp/VelComp.java index 469d217665..deec6756d1 100644 --- a/core/src/mindustry/entities/comp/VelComp.java +++ b/core/src/mindustry/entities/comp/VelComp.java @@ -3,9 +3,13 @@ package mindustry.entities.comp; import arc.math.*; import arc.math.geom.*; import arc.util.*; +import arc.util.ArcAnnotate.*; import mindustry.annotations.Annotations.*; +import mindustry.entities.EntityCollisions.*; import mindustry.gen.*; +import static mindustry.Vars.*; + @Component abstract class VelComp implements Posc{ @Import float x, y; @@ -22,12 +26,35 @@ abstract class VelComp implements Posc{ vel.scl(Mathf.clamp(1f - drag * Time.delta)); } + /** @return function to use for check solid state. if null, no checking is done. */ + @Nullable + SolidPred solidity(){ + return null; + } + + /** @return whether this entity can move through a location*/ + boolean canPass(int tileX, int tileY){ + SolidPred s = solidity(); + return s == null || !s.solid(tileX, tileY); + } + + /** @return whether this entity can exist on its current location*/ + boolean canPassOn(){ + return canPass(tileX(), tileY()); + } + boolean moving(){ return !vel.isZero(0.01f); } void move(float cx, float cy){ - x += cx; - y += cy; + SolidPred check = solidity(); + + if(check != null){ + collisions.move(self(), cx, cy, check); + }else{ + x += cx; + y += cy; + } } } diff --git a/core/src/mindustry/entities/comp/WaterMoveComp.java b/core/src/mindustry/entities/comp/WaterMoveComp.java index 9671d694ea..f87679efdb 100644 --- a/core/src/mindustry/entities/comp/WaterMoveComp.java +++ b/core/src/mindustry/entities/comp/WaterMoveComp.java @@ -4,17 +4,17 @@ import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.util.*; +import mindustry.ai.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; +import mindustry.entities.EntityCollisions.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.environment.*; -import static mindustry.Vars.*; - //just a proof of concept @Component abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc, Unitc{ @@ -38,16 +38,8 @@ abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc, Unitc{ @Override @Replace - public void lookAt(float angle){ - if(onLiquid()){ - rotation = Angles.moveToward(rotation, angle, type.rotateSpeed * Time.delta); - } - } - - @Override - @Replace - public boolean canShoot(){ - return onLiquid(); + public int pathType(){ + return Pathfinder.costWater; } @Override @@ -74,13 +66,8 @@ abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc, Unitc{ @Replace @Override - public void move(float cx, float cy){ - if(isGrounded()){ - collisions.moveCheck(this, cx, cy, EntityCollisions::waterSolid); - }else{ - x += cx; - y += cy; - } + public SolidPred solidity(){ + return isFlying() ? null : EntityCollisions::waterSolid; } @Replace diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index 58757f10bf..43358e9824 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -596,7 +596,7 @@ public class DesktopInput extends InputHandler{ } protected void updateMovement(Unit unit){ - boolean omni = !(unit instanceof WaterMovec); + boolean omni = unit.type().omniMovement; boolean ground = unit.isGrounded(); float strafePenalty = ground ? 1f : Mathf.lerp(1f, unit.type().strafePenalty, Angles.angleDist(unit.vel().angle(), unit.rotation()) / 180f); diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index c678723fec..3f102890e2 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -292,7 +292,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ }else if(unit == null){ //just clear the unit (is this used?) player.clearUnit(); //make sure it's AI controlled, so players can't overwrite each other - }else if(unit.isAI() && unit.team == player.team() && !unit.deactivated() && !unit.dead){ + }else if(unit.isAI() && unit.team == player.team() && !unit.dead){ if(!net.client()){ player.unit(unit); } @@ -365,7 +365,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } if(controlledType != null && player.dead()){ - Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type() == controlledType && !u.deactivated() && !u.dead); + Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type() == controlledType && !u.dead); if(unit != null){ Call.unitControl(player, unit); @@ -375,7 +375,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public void checkUnit(){ if(controlledType != null){ - Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type() == controlledType && !u.deactivated() && !u.dead); + Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type() == controlledType && !u.dead); if(unit == null && controlledType == UnitTypes.block){ unit = world.buildWorld(player.x, player.y) instanceof ControlBlock ? ((ControlBlock)world.buildWorld(player.x, player.y)).unit() : null; } @@ -931,7 +931,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public @Nullable Unit selectedUnit(){ - Unit unit = Units.closest(player.team(), Core.input.mouseWorld().x, Core.input.mouseWorld().y, 40f, u -> u.isAI() && !u.deactivated()); + Unit unit = Units.closest(player.team(), Core.input.mouseWorld().x, Core.input.mouseWorld().y, 40f, u -> u.isAI()); if(unit != null){ unit.hitbox(Tmp.r1); Tmp.r1.grow(6f); diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 28ffb9e1b6..03d90e18be 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -804,7 +804,7 @@ public class MobileInput extends InputHandler implements GestureListener{ if(type == null) return; boolean flying = type.flying; - boolean omni = !(unit instanceof WaterMovec); + boolean omni = unit.type().omniMovement; boolean legs = unit.isGrounded(); boolean allowHealing = type.canHeal; boolean validHealTarget = allowHealing && target instanceof Building && ((Building)target).isValid() && target.team() == unit.team && diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index d037876f18..8fd2e45e82 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -55,6 +55,7 @@ public class UnitType extends UnlockableContent{ public float visualElevation = -1f; public boolean allowLegStep = false; public boolean hovering = false; + public boolean omniMovement = true; public Effect fallEffect = Fx.fallSmoke; public Effect fallThrusterEffect = Fx.fallSmoke; public Seq abilities = new Seq<>(); @@ -195,13 +196,6 @@ public class UnitType extends UnlockableContent{ }).growX(); table.row(); - if(unit.deactivated){ - table.table(d -> { - d.left(); - d.label(() -> Core.bundle.format("bar.limitreached", unit.count(), unit.cap(), Fonts.getUnicodeStr(name))); - }).left().visible(() -> unit.deactivated); - } - } @Override @@ -231,6 +225,15 @@ public class UnitType extends UnlockableContent{ public void init(){ if(constructor == null) throw new IllegalArgumentException("no constructor set up for unit '" + name + "'"); + Unit example = constructor.get(); + + //water preset + if(example instanceof WaterMovec){ + canDrown = false; + omniMovement = false; + immunities.add(StatusEffects.wet); + } + singleTarget = weapons.size <= 1; if(itemCapacity < 0){ @@ -397,10 +400,6 @@ public class UnitType extends UnlockableContent{ unit.trns(-legOffset.x, -legOffset.y); } - if(unit.deactivated){ - drawDeactive(unit); - } - if(unit.abilities.size > 0){ for(Ability a : unit.abilities){ Draw.reset(); @@ -411,16 +410,6 @@ public class UnitType extends UnlockableContent{ } } - public void drawDeactive(Unit unit){ - Draw.color(Color.scarlet); - Draw.alpha(0.8f); - - float size = 8f; - Draw.rect(Icon.warning.getRegion(), unit.x, unit.y, size, size); - - Draw.reset(); - } - public void drawPayload(T unit){ if(unit.hasPayload()){ Payload pay = unit.payloads().first(); diff --git a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java index 6d1e765fa6..656315446f 100644 --- a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java @@ -17,7 +17,7 @@ import mindustry.world.blocks.production.*; import static mindustry.Vars.*; public class PayloadConveyor extends Block{ - public float moveTime = 50f; + public float moveTime = 40f, moveForce = 201f; public @Load("@-top") TextureRegion topRegion; public @Load("@-edge") TextureRegion edgeRegion; public Interp interp = Interp.pow5; @@ -53,6 +53,7 @@ public class PayloadConveyor extends Block{ public class PayloadConveyorBuild extends Building{ public @Nullable Payload item; public float progress, itemRotation, animation; + public float curInterp, lastInterp; public @Nullable Building next; public boolean blocked; public int step = -1, stepAccepted = -1; @@ -99,6 +100,10 @@ public class PayloadConveyor extends Block{ public void updateTile(){ if(!enabled) return; + lastInterp = curInterp; + curInterp = fract(); + //rollover skip + if(lastInterp > curInterp) lastInterp = 0f; progress = time() % moveTime; updatePayload(); @@ -201,6 +206,14 @@ public class PayloadConveyor extends Block{ return Time.time(); } + @Override + public void unitOn(Unit unit){ + //calculate derivative of units moved last frame + float delta = (curInterp - lastInterp) * size * tilesize; + Tmp.v1.trns(rotdeg(), delta * moveForce).scl(1f / Math.max(unit.mass(), 201f)); + unit.move(Tmp.v1.x, Tmp.v1.y); + } + @Override public boolean acceptPayload(Building source, Payload payload){ if(source == this){ diff --git a/core/src/mindustry/world/blocks/payloads/UnitPayload.java b/core/src/mindustry/world/blocks/payloads/UnitPayload.java index db6597f309..751152fb1f 100644 --- a/core/src/mindustry/world/blocks/payloads/UnitPayload.java +++ b/core/src/mindustry/world/blocks/payloads/UnitPayload.java @@ -8,6 +8,7 @@ import arc.util.*; import arc.util.io.*; import mindustry.*; import mindustry.entities.*; +import mindustry.entities.EntityCollisions.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.ui.*; @@ -47,15 +48,16 @@ public class UnitPayload implements Payload{ return false; } - //naval units need water. - if(unit instanceof WaterMovec){ + //check if unit can be dumped here + SolidPred solid = unit.solidity(); + if(solid != null){ int tx = unit.tileX(), ty = unit.tileY(); - boolean nearEmpty = !EntityCollisions.waterSolid(tx, ty); + boolean nearEmpty = !solid.solid(tx, ty); for(Point2 p : Geometry.d4){ - nearEmpty |= !EntityCollisions.waterSolid(tx + p.x, ty + p.y); + nearEmpty |= !solid.solid(tx + p.x, ty + p.y); } - //cannot dump on dry land + //cannot dump on solid blocks if(!nearEmpty) return false; }