Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,483 @@
|
||||
#include "scripts/binds.h"
|
||||
#include "obj/object.h"
|
||||
#include "empire.h"
|
||||
#include "empire_stats.h"
|
||||
#include "main/references.h"
|
||||
#include "design/design.h"
|
||||
#include "vec2.h"
|
||||
#include "scripts/script_components.h"
|
||||
#include "util/stat_history.h"
|
||||
#include "network/network_manager.h"
|
||||
|
||||
extern Empire* defaultEmpire;
|
||||
extern Empire* playerEmpire;
|
||||
extern Empire* spectatorEmpire;
|
||||
|
||||
extern std::unordered_map<std::string,unsigned> statIndices;
|
||||
|
||||
namespace scripts {
|
||||
|
||||
static const Design* getDesignByName(Empire* emp, const std::string& name) {
|
||||
return emp->getDesign(name, true);
|
||||
}
|
||||
|
||||
static const Design* getDesignById(Empire* emp, int id) {
|
||||
return emp->getDesign(id, true);
|
||||
}
|
||||
|
||||
static unsigned getDesignCount(Empire* emp) {
|
||||
return emp->designIds.size();
|
||||
}
|
||||
|
||||
static unsigned getDesignClassCount(Empire* emp) {
|
||||
return emp->designClassIds.size();
|
||||
}
|
||||
|
||||
static Empire* empFactory() {
|
||||
return new Empire();
|
||||
}
|
||||
|
||||
static Empire* empFactory_b(bool unlisted) {
|
||||
return new Empire(unlisted ? INVALID_EMPIRE : UNLISTED_EMPIRE);
|
||||
}
|
||||
|
||||
static void writeDelta(Empire* emp, net::Message& msg) {
|
||||
emp->writeDelta(msg);
|
||||
}
|
||||
|
||||
static void readDelta(Empire* emp, net::Message& msg) {
|
||||
try {
|
||||
emp->readDelta(msg);
|
||||
}
|
||||
catch(net::MessageReadError) {
|
||||
scripts::throwException("Error reading from message: end of message.");
|
||||
}
|
||||
}
|
||||
|
||||
static bool ssUnlocked(Empire* emp, const SubsystemDef* def) {
|
||||
threads::ReadLock lock(emp->subsystemDataMutex);
|
||||
Empire::SubsystemData* ssdata = emp->getSubsystemData(def);
|
||||
return ssdata ? ssdata->unlocked : false;
|
||||
}
|
||||
|
||||
static bool ssModUnlocked(Empire* emp, const SubsystemDef* def, const SubsystemDef::ModuleDesc* mod) {
|
||||
threads::ReadLock lock(emp->subsystemDataMutex);
|
||||
Empire::SubsystemData* ssdata = emp->getSubsystemData(def);
|
||||
if(!ssdata)
|
||||
return false;
|
||||
if((int)ssdata->modulesUnlocked.size() <= mod->index)
|
||||
return false;
|
||||
return ssdata->modulesUnlocked[mod->index];
|
||||
}
|
||||
|
||||
static void ssSetModUnlock(Empire* emp, const SubsystemDef* def, const SubsystemDef::ModuleDesc* mod, bool val) {
|
||||
threads::WriteLock lock(emp->subsystemDataMutex);
|
||||
Empire::SubsystemData* ssdata = emp->getSubsystemData(def);
|
||||
if(ssdata) {
|
||||
if((int)ssdata->modulesUnlocked.size() <= mod->index)
|
||||
ssdata->modulesUnlocked.resize(mod->index+1, false);
|
||||
ssdata->modulesUnlocked[mod->index] = val;
|
||||
ssdata->delta = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssSetUnlock(Empire* emp, const SubsystemDef* def, bool val) {
|
||||
threads::WriteLock lock(emp->subsystemDataMutex);
|
||||
Empire::SubsystemData* ssdata = emp->getSubsystemData(def);
|
||||
if(ssdata) {
|
||||
ssdata->unlocked = val;
|
||||
ssdata->delta = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void removeModifier(Empire* emp, const SubsystemDef* def, unsigned id) {
|
||||
threads::WriteLock lock(emp->subsystemDataMutex);
|
||||
Empire::SubsystemData* ssdata = emp->getSubsystemData(def);
|
||||
if(ssdata) {
|
||||
ssdata->stages.erase(id);
|
||||
ssdata->delta = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void addModifier_d(asIScriptGeneric* f) {
|
||||
Empire* emp = (Empire*)f->GetObject();
|
||||
threads::WriteLock lock(emp->subsystemDataMutex);
|
||||
const SubsystemDef* def = (const SubsystemDef*)f->GetArgAddress(0);
|
||||
Empire::SubsystemData* ssdata = emp->getSubsystemData(def);
|
||||
|
||||
if(!ssdata)
|
||||
return;
|
||||
|
||||
//Find the modifier
|
||||
std::string& modname = *(std::string*)f->GetArgAddress(1);
|
||||
auto it = def->modifierIds.find(modname);
|
||||
if(it == def->modifierIds.end()) {
|
||||
scripts::throwException(
|
||||
format("Error: Could not find subsystem modifier '$1.$2'.\n",
|
||||
def->id, modname).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
const SubsystemDef::ModifyStage* stage = it->second;
|
||||
|
||||
//Check arguments
|
||||
if((int)stage->argumentNames.size() != f->GetArgCount() - 2) {
|
||||
scripts::throwException(
|
||||
format("Error: Subsystem modifier '$1.$2'"
|
||||
" expects $3 arguments, got $4.\n",
|
||||
def->id, modname,
|
||||
(unsigned)stage->argumentNames.size(),
|
||||
f->GetArgCount() - 1).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
//Create applied stage
|
||||
SubsystemDef::AppliedStage as;
|
||||
as.stage = stage;
|
||||
|
||||
for(unsigned i = 0, cnt = stage->argumentNames.size(); i < cnt; ++i)
|
||||
as.arguments[i] = f->GetArgFloat(i+2);
|
||||
|
||||
//Add stage to data
|
||||
unsigned id = ssdata->nextStageId++;
|
||||
ssdata->stages[id] = as;
|
||||
ssdata->delta = true;
|
||||
f->SetReturnDWord(id);
|
||||
}
|
||||
|
||||
struct StatReader {
|
||||
const StatHistory* history;
|
||||
const StatEntry* entry;
|
||||
const StatEvent* evt;
|
||||
|
||||
Empire* emp;
|
||||
unsigned id;
|
||||
|
||||
StatReader(const StatHistory* History, Empire* Emp, unsigned ID) : history(History), entry(0), evt(0), emp(Emp), id(ID) {}
|
||||
~StatReader() {
|
||||
if(emp)
|
||||
emp->unlockStatHistory(id);
|
||||
}
|
||||
|
||||
int get_int() const {
|
||||
if(entry)
|
||||
return entry->asInt;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
float get_float() const {
|
||||
if(entry)
|
||||
return entry->asFloat;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned get_time() const {
|
||||
if(entry)
|
||||
return entry->time;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned get_evt_type() const {
|
||||
if(evt)
|
||||
return evt->type;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string get_evt_name() const {
|
||||
if(evt)
|
||||
return evt->name;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
bool toHead() {
|
||||
if(!history)
|
||||
return false;
|
||||
|
||||
if(const StatEntry* head = history->getHead()) {
|
||||
entry = head;
|
||||
evt = 0;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool toTail() {
|
||||
if(!history)
|
||||
return false;
|
||||
|
||||
if(const StatEntry* tail = history->getTail()) {
|
||||
entry = tail;
|
||||
evt = 0;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool advance(int amount) {
|
||||
if(!history)
|
||||
return false;
|
||||
|
||||
if(amount > 0) {
|
||||
evt = 0;
|
||||
|
||||
if(entry == 0) {
|
||||
entry = history->getHead();
|
||||
|
||||
if(entry)
|
||||
return advance(amount-1);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
entry = entry->next;
|
||||
if(entry == 0)
|
||||
return false;
|
||||
} while(--amount != 0);
|
||||
|
||||
return entry != 0;
|
||||
}
|
||||
else if(amount < 0) {
|
||||
evt = 0;
|
||||
|
||||
if(entry == 0) {
|
||||
entry = history->getTail();
|
||||
|
||||
if(entry)
|
||||
return advance(amount+1);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
entry = entry->prev;
|
||||
if(entry == 0)
|
||||
return false;
|
||||
} while(--amount != 0);
|
||||
|
||||
return entry != 0;
|
||||
}
|
||||
else {
|
||||
evt = 0;
|
||||
return entry != 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool advanceEvent() {
|
||||
if(!history)
|
||||
return false;
|
||||
|
||||
if(entry) {
|
||||
if(evt == 0) {
|
||||
evt = entry->evt;
|
||||
return evt != 0;
|
||||
}
|
||||
else if(evt->next) {
|
||||
evt = evt->next;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void destroy(StatReader* reader) {
|
||||
delete reader;
|
||||
}
|
||||
};
|
||||
|
||||
StatReader* getStatHistory(Empire* emp, unsigned id) {
|
||||
const StatHistory* history = emp->lockStatHistory(id);
|
||||
if(!history) {
|
||||
return new StatReader(0, 0, 0);
|
||||
}
|
||||
else {
|
||||
return new StatReader(history, emp, id);
|
||||
}
|
||||
}
|
||||
|
||||
bool empIsHostile(Empire& from, Empire* to) {
|
||||
if(to == nullptr)
|
||||
return false;
|
||||
return from.hostileMask & to->mask;
|
||||
}
|
||||
|
||||
bool empIsHostile_restricted(Empire& from, Empire* to) {
|
||||
if(to == nullptr)
|
||||
return false;
|
||||
//if(&from != playerEmpire && to != playerEmpire)
|
||||
// return false;
|
||||
return from.hostileMask & to->mask;
|
||||
}
|
||||
|
||||
void empSetHostile(Empire& from, Empire& to, bool value) {
|
||||
threads::Lock lock(from.maskMutex);
|
||||
if(value)
|
||||
from.hostileMask |= to.mask;
|
||||
else
|
||||
from.hostileMask &= ~to.mask;
|
||||
}
|
||||
|
||||
static bool empControlled(Empire& emp) {
|
||||
return devices.network->getCurrentPlayer().controls(&emp);
|
||||
}
|
||||
|
||||
static bool empViewed(Empire& emp) {
|
||||
return devices.network->getCurrentPlayer().views(&emp);
|
||||
}
|
||||
|
||||
void RegisterEmpireBinds(bool declarations, bool server) {
|
||||
if(declarations) {
|
||||
ClassBind emp("Empire", asOBJ_REF | asOBJ_NOCOUNT);
|
||||
return;
|
||||
}
|
||||
|
||||
ClassBind emp("Empire");
|
||||
emp.addFactory("Empire@ f()", asFUNCTION(empFactory));
|
||||
emp.addFactory("Empire@ f(bool unlisted)", asFUNCTION(empFactory_b));
|
||||
emp.addMember("string name", offsetof(Empire,name));
|
||||
emp.addMember("Player@ player", offsetof(Empire,player));
|
||||
emp.addMember("uint8 id", offsetof(Empire,id));
|
||||
emp.addMember("int index", offsetof(Empire,index));
|
||||
emp.addMember("uint mask", offsetof(Empire,mask));
|
||||
emp.addMember("uint visionMask", offsetof(Empire,visionMask));
|
||||
emp.addMember("Color color", offsetof(Empire,color));
|
||||
emp.addMember("const Material@ background", offsetof(Empire,background));
|
||||
emp.addMember("const Material@ portrait", offsetof(Empire,portrait));
|
||||
emp.addMember("const Material@ flag", offsetof(Empire,flag));
|
||||
emp.addMember("string backgroundDef", offsetof(Empire,backgroundDef));
|
||||
emp.addMember("string portraitDef", offsetof(Empire,portraitDef));
|
||||
emp.addMember("string flagDef", offsetof(Empire,flagDef));
|
||||
emp.addMember("uint flagID", offsetof(Empire,flagID));
|
||||
emp.addMember("const Shipset@ shipset", offsetof(Empire, shipset));
|
||||
emp.addMember("string effectorSkin", offsetof(Empire, effectorSkin));
|
||||
|
||||
if(server) {
|
||||
emp.addMember("uint hostileMask", offsetof(Empire,hostileMask));
|
||||
emp.addExternMethod("bool isHostile(Empire@ emp)", asFUNCTION(empIsHostile));
|
||||
emp.addExternMethod("void setHostile(Empire& emp, bool value)", asFUNCTION(empSetHostile));
|
||||
emp.addMethod("void cacheVision()", asMETHOD(Empire,cacheVision));
|
||||
}
|
||||
else {
|
||||
emp.addExternMethod("bool isHostile(Empire@ emp)", asFUNCTION(empIsHostile_restricted));
|
||||
emp.addExternMethod("bool get_controlled() const", asFUNCTION(empControlled));
|
||||
emp.addExternMethod("bool get_viewable() const", asFUNCTION(empViewed));
|
||||
}
|
||||
|
||||
emp.addMethod("uint get_objectCount()", asMETHOD(Empire, objectCount));
|
||||
emp.addMethod("Object@+ get_objects(uint i)", asMETHOD(Empire, findObject));
|
||||
|
||||
//Stats
|
||||
{
|
||||
Namespace ns("stat");
|
||||
EnumBind statTypes("EmpireStat");
|
||||
for(auto i = statIndices.begin(), end = statIndices.end(); i != end; ++i)
|
||||
statTypes[i->first] = i->second;
|
||||
}
|
||||
|
||||
bind("string get_statName(stat::EmpireStat)", asFUNCTION(getEmpireStatName));
|
||||
|
||||
ClassBind stats("StatHistory", asOBJ_REF | asOBJ_SCOPED);
|
||||
classdoc(stats, "Accesses the history of an empire's stat. Locks the stat, so limit access to these histories.");
|
||||
|
||||
stats.addFactory("StatHistory@ f(Empire&, stat::EmpireStat)", asFUNCTION(getStatHistory));
|
||||
stats.addExternBehaviour(asBEHAVE_RELEASE, "void f()", asFUNCTION(StatReader::destroy));
|
||||
|
||||
stats.addMethod("bool toTail()", asMETHOD(StatReader,toTail))
|
||||
doc("Advances to the most recent stat entry.", "True if there was a tail to move to.");
|
||||
stats.addMethod("bool toHead()", asMETHOD(StatReader,toHead))
|
||||
doc("Advances to the earliest stat entry.", "True if there was a head to move to.");
|
||||
|
||||
stats.addMethod("bool advance(int offset = 1)", asMETHOD(StatReader,advance))
|
||||
doc("Advances to another stat entry.", "Number of entries to move. Positive is later in time, negative is earlier. Advancing 0 resets the event reader. If not on a valid entry, advances to a valid entry at the correspending head or tail. ", "Returns true if an entry existed at the offset.");
|
||||
stats.addMethod("int get_intVal() const", asMETHOD(StatReader,get_int))
|
||||
doc("Returns the stat's value as an integer.", "");
|
||||
stats.addMethod("float get_floatVal() const", asMETHOD(StatReader,get_float))
|
||||
doc("Returns the stat's value as a float.", "");
|
||||
stats.addMethod("uint get_time() const", asMETHOD(StatReader,get_time))
|
||||
doc("Returns the stat's timestamp in seconds from the start of the game.", "");
|
||||
|
||||
stats.addMethod("bool advanceEvent()", asMETHOD(StatReader,advanceEvent))
|
||||
doc("Advances to the next event for the current stat.", "True if there was an event to advance to.");
|
||||
stats.addMethod("uint get_eventType() const", asMETHOD(StatReader,get_evt_type))
|
||||
doc("Returns the current event's type identifier.", "");
|
||||
stats.addMethod("string get_eventName() const", asMETHOD(StatReader,get_evt_name))
|
||||
doc("Returns the current event's name.", "");
|
||||
|
||||
if(server) {
|
||||
emp.addMethod("void recordStat(stat::EmpireStat, int)", asMETHODPR(Empire,recordStat,(unsigned,int),void))
|
||||
doc("Records an int value for the specified empire stat at the current game time", "Stat index.", "Stat value.");
|
||||
emp.addMethod("void recordStat(stat::EmpireStat, float)", asMETHODPR(Empire,recordStat,(unsigned,float),void))
|
||||
doc("Records a float value for the specified empire stat at the current game time", "Stat index.", "Stat value.");
|
||||
emp.addMethod("void recordStatDelta(stat::EmpireStat, int)", asMETHODPR(Empire,recordStatDelta,(unsigned,int),void))
|
||||
doc("Records an int delta for the specified empire stat at the current game time", "Stat index.", "Stat delta.");
|
||||
emp.addMethod("void recordStatDelta(stat::EmpireStat, float)", asMETHODPR(Empire,recordStatDelta,(unsigned,float),void))
|
||||
doc("Records a float delta for the specified empire stat at the current game time", "Stat index.", "Stat delta.");
|
||||
emp.addMethod("void recordEvent(stat::EmpireStat, uint16, const string &in)", asMETHOD(Empire,recordEvent))
|
||||
doc("Records an event for the specified empire stat at the current game time", "Stat index.", "Event type.", "Event name.");
|
||||
}
|
||||
|
||||
|
||||
//Designs
|
||||
emp.addMember("ReadWriteMutex designMutex", offsetof(Empire, designMutex));
|
||||
emp.addExternMethod("uint get_designCount() const", asFUNCTION(getDesignCount));
|
||||
emp.addExternMethod("const Design@ getDesign(const string &in)", asFUNCTION(getDesignByName));
|
||||
emp.addExternMethod("const Design@ getDesign(int id)", asFUNCTION(getDesignById));
|
||||
emp.addExternMethod("const Design@ get_designs(int)", asFUNCTION(getDesignById));
|
||||
|
||||
emp.addExternMethod("uint get_designClassCount() const", asFUNCTION(getDesignClassCount));
|
||||
emp.addMethod("const DesignClass@ getDesignClass(int id)", asMETHODPR(Empire, getDesignClass, (int), DesignClass*));
|
||||
emp.addMethod("const DesignClass@ getDesignClass(const string &in, bool add = true)", asMETHODPR(Empire, getDesignClass, (const std::string&, bool), DesignClass*));
|
||||
emp.addMethod("bool addDesign(const DesignClass& cls, const Design&)", asMETHOD(Empire, addDesign));
|
||||
emp.addMethod("bool changeDesign(const Design&, const Design&, const DesignClass@ cls = null)", asMETHODPR(Empire, changeDesign, (const Design*, const Design*, DesignClass*), bool));
|
||||
emp.addMethod("const Design@+ updateDesign(const Design&, bool onlyOutdated = false)", asMETHODPR(Empire, updateDesign, (const Design*, bool), const Design*));
|
||||
emp.addMethod("void flagDesignOld(const Design&)", asMETHODPR(Empire, flagDesignOld, (const Design*), void))
|
||||
doc("Marks a design as out of date, to be updated whenever it is requested for construction.", "");
|
||||
|
||||
emp.addMethod("bool get_valid()", asMETHOD(Empire, valid));
|
||||
|
||||
//Subsystem modifiers
|
||||
emp.addMember("ReadWriteMutex subsystemDataMutex", offsetof(Empire, subsystemDataMutex));
|
||||
emp.addExternMethod("bool isUnlocked(const SubsystemDef& sys, const ModuleDef& mod)", asFUNCTION(ssModUnlocked));
|
||||
emp.addExternMethod("bool isUnlocked(const SubsystemDef& sys)", asFUNCTION(ssUnlocked));
|
||||
emp.addExternMethod("void setUnlocked(const SubsystemDef& sys, const ModuleDef& mod, bool unlocked)", asFUNCTION(ssSetModUnlock));
|
||||
emp.addExternMethod("void setUnlocked(const SubsystemDef& sys, bool unlocked)", asFUNCTION(ssSetUnlock));
|
||||
emp.addExternMethod("void removeModifier(const SubsystemDef& sys, uint id)", asFUNCTION(removeModifier));
|
||||
|
||||
emp.addExternMethod("void writeDelta(Message& msg)", asFUNCTION(writeDelta));
|
||||
emp.addExternMethod("void readDelta(Message& msg)", asFUNCTION(readDelta));
|
||||
|
||||
std::string dargs;
|
||||
for(unsigned i = 0; i <= MODIFY_STAGE_MAXARGS; ++i) {
|
||||
emp.addGenericMethod(
|
||||
format("uint addModifier(const SubsystemDef& def, const string&in$1)", dargs).c_str(),
|
||||
asFUNCTION(addModifier_d));
|
||||
dargs += ", float";
|
||||
}
|
||||
|
||||
//Global empire lists
|
||||
bindGlobal("Empire@ playerEmpire", &playerEmpire)
|
||||
doc("The player's current empire.");
|
||||
|
||||
bindGlobal("Empire@ spectatorEmpire", &spectatorEmpire);
|
||||
bindGlobal("Empire@ defaultEmpire", &defaultEmpire);
|
||||
|
||||
bind("uint getEmpireCount()", asFUNCTION(Empire::getEmpireCount));
|
||||
bind("Empire@ getEmpire(uint index)", asFUNCTION(Empire::getEmpireByIndex));
|
||||
bind("Empire@ getEmpireByID(uint8 id)", asFUNCTION(Empire::getEmpireByID));
|
||||
|
||||
RegisterEmpireComponentWrappers(emp, server);
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user