src/weapon/explosion.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *  Wormux is a convivial mass murder game.
00003  *  Copyright (C) 2001-2004 Lawrence Azzoug.
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00018  ******************************************************************************
00019  * Utilitaires pour les armes : applique une explosion en un point.
00020  *****************************************************************************/
00021 
00022 #include "explosion.h"
00023 #include "../graphic/surface.h"
00024 #include "../graphic/video.h"
00025 #include "../include/action_handler.h"
00026 #include "../map/camera.h"
00027 #include "../map/map.h"
00028 #include "../network/network.h"
00029 #include "../object/objects_list.h"
00030 #include "../particles/particle.h"
00031 #include "../object/physical_obj.h"
00032 #include "../sound/jukebox.h"
00033 #include "../team/macro.h"
00034 #include "../tool/debug.h"
00035 #include "../tool/math_tools.h"
00036 
00037 Profile *weapons_res_profile = NULL;
00038 
00039 // Network explosion defined below
00040 void ApplyExplosion_server (const Point2i &pos,
00041                      const ExplosiveWeaponConfig &config,
00042                      const std::string& son,
00043                      bool fire_particle,
00044                      ParticleEngine::ESmokeStyle smoke);
00045 
00046 void ApplyExplosion (const Point2i &pos,
00047                      const ExplosiveWeaponConfig &config,
00048                      const std::string& son,
00049                      bool fire_particle,
00050                      ParticleEngine::ESmokeStyle smoke
00051                      )
00052 {
00053   if(network.IsLocal())
00054     ApplyExplosion_common(pos, config, son, fire_particle, smoke);
00055   else
00056   if(network.IsServer())
00057     ApplyExplosion_server(pos, config, son, fire_particle, smoke);
00058   else
00059   if(network.IsClient())
00060     return;
00061   // client receives explosion via the action handler
00062 }
00063 
00064 void ApplyExplosion_common (const Point2i &pos,
00065                      const ExplosiveWeaponConfig &config,
00066                      const std::string& son,
00067                      bool fire_particle,
00068                      ParticleEngine::ESmokeStyle smoke
00069                      )
00070 {
00071   MSG_DEBUG("explosion", "explosion range : %i\n", config.explosion_range);
00072 
00073 #ifdef HAVE_A_REALLY_BIG_CPU
00074   // Add particles based on the ground image
00075   if(config.explosion_range >= 15)
00076   {
00077     for(int y=-config.explosion_range; y < (int)config.explosion_range; y += 10)
00078     {
00079       int dx = (int) (cos(asin((float)y / config.explosion_range)) * (float) y);
00080       for(int x=-dx; x < dx; x += 10)
00081         ParticleEngine::AddNow(pos + Point2i(x-5,y-5), 1, particle_GROUND, true);
00082     }
00083   }
00084   else
00085     ParticleEngine::AddNow(pos, 1, particle_GROUND, true);
00086 #endif
00087 
00088   // Make a hole in the ground
00089   world.Dig(pos, config.explosion_range);
00090 
00091   // Play a sound
00092   jukebox.Play("share", son);
00093 
00094   // Apply damage on the character.
00095   // Do not care about the death of the active worm.
00096   double highest_force = 0.0;
00097   Character* fastest_character = NULL;
00098   FOR_ALL_CHARACTERS(equipe,ver)
00099   {
00100     double distance = pos.Distance(ver -> GetCenter());
00101     if(distance < 1.0)
00102       distance = 1.0;
00103 
00104     // If the character is in the explosion range, apply damage on it !
00105     if (distance <= config.explosion_range)
00106     {
00107       MSG_DEBUG("explosion", "\n*Character %s : distance= %f", ver->GetName().c_str(), distance);
00108       double dmg = cos(M_PI_2 * distance / config.explosion_range);
00109       dmg *= config.damage;
00110       MSG_DEBUG("explosion", "hit_point_loss energy= %i", ver->GetName().c_str(), dmg);
00111       ver -> SetEnergyDelta (-(int)dmg);
00112     }
00113 
00114     // If the character is in the blast range, apply the blast on it !
00115     if (distance <= config.blast_range)
00116     {
00117       double angle;
00118       double force = cos(M_PI_2 * distance / config.blast_range);
00119       force *= config.blast_force;
00120 
00121       if ( force > highest_force )
00122       {
00123         fastest_character = &(*ver);
00124         highest_force = force;
00125       }
00126 
00127       if (!EgalZero(distance))
00128       {
00129         angle  = pos.ComputeAngle(ver -> GetCenter());
00130         if( angle > 0 )
00131           angle  = - angle;
00132       }
00133       else
00134         angle = -M_PI/2;
00135 
00136 
00137       MSG_DEBUG("explosion", "force = %f", force);
00138       ver->AddSpeed (force / ver->GetMass(), angle);
00139       ver->SignalExplosion();
00140     }
00141   }
00142 
00143   if(fastest_character != NULL)
00144     camera.FollowObject (fastest_character, true, true);
00145 
00146   // Apply the blast on physical objects.
00147   FOR_EACH_OBJECT(it)
00148    {
00149      PhysicalObj *obj = *it;
00150      if (!obj->GoesThroughWall() && !obj->IsGhost())
00151      {
00152        double distance = pos.Distance(obj->GetCenter());
00153        if(distance < 1.0)
00154          distance = 1.0;
00155 
00156        if (distance <= config.explosion_range)
00157        {
00158          double dmg = cos(M_PI_2 * distance / config.explosion_range);
00159          dmg *= config.damage;
00160          obj->AddDamage (config.damage);
00161        }
00162 
00163        if (distance <= config.blast_range)
00164        {
00165          double angle;
00166          double force = cos(M_PI_2 * distance / config.blast_range);
00167          force *= config.blast_force;
00168 
00169          if (!EgalZero(distance))
00170            angle  = pos.ComputeAngle(obj->GetCenter());
00171          else
00172            angle = -M_PI_2;
00173 
00174          if(fastest_character != NULL)
00175            camera.FollowObject (obj, true, true);
00176          obj->AddSpeed (force / obj->GetMass(), angle);
00177        }
00178      }
00179    }
00180 
00181   ParticleEngine::AddExplosionSmoke(pos, config.particle_range, smoke);
00182 
00183   // Do we need to generate some fire particles ?
00184   if (fire_particle)
00185      ParticleEngine::AddNow(pos , 5, particle_FIRE, true);
00186 }
00187 
00188 void ApplyExplosion_server (const Point2i &pos,
00189                      const ExplosiveWeaponConfig &config,
00190                      const std::string& son,
00191                      bool fire_particle,
00192                      ParticleEngine::ESmokeStyle smoke
00193                      )
00194 {
00195   ActionHandler* action_handler = ActionHandler::GetInstance();
00196 
00197   Action a_begin_sync(Action::ACTION_SYNC_BEGIN);
00198   network.SendAction(&a_begin_sync);
00199 
00200   TeamsList::iterator
00201     it=teams_list.playing_list.begin(),
00202     end=teams_list.playing_list.end();
00203 
00204   Action* send_char = new Action(Action::ACTION_SET_CHARACTER_PHYSICS);
00205 
00206   for (int team_no = 0; it != end; ++it, ++team_no)
00207   {
00208     Team& team = **it;
00209     Team::iterator
00210         tit = team.begin(),
00211         tend = team.end();
00212 
00213     for (int char_no = 0; tit != tend; ++tit, ++char_no)
00214     {
00215       Character &character = *tit;
00216 
00217       double distance = pos.Distance( character.GetCenter());
00218 
00219       // If the character is in the explosion range, apply damage on it !
00220       if (distance <= config.explosion_range || distance < config.blast_range)
00221       {
00222         // cliens : Place characters
00223         send_char->StoreCharacter(team_no, char_no);
00224       }
00225     }
00226   }
00227   action_handler->NewAction(send_char);
00228 
00229   Action* a = new Action(Action::ACTION_EXPLOSION);
00230   a->Push(pos.x);
00231   a->Push(pos.y);
00232   a->Push((int)config.explosion_range);
00233   a->Push((int)config.particle_range);
00234   a->Push((int)config.damage);
00235   a->Push(config.blast_range);
00236   a->Push(config.blast_force);
00237   a->Push(son);
00238   a->Push(fire_particle);
00239   a->Push(smoke);
00240 
00241   action_handler->NewAction(a);
00242   Action a_sync_end(Action::ACTION_SYNC_END);
00243   network.SendAction(&a_sync_end);
00244 }

Generated on Mon Jan 1 13:11:00 2007 for Wormux by  doxygen 1.4.7