diff --git a/bin/Makefile b/bin/Makefile index ee05d6f..c3a4637 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -49,11 +49,12 @@ endif # DATA. DATA_AI = $(shell find ../scripts/ai/ -name '*.lua') -DATA_GFX = $(shell find ../gfx/ -name '*.png') -DATA_XML = $(shell find ../dat/ -name '*.xml' -o -name '*.ttf') -DATA_SND = $(shell find ../snd/ -name '*.ogg' -o -name '*.wav') +DATA_GFX = $(shell find ../gfx/ -name '*.png') +DATA_XML = $(shell find ../dat/ -name '*.xml' -o -name '*.ttf') +DATA_SND = $(shell find ../snd/ -name '*.ogg' -o -name '*.wav') +DATA_MISN = $(shell find ../dat/missions/ -name '*.lua') DATA = data -DATAFILES = $(VERSIONFILE) $(DATA_AI) $(DATA_GFX) $(DATA_XML) $(DATA_SND) +DATAFILES = $(VERSIONFILE) $(DATA_AI) $(DATA_GFX) $(DATA_XML) $(DATA_SND) $(DATA_MISN) # TARGETS. %.o: %.c %.h diff --git a/dat/mission.xml b/dat/mission.xml index b118828..cc6e8e0 100644 --- a/dat/mission.xml +++ b/dat/mission.xml @@ -1,5 +1,8 @@ + + 1 + welcome None diff --git a/dat/missions/cargo.lua b/dat/missions/cargo.lua index ea9ba8a..71df38f 100644 --- a/dat/missions/cargo.lua +++ b/dat/missions/cargo.lua @@ -22,7 +22,7 @@ end function accept() player.addCargo(carg_type, carg_mass) toolkit.msg("Mission Accepted", - string.format("The workers load the %d tons of %s onto your ship." + string.format("The workers load the %d tons of %s onto your ship.", carg_mass, carg_type)) end diff --git a/src/faction.c b/src/faction.c index 965b51b..6939e32 100644 --- a/src/faction.c +++ b/src/faction.c @@ -176,7 +176,7 @@ int faction_ofAlliance(int f, int a) { return 0; } - aa = &alliances[a]; + aa = &alliances[a-ALLIANCE_OFFSET]; for(i = 0; i < aa->nfactions; i++) if(aa->factions[i] == f) diff --git a/src/land.c b/src/land.c index b91cd88..53e6397 100644 --- a/src/land.c +++ b/src/land.c @@ -6,6 +6,7 @@ #include "music.h" #include "economy.h" #include "hook.h" +#include "mission.h" #include "land.h" // Global/main window. @@ -37,13 +38,29 @@ #define MUSIC_TAKEOFF "liftoff" #define MUSIC_LAND "agriculture" -int landed = 0; +// We use visited flags to not duplicate missions generated. +#define VISITED_LAND (1<<0) +#define VISITED_COMMODITY (1<<1) +#define VISITED_BAR (1<<2) +#define VISITED_OUTFITS (1<<3) +#define VISITED_SHIPYARD (1<<4) +#define visited(f) (land_visited |= (f)) +#define has_visited(f) (land_visited & (f)) +static unsigned int land_visited = 0; +// Land variables. +int landed = 0; +Planet* land_planet = NULL; + +// Mission computer stack. +static Mission* mission_computer = NULL; +static int mission_ncomputer = 0; + +// Window stuff. static int land_wid = 0; // Primary land window. // For the second opened land window static int secondary_wid = 0; static int terciary_wid = 0; // For fancy things like news, your ship etc.. -Planet* land_planet = NULL; // Commodity excahnge. static void commodity_exchange(void); @@ -121,6 +138,11 @@ static void commodity_exchange(void) { goods, land_planet->ncommodities, 0, commodity_update); commodity_update(NULL); + + if(!has_visited(VISITED_COMMODITY)) { + // TODO: mission check. + visited(VISITED_COMMODITY); + } } static void commodity_exchange_close(char* str) { @@ -250,6 +272,11 @@ static void outfits(void) { // Write the outfits stuff. outfits_update(NULL); + + if(!has_visited(VISITED_OUTFITS)) { + // TODO: mission check. + visited(VISITED_OUTFITS); + } } static void outfits_close(char* str) { @@ -436,6 +463,11 @@ static void shipyard(void) { // Write the shipyard stuff. shipyard_update(NULL); + + if(!has_visited(VISITED_SHIPYARD)) { + // TODO: mission check. + visited(VISITED_SHIPYARD); + } } static void shipyard_close(char* str) { @@ -693,6 +725,11 @@ static void spaceport_bar(void) { BAR_WIDTH-40, BAR_HEIGHT - 40 - BUTTON_HEIGHT, 0, "txtDescription", &gl_smallFont, &cBlack, land_planet->bar_description); + + if(!has_visited(VISITED_BAR)) { + // TODO: mission check. + visited(VISITED_BAR); + } } static void spaceport_bar_close(char* str) { @@ -767,16 +804,26 @@ void land(Planet* p) { landed = 1; hooks_run("land"); + + // Generate mission computer stuff. + mission_computer = missions_computer(&mission_ncomputer, + land_planet->faction, land_planet->name, cur_system->name); + + if(!has_visited(VISITED_LAND)) { + // TODO: mission check. + visited(VISITED_LAND); + } } // Takeoff from the planet. void takeoff(void) { + int sw, sh, i; + if(!landed) return; music_load(MUSIC_TAKEOFF); music_play(); - int sw, sh; sw = land_planet->gfx_space->w; sh = land_planet->gfx_space->h; @@ -799,6 +846,14 @@ void takeoff(void) { land_planet = NULL; window_destroy(land_wid); landed = 0; + land_visited = 0; hooks_run("takeoff"); + + // Cleanup mission computer. + for(i = 0; i < mission_ncomputer; i++) + mission_free(&mission_computer[i]); + free(mission_computer); + mission_computer = NULL; + mission_ncomputer = 0; } diff --git a/src/mission.c b/src/mission.c index cb617ba..0b0c3a5 100644 --- a/src/mission.c +++ b/src/mission.c @@ -19,6 +19,9 @@ #define MISSION_DATA "../dat/mission.xml" #define MISSION_LUA_PATH "../dat/missions/" +#define luaL_dobuffer(L, b, n, s) \ + (luaL_loadbuffer(L, b, n, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + // Current player missions. static unsigned int mission_id = 0; Mission player_missions[MISSION_MAX]; @@ -31,13 +34,49 @@ static int mission_nstack = 0; extern int misn_run(Mission* misn, char* func); // Static. +static int mission_init(Mission* mission, MissionData* misn); static void mission_cleanup(Mission* misn); -static void mission_free(MissionData* mission); +static void mission_freeData(MissionData* mission); +static int mission_matchFaction(MissionData* misn, int faction); static int mission_location(char* loc); static MissionData* mission_parse(const xmlNodePtr parent); -// Create a mission. -int mission_create(MissionData* misn) { +// Initialize a mission. +static int mission_init(Mission* mission, MissionData* misn) { + char* buf; + uint32_t bufsize; + + mission->id = ++mission_id; + mission->data = misn; + + // Init lua. + mission->L = luaL_newstate(); + if(mission->L == NULL) { + ERR("Unable to create a new lua state."); + return -1; + } + + luaopen_string(mission->L); // string.format can be very useful. + misn_loadLibs(mission->L); // Load our custom libraries. + + buf = pack_readfile(DATA, misn->lua, &bufsize); + if(luaL_dobuffer(mission->L, buf, bufsize, misn->lua) != 0) { + ERR("Error loading AI file: %s", misn->lua); + ERR("%s", lua_tostring(mission->L, -1)); + WARN("Most likely Lua file has improper syntax, please check it"); + return -1; + } + + free(buf); + + // Run create function. + misn_run(mission, "create"); + + return mission->id; +} + +// Add a mission to the player, you can free the current mission safely. +int mission_add(Mission* mission) { int i; // Find last mission. @@ -47,17 +86,11 @@ int mission_create(MissionData* misn) { // No missions left. if(i >= MISSION_MAX) return -1; - player_missions[i].id = ++mission_id; - player_missions[i].data = misn; + // Copy it over. + memcpy(&player_missions[i], mission, sizeof(Mission)); + memset(mission, 0, sizeof(Mission)); - // 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; + return player_missions[i].id; } // Clean up a mission. @@ -71,7 +104,7 @@ static void mission_cleanup(Mission* misn) { } // Free a mission. -static void mission_free(MissionData* mission) { +static void mission_freeData(MissionData* mission) { if(mission->name) { free(mission->name); mission->name = NULL; @@ -91,6 +124,66 @@ static void mission_free(MissionData* mission) { } } +// Free an active mission. +void mission_free(Mission* mission) { + if(mission->id == 0) return; + + if(mission->title) { + free(mission->title); + mission->title = NULL; + } + + if(mission->desc) { + free(mission->desc); + mission->desc = NULL; + } + + if(mission->reward) { + free(mission->reward); + mission->reward = NULL; + } + + if(mission->L) { + lua_close(mission->L); + mission->L = NULL; + } +} + +// Does mission match faction requirement? +static int mission_matchFaction(MissionData* misn, int faction) { + int i; + + for(i = 0; i < misn->avail.nfactions; i++) { + if(faction_isFaction(misn->avail.factions[i]) && + (faction == misn->avail.factions[i])) + return 1; + else if(faction_ofAlliance(faction, misn->avail.factions[i])) + return 1; + } + return 0; +} + +// Generate missions for the computer - special case. +Mission* missions_computer(int* n, int faction, char* planet, char* system) { + int i, m; + Mission* tmp; + MissionData* misn; + + m = 0; + for(i = 0; i < mission_nstack; i++) { + misn = &mission_stack[i]; + if((misn->avail.loc == MIS_AVAIL_COMPUTER) && + (((misn->avail.planet && strcmp(misn->avail.planet, planet)==0)) || + (misn->avail.system && (strcmp(misn->avail.system, system)==0)) || + mission_matchFaction(misn, faction))) { + tmp = realloc(tmp, sizeof(Mission) * ++m); + mission_init(&tmp[m-1], misn); + } + } + (*n) = m; + return tmp; +} + // Return location based on string. static int mission_location(char* loc) { if(strcmp(loc, "None")==0) return MIS_AVAIL_NONE; @@ -126,7 +219,14 @@ static MissionData* mission_parse(const xmlNodePtr parent) { tmp->lua = strdup(str); str[0] = '\0'; } - else if(xml_isNode(node, "avail")) { + else if(xml_isNode(node, "flags")) { // Set the various flags. + cur = node->children; + do { + if(xml_isNode(cur, "unique")) + mis_setFlag(tmp, MISSION_UNIQUE); + } while((cur = cur->next)); + } + else if(xml_isNode(node, "avail")) { // Mission availability. cur = node->children; do { if(xml_isNode(cur, "location")) @@ -206,7 +306,7 @@ void missions_free(void) { // Free the mission data. for(i = 0; i < mission_nstack; i++) - mission_free(&mission_stack[i]); + mission_freeData(&mission_stack[i]); free(mission_stack); mission_stack = NULL; mission_nstack = 0; diff --git a/src/mission.h b/src/mission.h index 091ec6d..ec34803 100644 --- a/src/mission.h +++ b/src/mission.h @@ -14,6 +14,8 @@ #define mis_setFlag(m,f) ((m)->flags |= (f)) #define mis_rmFlag(m,f) ((m)->flags ^= (f)) +#define MISSION_UNIQUE 1 // Unique missions can't be repeated. + // Static mission data. typedef struct MissionData_ { char* name; // the name of the mission. @@ -53,6 +55,11 @@ typedef struct Mission_ { #define MISSION_MAX 6 // No sense in the player having unlimited missions.. extern Mission player_mission[MISSION_MAX]; +// For mission computer. +Mission* missions_computer(int* n, int faction, char* planet, char* system); +// Player accepted mission - mission computer. +void mission_accept(Mission* misn); + // Load/Quit. int missions_load(void); void missions_free(void);