From 6a2f07b5b793832c77553d486cd2e3b31920185a Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Mon, 4 Feb 2013 11:00:32 +0000
Subject: [PATCH] [Change] Optimized ai API some. [Fix] Few mem leaks.

---
 scripts/ai/API      |  2 +-
 scripts/ai/test.lua |  8 +++--
 src/ai.c            | 21 ++++++++---
 src/main.c          | 26 +++++++++++---
 src/opengl.c        |  2 ++
 src/physics.c       |  6 ++++
 src/physics.h       |  2 ++
 src/pilot.c         | 21 +++++++++++
 src/pilot.h         |  1 +
 src/player.c        | 12 +++++++
 src/player.h        |  3 ++
 src/space.c         | 85 ++++++++++++++++++++++++++++-----------------
 12 files changed, 145 insertions(+), 44 deletions(-)

diff --git a/scripts/ai/API b/scripts/ai/API
index 7f0dab2..c698b5b 100644
--- a/scripts/ai/API
+++ b/scripts/ai/API
@@ -64,7 +64,7 @@ face(number/Vec2 target, number invert)
   -- Turn to face the current target.
     -- target pilot ID or Vec2 to face.
     -- invert face away if 1
-    -- return nil
+    -- return number offset from target in grad
 
 // ================
 // MISC!
diff --git a/scripts/ai/test.lua b/scripts/ai/test.lua
index 09a1a41..6efafd7 100644
--- a/scripts/ai/test.lua
+++ b/scripts/ai/test.lua
@@ -1,6 +1,10 @@
 function follow()
-  face(1,1)
-  accel(1)
+  target = 1
+  dir = face(target)
+  dist = getdist(getpos(target))
+  if dir < 10 and dist > 100 then
+    accel()
+  end
 end
 
 function goto()
diff --git a/src/ai.c b/src/ai.c
index a813470..3cb4fa6 100644
--- a/src/ai.c
+++ b/src/ai.c
@@ -62,6 +62,12 @@ static Pilot* cur_pilot = NULL;
 static double pilot_acc = 0.;
 static double pilot_turn = 0.;
 
