From: Peter Todd <retep2@home.com>
Subject: Explosion Forces
To: pingus-devel@lists.deus.net
Date: Sat, 13 Nov 1999 11:55:53 -0500
Reply-To: retep@penguinpowered.com
Resent-From: pingus-devel@lists.deus.net

Here is the explosion forces patch. Now the bombers will kill
pingu next to them. There is a problem though... The velocity of
the explosion tends to instantly kill the pingu next to the
explosion instead of launching the pingu into the air. :-( While
this is realistic we're aiming for cartoon physics. Any ideas?

Also pingu that are preforming an action don't get effected by
the explosion. I tried to make them get effected but ended up
breaking *lots* of stuff.Index: pingus/src/FVec.cc
===================================================================
RCS file: /home/mbn/public_cvsroot/pingus/src/FVec.cc,v
retrieving revision 1.2
diff -u -r1.2 FVec.cc
--- FVec.cc	1999/11/09 09:49:22	1.2
+++ FVec.cc	1999/11/13 16:41:58
@@ -22,4 +22,89 @@
 
 CL_Vector grav(0,1);
 
+CL_Array<GravityForce> ForcesHolder::grav_array;
+CL_Array<ExplosionForce> ForcesHolder::explo_array;
+
+// Apply the explosion force
+CL_Vector ExplosionForce::apply_forces(CL_Vector p,CL_Vector v){
+  CL_Vector tmpv = v;
+  float imod,dist;
+
+  // Is p within the radius of the explosion?
+  if (!((p.x - ip.x < isize && p.x - ip.x > -isize) && (p.y - ip.y < isize && p.y - ip.y > -isize)))
+    return v;
+
+  dist = p.x - ip.x;
+  if (dist < 0)
+    dist = -dist; 
+  imod = iinten * ((isize - dist) / isize);
+
+  //  cout << "Intensity - x = " << imod;
+  
+  // Apply the explosion to p
+  if (p.x > ip.x)
+    tmpv.x += imod;
+  else
+    tmpv.x -= imod;
+
+  dist = p.y - ip.y;
+  if (dist < 0)
+    dist = -dist; 
+  imod = iinten * ((isize - dist) / isize);
+
+  //  cout << " y = " << imod << "\n";
+
+  if (p.y > ip.y)
+    tmpv.y += imod;
+  else
+    tmpv.y -= imod;
+
+  return tmpv;
+}
+
+void ForcesHolder::add_force(GravityForce *f){
+  grav_array.add(f);
+}
+
+void ForcesHolder::add_force(ExplosionForce *f){
+  explo_array.add(f);
+}
+
+void ForcesHolder::clear_explo_list(){
+  int i;
+  for (i = 0; i < ForcesHolder::explo_array.get_num_items(); i++){
+    delete explo_array[i];
+  }
+  explo_array.clear();
+}
+
+void ForcesHolder::clear_all_forces(){
+  int i;
+  for (i = 0; i < ForcesHolder::grav_array.get_num_items(); i++){
+    delete grav_array[i];
+  }
+  grav_array.clear();
+
+  clear_explo_list();
+}
+
+CL_Vector ForcesHolder::apply_forces(CL_Vector p,CL_Vector v){
+  CL_Vector tv = v;
+  int i;
+
+  // Go through all of the forces and apply them all
+
+  // Gravity array...
+  for (i = 0; i < ForcesHolder::grav_array.get_num_items(); i++){
+    tv = ForcesHolder::grav_array[i]->apply_forces(p,v);
+  }
+
+  // Explosion array...
+  for (i = 0; i < ForcesHolder::explo_array.get_num_items(); i++){
+    tv = ForcesHolder::explo_array[i]->apply_forces(p,v);
+  }
+
+  return tv;
+}
+
 /* EOF */
Index: pingus/src/FVec.hh
===================================================================
RCS file: /home/mbn/public_cvsroot/pingus/src/FVec.hh,v
retrieving revision 1.2
diff -u -r1.2 FVec.hh
--- FVec.hh	1999/11/09 09:49:22	1.2
+++ FVec.hh	1999/11/13 16:42:01
@@ -25,6 +25,74 @@
 // Gravity
 extern CL_Vector grav;
 
+// The GravityForce class.
+class GravityForce {
+protected:
+  // The force vector
+  CL_Vector ifv; 
+
+public:
+  GravityForce(CL_Vector fv){
+    ifv = fv;
+  }
+
+  // Applies the force to a velocity vector, v, a position p and
+  // returns the new velicty vector. Just adds fv to v, p is ignored
+  // as gravity is universal.
+  CL_Vector apply_forces(CL_Vector p,CL_Vector v){
+    return v + ifv;
+  }
+};
+
+// The ExplosionForce class.
+class ExplosionForce {
+protected:
+  // The intensity
+  float iinten;
+  
+  // The size
+  float isize;
+
+  // The position
+  CL_Vector ip;
+
+public:
+  ExplosionForce(float inten, float size,CL_Vector p){
+    iinten = inten;
+    isize = size;
+    ip = p;
+  }
+
+  CL_Vector apply_forces(CL_Vector p,CL_Vector v);
+};
+
+// The force holder
+class ForcesHolder {
+public:
+  // The gravity force array
+  static CL_Array<GravityForce> grav_array;
+
+  // The explosion force array
+  static CL_Array<ExplosionForce> explo_array;
+
+public:
+  
+  // Add a gravity force
+  static void add_force(GravityForce *f);
+
+  // Add a explosion force
+  static void add_force(ExplosionForce *f);
+
+  // Clear the explosion force list
+  static void clear_explo_list();
+
+  // Clear all forces
+  static void clear_all_forces();
+
+  // Apply forces
+  static CL_Vector apply_forces(CL_Vector p,CL_Vector v);
+};
+
 #endif /* FVEC_HH */
 
 /* EOF */
Index: pingus/src/Pingu.cc
===================================================================
RCS file: /home/mbn/public_cvsroot/pingus/src/Pingu.cc,v
retrieving revision 1.33
diff -u -r1.33 Pingu.cc
--- Pingu.cc	1999/11/09 09:51:11	1.33
+++ Pingu.cc	1999/11/13 16:44:07
@@ -296,77 +296,54 @@
       }
     }
   }
