From 371e5b8aba6be0fad0e0085cabcfebd5d249a06e Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Thu, 4 Apr 2013 18:15:56 +0100
Subject: [PATCH] [Change] Improved lua api for missions somewhat.

---
 dat/missions/cargo.lua | 29 +++++++++++----
 src/misn_lua.c         | 80 ++++++++++++++++++++++++++++++++++++++----
 src/mission.c          | 20 ++---------
 src/mission.h          |  2 +-
 src/rng.h              |  2 +-
 src/space.c            | 32 +++++++++++++++++
 src/space.h            |  1 +
 7 files changed, 135 insertions(+), 31 deletions(-)

diff --git a/dat/missions/cargo.lua b/dat/missions/cargo.lua
index 183a69a..0cc9ccd 100644
--- a/dat/missions/cargo.lua
+++ b/dat/missions/cargo.lua
@@ -1,7 +1,15 @@
 -- Create the mission.
 function create()
   -- Target destination.
-  planet = space.getPlanet(misn.factions())
+  local i = 0
+  repeat
+    planet = space.getPlanet(misn.factions())
+    i = i + 1
+  until planet ~= space.landName() or i > 10
+  -- Protect agains inf loop.
+  if i > 10 then
+    misn.finish()
+  end
 
   -- Missions generic.
   misn_type = "Rush"
@@ -18,11 +26,20 @@ function create()
 end
 
 function accept()
-  player.addCargo(carg_type, carg_mass)
-  tk.msg("Mission Accepted",
-        string.format("The workers load the %d tons of %s onto your ship.",
-        carg_mass, carg_type))
-  hook.land("land")
+  if player.freeCargo() < carg_mass then
+    tk.msg("Ship is full",
+           string.format("Your ship is too full, You need to make room for \
+                          %d more tons if you want to be able to accept the mission.",
+                          carg_mass-player.freeCargo()))
+    elseif misn.accept() then -- Able to accept the mission, hooks BREAK after accepting.
+      player.addCargo(carg_type, carg_mass)
+      tk.msg("Mission Accepted",
+             string.format("The workers load the %d tons of %s onto your ship.",
+             carg_mass, carg_type))
+      hook.land("land"); -- Only hook after accepting.
+    else
+      tk.msg("Too many missions", "You have too many active missions.")
+    end
 end
 
 function land()
diff --git a/src/misn_lua.c b/src/misn_lua.c
index 1bc3ea6..7cbae32 100644
--- a/src/misn_lua.c
+++ b/src/misn_lua.c
@@ -27,12 +27,14 @@ static int misn_setTitle(lua_State* L);
 static int misn_setDesc(lua_State* L);
 static int misn_setReward(lua_State* L);
 static int misn_factions(lua_State* L);
+static int misn_accept(lua_State* L);
 static int misn_finish(lua_State* L);
 static const luaL_Reg misn_methods[] = {
   { "setTitle",     misn_setTitle   },
   { "setDesc",      misn_setDesc    },
   { "setReward",    misn_setReward  },
   { "factions",     misn_factions   },
+  { "accept",       misn_accept     },
   { "finish",       misn_finish     },
   { 0, 0 }
 };
