Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,712 @@
|
||||
import settings.game_settings;
|
||||
from empire_ai.EmpireAI import AIController;
|
||||
|
||||
import AIComponent@ createColonization() from "empire_ai.weasel.Colonization";
|
||||
import AIComponent@ createResources() from "empire_ai.weasel.Resources";
|
||||
import AIComponent@ createPlanets() from "empire_ai.weasel.Planets";
|
||||
import AIComponent@ createSystems() from "empire_ai.weasel.Systems";
|
||||
import AIComponent@ createFleets() from "empire_ai.weasel.Fleets";
|
||||
import AIComponent@ createScouting() from "empire_ai.weasel.Scouting";
|
||||
import AIComponent@ createDevelopment() from "empire_ai.weasel.Development";
|
||||
import AIComponent@ createDesigns() from "empire_ai.weasel.Designs";
|
||||
import AIComponent@ createBudget() from "empire_ai.weasel.Budget";
|
||||
import AIComponent@ createConstruction() from "empire_ai.weasel.Construction";
|
||||
import AIComponent@ createMilitary() from "empire_ai.weasel.Military";
|
||||
import AIComponent@ createMovement() from "empire_ai.weasel.Movement";
|
||||
import AIComponent@ createCreeping() from "empire_ai.weasel.Creeping";
|
||||
import AIComponent@ createRelations() from "empire_ai.weasel.Relations";
|
||||
import AIComponent@ createIntelligence() from "empire_ai.weasel.Intelligence";
|
||||
import AIComponent@ createWar() from "empire_ai.weasel.War";
|
||||
import AIComponent@ createResearch() from "empire_ai.weasel.Research";
|
||||
import AIComponent@ createEnergy() from "empire_ai.weasel.Energy";
|
||||
import IAIComponent@ createDiplomacy() from "empire_ai.weasel.Diplomacy";
|
||||
import AIComponent@ createConsider() from "empire_ai.weasel.Consider";
|
||||
import AIComponent@ createOrbitals() from "empire_ai.weasel.Orbitals";
|
||||
|
||||
import AIComponent@ createHyperdrive() from "empire_ai.weasel.ftl.Hyperdrive";
|
||||
import AIComponent@ createGate() from "empire_ai.weasel.ftl.Gate";
|
||||
import AIComponent@ createFling() from "empire_ai.weasel.ftl.Fling";
|
||||
import AIComponent@ createSlipstream() from "empire_ai.weasel.ftl.Slipstream";
|
||||
import AIComponent@ createJumpdrive() from "empire_ai.weasel.ftl.Jumpdrive";
|
||||
|
||||
import AIComponent@ createVerdant() from "empire_ai.weasel.race.Verdant";
|
||||
import AIComponent@ createMechanoid() from "empire_ai.weasel.race.Mechanoid";
|
||||
import AIComponent@ createStarChildren() from "empire_ai.weasel.race.StarChildren";
|
||||
import AIComponent@ createExtragalactic() from "empire_ai.weasel.race.Extragalactic";
|
||||
import AIComponent@ createLinked() from "empire_ai.weasel.race.Linked";
|
||||
import AIComponent@ createDevout() from "empire_ai.weasel.race.Devout";
|
||||
import AIComponent@ createAncient() from "empire_ai.weasel.race.Ancient";
|
||||
|
||||
import AIComponent@ createInvasion() from "empire_ai.weasel.misc.Invasion";
|
||||
import bool hasInvasionMap() from "Invasion.InvasionMap";
|
||||
|
||||
from buildings import BuildingType;
|
||||
from orbitals import OrbitalModule;
|
||||
import util.formatting;
|
||||
|
||||
from empire import ai_full_speed;
|
||||
|
||||
from traits import getTraitID;
|
||||
|
||||
export IAIComponent, AIComponent, AI;
|
||||
uint GUARD = 0xDEADBEEF;
|
||||
|
||||
enum AddedComponent {
|
||||
AC_Invasion = 0x1,
|
||||
};
|
||||
|
||||
interface IAIComponent : Savable {
|
||||
void set(AI& ai);
|
||||
void setLog();
|
||||
void setLogCritical();
|
||||
|
||||
double getPrevFocus();
|
||||
void setPrevFocus(double value);
|
||||
|
||||
void create();
|
||||
void start();
|
||||
|
||||
void tick(double time);
|
||||
void focusTick(double time);
|
||||
void turn();
|
||||
|
||||
void save(SaveFile& file);
|
||||
void load(SaveFile& file);
|
||||
void postLoad(AI& ai);
|
||||
void postSave(AI& ai);
|
||||
void loadFinalize(AI& ai);
|
||||
};
|
||||
|
||||
class AIComponent : IAIComponent, Savable {
|
||||
AI@ ai;
|
||||
double prevFocus = 0;
|
||||
bool log = false;
|
||||
bool logCritical = false;
|
||||
bool logErrors = true;
|
||||
|
||||
double getPrevFocus() { return prevFocus; }
|
||||
void setPrevFocus(double value) { prevFocus = value; }
|
||||
|
||||
void setLog() { log = true; }
|
||||
void setLogCritical() { logCritical = true; }
|
||||
|
||||
void set(AI& ai) { @this.ai = ai; }
|
||||
void create() {}
|
||||
void start() {}
|
||||
|
||||
void tick(double time) {}
|
||||
void focusTick(double time) {}
|
||||
void turn() {}
|
||||
|
||||
void save(SaveFile& file) {}
|
||||
void load(SaveFile& file) {}
|
||||
void postLoad(AI& ai) {}
|
||||
void postSave(AI& ai) {}
|
||||
void loadFinalize(AI& ai) {}
|
||||
};
|
||||
|
||||
class ProfileData {
|
||||
double tickPeak = 0.0;
|
||||
double tickAvg = 0.0;
|
||||
double tickCount = 0.0;
|
||||
|
||||
double focusPeak = 0.0;
|
||||
double focusAvg = 0.0;
|
||||
double focusCount = 0.0;
|
||||
};
|
||||
|
||||
final class AIBehavior {
|
||||
//How many focuses we can manage in a tick
|
||||
uint focusPerTick = 2;
|
||||
|
||||
//The maximum colonizations this AI can do in one turn
|
||||
uint maxColonizations = UINT_MAX;
|
||||
//How many colonizations we're guaranteed to be able to do in one turn regardless of finances
|
||||
uint guaranteeColonizations = 2;
|
||||
//How many colonizations at most we can be doing at once
|
||||
uint maxConcurrentColonizations = UINT_MAX;
|
||||
//Whether this AI will colonize planets in systems owned by someone else
|
||||
// TODO: This should be partially ignored for border systems, so it can try to aggressively expand into the border
|
||||
bool colonizeEnemySystems = false;
|
||||
bool colonizeNeutralOwnedSystems = false;
|
||||
bool colonizeAllySystems = false;
|
||||
//How much this AI values claiming new systems instead of colonizing stuff in its existing ones
|
||||
double weightOutwardExpand = 2.0;
|
||||
//How much money this AI considers a colonization event to cost out of the budget
|
||||
int colonizeBudgetCost = 80;
|
||||
//Whether to do any generic expansion beyond any requests
|
||||
bool colonizeGenericExpand = true;
|
||||
//Latest percentage into a budget cycle that we still allow colonization
|
||||
double colonizeMaxBudgetProgress = 0.66;
|
||||
//Time after initial ownership change that an incomplete colonization is canceled
|
||||
double colonizeFailGraceTime = 100.0;
|
||||
//Time a planet that we failed to colonize is disregarded for colonization
|
||||
double colonizePenalizeTime = 9.0 * 60.0;
|
||||
|
||||
//Maximum amount of scouting missions that can be performed simultaneously
|
||||
uint maxScoutingMissions = UINT_MAX;
|
||||
//Minimum time after losing vision over a system that we can scout it again
|
||||
double minScoutingInterval = 3.0 * 60.0;
|
||||
//Weight that it gives to exploring things near our empire instead of greedily exploring nearby things
|
||||
double exploreBorderWeight = 2.0;
|
||||
//How long we consider all fleets viable for scouting with
|
||||
double scoutAllTimer = 3.0 * 60.0;
|
||||
//How many scouts we want to have active
|
||||
uint scoutsActive = 2;
|
||||
//How many scanning missions we can do at once
|
||||
uint maxScanningMissions = 1;
|
||||
//Whether to prioritize scouting over scanning if we only have one scout
|
||||
bool prioritizeScoutOverScan = true;
|
||||
|
||||
//Weights for what to do in generic planet development
|
||||
// Leveling up an existing development focus
|
||||
double focusDevelopWeight = 1.0;
|
||||
// Colonizing a new scalable or high tier to focus on
|
||||
double focusColonizeNewWeight = 4.0;
|
||||
// Colonizing a new high tier resource to import to one of our focuses
|
||||
double focusColonizeHighTierWeight = 1.0;
|
||||
|
||||
//How many potential designs are evaluated before choosing the best one
|
||||
uint designEvaluateCount = 10;
|
||||
//How long a fleet has to be fully idle before it returns to its stationed system
|
||||
double fleetIdleReturnStationedTime = 60.0;
|
||||
//How long we try to have a fleet be capable of firing before running out of supplies
|
||||
double fleetAimSupplyDuration = 2.0 * 60.0;
|
||||
|
||||
//How long a potential construction can take at most before we consider it unreasonable
|
||||
double constructionMaxTime = 10.0 * 60.0;
|
||||
//How long a factory has to have been idle for us to consider constructing labor storage
|
||||
double laborStoreIdleTimer = 60.0;
|
||||
//Maximum amount of time worth of labor we want to store in our warehouses
|
||||
double laborStoreMaxFillTime = 60.0 * 10.0;
|
||||
//Whether to use labor to build asteroids in the background
|
||||
bool backgroundBuildAsteroids = true;
|
||||
//Whether to choose the best resource on an asteroid, instead of doing it randomly
|
||||
bool chooseAsteroidResource = true;
|
||||
//Whether to distribute labor to shipyards when planets are idle
|
||||
bool distributeLaborExports = true;
|
||||
//Whether to build a shipyard to consolidate multiple planets of labor where possible
|
||||
bool consolidateLaborExports = true;
|
||||
//Estimate amount of labor spent per point of support ship size
|
||||
double estSizeSupportLabor = 0.25;
|
||||
|
||||
//Maximum combat fleets we can have in service at once (counts starting fleet(s))
|
||||
uint maxActiveFleets = UINT_MAX;
|
||||
//How much flagship size we try to make per available money
|
||||
double shipSizePerMoney = 1.0 / 3.5;
|
||||
//How much flagship size we try to make per available labor
|
||||
double shipSizePerLabor = 1.0 / 0.33;
|
||||
//How much maintenance we expect per ship size
|
||||
double maintenancePerShipSize = 2.0;
|
||||
//Minimum percentage increase in size before we decide to retrofit a flagship to be bigger
|
||||
double shipRetrofitThreshold = 0.5;
|
||||
//Whether to retrofit our free starting fleet if appropriate
|
||||
bool retrofitFreeFleets = false;
|
||||
//Minimum percentage of average current flagship size new fleets should be
|
||||
double flagshipBuildMinAvgSize = 1.00;
|
||||
//Minimum game time before we consider constructing new flagships
|
||||
double flagshipBuildMinGameTime = 4.0 * 60.0;
|
||||
//Whether to build factories when we need labor
|
||||
bool buildFactoryForLabor = true;
|
||||
//Whether to build warehouses when we're not using labor
|
||||
bool buildLaborStorage = true;
|
||||
//Whether factories can queue labor resource imports when needed
|
||||
bool allowRequestLaborImports = true;
|
||||
//Whether fleets with ghosted supports attempt to rebuild the ghosts or just clear them
|
||||
bool fleetsRebuildGhosts = true;
|
||||
//When trying to order supports on a fleet, wait for the planet to construct its supports so we can claim them
|
||||
bool supportOrderWaitOnFactory = true;
|
||||
|
||||
//How much stronger we need to be than a remnant fleet to clear it
|
||||
double remnantOverkillFactor = 1.5;
|
||||
//Whether to allow idle fleets to be sent to clear remnants
|
||||
// Modified by Relations
|
||||
bool remnantAllowArbitraryClear = true;
|
||||
|
||||
//Whether we should aggressively try to take out enemies
|
||||
bool aggressive = false;
|
||||
//Whether to become aggressive after we get boxed in and can no longer expand anywhere
|
||||
bool aggressiveWhenBoxedIn = false;
|
||||
//Whether we should never declare war ourselves
|
||||
bool passive = false;
|
||||
//Whether to hate human players the most
|
||||
bool biased = false;
|
||||
//How much stronger we need to be than someone to declare war out of hatred
|
||||
double hatredWarOverkill = 0.5;
|
||||
//How much stronger we need to be than someone to try to take them out in an aggressive war
|
||||
double aggressiveWarOverkill = 1.5;
|
||||
//How much stronger we want to be before we attack a system
|
||||
double attackStrengthOverkill = 1.5;
|
||||
//How many battles we can be performing at once
|
||||
uint maxBattles = UINT_MAX;
|
||||
//How much we try to overkill while fighting
|
||||
double battleStrengthOverkill = 1.5;
|
||||
//How many fleets we don't commit to attacks when we're already currently fighting
|
||||
uint battleReserveFleets = 1;
|
||||
//How much extra supply we try to have before starting a capture, to make sure we can actually do it
|
||||
double captureSupplyEstimate = 1.5;
|
||||
//Maximum hop distance we use as staging areas for our attacks
|
||||
int stagingMaxHops = 5;
|
||||
//If our fleet fill is less than this, immediately move back to factory from staging
|
||||
double stagingToFactoryFill = 0.6;
|
||||
|
||||
//How much ftl is reserved for critical applications
|
||||
double ftlReservePctCritical = 0.25;
|
||||
//How much ftl is reserved to not be used for background applications
|
||||
double ftlReservePctNormal = 0.25;
|
||||
|
||||
//How many artifacts we consider where to use per focus turn
|
||||
uint artifactFocusConsiderCount = 2;
|
||||
|
||||
//How long after trying to build a generically requested building we give up
|
||||
double genericBuildExpire = 3.0 * 60.0;
|
||||
|
||||
//How much the hate in a relationship decays to every minute
|
||||
double hateDecayRate = 0.9;
|
||||
//How much weaker we need to be to even consider surrender
|
||||
double surrenderMinStrength = 0.5;
|
||||
//How many of our total war points have to be taken by an empire for us to surrender
|
||||
double acceptSurrenderRatio = 0.75;
|
||||
double offerSurrenderRatio = 0.5;
|
||||
|
||||
void setDifficulty(int diff, uint flags) {
|
||||
//This changes the behavior values based on difficulty and flags
|
||||
if(flags & AIF_Aggressive != 0)
|
||||
aggressive = true;
|
||||
if(flags & AIF_Passive != 0)
|
||||
passive = true;
|
||||
if(flags & AIF_Biased != 0)
|
||||
biased = true;
|
||||
|
||||
//Low difficulties can't colonize as many things at once
|
||||
if(diff <= 0) {
|
||||
maxConcurrentColonizations = 1;
|
||||
guaranteeColonizations = 1;
|
||||
weightOutwardExpand = 0.5;
|
||||
}
|
||||
else if(diff <= 1) {
|
||||
maxConcurrentColonizations = 2;
|
||||
weightOutwardExpand = 1.0;
|
||||
}
|
||||
|
||||
//Hard AI becomes aggressive when it gets boxed in
|
||||
aggressiveWhenBoxedIn = diff >= 2;
|
||||
|
||||
//Easy difficulty can't attack and defend at the same time
|
||||
if(diff <= 0)
|
||||
maxBattles = 1;
|
||||
|
||||
//Low difficulties aren't as good at managing labor
|
||||
if(diff <= 0) {
|
||||
distributeLaborExports = false;
|
||||
consolidateLaborExports = false;
|
||||
buildLaborStorage = false;
|
||||
}
|
||||
else if(diff <= 1) {
|
||||
consolidateLaborExports = false;
|
||||
}
|
||||
|
||||
//Low difficulties aren't as good at managing fleets
|
||||
if(diff <= 0) {
|
||||
maxActiveFleets = 2;
|
||||
retrofitFreeFleets = true;
|
||||
}
|
||||
|
||||
//Low difficulties aren't as good at scouting
|
||||
if(diff <= 1)
|
||||
scoutAllTimer = 0.0;
|
||||
|
||||
//Low difficulties are worse at designing
|
||||
if(diff <= 0)
|
||||
designEvaluateCount = 3;
|
||||
else if(diff <= 1)
|
||||
designEvaluateCount = 8;
|
||||
else
|
||||
designEvaluateCount = 12;
|
||||
|
||||
//Easy is a bit slow
|
||||
if(diff <= 0)
|
||||
focusPerTick = 1;
|
||||
else if(diff >= 2)
|
||||
focusPerTick = 3;
|
||||
}
|
||||
};
|
||||
|
||||
final class AIDefs {
|
||||
const BuildingType@ Factory;
|
||||
const BuildingType@ LaborStorage;
|
||||
const OrbitalModule@ Shipyard;
|
||||
};
|
||||
|
||||
final class AI : AIController, Savable {
|
||||
Empire@ empire;
|
||||
AIBehavior behavior;
|
||||
AIDefs defs;
|
||||
|
||||
int cycleId = -1;
|
||||
uint componentCycle = 0;
|
||||
uint addedComponents = 0;
|
||||
|
||||
uint majorMask = 0;
|
||||
uint difficulty = 0;
|
||||
uint flags = 0;
|
||||
bool isLoading = false;
|
||||
|
||||
array<IAIComponent@> components;
|
||||
array<ProfileData> profileData;
|
||||
IAIComponent@ fleets;
|
||||
IAIComponent@ budget;
|
||||
IAIComponent@ colonization;
|
||||
IAIComponent@ resources;
|
||||
IAIComponent@ planets;
|
||||
IAIComponent@ systems;
|
||||
IAIComponent@ scouting;
|
||||
IAIComponent@ development;
|
||||
IAIComponent@ designs;
|
||||
IAIComponent@ construction;
|
||||
IAIComponent@ military;
|
||||
IAIComponent@ movement;
|
||||
IAIComponent@ creeping;
|
||||
IAIComponent@ relations;
|
||||
IAIComponent@ intelligence;
|
||||
IAIComponent@ war;
|
||||
IAIComponent@ research;
|
||||
IAIComponent@ energy;
|
||||
IAIComponent@ diplomacy;
|
||||
IAIComponent@ consider;
|
||||
IAIComponent@ orbitals;
|
||||
|
||||
IAIComponent@ ftl;
|
||||
IAIComponent@ race;
|
||||
|
||||
IAIComponent@ invasion;
|
||||
|
||||
void createComponents() {
|
||||
//NOTE: This is also save/load order, so
|
||||
//make sure to add loading logic when changing this list
|
||||
@budget = add(createBudget());
|
||||
@planets = add(createPlanets());
|
||||
@resources = add(createResources());
|
||||
@colonization = add(createColonization());
|
||||
@systems = add(createSystems());
|
||||
@fleets = add(createFleets());
|
||||
@scouting = add(createScouting());
|
||||
@development = add(createDevelopment());
|
||||
@designs = add(createDesigns());
|
||||
@construction = add(createConstruction());
|
||||
@military = add(createMilitary());
|
||||
@movement = add(createMovement());
|
||||
@creeping = add(createCreeping());
|
||||
@relations = add(createRelations());
|
||||
@intelligence = add(createIntelligence());
|
||||
@war = add(createWar());
|
||||
@research = add(createResearch());
|
||||
@energy = add(createEnergy());
|
||||
@diplomacy = add(createDiplomacy());
|
||||
@consider = add(createConsider());
|
||||
@orbitals = add(createOrbitals());
|
||||
|
||||
//Make FTL component
|
||||
if(empire.hasTrait(getTraitID("Hyperdrive")))
|
||||
@ftl = add(createHyperdrive());
|
||||
else if(empire.hasTrait(getTraitID("Gate")))
|
||||
@ftl = add(createGate());
|
||||
else if(empire.hasTrait(getTraitID("Fling")))
|
||||
@ftl = add(createFling());
|
||||
else if(empire.hasTrait(getTraitID("Slipstream")))
|
||||
@ftl = add(createSlipstream());
|
||||
else if(empire.hasTrait(getTraitID("Jumpdrive")))
|
||||
@ftl = add(createJumpdrive());
|
||||
|
||||
//Make racial component
|
||||
if(empire.hasTrait(getTraitID("Verdant")))
|
||||
@race = add(createVerdant());
|
||||
else if(empire.hasTrait(getTraitID("Mechanoid")))
|
||||
@race = add(createMechanoid());
|
||||
else if(empire.hasTrait(getTraitID("StarChildren")))
|
||||
@race = add(createStarChildren());
|
||||
else if(empire.hasTrait(getTraitID("Extragalactic")))
|
||||
@race = add(createExtragalactic());
|
||||
else if(empire.hasTrait(getTraitID("Linked")))
|
||||
@race = add(createLinked());
|
||||
else if(empire.hasTrait(getTraitID("Devout")))
|
||||
@race = add(createDevout());
|
||||
else if(empire.hasTrait(getTraitID("Ancient")))
|
||||
@race = add(createAncient());
|
||||
|
||||
//Misc components
|
||||
if(hasInvasionMap() || addedComponents & AC_Invasion != 0) {
|
||||
@invasion = add(createInvasion());
|
||||
addedComponents |= AC_Invasion;
|
||||
}
|
||||
|
||||
//if(empire is playerEmpire) {
|
||||
//log(race);
|
||||
// log(colonization);
|
||||
// log(resources);
|
||||
// log(construction);
|
||||
//}
|
||||
//log(intelligence);
|
||||
//logAll();
|
||||
logCritical();
|
||||
|
||||
profileData.length = components.length;
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i)
|
||||
components[i].create();
|
||||
}
|
||||
|
||||
void createGeneral() {
|
||||
}
|
||||
|
||||
void init(Empire& emp, EmpireSettings& settings) {
|
||||
@this.empire = emp;
|
||||
flags = settings.aiFlags;
|
||||
difficulty = settings.difficulty;
|
||||
behavior.setDifficulty(difficulty, flags);
|
||||
|
||||
createComponents();
|
||||
}
|
||||
|
||||
int getDifficultyLevel() {
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
void load(SaveFile& file) {
|
||||
file >> empire;
|
||||
file >> cycleId;
|
||||
file >> majorMask;
|
||||
file >> difficulty;
|
||||
file >> flags;
|
||||
if(file >= SV_0153)
|
||||
file >> addedComponents;
|
||||
behavior.setDifficulty(difficulty, flags);
|
||||
createComponents();
|
||||
createGeneral();
|
||||
|
||||
uint loadCnt = 0;
|
||||
file >> loadCnt;
|
||||
loadCnt = loadCnt;
|
||||
for(uint i = 0; i < loadCnt; ++i) {
|
||||
double prevFocus = 0;
|
||||
file >> prevFocus;
|
||||
components[i].setPrevFocus(prevFocus);
|
||||
file >> components[i];
|
||||
|
||||
uint check = 0;
|
||||
file >> check;
|
||||
if(check != GUARD)
|
||||
error("ERROR: AI Load error detected in component "+addrstr(components[i])+" of "+empire.name);
|
||||
}
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i)
|
||||
components[i].postLoad(this);
|
||||
isLoading = true;
|
||||
}
|
||||
|
||||
void save(SaveFile& file) {
|
||||
file << empire;
|
||||
file << cycleId;
|
||||
file << majorMask;
|
||||
file << difficulty;
|
||||
file << flags;
|
||||
file << addedComponents;
|
||||
uint saveCnt = components.length;
|
||||
file << saveCnt;
|
||||
for(uint i = 0; i < saveCnt; ++i) {
|
||||
file << components[i].getPrevFocus();
|
||||
file << components[i];
|
||||
file << GUARD;
|
||||
}
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i)
|
||||
components[i].postSave(this);
|
||||
}
|
||||
|
||||
void log(IAIComponent@ comp) {
|
||||
if(comp is null)
|
||||
return;
|
||||
comp.setLog();
|
||||
comp.setLogCritical();
|
||||
}
|
||||
|
||||
void logCritical() {
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i)
|
||||
components[i].setLogCritical();
|
||||
}
|
||||
|
||||
void logAll() {
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i) {
|
||||
components[i].setLog();
|
||||
components[i].setLogCritical();
|
||||
}
|
||||
}
|
||||
|
||||
IAIComponent@ add(IAIComponent& component) {
|
||||
component.set(this);
|
||||
components.insertLast(component);
|
||||
return component;
|
||||
}
|
||||
|
||||
void init(Empire& emp) {
|
||||
majorMask = 0;
|
||||
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
|
||||
Empire@ emp = getEmpire(i);
|
||||
if(emp.major)
|
||||
majorMask |= emp.mask;
|
||||
}
|
||||
|
||||
createGeneral();
|
||||
}
|
||||
|
||||
bool hasStarted = false;
|
||||
void tick(Empire& emp, double time) {
|
||||
if(isLoading) {
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i)
|
||||
components[i].loadFinalize(this);
|
||||
isLoading = false;
|
||||
hasStarted = true;
|
||||
}
|
||||
else if(!hasStarted) {
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i)
|
||||
components[i].start();
|
||||
hasStarted = true;
|
||||
}
|
||||
else if(emp.Victory == -1) {
|
||||
//Don't do anything when actually defeated
|
||||
return;
|
||||
}
|
||||
|
||||
//Manage gametime-specific behaviors
|
||||
behavior.colonizeGenericExpand = gameTime >= 6.0 * 60.0;
|
||||
|
||||
//Find cycled turns
|
||||
int curCycle = emp.BudgetCycleId;
|
||||
if(curCycle != cycleId) {
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i)
|
||||
components[i].turn();
|
||||
cycleId = curCycle;
|
||||
}
|
||||
|
||||
//Generic ticks
|
||||
double startTime = getExactTime();
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i) {
|
||||
auto@ comp = components[i];
|
||||
comp.tick(time);
|
||||
|
||||
double endTime = getExactTime();
|
||||
//double ms = 1000.0 * (endTime - startTime);
|
||||
startTime = endTime;
|
||||
|
||||
//auto@ dat = profileData[i];
|
||||
//dat.tickPeak = max(dat.tickPeak, ms);
|
||||
//dat.tickAvg += ms;
|
||||
//dat.tickCount += 1.0;
|
||||
}
|
||||
|
||||
//Do focuseds tick on components
|
||||
uint focusCount = behavior.focusPerTick;
|
||||
if(ai_full_speed.value == 1.0)
|
||||
focusCount = max(uint(round((time / 0.25) * behavior.focusPerTick)), behavior.focusPerTick);
|
||||
double allocStart = startTime;
|
||||
|
||||
for(uint n = 0; n < focusCount; ++n) {
|
||||
componentCycle = (componentCycle+1) % components.length;
|
||||
auto@ focusComp = components[componentCycle];
|
||||
focusComp.focusTick(gameTime - focusComp.getPrevFocus());
|
||||
focusComp.setPrevFocus(gameTime);
|
||||
|
||||
double endTime = getExactTime();
|
||||
//double ms = 1000.0 * (endTime - startTime);
|
||||
startTime = endTime;
|
||||
if(endTime - allocStart > 4000.0)
|
||||
break;
|
||||
|
||||
//auto@ dat = profileData[componentCycle];
|
||||
//dat.focusPeak = max(dat.focusPeak, ms);
|
||||
//dat.focusAvg += ms;
|
||||
//dat.focusCount += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void dumpProfile() {
|
||||
for(uint i = 0, cnt = components.length; i < cnt; ++i) {
|
||||
auto@ c = profileData[i];
|
||||
print(pad(addrstr(components[i]), 40)+" tick peak "+toString(c.tickPeak,2)+" tick avg "+toString(c.tickAvg/c.tickCount, 2)
|
||||
+" focus peak "+toString(c.focusPeak,2)+" focus avg "+toString(c.focusAvg/c.focusCount, 2));
|
||||
}
|
||||
}
|
||||
|
||||
void resetProfile() {
|
||||
for(uint i = 0, cnt = profileData.length; i < cnt; ++i) {
|
||||
auto@ c = profileData[i];
|
||||
c.tickPeak = 0.0;
|
||||
c.tickAvg = 0.0;
|
||||
c.tickCount = 0.0;
|
||||
c.focusPeak = 0.0;
|
||||
c.focusAvg = 0.0;
|
||||
c.focusCount = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
uint get_mask() {
|
||||
return empire.mask;
|
||||
}
|
||||
|
||||
uint get_teamMask() {
|
||||
//TODO
|
||||
return empire.mask;
|
||||
}
|
||||
|
||||
uint get_visionMask() {
|
||||
return majorMask & empire.visionMask;
|
||||
}
|
||||
|
||||
uint get_allyMask() {
|
||||
return empire.mutualDefenseMask | empire.ForcedPeaceMask.value;
|
||||
}
|
||||
|
||||
uint get_enemyMask() {
|
||||
return empire.hostileMask & majorMask;
|
||||
}
|
||||
|
||||
uint get_neutralMask() {
|
||||
return majorMask & ~allyMask & ~mask & ~enemyMask;
|
||||
}
|
||||
|
||||
uint get_otherMask() {
|
||||
return majorMask & ~mask;
|
||||
}
|
||||
|
||||
string pad(const string& input, uint width) {
|
||||
string str = input;
|
||||
while(str.length < width)
|
||||
str += " ";
|
||||
return str;
|
||||
}
|
||||
|
||||
void print(const string& info, Object@ related = null, double value = INFINITY, bool flag = false, Empire@ emp = null) {
|
||||
string str = info;
|
||||
if(related !is null)
|
||||
str = pad(related.name, 16)+" | "+str;
|
||||
str = pad("["+empire.index+": "+empire.name+" AI] ", 20)+str;
|
||||
str = formatGameTime(gameTime) + " " + str;
|
||||
if(value != INFINITY)
|
||||
str += " | Value = "+standardize(value, true);
|
||||
if(flag)
|
||||
str += " | FLAGGED On";
|
||||
if(emp !is null)
|
||||
str += " | Target = "+emp.name;
|
||||
::print(str);
|
||||
}
|
||||
|
||||
void debugAI() {}
|
||||
void commandAI(string cmd) {}
|
||||
void aiPing(Empire@ fromEmpire, vec3d position, uint type) {}
|
||||
void pause(Empire& emp) {}
|
||||
void resume(Empire& emp) {}
|
||||
vec3d get_aiFocus() { return vec3d(); }
|
||||
string getOpinionOf(Empire& emp, Empire@ other) { return ""; }
|
||||
int getStandingTo(Empire& emp, Empire@ other) { return 0; }
|
||||
};
|
||||
|
||||
AIController@ createWeaselAI() {
|
||||
return AI();
|
||||
}
|
||||
Reference in New Issue
Block a user