-
-  if (action) { // if it has a action, do it
+  
+  if (action) { // if it has a
+    // action, do it but don't let the pingu do anything while moving
     action->let_move();
   } else {      // if not, do a walk
-    if (rel_getpixel(0, -1) == ColMap::NOTHING) { // if pingu is not on ground
 
-      // Replaced by the force vectors
-      if (!force_vectors){
-	++y_pos;
-	if (rel_getpixel(0, -1) == ColMap::NOTHING)
-	  ++y_pos;
-	++falling;
-	if (falling > 3) {
-	  environment = sky;
+    // Forces are only applied if the pingu isn't going something else
+    if (force_vectors){
+
+      // Apply forces
+      CL_Vector tmpvec;
+      tmpvec.x = x_pos;
+      tmpvec.y = y_pos;
+      
+      // Apply all forces
+      v = ForcesHolder::apply_forces(tmpvec,v);
+    
+      // Update x and y by moving the penguin to it's target *slowly*
+      // and checking if the penguin has hit the bottom at each loop
+      CL_Vector newp = v;
+      while (1){
+	if (newp.x != 0) {
+	  x_pos++;
+	  newp.x--;
+	}
+	if (newp.y != 0) {
+	  y_pos++;
+	  newp.y--;
 	}
-      } else {
+
+	if ((rel_getpixel(0, -1) != ColMap::NOTHING) || ((newp.x == 0) && (newp.y == 0)))
+	  break;
+      }
+    
+      if (rel_getpixel(0, -1) == ColMap::NOTHING) { // if pingu is not on ground
 	++falling;
 	old_v = v;
-
+      
 	if (falling > 3) {
 	  environment = sky;
 	}
-
-	// Add grav to velocity if the velocity is zero. Otherwise
-	// double the velocity if we are going down, half it if going
-	// up.
-	if (v.x == 0) {
-	  v = v + grav;
-	} else {
-	  if (v.x > 1) 
-	    v.x = v.x + v.x;
-	  else 
-	    v.x = v.x / 2;
-	}
-
-	// Update x and y by moving the penguin to it's target *slowly*
-	// and checking if the penguin has hit the bottom at each loop
-	CL_Vector newp = v;
-	while (1){
-	  if (newp.x != 0) {
-	    x_pos++;
-	    newp.x--;
-	  }
-	  if (newp.y != 0) {
-	    y_pos++;
-	    newp.y--;
-	  }
-	  if ((rel_getpixel(0, -1) != ColMap::NOTHING) || ((newp.x == 0) && (newp.y == 0)))
-	    break;
-	}
-
+      
 	// If we are going fast enough to get smashed set falling to 80
-	/*	if (((v.x - old_v.x > 15) || (v.x - old_v.x < - 15))
-		|| ((v.y - old_v.y > 15) || (v.y - old_v.y < - 15))) {*/
 	if (((v.x > 15) || (v.x < - 15))
 	    || ((v.y > 15) || (v.y < - 15))) {
 	  falling = 80;
-	}
-      }
-    } else { // if pingu is on ground
-      if (!force_vectors) {
-	if (falling > 75) {
-	  // FIXME: This is a LinuxTag Hack and should be replaced
-	  // with a real ground smashing action! 
-	  set_action(new Smashed);
 	}
-	falling = 0;
-      }
-      environment = land;
-
-      if (force_vectors){
+      }else {
 	// Did we stop too fast?
 	if (((v.x - old_v.x > 15) || (v.x - old_v.x < - 15))
 	    || ((v.y - old_v.y > 15) || (v.y - old_v.y < - 15))) {
@@ -376,13 +353,37 @@
 	}
 	//if (((v.x - old_v.x) != 0) || ((v.y - old_v.y != 0))) 
 	//cout << "Velocity difference - " << v.x - old_v.x << "," << v.y - old_v.y << "\n";
-
+      
 	// Reset the velocity
 	v.x = 0;
 	v.y = 0;
+      
+	falling = 0;
+      }
+    }
 
+    if (rel_getpixel(0, -1) == ColMap::NOTHING) { // if pingu is not on ground
+
+      // Replaced by the force vectors
+      if (!force_vectors){
+	++y_pos;
+	if (rel_getpixel(0, -1) == ColMap::NOTHING)
+	  ++y_pos;
+	++falling;
+	if (falling > 3) {
+	  environment = sky;
+	}
+      }
+    } else { // if pingu is on ground
+      if (!force_vectors) {
+	if (falling > 75) {
+	  // FIXME: This is a LinuxTag Hack and should be replaced
+	  // with a real ground smashing action! 
+	  set_action(new Smashed);
+	}
 	falling = 0;
       }
+      environment = land;
 
       if (rel_getpixel(1, 0) == ColMap::NOTHING) { // if infront is free
 	x_pos += direction;    
Index: pingus/src/World.cc
===================================================================
RCS file: /home/mbn/public_cvsroot/pingus/src/World.cc,v
retrieving revision 1.47
diff -u -r1.47 World.cc
--- World.cc	1999/10/03 08:22:23	1.47
+++ World.cc	1999/11/13 16:44:09
@@ -38,6 +38,7 @@
 #include "actions/pingu_actions.hh"
 #include "actions/bomber.hh"
 #include "entrances/entrances.hh"
+#include "FVec.hh"
 
 // Workaround for a VC bug
 #ifdef WIN32
@@ -171,6 +172,10 @@
 
   particle.let_move();
   bg->let_move();
+
+  if (force_vectors)
+    // Clear the explosion force list
+    ForcesHolder::clear_explo_list();
 }
 
 void 
@@ -327,6 +332,13 @@
   } 
  
   if (sound_enabled) PingusSound::play(PingusSound::LETSGO);
+
+  // Setup the gravity force
+  if (force_vectors){
+    // Clear all old forces
+    ForcesHolder::clear_all_forces();
+    ForcesHolder::add_force(new GravityForce(grav));
+  }
 }
 
 PinguHolder*
Index: pingus/src/actions/bomber.cc
===================================================================
RCS file: /home/mbn/public_cvsroot/pingus/src/actions/bomber.cc,v
retrieving revision 1.18
diff -u -r1.18 bomber.cc
--- bomber.cc	1999/10/02 20:15:57	1.18
+++ bomber.cc	1999/11/13 16:44:09
@@ -18,6 +18,7 @@
 #include "bomber.hh"
 #include "../globals.hh"
 #include "../PingusSound.hh"
+#include "../FVec.hh"
 
 PinguAction*
 make_Bomber()
@@ -114,7 +115,15 @@
     // Remove some ground
     pingu->colmap->remove(bomber_radius, pingu->x_pos - 20, pingu->y_pos - 16 - 20);
     pingu->map->remove(bomber_radius, pingu->x_pos - 20, pingu->y_pos - 16 - 20);
+
+    // Add an explosion to the forces list
+    if (force_vectors) {
+      CL_Vector tmpv(pingu->x_pos,pingu->y_pos);
+      
+      ForcesHolder::add_force(new ExplosionForce(10,30,tmpv));
+    }
   }
+
 }
 
 /* EOF */
