Files
starruler-linux/scripts/definitions/traits.as
T
2018-07-17 14:15:37 +02:00

352 lines
7.7 KiB
ActionScript

#priority init 5500
#section game
import saving;
import hooks;
#section menu
class Hook {};
#section all
export Trait;
export getTrait, getTraitCount;
export TraitCategory;
export getTraitCategory, getTraitCategoryCount;
tidy final class Trait {
uint id;
const TraitCategory@ category;
string ident;
string name;
string description;
string unique;
Sprite icon;
Color color;
int order = 0;
int cost = 0;
int gives = 0;
bool defaultTrait = false;
bool available = true;
bool aiSupport = true;
string dlc;
array<ITraitEffect@> hooks;
array<string> hookDefs;
array<const Trait@> conflicts;
array<string> conflictDefs;
void preInit(Empire& emp, array<any>& data) const {
data.length = hooks.length;
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
hooks[i].preInit(emp, data[i]);
}
void init(Empire& emp, array<any>& data) const {
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
hooks[i].init(emp, data[i]);
}
void postInit(Empire& emp, array<any>& data) const {
data.length = hooks.length;
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
hooks[i].postInit(emp, data[i]);
}
void tick(Empire& emp, array<any>& data, double time) const {
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
hooks[i].tick(emp, data[i], time);
}
void save(array<any>& data, SaveFile& file) const {
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
hooks[i].save(data[i], file);
}
void load(array<any>& data, SaveFile& file) const {
data.length = hooks.length;
for(uint i = 0, cnt = hooks.length; i < cnt; ++i)
hooks[i].load(data[i], file);
}
void addConflict(const Trait@ other) {
if(conflicts.find(other) != -1)
return;
conflicts.insertLast(other);
}
bool get_hasDLC() const {
if(dlc.length == 0)
return true;
return hasDLC(dlc);
}
bool hasConflicts(const array<const Trait@>& list) const {
for(uint i = 0, cnt = list.length; i < cnt; ++i) {
auto@ other = list[i];
if(other is this)
continue;
if(conflicts.find(other) != -1)
return true;
if(unique.length != 0 && unique == other.unique)
return true;
}
return false;
}
int opCmp(const Trait@ other) const {
if(order < other.order)
return -1;
if(order > other.order)
return 1;
return 0;
}
bool opEquals(const Trait@ other) const {
return other.id == id;
}
};
interface ITraitEffect {
void preInit(Empire& emp, any@ data) const;
void init(Empire& emp, any@ data) const;
void postInit(Empire& emp, any@ data) const;
void tick(Empire& emp, any@ data, double time) const;
void save(any@ data, SaveFile& file) const;
void load(any@ data, SaveFile& file) const;
};
class TraitEffect : Hook, ITraitEffect {
void preInit(Empire& emp, any@ data) const {}
void init(Empire& emp, any@ data) const {}
void postInit(Empire& emp, any@ data) const {}
void tick(Empire& emp, any@ data, double time) const {}
void save(any@ data, SaveFile& file) const {}
void load(any@ data, SaveFile& file) const {}
};
array<Trait@> traits;
dictionary idents;
const Trait@ getTrait(uint id) {
if(id >= traits.length)
return null;
return traits[id];
}
const Trait@ getTrait(const string& ident) {
Trait@ def;
if(idents.get(ident, @def))
return def;
return null;
}
int getTraitID(const string& ident) {
auto@ type = getTrait(ident);
if(type is null)
return -1;
return int(type.id);
}
string getTraitIdent(int id) {
auto@ type = getTrait(id);
if(type is null)
return "";
return type.ident;
}
uint getTraitCount() {
return traits.length;
}
void addTrait(Trait@ type) {
type.id = traits.length;
traits.insertLast(type);
idents.set(type.ident, @type);
}
tidy final class TraitCategory {
uint id;
string ident;
string name;
TraitCategory(const string& ident) {
this.ident = ident;
name = localize("#TRAIT_CAT_"+ident);
if(name[0] == '#')
name = ident;
}
};
array<TraitCategory@> categories;
dictionary catIdents;
const TraitCategory@ getTraitCategory(uint id) {
if(id >= categories.length)
return null;
return categories[id];
}
const TraitCategory@ getTraitCategory(const string& ident, bool create = false) {
TraitCategory@ def;
if(catIdents.get(ident, @def))
return def;
if(create)
return addTraitCategory(TraitCategory(ident));
return null;
}
uint getTraitCategoryCount() {
return categories.length;
}
TraitCategory@ addTraitCategory(TraitCategory@ type) {
type.id = categories.length;
categories.insertLast(type);
catIdents.set(type.ident, @type);
return type;
}
void saveIdentifiers(SaveFile& file) {
#section game
for(uint i = 0, cnt = traits.length; i < cnt; ++i) {
auto type = traits[i];
file.addIdentifier(SI_Trait, type.id, type.ident);
}
#section all
}
void parseLine(string& line, Trait@ trait, ReadFile@ file) {
#section game
//Hook line
trait.hookDefs.insertLast(line);
#section all
}
void loadTraits(const string& filename) {
ReadFile file(filename, true);
string key, value;
Trait@ trait;
uint index = 0;
while(file++) {
key = file.key;
value = file.value;
if(file.fullLine) {
string line = file.line;
parseLine(line, trait, file);
}
else if(key.equals_nocase("Trait")) {
if(trait !is null)
addTrait(trait);
@trait = Trait();
trait.ident = value;
}
else if(trait is null) {
file.error("Missing trait ID' line");
}
else if(key.equals_nocase("Name")) {
trait.name = localize(value);
}
else if(key.equals_nocase("Description")) {
trait.description = localize(value);
}
else if(key.equals_nocase("Costs Points")) {
trait.cost = toInt(value);
}
else if(key.equals_nocase("Gives Points")) {
trait.gives = toInt(value);
}
else if(key.equals_nocase("Category")) {
@trait.category = getTraitCategory(value, create=true);
}
else if(key.equals_nocase("Icon")) {
trait.icon = getSprite(value);
}
else if(key.equals_nocase("Color")) {
trait.color = toColor(value);
}
else if(key.equals_nocase("Order")) {
trait.order = toInt(value);
}
else if(key.equals_nocase("Unique")) {
trait.unique = value;
}
else if(key.equals_nocase("Default")) {
trait.defaultTrait = toBool(value);
}
else if(key.equals_nocase("Available")) {
trait.available = toBool(value);
}
else if(key.equals_nocase("Conflict")) {
trait.conflictDefs.insertLast(value);
}
else if(key.equals_nocase("DLC")) {
trait.dlc = value;
}
else if(key.equals_nocase("AI Support")) {
trait.aiSupport = toBool(value);
}
else {
string line = file.line;
parseLine(line, trait, file);
}
}
if(trait !is null)
addTrait(trait);
}
export initTraits;
bool initialized = false;
void initTraits() {
if(initialized)
return;
initialized = true;
FileList list("data/traits", "*.txt", true);
for(uint i = 0, cnt = list.length; i < cnt; ++i)
loadTraits(list.path[i]);
}
void preInit() {
initTraits();
#section game
for(uint i = 0, cnt = traits.length; i < cnt; ++i) {
auto@ trait = traits[i];
for(uint n = 0, ncnt = trait.hookDefs.length; n < ncnt; ++n) {
auto@ hook = cast<ITraitEffect>(parseHook(trait.hookDefs[n], "trait_effects::", instantiate=false));
if(hook !is null)
trait.hooks.insertLast(hook);
}
}
#section all
}
void init() {
for(uint i = 0, cnt = traits.length; i < cnt; ++i) {
auto@ trait = traits[i];
#section game
for(uint n = 0, ncnt = trait.hooks.length; n < ncnt; ++n) {
if(!cast<Hook>(trait.hooks[n]).instantiate())
error("Could not instantiate hook "+addrstr(trait.hooks[n])+" on trait "+trait.ident);
}
#section all
for(uint n = 0, ncnt = trait.conflictDefs.length; n < ncnt; ++n) {
Trait@ other;
if(!idents.get(trait.conflictDefs[n], @other)) {
error("Could not find conflict trait "+trait.conflictDefs[n]+" in trait "+trait.ident);
continue;
}
trait.addConflict(other);
other.addConflict(trait);
}
}
}