@@ -154,9 +156,38 @@ static int misn_setReward(lua_State* L) {
 }
 
 static int misn_factions(lua_State* L) {
-  (void) L;
-  // TODO: proper misn.factions() implementation.
-  return 0;
+  int i;
+  MissionData* dat;
+
+  dat = cur_mission->data;
+
+  lua_newtable(L);
+  for(i = 0; i < dat->avail.nfactions; i++) {
+    lua_pushnumber(L, i+1);   // Index, starts with 1.
+    lua_pushnumber(L, dat->avail.factions[i]); // Value.
+    lua_rawset(L, -3);  // Store the value in the table.
+  }
+  return 1;
+}
+
+static int misn_accept(lua_State* L) {
+  int i, ret;
+
+  ret = 0;
+
+  // Find the last mission.
+  //for(i = 0; i < MISSION_MAX; i++)
+    //if(player_missions[i].data == NULL) break;
+
+  // No missions left.
+  if(i >= MISSION_MAX) ret = 1;
+  else {
+    memcpy(&player_missions[i], cur_mission, sizeof(Mission));
+    memset(cur_mission, 0, sizeof(Mission));
+    cur_mission = &player_missions[i];
+  }
+  lua_pushboolean(L, !ret); // We'll convert C style return to lua.
+  return 1;
 }
 
 static int misn_finish(lua_State* L) {
@@ -169,9 +200,46 @@ static int misn_finish(lua_State* L) {
 }
 
 static int space_getPlanet(lua_State* L) {
-  // TODO: Proper getPlanet implementation.
-  lua_pushstring(L, "KonoSphere");
-  return 1;
+  int i;
+  int *factions;
+  int nfactions;
+  char** planets;
+  int nplanets;
+  char* rndplanet;
+
+  if(lua_gettop(L) == 0) {
+    // Get random planet.
+  }
+  else if(lua_istable(L, -1)) {
+    // Get planet of faction in table.
+    
+    // Load up the table.
+    lua_pushnil(L);
+    nfactions = (int) lua_gettop(L);
+    factions = malloc(sizeof(int) * nfactions);
+    i = 0;
+    while(lua_next(L, -2) != 0) {
+      factions[i++] = (int) lua_tonumber(L, -1);
+      lua_pop(L, 1);
+    }
+
+    // Get the planets.
+    planets = space_getFactionPlanet(&nplanets, factions, nfactions);
+    free(factions);
+
+    // Choose random planet.
+    if(nplanets == 0) {
+      // No suitable planets.
+      free(planets);
+      return 0;;
+    }
+    rndplanet = planets[RNG(0, nplanets)];
+    free(planets);
+
+    lua_pushstring(L, rndplanet);
+    return 1;
+  }
+  return 0; // Nothing good passed.
 }
 
 static int space_landName(lua_State* L) {
diff --git a/src/mission.c b/src/mission.c
index f731122..cc04c18 100644
--- a/src/mission.c
+++ b/src/mission.c
@@ -60,7 +60,8 @@ static int mission_init(Mission* mission, MissionData* misn) {
     ERR("Unable to create a new lua state.");
     return -1;
   }
-
+  
+  luaopen_base(mission->L);   // Can be useful.
   luaopen_string(mission->L); // string.format can be very useful.
   misn_loadLibs(mission->L);  // Load our custom libraries.
 
@@ -80,23 +81,8 @@ static int mission_init(Mission* mission, MissionData* misn) {
   return mission->id;
 }
 
-// Accept mission, used basically for mission computers.
 void mission_accept(Mission* mission) {
-  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;
-
-  // Copy it over.
-  memcpy(&player_missions[i], mission, sizeof(Mission));
-  memset(mission, 0, sizeof(Mission));
-  
-  // Run the accept commandz.
-  misn_run(&player_missions[i], "accept");
+  misn_run(mission, "accept");
 }
 
 // Clean up a mission.
diff --git a/src/mission.h b/src/mission.h
index 92a1331..5083a78 100644
--- a/src/mission.h
+++ b/src/mission.h
@@ -53,7 +53,7 @@ typedef struct Mission_ {
 } Mission;
 
 #define MISSION_MAX 6 // No sense in the player having unlimited missions..
-extern Mission player_mission[MISSION_MAX];
+extern Mission player_missions[MISSION_MAX];
 
 // For mission computer.
 Mission* missions_computer(int* n, int faction, char* planet, char* system);
diff --git a/src/rng.h b/src/rng.h
index 212e4eb..eea770a 100644
--- a/src/rng.h
+++ b/src/rng.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#define RNG(L,H)  ((int)L + (int)((double)(H-L+1) * randfp()))
+#define RNG(L,H)  ((int)L + (int)((double)(H-L) * randfp())) // L <= RNG <= H
 #define RNGF()  (randfp())
 
 void rng_init(void);
diff --git a/src/space.c b/src/space.c
index f64b2ed..a281ee7 100644
--- a/src/space.c
+++ b/src/space.c
@@ -193,6 +193,38 @@ int space_hyperspace(Pilot* p) {
   return 0;
 }
 
+// Return the name of all the planets that belong to factions.
+char** space_getFactionPlanet(int* nplanets, int* factions, int nfactions) {
+  int i, j, k;
+  Planet* planet;
+  char** tmp;
+  int ntmp;
+  int mtmp;
+
+  ntmp = 0;
+  mtmp = 25;
+  tmp = malloc(sizeof(char*) * mtmp);
+
+  for(i = 0; i < systems_nstack; i++)
+    for(j = 0; j < systems_stack[i].nplanets; j++) {
+      planet = &systems_stack[i].planets[j];
+      for(k = 0; k < nfactions; k++)
+        if((faction_isFaction(factions[k]) &&
+              (planet->faction == factions[k])) ||
+            (faction_isAlliance(factions[k]) &&
+             faction_ofAlliance(planet->faction, factions[k]))) {
+          ntmp++;
+          if(ntmp > mtmp) {
+            mtmp += 25;
+            tmp = realloc(tmp, sizeof(char*) * mtmp);
+          }
+          tmp[ntmp-1] = planet->name;
+        }
+    }
+  (*nplanets) = ntmp;
+  return tmp;
+}
+
 // Basically used for spawning fleets.
 void space_update(const double dt) {
   unsigned int t;
diff --git a/src/space.h b/src/space.h
index 6d77eba..eb7c38b 100644
--- a/src/space.h
+++ b/src/space.h
@@ -108,5 +108,6 @@ void space_update(const double dt);
 // Misc.
 int space_canHyperspace(Pilot* p);
 int space_hyperspace(Pilot* p);
+char** space_getFactionPlanet(int* nplanets, int* factions, int nfactions);
 extern char* stardate;