Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,764 @@
|
||||
import empire_ai.weasel.WeaselAI;
|
||||
import empire_ai.weasel.Planets;
|
||||
import empire_ai.weasel.Resources;
|
||||
import empire_ai.weasel.Colonization;
|
||||
import empire_ai.weasel.Systems;
|
||||
|
||||
import planet_levels;
|
||||
import buildings;
|
||||
|
||||
import ai.consider;
|
||||
from ai.buildings import Buildings, BuildingAI, BuildingUse;
|
||||
from ai.resources import AIResources, ResourceAI;
|
||||
|
||||
interface RaceDevelopment {
|
||||
bool shouldBeFocus(Planet& pl, const ResourceType@ resource);
|
||||
};
|
||||
|
||||
class DevelopmentFocus {
|
||||
Object@ obj;
|
||||
PlanetAI@ plAI;
|
||||
int targetLevel = 0;
|
||||
int requestedLevel = 0;
|
||||
int maximumLevel = INT_MAX;
|
||||
array<ExportData@> managedPressure;
|
||||
double weight = 1.0;
|
||||
|
||||
void tick(AI& ai, Development& dev, double time) {
|
||||
if(targetLevel != requestedLevel) {
|
||||
if(targetLevel > requestedLevel) {
|
||||
int nextLevel = min(targetLevel, min(obj.resourceLevel, requestedLevel)+1);
|
||||
if(nextLevel != requestedLevel) {
|
||||
for(int i = requestedLevel+1; i <= nextLevel; ++i)
|
||||
dev.resources.organizeImports(obj, i);
|
||||
requestedLevel = nextLevel;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dev.resources.organizeImports(obj, targetLevel);
|
||||
requestedLevel = targetLevel;
|
||||
}
|
||||
}
|
||||
|
||||
//Remove managed pressure resources that are no longer valid
|
||||
for(uint i = 0, cnt = managedPressure.length; i < cnt; ++i) {
|
||||
ExportData@ res = managedPressure[i];
|
||||
if(res.request !is null || res.obj is null || !res.obj.valid || res.obj.owner !is ai.empire || !res.usable || res.developUse !is obj) {
|
||||
if(res.developUse is obj)
|
||||
@res.developUse = null;
|
||||
managedPressure.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
|
||||
//Make sure we're not exporting our resource
|
||||
if(plAI !is null && plAI.resources !is null && plAI.resources.length != 0) {
|
||||
auto@ res = plAI.resources[0];
|
||||
res.localOnly = true;
|
||||
if(res.request !is null && res.request.obj !is res.obj)
|
||||
dev.resources.breakImport(res);
|
||||
}
|
||||
|
||||
//TODO: We should be able to bump managed pressure resources back to Development for
|
||||
//redistribution if we run out of pressure capacity.
|
||||
}
|
||||
|
||||
void save(Development& development, SaveFile& file) {
|
||||
file << obj;
|
||||
development.planets.saveAI(file, plAI);
|
||||
file << targetLevel;
|
||||
file << requestedLevel;
|
||||
file << maximumLevel;
|
||||
file << weight;
|
||||
|
||||
uint cnt = managedPressure.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
development.resources.saveExport(file, managedPressure[i]);
|
||||
}
|
||||
|
||||
void load(Development& development, SaveFile& file) {
|
||||
file >> obj;
|
||||
@plAI = development.planets.loadAI(file);
|
||||
file >> targetLevel;
|
||||
file >> requestedLevel;
|
||||
file >> maximumLevel;
|
||||
file >> weight;
|
||||
|
||||
uint cnt = 0;
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = development.resources.loadExport(file);
|
||||
managedPressure.insertLast(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Development : AIComponent, Buildings, ConsiderFilter, AIResources {
|
||||
RaceDevelopment@ race;
|
||||
Planets@ planets;
|
||||
Resources@ resources;
|
||||
Colonization@ colonization;
|
||||
Systems@ systems;
|
||||
|
||||
array<DevelopmentFocus@> focuses;
|
||||
array<ExportData@> managedPressure;
|
||||
|
||||
array<ColonizeData@> pendingFocuses;
|
||||
array<ColonizeData@> pendingResources;
|
||||
|
||||
array<BuildingRequest@> genericBuilds;
|
||||
array<ExportData@> aiResources;
|
||||
|
||||
double aimFTLStorage = 0.0;
|
||||
|
||||
bool managePlanetPressure = true;
|
||||
bool manageAsteroidPressure = true;
|
||||
bool buildBuildings = true;
|
||||
bool colonizeResources = true;
|
||||
|
||||
void create() {
|
||||
@planets = cast<Planets>(ai.planets);
|
||||
@resources = cast<Resources>(ai.resources);
|
||||
@colonization = cast<Colonization>(ai.colonization);
|
||||
@systems = cast<Systems>(ai.systems);
|
||||
@race = cast<RaceDevelopment>(ai.race);
|
||||
|
||||
//Register specialized building types
|
||||
for(uint i = 0, cnt = getBuildingTypeCount(); i < cnt; ++i) {
|
||||
auto@ type = getBuildingType(i);
|
||||
for(uint n = 0, ncnt = type.ai.length; n < ncnt; ++n) {
|
||||
auto@ hook = cast<BuildingAI>(type.ai[n]);
|
||||
if(hook !is null)
|
||||
hook.register(this, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Empire@ get_empire() {
|
||||
return ai.empire;
|
||||
}
|
||||
|
||||
Considerer@ get_consider() {
|
||||
return cast<Considerer>(ai.consider);
|
||||
}
|
||||
|
||||
void registerUse(BuildingUse use, const BuildingType& type) {
|
||||
switch(use) {
|
||||
case BU_Factory:
|
||||
@ai.defs.Factory = type;
|
||||
break;
|
||||
case BU_LaborStorage:
|
||||
@ai.defs.LaborStorage = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void save(SaveFile& file) {
|
||||
file << aimFTLStorage;
|
||||
|
||||
uint cnt = focuses.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ focus = focuses[i];
|
||||
focus.save(this, file);
|
||||
}
|
||||
|
||||
cnt = managedPressure.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
resources.saveExport(file, managedPressure[i]);
|
||||
|
||||
cnt = pendingFocuses.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
colonization.saveColonize(file, pendingFocuses[i]);
|
||||
|
||||
cnt = pendingResources.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
colonization.saveColonize(file, pendingResources[i]);
|
||||
|
||||
cnt = genericBuilds.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
planets.saveBuildingRequest(file, genericBuilds[i]);
|
||||
|
||||
cnt = aiResources.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
resources.saveExport(file, aiResources[i]);
|
||||
}
|
||||
|
||||
void load(SaveFile& file) {
|
||||
file >> aimFTLStorage;
|
||||
|
||||
uint cnt = 0;
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ focus = DevelopmentFocus();
|
||||
focus.load(this, file);
|
||||
|
||||
if(focus.obj !is null)
|
||||
focuses.insertLast(focus);
|
||||
}
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = resources.loadExport(file);
|
||||
if(data !is null)
|
||||
managedPressure.insertLast(data);
|
||||
}
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = colonization.loadColonize(file);
|
||||
if(data !is null)
|
||||
pendingFocuses.insertLast(data);
|
||||
}
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = colonization.loadColonize(file);
|
||||
if(data !is null)
|
||||
pendingResources.insertLast(data);
|
||||
}
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = planets.loadBuildingRequest(file);
|
||||
if(data !is null)
|
||||
genericBuilds.insertLast(data);
|
||||
}
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = resources.loadExport(file);
|
||||
if(data !is null)
|
||||
aiResources.insertLast(data);
|
||||
}
|
||||
}
|
||||
|
||||
bool requestsFTLStorage() {
|
||||
double capacity = ai.empire.FTLCapacity;
|
||||
if(aimFTLStorage <= capacity)
|
||||
return false;
|
||||
if(ai.empire.FTLStored < capacity * 0.5)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isBuilding(const BuildingType& type) {
|
||||
for(uint i = 0, cnt = genericBuilds.length; i < cnt; ++i) {
|
||||
if(genericBuilds[i].type is type)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isLeveling() {
|
||||
for(uint i = 0, cnt = focuses.length; i < cnt; ++i) {
|
||||
if(focuses[i].obj.resourceLevel < uint(focuses[i].targetLevel)) {
|
||||
auto@ focus = focuses[i].obj;
|
||||
|
||||
//If all our requirements are resolved, then we can safely assume it will be leveled up
|
||||
bool allResolved = true;
|
||||
for(uint n = 0, ncnt = resources.requested.length; n < ncnt; ++n) {
|
||||
auto@ req = resources.requested[n];
|
||||
if(req.obj !is focus)
|
||||
continue;
|
||||
if(req.beingMet)
|
||||
continue;
|
||||
|
||||
if(!req.isColonizing) {
|
||||
allResolved = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!colonization.isResolved(req)) {
|
||||
allResolved = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!allResolved)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isBusy() {
|
||||
if(pendingFocuses.length != 0)
|
||||
return true;
|
||||
if(pendingResources.length != 0)
|
||||
return true;
|
||||
if(isLeveling())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isFocus(Object@ obj) {
|
||||
for(uint i = 0, cnt = focuses.length; i < cnt; ++i) {
|
||||
if(focuses[i].obj is obj)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isManaging(ExportData@ res) {
|
||||
for(uint i = 0, cnt = managedPressure.length; i < cnt; ++i) {
|
||||
if(managedPressure[i] is res)
|
||||
return true;
|
||||
}
|
||||
for(uint i = 0, cnt = aiResources.length; i < cnt; ++i) {
|
||||
if(aiResources[i] is res)
|
||||
return true;
|
||||
}
|
||||
for(uint n = 0, ncnt = focuses.length; n < ncnt; ++n) {
|
||||
auto@ f = focuses[n];
|
||||
if(f.obj is res.obj)
|
||||
return true;
|
||||
for(uint i = 0, cnt = f.managedPressure.length; i < cnt; ++i) {
|
||||
if(f.managedPressure[i] is res)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDevelopingIn(Region@ reg) {
|
||||
if(reg is null)
|
||||
return false;
|
||||
for(uint i = 0, cnt = focuses.length; i < cnt; ++i) {
|
||||
if(focuses[i].obj.region is reg)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void start() {
|
||||
//Level up the homeworld to level 3 to start with
|
||||
for(uint i = 0, cnt = ai.empire.planetCount; i < cnt; ++i) {
|
||||
Planet@ homeworld = ai.empire.planetList[i];
|
||||
if(homeworld !is null && homeworld.valid) {
|
||||
auto@ hwFocus = addFocus(planets.register(homeworld));
|
||||
if(homeworld.nativeResourceCount >= 2 || homeworld.primaryResourceLimitLevel >= 3 || cnt == 1)
|
||||
hwFocus.targetLevel = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double idlePenalty = 0;
|
||||
void findSomethingToDo() {
|
||||
if(idlePenalty > gameTime)
|
||||
return;
|
||||
|
||||
double totalChance =
|
||||
ai.behavior.focusDevelopWeight
|
||||
+ ai.behavior.focusColonizeNewWeight * sqr(1.0 / double(focuses.length))
|
||||
+ ai.behavior.focusColonizeHighTierWeight;
|
||||
double roll = randomd(0.0, totalChance);
|
||||
|
||||
//Level up one of our existing focuses
|
||||
roll -= ai.behavior.focusDevelopWeight;
|
||||
if(roll <= 0) {
|
||||
DevelopmentFocus@ levelup;
|
||||
double totalWeight = 0.0;
|
||||
for(uint i = 0, cnt = focuses.length; i < cnt; ++i) {
|
||||
auto@ f = focuses[i];
|
||||
if(f.weight == 0)
|
||||
continue;
|
||||
if(f.targetLevel >= f.maximumLevel)
|
||||
continue;
|
||||
totalWeight += f.weight;
|
||||
if(randomd() < f.weight / totalWeight)
|
||||
@levelup = f;
|
||||
}
|
||||
|
||||
if(levelup !is null) {
|
||||
levelup.targetLevel += 1;
|
||||
if(log)
|
||||
ai.print("Develop chose to level this up to "+levelup.targetLevel, levelup.obj);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if(log)
|
||||
ai.print("Develop ran out of things to level up.");
|
||||
}
|
||||
}
|
||||
|
||||
if(!colonizeResources)
|
||||
return;
|
||||
|
||||
//Find a scalable or high tier resource to colonize and turn into a focus
|
||||
roll -= ai.behavior.focusColonizeNewWeight * sqr(1.0 / double(focuses.length));
|
||||
if(roll <= 0) {
|
||||
Planet@ newFocus;
|
||||
double totalWeight = 0.0;
|
||||
|
||||
for(uint i = 0, cnt = colonization.potentials.length; i < cnt; ++i) {
|
||||
auto@ p = colonization.potentials[i];
|
||||
|
||||
if(p.resource.level < 3 && p.resource.cls !is colonization.scalableClass)
|
||||
continue;
|
||||
|
||||
Region@ reg = p.pl.region;
|
||||
if(reg is null)
|
||||
continue;
|
||||
|
||||
if(colonization.isColonizing(p.pl))
|
||||
continue;
|
||||
|
||||
vec2i surfaceSize = p.pl.surfaceGridSize;
|
||||
int tiles = surfaceSize.width * surfaceSize.height;
|
||||
if(tiles < 144)
|
||||
continue;
|
||||
|
||||
auto@ sys = systems.getAI(reg);
|
||||
|
||||
double w = 1.0;
|
||||
if(sys.border)
|
||||
w *= 0.25;
|
||||
if(sys.obj.PlanetsMask & ~ai.mask != 0)
|
||||
w *= 0.25;
|
||||
if(p.resource.cls is colonization.scalableClass)
|
||||
w *= 10.0;
|
||||
|
||||
totalWeight += w;
|
||||
if(randomd() < w / totalWeight)
|
||||
@newFocus = p.pl;
|
||||
}
|
||||
|
||||
if(newFocus !is null) {
|
||||
auto@ data = colonization.colonize(newFocus);
|
||||
if(data !is null)
|
||||
pendingFocuses.insertLast(data);
|
||||
if(log)
|
||||
ai.print("Colonize to become develop focus", data.target);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if(log)
|
||||
ai.print("Develop could not find a scalable or high tier resource to make a focus.");
|
||||
}
|
||||
}
|
||||
|
||||
if(focuses.length == 0)
|
||||
return;
|
||||
|
||||
//Find a high tier resource to import to one of our focuses
|
||||
roll -= ai.behavior.focusColonizeHighTierWeight;
|
||||
if(roll <= 0) {
|
||||
ResourceSpec spec;
|
||||
spec.type = RST_Level_Minimum;
|
||||
spec.level = 3;
|
||||
spec.isLevelRequirement = false;
|
||||
|
||||
auto@ data = colonization.colonize(spec);
|
||||
if(data !is null) {
|
||||
if(log)
|
||||
ai.print("Colonize as free resource", data.target);
|
||||
pendingResources.insertLast(data);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if(log)
|
||||
ai.print("Develop could not find a high tier resource to colonize as free resource.");
|
||||
}
|
||||
}
|
||||
|
||||
//Try to find a level 2 resource if everything else failed
|
||||
{
|
||||
ResourceSpec spec;
|
||||
spec.type = RST_Level_Minimum;
|
||||
spec.level = 2;
|
||||
spec.isLevelRequirement = false;
|
||||
|
||||
if(colonization.shouldQueueFor(spec)) {
|
||||
auto@ data = colonization.colonize(spec);
|
||||
if(data !is null) {
|
||||
if(log)
|
||||
ai.print("Colonize as free resource", data.target);
|
||||
pendingResources.insertLast(data);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if(log)
|
||||
ai.print("Develop could not find a level 2 resource to colonize as free resource.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idlePenalty = gameTime + randomd(10.0, 40.0);
|
||||
}
|
||||
|
||||
uint bldIndex = 0;
|
||||
uint aiInd = 0;
|
||||
uint presInd = 0;
|
||||
uint chkInd = 0;
|
||||
void focusTick(double time) override {
|
||||
//Remove any resources we're managing that got used
|
||||
for(uint i = 0, cnt = managedPressure.length; i < cnt; ++i) {
|
||||
ExportData@ res = managedPressure[i];
|
||||
if(res.request !is null || res.obj is null || !res.obj.valid || res.obj.owner !is ai.empire || !res.usable) {
|
||||
managedPressure.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
|
||||
//Find new resources that we can put in our pressure manager
|
||||
uint avCnt = resources.available.length;
|
||||
if(avCnt != 0) {
|
||||
uint index = randomi(0, avCnt-1);
|
||||
for(uint i = 0, cnt = min(avCnt, 3); i < cnt; ++i) {
|
||||
uint resInd = (index+i) % avCnt;
|
||||
ExportData@ res = resources.available[resInd];
|
||||
if(res.usable && res.request is null && res.obj !is null && res.obj.valid && res.obj.owner is ai.empire && res.developUse is null) {
|
||||
if(res.resource.ai.length != 0) {
|
||||
if(!isManaging(res))
|
||||
aiResources.insertLast(res);
|
||||
}
|
||||
else if(res.resource.totalPressure > 0 && res.resource.exportable) {
|
||||
if(!managePlanetPressure && res.obj.isPlanet)
|
||||
continue;
|
||||
if(!manageAsteroidPressure && res.obj.isAsteroid)
|
||||
continue;
|
||||
if(!isManaging(res))
|
||||
managedPressure.insertLast(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Distribute managed pressure resources
|
||||
if(managedPressure.length != 0) {
|
||||
presInd = (presInd+1) % managedPressure.length;
|
||||
ExportData@ res = managedPressure[presInd];
|
||||
|
||||
int pressure = res.resource.totalPressure;
|
||||
|
||||
DevelopmentFocus@ onFocus;
|
||||
double bestWeight = 0;
|
||||
bool havePressure = ai.empire.HasPressure != 0.0;
|
||||
|
||||
for(uint i = 0, cnt = focuses.length; i < cnt; ++i) {
|
||||
auto@ f = focuses[i];
|
||||
|
||||
int cap = f.obj.pressureCap;
|
||||
if(!havePressure)
|
||||
cap = 10000;
|
||||
int cur = f.obj.totalPressure;
|
||||
|
||||
if(cur + pressure > 2 * cap)
|
||||
continue;
|
||||
|
||||
double w = 1.0;
|
||||
if(cur + pressure > cap)
|
||||
w *= 0.1;
|
||||
|
||||
if(w > bestWeight) {
|
||||
bestWeight = w;
|
||||
@onFocus = f;
|
||||
}
|
||||
}
|
||||
|
||||
if(onFocus !is null) {
|
||||
if(res.obj !is onFocus.obj)
|
||||
res.obj.exportResourceByID(res.resourceId, onFocus.obj);
|
||||
else
|
||||
res.obj.exportResourceByID(res.resourceId, null);
|
||||
@res.developUse = onFocus.obj;
|
||||
|
||||
onFocus.managedPressure.insertLast(res);
|
||||
managedPressure.removeAt(presInd);
|
||||
|
||||
if(log)
|
||||
ai.print("Take "+res.resource.name+" from "+res.obj.name+" for pressure", onFocus.obj);
|
||||
}
|
||||
}
|
||||
|
||||
//Use generic AI distribution hooks
|
||||
if(aiResources.length != 0) {
|
||||
aiInd = (aiInd+1) % aiResources.length;
|
||||
ExportData@ res = aiResources[aiInd];
|
||||
if(res.request !is null || res.obj is null || !res.obj.valid || res.obj.owner !is ai.empire || !res.usable) {
|
||||
aiResources.removeAt(aiInd);
|
||||
}
|
||||
else {
|
||||
Object@ newTarget = res.developUse;
|
||||
if(newTarget !is null) {
|
||||
if(!newTarget.valid || newTarget.owner !is ai.empire)
|
||||
@newTarget = null;
|
||||
}
|
||||
|
||||
for(uint i = 0, cnt = res.resource.ai.length; i < cnt; ++i) {
|
||||
auto@ hook = cast<ResourceAI>(res.resource.ai[i]);
|
||||
if(hook !is null)
|
||||
@newTarget = hook.distribute(this, res.resource, newTarget);
|
||||
}
|
||||
|
||||
if(newTarget !is res.developUse) {
|
||||
if(res.obj !is newTarget)
|
||||
res.obj.exportResourceByID(res.resourceId, newTarget);
|
||||
else
|
||||
res.obj.exportResourceByID(res.resourceId, null);
|
||||
@res.developUse = newTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Deal with focuses we're colonizing
|
||||
for(uint i = 0, cnt = pendingFocuses.length; i < cnt; ++i) {
|
||||
auto@ data = pendingFocuses[i];
|
||||
if(data.completed) {
|
||||
auto@ focus = addFocus(planets.register(data.target));
|
||||
focus.targetLevel = 3;
|
||||
|
||||
pendingFocuses.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
else if(data.canceled) {
|
||||
pendingFocuses.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i = 0, cnt = pendingResources.length; i < cnt; ++i) {
|
||||
auto@ data = pendingResources[i];
|
||||
if(data.completed) {
|
||||
planets.requestLevel(planets.register(data.target), data.target.primaryResourceLevel);
|
||||
pendingResources.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
else if(data.canceled) {
|
||||
pendingResources.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
|
||||
//If we're not currently leveling something up, find something else to do
|
||||
if(!isBusy())
|
||||
findSomethingToDo();
|
||||
|
||||
//Deal with building AI hints
|
||||
for(uint i = 0, cnt = genericBuilds.length; i < cnt; ++i) {
|
||||
auto@ build = genericBuilds[i];
|
||||
if(build.canceled) {
|
||||
genericBuilds.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
else if(build.built) {
|
||||
if(build.getProgress() >= 1.f) {
|
||||
if(build.expires < gameTime) {
|
||||
genericBuilds.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
else
|
||||
build.expires = gameTime + 60.0;
|
||||
}
|
||||
}
|
||||
if(buildBuildings) {
|
||||
for(uint i = 0, cnt = getBuildingTypeCount(); i < cnt; ++i) {
|
||||
bldIndex = (bldIndex+1) % cnt;
|
||||
|
||||
auto@ type = getBuildingType(bldIndex);
|
||||
if(type.ai.length == 0)
|
||||
continue;
|
||||
|
||||
//If we're already generically building something of this type, wait
|
||||
bool existing = false;
|
||||
for(uint n = 0, ncnt = genericBuilds.length; n < ncnt; ++n) {
|
||||
auto@ build = genericBuilds[n];
|
||||
if(build.type is type && !build.built) {
|
||||
existing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(existing)
|
||||
break;
|
||||
|
||||
@filterType = type;
|
||||
@consider.filter = this;
|
||||
|
||||
//See if we should generically build something of this type
|
||||
for(uint n = 0, ncnt = type.ai.length; n < ncnt; ++n) {
|
||||
auto@ hook = cast<BuildingAI>(type.ai[n]);
|
||||
if(hook !is null) {
|
||||
Object@ buildOn = hook.considerBuild(this, type);
|
||||
if(buildOn !is null && buildOn.isPlanet) {
|
||||
auto@ plAI = planets.getAI(cast<Planet>(buildOn));
|
||||
if(plAI !is null) {
|
||||
if(log)
|
||||
ai.print("AI hook generically requested building of type "+type.name, buildOn);
|
||||
|
||||
auto@ req = planets.requestBuilding(plAI, type, expire=ai.behavior.genericBuildExpire);
|
||||
if(req !is null)
|
||||
genericBuilds.insertLast(req);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Find planets we've acquired 'somehow' that have scalable resources and should be development focuses
|
||||
if(planets.planets.length != 0) {
|
||||
chkInd = (chkInd+1) % planets.planets.length;
|
||||
auto@ plAI = planets.planets[chkInd];
|
||||
|
||||
if(plAI.resources.length != 0) {
|
||||
auto@ res = plAI.resources[0];
|
||||
if(res.resource.cls is colonization.scalableClass
|
||||
|| focuses.length == 0 && res.resource.level >= 2
|
||||
|| (race !is null && race.shouldBeFocus(plAI.obj, res.resource))) {
|
||||
if(!isFocus(plAI.obj)) {
|
||||
auto@ focus = addFocus(plAI);
|
||||
focus.targetLevel = max(1, res.resource.level);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DevelopmentFocus@ addFocus(PlanetAI@ plAI) {
|
||||
DevelopmentFocus focus;
|
||||
@focus.obj = plAI.obj;
|
||||
@focus.plAI = plAI;
|
||||
focus.maximumLevel = getMaxPlanetLevel(plAI.obj);
|
||||
|
||||
focuses.insertLast(focus);
|
||||
return focus;
|
||||
}
|
||||
|
||||
DevelopmentFocus@ getFocus(Planet& pl) {
|
||||
for(uint i = 0, cnt = focuses.length; i < cnt; ++i) {
|
||||
if(focuses[i].obj is pl)
|
||||
return focuses[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void tick(double time) override {
|
||||
for(uint i = 0, cnt = focuses.length; i < cnt; ++i)
|
||||
focuses[i].tick(ai, this, time);
|
||||
}
|
||||
|
||||
const BuildingType@ filterType;
|
||||
bool filter(Object@ obj) {
|
||||
for(uint i = 0, cnt = genericBuilds.length; i < cnt; ++i) {
|
||||
auto@ build = genericBuilds[i];
|
||||
if(build.type is filterType && build.plAI.obj is obj)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
AIComponent@ createDevelopment() {
|
||||
return Development();
|
||||
}
|
||||
Reference in New Issue
Block a user