From 57dc51fb91a43cdff8ec927f455728f0657b929e Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Sun, 3 Feb 2013 00:37:42 +0000
Subject: [PATCH] [Add] Initial AI support with Lua

---
 bin/ai_test.lua |  4 ++++
 dat/ship.xml    |  2 +-
 src/ai.c        | 60 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/main.c      |  6 ++---
 src/physics.c   | 46 ++++++++++++++++++++++---------------
 src/physics.h   |  6 +++--
 src/pilot.c     |  2 +-
 src/player.c    |  3 +--
 8 files changed, 101 insertions(+), 28 deletions(-)
 create mode 100644 bin/ai_test.lua

diff --git a/bin/ai_test.lua b/bin/ai_test.lua
new file mode 100644
index 0000000..4a9cbd3
--- /dev/null
+++ b/bin/ai_test.lua
@@ -0,0 +1,4 @@
+function control(pilot)
+  accel(1)
+end
+
diff --git a/dat/ship.xml b/dat/ship.xml
index f9ed5f2..e657d1c 100644
--- a/dat/ship.xml
+++ b/dat/ship.xml
@@ -5,7 +5,7 @@
 		<class>1</class>
 		<movement>
 			<thrust>400</thrust>
-			<turn>960</turn>
+			<turn>360</turn>
 			<speed>360</speed>
 		</movement>
 		<health>
diff --git a/src/ai.c b/src/ai.c
index b19aed7..944b73a 100644
--- a/src/ai.c
+++ b/src/ai.c
@@ -6,6 +6,7 @@
 #include "def.h"
 #include "log.h"
 #include "pilot.h"
+#include "physics.h"
 #include "ai.h"
 
 // == AI ======================================================
@@ -21,23 +22,45 @@
 //      (task).
 // ============================================================
 
+// Call the AI function with name f.
+#define AI_LCALL(f) (lua_getglobal(L, f), lua_call(L, 0, 0))
+
+static int ai_minbrakedist(lua_State* L); // Minimal breaking distance.
+static int ai_accel(lua_State* L); // Accelerate.
 
 // Basic task.
 // name   : Tasks name (Lua function.)
 // target : Target, this will depend on the task itself.
 typedef struct {
   char* name;
-  void* target;
+  union {
+    void* target;
+    unsigned int ID;
+  };
 } Task;
 
 // Global Lua interpreter.
 static lua_State* L = NULL;
 
+// Current pilot "thinking" and assorted variables.
+static Pilot* cur_pilot = NULL;
+static double pilot_acc = 0.;
+static double pilot_turn = 0.;
+
 int ai_init(void) {
   L = luaL_newstate();
   if(L == NULL)
     return -1;
 
+  // Register C funstions in Lua.
+  lua_register(L, "minbrakedist", ai_minbrakedist);
+  lua_register(L, "accel", ai_accel);
+
+  if(luaL_dofile(L, "ai_test.lua") != 0) {
+    WARN("Unable to load AI file: %s", "ai_test.lua");
+    return -1;
+  }
+
   return 0;
 }
 
