Files
starruler-linux/scripts/server/empire_ai/weasel/ftl/Jumpdrive.as
T
2018-07-17 14:15:37 +02:00

209 lines
5.6 KiB
ActionScript

import empire_ai.weasel.WeaselAI;
import empire_ai.weasel.Movement;
import empire_ai.weasel.Development;
import empire_ai.weasel.Fleets;
import ftl;
import system_flags;
import regions.regions;
import systems;
from orders import OrderType;
const double REJUMP_MIN_DIST = 8000.0;
class Jumpdrive : FTL {
Development@ development;
Fleets@ fleets;
int safetyFlag = -1;
array<Region@> safeRegions;
void create() override {
@development = cast<Development>(ai.development);
@fleets = cast<Fleets>(ai.fleets);
safetyFlag = getSystemFlag("JumpdriveSafety");
}
void save(SaveFile& file) {
uint cnt = safeRegions.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << safeRegions[i];
}
void load(SaveFile& file) {
uint cnt = 0;
file >> cnt;
safeRegions.length = cnt;
for(uint i = 0; i < cnt; ++i)
file >> safeRegions[i];
}
double jdETA(Object& obj, const vec3d& position) {
double charge = JUMPDRIVE_CHARGE_TIME;
return charge;
}
double subETA(Object& obj, const vec3d& position) {
return newtonArrivalTime(obj.maxAcceleration, position - obj.position, vec3d());
}
bool shouldJD(Object& obj, const vec3d& position, uint priority) {
//This makes me sad
if(position.distanceTo(obj.position) < 3000)
return false;
return true;
/*double factor = 0.8;*/
/*if(priority == MP_Critical)*/
/* factor = 1.0;*/
/*return jdETA(obj, position) <= factor * subETA(obj, position);*/
}
uint order(MoveOrder& ord) override {
return order(ord, ord.obj.position, false);
}
uint order(MoveOrder& ord, const vec3d& fromPos, bool secondary) {
if(!canJumpdrive(ord.obj))
return F_Pass;
double avail = usableFTL(ai, ord);
if(avail > 0) {
vec3d toPosition;
if(targetPosition(ord, toPosition)) {
double maxRange = jumpdriveRange(ord.obj);
double dist = toPosition.distanceTo(fromPos);
bool isSafe = false;
Region@ reg = getRegion(toPosition);
if(reg !is null)
isSafe = reg.getSystemFlag(ai.empire, safetyFlag);
if(dist > maxRange && !isSafe) {
//See if we should jump to a safe region first
if(!secondary) {
double bestHop = INFINITY;
Region@ hopRegion;
vec3d bestPos;
for(uint i = 0, cnt = safeRegions.length; i < cnt; ++i) {
if(!safeRegions[i].getSystemFlag(ai.empire, safetyFlag))
continue;
vec3d hopPos = safeRegions[i].position;
hopPos = hopPos + (fromPos-hopPos).normalized(safeRegions[i].radius * 0.85);
double d = hopPos.distanceTo(toPosition);
if(d < bestHop) {
bestHop = d;
@hopRegion = safeRegions[i];
bestPos = hopPos;
}
}
if(bestHop < dist * 0.8) {
double cost = jumpdriveCost(ord.obj, fromPos, bestPos);
if(avail >= cost) {
ord.obj.addJumpdriveOrder(bestPos);
order(ord, bestPos, true);
return F_Continue;
}
}
}
//Shorten our jump
if(ord.priority < MP_Normal)
return F_Pass;
toPosition = fromPos + (toPosition - fromPos).normalized(maxRange);
}
if(shouldJD(ord.obj, toPosition, ord.priority)) {
double cost = jumpdriveCost(ord.obj, toPosition);
if(avail >= cost) {
ord.obj.addJumpdriveOrder(toPosition, append=secondary);
return F_Continue;
}
}
}
}
return F_Pass;
}
uint tick(MoveOrder& ord, double time) {
if(ord.priority == MP_Critical && canJumpdrive(ord.obj) && ord.obj.firstOrderType != OT_Jumpdrive) {
vec3d toPosition;
if(targetPosition(ord, toPosition)) {
double dist = ord.obj.position.distanceToSQ(toPosition);
if(dist > REJUMP_MIN_DIST * REJUMP_MIN_DIST) {
double maxRange = jumpdriveRange(ord.obj);
dist = sqrt(dist);
bool isSafe = false;
Region@ reg = getRegion(toPosition);
if(reg !is null)
isSafe = reg.getSystemFlag(ai.empire, safetyFlag);
if(dist > maxRange && !isSafe)
toPosition = ord.obj.position + (toPosition - ord.obj.position).normalized(maxRange);
if(shouldJD(ord.obj, toPosition, ord.priority)) {
double avail = usableFTL(ai, ord);
double cost = jumpdriveCost(ord.obj, toPosition);
if(avail >= cost) {
cast<Movement>(ai.movement).order(ord);
return F_Continue;
}
}
}
}
}
return F_Pass;
}
uint sysChk = 0;
void start() {
for(uint i = 0, cnt = systemCount; i < cnt; ++i) {
Region@ reg = getSystem(i).object;
if(reg.getSystemFlag(ai.empire, safetyFlag))
safeRegions.insertLast(reg);
}
}
void focusTick(double time) override {
//Try to get enough ftl storage that we can ftl our largest fleet a fair distance and have some remaining
double highestCost = 0.0;
for(uint i = 0, cnt = fleets.fleets.length; i < cnt; ++i) {
auto@ flAI = fleets.fleets[i];
if(flAI.fleetClass != FC_Combat)
continue;
double dist = jumpdriveRange(flAI.obj);
vec3d toPosition = flAI.obj.position + vec3d(0, 0, dist);
highestCost = max(highestCost, double(jumpdriveCost(flAI.obj, toPosition)));
}
development.aimFTLStorage = highestCost / (1.0 - ai.behavior.ftlReservePctCritical - ai.behavior.ftlReservePctNormal);
//Disable systems that are no longer safe
for(uint i = 0, cnt = safeRegions.length; i < cnt; ++i) {
if(!safeRegions[i].getSystemFlag(ai.empire, safetyFlag)) {
safeRegions.removeAt(i);
--i; --cnt;
}
}
//Try to find regions that are safe for us
{
sysChk = (sysChk+1) % systemCount;
auto@ reg = getSystem(sysChk).object;
if(reg.getSystemFlag(ai.empire, safetyFlag)) {
if(safeRegions.find(reg) == -1)
safeRegions.insertLast(reg);
}
}
}
};
AIComponent@ createJumpdrive() {
return Jumpdrive();
}