691 lines
18 KiB
ActionScript
691 lines
18 KiB
ActionScript
#priority init 2000
|
|
import tile_resources;
|
|
from saving import SaveIdentifier, SaveVersion;
|
|
import util.formatting;
|
|
import biomes;
|
|
import hooks;
|
|
|
|
export BuildingClass;
|
|
export BuildingType;
|
|
export SurfaceBuilding;
|
|
export getBuildingTypeCount, getBuildingType;
|
|
|
|
namespace buildings {
|
|
::array<::BuildingType@> types;
|
|
::dictionary typeIdents;
|
|
};
|
|
|
|
enum BuildingClass {
|
|
BC_Building,
|
|
BC_Civilian,
|
|
BC_City,
|
|
};
|
|
|
|
tidy class BiomeAffinity {
|
|
const Biome@ biome;
|
|
double factor = 0.0;
|
|
string def;
|
|
|
|
BiomeAffinity(const string& spec) {
|
|
int pos = spec.findFirst(" ");
|
|
if(pos == -1) {
|
|
def = spec;
|
|
}
|
|
else {
|
|
def = spec.substr(0, pos);
|
|
factor = toDouble(spec.substr(pos+1));
|
|
}
|
|
}
|
|
|
|
void init() {
|
|
@biome = getBiome(def);
|
|
if(biome is null)
|
|
error("Invalid affinity biome: "+def);
|
|
}
|
|
};
|
|
|
|
tidy final class BuildingType {
|
|
uint id = 0;
|
|
string ident;
|
|
|
|
string name;
|
|
string description;
|
|
string category;
|
|
Sprite sprite;
|
|
|
|
string upgradesFrom;
|
|
const BuildingType@ base;
|
|
array<const BuildingType@> upgrades;
|
|
|
|
array<IBuildingHook@> hooks;
|
|
array<Hook@> ai;
|
|
|
|
array<BiomeAffinity@> buildAffinities;
|
|
array<BiomeAffinity@> maintainAffinities;
|
|
|
|
float hubWeight = 1.f;
|
|
BuildingClass cls = BC_Building;
|
|
|
|
double[] resources = double[](TR_COUNT, 0.f);
|
|
float[] saturates = float[](TR_COUNT, 0.f);
|
|
|
|
double totalResource = 0.f;
|
|
float totalSaturate = 0.f;
|
|
int pressureCapTaken = 0;
|
|
|
|
vec2u size(1, 1);
|
|
|
|
int baseBuildCost = 0;
|
|
int tileBuildCost = 0;
|
|
int baseMaintainCost = 0;
|
|
int tileMaintainCost = 0;
|
|
|
|
double buildTime = 3.0 * 60.0;
|
|
double laborCost = 0;
|
|
bool buildInQueue = false;
|
|
|
|
double getBuildTime(Object& obj) const {
|
|
double time = buildTime;
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].modBuildTime(obj, time);
|
|
return time;
|
|
}
|
|
|
|
string getTooltip(bool showName = true, bool showCost = true, bool showSize = true, bool showAffinity = true, Object@ valueObject = null, bool isOption = false) const {
|
|
string tt;
|
|
if(showName)
|
|
tt += format("[font=Medium][b]$1[/b][/font]\n", name);
|
|
tt += format("[vspace=4/][center][img=$1;$2x$3/][/center][vspace=4/]",
|
|
getSpriteDesc(sprite), toString(40*size.x,0), toString(40*size.y,0));
|
|
tt += description;
|
|
|
|
string vname, vvalue;
|
|
Sprite vicon;
|
|
Color color;
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i) {
|
|
if(hooks[i].getVariable(valueObject, vicon, vname, vvalue, color, isOption)) {
|
|
tt += format("[nl/]\n[img=$1;22][b][color=$4]$2[/color][/b] [offset=120]$3[/offset][/img]",
|
|
getSpriteDesc(vicon), vname, vvalue, toString(color));
|
|
color = colors::White;
|
|
}
|
|
}
|
|
if(showCost && !civilian) {
|
|
tt += "[nl/]\n";
|
|
if(showSize && (size.x > 1 || size.y > 1))
|
|
tt += format(locale::BLD_TT_SIZE, toString(size.x), toString(size.y))+"\n";
|
|
|
|
int bld = buildCostEst, mnt = maintainCostEst;
|
|
if(bld != 0 || mnt != 0)
|
|
tt += format(locale::BLD_TT_COST, formatMoney(bld, mnt));
|
|
|
|
if(showAffinity) {
|
|
for(uint n = 0, ncnt = buildAffinities.length; n < ncnt; ++n) {
|
|
auto@ aff = buildAffinities[n];
|
|
if(aff.biome is null)
|
|
continue;
|
|
if(aff.factor > 1)
|
|
tt += "[nl/]\n"+format(locale::BLD_TT_AFFINITY_BUILD_NEG, toString((aff.factor-1.0)*100,0)+"%", toString(aff.biome.color), aff.biome.name, getSpriteDesc(icons::Minus));
|
|
else
|
|
tt += "[nl/]\n"+format(locale::BLD_TT_AFFINITY_BUILD, toString((1.0-aff.factor)*100,0)+"%", toString(aff.biome.color), aff.biome.name, getSpriteDesc(icons::Plus));
|
|
}
|
|
for(uint n = 0, ncnt = maintainAffinities.length; n < ncnt; ++n) {
|
|
auto@ aff = maintainAffinities[n];
|
|
if(aff.biome is null)
|
|
continue;
|
|
if(aff.factor > 1)
|
|
tt += "[nl/]\n"+format(locale::BLD_TT_AFFINITY_MAINT_NEG, toString((aff.factor-1.0)*100,0)+"%", toString(aff.biome.color), aff.biome.name, getSpriteDesc(icons::Minus));
|
|
else
|
|
tt += "[nl/]\n"+format(locale::BLD_TT_AFFINITY_MAINT, toString((1.0-aff.factor)*100,0)+"%", toString(aff.biome.color), aff.biome.name, getSpriteDesc(icons::Plus));
|
|
}
|
|
if(!civilian && (tileBuildCost != 0 || tileMaintainCost != 0))
|
|
tt += "[nl/]\n"+locale::BLD_TT_DEV;
|
|
}
|
|
}
|
|
else {
|
|
if(showSize && (size.x > 1 || size.y > 1)) {
|
|
tt += "[nl/]\n";
|
|
tt += format(locale::BLD_TT_SIZE, toString(size.x), toString(size.y));
|
|
}
|
|
}
|
|
return tt;
|
|
}
|
|
|
|
bool canProgress(Object& obj) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i) {
|
|
if(!hooks[i].canProgress(obj))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool consume(Object& obj) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i) {
|
|
if(!hooks[i].consume(obj)) {
|
|
for(uint j = 0; j < i; ++j)
|
|
hooks[j].reverse(obj);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void reverseConsume(Object& obj) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].reverse(obj);
|
|
}
|
|
|
|
double getMaintenanceFor(const Biome@ biome) const {
|
|
double cost = tileMaintainCost;
|
|
for(uint i = 0, cnt = maintainAffinities.length; i < cnt; ++i) {
|
|
if(maintainAffinities[i].biome is biome)
|
|
cost *= maintainAffinities[i].factor;
|
|
}
|
|
return cost;
|
|
}
|
|
|
|
bool get_civilian() const {
|
|
return cls != BC_Building;
|
|
}
|
|
|
|
bool canBuildOn(Object@ obj, bool ignoreState = false) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i) {
|
|
if(!hooks[i].canBuildOn(obj, ignoreState))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool canRemove(Object@ obj) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i) {
|
|
if(!hooks[i].canRemove(obj))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int get_buildCostEst() const {
|
|
return baseBuildCost + size.x * size.y * tileBuildCost;
|
|
}
|
|
|
|
int get_maintainCostEst() const {
|
|
return baseMaintainCost + size.x * size.y * tileMaintainCost;
|
|
}
|
|
|
|
vec2u getCenter() const {
|
|
vec2u center(floor(float(size.x) / 2.f), floor(float(size.y) / 2.f));
|
|
center.x = clamp(center.x, 0, size.x-1);
|
|
center.y = clamp(center.y, 0, size.y-1);
|
|
return center;
|
|
}
|
|
|
|
void startConstruction(Object& obj, SurfaceBuilding@ bld) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].startConstruction(obj, bld);
|
|
}
|
|
|
|
void cancelConstruction(Object& obj, SurfaceBuilding@ bld) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].cancelConstruction(obj, bld);
|
|
}
|
|
|
|
void complete(Object& obj, SurfaceBuilding@ bld) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].complete(obj, bld);
|
|
}
|
|
|
|
void ownerChange(Object& obj, SurfaceBuilding@ bld, Empire@ prevOwner, Empire@ newOwner) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].ownerChange(obj, bld, prevOwner, newOwner);
|
|
}
|
|
|
|
void remove(Object& obj, SurfaceBuilding@ bld) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].remove(obj, bld);
|
|
}
|
|
|
|
void tick(Object& obj, SurfaceBuilding@ bld, double time) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].tick(obj, bld, time);
|
|
}
|
|
|
|
void save(SurfaceBuilding@ bld, SaveFile& file) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].save(bld, file);
|
|
}
|
|
|
|
void load(SurfaceBuilding@ bld, SaveFile& file) const {
|
|
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
|
|
hooks[i].load(bld, file);
|
|
}
|
|
};
|
|
|
|
interface IBuildingHook {
|
|
void initialize(BuildingType@ type, uint index);
|
|
void startConstruction(Object& obj, SurfaceBuilding@ bld) const;
|
|
void cancelConstruction(Object& obj, SurfaceBuilding@ bld) const;
|
|
void complete(Object& obj, SurfaceBuilding@ bld) const;
|
|
void ownerChange(Object& obj, SurfaceBuilding@ bld, Empire@ prevOwner, Empire@ newOwner) const;
|
|
void remove(Object& obj, SurfaceBuilding@ bld) const;
|
|
void tick(Object& obj, SurfaceBuilding@ bld, double time) const;
|
|
void save(SurfaceBuilding@ bld, SaveFile& file) const;
|
|
void load(SurfaceBuilding@ bld, SaveFile& file) const;
|
|
bool canBuildOn(Object& obj, bool ignoreState = false) const;
|
|
bool canRemove(Object& obj) const;
|
|
bool getVariable(Object@ obj, Sprite& sprt, string& name, string& value, Color& color, bool isOption) const;
|
|
bool getCost(Object& obj, string& value, Sprite& icon) const;
|
|
bool consume(Object& obj) const;
|
|
void reverse(Object& obj) const;
|
|
void modBuildTime(Object& obj, double& time) const;
|
|
bool canProgress(Object& obj) const;
|
|
};
|
|
|
|
class BuildingHook : Hook, IBuildingHook {
|
|
uint hookIndex = 0;
|
|
void initialize(BuildingType@ type, uint index) { hookIndex = index; }
|
|
void startConstruction(Object& obj, SurfaceBuilding@ bld) const {}
|
|
void cancelConstruction(Object& obj, SurfaceBuilding@ bld) const {}
|
|
void complete(Object& obj, SurfaceBuilding@ bld) const {}
|
|
void ownerChange(Object& obj, SurfaceBuilding@ bld, Empire@ prevOwner, Empire@ newOwner) const {}
|
|
void remove(Object& obj, SurfaceBuilding@ bld) const {}
|
|
void tick(Object& obj, SurfaceBuilding@ bld, double time) const {}
|
|
void save(SurfaceBuilding@ bld, SaveFile& file) const {}
|
|
void load(SurfaceBuilding@ bld, SaveFile& file) const {}
|
|
bool canBuildOn(Object& obj, bool ignoreState = false) const { return true; }
|
|
bool canRemove(Object& obj) const { return true; }
|
|
bool getVariable(Object@ obj, Sprite& sprt, string& name, string& value, Color& color, bool isOption) const {
|
|
return false;
|
|
}
|
|
bool consume(Object& obj) const { return true; }
|
|
void reverse(Object& obj) const {}
|
|
bool getCost(Object& obj, string& value, Sprite& icon) const {
|
|
return false;
|
|
}
|
|
void modBuildTime(Object& obj, double& time) const {}
|
|
bool canProgress(Object& obj) const { return true; }
|
|
};
|
|
|
|
tidy final class SurfaceBuilding : Serializable, Savable {
|
|
vec2u position;
|
|
const BuildingType@ type;
|
|
float completion = 0.f;
|
|
bool disabled = false;
|
|
bool upgrading = false;
|
|
bool delta = false;
|
|
int cost = 0;
|
|
int cycle = -1;
|
|
Object@ tied;
|
|
array<any>@ data;
|
|
|
|
SurfaceBuilding() {}
|
|
SurfaceBuilding(const BuildingType@ Type) {
|
|
@type = Type;
|
|
if(type.hooks.length > 0)
|
|
@data = array<any>(type.hooks.length);
|
|
}
|
|
|
|
void write(Message& msg) {
|
|
msg.writeSmall(position.x);
|
|
msg.writeSmall(position.y);
|
|
msg.writeSmall(type.id);
|
|
msg << disabled;
|
|
msg << upgrading;
|
|
if(tied !is null) {
|
|
msg.write1();
|
|
msg << tied;
|
|
}
|
|
else {
|
|
msg.write0();
|
|
}
|
|
|
|
if(completion < 1.f) {
|
|
msg.write1();
|
|
msg.writeFixed(completion, 0, 1.f, 7);
|
|
}
|
|
else {
|
|
msg.write0();
|
|
}
|
|
}
|
|
|
|
void read(Message& msg) {
|
|
position.x = msg.readSmall();
|
|
position.y = msg.readSmall();
|
|
|
|
@type = getBuildingType(msg.readSmall());
|
|
|
|
msg >> disabled;
|
|
msg >> upgrading;
|
|
|
|
if(msg.readBit())
|
|
msg >> tied;
|
|
else
|
|
@tied = null;
|
|
|
|
if(msg.readBit()) {
|
|
completion = msg.readFixed(0, 1.f, 7);
|
|
}
|
|
else {
|
|
completion = 1.f;
|
|
}
|
|
}
|
|
|
|
void save(SaveFile& msg) {
|
|
msg << position;
|
|
msg.writeIdentifier(SI_Building, type.id);
|
|
msg << completion;
|
|
msg << disabled;
|
|
msg << upgrading;
|
|
msg << tied;
|
|
msg << cost;
|
|
msg << cycle;
|
|
|
|
if(completion >= 1.f)
|
|
type.save(this, msg);
|
|
}
|
|
|
|
void load(SaveFile& msg) {
|
|
msg >> position;
|
|
|
|
uint tid = msg.readIdentifier(SI_Building);
|
|
@type = getBuildingType(tid);
|
|
if(type.hooks.length > 0)
|
|
@data = array<any>(type.hooks.length);
|
|
|
|
msg >> completion;
|
|
msg >> disabled;
|
|
msg >> upgrading;
|
|
msg >> tied;
|
|
|
|
if(msg >= SV_0072) {
|
|
msg >> cost;
|
|
msg >> cycle;
|
|
}
|
|
|
|
if(completion >= 1.f || msg < SV_0136)
|
|
type.load(this, msg);
|
|
}
|
|
|
|
string getTooltip(Object@ obj = null) {
|
|
return type.getTooltip(showCost=false, showSize=false, valueObject=obj);
|
|
}
|
|
};
|
|
|
|
void parseLine(ReadFile& file, string& line, BuildingType@ bld) {
|
|
if(line.findFirst("(") == -1) {
|
|
//Resource line
|
|
array<string>@ decls = line.split(",");
|
|
for(uint i = 0, cnt = decls.length; i < cnt; ++i) {
|
|
array<string>@ parts = decls[i].split(" ");
|
|
if(parts.length != 3) {
|
|
file.error("Invalid building effect: "+escape(decls[i].trimmed()));
|
|
continue;
|
|
}
|
|
|
|
uint resource = getTileResource(parts[1]);
|
|
if(resource == TR_INVALID) {
|
|
file.error("Invalid building effect: "+escape(decls[i].trimmed()));
|
|
continue;
|
|
}
|
|
|
|
double amt = toDouble(parts[0]);
|
|
string type = parts[2].trimmed();
|
|
if(type.equals_nocase("saturation")) {
|
|
bld.saturates[resource] += amt;
|
|
}
|
|
else if(type.equals_nocase("production")) {
|
|
bld.resources[resource] += amt;
|
|
}
|
|
else {
|
|
file.error("Invalid building effect: "+escape(decls[i].trimmed()));
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
//Hook line
|
|
auto@ hook = cast<IBuildingHook@>(parseHook(line, "building_effects::", instantiate=false, file=file));
|
|
if(hook !is null) {
|
|
hook.initialize(bld, bld.hooks.length);
|
|
bld.hooks.insertLast(hook);
|
|
}
|
|
}
|
|
}
|
|
|
|
void loadBuildings(const string& filename) {
|
|
ReadFile file(filename, true);
|
|
|
|
string key, value;
|
|
BuildingType@ bld;
|
|
uint index = 0;
|
|
while(file++) {
|
|
key = file.key;
|
|
value = file.value;
|
|
|
|
if(file.fullLine) {
|
|
if(bld is null) {
|
|
file.error("Missing 'Building: ID' line");
|
|
continue;
|
|
}
|
|
|
|
string line = file.line;
|
|
parseLine(file, line, bld);
|
|
}
|
|
else if(key == "Building") {
|
|
if(bld !is null)
|
|
addBuildingType(bld);
|
|
@bld = BuildingType();
|
|
bld.ident = value;
|
|
}
|
|
else if(bld is null) {
|
|
error("Missing 'Building: ID' line in " + filename);
|
|
}
|
|
else if(key == "Name") {
|
|
bld.name = localize(value);
|
|
}
|
|
else if(key == "Description") {
|
|
bld.description = localize(value);
|
|
}
|
|
else if(key == "Sprite") {
|
|
bld.sprite = getSprite(value);
|
|
}
|
|
else if(key == "Upgrades From") {
|
|
bld.upgradesFrom = value;
|
|
}
|
|
else if(key == "Category") {
|
|
bld.category = value;
|
|
}
|
|
else if(key == "Civilian") {
|
|
if(toBool(value)) {
|
|
bld.cls = BC_Civilian;
|
|
bld.pressureCapTaken = 1;
|
|
}
|
|
}
|
|
else if(key == "City") {
|
|
if(toBool(value)) {
|
|
bld.cls = BC_City;
|
|
bld.pressureCapTaken = 0;
|
|
}
|
|
}
|
|
else if(key == "Size") {
|
|
array<string>@ split = value.split("x");
|
|
if(split.length != 2) {
|
|
error("Invalid building size: "+escape(file.line));
|
|
}
|
|
else {
|
|
bld.size.x = toUInt(split[0]);
|
|
bld.size.y = toUInt(split[1]);
|
|
}
|
|
}
|
|
else if(key == "Base Cost") {
|
|
bld.baseBuildCost = toInt(value);
|
|
}
|
|
else if(key == "Tile Cost") {
|
|
bld.tileBuildCost = toInt(value);
|
|
}
|
|
else if(key == "Base Maintenance") {
|
|
bld.baseMaintainCost = toInt(value);
|
|
}
|
|
else if(key == "Tile Maintenance") {
|
|
bld.tileMaintainCost = toInt(value);
|
|
}
|
|
else if(key == "Build Time") {
|
|
bld.buildTime = toDouble(value);
|
|
}
|
|
else if(key == "Labor Cost") {
|
|
bld.laborCost = toDouble(value);
|
|
bld.buildInQueue = true;
|
|
}
|
|
else if(key == "Pressure Cap") {
|
|
bld.pressureCapTaken = toInt(value);
|
|
}
|
|
else if(key == "Build Affinity") {
|
|
bld.buildAffinities.insertLast(BiomeAffinity(value));
|
|
}
|
|
else if(key == "Maintenance Affinity") {
|
|
bld.maintainAffinities.insertLast(BiomeAffinity(value));
|
|
}
|
|
else if(key == "In Queue") {
|
|
bld.buildInQueue = toBool(value);
|
|
}
|
|
else if(key == "Saturation") {
|
|
array<string>@ decls = value.split(",");
|
|
for(uint i = 0, cnt = decls.length; i < cnt; ++i) {
|
|
array<string>@ parts = decls[i].split(" ");
|
|
if(parts.length != 2) {
|
|
file.error("Invalid saturation spec: "+escape(decls[i]));
|
|
continue;
|
|
}
|
|
|
|
uint resource = getTileResource(parts[1]);
|
|
if(resource == TR_INVALID) {
|
|
file.error("Invalid pressure spec: "+escape(decls[i]));
|
|
continue;
|
|
}
|
|
|
|
double amt = toDouble(parts[0]);
|
|
bld.saturates[resource] += amt;
|
|
}
|
|
}
|
|
else if(key == "Production") {
|
|
array<string>@ decls = value.split(",");
|
|
for(uint i = 0, cnt = decls.length; i < cnt; ++i) {
|
|
array<string>@ parts = decls[i].split(" ");
|
|
if(parts.length != 2) {
|
|
file.error("Invalid saturation spec: "+escape(decls[i]));
|
|
continue;
|
|
}
|
|
|
|
uint resource = getTileResource(parts[1]);
|
|
if(resource == TR_INVALID) {
|
|
file.error("Invalid pressure spec: "+escape(decls[i]));
|
|
continue;
|
|
}
|
|
|
|
double amt = toDouble(parts[0]);
|
|
bld.resources[resource] += amt;
|
|
}
|
|
}
|
|
else if(key.equals_nocase("AI")) {
|
|
auto@ hook = parseHook(value, "ai.buildings::", instantiate=false, file=file);
|
|
if(hook !is null)
|
|
bld.ai.insertLast(hook);
|
|
else
|
|
file.error("Could not find AI hook "+value);
|
|
}
|
|
else {
|
|
string line = file.line;
|
|
parseLine(file, line, bld);
|
|
}
|
|
}
|
|
|
|
if(bld !is null)
|
|
addBuildingType(bld);
|
|
}
|
|
|
|
void preInit() {
|
|
FileList list("data/buildings", "*.txt", true);
|
|
for(uint i = 0, cnt = list.length; i < cnt; ++i)
|
|
loadBuildings(list.path[i]);
|
|
|
|
for(uint i = 0, cnt = buildings::types.length; i < cnt; ++i) {
|
|
BuildingType@ type = buildings::types[i];
|
|
if(type.upgradesFrom.length != 0) {
|
|
BuildingType@ par;
|
|
buildings::typeIdents.get(type.upgradesFrom, @par);
|
|
|
|
if(par !is null) {
|
|
par.upgrades.insertLast(type);
|
|
@type.base = par;
|
|
}
|
|
else {
|
|
error("Error: "+type.ident+": Could not find base building "+type.upgradesFrom);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void init() {
|
|
auto@ list = buildings::types;
|
|
for(uint i = 0, cnt = list.length; i < cnt; ++i) {
|
|
auto@ type = list[i];
|
|
for(uint n = 0, ncnt = type.hooks.length; n < ncnt; ++n)
|
|
if(!cast<Hook>(type.hooks[n]).instantiate())
|
|
error("Could not instantiate hook: "+addrstr(type.hooks[n])+" in "+type.ident);
|
|
for(uint n = 0, ncnt = type.buildAffinities.length; n < ncnt; ++n)
|
|
type.buildAffinities[n].init();
|
|
for(uint n = 0, ncnt = type.maintainAffinities.length; n < ncnt; ++n)
|
|
type.maintainAffinities[n].init();
|
|
for(uint n = 0, ncnt = type.ai.length; n < ncnt; ++n) {
|
|
if(!type.ai[n].instantiate())
|
|
error("Could not instantiate AI hook: "+addrstr(type.ai[n])+" in building "+type.ident);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint getBuildingTypeCount() {
|
|
return buildings::types.length;
|
|
}
|
|
|
|
string getBuildingIdent(int id) {
|
|
if(uint(id) < buildings::types.length)
|
|
return buildings::types[id].ident;
|
|
return "";
|
|
}
|
|
|
|
int getBuildingID(const string& ident) {
|
|
BuildingType@ def;
|
|
buildings::typeIdents.get(ident, @def);
|
|
if(def is null)
|
|
return -1;
|
|
return def.id;
|
|
}
|
|
|
|
const BuildingType@ getBuildingType(uint id) {
|
|
if(id < buildings::types.length)
|
|
return buildings::types[id];
|
|
return null;
|
|
}
|
|
|
|
const BuildingType@ getBuildingType(const string& ident) {
|
|
BuildingType@ def;
|
|
buildings::typeIdents.get(ident, @def);
|
|
return def;
|
|
}
|
|
|
|
void addBuildingType(BuildingType@ def) {
|
|
def.id = buildings::types.length;
|
|
buildings::typeIdents.set(def.ident, @def);
|
|
buildings::types.insertLast(def);
|
|
|
|
for(uint i = 0; i < TR_COUNT; ++i) {
|
|
def.totalResource += def.resources[i];
|
|
def.totalSaturate += def.saturates[i];
|
|
}
|
|
}
|
|
|
|
void saveIdentifiers(SaveFile& file) {
|
|
for(uint i = 0, cnt = buildings::types.length; i < cnt; ++i) {
|
|
BuildingType@ type = buildings::types[i];
|
|
file.addIdentifier(SI_Building, type.id, type.ident);
|
|
}
|
|
}
|