From e9985fc8cafaa78d48f44ca351b0564fe19ccf21 Mon Sep 17 00:00:00 2001
From: Allanis <allanis@saracraft.net>
Date: Thu, 12 Sep 2013 16:10:36 +0100
Subject: [PATCH] [Change] Improved accuracy of collision on explosions.

---
 src/collision.c | 139 +++++++++++++++++-------------------------------
 src/collision.h |   9 ++--
 src/menu.c      |   2 +-
 src/weapon.c    |  32 +++++++----
 4 files changed, 77 insertions(+), 105 deletions(-)

diff --git a/src/collision.c b/src/collision.c
index e5097a1..90fd4b0 100644
--- a/src/collision.c
+++ b/src/collision.c
@@ -3,22 +3,32 @@
 #include "collision.h"
 
 /**
- * @brief Collide sprite at (asx, asy) in 'at' at pos 'ap' with sprite at (bsx,bsy)
- * in 'bt' at 'bp'
  *
- * @param[in] at   - Texture a.
- * @param[in] asx  - Position of x of sprite a.
- * @param[in] asy  - Position of y of sprite a.
- * @param[in] ap   - Position in space of sprite a.
- * @param[in] bt   - Texture b.
- * @param[in] bsx  - Position of x of sprite b.
- * @param[in] bsy  - Position of y of sprite b.
- * @param[in] bp   - Position in space of sprite b.
+ * @fn CollideSprite(const glTexture* at, const int asx, const int asy,
+ *                  const Vec2* ap, const glTexture* bt,
+ *                  const int bsx, const int bsy, const Vec2* bp,
+ *                  Vec2* crash)
+ *
+ * @brief Check whether or not sprites collide.
+ *
+ * This function does pixel perfect checks. If the collision actually accurs,
+ * crash is set to store the real position of the collision.
+ *
+ * @param[in] at      - Texture a.
+ * @param[in] asx     - Position of x of sprite a.
+ * @param[in] asy     - Position of y of sprite a.
+ * @param[in] ap      - Position in space of sprite a.
+ * @param[in] bt      - Texture b.
+ * @param[in] bsx     - Position of x of sprite b.
+ * @param[in] bsy     - Position of y of sprite b.
+ * @param[in] bp      - Position in space of sprite b.
+ * @param[out] crash  - Actual position of the collision (only on collision).
  * @return 1 on collision, 0 else.
  */
 int CollideSprite(const glTexture* at, const int asx, const int asy,
                   const Vec2* ap, const glTexture* bt,
-                  const int bsx, const int bsy, const Vec2* bp) {
+                  const int bsx, const int bsy, const Vec2* bp,
+                  Vec2* crash) {
 
   int x,y;
   int ax1, ax2, ay1, ay2;
@@ -63,92 +73,43 @@ int CollideSprite(const glTexture* at, const int asx, const int asy,
     for(x = inter_x0; x <= inter_x1; x++)
       /* Compute offsets for surface before passing to TransparentPixel test. */
       if((!gl_isTrans(at, abx + x, aby + y)) &&
-         (!gl_isTrans(bt, bbx + x, bby + y)))
+         (!gl_isTrans(bt, bbx + x, bby + y))) {
+
+        /* Set the crash position. */
+        crash->x = x;
+        crash->y = y;
         return 1;
+      }
 
   return 0;
 }
 
 /**
- * @brief Calculate collision path corrections.
+ * @fn int CollideLineSprite(const Vec2* ap, double dir,
+ *                           const glTexture* bt, const int bsx, const int bsy,
+ *                           const Vec2& bp, Vec2* crash)
  *
- * @param[in] p     - Position of object that's trying to collide.
- * @param[in] v     - Velocity of object that's trying to collide.
- * @param[in] tp    - Position of the target to collide into.
- * @param[in] tv    - Velocity of the target to collide into.
- * @param[in] limit - Accuracy limit.
- * @return Direction object will need to adjust velocity to for collision.
+ *    @param[in] ap Origin of the line.
+ *    @param[in] ad Direction of the line.
+ *    @param[in] bt Texture b.
+ *    @param[in] bsx Position of x of sprite b.
+ *    @param[in] bsy Position of y of sprite b
+ *    @param[in] bp Position in space of sprite b.
+ *    @return 1 on Collision, else 0.
+ *
+ * @sa CollideSprite
  */
