From 29b8b5ba18d0b2d15ba575b73d9d5703cc9e9c28 Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Sun, 10 Feb 2013 18:32:02 +0000
Subject: [PATCH] [Add] A few more AI calls. [Add] Ai protection and some
 tweaks.   -- eg. Once armor/shield is regenerated, enemy will come back for
 another round.

---
 bin/conf.example      | 15 ++++-----
 scripts/ai/API        | 15 +++++++++
 scripts/ai/pirate.lua | 35 ++++++++++++++++++---
 scripts/ai/test.lua   | 14 +++++++++
 src/ai.c              | 72 ++++++++++++++++++++++++++++++++++++++++---
 src/pilot.h           |  6 ++--
 src/space.c           | 28 +++++++++++++++++
 src/space.h           |  4 +++
 8 files changed, 171 insertions(+), 18 deletions(-)

diff --git a/bin/conf.example b/bin/conf.example
index e936dca..80631c5 100644
--- a/bin/conf.example
+++ b/bin/conf.example
@@ -16,11 +16,12 @@ joystick = "Precision"
 -- If left is an axis, it will automatically set right to the same axis.
 -- setting both to the same axis (key).
 -- You can use reverse = 1 option to reverse them.
-accel       = { type = "jbutton", key = 0 }
-left        = { type = "jaxis", key = 0 }
-right       = { type = "jaxis", key = 0 }
-primary     = { type = "jbutton", key = 1 }
-target      = { type = "jbutton", key = 4 }
-mapzoomin   = { type = "jbutton", key = 7 }
-mapzoomout  = { type = "jbuton", key = 6 }
+accel           = { type = "jbutton", key = 0 }
+left            = { type = "jaxis",   key = 0 }
+right           = { type = "jaxis",   key = 0 }
+primary         = { type = "jbutton", key = 1 }
+target          = { type = "jbutton", key = 4 }
+target_nearest  = { type = "jbutton", key = 3 }
+mapzoomin       = { type = "jbutton", key = 7 }
+mapzoomout      = { type = "jbuton",  key = 6 }
 
diff --git a/scripts/ai/API b/scripts/ai/API
index 04e8fe5..a2a7a55 100644
--- a/scripts/ai/API
+++ b/scripts/ai/API
@@ -71,6 +71,11 @@ pshield()
 // BOOLEAN!
 // ================
 
+exists(number id)
+  -- Check to see if pilot id is valid.
+    -- id -- Pilot to check.
+    -- return true if the pilot is valid.
+
 ismaxval()
   -- Check if velocity is maximum.
     -- return true if velocity is max, false otherwise.
@@ -89,6 +94,11 @@ isally(Pilot p)
     -- p - Pilot to check if ally.
     -- return true if p is ally.
 
+incombat([number id])
+  -- Queries whether a pilot is in combat or not.
+    -- id - Pilot to check if is in combat. -- Defaults to self.
+    -- return if pilos is in combat or not.
+
 // ================
 // MOVEMENT!
 // ================
@@ -125,6 +135,11 @@ getrndplanet()
 // COMBAT!
 // ================
 
+combat([number b])
+  -- Set pilot as either in combat or out (for comm etc.)
+    -- b - if 0 set the pilot to be in combat, if 1 or ommitted sets it to be in combat.
+    -- return nil
+
 shoot([number weapon])
   -- Make the pilot shoot weapons.
     -- weapon to shoot, 1 if primary, 2 if secondary, 3 if both. Defaults to 1.
diff --git a/scripts/ai/pirate.lua b/scripts/ai/pirate.lua
index a8cc666..99299cd 100644
--- a/scripts/ai/pirate.lua
+++ b/scripts/ai/pirate.lua
@@ -4,10 +4,19 @@ control_rate = 2
 -- Required "control" function.
 function control()
   task = taskname()
-  if task ~= "attack" and task ~= "runaway" then
+
+  -- Running pilot has healed up some.
+  if task == "runaway" then
+    if parmor() == 100 then
+      -- "attack" should be called after "runaway".
+      poptask()
+    end
+
+    -- Nothing to do.
+  elseif task ~= "attack" and task ~= "runaway" then
     -- If getenemy() is 0, there is no enemy around.
     enemy = getenemy()
-    if enemy ~= 0 then
+    if parmor() == 100 and enemy ~= 0 then
       -- Taunts.
       num = rng(0,4)
       if num == 0 then msg "Prepare to be boarded!"
@@ -20,7 +29,9 @@ function control()
       hostile(enemy)
 
       -- Go ahead and attack.
