From 5518f0c3904243b826398f2621adbfa638eff353 Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Mon, 6 Jan 2014 19:49:43 +0000
Subject: [PATCH] [Change] AI now takes into account relative velocities.

---
 scripts/ai/include/attack_generic.lua | 101 +++++++++++++++++---------
 src/ai.c                              |  22 ++++++
 2 files changed, 89 insertions(+), 34 deletions(-)

diff --git a/scripts/ai/include/attack_generic.lua b/scripts/ai/include/attack_generic.lua
index 51129b1..6a65f60 100644
--- a/scripts/ai/include/attack_generic.lua
+++ b/scripts/ai/include/attack_generic.lua
@@ -2,6 +2,10 @@
 --  Generic attack functions.
 --]]
 
+atk_changetarget  = 1.8
+atk_approach      = 1.4
+atk_aim           = 1.0
+
 --[[
 --  Mainly manages targetting nearest enemy.
 --]]
@@ -15,7 +19,7 @@ function atk_g_think()
     range = ai.getweaprange()
 
     -- Shouldn't switch targets if close.
-    if dist > range * 1.6 then
+    if dist > range * atk_changetarget then
       ai.poptask()
       ai.pushtask(0, "attack", enemy)
     end
@@ -41,43 +45,72 @@ function atk_g()
   range = ai.getweaprange()
 
   -- We first bias towards range.
-  if dist > range*1.3 then
-    dir = ai.face(target) -- Normal face the target.
+  if dist > range * atk_approach then
+    atk_g_ranged(target, dist)
 
-    secondary, special, ammo = ai.secondary("Launcher")
-
-    -- Shoot missiles if in range.
-    if secondary == "Launcher" and
-        dist < ai.getweaprange(1) then
-      -- More lenient with aiming.
-      if special == "Smart" and dir < 30 then
-        ai.shoot(2)
-      -- Non-smart miss more.
-      elseif dir < 10 then
-        ai.shoot(2)
-      end
+  elseif dist > range * atk_aim then
+    if ai.relvel(target) < 0 then
+      atk_g_ranged(target, dist)
+    else
+      atk_g_aim(target, dist)
     end
 
-    -- Approach for melee.
-    if dir < 10 then
-      ai.accel()
-    end
-    -- Close enough to melee.
+  -- Close enough to melee.
   else
-    secondary, special = ai.secondary("Beam Weapon")
-    dir = ai.aim(target) -- We aim instead of face.
-
-    -- Fire non-smart secondary weapons.
-    if(secondary == "Launcher" and special ~= "Smart") or
-        secondary == "Beam Weapon" then
-      if dir < 10 or special == "Turret" then -- Need good accuracy.
-        ai.shoot(2)
-      end
-    end
-
-    if(dir < 10 and dist < range) or ai.hasturrets() then
-      ai.shoot()
-    end
+    atk_g_melee(target, dist)
+  end
+end
+
+-- ]]
+--    Enter ranged combat with the target.
+-- ]]
+function atk_g_ranged(target, dist)
+  dir = ai.face(target) -- Normal face the target.
+  secondary, special, ammo = ai.secondary("Launcher")
+
+  -- Shoot missiles if in range.
+  if secondary == "Launcher" and
+        dist < ai.getweaprange(1) then
+    -- More lenient with aiming.
+    if special == "Smart" and dir < 30 then
+      ai.shoot(2)
+
+    -- Non-smart miss more.
+    elseif dir < 10 then
+      ai.shoot(2)
+    end
+  end
+
+  -- Approach for melee.
+  if dir < 10 then
+    ai.accel()
+  end
+end
+
+--[[
+--    Aim at the target.
+--]]
+function atk_g_aim(target, dist)
+  dir = ai.aim(target)
+end
+
+--[[
+--    Melee the target.
+--]]
+function atk_g_melee(target, dist)
+  secondary, special = ai.secondary("Beam Weapon")
+  dir = ai.aim(target) -- We aim instead of face.
+
+  -- Fire non-smart secondary weapons.
+  if(secondary == "Launcher" and special ~= "Smart") or
+    secondary == "Beam Weapon" then
+    if dir < 10 or special == "Turret" then -- Need good acuracy.
+      ai.shoot(2)
+    end
+  end
+
+  if(dir < 10 and dist < range) or ai.hasturrets() then
+    ai.shoot()
   end
 end
 
diff --git a/src/ai.c b/src/ai.c
index e142b12..d3ebca7 100644
--- a/src/ai.c
+++ b/src/ai.c
@@ -150,6 +150,7 @@ static int ai_getrndplanet(lua_State* L);       /* Vec2 getrndplanet() */
 static int ai_getlandplanet(lua_State* L);      /* Vec2 getlandplanet() */
 static int ai_hyperspace(lua_State* L);         /* [number] hyperspace() */
 static int ai_stop(lua_State* L);               /* stop() */
+static int ai_relvel(lua_State* L);             /* relvel(number) */
 /* Escorts. */
 static int ai_e_attack(lua_State* L);           /* bool e_attack() */
 static int ai_e_hold(lua_State* L);             /* bool e_hold() */
@@ -212,6 +213,7 @@ static const luaL_Reg ai_methods[] = {
   { "brake",                ai_brake            },
   { "stop",                 ai_stop             },
   { "hyperspace",           ai_hyperspace       },
+  { "relvel",               ai_relvel           },
   /* Escorts. */
   { "e_attack",             ai_e_attack         },
   { "e_hold",               ai_e_hold           },
@@ -1108,6 +1110,26 @@ static int ai_hyperspace(lua_State* L) {
   return 1;
 }
 
+/* Get the relative velocity of a pilot. */
+static int ai_relvel(lua_State* L) {
+  unsigned int id;
+  Pilot* p;
+
+  LLUA_MIN_ARGS(1);
+
+  if(lua_isnumber(L, 1)) id = (unsigned int)lua_tonumber(L, 1);
+  else LLUA_INVALID_PARAMETER();
+
+  p = pilot_get(id);
+  if(p == NULL) {
+    LLUA_DEBUG("Invalid pilot identifier.");
+    return 0;
+  }
+
+  lua_pushnumber(L, vect_dist(&cur_pilot->solid->vel, &p->solid->vel));
+  return 1;
+}
+
 /* Completely stop the pilot if it is below minimum vel error. (No instant stops.) */
 static int ai_stop(lua_State* L) {
   (void)L; /* Just avoid a gcc warning. */