-/*
- * Doesn't work as expected, needs to be fixed to allow missiles to use
- * the physics engine instead of hacking their velocities.
- */
-#if 0
-double CollidePath(const Vec2* p, Vec2* v,
-    const Vec2* tp, Vec2* tv, double limit) {
+int CollideLineSprite(const Vec2* ap, double ad,
+    const glTexture* bt, const int bsx, const int bsy, const Vec2* bp,
+    Vec2* crash) {
 
-  double mx, my;        /* Position modifiers. */
-  double t, tt;         /* Time to target. */
-  Vec2   test, ttest;   /* Test vector and target test vector. */
-  double offset;        /* Direction to face and error it produces. */
-  double mod, moddir;   /* Modifier for iteration. */
-  int i;
+  (void)ap;
+  (void)ad;
+  (void)bt;
+  (void)bsx;
+  (void)bsy;
+  (void)bp;
+  (void)crash;
 
-  /* Test vector. */
-  vect_cset(&test, tp->x - p->x, tp->y - p->y); /* Start byt straight line. */
-  t = VMOD(test) / VMOD(*v);                    /* d=v*t ==> t=d/v. */
-
-  /* Target test vector. */
-  vectnull(&ttest); /* Starting from itself. */
-  tt = VMOD(ttest) / VMOD(*tv);
-
-  /* Special case object isn't moving. */
-  if(VMOD(*v) < 1e-6)
-    return VANGLE(test);
-
-  /* Target faster than object. */
-  if(VMOD(*v) < VMOD(*tv)) {
-    vect_reflect(&test, v, tv);
-    return VANGLE(test);
-  }
-
-  /* Loop until error is minimal. */
-  offset = tt - t;
-  moddir = 1.;    /* Start off by position increments. */
-  mod    = 10.;   /* Start off by a 10 second jump. */
-  i = 0;
-  while(FABS(offset) > limit) {
-    if(i > 100) break;
-
-    /* Calculate position modifiers. */
-    if(offset < -mod/2.)  /* tt>t ==> major overshot. */
-      moddir = -1.;
-    else if(offset < 0.) { /* tt>t ==> overshot. */
-      /* Invert direction and half. */
-      moddir = -1.;
-      mod = mod/2.;
-    }
-    else if(offset > mod) /* tt<t ==> undershot. */
-      moddir = 1.; /* Make sure it's positive. */
-    else if(offset > 0.) { /* tt<t ==> minor undershot. */
-      /* Positive and shrink step. */
-      moddir = 1.;
-      mod = FABS(mod)/2.;
-    }
-    mx = tv->x * mod * moddir;
-    my = tv->y * mod * moddir;
-
-    /* Increment test vectors. */
-    vect_cadd(&test, mx, my);
-    vect_cadd(&ttest, mx, my);
-
-    /* Compare results. */
-    t = VMOD(test) / VMOD(*v);
-    tt = VMOD(ttest) / VMOD(*tv);
-    offset = tt - t;
-
-    i++;
-  }
-  return VANGLE(test);
 }
-#endif
+
diff --git a/src/collision.h b/src/collision.h
index 02a5388..9aaefbe 100644
--- a/src/collision.h
+++ b/src/collision.h
@@ -5,9 +5,10 @@
 /* Return 1 if collision is detected. */
 int CollideSprite(const glTexture* at, const int asx, const int asy,
                   const Vec2* ap, const glTexture* bt,
-                  const int bsx, const int bsy, const Vec2* bp);
+                  const int bsx, const int bsy, const Vec2* bp,
+                  Vec2* crash);
 
-/* Get direction to face the target. */
-/*double CollidePath(const Vec2* p, Vec2* v,
-    const Vec2* tp, Vec2* tv, const double limit);*/
+int CollideLineSprite(const Vec2* ap, double dir,
+    const glTexture* bt, const int bsx, const int bsy, const Vec2* bp,
+    Vec2* crash);
 
diff --git a/src/menu.c b/src/menu.c
index f3831bd..fc4e85a 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -150,7 +150,7 @@ static void menu_main_exit(char* str) {
 /* Ze ingame menu. */
 /* Small ingame menu. */
 void menu_small(void) {
-  if((player == NULL) player_isFlag(PLAYER_DESTROYED)
+  if((player == NULL) || player_isFlag(PLAYER_DESTROYED)
       || pilot_isFlag(player, PILOT_DEAD) ||
       (menu_isOpen(MENU_MAIN) ||
        menu_isOpen(MENU_SMALL) ||
diff --git a/src/weapon.c b/src/weapon.c
index e8e9c79..782aab3 100644
--- a/src/weapon.c
+++ b/src/weapon.c
@@ -68,7 +68,7 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir,
 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);
+static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer, Vec2* pos);
 static void weapon_destroy(Weapon* w, WeaponLayer layer);
 static void weapon_free(Weapon* w);
 /* Think. */
@@ -313,6 +313,7 @@ static void weapon_render(const Weapon* w) {
 static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
   int i, wsx, wsy, psx, psy;
   glTexture* gfx;
+  Vec2 crash;
 
   gfx = outfit_gfx(w->outfit);
 
@@ -329,16 +330,19 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
     /* Smart weapons only collide with  their target. */
     if((weapon_isSmart(w)) && (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)) {
-      weapon_hit(w, pilot_stack[i], layer);
+         pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos,
+         &crash)) {
+
+      weapon_hit(w, pilot_stack[i], layer, &crash);
       return;
     }
     /* Dumb weapons hit anything not of the same faction. */
     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)) {
-      weapon_hit(w, pilot_stack[i], layer);
+              pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos,
+              &crash)) {
+      weapon_hit(w, pilot_stack[i], layer, &crash);
       return;
     }
   }
@@ -349,8 +353,16 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
   (*w->solid->update)(w->solid, dt);
 }
 
-/* Good shot. */
-static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer) {
+/**
+ * fn static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer, vec2* pos)
+ *
+ * @breif Weapon hit the pilot.
+ *    @param w Weapon Involved in the collision.
+ *    @param p Pilot that got it.
+ *    @param layer Layer to which the weapon belongs.
+ *    @param pos Position of the hit.
+ */
+static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer, Vec2* pos) {
   /* Someone should let the ai know it's been attacked. */
   if(!pilot_isPlayer(p)) {
     if((player_target == p->id) || (RNG(0,2) == 0)) { /* 33% chance. */
@@ -361,12 +373,10 @@ static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer) {
       }
       ai_attacked(p, w->parent);
     }
-    spfx_add(outfit_spfx(w->outfit),
-             VX(w->solid->pos), VY(w->solid->pos),
+    spfx_add(outfit_spfx(w->outfit), pos->x, pos->y,
              VX(p->solid->vel), VY(p->solid->vel), SPFX_LAYER_BACK);
   } else
-    spfx_add(outfit_spfx(w->outfit),
-             VX(w->solid->pos), VY(w->solid->pos),
+    spfx_add(outfit_spfx(w->outfit), pos->x, pos->y,
              VX(p->solid->vel), VY(p->solid->vel), SPFX_LAYER_FRONT);
 
   /* Let the ship know that is should take some kind of damage. */