117 lines
3.4 KiB
Java
117 lines
3.4 KiB
Java
package mindustry.entities.comp;
|
|
|
|
import arc.func.*;
|
|
import arc.math.geom.*;
|
|
import arc.struct.*;
|
|
import arc.util.*;
|
|
import mindustry.ai.formations.*;
|
|
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 Entityc, Posc{
|
|
private static final Seq<FormationMember> members = new Seq<>();
|
|
private static final Seq<Unit> units = new Seq<>();
|
|
|
|
@Import float x, y, rotation, hitSize;
|
|
@Import Team team;
|
|
@Import UnitType type;
|
|
|
|
transient @Nullable Formation formation;
|
|
transient Seq<Unit> controlling = new Seq<>(10);
|
|
/** minimum speed of any unit in the formation. */
|
|
transient float minFormationSpeed;
|
|
|
|
public void update(){
|
|
if(formation != null){
|
|
formation.anchor.set(x, y, /*rotation*/ 0); //TODO rotation set to 0 because rotating is pointless
|
|
formation.updateSlots();
|
|
}
|
|
}
|
|
|
|
public void remove(){
|
|
clearCommand();
|
|
}
|
|
|
|
public void killed(){
|
|
clearCommand();
|
|
}
|
|
|
|
//make sure to reset command state when the controller is switched
|
|
public void controller(UnitController next){
|
|
clearCommand();
|
|
}
|
|
|
|
void commandNearby(FormationPattern pattern){
|
|
commandNearby(pattern, u -> true);
|
|
}
|
|
|
|
void commandNearby(FormationPattern pattern, Boolf<Unit> include){
|
|
Formation formation = new Formation(new Vec3(x, y, rotation), pattern);
|
|
formation.slotAssignmentStrategy = new DistanceAssignmentStrategy(pattern);
|
|
|
|
units.clear();
|
|
|
|
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);
|
|
}
|
|
});
|
|
|
|
//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);
|
|
}
|
|
|
|
void command(Formation formation, Seq<Unit> units){
|
|
clearCommand();
|
|
|
|
float spacing = hitSize * 0.65f;
|
|
minFormationSpeed = type.speed;
|
|
|
|
controlling.addAll(units);
|
|
for(Unit unit : units){
|
|
FormationAI ai;
|
|
unit.controller(ai = new FormationAI(self(), formation));
|
|
spacing = Math.max(spacing, ai.formationSize());
|
|
minFormationSpeed = Math.min(minFormationSpeed, unit.type().speed);
|
|
}
|
|
this.formation = formation;
|
|
|
|
//update formation spacing based on max size
|
|
formation.pattern.spacing = spacing;
|
|
|
|
members.clear();
|
|
for(Unitc u : units){
|
|
members.add((FormationAI)u.controller());
|
|
}
|
|
|
|
//TODO doesn't handle units that don't fit a formation
|
|
formation.addMembers(members);
|
|
}
|
|
|
|
boolean isCommanding(){
|
|
return formation != null;
|
|
}
|
|
|
|
void clearCommand(){
|
|
//reset controlled units
|
|
for(Unit unit : controlling){
|
|
if(unit.controller().isBeingControlled(self())){
|
|
unit.controller(unit.type().createController());
|
|
}
|
|
}
|
|
|
|
controlling.clear();
|
|
formation = null;
|
|
}
|
|
}
|