-      pushtask(0, "attack", enemy)
+      combat() -- Set to be in combat.
+      pushtask(0, "attack", enemy) -- Begin the attack.
+    -- Nothing to attack.
     else
       pushtask(0, "fly")
     end
@@ -30,9 +41,12 @@ end
 -- Required "attacked" function
 function attacked(attacker)
   task = taskname()
+
+  -- Pirate isn't fighting or fleeing already.
   if task ~= "attack" and task ~= "runaway" then
     taunt()
     pushtask(0, "attack", attacker)
+  -- Pirate is fighting bit switches to new target (doesn't forget the old on though).
   elseif task == "attack" then
     if gettargetid() ~= attacker then
       pushtask(0, "attack", attacker)
@@ -53,6 +67,13 @@ end
 -- Run away from the target.
 function runaway()
   target = gettargerid()
+
+  -- Ensure target exists.
+  if not exists(targe) then
+    poptask()
+    return
+  end
+
   dir = face(target, 1)
   accel()
 end
@@ -60,12 +81,18 @@ end
 -- Attack the target.
 function attack()
   target = gettargetid()
+
+  -- Ensure target exists.
+  if not exists(target) then
+    poptask()
+    return
+  end
+
   dir = face(target)
   dist = getdist(getpos(target))
 
   -- We need to know when to run away.
   if parmor() < 70 then
-    poptask()
     pushtask(0, "runaway", target)
   -- Try to obliterate the target.
   elseif dir < 10 and dist > 300 then
diff --git a/scripts/ai/test.lua b/scripts/ai/test.lua
index f09b92a..dd6f971 100644
--- a/scripts/ai/test.lua
+++ b/scripts/ai/test.lua
@@ -28,6 +28,13 @@ end
 -- Runs away.
 function runaway()
   target = gettargetid()
+
+  -- Make sure pilot exists.
+  if not exists(target) then
+    poptask()
+    return
+  end
+
   dir = face(target, 1)
   accel()
 end
@@ -35,6 +42,13 @@ end
 -- Attack
 function attack()
   target = gettargetid()
+
+  -- Make sure target exists.
+  if not exists(target) then
+    poptask()
+    return
+  end
+
   dir = face(target)
   dist = getdist(getpos(target))
 
diff --git a/src/ai.c b/src/ai.c
index bf9fd2f..751c834 100644
--- a/src/ai.c
+++ b/src/ai.c
@@ -98,10 +98,12 @@ static int ai_getdistance(lua_State* L);        // Number getdist(Vec2)
 static int ai_getpos(lua_State* L);             // getpos(number)
 static int ai_minbrakedist(lua_State* L);       // Number minbrakedist()
 // Boolean expressions.
+static int ai_exists(lua_State* L);             // boolean exists
 static int ai_ismaxvel(lua_State* L);           // Boolean ismaxvel()
 static int ai_isstopped(lua_State* L);          // Boolean isstopped()
-static int ai_isenemy(lua_State* L);            // bool isenemy(number).
-static int ai_isally(lua_State* L);             // bool isally(number).
+static int ai_isenemy(lua_State* L);            // boolean isenemy(number).
+static int ai_isally(lua_State* L);             // boolean isally(number).
+static int ai_incombat(lua_State* L);           // boolean incombat([number])
 // Movement.
 static int ai_accel(lua_State* L);              // accel(number); nuimber <= 1.
 static int ai_turn(lua_State* L);               // turn(number); abs(number) <= 1.
@@ -109,13 +111,15 @@ static int ai_face(lua_State* L);               // face(number/pointer)
 static int ai_brake(lua_State* L);              // Brake()
 static int ai_getnearestplanet(lua_State* L);   // pointer getnearestplanet()
 static int ai_getrndplanet(lua_State* L);       // pointer getrndplanet()
+static int ai_hyperspace(lua_State* L);         // [number] hyperspace()
 // Combat.
+static int ai_combat(lua_State* L);             // combat(number)
 static int ai_shoot(lua_State* L);              // shoot(number) number = 1,2,3.
 static int ai_getenemy(lua_State* L);           // number getenemy().
 static int ai_hostile(lua_State* L);            // hostile(number).
 // Timers.
 static int ai_settimer(lua_State* L);           // settimer(number, number)
-static int ai_timeup(lua_State* L);             // bool timeup(number)
+static int ai_timeup(lua_State* L);             // boolean timeup(number)
 // Misc.
 static int ai_createvect(lua_State* L);         // createvect(number, number)
 static int ai_comm(lua_State* L);               // comm(string)
@@ -200,10 +204,12 @@ static int ai_loadProfile(char* filename) {
   lua_register(L, "getpos",             ai_getpos);
   lua_register(L, "minbrakedist",       ai_minbrakedist);
   // Boolean.
+  lua_register(L, "exists",             ai_exists);
   lua_register(L, "ismaxvel",           ai_ismaxvel);
   lua_register(L, "isstopped",          ai_isstopped);
   lua_register(L, "isenemy",            ai_isenemy);
   lua_register(L, "isally",             ai_isally);
+  lua_register(L, "incombat",           ai_incombat);
   // Movement.
   lua_register(L, "accel",              ai_accel);
   lua_register(L, "turn",               ai_turn);
@@ -211,7 +217,9 @@ static int ai_loadProfile(char* filename) {
   lua_register(L, "brake",              ai_brake);
   lua_register(L, "getnearestplanet",   ai_getnearestplanet);
   lua_register(L, "getrndplanet",       ai_getrndplanet);
+  lua_register(L, "hyperspace",         ai_hyperspace);
   // Combat.
+  lua_register(L, "combat",             ai_combat);
   lua_register(L, "shoot",              ai_shoot);
   lua_register(L, "getenemy",           ai_getenemy);
   lua_register(L, "hostile",            ai_hostile);
@@ -459,7 +467,10 @@ static int ai_getdistance(lua_State* L) {
 // Get the pilots position.
 static int ai_getpos(lua_State* L) {
   Pilot* p;
-  if(lua_isnumber(L, 1)) p = pilot_get((int)lua_tonumber(L,1)); // Pilot ID.
+  if(lua_isnumber(L, 1)) {
+    p = pilot_get((int)lua_tonumber(L,1)); // Pilot ID.
+    if(p == NULL) return 0;
+  }
   else p = cur_pilot; // Default to ones self.
 
   lua_pushlightuserdata(L, &p->solid->pos);
@@ -487,6 +498,16 @@ static int ai_minbrakedist(lua_State* L) {
   return 1;
 }
 
+static int ai_exists(lua_State* L) {
+  MIN_ARGS(1);
+  
+  if(lua_isnumber(L,1)) {
+    lua_pushboolean(L, (int)pilot_get((unsigned int)lua_tonumber(L,1)));
+    return 1;
+  }
+  return 0;
+}
+
 // Are we at max velocity?
 static int ai_ismaxvel(lua_State* L) {
   lua_pushboolean(L, VMOD(cur_pilot->solid->vel) == cur_pilot->ship->speed);
@@ -512,6 +533,17 @@ static int ai_isally(lua_State* L) {
   return 1;
 }
 
+// Check to see if the pilot is in combat. Defaults to self.
+static int ai_incombat(lua_State* L) {
+  Pilot* p;
+
+  if(lua_isnumber(L, 1)) p = pilot_get((unsigned int)lua_tonumber(L,1));
+  else p = cur_pilot;
+
+  lua_pushboolean(L,pilot_isFlag(p, PILOT_COMBAT));
+  return 1;
+}
+
 // Accelerate the pilot based on a param.
 static int ai_accel(lua_State* L) {
   pilot_acc = (lua_gettop(L) > 1 && lua_isnumber(L, 1)) ? ABS((double)lua_tonumber(L, 1)) : 1.;
@@ -529,7 +561,13 @@ static int ai_turn(lua_State* L) {
 static int ai_face(lua_State* L) {
   MIN_ARGS(1);
   Vec2* v; // Grab the position to face.
-  if(lua_isnumber(L,1)) v = &pilot_get((unsigned int)lua_tonumber(L,1))->solid->pos;
+  Pilot* p;
+  
+  if(lua_isnumber(L,1)) {
+   p = pilot_get((unsigned int)lua_tonumber(L,1));
+   if(p == NULL) return 0; // Make sure pilot is valid.
+   v = &p->solid->pos;
+  }
   else if(lua_islightuserdata(L,1)) v = (Vec2*)lua_topointer(L,1);
 
   double mod = -10;
@@ -614,6 +652,30 @@ static int ai_getrndplanet(lua_State* L) {
   return 1;
 }
 
+// Attempt to enter the pilot hyperspace. Return the distance if too far away.
+static int ai_hyperspace(lua_State* L) {
+  int dist;
+
+  dist = space_hyperspace(cur_pilot);
+  if(dist == 0) return 0;
+
+  lua_pushnumber(L,dist);
+  return 1;
+}
+
+// Toggle combat flag. Default is on.
+static int ai_combat(lua_State* L) {
+  int i;
+
+  if(lua_isnumber(L, 1)) {
+    i = (int)lua_tonumber(L,1);
+    if(i == 1) pilot_setFlag(cur_pilot, PILOT_COMBAT);
+    else if(i == 0) pilot_rmFlag(cur_pilot, PILOT_COMBAT);
+  } else pilot_setFlag(cur_pilot, PILOT_COMBAT);
+
+  return 0;
+}
+
 // Pew pew.. Says the pilot.
 static int ai_shoot(lua_State* L) {
   int n = 1;
diff --git a/src/pilot.h b/src/pilot.h
index 532b2d9..f0b9ee6 100644
--- a/src/pilot.h
+++ b/src/pilot.h
@@ -17,9 +17,11 @@
 #define pilot_setFlag(p,f)  (p->flags |= f)
 #define pilot_rmFlag(p,f)   (p->flags ^= f)
 // Creation.
-#define PILOT_PLAYER        (1<<0) // Pilot is a player.
+#define PILOT_PLAYER        (1<<0)  // Pilot is a player.
 // Dynamic.
-#define PILOT_HOSTILE       (1<<1) // Pilot is hostile to the player.
+#define PILOT_HOSTILE       (1<<1)  // Pilot is hostile to the player.
+#define PILOT_COMBAT        (1<<2)  // Pilot is engaged in combat.
+#define PILOT_HYPERSPACE    (1<<3)  // Pilot is in hyperspace.
 
 // Just makes life simpler.
 #define pilot_isPlayer(p)   ((p)->flags & PILOT_PLAYER)
diff --git a/src/space.c b/src/space.c
index 7d65eeb..c560c3d 100644
--- a/src/space.c
+++ b/src/space.c
@@ -34,6 +34,10 @@ static StarSystem* systems = NULL;
 static int nsystems = 0;
 StarSystem* cur_system = NULL; // Current star system.
 
+// Current stardate in nice format.
+char* stardate = "Stardate";
+unsigned int date = 0; // time since epoch.
+
 #define STAR_BUF 100 // Area to leave around screen, more = less repitition.
 typedef struct {
   double x, y; // Position. It is simpler ligher to use two doubles than the physics.
@@ -43,9 +47,12 @@ typedef struct {
 static Star* stars = NULL; // Star array.
 static int nstars = 0; // Total stars.
 
+// Intern
 static Planet* planet_get(const char* name);
 static StarSystem* system_parse(const xmlNodePtr parent);
 static PlanetClass planetclass_get(const char a);
+// Extern.
+extern void player_message(const char* fmt, ...);
 
 // Draw the planet. Used in planet.c
 // Matrix mode is already displaced to center of the minimap.
@@ -135,6 +142,25 @@ static PlanetClass planetclass_get(const char a) {
   };
 }
 
+// Hyperspaces, return 0 if entering hyperspace, or distance otherwise.
+int space_hyperspace(Pilot* p) {
+  int i;
+  double d;
+  for(i = 0; i < cur_system->nplanets; i++) {
+    d = vect_dist(&p->solid->pos, &cur_system->planets[i].pos);
+    if(d < MIN_HYPERSPACE_DIST)
+      return (int)(MIN_HYPERSPACE_DIST - d);
+  }
+  // TODO: All hyperspace worky work.
+  if(p == player) {
+    // Player crap.
+  } else {
+    
+  }
+
+  return 0;
+}
+
 // Init the system.
 void space_init(const char* sysname) {
   int i, j;
@@ -146,6 +172,8 @@ void space_init(const char* sysname) {
   if(i == nsystems) ERR("System %s not found in stack", sysname);
   cur_system = systems+i;
 
+  player_message("Entering System %s on %s", sysname, stardate);
+
   // Set up stars.
   nstars = (cur_system->stars*gl_screen.w*gl_screen.h+STAR_BUF*STAR_BUF)/(800*640);
   stars = realloc(stars, sizeof(Star)*nstars); // Should realloc this, not malloc.
diff --git a/src/space.h b/src/space.h
index f5c4014..86fd2c1 100644
--- a/src/space.h
+++ b/src/space.h
@@ -72,3 +72,7 @@ void space_exit(void);
 void space_render(double dt);
 void planets_render(void);
 
+// Misc.
+int space_hyperspace(Pilot* p);
+extern char* stardate;
+