+// Destroy the AI part of the pilot.
+void ai_destroy(Pilot* p) {
+  ai_freetask(p->task);
+}
+
+// Init the AI stuff. Which is basically Lua.
 int ai_init(void) {
   L = luaL_newstate();
   if(L == NULL)
@@ -76,7 +82,7 @@ int ai_init(void) {
   lua_register(L, "taskname",     ai_taskname);
   lua_register(L, "gettarget",    ai_gettarget);
   lua_register(L, "gettargetid",  ai_gettargetid);
-  lua_register(L, "getdistance",  ai_getdistance);
+  lua_register(L, "getdist",      ai_getdistance);
   lua_register(L, "getpos",       ai_getpos);
   lua_register(L, "minbrakedist", ai_minbrakedist);
   lua_register(L, "accel",        ai_accel);
@@ -96,6 +102,7 @@ int ai_init(void) {
   return 0;
 }
 
+// Clean up global AI
 void ai_exit(void) {
   lua_close(L);
 }
@@ -148,6 +155,7 @@ static int ai_pushtask(lua_State* L) {
   Task* t = MALLOC_L(Task);
   t->name = (lua_isstring(L, 2)) ? strdup((char*) lua_tostring(L, 2)) : NULL;
   t->next = NULL;
+  t->target = NULL;
 
   if(lua_gettop(L) > 2) {
     if(lua_isnumber(L, 3))
@@ -241,8 +249,7 @@ static int ai_minbrakedist(lua_State* L) {
 
 // Accelerate the pilot based on a param.
 static int ai_accel(lua_State* L) {
-  MIN_ARGS(1);
-  pilot_acc = (lua_isnumber(L, 1)) ? ABS((double)lua_tonumber(L, 1)) : 1.;
+  pilot_acc = (lua_gettop(L) > 1 && lua_isnumber(L, 1)) ? ABS((double)lua_tonumber(L, 1)) : 1.;
   return 0;
 }
 
@@ -263,13 +270,17 @@ static int ai_face(lua_State* L) {
   double mod = 10;
   if(lua_gettop(L) > 1 && lua_isnumber(L,2))
     switch((int)lua_tonumber(L,2)) {
+      case 0: break;
       case 1: mod *= -1; break;
       case 2: break;
     }
+  double diff = angle_diff(cur_pilot->solid->dir, vect_angle(&cur_pilot->solid->pos, v));
   
-  pilot_turn = mod * angle_diff(cur_pilot->solid->dir, vect_angle(&cur_pilot->solid->pos, v));
+  pilot_turn = mod*diff;
 
-  return 0;
+  lua_pushnumber(L, ABS(diff*180./M_PI));
+
+  return 1;
 }
 
 // Create a vector.
diff --git a/src/main.c b/src/main.c
index 6384edd..14c9bba 100644
--- a/src/main.c
+++ b/src/main.c
@@ -28,6 +28,8 @@ extern const char* keybindNames[]; // Keybindings.
 static int quit = 0; // Primary loop.
 static unsigned int time = 0; // Calculate FPS and movement.
 
+static int show_fps = 1; // Default - True.
+
 // Prototypes.
 
 static void print_usage(char** argv);
@@ -82,6 +84,10 @@ int main(int argc, char** argv) {
       if((int)lua_tonumber(L, -1) == 1)
         gl_screen.fullscreen = 1;
 
+    lua_getglobal(L, "fps");
+    if(lua_isnumber(L, -1))
+      show_fps = (int)lua_tonumber(L, -1);
+
     // Joystick.
     lua_getglobal(L, "joystick");
     if(lua_isnumber(L, -1))
@@ -137,19 +143,23 @@ int main(int argc, char** argv) {
   // Parse arguments.
   static struct option long_options[] = {
     { "fullscreen", no_argument, 0, 'f' },
+    { "fps", optional_argument, 0, 'F' },
     { "joystick", required_argument, 0, 'j' },
     { "joystick", required_argument, 0, 'J' },
     { "help", no_argument, 0, 'h' },
     { "version", no_argument, 0, 'v' },
-    { 0, 0, 0, 0 }
+    { NULL, 0, 0, 0 }
   };
   int option_index = 0;
   int c = 0;
-  while((c = getopt_long(argc, argv, "fJ:j:hv", long_options, &option_index)) != -1) {
+  while((c = getopt_long(argc, argv, "fFJ:j:hv", long_options, &option_index)) != -1) {
     switch(c) {
       case 'f':
         gl_screen.fullscreen = 1;
         break;
+      case 'F':
+        if(optarg != NULL) show_fps = atoi(optarg);
+        break;
       case 'j':
         indjoystick = atoi(optarg);
         break;
@@ -256,7 +266,7 @@ static void update_all(void) {
   
   if(dt > MINIMUM_FPS) {
     Vec2 pos;
-    vect_cset(&pos, 10., (double)(gl_screen.h-40));
+    vect_csetmin(&pos, 10., (double)(gl_screen.h-40));
     gl_print(NULL, &pos, "FPS is really low! Skipping frames.");
     SDL_GL_SwapBuffers();
     return;
@@ -264,10 +274,15 @@ static void update_all(void) {
 
   glClear(GL_COLOR_BUFFER_BIT);
   
+  // BG.
   space_render(dt);
   planets_render();
   
+  // N
   pilots_update(dt);
+  
+  // FG.
+  player_renderGUI();
 
   display_fps(dt);
 
@@ -287,7 +302,8 @@ static void display_fps(const double dt) {
     fps_dt = fps_cur = 0.;
   }
   Vec2 pos;
-  vect_cset(&pos, 10., (double)(gl_screen.h-20));
-  gl_print(NULL, &pos, "%3.2f", fps);
+  vect_csetmin(&pos, 10., (double)(gl_screen.h-20));
+  if(show_fps)
+    gl_print(NULL, &pos, "%3.2f", fps);
 }
 
diff --git a/src/opengl.c b/src/opengl.c
index aa0b43d..132d11a 100644
--- a/src/opengl.c
+++ b/src/opengl.c
@@ -420,6 +420,8 @@ static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* te
 
   // End of the display list.
   glEndList();
+
+  FT_Done_Glyph(glyph);
 }
 
 void gl_fontInit(gl_font* font, const char* fname, unsigned int h) {
diff --git a/src/physics.c b/src/physics.c
index 12d587e..8e3c103 100644
--- a/src/physics.c
+++ b/src/physics.c
@@ -25,6 +25,12 @@ void vect_cset(Vec2* v, const double x, const double y) {
   v->angle = ANGLE(x, y);
 }
 
+// Create a minimal vector, only valid for blitting.
+void vect_csetmin(Vec2* v, const double x, const double y) {
+  v->x = x;
+  v->y = y;
+}
+
 // Set the vector value using polar coords.
 void vect_pset(Vec2* v, const double mod, const double angle) {
   v->mod = mod;
diff --git a/src/physics.h b/src/physics.h
index 77f6e28..1940ecd 100644
--- a/src/physics.h
+++ b/src/physics.h
@@ -20,6 +20,8 @@ typedef struct {
 
 // Vector manupulation.
 void vect_cset(Vec2* v, const double x, const double y);
+// Doesn't set mod nor angle.
+void vect_csetmin(Vec2* v, const double x, const double y);
 void vect_pset(Vec2* v, const double mod, const double angle);
 void vectcpy(Vec2* dest, const Vec2* src);
 void vectnull(Vec2* v);
diff --git a/src/pilot.c b/src/pilot.c
index 180f76d..e124e44 100644
--- a/src/pilot.c
+++ b/src/pilot.c
@@ -14,8 +14,11 @@ static unsigned int pilot_id = 0;
 static Pilot** pilot_stack;
 static int pilots = 0;
 
+// External.
+extern void ai_destroy(Pilot* p); // Ai.
 extern void player_think(Pilot* pilot, const double dt); // Player.c
 extern void ai_think(Pilot* pilot); // Ai.c
+// Internal.
 static void pilot_update(Pilot* pilot, const double dt);
 static void pilot_render(Pilot* pilot);
 
@@ -110,6 +113,24 @@ unsigned int pilot_create(Ship* ship, char* name, const Vec2* vel, const Vec2* p
   return dyn->id;
 }
 
+// Frees and cleans up a pilot.
+void pilot_destroy(Pilot* p) {
+  int i;
+
+  solid_free(p->solid);
+  free(p->name);
+  ai_destroy(p);
+
+  for(i = 0; i < pilots; i++)
+    if(pilot_stack[i] == p)
+      break;
+  while(i < pilots) {
+    pilot_stack[i] = pilot_stack[i+1];
+    i++;
+  }
+  free(p);
+}
+
 // Free the prisoned pilot!
 void pilots_free(void) {
   int i;
diff --git a/src/pilot.h b/src/pilot.h
index 65e0d07..26fa190 100644
--- a/src/pilot.h
+++ b/src/pilot.h
@@ -39,6 +39,7 @@ unsigned int pilot_create(Ship* ship, char* name, const Vec2* vel,
       const Vec2* pos, const int flags);
 
 // Cleanup.
+void pilot_destroy(Pilot* p);
 void pilots_free(void);
 
 // Update.
diff --git a/src/player.c b/src/player.c
index 2736bc6..deaaf60 100644
--- a/src/player.c
+++ b/src/player.c
@@ -32,6 +32,17 @@ void player_think(Pilot* player, const double dt) {
   vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir);
 }
 
+// ================
+// GUI!
+// ================
+void player_renderGUI(void) {
+
+}
+
+
+// ================
+// INPUT!
+// ================
 // Initialization/exit functions (does not assign keys).
 void input_init(void) {
   Keybind* tmp;
@@ -178,6 +189,7 @@ void input_handle(SDL_Event* event) {
       break;
     case SDL_JOYBUTTONUP:
       input_joyup(event->jbutton.button);
+      break;
     case SDL_KEYDOWN:
       input_keydown(event->key.keysym.sym);
       break;
diff --git a/src/player.h b/src/player.h
index 6083a2f..dc248d5 100644
--- a/src/player.h
+++ b/src/player.h
@@ -3,6 +3,9 @@
 
 typedef enum { KEYBIND_NULL, KEYBIND_KEYBOARD, KEYBIND_JAXIS, KEYBIND_JBUTTON } KeybindType;
 
+// GUI.
+void player_renderGUI(void);
+
 int player_isFlag(unsigned int flag);
 void player_setFlag(unsigned int flag);
 void player_rmFlag(unsigned int flag);
diff --git a/src/space.c b/src/space.c
index c7b7006..93d2790 100644
--- a/src/space.c
+++ b/src/space.c
@@ -26,6 +26,13 @@
 
 #define PLANET_GFX      "../gfx/planet/"
 
+// Overcome warning due to zero value.
+
+#define FLAG_XSET           (1<<0)
+#define FLAG_YSET           (1<<1)
+#define FLAG_ASTEROIDSSET    (1<<2)
+#define FLAG_INTEFERENCESET (1<<3)
+
 // Planet types. I didn't take them from Star Trek, I promise.
 typedef enum {
   PLANET_CLASS_A, // Geothermal.
@@ -55,14 +62,14 @@ typedef enum {
 
 typedef struct {
   char* name;
-  double x, y; // Position in star system.
+  Vec2 pos; // Position in star system.
   PlanetClass class;
   gl_texture* gfx_space; // Graphics in space.
 } Planet;
 
 typedef struct {
   char* name;
-  double x, y; // Position.
+  Vec2 pos; // Position.
   int stars, asteroids; // Un numero!
   double interference; // Un uh.. Percentage.
 
@@ -112,6 +119,9 @@ static Planet* planet_get(const char* name) {
   Planet* tmp = NULL;
 
   char str[MAX_PATH_NAME] = "\0";
+  char* tstr;
+
+  uint32_t flags = 0;
 
   uint32_t bufsize;
   char* buf = pack_readfile(DATA, PLANET_DATA, &bufsize);
@@ -133,9 +143,10 @@ static Planet* planet_get(const char* name) {
 
   do {
     if(node->type == XML_NODE_START && strcmp((char*)node->name, XML_PLANET_TAG)==0) {
-      if(strcmp((char*)xmlGetProp(node, (xmlChar*)"name"), name)==0) { // Found.
+      tstr = (char*)xmlGetProp(node, (xmlChar*)"name");
+      if(strcmp(tstr, name)==0) { // Found.
         tmp = CALLOC_L(Planet);
-        tmp->name = strdup(name);
+        tmp->name = tstr;
 
         node = node->xmlChildrenNode;
 
@@ -151,10 +162,14 @@ static Planet* planet_get(const char* name) {
           else if(strcmp((char*)node->name, "pos")==0) {
             cur = node->children;
             while((cur = cur->next)) {
-              if(strcmp((char*)cur->name, "x")==0)
-                tmp->x = atof((char*)cur->children->content);
-              else if(strcmp((char*)cur->name, "y")==0)
-                tmp->y = atof((char*)cur->children->content);
+              if(strcmp((char*)cur->name, "x")==0) {
+                flags |= FLAG_XSET;
+                tmp->pos.x = atof((char*)cur->children->content);
+              }
+              else if(strcmp((char*)cur->name, "y")==0) {
+                flags |= FLAG_YSET;
+                tmp->pos.y = atof((char*)cur->children->content);
+              }
             }
           }
           else if(strcmp((char*)node->name, "general")==0) {
@@ -166,7 +181,8 @@ static Planet* planet_get(const char* name) {
           }
         }
         break;
-      }
+      } else
+        free(tstr); // xmlGetProp mallocs the string.
     }
   } while((node = node->next));
 
@@ -176,9 +192,9 @@ static Planet* planet_get(const char* name) {
 
   // Check elements.
   if(tmp) {
-#define MELEMENT(o,s) if(o == 0) WARN("Planet '%s' missing '"s"' element", tmp->name)
-    MELEMENT(tmp->x, "x");
-    MELEMENT(tmp->x, "y");
+#define MELEMENT(o,s) if((o) == 0) WARN("Planet '%s' missing '"s"' element", tmp->name)
+    MELEMENT(flags&FLAG_XSET, "x");
+    MELEMENT(flags&FLAG_YSET, "y");
     MELEMENT(tmp->class, "class");
 #undef MELEMENT
   } else
@@ -194,8 +210,10 @@ static StarSystem* system_parse(const xmlNodePtr parent) {
   StarSystem* tmp = CALLOC_L(StarSystem);
   xmlNodePtr cur, node;
 
-  tmp->name = strdup((char*) xmlGetProp(parent, (xmlChar*)"name"));
-  
+  uint32_t flags;
+
+  tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); // Already mallocs.
+
   node = parent->xmlChildrenNode;
 
   while((node = node->next)) {
@@ -203,21 +221,29 @@ static StarSystem* system_parse(const xmlNodePtr parent) {
     if(strcmp((char*)node->name, "pos")==0) {
       cur = node->children;
       while((cur = cur->next)) {
-        if(strcmp((char*)cur->name, "x")==0)
-          tmp->x = atof((char*)cur->children->content);
-        if(strcmp((char*)cur->name, "y")==0)
-          tmp->y = atof((char*)cur->children->content);
+        if(strcmp((char*)cur->name, "x")==0) {
+          flags |= FLAG_XSET;
+          tmp->pos.x = atof((char*)cur->children->content);
+        }
+        if(strcmp((char*)cur->name, "y")==0) {
+          flags |= FLAG_YSET;
+          tmp->pos.y = atof((char*)cur->children->content);
+        }
       }
     }
     else if(strcmp((char*)node->name, "general")==0) {
       cur = node->children;
       while((cur = cur->next)) {
-        if(strcmp((char*)cur->name, "stars")==0)
+        if(strcmp((char*)cur->name, "stars")==0) // Non-zero.
           tmp->stars = atoi((char*)cur->children->content);
-        else if(strcmp((char*)cur->name, "asteroids")==0)
+        else if(strcmp((char*)cur->name, "asteroids")==0) {
+          flags |= FLAG_ASTEROIDSSET;
           tmp->asteroids = atoi((char*)cur->children->content);
-        else if(strcmp((char*)cur->name, "interference")==0)
+        }
+        else if(strcmp((char*)cur->name, "interference")==0) {
+          flags |= FLAG_INTEFERENCESET;
           tmp->interference = atof((char*)cur->children->content);
+        }
       }
     }
     else if(strcmp((char*)node->name, "planets")==0) {
@@ -233,12 +259,12 @@ static StarSystem* system_parse(const xmlNodePtr parent) {
     }
   }
   // Check elements.
-#define MELEMENT(o,s) if(o == 0) WARN("Star System '%s' missing '"s"' element", tmp->name)
-  MELEMENT(tmp->x, "x");
-  MELEMENT(tmp->x, "y");
+#define MELEMENT(o,s) if((o) == 0) WARN("Star System '%s' missing '"s"' element", tmp->name)
+  MELEMENT(flags&FLAG_XSET, "x");
+  MELEMENT(flags&FLAG_YSET, "y");
   MELEMENT(tmp->stars, "stars");
-  /*MELEMENT(tmp->asteroids, "asteroids"); // Can be 0.
-  MELEMENT(tmp->interference, "interference");*/
+  MELEMENT(flags&FLAG_ASTEROIDSSET, "asteroids"); // Can be 0.
+  MELEMENT(flags&FLAG_INTEFERENCESET, "inteference");
 #undef MELEMENT
   DEBUG("Loaded Star System '%s' with %d Planets%s", tmp->name, tmp->nplanets, (tmp->nplanets > 1) ? "s" : "");
 
@@ -314,11 +340,8 @@ void space_render(double dt) {
 void planets_render(void) {
   int i;
   Vec2 v;
-  for(i = 0; i < cur_system->nplanets; i++) {
-    v.x = cur_system->planets[i].x;
-    v.y = cur_system->planets[i].y;
-    gl_blitSprite(cur_system->planets[i].gfx_space, &v, 0, 0);
-  }
+  for(i = 0; i < cur_system->nplanets; i++)
+    gl_blitSprite(cur_system->planets[i].gfx_space, &cur_system->planets[i].pos, 0, 0);
 }
 
 // Clean up the system.