From 4d8b46235962e53853ae735e58ad0b8705ae006e Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Mon, 30 Sep 2013 22:29:53 +0100
Subject: [PATCH] [Add] First round to bring more control to beam weapons.

---
 src/pilot.c  |  61 ++++++++++++++++++++++++++-
 src/pilot.h  |   3 ++
 src/player.c |  31 ++++++++++----
 src/player.h |   8 ++--
 src/weapon.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/weapon.h |   6 +++
 6 files changed, 210 insertions(+), 14 deletions(-)

diff --git a/src/pilot.c b/src/pilot.c
index 069658e..1c843dd 100644
--- a/src/pilot.c
+++ b/src/pilot.c
@@ -222,6 +222,39 @@ void pilot_shoot(Pilot* p, const unsigned int target, const int secondary) {
   }
 }
 
+/**
+ * @fn void pilot_shootStop(Pilot* p, const int secondary)
+ *
+ * @brief 
+ */
+void pilot_shootStop(Pilot* p, 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. */
+      o = p->outfits[i].outfit;
+      if(!outfit_isProp(o, OUTFIT_PROP_WEAP_SECONDARY) &&
+          outfit_isBeam(o)) /** @todo Possibly make this neater. */
+        if(p->outfits[i].beamid > 0) {
+          p->outfits[i].beamid = 0;
+        }
+    }
+  } else { /* Secondary weapons. */
+    o = p->secondary->outfit;
+
+    if(o == NULL) return; /* No secondary weapon. */
+
+    if(outfit_isBeam(o) && (p->secondary->beamid > 0)) {
+      beam_end(p->id, p->secondary->beamid);
+      p->secondary->beamid = 0;
+    }
+  }
+}
+
 /**
  * @fn static void pilot_shootWeapon(Pilot* p, PilotOutfit* w, const unsigned int t)
  *
@@ -254,8 +287,8 @@ static void pilot_shootWeapon(Pilot* p, PilotOutfit* w, const unsigned int t) {
 
     /** @todo Handle warmup stage. */
     w->state = PILOT_OUTFIT_ON;
-    weapon_add(w->outfit, p->solid->dir,
-        &p->solid->pos, &p->solid->vel, p->id, t);
+    w->beamid = beam_start(w->outfit, p->solid, p->solid->dir,    
+      &p->solid->pos, &p->solid->vel, p->id, t);
   }
 
   /*
@@ -289,6 +322,30 @@ static void pilot_shootWeapon(Pilot* p, PilotOutfit* w, const unsigned int t) {
   w->timer = SDL_GetTicks();
 }
 
+/**
+ * @fn void pilot_switchSecondary(Pilot* p, int i)
+ *
+ * @brief 
+ */
+void pilot_switchSecondary(Pilot* p, int i) {
+  PilotOutfit* cur;
+
+  cur = player->secondary;
+
+  if((i < 0) || (i >= player->noutfits))
+    player->secondary = NULL;
+  else
+    player->secondary = &player->outfits[i];
+
+  /* Check for weapon change. */
+  if((cur != NULL) && (player->secondary != cur)) {
+    if(outfit_isBeam(cur->outfit) && (cur->beamid > 0)) {
+      beam_end(p->id, cur->beamid);
+      cur->beamid = 0;
+    }
+  }
+}
+
 /**
  * @fn void pilot_hit(Pilot* p, const Solid* w, const unsigned int shooter,
  *                    const DamageType dtype, const double damage)
diff --git a/src/pilot.h b/src/pilot.h
index a6f7344..36b7159 100644
--- a/src/pilot.h
+++ b/src/pilot.h
@@ -76,6 +76,7 @@ typedef struct PilotOutfit_ {
   Outfit* outfit;         /**< Associated outfit. */
   int quantity;           /**< Number of outfits of this type that the pilot has. */
   PilotOutfitState state; /**< State of the outfit. */
+  int beamid;             /**< ID of the beam used in this outfit, only for beams. */
   unsigned int timer;     /**< Used to store last used weapon time. */
 } PilotOutfit;
 
@@ -213,8 +214,10 @@ int pilot_getJumps(const Pilot* p);
 
 /* Misc. */
 void pilot_shoot(Pilot* p, const unsigned int target, const int secondary);
+void pilot_shootStop(Pilot* p, const int secondary);
 void pilot_hit(Pilot* p, const Solid* w, const unsigned int shooter,
     const DamageType dtype, const double damage);
+void pilot_switchSecondary(Pilot* p, int i);
 void pilot_setSecondary(Pilot* p, const char* secondary);
 void pilot_setAmmo(Pilot* p);
 void pilot_setAfterburner(Pilot* p);
diff --git a/src/player.c b/src/player.c
index 49c765e..42019ba 100644
--- a/src/player.c
+++ b/src/player.c
@@ -1389,9 +1389,27 @@ void player_think(Pilot* pplayer) {
       pplayer->solid->dir_vel -= player->turn * player_turn;
   }
 
