00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
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 
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   
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   
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   
00089   world.Dig(pos, config.explosion_range);
00090 
00091   
00092   jukebox.Play("share", son);
00093 
00094   
00095   
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     
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     
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   
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   
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       
00220       if (distance <= config.explosion_range || distance < config.blast_range)
00221       {
00222         
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 }