From 05b1d19e551b411873a8d6eb26701293da66ac2a Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Sun, 24 Nov 2013 21:56:40 +0000
Subject: [PATCH] [Add] Added explosions, only being used on deaths right now.

---
 src/explosion.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/explosion.h | 15 +++++++++
 src/pilot.c     | 45 +++++++++++++++++++++++--
 src/pilot.h     |  8 +++--
 src/weapon.c    | 63 +++++++++++++++++++++++++++++++++++
 src/weapon.h    |  4 +++
 6 files changed, 217 insertions(+), 5 deletions(-)
 create mode 100644 src/explosion.c
 create mode 100644 src/explosion.h

diff --git a/src/explosion.c b/src/explosion.c
new file mode 100644
index 0000000..d4050fa
--- /dev/null
+++ b/src/explosion.c
@@ -0,0 +1,87 @@
+/**
+ * @file explosion.c
+ */
+#include "lephisto.h"
+#include "log.h"
+#include "pilot.h"
+#include "weapon.h"
+#include "spfx.h"
+#include "rng.h"
+#include "explosion.h"
+
+/**
+ * @fn void expl_explode(double x, double y, double vx, double vy,
+ * double radius, DamageType dtype, double damage,
+ *  unsigned int parent, int mode)
+ *
+ * @brief 
+ */
+void expl_explode(double x, double y, double vx, double vy,
+    double radius, DamageType dtype, double damage,
+    unsigned int parent, int mode) { 
+
+  int i, n;
+  double a, d;
+  double area;
+  double ex, ey;
+  double layer;
+  int efx;
+  int exp_s, exp_m, exp_l;
+
+  /* Standard stuff. */
+  exp_s = spfx_get("ExpS");
+  exp_m = spfx_get("ExpM");
+  exp_s = spfx_get("ExpL");
+  layer = SPFX_LAYER_FRONT;
+
+  /* Number of explosions. */
+  area = M_PI * pow2(radius);
+  n = (int)(area / 100.);
+
+  /* Create explosions. */
+  for(i = 0; i < n; i++) {
+    /* Get position. */
+    a = RNGF()*360.;
+    d = RNGF()*(radius-5.) + 5.;
+    ex = d*cos(a);
+    ey = d*sin(a);
+
+    /* Create explosion. */
+    efx = (RNG(0,2)==0) ? exp_m : exp_s;
+    spfx_add(efx, x+ex, y+ey, vx, vy, layer);
+  }
+
+  /* Final explosion. */
+  spfx_add(exp_l, x, y, vx, vy, layer);
+
+  /* Run the damage. */
+  if(damage > 0.)
+    expl_explodeDamage(x, y, radius, dtype, damage, parent, mode);
+}
+
+/**
+ * @fn 
+ *
+ * @brief
+ */
+void expl_explodeDamage(double x, double y, double radius,
+    DamageType dtype, double damage,
+    unsigned int parent, int mode) {
+
+  /* Explosion affects ships. */
+  if(mode & EXPL_MODE_SHIP)
+    pilot_explode(x, y, radius, dtype, damage, parent);
+
+  /* Explosion affects missiles and bolts. */
+  if((mode & EXPL_MODE_MISSILE) && (mode & EXPL_MODE_BOLT))
+    weapon_explode(x, y, radius, dtype, damage, parent, mode);
+
+  /* Explosion affects missiles. */
+  else if(mode & EXPL_MODE_MISSILE)
+    weapon_explode(x, y, radius, dtype, damage, parent, mode);
+
+  /* Explosion affects bolts. */
+  else if(mode & EXPL_MODE_BOLT)
+    weapon_explode(x, y, radius, dtype, damage, parent, mode);
+}
+
diff --git a/src/explosion.h b/src/explosion.h
new file mode 100644
index 0000000..6e5976a
--- /dev/null
+++ b/src/explosion.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "outfit.h"
+
+#define EXPL_MODE_SHIP      (1<<0)  /**< Affects ships. */
+#define EXPL_MODE_MISSILE   (1<<1)  /**< Affects missiles. */
+#define EXPL_MODE_BOLT      (1<<2)  /**< Affects bots. */
+
+void expl_explode(double x, double y, double vx, double vy,
+    double radius, DamageType dtype, double damage,
+    unsigned int parent, int mode);
+
+void expl_explodeDamage(double x, double y, double radius,
+    DamageType dtype, double damage,
+    unsigned int parent, int mode);
+
diff --git a/src/pilot.c b/src/pilot.c
index a6353e7..2b45c49 100644
--- a/src/pilot.c
+++ b/src/pilot.c
@@ -17,6 +17,7 @@
 #include "rng.h"
 #include "hook.h"
 #include "map.h"
+#include "explosion.h"
 #include "pilot.h"
 
 #define XML_ID    "Fleets"  /**< XML document identifier. */
@@ -554,6 +555,40 @@ void pilot_setAfterburner(Pilot* p) {
   p->afterburner = NULL;
 }
 
