From 6fc39a69e09bc58df6df8e7656358afeee3891c8 Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Sun, 31 Mar 2013 19:00:05 +0100
Subject: [PATCH] [Add] Game now tries to load mission properly, excpet lua
 needs more bindings. ;)

---
 bin/Makefile           |   9 +--
 dat/mission.xml        |   3 +
 dat/missions/cargo.lua |   2 +-
 src/faction.c          |   2 +-
 src/land.c             |  61 ++++++++++++++++++-
 src/mission.c          | 132 ++++++++++++++++++++++++++++++++++++-----
 src/mission.h          |   7 +++
 7 files changed, 191 insertions(+), 25 deletions(-)

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 @@
 <Missions>
   <mission name="Welcome">
+    <flags>
+      <unique>1</unique>
+    </flags>
     <lua>welcome</lua>
     <avail>
       <location>None</location>
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);