-  if(player_isFlag(PLAYER_PRIMARY)) pilot_shoot(pplayer, player_target, 0);
-  if(player_isFlag(PLAYER_SECONDARY)) /* Needs a target. */
-    pilot_shoot(pplayer, player_target, 1);
+  /* Weapon shooting stuff. */
+
+  /* Primary weapon. */
+  if(player_isFlag(PLAYER_PRIMARY)) {
+    pilot_shoot(pplayer, player_target, 0);
+    player_setFlag(PLAYER_PRIMARY_L);
+  }
+  else if(player_isFlag(PLAYER_PRIMARY_L)) {
+    pilot_shootStop(pplayer, 0);
+    player_rmFlag(PLAYER_PRIMARY_L);
+  }
+
+  /* Secondary. */
+   if(player_isFlag(PLAYER_SECONDARY)) {
+    pilot_shoot(pplayer, player_target, 0);
+    player_setFlag(PLAYER_SECONDARY_L);
+  }
+  else if(player_isFlag(PLAYER_SECONDARY_L)) {
+    pilot_shootStop(pplayer, 0);
+    player_rmFlag(PLAYER_SECONDARY_L);
+  } 
 
   /* Afterburn! */
   if(player_isFlag(PLAYER_AFTERBURNER)) {
@@ -1405,7 +1423,7 @@ void player_think(Pilot* pplayer) {
     vect_pset(&pplayer->solid->force, pplayer->thrust * player_acc,
               pplayer->solid->dir);
 
-  /* Update sound position. */
+  /* Sound. */
   sound_updateListener(pplayer->solid->dir,
       pplayer->solid->pos.x, pplayer->solid->pos.y);
 
@@ -1447,13 +1465,12 @@ void player_secondaryNext(void) {
   /* Get the next secondary weapon. */
   for(; i < player->noutfits; i++)
     if(outfit_isProp(player->outfits[i].outfit, OUTFIT_PROP_WEAP_SECONDARY)) {
-      player->secondary = player->outfits + i;
+      pilot_switchSecondary(player, i);
       break;
     }
   /* We didn't find an outfit. */
   if(i >= player->noutfits)
-    player->secondary = NULL;
-
+    pilot_switchSecondary(player, -1);
   /* Set ammo. */
   pilot_setAmmo(player);
 }
diff --git a/src/player.h b/src/player.h
index d440f3b..db48164 100644
--- a/src/player.h
+++ b/src/player.h
@@ -9,9 +9,11 @@
 #define PLAYER_DESTROYED    (1<<9)    /* Player goes BOOM! */
 #define PLAYER_FACE         (1<<10)   /* Player is facing target. */
 #define PLAYER_PRIMARY      (1<<11)   /* Player is shooting primary weapon. */
-#define PLAYER_SECONDARY    (1<<12)   /* Player is shooting secondary weapon. */
-#define PLAYER_LANDACK      (1<<13)   /* Player has permission to land. */
-#define PLAYER_CREATING     (1<<14)   /* Player is being created. */
+#define PLAYER_PRIMARY_L    (1<<12)   /**< Player shot primary weapon last frame. */
+#define PLAYER_SECONDARY    (1<<13)   /* Player is shooting secondary weapon. */
+#define PLAYER_SECONDARY_L  (1<<14)   /**< Player shot secondary last frame. */
+#define PLAYER_LANDACK      (1<<15)   /* Player has permission to land. */
+#define PLAYER_CREATING     (1<<16)   /* Player is being created. */
 
 /* Flag functions. */
 #define player_isFlag(f)  (player_flags  & f)
diff --git a/src/weapon.c b/src/weapon.c
index e6b1981..b0bd66a 100644
--- a/src/weapon.c
+++ b/src/weapon.c
@@ -39,6 +39,7 @@ extern void ai_attacked(Pilot* attacked, const unsigned int attacker);
 
 typedef struct Weapon_ {
   Solid* solid; /* Actually has its own solid. :D */
+  int ID;       /**< Only used for beam weapons. */
 
   unsigned int faction; /* Faction of pilot that shot the weapon. */
   unsigned int parent;  /* The pilot that just shot at you! */
@@ -64,6 +65,9 @@ static Weapon** wfrontLayer = NULL;  /* Behind pilots. */
 static int nwfrontLayer    = 0;    /* Number of elements. */
 static int mwfrontLayer    = 0;    /* Allocated memory size. */
 
+/* Internal stuff. */
+static int beam_idgen = 0;          /**< Beam identifier generator. */
+
 /* Static. */
 static Weapon* weapon_create(const Outfit* outfit, const double dir,
                              const Vec2* pos, const Vec2* vel,
@@ -703,8 +707,8 @@ void weapon_add(const Outfit* outfit, const double dir, const Vec2* pos,
   Weapon** curLayer;
   int* mLayer, *nLayer;
 
-  if(!outfit_isWeapon(outfit) &&
-     !outfit_isAmmo(outfit) && !outfit_isTurret(outfit)) {
+  if(!outfit_isBolt(outfit) &&
+      !outfit_isAmmo(outfit)) {
     ERR("Trying to create a weapon from a non-Weapon type Outfit");
     return;
   }
@@ -745,6 +749,113 @@ void weapon_add(const Outfit* outfit, const double dir, const Vec2* pos,
   }
 }
 
+/**
+ * @fn int beam_start(const Outfit* outfit,
+ *           const double dir, const Vec2* pos, const Vec2* vel,
+ *           const unsigned int parent, const unsigned int target)
+ * 
+ * @brief Start the beam weapon.
+ *    @param outfit Outfit which spawns the weapon.
+ *    @param dir Direction of the shooter.
+ *    @param vel Velocity of the shooter.
+ *    @param parent Pilot ID of the shooter.
+ *    @param target Target ID that is getting shot.
+ *    @return The identifier of the beam weapon.
+ */
+int beam_start(const Outfit* outfit,
+    const double dir, const Vec2* pos, const Vec2* vel,
+    const unsigned int parent, const unsigned int target) {
+  
+  WeaponLayer layer;
+  Weapon* w;
+  Weapon** curLayer;
+  int* mLayer, *nLayer;
+
+  if(!outfit_isBeam(outfit)) {
+    ERR("Trying to create a Beam Weapon from a non-beam outfit.");
+    return -1;
+  }
+
+  layer = (parent == PLAYER_ID) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG;
+  w = weapon_create(outfit, dir, pos, vel, parent, target);
+  w->ID = ++beam_idgen;
+
+  switch(layer) {
+    case WEAPON_LAYER_BG:
+      curLayer  = wbackLayer;
+      nLayer    = &nwbackLayer;
+      mLayer    = &mwbackLayer;
+      break;
+    case WEAPON_LAYER_FG:
+      curLayer  = wfrontLayer;
+      nLayer    = &nwfrontLayer;
+      mLayer    = &mwbackLayer;
+      break;
+    default:
+      ERR("Invalid WEAPON_LAYER specified.");
+      return -1;
+  }
+
+  if(*mLayer > *nLayer) /* More memory allocated then needed. */
+    curLayer[(*nLayer)++] = w;
+  else { /* Need to allocate more memory. */
+    switch (layer) {
+      case WEAPON_LAYER_BG:
+        (*mLayer) += WEAPON_CHUNK;
+        curLayer = wbackLayer = realloc(curLayer, (*mLayer)*sizeof(Weapon*));
+        break;
+      case WEAPON_LAYER_FG:
+        (*mLayer) += WEAPON_CHUNK;
+        curLayer = wfrontLayer = realloc(curLayer, (*mLayer)*sizeof(Weapon*));
+        break;
+    }
+    curLayer[(*nLayer)++] = w;
+  }
+
+  return w->ID;
+}
+
+/**
+ * @fn void beam_end(const unsigned int parent, int beam)
+ *
+ * @brief End a beam weapon.
+ *    @param parent
+ *    @param beam
+ */
+void beam_end(const unsigned int parent, int beam) {
+  int i;
+  WeaponLayer layer;
+  Weapon** curLayer;
+  int* mLayer, *nLayer;
+
+  layer = (parent == PLAYER_ID) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG;
+
+  /* Set the proper layer. */
+  switch(layer) {
+    case WEAPON_LAYER_BG:
+      curLayer  = wbackLayer;
+      nLayer    = &nwbackLayer;
+      mLayer    = &mwbackLayer;
+      break;
+    case WEAPON_LAYER_FG:
+      curLayer  = wfrontLayer;
+      nLayer    = &nwfrontLayer;
+      mLayer    = &mwfrontLayer;
+      break;
+    default:
+      ERR("Invalid WEAPON_LAYER specified.");
+      return;
+  }
+
+  /* Now try to destroy the beam. */
+  for(i = 0; i < *nLayer; i++) {
+    if(curLayer[i]->ID == beam) { /* Found it. */
+      weapon_destroy(curLayer[i], layer);
+      break;
+    }
+  }
+}
+
 /* Destroy the weapon. */
 static void weapon_destroy(Weapon* w, WeaponLayer layer) {
   int i;
diff --git a/src/weapon.h b/src/weapon.h
index 2c8e7c7..0462091 100644
--- a/src/weapon.h
+++ b/src/weapon.h
@@ -16,6 +16,12 @@ void weapon_add(const Outfit* outfit, const double dir, const Vec2* pos,
                 const Vec2* vel, unsigned int parent,
                 const unsigned int target);
 
+int beam_start(const Outfit* outfit,
+    const double dir, const Vec2* pos, const Vec2* vel,
+    const unsigned int parent, const unsigned int beam);
+
+void beam_end(const unsigned int parent, int beam);
+
 /* Update. */
 void weapons_update(const double dt);
 void weapons_render(const WeaponLayer layer);