@@ -47,8 +70,43 @@ void ai_exit(void) {
 
 // Heart of hearts of the ai!! Brains of the pilot.
 void ai_think(Pilot* pilot) {
+  cur_pilot = pilot; // Set current pilot being processed.
+  pilot_acc = pilot_turn = 0.; // Clean up some variables.
   if(pilot->action == NULL) {
     // Idle git!
+    AI_LCALL("control");
   }
+
+  cur_pilot->solid->dir_vel = 0.;
+  if(pilot_turn)
+    cur_pilot->solid->dir_vel -= cur_pilot->ship->turn * pilot_turn;
+  vect_pset(&cur_pilot->solid->force, cur_pilot->ship->thrust * pilot_acc, cur_pilot->solid->dir);
+}
+
+// ========================================================
+// C functions to call from Lua.
+// -----------------------------
+// Get the minimum braking distance.
+// 
+// Braking vel ==> v*t = 0.5 a * t^2 => t = 2*v / a
+// Add turn around time (to initial velocity) :
+// ==> 180.*360./cur_pilot->ship->turn
+// Add it to general euler equation x = v*t + 0.5 * a * t^2
+// Have fun.
+// ========================================================
+static int ai_minbrakedist(lua_State* L) {
+  double time = 2. * VMOD(cur_pilot->solid->vel) /
+        (cur_pilot->ship->thrust / cur_pilot->solid->mass);
+
+  double dist = VMOD(cur_pilot->solid->vel) * (time + 0.5 * (180. * 360. / cur_pilot->ship->turn)) -
+        0.5 * (cur_pilot->ship->thrust / cur_pilot->solid->mass)*time*time;
+
+  lua_pushnumber(L, dist); // return
+  return 1;
+}
+
+static int ai_accel(lua_State* L) {
+  pilot_acc = (lua_isnumber(L, 1)) ? (double)lua_tonumber(L, 1) : 1.;
+  return 0;
 }
 
diff --git a/src/main.c b/src/main.c
index abb5b25..fa30dd3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -239,12 +239,12 @@ int main(int argc, char** argv) {
 //        | Text and GUI.
 // ========================================================
 static void update_all(void) {
-  double dt = (double)(SDL_GetTicks() - time) / 1000.0;
+  double dt = (double)(SDL_GetTicks() - time) / 1000.;
   time = SDL_GetTicks();
   
   if(dt > MINIMUM_FPS) {
     Vec2 pos;
-    vect_cinit(&pos, 10., (double)(gl_screen.h-40));
+    vect_cset(&pos, 10., (double)(gl_screen.h-40));
     gl_print(NULL, &pos, "FPS is really low! Skipping frames.");
     SDL_GL_SwapBuffers();
     return;
@@ -273,7 +273,7 @@ static void display_fps(const double dt) {
     fps_dt = fps_cur = 0.;
   }
   Vec2 pos;
-  vect_cinit(&pos, 10., (double)(gl_screen.h-20));
+  vect_cset(&pos, 10., (double)(gl_screen.h-20));
   gl_print(NULL, &pos, "%3.2f", fps);
 }
 
diff --git a/src/physics.c b/src/physics.c
index 7bc523d..f0a0fa8 100644
--- a/src/physics.c
+++ b/src/physics.c
@@ -8,16 +8,33 @@
 #define M_PI 3.14159265358979323846f
 #endif
 
-// Init cartesian vector.
-void vect_cinit(Vec2* v, double x, double y) {
+// Set the vector value using cartesian coords.
+void vect_cset(Vec2* v, double x, double y) {
+  v->x = x;
+  v->y = y;
   v->mod = MOD(x,y);
   v->angle = ANGLE(x, y);
 }
 
-// Init polarized vector
-void vect_pinit(Vec2* v, double mod, double angle) {
+// Set the vector value using polar coords.
+void vect_pset(Vec2* v, double mod, double angle) {
   v->mod = mod;
   v->angle = angle;
+  v->x = v->mod*cos(v->angle);
+  v->y = v->mod*sin(v->angle);
+}
+
+// Copy vector source to destination.
+void vectcpy(Vec2* dest, const Vec2* src) {
+  dest->x = src->x;
+  dest->y = src->y;
+  dest->mod = src->mod;
+  dest->angle = src->angle;
+}
+
+// Null a vector.
+void vectnull(Vec2* v) {
+  v->x = v->y = v->mod = v->angle = 0.;
 }
 
 // ==Update method.========================================
@@ -124,14 +141,12 @@ static void rk4_update(Solid* obj, const double dt) {
       py += ty;
       vy += ay*h;
     }
-    obj->vel.mod = MOD(vx, vy);
-    obj->vel.angle = ANGLE(vx, vy);
+    vect_cset(&obj->vel, vx, vy);
   } else {
     px += dt*vx;
     py += dt*vy;
   }
-  obj->pos.mod = MOD(px, py);
-  obj->pos.angle = ANGLE(px, py);
+  vect_cset(&obj->pos, px, py);
 }
 
 // Initialize a new solid.
@@ -141,18 +156,13 @@ void solid_init(Solid* dest, const double mass, const Vec2* vel, const Vec2* pos
   dest->force.mod = 0;
   dest->dir       = 0;
 
-  if(vel == NULL)
-    vect_cinit(&dest->vel, 0., 0.);
-  else
-    vect_pinit(&dest->vel, vel->mod, vel->angle);
-
-  if(pos == NULL)
-    vect_cinit(&dest->pos, 0., 0.);
-  else
-    vect_pinit(&dest->pos, pos->mod, pos->angle);
+  if(vel == NULL) vectnull(&dest->vel);
+  else vectcpy(&dest->vel, vel);
+  
+  if(pos == NULL) vectnull(&dest->pos);
+  else vectcpy(&dest->pos, pos);
 
   dest->update = rk4_update;
-  //dest->update = simple_update;
 }
 
 // Create a new solid.
diff --git a/src/physics.h b/src/physics.h
index a674dfb..a939652 100644
--- a/src/physics.h
+++ b/src/physics.h
@@ -16,8 +16,10 @@ typedef struct {
 } Vec2;
 
 // Vector manupulation.
-void vect_cinit(Vec2* v, double x, double y);
-void vect_pinit(Vec2* v, double mod, double angle);
+void vect_cset(Vec2* v, double x, double y);
+void vect_pset(Vec2* v, double mod, double angle);
+void vectcpy(Vec2* dest, const Vec2* src);
+void vectnull(Vec2* v);
 
 // Describe any solid in 2D space.
 struct Solid {
diff --git a/src/pilot.c b/src/pilot.c
index 5440ff3..d7077b0 100644
--- a/src/pilot.c
+++ b/src/pilot.c
@@ -56,7 +56,7 @@ static void pilot_update(Pilot* pilot, const double dt) {
   
   if(VMOD(pilot->solid->vel) > pilot->ship->speed) {
     // Should not go faster.
-    VMOD(pilot->solid->vel) = pilot->ship->speed;
+    vect_pset(&pilot->solid->vel, pilot->ship->speed, VANGLE(pilot->solid->vel));
   }
 
   pilot_render(pilot);
diff --git a/src/player.c b/src/player.c
index 56a2841..6ec1aac 100644
--- a/src/player.c
+++ b/src/player.c
@@ -29,8 +29,7 @@ void player_think(Pilot* player, const double dt) {
   if(player_turn)
     player->solid->dir_vel -= player->ship->turn * player_turn;
 
-  player->solid->force.angle = player->solid->dir;
-  player->solid->force.mod = player->ship->thrust * player_acc;
+  vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir);
 }
 
 // Initialization/exit functions (does not assign keys).