Files
2018-07-17 14:15:37 +02:00

350 lines
8.0 KiB
ActionScript

import empire_ai.weasel.WeaselAI;
import empire_ai.weasel.Fleets;
import empire_ai.weasel.Systems;
import empire_ai.weasel.Movement;
import empire_ai.weasel.searches;
import systems;
from empire import Pirates;
class InvasionDefendMission : Mission {
FleetAI@ fleet;
Region@ targRegion;
MoveOrder@ move;
bool pending = false;
Object@ eliminate;
void save(Fleets& fleets, SaveFile& file) override {
fleets.saveAI(file, fleet);
file << targRegion;
fleets.movement.saveMoveOrder(file, move);
file << pending;
}
void load(Fleets& fleets, SaveFile& file) override {
@fleet = fleets.loadAI(file);
file >> targRegion;
@move = fleets.movement.loadMoveOrder(file);
file >> pending;
}
bool get_isActive() override {
return targRegion !is null;
}
void tick(AI& ai, FleetAI& fleet, double time) override {
if(targRegion is null)
return;
if(move !is null)
return;
//Find stuff to fight
if(eliminate is null)
@eliminate = findEnemy(targRegion, null, ai.empire.hostileMask);
if(eliminate !is null) {
if(!eliminate.valid) {
@eliminate = null;
}
else {
if(!fleet.obj.hasOrders)
fleet.obj.addAttackOrder(eliminate);
if((fleet.filled < 0.3 || fleet.supplies < 0.3 || fleet.flagshipHealth < 0.5)
&& eliminate.getFleetStrength() * 2.0 > fleet.strength
&& !pending) {
@targRegion = null;
@eliminate = null;
@move = cast<Fleets>(ai.fleets).returnToBase(fleet, MP_Critical);
}
}
}
}
void update(AI& ai, Invasion& invasion) {
//Manage movement
if(move !is null) {
if(move.failed || move.completed)
@move = null;
}
//Find new regions to go to
if(targRegion is null || (!pending && move is null && !invasion.isFighting(targRegion))) {
bool ready = fleet.actionableState && move is null;
DefendSystem@ bestDef;
double bestWeight = 0.0;
for(uint i = 0, cnt = invasion.defending.length; i < cnt; ++i) {
auto@ def = invasion.defending[i];
double w = randomd(0.9, 1.1);
if(!def.fighting) {
if(!ready)
continue;
else
w *= 0.1;
}
if(!def.winning) {
w *= 10.0;
}
else {
if(!ready)
continue;
}
if(def.obj is targRegion)
w *= 1.5;
if(w > bestWeight) {
bestWeight = w;
@bestDef = def;
}
}
if(bestDef !is null && fleet.supplies >= 0.25 && fleet.filled >= 0.2 && fleet.fleetHealth >= 0.2) {
@targRegion = bestDef.obj;
invasion.pend(targRegion, fleet);
pending = true;
}
}
//Move to the region we want to go to
if(targRegion !is null) {
if(move is null) {
if(fleet.obj.region !is targRegion) {
@eliminate = findEnemy(targRegion, null, ai.empire.hostileMask);
if(eliminate is null) {
vec3d targPos = targRegion.position;
targPos += (targRegion.position - ai.empire.HomeSystem.position).normalized(targRegion.radius * 0.85);
@move = invasion.movement.move(fleet.obj, targPos, MP_Critical);
}
else {
@move = invasion.movement.move(fleet.obj, eliminate, MP_Critical, nearOnly=true);
}
}
else {
//Remove from pending list
if(pending) {
invasion.unpend(targRegion, fleet);
pending = false;
}
//See if we should return to base
if(!invasion.isFighting(targRegion) && (fleet.supplies < 0.25 || fleet.filled < 0.5)) {
@targRegion = null;
@move = invasion.fleets.returnToBase(fleet, MP_Critical);
}
}
}
}
}
};
class DefendSystem {
Region@ obj;
array<FleetAI@> pending;
double enemyStrength = 0.0;
double ourStrength = 0.0;
double remnantStrength = 0.0;
double pendingStrength = 0.0;
void save(Invasion& invasion, SaveFile& file) {
file << obj;
uint cnt = pending.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
invasion.fleets.saveAI(file, pending[i]);
file << enemyStrength;
file << ourStrength;
file << remnantStrength;
file << pendingStrength;
}
void load(Invasion& invasion, SaveFile& file) {
file >> obj;
uint cnt = 0;
file >> cnt;
for(uint i = 0; i < cnt; ++i) {
auto@ fleet = invasion.fleets.loadAI(file);
if(fleet !is null && fleet.obj !is null)
pending.insertLast(fleet);
}
file >> enemyStrength;
file >> ourStrength;
file >> remnantStrength;
file >> pendingStrength;
}
void update(AI& ai, Invasion& invasion) {
enemyStrength = getTotalFleetStrength(obj, ai.empire.hostileMask);
ourStrength = getTotalFleetStrength(obj, ai.mask);
remnantStrength = getTotalFleetStrength(obj, Pirates.mask);
if(gameTime < 10.0 * 60.0)
ourStrength += remnantStrength;
else if(gameTime < 30.0 * 60.0)
ourStrength += remnantStrength * 0.5;
pendingStrength = 0.0;
for(uint i = 0, cnt = pending.length; i < cnt; ++i)
pendingStrength += sqrt(pending[i].strength);
pendingStrength *= pendingStrength;
if(obj.PlanetsMask & ai.empire.mask != 0)
ai.empire.setDefending(obj, true);
}
bool get_fighting() {
return enemyStrength > 0;
}
bool get_winning() {
return ourStrength + pendingStrength > enemyStrength;
}
};
class Invasion : AIComponent {
Fleets@ fleets;
Movement@ movement;
array<DefendSystem@> defending;
array<InvasionDefendMission@> tracked;
void create() {
@fleets = cast<Fleets>(ai.fleets);
@movement = cast<Movement>(ai.movement);
ai.behavior.maintenancePerShipSize = 0.0;
}
void save(SaveFile& file) {
uint cnt = defending.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
defending[i].save(this, file);
cnt = tracked.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
fleets.saveMission(file, tracked[i]);
}
void load(SaveFile& file) {
uint cnt = 0;
file >> cnt;
for(uint i = 0; i < cnt; ++i) {
DefendSystem def;
def.load(this, file);
defending.insertLast(def);
}
file >> cnt;
for(uint i = 0; i < cnt; ++i) {
InvasionDefendMission@ miss = cast<InvasionDefendMission>(fleets.loadMission(file));
if(miss !is null)
tracked.insertLast(miss);
}
}
void start() {
//Find systems to defend
Region@ home = ai.empire.HomeSystem;
const SystemDesc@ sys = getSystem(home);
for(uint i = 0, cnt = sys.adjacent.length; i < cnt; ++i) {
auto@ otherSys = getSystem(sys.adjacent[i]);
if(findEnemy(otherSys.object, null, Pirates.mask, fleets=false, stations=true) !is null) {
DefendSystem def;
@def.obj = otherSys.object;
defending.insertLast(def);
}
}
}
bool isManaging(FleetAI& fleet) {
if(fleet.mission is null)
return false;
for(uint i = 0, cnt = tracked.length; i < cnt; ++i) {
if(tracked[i] is fleet.mission)
return true;
}
return false;
}
void manage(FleetAI& fleet) {
InvasionDefendMission miss;
@miss.fleet = fleet;
fleets.performMission(fleet, miss);
tracked.insertLast(miss);
}
void pend(Region@ region, FleetAI& fleet) {
for(uint i = 0, cnt = defending.length; i < cnt; ++i ){
if(defending[i].obj is region) {
defending[i].pending.insertLast(fleet);
break;
}
}
}
void unpend(Region@ region, FleetAI& fleet) {
for(uint i = 0, cnt = defending.length; i < cnt; ++i ){
if(defending[i].obj is region) {
defending[i].pending.remove(fleet);
break;
}
}
}
DefendSystem@ getDefending(Region@ region) {
for(uint i = 0, cnt = defending.length; i < cnt; ++i ){
if(defending[i].obj is region)
return defending[i];
}
return null;
}
bool isFighting(Region@ region) {
for(uint i = 0, cnt = defending.length; i < cnt; ++i ){
if(defending[i].obj is region)
return defending[i].fighting;
}
return false;
}
uint sysUpd = 0;
void focusTick(double time) {
//All your fleets are belong to us
for(uint i = 0, cnt = fleets.fleets.length; i < cnt; ++i) {
auto@ flAI = fleets.fleets[i];
if(flAI.fleetClass != FC_Combat)
continue;
if(!isManaging(flAI))
manage(flAI);
}
//Update systems we're defending
if(defending.length != 0) {
sysUpd = (sysUpd+1) % defending.length;
defending[sysUpd].update(ai, this);
}
//Make sure our fleets are in the right places
for(uint i = 0, cnt = tracked.length; i < cnt; ++i)
tracked[i].update(ai, this);
}
};
AIComponent@ createInvasion() {
return Invasion();
}