Lephisto/src/mission.c
2013-03-30 23:35:31 +00:00

208 lines
5.2 KiB
C

#include <stdint.h>
#include <string.h>
#include <malloc.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lephisto.h"
#include "log.h"
#include "hook.h"
#include "pack.h"
#include "xml.h"
#include "mission.h"
#define XML_MISSION_ID "Missions" // XML section identifier.
#define XML_MISSION_TAG "mission"
#define MISSION_DATA "../dat/mission.xml"
#define MISSION_LUA_PATH "../dat/missions/"
// Current player missions.
static unsigned int mission_id = 0;
Mission player_missions[MISSION_MAX];
// Mission stack.
static Mission* mission_stack = NULL; // Unmuteable after creation.
static int mission_nstack = 0;
// Extern.
extern int misn_run(Mission* misn, char* func);
// Static.
static void mission_cleanup(Mission* misn);
static void mission_free(MissionData* mission);
static int mission_location(char* loc);
static MissionData* mission_parse(const xmlNodePtr parent);
// Create a mission.
int mission_create(MissionData* misn) {
int i;
// Find last mission.
for(i = 0; i < MISSION_MAX; i++)
if(player_missions[i].data == NULL) break;
// No missions left.
if(i >= MISSION_MAX) return -1;
player_missions[i].id = ++mission_id;
player_missions[i].data = misn;
// Init lua.
player_missions[i].L = luaL_newstate();
luaopen_string(player_missions[i].L); // String.format can be useful..
misn_loadLibs(player_missions[i].L); // Load our custom libraries.
misn_run(&player_missions[i], "create");
return 0;
}
// Clean up a mission.
static void mission_cleanup(Mission* misn) {
hook_rmParent(misn->id); // Remove existing hooks.
misn->data = NULL;
if(misn->title) free(misn->title);
if(misn->desc) free(misn->desc);
if(misn->reward) free(misn->reward);
lua_close(misn->L);
}
// Free a mission.
static void mission_free(MissionData* mission) {
if(mission->name) {
free(mission->name);
mission->name = NULL;
}
if(mission->avail.planet) {
free(mission->avail.planet);
mission->avail.planet = NULL;
}
if(mission->avail.system) {
free(mission->avail.system);
mission->avail.system = NULL;
}
if(mission->avail.factions) {
free(mission->avail.factions);
mission->avail.factions = NULL;
mission->avail.nfactions = 0;
}
}
// Return location based on string.
static int mission_location(char* loc) {
if(strcmp(loc, "None")==0) return MIS_AVAIL_NONE;
else if(strcmp(loc, "Computer")==0) return MIS_AVAIL_COMPUTER;
else if(strcmp(loc, "Bar")==0) return MIS_AVAIL_BAR;
else if(strcmp(loc, "Outfit")==0) return MIS_AVAIL_OUTFIT;
else if(strcmp(loc, "Shipyard")==0) return MIS_AVAIL_SHIPYARD;
else if(strcmp(loc, "Land")==0) return MIS_AVAIL_LAND;
return -1;
}
// Parse a node of a mission.
static MissionData* mission_parse(const xmlNodePtr parent) {
MissionData* tmp;
xmlNodePtr cur, node;
tmp = malloc(sizeof(MissionData));
memset(tmp, 0, sizeof(MissionData));
// Get the name.
tmp->name = xml_nodeProp(parent, "name");
if(tmp->name == NULL) WARN("Mission in "MISSION_DATA" has invalid or no name");
node = parent->xmlChildrenNode;
char str[PATH_MAX] = "\0";
// Load all the data.
do {
if(xml_isNode(node, "lua")) {
snprintf(str, PATH_MAX, MISSION_LUA_PATH"%s.lua", xml_get(node));
tmp->lua = strdup(str);
str[0] = '\0';
}
else if(xml_isNode(node, "avail")) {
cur = node->children;
do {
if(xml_isNode(cur, "location"))
tmp->avail.loc = mission_location(xml_get(cur));
/*else if(xml_isNode(cur, "")) // Need to parse other thingies.
tmp->u.amm.damage_shield = xml_getFloat(cur);*/
} while((cur = cur->next));
}
} while((node = node->next));
#define MELEMENT(o,s) \
if(o) WARN("Mission '%s' missing/invalid '"s"' element", tmp->name)
MELEMENT(tmp->lua==NULL, "lua");
MELEMENT(tmp->avail.loc==-1, "location");
#undef MELEMENT
return tmp;
}
// Load/Free.
int missions_load(void) {
uint32_t bufsize;
char* buf = pack_readfile(DATA, MISSION_DATA, &bufsize);
MissionData* tmp;
xmlNodePtr node;
xmlDocPtr doc = xmlParseMemory(buf, bufsize);
node = doc->xmlChildrenNode;
if(!xml_isNode(node, XML_MISSION_ID)) {
ERR("Malformed '"MISSION_DATA"' file: missing root element '" \
XML_MISSION_ID"'");
return -1;
}
node = node->xmlChildrenNode; // First mission node.
if(node == NULL) {
ERR("Malformed '"MISSION_DATA"' file: does not contain elements");
return -1;
}
do {
if(xml_isNode(node, XML_MISSION_TAG)) {
tmp = mission_parse(node);
mission_stack =
realloc(mission_stack, sizeof(MissionData)*(++mission_nstack));
memcpy(mission_stack+mission_nstack-1, tmp, sizeof(MissionData));
free(tmp);
}
} while((node = node->next));
xmlFreeDoc(doc);
free(buf);
xmlCleanupParser();
DEBUG("Loaded %d Mission%s", mission_nstack, (mission_nstack==1) ? "" : "s");
return 0;
}
void missions_free(void) {
int i;
// Free the mission data.
for(i = 0; i < mission_nstack; i++)
mission_free(&mission_stack[i]);
free(mission_stack);
mission_stack = NULL;
mission_nstack = 0;
}
void missions_cleanup(void) {
int i;
for(i = 0; i < MISSION_MAX; i++)
mission_cleanup(&player_missions[i]);
}