From 71ab2d863f8cf94f8afdd0b52ec83fe98f1784fb Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Mon, 23 Sep 2013 22:59:01 +0100
Subject: [PATCH] [Add] Added outfit states and beam hit function. Also added
 compile option for clang.

---
 bin/Makefile |   2 +
 src/pilot.c  |  23 +++++++----
 src/pilot.h  |  21 ++++++++--
 src/weapon.c | 112 ++++++++++++++++++++++++++++++++++++++++-----------
 4 files changed, 124 insertions(+), 34 deletions(-)

diff --git a/bin/Makefile b/bin/Makefile
index 55df686..79c922e 100644
--- a/bin/Makefile
+++ b/bin/Makefile
@@ -5,6 +5,8 @@ DEBUG = 1
 OS := LINUX
 #OS := WIN32
 
+#CC = clang
+
 # VERSION.
 VMAJOR  = 0
 VMINOR  = 0
diff --git a/src/pilot.c b/src/pilot.c
index 484333f..7a8c765 100644
--- a/src/pilot.c
+++ b/src/pilot.c
@@ -204,15 +204,18 @@ int pilot_freeSpace(Pilot* p) {
 /* Mkay, this is how we shoot. Listen up. */
 void pilot_shoot(Pilot* p, const unsigned int target, const int secondary) {
   int i;
+  Outfit* o;
 
   if(!p->outfits) return; /* No outfits. */
 
   if(!secondary) {
     /* Primary weapons. */
-    for(i = 0; i < p->noutfits; i++)
-      /* Cycle through outfits to find primary weapons. */
-      if(!outfit_isProp(p->outfits[i].outfit, OUTFIT_PROP_WEAP_SECONDARY))
+    for(i = 0; i < p->noutfits; i++) {
+      o = p->outfits[i].outfit;
+      if(!outfit_isProp(o, OUTFIT_PROP_WEAP_SECONDARY) &&
+          (outfit_isBolt(o) || outfit_isBeam(o))) /** @todo Possibly make the neater. */
         pilot_shootWeapon(p, &p->outfits[i], target);
+    }
   } else {
     if(!p->secondary) return; /* No secondary weapon. */
     pilot_shootWeapon(p, p->secondary, target);
@@ -243,14 +246,16 @@ static void pilot_shootWeapon(Pilot* p, PilotOutfit* w, const unsigned int t) {
     p->energy -= outfit_energy(w->outfit);
     weapon_add(w->outfit, p->solid->dir,
         &p->solid->pos, &p->solid->vel, p->id, t);
-
-    /* Can't shoot it for a bit. */
-    w->timer = SDL_GetTicks();
   }
 
   /* Beam Weapons. */
   else if(outfit_isBeam(w->outfit)) {
+    if(outfit_energy(w->outfit) > p->energy) return;
 
+    /** @todo Handle warmup stage. */
+    w->state = PILOT_OUTFIT_ON;
+    weapon_add(w->outfit, p->solid->dir,
+        &p->solid->pos, NULL, p->id, t);
   }
 
   /*
@@ -275,9 +280,13 @@ static void pilot_shootWeapon(Pilot* p, PilotOutfit* w, const unsigned int t) {
     weapon_add(p->ammo->outfit, p->solid->dir, &p->solid->pos,
                &p->solid->vel, p->id, t);
 
-    w->timer = SDL_GetTicks(); /* Can't shoot for a while. */
     p->ammo->quantity -= 1; /* There's no getting this one back. */
+  } else {
+    WARN("Shooting unknown weapon type: %s", w->outfit->name);
   }
+
+  /* Update the weapon last used timer. */
+  w->timer = SDL_GetTicks();
 }
 
 /**
diff --git a/src/pilot.h b/src/pilot.h
index 8e70382..7cc6ff2 100644
--- a/src/pilot.h
+++ b/src/pilot.h
@@ -53,16 +53,29 @@
 #define pilot_isPlayer(p)   ((p)->flags & PILOT_PLAYER)   /**< Check if pilot is a player. */
 #define pilot_isDisabled(p) ((p)->flags & PILOT_DISABLED) /**< Check if pilot is disabled. */
 
+/**
+ * @enum PilotOutfitState
+ *
+ * @brief Contains the state of the outfit.
+ *
+ * Currently only applicable to beam weapons.
+ */
+typedef enum PilotOutfitState_ {
+  PILOT_OUTFIT_OFF,     /**< Normal state. */
+  PILOT_OUTFIT_WARMUP,  /**< Outfit is starting to warm up. */
+  PILOT_OUTFIT_ON       /**< Outfit is activated and running. */
+} PilotOutfitState;
+
 /**
  * @struct PilotOutfit
  *
  * @brief Store an outfit the pilot has.
  */
 typedef struct PilotOutfit_ {
-  Outfit* outfit;     /**< Associated outfit. */
-  int quantity;       /**< Number of outfits of this type that the pilot has. */
-
-  unsigned int timer; /**< Used to store last used weapon time. */
+  Outfit* outfit;         /**< Associated outfit. */
+  int quantity;           /**< Number of outfits of this type that the pilot has. */
+  PilotOutfitState state; /**< State of the outfit. */
+  unsigned int timer;     /**< Used to store last used weapon time. */
 } PilotOutfit;
 
 /**
diff --git a/src/weapon.c b/src/weapon.c
index c583029..d081e74 100644
--- a/src/weapon.c
+++ b/src/weapon.c
@@ -11,6 +11,7 @@
 #include "collision.h"
 #include "player.h"
 #include "spfx.h"
+#include "opengl.h"
 #include "weapon.h"
 
 #define weapon_isSmart(w) (w->think != NULL)
@@ -22,7 +23,11 @@
 #define WEAPON_STATUS_JAMMED    1 /* Got jammed. */
 #define WEAPON_STATUS_UNJAMMED  2 /* Surviving jaming. */
 
-/* Some stuff from pilot. */
+/* OpenGL stuff. */
+extern Vec2* gl_camera;
+extern double gui_xoff, gui_yoff;
+
+/* Pilot stuff. */
 extern Pilot** pilot_stack;
 extern int pilot_nstack;
 
@@ -69,6 +74,8 @@ static void weapon_render(const Weapon* w);
 static void weapons_updateLayer(const double dt, const WeaponLayer layer);
 static void weapon_update(Weapon* w, const double dt, WeaponLayer layer);
 static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer, Vec2* pos);
