mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-03-12 02:49:30 +07:00
Unified command
This commit is contained in:
parent
261c1b1611
commit
773e4c7053
annotations/src/main
core/src/mindustry
@ -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{
|
||||
|
@ -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
|
||||
mindustry.gen.BuilderPayloadUnit=23
|
||||
mindustry.gen.UnitWaterMove=20
|
||||
mindustry.gen.BuilderLegsUnit=21
|
||||
vela=25
|
||||
|
@ -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<mindustry.world.blocks.payloads.Payload>},{name:plans,type:arc.struct.Queue<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}
|
@ -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<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}
|
@ -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<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]}
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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){
|
||||
|
@ -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<FormationMember> members = new Seq<>();
|
||||
private static final Seq<Unit> 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<Unit> controlling = new Seq<>();
|
||||
transient Seq<Unit> 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<Unit> 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){
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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 -> {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user