Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+338
View File
@@ -0,0 +1,338 @@
import hooks;
import artifacts;
import resources;
import ai.consider;
#section server
from empire import Creeps;
#section all
interface Artifacts {
Empire@ get_empire();
Considerer@ get_consider();
}
class ArtifactAI : Hook, ConsiderHook {
double consider(Considerer& cons, Object@ obj) const {
return 0.0;
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const {
return false;
}
};
class Value : ArtifactAI {
Document doc("Sets the value for the artifact to a basic amount.");
Argument value(AT_Decimal, doc="Value to set for the artifact.");
#section server
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
value *= this.value.decimal;
return true;
}
#section all
};
class ActivateOnBestFleet : ArtifactAI {
Document doc("This artifact should be activated on our strongest fleet that it can be.");
Argument value(AT_Decimal, "1.0", doc="Value for activating on the best fleet.");
Argument min_strength(AT_Decimal, "1000", doc="Minimum strength for a fleet to be considered for this.");
#section server
double consider(Considerer& cons, Object@ fleet) const override {
double str = fleet.getFleetStrength() * 0.001;
if(str < min_strength.decimal)
return 0.0;
if(!cons.artifact.canTarget(fleet))
return 0.0;
return str;
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
@ai.consider.artifact = c;
Object@ best = ai.consider.Fleets(this);
if(best !is null) {
c.setTarget(best);
value *= this.value.decimal;
return true;
}
else {
return false;
}
}
#section all
};
class ActivateOnBestPlanet : ArtifactAI {
Document doc("This artifact should be activated on our best planet that it can be.");
Argument value(AT_Decimal, "1.0", doc="Value for activating on the best planet.");
Argument min_population(AT_Decimal, "10", doc="Minimum population for a planet to be considered for this.");
#section server
double consider(Considerer& cons, Object@ planet) const override {
double pop = planet.population;
if(pop < min_population.decimal)
return 0.0;
if(!cons.artifact.canTarget(planet))
return 0.0;
return pop;
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
@ai.consider.artifact = c;
Object@ best = ai.consider.ImportantPlanets(this);
if(best !is null) {
c.setTarget(best);
value *= this.value.decimal;
return true;
}
else {
return false;
}
}
#section all
};
class AsCreatedResource : ArtifactAI {
Document doc("This artifact is used to spawn a new resource type on a planet that needs it.");
Argument resource(AT_PlanetResource, doc="Resource to match import requests to.");
Argument value(AT_Decimal, "1.0", doc="Value for activating this.");
Argument replaces_existing(AT_Boolean, "True", doc="Whether this can be used to replace an existing import of that type or not.");
#section server
double consider(Considerer& cons, Object@ requestedAt) const override {
if(!cons.artifact.canTarget(requestedAt))
return 0.0;
if(cons.currentSupplier !is null)
return 0.5;
return 1.0;
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
@ai.consider.artifact = c;
Object@ best = ai.consider.MatchingImportRequests(this, getResource(resource.integer), replaces_existing.boolean);
if(best !is null) {
c.setTarget(best);
value *= this.value.decimal;
return true;
}
else {
return false;
}
}
#section all
};
class ActivateInOwnedSystem : ArtifactAI {
Document doc("Activate this artifact on a position in an arbitrary owned system.");
Argument value(AT_Decimal, "1.0", doc="Value for activating this.");
#section server
double consider(Considerer& cons, Object@ obj) const override {
Region@ sys = cast<Region>(obj);
if(sys.PlanetsMask & ~cons.empire.mask != 0)
return randomd(0.4, 0.6);
return randomd(0.9, 1.1);
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
Region@ best = cast<Region>(ai.consider.OwnedSystems(this));
if(best !is null) {
vec3d position = best.position;
vec2d offset = random2d(best.radius * 0.4, best.radius * 0.85);
position.x += offset.x;
position.z += offset.y;
if(!c.canTargetPosition(position))
return false;
c.setTargetPosition(position);
if(best.PlanetsMask & ~ai.empire.mask != 0)
value *= 0.5;
value *= this.value.decimal;
return true;
}
else {
return false;
}
}
#section all
};
class ActivateNearOwnedSystem : ArtifactAI {
Document doc("Activate this artifact on a position placed outside an arbitrary owned system.");
Argument value(AT_Decimal, "1.0", doc="Value for activating this.");
Argument min_distance(AT_Decimal, "2000", doc="Minimum distance from the system boundary to place it.");
#section server
double consider(Considerer& cons, Object@ obj) const override {
Region@ sys = cast<Region>(obj);
if(sys.PlanetsMask & ~cons.empire.mask != 0)
return randomd(0.4, 0.6);
return randomd(0.9, 1.1);
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
Region@ best = cast<Region>(ai.consider.OwnedSystems(this));
if(best !is null) {
vec3d position = best.position;
vec2d offset = random2d(best.radius + min_distance.decimal, best.radius + min_distance.decimal * 2.0);
position.x += offset.x;
position.z += offset.y;
position.y += min_distance.decimal * randomd(0.0, 0.25);
if(!c.canTargetPosition(position))
return false;
c.setTargetPosition(position);
if(best.PlanetsMask & ~ai.empire.mask != 0)
value *= 0.5;
value *= this.value.decimal;
return true;
}
else {
return false;
}
}
#section all
};
class AsVisionGain : ArtifactAI {
Document doc("Activate this to gain vision over systems with other people in them we want to see.");
Argument value(AT_Decimal, "1.0", doc="Value for activating this.");
#section server
double consider(Considerer& cons, Object@ obj) const override {
Region@ sys = cast<Region>(obj);
if(sys.VisionMask & cons.empire.visionMask != 0)
return 0.0;
if(!cons.artifact.canTarget(sys))
return 0.0;
double w = 1.0;
if(sys.PlanetsMask & cons.empire.hostileMask != 0)
w *= 2.0;
return w * randomd(0.9, 1.1);
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
@ai.consider.artifact = c;
Region@ best = cast<Region>(ai.consider.OtherSystems(this));
if(best !is null) {
c.setTarget(best);
value *= this.value.decimal;
if(best.PlanetsMask & ai.empire.hostileMask != 0)
value *= 2.0;
return true;
}
else {
return false;
}
}
#section all
};
class RevenantPart : ArtifactAI {
Document doc("Special AI to deal with using parts of the revenant.");
#section server
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
//If we are subjugated don't use these
if(ai.empire.SubjugatedBy !is null)
return false;
value *= 10.0;
//If we have parts ourselves, weight more
value *= pow(2.0, ai.empire.RevenantParts);
//If an enemy has multilple parts, weight more
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ other = getEmpire(i);
if(!other.major || other !is ai.empire)
value *= pow(3.0, other.RevenantParts);
}
return true;
}
#section all
};
class ActivateAsPressureBoost : ArtifactAI {
Document doc("Activate this artifact on a planet to boost its pressure.");
Argument value(AT_Decimal, "1.0", doc="Value for activating on the best planet.");
Argument pressure_amount(AT_Decimal, "1.0", doc="Amount of pressure that is added.");
#section server
double consider(Considerer& cons, Object@ planet) const override {
auto@ res = getResource(planet.primaryResourceType);
if(res is null)
return 0.0;
if(res.totalPressure < 1)
return 0.0;
double pres = planet.totalPressure;
double cap = planet.pressureCap;
if(pres + pressure_amount.decimal > cap * 1.5)
return 0.0;
if(!cons.artifact.canTarget(planet))
return 0.0;
return 1.0;
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
@ai.consider.artifact = c;
Object@ best = ai.consider.SomePlanets(this);
Object@ existing = c.getTarget();
if(existing !is null && consider(ai.consider, existing) > ai.consider.selectedWeight)
@best = existing;
if(best !is null) {
c.setTarget(best);
value *= this.value.decimal;
return true;
}
else {
return false;
}
}
#section all
};
class ActivateOnRemnantStation : ArtifactAI {
Document doc("Find remnant stations to trigger this on.");
Argument value(AT_Decimal, "1.0", doc="Value for activating on the best station.");
#section server
double consider(Considerer& cons, Object@ obj) const override {
Region@ reg = cast<Region>(obj);
if(reg.getStrength(Creeps) > 0)
return 1.0;
return 0.0;
}
bool consider(Artifacts& ai, ArtifactConsider& c, double& value) const override {
@ai.consider.artifact = c;
Object@ best;
Object@ reg = cast<Region>(ai.consider.OwnedSystems(this));
if(reg !is null) {
Object@ en = reg.findEnemy(ai.empire, Creeps.mask, fleets=false, stations=true);
if(en !is null) {
if(c.canTarget(en))
@best = en;
}
}
Object@ existing = c.getTarget();
if(best is null && existing !is null && existing.valid && c.canTarget(existing))
@best = existing;
if(best !is null) {
c.setTarget(best);
value *= this.value.decimal;
return true;
}
else {
return false;
}
}
#section all
};
+141
View File
@@ -0,0 +1,141 @@
import hooks;
import buildings;
import resources;
import ai.consider;
interface Buildings : ConsiderComponent {
Empire@ get_empire();
Considerer@ get_consider();
bool requestsFTLStorage();
bool isBuilding(const BuildingType& type);
bool isFocus(Object@ obj);
void registerUse(BuildingUse use, const BuildingType& type);
};
enum BuildingUse {
BU_Factory,
BU_LaborStorage,
};
const array<string> BuildingUseName = {
"Factory",
"LaborStorage",
};
class BuildingAI : Hook, ConsiderHook {
double consider(Considerer& cons, Object@ obj) const {
return 0.0;
}
void register(Buildings& buildings, const BuildingType& type) const {
}
//Return the planet to build this building on
Object@ considerBuild(Buildings& buildings, const BuildingType& type) const {
return null;
}
};
class RegisterForUse : BuildingAI {
Document doc("Register this building for a particular use. Only one building can be used for a specific specialized use.");
Argument use(AT_Custom, doc="Specialized usage for this building.");
void register(Buildings& buildings, const BuildingType& type) const override {
for(uint i = 0, cnt = BuildingUseName.length; i < cnt; ++i) {
if(BuildingUseName[i] == use.str) {
buildings.registerUse(BuildingUse(i), type);
return;
}
}
}
};
class AsCreatedResource : BuildingAI {
Document doc("This building is used to spawn a new resource type on a planet that needs it.");
Argument resource(AT_PlanetResource, doc="Resource to match import requests to.");
Argument minimum_idle(AT_Decimal, "180", doc="Minimum amount of time the resource request has to have been idle to consider this.");
Argument minimum_colonize_idle(AT_Decimal, "180", doc="Minimum amount of time since we've colonized something matching the request before we consider building this.");
Argument minimum_gametime(AT_Decimal, "1500", doc="Minimum gametime that needs to have passed before we consider building this.");
#section server
double consider(Considerer& cons, Object@ requestedAt) const override {
double w = 1.0;
if(cons.currentSupplier !is null)
return 0.0;
if(cons.idleTime < minimum_idle.decimal)
return 0.0;
if(cons.timeSinceMatchingColonize() < minimum_colonize_idle.decimal)
return 0.0;
if(!cons.building.canBuildOn(requestedAt, ignoreState=true))
return 0.0;
return w;
}
Object@ considerBuild(Buildings& buildings, const BuildingType& type) const override {
if(gameTime < minimum_gametime.decimal)
return null;
@buildings.consider.building = type;
return buildings.consider.MatchingImportRequests(this, getResource(resource.integer), false);
}
#section all
};
class BuildForPressureCap : BuildingAI {
Document doc("Build this to increase the pressure capacity on a planet.");
Argument increase(AT_Integer, doc="Pressure this should increase the cap by.");
#section server
double consider(Considerer& cons, Object@ obj) const override {
double w = 1.0;
int pres = obj.totalPressure;
int cap = obj.pressureCap;
if(pres <= cap)
return 0.0;
if(obj.level <= 0)
return 0.0;
if(double(obj.population) < double(obj.maxPopulation) * 0.9)
return 0.0;
double eff = double(pres) / double(cap);
if(eff < 1.5 && cap + increase.integer > 2 * pres)
return 0.0;
if(!cons.building.canBuildOn(obj, ignoreState=true))
return 0.0;
return eff;
}
Object@ considerBuild(Buildings& buildings, const BuildingType& type) const override {
@buildings.consider.building = type;
return buildings.consider.SomePlanets(this);
}
#section all
};
class AsFTLStorage : BuildingAI {
Document doc("This building is built whenever more ftl storage is requested.");
#section server
double consider(Considerer& cons, Object@ obj) const override {
if(cast<Buildings>(cons.component).isFocus(obj))
return 0.0;
if(obj.emptyDevelopedTiles < 10)
return 0.0;
if(!cons.building.canBuildOn(obj, ignoreState=true))
return 0.0;
return 1.0;
}
Object@ considerBuild(Buildings& buildings, const BuildingType& type) const override {
if(!buildings.requestsFTLStorage())
return null;
if(buildings.isBuilding(type))
return null;
@buildings.consider.component = buildings;
@buildings.consider.building = type;
return buildings.consider.SomePlanets(this);
}
#section all
};
+75
View File
@@ -0,0 +1,75 @@
import resources;
import buildings;
export Considerer;
export ConsiderHook;
export ArtifactConsider;
export ConsiderComponent;
export ConsiderFilter;
interface ArtifactConsider {
void setTarget(Object@ obj);
Object@ getTarget();
bool canTarget(Object@ obj);
void setTargetPosition(const vec3d& pos);
vec3d getTargetPosition();
bool canTargetPosition(const vec3d& pos);
};
interface ConsiderComponent {
};
interface ConsiderFilter {
bool filter(Object@ obj);
};
interface Considerer {
Empire@ get_empire();
Object@ get_currentSupplier();
ArtifactConsider@ get_artifact();
void set_artifact(ArtifactConsider@ cons);
double get_selectedWeight();
double get_idleTime();
const BuildingType@ get_building();
void set_building(const BuildingType@ type);
ConsiderComponent@ get_component();
void set_component(ConsiderComponent@ comp);
void set_filter(ConsiderFilter@ filter);
//Consider all systems we currently have planets in
Object@ OwnedSystems(const ConsiderHook& hook, uint limit = uint(-1));
//Consider all systems on our empire borders
Object@ BorderSystems(const ConsiderHook& hook);
//Consider all systems we know other empires have planets in
Object@ OtherSystems(const ConsiderHook& hook);
//Consider all our fleets
Object@ Fleets(const ConsiderHook& hook);
//Consider planets we own that are important in some way
Object@ ImportantPlanets(const ConsiderHook& hook);
//Consider all our planets
Object@ AllPlanets(const ConsiderHook& hook);
//Consider a random selection of our planets
Object@ SomePlanets(const ConsiderHook& hook, uint count = 5, bool alwaysImportant = true);
//Consider any planets we're using as factories to build things
Object@ FactoryPlanets(const ConsiderHook& hook);
//Consider import requests that could be satisfied by the specified resource type
Object@ MatchingImportRequests(const ConsiderHook& hook, const ResourceType@ type, bool considerExisting);
//Time since the last colonization of theh import request we're currently considering
double timeSinceMatchingColonize();
};
interface ConsiderHook {
double consider(Considerer& cons, Object@ object) const;
};
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
import hooks;
import orbitals;
import ai.consider;
interface AIOrbitals : ConsiderComponent {
Empire@ get_empire();
Considerer@ get_consider();
void registerUse(OrbitalUse use, const OrbitalModule& type);
};
enum OrbitalUse {
OU_Shipyard,
};
const array<string> OrbitalUseName = {
"Shipyard",
};
class OrbitalAIHook : Hook, ConsiderHook {
double consider(Considerer& cons, Object@ obj) const {
return 0.0;
}
void register(AIOrbitals& orbitals, const OrbitalModule& type) const {
}
//Return a system or a planet to build this orbital in/around
Object@ considerBuild(AIOrbitals& orbitals, const OrbitalModule& type) const {
return null;
}
};
class RegisterForUse : OrbitalAIHook {
Document doc("Register this orbital for a particular use. Only one orbital can be used for a specific specialized use.");
Argument use(AT_Custom, doc="Specialized usage for this orbital.");
void register(AIOrbitals& orbitals, const OrbitalModule& type) const override {
for(uint i = 0, cnt = OrbitalUseName.length; i < cnt; ++i) {
if(OrbitalUseName[i] == use.str) {
orbitals.registerUse(OrbitalUse(i), type);
return;
}
}
}
};
+100
View File
@@ -0,0 +1,100 @@
import hooks;
import resources;
import ai.consider;
interface AIResources : ConsiderComponent {
Empire@ get_empire();
Considerer@ get_consider();
};
class ResourceAI : Hook, ConsiderHook {
double consider(Considerer& cons, Object@ obj) const {
return 1.0;
}
//If the AI is not currently using this resource for anything
//that explicitly requested it, this hook determines where it will
//be distributed to in the meantime. Returning null means it will not be
//placed anywhere.
Object@ distribute(AIResources& ai, const ResourceType& type, Object@ current) const {
return null;
}
};
class DistributeToImportantPlanet : ResourceAI {
Document doc("This resource goes to important planets to make them better.");
#section server
double consider(Considerer& cons, Object@ obj) const {
return 1.0 + obj.level;
}
Object@ distribute(AIResources& ai, const ResourceType& type, Object@ current) const {
if(current !is null)
return current;
return ai.consider.ImportantPlanets(this);
}
#section all
};
class DistributeToLaborUsing : ResourceAI {
Document doc("This resource gets distributed to planets building things with labor.");
Argument remove_idle(AT_Boolean, "True", doc="Remove the resource again when the target goes idle.");
#section server
double consider(Considerer& cons, Object@ obj) const {
if(obj.constructionCount == 0)
return 0.0;
return 1.0;
}
Object@ distribute(AIResources& ai, const ResourceType& type, Object@ current) const {
if(current !is null) {
if(!remove_idle.boolean || current.constructionCount != 0)
return current;
}
return ai.consider.FactoryPlanets(this);
}
#section all
};
class DistributeAsLocalPressureBoost : ResourceAI {
Document doc("This resource gets distributed to boost the native pressure of a resource.");
Argument amount(AT_Integer, doc="Amount of pressure this boosts by.");
#section server
double consider(Considerer& cons, Object@ obj) const {
auto@ resource = getResource(obj.primaryResourceType);
if(resource is null)
return 0.0;
if(resource.totalPressure <= 0)
return 0.0;
bool havePressure = obj.owner.HasPressure != 0.0;
if(havePressure) {
int presCap = obj.pressureCap;
int presUse = obj.totalPressure;
if(presUse + amount.integer <= presCap)
return 1.0;
return 0.0;
}
else {
return 1.0;
}
}
Object@ distribute(AIResources& ai, const ResourceType& type, Object@ current) const {
if(current !is null) {
int presCap = current.pressureCap;
int presUse = current.totalPressure;
if(presUse <= presCap)
return current;
}
Object@ check = ai.consider.SomePlanets(this);
if(check !is null)
return check;
else
return current;
}
#section all
};