208 lines
5.2 KiB
C
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]);
|
|
}
|
|
|