[Add] You can now use lua as conditions for missions.

This commit is contained in:
Allanis 2013-06-01 19:11:38 +01:00
parent 848a5e120d
commit 273607eda0
6 changed files with 98 additions and 27 deletions

View File

@ -32,7 +32,7 @@
<mission name = "Empire Shipping">
<lua>es_cargo</lua>
<avail>
<req>es_cargo</req>
<cond>var.peek("es_cargo") == true</cond>
<chance>350</chance>
<location>Computer</location>
<alliance>Empire United</alliance>

View File

@ -3,7 +3,7 @@ if lang == "es" then
-- Not translated atm.
else -- Default english.
misn_title = "Collective Scout"
misn_reward = ""
misn_reward = "None"
misn_desc = {}
misn_desc[1] = "Find a scout near %s."
misn_desc[2] = "Travel back to %s in %s."

View File

@ -94,6 +94,12 @@ static const luaL_reg var_methods[] = {
{0, 0}
};
// Only conditional.
static const luaL_reg var_cond_methods[] = {
{ "peek", var_peek },
{0, 0 }
};
// Space.
static int space_getPlanet(lua_State* L);
static int space_getSystem(lua_State* L);
@ -200,6 +206,12 @@ int misn_loadLibs(lua_State* L) {
return 0;
}
int misn_loadCondLibs(lua_State* L) {
luaL_register(L, "time", time_methods);
luaL_register(L, "var", var_cond_methods);
return 0;
}
// Run a mission function.
//
// -1 on error, 1 on misn.finish() call and 0 normally.

View File

@ -8,4 +8,5 @@ void var_cleanup(void);
// Load the libraries for a lua state.
int misn_loadLibs(lua_State* L);
int misn_loadCondLibs(lua_State* L); // Safe read only stuff.

View File

