diff --git a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java index 94c988272d..93e6465639 100644 --- a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java +++ b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java @@ -643,7 +643,7 @@ public class EntityProcess extends BaseProcessor{ //assign IDs definitions.sort(Structs.comparing(t -> t.naming.toString())); for(EntityDefinition def : definitions){ - String name = def.naming.fullName(); + String name = def.name; if(map.containsKey(name)){ def.classID = map.getInt(name); }else{ diff --git a/annotations/src/main/resources/classids.properties b/annotations/src/main/resources/classids.properties index 43a3517ff0..ff34009dc1 100644 --- a/annotations/src/main/resources/classids.properties +++ b/annotations/src/main/resources/classids.properties @@ -2,11 +2,11 @@ alpha=0 atrax=1 -block=2 -corvus=24 -flare=3 -mace=4 -mega=5 +mindustry.gen.BlockUnitUnit=2 +mindustry.gen.LegsUnit=24 +mindustry.gen.UnitEntity=3 +mindustry.gen.MechUnit=4 +mindustry.gen.BuilderMinerPayloadUnit=5 mindustry.entities.comp.BuildingComp=6 mindustry.entities.comp.BulletComp=7 mindustry.entities.comp.DecalComp=8 @@ -20,12 +20,12 @@ mindustry.entities.comp.PuddleComp=13 mindustry.type.Weather.WeatherStateComp=14 mindustry.world.blocks.campaign.LaunchPad.LaunchPayloadComp=15 mindustry.world.blocks.defense.ForceProjector.ForceDrawComp=22 -mono=16 -nova=17 -oct=26 -poly=18 +mindustry.gen.MinerUnit=16 +mindustry.gen.BuilderMechMinerUnit=17 +mindustry.gen.AmmoDistributeBuilderPayloadUnit=26 +mindustry.gen.BuilderMinerUnit=18 pulsar=19 -quad=23 -risso=20 -spiroct=21 -vela=25 \ No newline at end of file +mindustry.gen.BuilderPayloadUnit=23 +mindustry.gen.UnitWaterMove=20 +mindustry.gen.BuilderLegsUnit=21 +vela=25 diff --git a/annotations/src/main/resources/revisions/AmmoDistributeBuilderPayloadUnit/0.json b/annotations/src/main/resources/revisions/AmmoDistributeBuilderPayloadUnit/0.json new file mode 100644 index 0000000000..391c6ca535 --- /dev/null +++ b/annotations/src/main/resources/revisions/AmmoDistributeBuilderPayloadUnit/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMechMinerUnit/0.json b/annotations/src/main/resources/revisions/BuilderMechMinerUnit/0.json new file mode 100644 index 0000000000..b2a9e3161a --- /dev/null +++ b/annotations/src/main/resources/revisions/BuilderMechMinerUnit/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/UnitWaterMove/0.json b/annotations/src/main/resources/revisions/UnitWaterMove/0.json new file mode 100644 index 0000000000..ddde244f79 --- /dev/null +++ b/annotations/src/main/resources/revisions/UnitWaterMove/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/core/src/mindustry/ai/BaseAI.java b/core/src/mindustry/ai/BaseAI.java index 83f393cc83..3b45d8a17b 100644 --- a/core/src/mindustry/ai/BaseAI.java +++ b/core/src/mindustry/ai/BaseAI.java @@ -44,7 +44,7 @@ public class BaseAI{ CoreBlock block = (CoreBlock)data.core().block; //create AI core unit - if(!Groups.unit.contains(u -> u.team() == data.team && u.type() == block.unitType)){ + if(!state.isEditor() && !Groups.unit.contains(u -> u.team() == data.team && u.type() == block.unitType)){ Unit unit = block.unitType.create(data.team); unit.set(data.core()); unit.add(); diff --git a/core/src/mindustry/ai/types/FormationAI.java b/core/src/mindustry/ai/types/FormationAI.java index e988294e1d..cbe12a565e 100644 --- a/core/src/mindustry/ai/types/FormationAI.java +++ b/core/src/mindustry/ai/types/FormationAI.java @@ -69,10 +69,6 @@ public class FormationAI extends AIController implements FormationMember{ @Override public float formationSize(){ - if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){ - //TODO return formation size - //eturn ((Commanderc)unit).formation(). - } return unit.hitSize * 1f; } diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 2fcb360274..9a92882cf6 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -19,14 +19,14 @@ public class UnitTypes implements ContentList{ //mech public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign; - //mech + builder + miner + commander - public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class, Commanderc.class}) UnitType nova, pulsar, quasar; + //mech + builder + miner + public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class}) UnitType nova, pulsar, quasar; - //mech + commander - public static @EntityDef({Unitc.class, Mechc.class, Commanderc.class}) UnitType vela; + //mech + public static @EntityDef({Unitc.class, Mechc.class}) UnitType vela; - //legs + commander - public static @EntityDef({Unitc.class, Legsc.class, Commanderc.class}) UnitType corvus; + //legs + public static @EntityDef({Unitc.class, Legsc.class}) UnitType corvus; //legs public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax; @@ -49,14 +49,14 @@ public class UnitTypes implements ContentList{ //air + building + payload public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class}) UnitType quad; - //air + building + payload + command - public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class, Commanderc.class, AmmoDistributec.class}) UnitType oct; + //air + building + payload + public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class, AmmoDistributec.class}) UnitType oct; //air + building + mining public static @EntityDef({Unitc.class, Builderc.class, Minerc.class}) UnitType alpha, beta, gamma; - //water + commander - public static @EntityDef({Unitc.class, WaterMovec.class, Commanderc.class}) UnitType risso, minke, bryde, sei, omura; + //water + public static @EntityDef({Unitc.class, WaterMovec.class}) UnitType risso, minke, bryde, sei, omura; //special block unit type public static @EntityDef({Unitc.class, BlockUnitc.class}) UnitType block; @@ -1660,6 +1660,7 @@ public class UnitTypes implements ContentList{ health = 120f; engineOffset = 6f; hitSize = 8f; + commandLimit = 3; weapons.add(new Weapon("small-basic-weapon"){{ reload = 17f; @@ -1696,6 +1697,7 @@ public class UnitTypes implements ContentList{ hitSize = 9f; rotateShooting = false; lowAltitude = true; + commandLimit = 5; weapons.add(new Weapon("small-mount-weapon"){{ top = false; @@ -1734,6 +1736,7 @@ public class UnitTypes implements ContentList{ health = 190f; engineOffset = 6f; hitSize = 10f; + commandLimit = 7; weapons.add(new Weapon("small-mount-weapon"){{ top = false; diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index 6af5de6c42..d57b1b5b6d 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -208,7 +208,7 @@ abstract class BuilderComp implements Unitc{ BuildPlan plan = buildPlan(); Tile tile = world.tile(plan.x, plan.y); - if(!within(tile, buildingRange) && !state.isEditor()){ + if((!within(tile, buildingRange) && !state.isEditor()) || tile == null){ return; } diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index cd96f4ce5f..aee2464d9e 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -215,9 +215,12 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, return true; } - public void applyBoost(float intensity, float duration){ + public void applyBoost(float intensity, float duration){ + //do not refresh time scale when getting a weaker intensity + if(intensity >= this.timeScale){ + timeScaleDuration = Math.max(timeScaleDuration, duration); + } timeScale = Math.max(timeScale, intensity); - timeScaleDuration = Math.max(timeScaleDuration, duration); } public Building nearby(int dx, int dy){ diff --git a/core/src/mindustry/entities/comp/CommanderComp.java b/core/src/mindustry/entities/comp/CommanderComp.java index a74c8aaf51..b0fbddcf85 100644 --- a/core/src/mindustry/entities/comp/CommanderComp.java +++ b/core/src/mindustry/entities/comp/CommanderComp.java @@ -9,22 +9,25 @@ import mindustry.ai.types.*; import mindustry.annotations.Annotations.*; import mindustry.entities.*; import mindustry.entities.units.*; +import mindustry.game.*; import mindustry.gen.*; +import mindustry.type.*; /** A unit that can command other units. */ @Component -abstract class CommanderComp implements Unitc{ +abstract class CommanderComp implements Entityc, Posc{ private static final Seq members = new Seq<>(); private static final Seq units = new Seq<>(); - @Import float x, y, rotation; + @Import float x, y, rotation, hitSize; + @Import Team team; + @Import UnitType type; transient @Nullable Formation formation; - transient Seq controlling = new Seq<>(); + transient Seq controlling = new Seq<>(10); /** minimum speed of any unit in the formation. */ transient float minFormationSpeed; - @Override public void update(){ if(formation != null){ formation.anchor.set(x, y, /*rotation*/ 0); //TODO rotation set to 0 because rotating is pointless @@ -32,18 +35,15 @@ abstract class CommanderComp implements Unitc{ } } - @Override public void remove(){ clearCommand(); } - @Override public void killed(){ clearCommand(); } //make sure to reset command state when the controller is switched - @Override public void controller(UnitController next){ clearCommand(); } @@ -58,14 +58,15 @@ abstract class CommanderComp implements Unitc{ units.clear(); - Units.nearby(team(), x, y, 200f, u -> { - if(u.isAI() && include.get(u) && u != self()){ + Units.nearby(team, x, y, 150f, u -> { + if(u.isAI() && include.get(u) && u != self() && u.type().flying == type.flying && u.hitSize <= hitSize * 1.1f){ units.add(u); } }); - units.sort(u -> u.dst2(this)); - units.truncate(type().commandLimit); + //sort by hitbox size, then by distance + units.sort(Structs.comps(Structs.comparingFloat(u -> -u.hitSize), Structs.comparingFloat(u -> u.dst2(this)))); + units.truncate(type.commandLimit); command(formation, units); } @@ -73,8 +74,8 @@ abstract class CommanderComp implements Unitc{ void command(Formation formation, Seq units){ clearCommand(); - float spacing = hitSize() * 0.65f; - minFormationSpeed = type().speed; + float spacing = hitSize * 0.65f; + minFormationSpeed = type.speed; controlling.addAll(units); for(Unit unit : units){ diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 99131bafdc..1cf0f7e216 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -28,7 +28,7 @@ import mindustry.world.blocks.payloads.*; import static mindustry.Vars.*; @Component(base = true) -abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Senseable, Ranged{ +abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged{ @Import boolean hovering, dead; @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo; diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index ae0f1cd888..0b21a2cea4 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -606,12 +606,12 @@ public class DesktopInput extends InputHandler{ float baseSpeed = unit.type().speed; //limit speed to minimum formation speed to preserve formation - if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){ + if(unit.isCommanding()){ //add a tiny multiplier to let units catch up just in case - baseSpeed = ((Commanderc)unit).minFormationSpeed() * 0.95f; + baseSpeed = unit.minFormationSpeed * 0.95f; } - float speed = baseSpeed * Mathf.lerp(1f, unit.type().canBoost ? unit.type().boostMultiplier : 1f, unit.elevation) * strafePenalty; + float speed = baseSpeed * Mathf.lerp(1f, unit.isCommanding() ? 1f : unit.type().canBoost ? unit.type().boostMultiplier : 1f, unit.elevation) * strafePenalty; float xa = Core.input.axis(Binding.move_x); float ya = Core.input.axis(Binding.move_y); boolean boosted = (unit instanceof Mechc && unit.isFlying()); @@ -661,10 +661,8 @@ public class DesktopInput extends InputHandler{ } //update commander inut - if(unit instanceof Commanderc){ - if(Core.input.keyTap(Binding.command)){ - Call.unitCommand(player); - } + if(Core.input.keyTap(Binding.command)){ + Call.unitCommand(player); } } } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 85a1f8dab4..6b3509a052 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -364,7 +364,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ if(commander.isCommanding()){ commander.clearCommand(); - }else{ + }else if(player.unit().type().commandLimit > 0){ //TODO try out some other formations commander.commandNearby(new CircleFormation()); diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 26e1c6e909..19f458ea88 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -365,7 +365,7 @@ public class MobileInput extends InputHandler implements GestureListener{ } //draw targeting crosshair - if(target != null && !state.isEditor()){ + if(target != null && !state.isEditor() && !manualShooting){ if(target != lastTarget){ crosshairScale = 0f; lastTarget = target; @@ -525,7 +525,6 @@ public class MobileInput extends InputHandler implements GestureListener{ if(mode == none){ Vec2 pos = Core.input.mouseWorld(x, y); - //TODO find payload target if(player.unit() instanceof Payloadc pay){ Unit target = Units.closest(player.team(), pos.x, pos.y, 8f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(pos, u.hitSize + 8f)); if(target != null){ @@ -540,10 +539,12 @@ public class MobileInput extends InputHandler implements GestureListener{ payloadTarget = new Vec2(pos); }else{ manualShooting = true; + this.target = null; } } }else{ manualShooting = true; + this.target = null; } if(!state.isPaused()) Fx.select.at(pos); @@ -610,10 +611,8 @@ public class MobileInput extends InputHandler implements GestureListener{ //reset payload target payloadTarget = null; //apply command on double tap when own unit is tapped - if(Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize)){ - if(player.unit() instanceof Commanderc){ - Call.unitCommand(player); - } + if(Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 0.6f + 8f)){ + Call.unitCommand(player); }else{ //control a unit/block Unit on = selectedUnit(); @@ -859,12 +858,12 @@ public class MobileInput extends InputHandler implements GestureListener{ float baseSpeed = unit.type().speed; //limit speed to minimum formation speed to preserve formation - if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){ + if(unit.isCommanding()){ //add a tiny multiplier to let units catch up just in case - baseSpeed = ((Commanderc)unit).minFormationSpeed() * 0.98f; + baseSpeed = unit.minFormationSpeed * 0.98f; } - float speed = baseSpeed * Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, unit.elevation) * strafePenalty; + float speed = baseSpeed * Mathf.lerp(1f, unit.isCommanding() ? 1f : type.canBoost ? type.boostMultiplier : 1f, unit.elevation) * strafePenalty; float range = unit.hasWeapons() ? unit.range() : 0f; float bulletSpeed = unit.hasWeapons() ? type.weapons.first().bullet.speed : 0f; float mouseAngle = unit.angleTo(unit.aimX(), unit.aimY()); @@ -946,6 +945,8 @@ public class MobileInput extends InputHandler implements GestureListener{ } } } + + unit.aim(Tmp.v1.trns(unit.rotation, 1000f).add(unit)); }else{ Vec2 intercept = Predict.intercept(unit, target, bulletSpeed); @@ -955,7 +956,6 @@ public class MobileInput extends InputHandler implements GestureListener{ unit.aim(player.mouseX, player.mouseY); } - } unit.controlWeapons(player.shooting && !boosted); diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 06458f432b..f36a5d6a16 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -424,9 +424,11 @@ public class LExecutor{ ai.plan.set(x, y, rot, block); ai.plan.config = null; - builder.clearBuilding(); - builder.updateBuilding(true); - builder.addBuild(ai.plan); + if(ai.plan.tile() != null){ + builder.clearBuilding(); + builder.updateBuilding(true); + builder.addBuild(ai.plan); + } } } case getBlock -> { diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 218599b44f..661e735fa7 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -50,7 +50,7 @@ public class UnitType extends UnlockableContent{ public float groundLayer = Layer.groundUnit; public float payloadCapacity = 8; public float aimDst = -1f; - public int commandLimit = 24; + public int commandLimit = 8; public float visualElevation = -1f; public boolean allowLegStep = false; public boolean hovering = false;