src/weapon/snipe_rifle.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  * Snipe Rifle. Overide the Draw method in order to draw the laser beam.
00020  *****************************************************************************/
00021 
00022 #include "snipe_rifle.h"
00023 #include <sstream>
00024 #include "explosion.h"
00025 #include "../game/time.h"
00026 #include "../interface/game_msg.h"
00027 #include "../map/map.h"
00028 #include "../map/camera.h"
00029 #include "../object/objects_list.h"
00030 #include "../team/teams_list.h"
00031 #include "../tool/i18n.h"
00032 #include "../include/app.h"
00033 #include "../game/game_loop.h"
00034 
00035 
00036 const uint SNIPE_RIFLE_BEAM_START = 5;
00037 const uint SNIPE_RIFLE_BULLET_SPEED = 20;
00038 const uint SNIPE_RIFLE_MAX_BEAM_SIZE = 500;
00039 
00040 SnipeBullet::SnipeBullet(ExplosiveWeaponConfig& cfg,
00041                      WeaponLauncher * p_launcher) :
00042     WeaponBullet("snipe_rifle_bullet", cfg, p_launcher)
00043 { 
00044 }
00045 
00046 void SnipeBullet::ShootSound()
00047 {
00048   jukebox.Play("share","weapon/gun");
00049 }
00050 
00051 //-----------------------------------------------------------------------------
00052 
00053 SnipeRifle::SnipeRifle() : WeaponLauncher(WEAPON_SNIPE_RIFLE,"snipe_rifle", new ExplosiveWeaponConfig())
00054 {
00055   m_name = _("Sniper Rifle");
00056 
00057   last_angle = 0.0;
00058   targeting_something = false;
00059   m_laser_image = new Sprite(resource_manager.LoadImage(weapons_res_profile,m_id+"_laser"));
00060   m_weapon_fire = new Sprite(resource_manager.LoadImage(weapons_res_profile,m_id+"_fire"));
00061   m_weapon_fire->EnableRotationCache(32);
00062   laser_beam_color = resource_manager.LoadColor(weapons_res_profile,m_id+"_laser_color");
00063 
00064   ReloadLauncher();
00065 }
00066 
00067 WeaponProjectile * SnipeRifle::GetProjectileInstance()
00068 {
00069   return dynamic_cast<WeaponProjectile *>
00070       (new SnipeBullet(cfg(),dynamic_cast<WeaponLauncher *>(this)));
00071 }
00072 
00073 bool SnipeRifle::p_Shoot()
00074 {
00075   if(m_is_active)
00076     return false;
00077 
00078   m_is_active = true;
00079   projectile->Shoot (SNIPE_RIFLE_BULLET_SPEED);
00080   projectile = NULL;
00081   ReloadLauncher();
00082   return true;
00083 }
00084 
00085 // When an explosion occurs, we compute a new targeted point
00086 void SnipeRifle::SignalProjectileGhostState()
00087 {
00088   m_is_active = false;
00089   ReloadLauncher();
00090   ComputeCrossPoint(true);
00091 }
00092 
00093 bool SnipeRifle::ComputeCrossPoint(bool force = false)
00094 {
00095   // Did the current character is moving ?
00096   Point2i pos = GetGunHolePosition();
00097   double angle = ActiveCharacter().GetFiringAngle();
00098   if ( !force && last_rifle_pos == pos && last_angle == angle ) return targeting_something;
00099   else {
00100     last_rifle_pos=pos;
00101     last_angle=angle;
00102   }
00103 
00104   // Equation of movement : y = ax + b
00105   double a, b;
00106   a = sin(angle) / cos(angle);
00107   b = pos.y - ( a * pos.x );
00108   Point2i delta_pos, size, start_point;
00109   start_point = pos;
00110   uint distance = 0;
00111   targeting_something = false;
00112   // While test is not finished
00113   while( distance < SNIPE_RIFLE_MAX_BEAM_SIZE ){
00114     // going upwards ( -3pi/4 < angle <-pi/4 )
00115     if (angle < -0.78 && angle > -2.36){
00116       pos.x = (int)((pos.y-b)/a);       //Calculate x
00117       delta_pos.y = -1;                   //Increment y
00118     // going downwards ( 3pi/4 > angle > pi/4 )
00119     } else if (angle > 0.78 && angle < 2.36){
00120       pos.x = (int)((pos.y-b)/a);       //Calculate x
00121       delta_pos.y = 1;                    //Increment y
00122     // else going at right or left
00123     } else {
00124       pos.y = (int)((a*pos.x) + b);   //Calculate y
00125       delta_pos.x = ActiveCharacter().GetDirection();   //Increment x
00126     }
00127     // start point of the laser beam
00128     if ( distance < SNIPE_RIFLE_BEAM_START ) laser_beam_start = pos;
00129 
00130     // the point is outside the map
00131     if ( world.EstHorsMondeX(pos.x) || world.EstHorsMondeY(pos.y) ) break;
00132 
00133     // is there a collision ??
00134     if ( distance > 30 && !projectile->IsInVacuumXY( pos )){
00135       targeting_something = true;
00136       break;
00137     }
00138     pos += delta_pos;
00139     distance = (int) start_point.Distance(pos);
00140   }
00141   targeted_point=pos;
00142   return targeting_something;
00143 }
00144 
00145 // Reset crosshair when switching from a weapon to another to avoid misused
00146 void SnipeRifle::p_Deselect()
00147 {
00148   ActiveCharacter().SetFiringAngle(0.);
00149 }
00150 
00151 void SnipeRifle::DrawBeam()
00152 {
00153   Point2i pos1 = laser_beam_start - camera.GetPosition();
00154   Point2i pos2 = targeted_point - camera.GetPosition();
00155   AppWormux::GetInstance()->video.window.AALineColor(pos1.x, pos2.x, pos1.y, pos2.y, laser_beam_color);
00156 
00157   // Set area of the screen to be redrawn:
00158   // Splited into little rectangles to avoid too large area of redraw
00159   float redraw_size = 20.0;
00160   float dst = laser_beam_start.Distance(targeted_point);
00161   Point2f pos = Point2f((float)laser_beam_start.x, (float)laser_beam_start.y);
00162   Point2f delta = ( Point2f((float)targeted_point.x, (float)targeted_point.y) - pos ) * redraw_size / dst;
00163   Point2i delta_i((int)delta.x, (int)delta.y);
00164 
00165   if(delta_i.x < 0) delta_i.x = - delta_i.x; // the Map::ToRedraw method doesn't support negative rectangles
00166   if(delta_i.y < 0) delta_i.y = - delta_i.y;
00167   delta_i.x += 6; // We have to increase the size of the rectangle so the corner of the rectangles overlaps
00168   delta_i.y += 6;
00169 
00170   int i = 0;
00171   while( (float)i * redraw_size < dst )
00172   {
00173     // float to int conversion...
00174     Point2i pos_i((int)pos.x, (int)pos.y);
00175     if(delta.x < 0.0)
00176     {
00177       pos_i.x -= delta_i.x;
00178       pos_i.x += 3;
00179     }
00180     else
00181       pos_i.x -= 3;
00182 
00183     if(delta.y < 0.0)
00184     {
00185       pos_i.y -= delta_i.y;
00186       pos_i.y += 3;
00187     }
00188     else
00189       pos_i.y -= 3;
00190 
00191     world.ToRedrawOnMap(Rectanglei( pos_i, delta_i ));
00192     pos += delta;
00193     i++;
00194   }
00195 }
00196 
00197 void SnipeRifle::Draw()
00198 {
00199   WeaponLauncher::Draw();
00200   if( GameLoop::GetInstance()->ReadState() != GameLoop::PLAYING || IsActive() ) return;
00201   ComputeCrossPoint();
00202   DrawBeam();
00203   // Draw the laser impact
00204   if( targeting_something ) m_laser_image->Draw(targeted_point - (m_laser_image->GetSize()/2));
00205 }

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