@ -38,9 +38,10 @@ extern int misn_run(Mission* misn, char* func);
// Static.
static unsigned int mission_genID(void);
static int mission_init(Mission* mission, MissionData* misn);
static int mission_init(Mission* mission, MissionData* misn, int load);
static void mission_freeData(MissionData* mission);
static int mission_alreadyRunning(MissionData* misn);
static int mission_meetCond(MissionData* misn);
static int mission_meetReq(int mission, int faction, char* planet, char* system);
static int mission_matchFaction(MissionData* misn, int faction);
static int mission_location(char* loc);
@ -80,15 +81,16 @@ MissionData* mission_get(int id) {
}
// Initialize a mission.
static int mission_init(Mission* mission, MissionData* misn) {
static int mission_init(Mission* mission, MissionData* misn, int load) {
char* buf;
uint32_t bufsize;
if(misn != NULL) {
// Don't set the data either.
if(load != 0)
mission->id = 0;
else
mission->id = mission_genID();
mission->data = misn;
}
// Sane defaults.
mission->title = NULL;
@ -108,9 +110,6 @@ static int mission_init(Mission* mission, MissionData* misn) {
luaopen_string(mission->L); // string.format can be very useful.
misn_loadLibs(mission->L); // Load our custom libraries.
// Don't load it with data.
if(misn != NULL) {
// Load the file.
buf = pack_readfile(DATA, misn->lua, &bufsize);
if(luaL_dobuffer(mission->L, buf, bufsize, misn->lua) != 0) {
ERR("Error loading mission file: %s", misn->lua);
@ -118,10 +117,10 @@ static int mission_init(Mission* mission, MissionData* misn) {
WARN("Most likely Lua file has improper syntax, please check");
return -1;
}
}
free(buf);
// Run create function.
if(load == 0) // Never run when loading.
misn_run(mission, "create");
return mission->id;
@ -145,6 +144,60 @@ static int mission_alreadyRunning(MissionData* misn) {
return 0;
}
// Is the lua condition for misn met?
static lua_State* mission_cond_L = NULL;
static int mission_meetCond(MissionData* misn) {
int ret;
char buf[256];
if(mission_cond_L == NULL) {
// Must create the conditional environment.
mission_cond_L = luaL_newstate();
misn_loadCondLibs(mission_cond_L);
}
snprintf(buf, 256, "return %s", misn->avail.cond);
ret = luaL_loadstring(mission_cond_L, buf);
switch(ret) {
case LUA_ERRSYNTAX:
WARN("Missions '%s' Lua Conditional syntax error", misn->name);
return 0;
case LUA_ERRMEM:
WARN("Mission '%s' Lua Conditional ran out of memory", misn->name);
return 0;
default:
break;
}
ret = lua_pcall(mission_cond_L, 0, 1, 0);
switch(ret) {
case LUA_ERRRUN:
WARN("Mission '%s' Lua Conditional had a runtime error: %s",
misn->name, lua_tostring(mission_cond_L, -1));
return 0;
case LUA_ERRMEM:
WARN("Mission '%s' Lua Conditional ran out of memory", misn->name);
return 0;
case LUA_ERRERR:
WARN("Mission '%s' Lua Conditional had an error while handling error function",
misn->name);
return 0;
default:
break;
}
if(lua_isboolean(mission_cond_L, -1)) {
if(lua_toboolean(mission_cond_L, -1))
return 1;
else
return 0;
}
WARN("Mission '%s' Conditional Lua didn't return a boolean", misn->name);
return 0;
}
// Does the mission meet the minimum requirements?
static int mission_meetReq(int mission, int faction, char* planet, char* system) {
MissionData* misn;
@ -162,8 +215,8 @@ static int mission_meetReq(int mission, int faction, char* planet, char* system)
mission_alreadyRunning(misn)))
return 0;
if((misn->avail.req != NULL) && // Mission doesn't meet the requirement.
!var_checkflag(misn->avail.req))
if((misn->avail.cond != NULL) && // Mission doesn't meet the requirement.
!mission_meetCond(misn))
return 0;
return 1;
@ -185,7 +238,7 @@ void missions_bar(int faction, char* planet, char* system) {
chance = (double)(misn->avail.chance % 100)/100.;
if(RNGF() < chance) {
mission_init(&mission, misn);
mission_init(&mission, misn, 0);
mission_cleanup(&mission); // It better clean up for itself or we do it.
}
}
@ -300,7 +353,7 @@ Mission* missions_computer(int* n, int faction, char* planet, char* system) {
// Random chance of rep appearances.
if(RNGF() < chance) {
tmp = realloc(tmp, sizeof(Mission) * ++m);
mission_init(&tmp[m-1], misn);
mission_init(&tmp[m-1], misn, 0);
}
}
}
@ -373,8 +426,8 @@ static MissionData* mission_parse(const xmlNodePtr parent) {
tmp->avail.factions[tmp->avail.nfactions-1] =
faction_get(xml_get(cur));
}
else if(xml_isNode(cur, "req"))
tmp->avail.req = strdup(xml_get(cur));
else if(xml_isNode(cur, "cond"))
tmp->avail.cond = strdup(xml_get(cur));
} while(xml_nextNode(cur));
}
} while(xml_nextNode(node));
@ -438,6 +491,11 @@ void missions_free(void) {
free(mission_stack);
mission_stack = NULL;
mission_nstack = 0;
if(mission_cond_L != NULL) {
lua_close(mission_cond_L);
mission_cond_L = NULL;
}
}
void missions_cleanup(void) {
@ -590,7 +648,7 @@ static int missions_parseActive(xmlNodePtr parent) {
// Process the attributes to create the mission.
xmlr_attr(node, "data", buf);
mission_init(misn, mission_get(mission_getID(buf)));
mission_init(misn, mission_get(mission_getID(buf)), 1);
free(buf);
// This will orphan an identifier.

View File

@ -33,7 +33,7 @@ typedef struct MissionData_ {
int* factions;
int nfactions;
char* req; // Required variable.
char* cond; // Conditional that must be met.
} avail;
unsigned int flags; // Flags to store binary properties.