+/**
+ */
+void pilot_explode(double x, double y, double radius,
+    DamageType dtype, double damage, unsigned int parent) {
+  
+  int i;
+  double rx, ry;
+  double dist, rad2;
+  Pilot* p;
+  Solid s; /* Only need to manipulate mass and vel. */
+
+  rad2 = radius*radius;
+
+  for(i = 0; i < pilot_nstack; i++) {
+    p = pilot_stack[i];
+
+    /* Calculate a bit. */
+    rx = p->solid->pos.x - x;
+    ry = p->solid->pos.y - y;
+    dist = pow2(rx) + pow2(ry);
+
+    /* Pilot is hit. */
+    if(dist < rad2) {
+      /* Impact settings. */
+      s.mass = (rad2 - dist) / 10.;
+      s.vel.x = rx;
+      s.vel.y = ry;
+
+      /* Actual damage calculations. */
+      pilot_hit(p, &s, parent, dtype, damage);
+    }
+  }
+}
+
 /**
  * @fn void pilot_render(Pilot* p)
  *
@@ -601,9 +636,13 @@ static void pilot_update(Pilot* pilot, const double dt) {
 
     /* Final explosion. */
     else if(!pilot_isFlag(pilot, PILOT_EXPLODED) && (t > pilot->ptimer - 200)) {
-      spfx_add(spfx_get("ExpL"),
-               VX(pilot->solid->pos), VY(pilot->solid->pos),
-               VX(pilot->solid->vel), VY(pilot->solid->vel), SPFX_LAYER_BACK);
+      /* Damage from explosion. */
+      a = sqrt(pilot->solid->mass);
+      expl_explode(pilot->solid->pos.x, pilot->solid->pos.y,
+          pilot->solid->vel.x, pilot->solid->vel.y,
+          pilot->ship->gfx_space->sw / 2. + a,
+          DAMAGE_TYPE_KINETIC, 2.*a - 20.,
+          0, EXPL_MODE_SHIP);
       pilot_setFlag(pilot, PILOT_EXPLODED);
 
       /* Release cargo. */
diff --git a/src/pilot.h b/src/pilot.h
index 92aad51..ad80af8 100644
--- a/src/pilot.h
+++ b/src/pilot.h
@@ -219,13 +219,17 @@ 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);
+double pilot_face(Pilot* p, const double dir);
+void pilot_hyperspaceAbort(Pilot* p);
+/* Special outfit stuff. */
 void pilot_switchSecondary(Pilot* p, int i);
 void pilot_setSecondary(Pilot* p, const char* secondary);
 void pilot_setAmmo(Pilot* p);
 int pilot_getAmmo(Pilot* p, Outfit* o);
 void pilot_setAfterburner(Pilot* p);
-double pilot_face(Pilot* p, const double dir);
-void pilot_hyperspaceAbort(Pilot* p);
+/* Explosion. */
+void pilot_explode(double x, double y, double radius,
+    DamageType dtype, double damage, unsigned int parent);
 /* Outfits. */
 int pilot_freeSpace(Pilot* p); /* Pilot space. */
 int pilot_addOutfit(Pilot* pilot, Outfit* outfit, int quantity);
diff --git a/src/weapon.c b/src/weapon.c
index a62918c..9c612eb 100644
--- a/src/weapon.c
+++ b/src/weapon.c
@@ -21,6 +21,7 @@
 #include "player.h"
 #include "spfx.h"
 #include "opengl.h"
+#include "explosion.h"
 #include "weapon.h"
 
 #define weapon_isSmart(w) (w->think != NULL) /**< Checks if the weapon w is smart. */
@@ -98,6 +99,9 @@ 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);
+static void weapon_explodeLayer(WeaponLayer layer,
+    double x, double y, double radius,
+    unsigned int parent, int mode);
 /* Think. */
 static void think_seeker(Weapon* w, const double dt);
 static void think_beam(Weapon* w, const double dt);
@@ -1039,3 +1043,62 @@ void weapon_exit(void) {
   }
 }
 
+/**
+ * @fn void weapon_explode(double x, double y, double radius,
+    DamageType dtype, double damage,
+    unsigned int parent, int mode)
+
+    @brief Clear possible exploded weapons.
+ */
+void weapon_explode(double x, double y, double radius,
+    DamageType dtype, double damage,
+    unsigned int parent, int mode) {
+
+  (void)dtype;
+  (void)damage;
+  weapon_explodeLayer(WEAPON_LAYER_FG, x, y, radius, parent, mode);
+  weapon_explodeLayer(WEAPON_LAYER_BG, x, y, radius, parent, mode);
+}
+
+static void weapon_explodeLayer(WeaponLayer layer,
+    double x, double y, double radius,
+    unsigned int parent, int mode) {
+  
+  (void)parent;
+  int i;
+  Weapon** curLayer;
+  int *nLayer;
+  double dist, rad2;
+
+  /* Set the proper layer. */
+  switch(layer) {
+    case WEAPON_LAYER_BG:
+      curLayer = wbackLayer;
+      nLayer = &nwbackLayer;
+      break;
+    case WEAPON_LAYER_FG:
+      curLayer = wfrontLayer;
+      nLayer = &nwbackLayer;
+      break;
+    default:
+      ERR("Invalid WEAPON_LAYER specified.");
+      return;
+  }
+
+  rad2 = radius*radius;
+
+  /* Now try to destroy the weapons affected. */
+  for(i = 0; i < *nLayer; i++) {
+    if(((mode & EXPL_MODE_MISSILE) && outfit_isAmmo(curLayer[i]->outfit)) ||
+        ((mode & EXPL_MODE_BOLT) && outfit_isBolt(curLayer[i]->outfit))) {
+      dist = pow2(curLayer[i]->solid->pos.x - x) +
+        pow2(curLayer[i]->solid->pos.y - y);
+
+      if(dist < rad2) {
+        weapon_destroy(curLayer[i], layer);
+        i--;
+      }
+    }
+  }
+}
+
diff --git a/src/weapon.h b/src/weapon.h
index 03f9cd7..1ee8471 100644
--- a/src/weapon.h
+++ b/src/weapon.h
@@ -22,6 +22,10 @@ int beam_start(const Outfit* outfit,
 
 void beam_end(const unsigned int parent, int beam);
 
+void weapon_explode(double x, double y, double radius,
+    DamageType dtype, double damage,
+    unsigned int parent, int mode);
+
 /* Update. */
 void weapons_update(const double dt);
 void weapons_render(const WeaponLayer layer);