+static void weapon_hitBeam(Weapon* w, Pilot* p, WeaponLayer layer,
+    Vec2 pos[2], const double dt);
 static void weapon_destroy(Weapon* w, WeaponLayer layer);
 static void weapon_free(Weapon* w);
 /* Think. */
@@ -80,8 +87,20 @@ void weapon_minimap(const double res, const double w,
     const double h, const RadarShape shape);
 
 /* Draw the minimap weapons (player.c). */
-#define PIXEL(x,y) if((shape == RADAR_RECT && ABS(x) < w/2. && ABS(y)<h/2.) || \
-  (shape == RADAR_CIRCLE && (((x)*(x)+(y)*(y))<rc))) glVertex2i((x),(y))
+#define PIXEL(x,y) \
+  if((shape == RADAR_RECT && ABS(x) < w/2. && ABS(y)<h/2.) || \
+  (shape == RADAR_CIRCLE && (((x)*(x)+(y)*(y))<rc))) \
+  glVertex2i((x),(y)) /**< Set a pixel if within range. */
+/**
+ * @fn void weapon_minimap(const double res, const double w,
+ *               const double h, const RadarShape shape)
+ * 
+ * @brief Draw the minimap weapons (used in player.c).
+ *    @param res Minimap resolution.
+ *    @param w Width of minimap.
+ *    @param h Height of minimap.
+ *    @param shape Shape of the minimap.
+ */
 void weapon_minimap(const double res, const double w,
     const double h, const RadarShape shape) {
   int i, rc;
@@ -296,6 +315,7 @@ void weapons_render(const WeaponLayer layer) {
 /* Render the weapons. */
 static void weapon_render(const Weapon* w) {
   int sx, sy;
+  double x, y;
   glTexture* gfx;
 
   switch(w->outfit->type) {
@@ -315,10 +335,13 @@ static void weapon_render(const Weapon* w) {
     /* Beam weapons. */
     case OUTFIT_TYPE_BEAM:
     case OUTFIT_TYPE_TURRET_BEAM:
+      x = w->solid->pos.x - VX(*gl_camera) + gui_xoff;
+      y = w->solid->pos.y - VY(*gl_camera) + gui_yoff;
+      COLOUR(*w->outfit->u.bem.colour);
       glBegin(GL_LINES);
-        glVertex2d(w->solid->pos.x, w->solid->pos.y);
-        glVertex2d(w->solid->pos.x + w->outfit->u.bem.range*cos(w->solid->dir),
-            w->solid->pos.y + w->outfit->u.bem.range*sin(w->solid->dir));
+        glVertex2d(x, y);
+        glVertex2d(x + w->outfit->u.bem.range * cos(w->solid->dir),
+            y + w->outfit->u.bem.range * sin(w->solid->dir));
       glEnd();
       break;
 
@@ -335,10 +358,6 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
   glTexture* gfx;
   Vec2 crash[2];
 
-  gfx = outfit_gfx(w->outfit);
-
-  gl_getSpriteFromDir(&wsx, &wsy, gfx, w->solid->dir);
-
   for(i = 0; i < pilot_nstack; i++) {
     /* Check for player to exist. */
     if((i == 0) && (player == NULL)) continue;
@@ -356,7 +375,7 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
             &pilot_stack[i]->solid->pos,
             crash)) {
 
-        /** @todo beam_hit Needs it's own function. */
+        weapon_hitBeam(w, pilot_stack[i], layer, crash, dt);
 
         /* No return because beam can still think, it's not
          * destroyed like the other weapons. */
@@ -365,27 +384,31 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
 
     /* Smart weapons only collide with  their target. */
     else if(weapon_isSmart(w)) {
+      gfx = outfit_gfx(w->outfit);
+      gl_getSpriteFromDir(&wsx, &wsy, gfx, w->solid->dir);
       if((pilot_stack[i]->id == w->target) &&
           CollideSprite(gfx, wsx, wsy, &w->solid->pos,
             pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos,
             &crash[0])) {
         
         weapon_hit(w, pilot_stack[i], layer, &crash[0]);
-        return;
-      }
-      /* Dumb weapons hit anything not of the same faction. */
-      else if(!weapon_isSmart(w) &&
-          !areAllies(w->faction, pilot_stack[i]->faction) &&
-          CollideSprite(gfx, wsx, wsy, &w->solid->pos,
-            pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos,
-            &crash[0])) {
-        
-        weapon_hit(w, pilot_stack[i], layer, &crash[0]);
-        return;
+        return; /* Weapon is destroyed. */
       }
     }
-  }
+    /* Dumb weapons hit anything not of the same faction. */
+    else if(!weapon_isSmart(w)) {
+      gfx = outfit_gfx(w->outfit);
+      gl_getSpriteFromDir(&wsx, &wsy, gfx, w->solid->dir);
 
+        if(!areAllies(w->faction, pilot_stack[i]->faction) &&
+            CollideSprite(gfx, wsx, wsy, &w->solid->pos,
+              pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos,
+              &crash[0])) {
+          weapon_hit(w, pilot_stack[i], layer, &crash[0]);
+          return; /* Weapon is destroyed. */
+        }
+      }
+    }
   /* Smart weapons also get to think their next move. */
   if(weapon_isSmart(w)) (*w->think)(w,dt);
 
@@ -425,6 +448,48 @@ static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer, Vec2* pos) {
   weapon_destroy(w, layer);
 }
 
+/**
+ * @fn static void weapon_hitBeam(Weapon* w, Pilot* p, WeaponLayer layer,
+ *      Vec2 pos[2], const double dt)
+ *
+ * @brief Weapon hit the pilot.
+ *    @param w Weapon involved in the collision.
+ *    @param p Pilot that got hit.
+ *    @param layer Layer to which the weapon belongs.
+ *    @param pos Position of the hit.
+ */
+static void weapon_hitBeam(Weapon* w, Pilot* p, WeaponLayer layer,
+    Vec2 pos[2], const double dt) {
+  
+  (void)layer;
+
+  /* Inform the ai it has been attacked, useless if player. */
+  if(!pilot_isPlayer(p)) {
+    if((player_target == p->id) || (RNGF()*dt < 0.70)) { /* 70% chance per second. */
+      if((w->parent == PLAYER_ID) &&
+          (!pilot_isFlag(p, PILOT_HOSTILE) || (RNGF() < 0.5))) { /* 50% chance. */
+        faction_modPlayer(p->faction, -1); /* Slowly lower faction. */
+        pilot_setFlag(p, PILOT_HOSTILE);
+      }
+      ai_attacked(p, w->parent);
+    }
+    spfx_add(outfit_spfx(w->outfit), pos[0].x, pos[0].y,
+          VX(p->solid->vel), VY(p->solid->vel), SPFX_LAYER_BACK);
+    spfx_add(outfit_spfx(w->outfit), pos[1].x, pos[1].y,
+          VX(p->solid->vel), VY(p->solid->vel), SPFX_LAYER_BACK);
+   
+  } else {
+    spfx_add(outfit_spfx(w->outfit), pos[0].x, pos[0].y,
+        VX(p->solid->vel), VY(p->solid->vel), SPFX_LAYER_FRONT);
+    spfx_add(outfit_spfx(w->outfit), pos[1].x, pos[1].y,
+        VX(p->solid->vel), VY(p->solid->vel), SPFX_LAYER_FRONT);
+  }
+
+  /* Inform the ship that it should take some damage. */
+  pilot_hit(p, w->solid, w->parent,
+      outfit_damageType(w->outfit), outfit_damage(w->outfit)*dt);
+}
+
 static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* pos,
                              const Vec2* vel, unsigned int parent, const unsigned int target) {
   Vec2 v;
@@ -491,6 +556,7 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
       mass = 1.;
       w->solid = solid_create(mass, dir, pos, NULL);
       w->think = think_beam;
+      w->timer = outfit->u.bem.duration;
       break;
   
   /* Treat seekers togther. */