src/weapon/launcher.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  * WeaponLauncher: generic weapon to launch a projectile
00020  *****************************************************************************/
00021 
00022 #include "launcher.h"
00023 
00024 #include <sstream>
00025 
00026 #include "explosion.h"
00027 #include "../game/config.h"
00028 #include "../game/time.h"
00029 #include "../graphic/video.h"
00030 #include "../include/action_handler.h"
00031 #include "../include/app.h"
00032 #include "../interface/game_msg.h"
00033 #include "../map/camera.h"
00034 #include "../object/objects_list.h"
00035 #include "../team/macro.h"
00036 #include "../team/teams_list.h"
00037 #include "../tool/debug.h"
00038 #include "../tool/math_tools.h"
00039 #include "../tool/i18n.h"
00040 
00041 #ifdef DEBUG
00042 //#define DEBUG_EXPLOSION_CONFIG
00043 #endif
00044 
00045 WeaponBullet::WeaponBullet(const std::string &name,
00046                            ExplosiveWeaponConfig& cfg,
00047                            WeaponLauncher * p_launcher) :
00048   WeaponProjectile(name, cfg, p_launcher)
00049 {
00050   explode_colliding_character = true;
00051   ResetTimeOut();
00052 }
00053 
00054 // Signal that the bullet has hit the ground
00055 void WeaponBullet::SignalGroundCollision()
00056 {
00057   jukebox.Play("share", "weapon/ricoche1");
00058   WeaponProjectile::SignalGroundCollision();
00059   launcher->IncMissedShots();
00060 }
00061 
00062 void WeaponBullet::SignalOutOfMap()
00063 {
00064   WeaponProjectile::SignalOutOfMap();
00065   launcher->IncMissedShots();
00066 }
00067 
00068 void WeaponBullet::SignalObjectCollision(PhysicalObj * obj)
00069 {
00070   if (typeid(*obj) != typeid(Character)) {
00071     obj->AddDamage(cfg.damage);
00072     Explosion();
00073   } else {
00074     Character * tmp = (Character*)(obj);
00075     tmp -> SetEnergyDelta (-cfg.damage);
00076     tmp -> AddSpeed (2, GetSpeedAngle());
00077     Ghost();
00078   }
00079 }
00080 
00081 void WeaponBullet::Refresh()
00082 {
00083   WeaponProjectile::Refresh();
00084   image->SetRotation_rad(GetSpeedAngle());
00085 }
00086 
00087 void WeaponBullet::DoExplosion()
00088 {
00089   Point2i pos = GetCenter();
00090   ApplyExplosion (pos, cfg, "", false, ParticleEngine::LittleESmoke);
00091 }
00092 //-----------------------------------------------------------------------------
00093 
00094 
00095 WeaponProjectile::WeaponProjectile (const std::string &name,
00096                                     ExplosiveWeaponConfig& p_cfg,
00097                                     WeaponLauncher * p_launcher)
00098   : PhysicalObj (name), cfg(p_cfg)
00099 {
00100   m_allow_negative_y = true;
00101   SetCollisionModel(false, true, true);
00102   launcher = p_launcher;
00103 
00104   explode_colliding_character = false;
00105   explode_with_timeout = true;
00106   explode_with_collision = true;
00107 
00108   image = resource_manager.LoadSprite( weapons_res_profile, name);
00109   image->EnableRotationCache(32);
00110   SetSize(image->GetSize());
00111 
00112   // Set rectangle test
00113   int dx = image->GetWidth()/2-1;
00114   int dy = image->GetHeight()/2-1;
00115   SetTestRect (dx, dx, dy, dy);
00116 
00117   ResetTimeOut();
00118 }
00119 
00120 WeaponProjectile::~WeaponProjectile()
00121 {
00122   //  delete image; /*-> it causes a segfault :-/ */
00123 }
00124 
00125 void WeaponProjectile::Shoot(double strength)
00126 {
00127   MSG_DEBUG("weapon_projectile", "shoot.\n");
00128 
00129   Init();
00130 
00131   if (launcher != NULL) launcher->IncActiveProjectile();
00132 
00133   // Set the physical factors
00134   ResetConstants();
00135 
00136   // Set the initial position.
00137   SetXY(launcher->GetGunHolePosition());
00138   SetOverlappingObject(&ActiveCharacter());
00139 
00140   // Set the initial speed.
00141   double angle = ActiveCharacter().GetFiringAngle();
00142   RandomizeShoot(angle,strength);
00143   SetSpeed (strength, angle);
00144   PutOutOfGround(angle);
00145 
00146   begin_time = Time::GetInstance()->Read();
00147 
00148   ShootSound();
00149 
00150   lst_objects.AddObject (this);
00151   camera.FollowObject(this, true, true, true);
00152 }
00153 
00154 void WeaponProjectile::ShootSound()
00155 {
00156   jukebox.Play(ActiveTeam().GetSoundProfile(), "fire");
00157 }
00158 
00159 void WeaponProjectile::Refresh()
00160 {
00161   // Explose after timeout
00162   double tmp = Time::GetInstance()->Read() - begin_time;
00163 
00164   if(cfg.timeout && tmp > 1000 * (GetTotalTimeout())) SignalTimeout();
00165 }
00166 
00167 void WeaponProjectile::Draw()
00168 {
00169   image->Draw(GetPosition());
00170 
00171   int tmp = GetTotalTimeout();
00172 
00173   if (cfg.timeout && tmp != 0)
00174   {
00175     tmp -= (int)((Time::GetInstance()->Read() - begin_time) / 1000);
00176     if (tmp >= 0)
00177     {
00178       std::ostringstream ss;
00179       ss << tmp ;
00180       int txt_x = GetX() + GetWidth() / 2;
00181       int txt_y = GetY() - GetHeight();
00182       (*Font::GetInstance(Font::FONT_SMALL)).WriteCenterTop( Point2i(txt_x, txt_y) - camera.GetPosition(),
00183       ss.str(), white_color);
00184     }
00185   }
00186 }
00187 
00188 bool WeaponProjectile::IsImmobile() const
00189 {
00190   if(explode_with_timeout && begin_time + GetTotalTimeout() * 1000 > Time::GetInstance()->Read())
00191     return false;
00192   return PhysicalObj::IsImmobile();
00193 }
00194 
00195 // projectile explode and signal to the launcher the collision
00196 void WeaponProjectile::SignalObjectCollision(PhysicalObj * obj)
00197 {
00198   assert (obj != NULL);
00199 
00200   if (explode_colliding_character)
00201     Explosion();
00202 }
00203 
00204 // projectile explode when hiting the ground
00205 void WeaponProjectile::SignalGroundCollision()
00206 {
00207   if (explode_with_collision)
00208     Explosion();
00209 }
00210 
00211 // Default behavior : signal to launcher a collision and explode
00212 void WeaponProjectile::SignalCollision()
00213 {
00214   if (launcher != NULL && !launcher->ignore_collision_signal) launcher->SignalProjectileCollision();
00215 }
00216 
00217 // Default behavior : signal to launcher projectile is drowning
00218 void WeaponProjectile::SignalDrowning()
00219 {
00220   PhysicalObj::SignalDrowning();
00221   if (launcher != NULL && !launcher->ignore_drowning_signal)
00222     launcher->SignalProjectileDrowning();
00223 }
00224 
00225 // Signal a ghost state
00226 void WeaponProjectile::SignalGhostState(bool)
00227 {
00228   if (launcher != NULL && !launcher->ignore_ghost_state_signal)
00229     launcher->SignalProjectileGhostState();
00230 }
00231 
00232 void WeaponProjectile::SignalOutOfMap()
00233 {
00234 }
00235 
00236 // Implement it in subclass to randomize fire
00237 void WeaponProjectile::RandomizeShoot(double &angle,double &strength)
00238 {
00239 }
00240 
00241 // the projectile explode and signal the explosion to launcher
00242 void WeaponProjectile::Explosion()
00243 {
00244   MSG_DEBUG (m_name.c_str(), "Explosion");
00245   DoExplosion();
00246   SignalExplosion();
00247   Ghost();
00248 }
00249 
00250 void WeaponProjectile::SignalExplosion()
00251 {
00252   if (launcher != NULL && !launcher->ignore_explosion_signal)
00253     launcher->SignalProjectileExplosion();
00254 }
00255 
00256 void WeaponProjectile::DoExplosion()
00257 {
00258   Point2i pos = GetCenter();
00259   ApplyExplosion (pos, cfg);
00260 }
00261 
00262 void WeaponProjectile::IncrementTimeOut()
00263 {
00264   if (cfg.allow_change_timeout && GetTotalTimeout()<(int)cfg.timeout*2)
00265     m_timeout_modifier += 1 ;
00266 }
00267 
00268 void WeaponProjectile::DecrementTimeOut()
00269 {
00270   // -1s for grenade timout. 1 is min.
00271   if (cfg.allow_change_timeout && GetTotalTimeout()>1)
00272     m_timeout_modifier -= 1 ;
00273 }
00274 
00275 void WeaponProjectile::SetTimeOut(int timeout)
00276 {
00277   if (cfg.allow_change_timeout && timeout <= (int)cfg.timeout*2 && timeout >= 1)
00278     m_timeout_modifier = timeout - cfg.timeout ;
00279 }
00280 
00281 void WeaponProjectile::ResetTimeOut()
00282 {
00283   m_timeout_modifier = 0 ;
00284 }
00285 
00286 int WeaponProjectile::GetTotalTimeout() const
00287 {
00288   return (int)(cfg.timeout)+m_timeout_modifier;
00289 }
00290 
00291 // Signal a projectile timeout and explode
00292 void WeaponProjectile::SignalTimeout()
00293 {
00294   if (launcher != NULL && !launcher->ignore_timeout_signal) launcher->SignalProjectileTimeout();
00295   if (explode_with_timeout) Explosion();
00296 }
00297 
00298 //Public function which let know if changing timeout is allowed.
00299 bool WeaponProjectile::change_timeout_allowed()
00300 {
00301   return cfg.allow_change_timeout;
00302 }
00303 
00304 //-----------------------------------------------------------------------------
00305 
00306 WeaponLauncher::WeaponLauncher(Weapon_type type,
00307                                const std::string &id,
00308                                EmptyWeaponConfig * params,
00309                                weapon_visibility_t visibility) :
00310     Weapon(type, id, params, visibility)
00311 {
00312   projectile = NULL;
00313   nb_active_projectile = 0;
00314   missed_shots = 0;
00315   announce_missed_shots = true;
00316   ignore_timeout_signal = false;
00317   ignore_collision_signal = false;
00318   ignore_explosion_signal = false;
00319   ignore_ghost_state_signal = false;
00320   ignore_drowning_signal = false;
00321 }
00322 
00323 WeaponLauncher::~WeaponLauncher()
00324 {
00325   if (projectile) delete projectile;
00326 }
00327 
00328 bool WeaponLauncher::p_Shoot ()
00329 {
00330 //   if (m_strength == max_strength)
00331 //   {
00332 //     m_strength = 0;
00333 //     DirectExplosion();
00334 //     return true;
00335 //   }
00336   projectile->Shoot (m_strength);
00337   projectile = NULL;
00338   ReloadLauncher();
00339   return true;
00340 }
00341 
00342 bool WeaponLauncher::ReloadLauncher()
00343 {
00344   if (projectile) return false;
00345   projectile = GetProjectileInstance();
00346   return true;
00347 }
00348 
00349 // Direct Explosion when pushing weapon to max power !
00350 void WeaponLauncher::DirectExplosion()
00351 {
00352   Point2i pos = ActiveCharacter().GetCenter();
00353   ApplyExplosion (pos, cfg());
00354 }
00355 
00356 // Signal that a projectile explosion
00357 void WeaponLauncher::SignalProjectileExplosion()
00358 {
00359   DecActiveProjectile();
00360   m_is_active = false;
00361 }
00362 
00363 // Signal that a projectile fired by this weapon has hit something (ground, character etc)
00364 void WeaponLauncher::SignalProjectileCollision()
00365 {
00366   m_is_active = false;
00367 }
00368 
00369 // Signal a ghost state
00370 void WeaponLauncher::SignalProjectileGhostState()
00371 {
00372   m_is_active = false;
00373 }
00374 
00375 // Signal a projectile timeout (for exemple: grenade, disco grenade ... etc.)
00376 void WeaponLauncher::SignalProjectileTimeout()
00377 {
00378   m_is_active = false;
00379 }
00380 
00381 // Signal a projectile is drowning
00382 void WeaponLauncher::SignalProjectileDrowning()
00383 {
00384   m_is_active = false;
00385 }
00386 
00387 // Keep the total amount of active projectile
00388 void WeaponLauncher::IncActiveProjectile()
00389 {
00390   ++nb_active_projectile;
00391 }
00392 
00393 void WeaponLauncher::DecActiveProjectile()
00394 {
00395   --nb_active_projectile;
00396 }
00397 
00398 // Call by the object list class to refresh the weapon's state
00399 void WeaponLauncher::Refresh()
00400 {
00401 }
00402 
00403 void WeaponLauncher::Draw()
00404 {
00405   //Display timeout for projectil if can be changed.
00406   if (projectile->change_timeout_allowed())
00407   {
00408     if( IsActive() ) //Do not display after launching.
00409       return;
00410 
00411     int tmp = projectile->GetTotalTimeout();
00412     std::ostringstream ss;
00413     ss << tmp;
00414     ss << "s";
00415     int txt_x = ActiveCharacter().GetX() + ActiveCharacter().GetWidth() / 2;
00416     int txt_y = ActiveCharacter().GetY() - ActiveCharacter().GetHeight();
00417     (*Font::GetInstance(Font::FONT_SMALL)).WriteCenterTop( Point2i(txt_x, txt_y) - camera.GetPosition(),
00418     ss.str(), white_color);
00419   }
00420 
00421   Weapon::Draw();
00422 
00423 #ifdef DEBUG_EXPLOSION_CONFIG
00424   ExplosiveWeaponConfig* cfg = dynamic_cast<ExplosiveWeaponConfig*>(extra_params);
00425   if( cfg != NULL )
00426   {
00427     Point2i p = ActiveCharacter().GetHandPosition() - camera.GetPosition();
00428     // Red color for the blast range (should be superior to the explosion_range)
00429     AppWormux::GetInstance()->video.window.CircleColor(p.x, p.y, (int)cfg->blast_range, c_red);
00430     // Yellow color for the blast range (should be superior to the explosion_range)
00431     AppWormux::GetInstance()->video.window.CircleColor(p.x, p.y, (int)cfg->explosion_range, c_black);
00432   }
00433   AppWormux::GetInstance()->video.window.CircleColor(GetGunHolePosition().x-camera.GetPositionX(), GetGunHolePosition().y-camera.GetPositionY(), 5, c_black);
00434 #endif
00435 }
00436 
00437 void WeaponLauncher::p_Select()
00438 {
00439   missed_shots = 0;
00440   if (projectile->change_timeout_allowed())
00441   {
00442     force_override_keys = true; //Allow overriding key during movement.
00443     projectile->ResetTimeOut();
00444   }
00445   Weapon::p_Select();
00446 }
00447 
00448 void WeaponLauncher::p_Deselect()
00449 {
00450   if (projectile->change_timeout_allowed())
00451   {
00452     force_override_keys = false;
00453   }
00454 }
00455 
00456 void WeaponLauncher::IncMissedShots()
00457 {
00458   missed_shots++;
00459   if(announce_missed_shots)
00460     GameMessages::GetInstance()->Add (_("Your shot has missed!"));
00461 }
00462 
00463 void WeaponLauncher::HandleKeyEvent(Action::Action_t action, Keyboard::Key_Event_t event_type)
00464 {
00465   if (event_type == Keyboard::KEY_RELEASED)
00466     switch (action) {
00467       case Action::ACTION_WEAPON_1:
00468         projectile->SetTimeOut(1);
00469         break;
00470       case Action::ACTION_WEAPON_2:
00471         projectile->SetTimeOut(2);
00472         break;
00473       case Action::ACTION_WEAPON_3:
00474         projectile->SetTimeOut(3);
00475         break;
00476       case Action::ACTION_WEAPON_4:
00477         projectile->SetTimeOut(4);
00478         break;
00479       case Action::ACTION_WEAPON_5:
00480         projectile->SetTimeOut(5);
00481         break;
00482       case Action::ACTION_WEAPON_6:
00483         projectile->SetTimeOut(6);
00484         break;
00485       case Action::ACTION_WEAPON_7:
00486         projectile->SetTimeOut(7);
00487         break;
00488       case Action::ACTION_WEAPON_8:
00489         projectile->SetTimeOut(8);
00490         break;
00491       case Action::ACTION_WEAPON_9:
00492         projectile->SetTimeOut(9);
00493         break;
00494 
00495       case Action::ACTION_WEAPON_MORE:
00496         projectile->IncrementTimeOut();
00497         break ;
00498 
00499       case Action::ACTION_WEAPON_LESS:
00500         projectile->DecrementTimeOut();
00501         break   ;
00502 
00503       default:
00504         break ;
00505 
00506     };
00507 
00508     if((action >= Action::ACTION_WEAPON_1 && action <= Action::ACTION_WEAPON_9)
00509         || action == Action::ACTION_WEAPON_MORE || action == Action::ACTION_WEAPON_LESS)
00510       ActionHandler::GetInstance()->NewAction(new Action(Action::ACTION_SET_TIMEOUT, projectile->m_timeout_modifier));
00511 
00512     ActiveCharacter().HandleKeyEvent(action, event_type);
00513 }
00514 
00515 // called by mousse.cpp when mousewhellup
00516 void WeaponLauncher::ActionUp()
00517 {
00518   projectile->IncrementTimeOut();
00519 }
00520 
00521 // called by mousse.cpp when mousewhelldown
00522 void WeaponLauncher::ActionDown()
00523 {
00524   projectile->DecrementTimeOut();
00525 }
00526 
00527 ExplosiveWeaponConfig& WeaponLauncher::cfg()
00528 {
00529   return static_cast<ExplosiveWeaponConfig&>(*extra_params);
00530 }

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