1 /* $Id: weapon.hpp,v 1.16 2005/10/20 19:46:52 chfreund Exp $ */
2 
3 #ifndef _WEAPON_HPP_
4 #define _WEAPON_HPP_
5 
6 #include "constants.hpp"
7 #include "serializable.hpp"
8 #include "serialize.hpp"
9 #include "audio.hpp"
10 #include "counter.hpp"
11 
12 class World;
13 class Avatar;
14 class StationaryGun;
15 
16 /*!
17 This class provides the basic functionality for a vanilla weapon. There are
18 four pure virtual methods which have to be overloaded:
19 - Weapon::reallyShoot
20 
21 These methods do not have to take care of the weapon counters like remaining
22 ammo, reloading, ... This is done in other base classes.
23 
24 To create a new weapon it is best to start from an already existing weapon
25 like WeaponShotgun or WeaponGrenade and alter its behavior. There are two
26 requirements for all new Weapon class contructors:
27 
28 - \a rechargeNow must be called
29 - \a m_shotSample must be initialized as is the following example:
30   \code
31 	m_shotSample = Audio::getInstance()->loadSound( "sound/weapons/shotgun/shotgun.wav" );
32 	\endcode
33 */
34 
35 class Weapon : public Serializable {
36 	protected:
37 		Weapon();
38 
39 		//! the weapon ID, defined in constants.hpp
40 		Sint32 m_ID;
41 		//! The maximum amount of ammo.
42 		Uint32 m_maximumAmmo;
43 		//! The required number of frames for preparing the next shot.
44 		real m_reloadTime;
45 		//! The required number of frames for recharging a completely empty weapon.
46 		Uint32 m_chargeTime;
47 
48 		//! The remaining number of frames until the empty weapon is recharged.
49 		Uint32 m_chargeTimer;
50 		//! The remaining number of frames until the weapon can fire the next shot.
51 		Counter m_reloadTimer;
52 		//! flags for special states
53 		Uint32 m_flags;
54 		//! The remaining amount of ammo.
55 		Uint32 m_ammo;
56 		//! This sample is played after a successful shot.
57 		Mix_Chunk* m_shotSample;
58 
59 		//! enumeration constants for member m_flags
60 		enum { NO_FLAG         = 0,
61 		       RELOAD_LOCKED   = 1<<0,
62 		       RECHARGE_LOCKED = 1<<2,
63 		       SHOT_LOCKED     = 1<<3 };
64 
65 	public:
66 
67 		//! \name IDs and nomenclature of weapons
68 		//@{
69 		//! returns the weapon's ID
getID() const70 		Sint32 getID() const { return m_ID; }
71 		//! returns the weapon's ID string
getIDString() const72 		const char* getIDString() const {
73 			DBG(3) ASSERT( INVALID_WEAPON < getID() && getID() < NUMBER_OF_WEAPON_IDs,
74 			               "Weapon::getIDString: %d is not a valid weapon ID "
75 			               "from range [0,%d]\n", getID(), NUMBER_OF_WEAPON_IDs-1 );
76 			return getIDString(getID()); }
77 		//! static method, that maps a weapon ID (constants.hpp) to its string
getIDString(const Sint32 id)78 		static const char* getIDString( const Sint32 id ) {
79 			ASSERT( INVALID_WEAPON < id && id < NUMBER_OF_WEAPON_IDs,
80 			        "Weapon::getIDString(%d): %d is not a valid weapon ID in "
81 			        "range [0,%d]\n", id, id, NUMBER_OF_WEAPON_IDs );
82 			return WeaponIDString[id];
83 		}
84 		//@}
85 
86 		//! \name special weapon controls
87 		//@{
88 		//! returns true, if reloading is locked
reloadIsLocked() const89 		bool reloadIsLocked() const { return m_flags & RELOAD_LOCKED; }
90 		//! locks the reloading of the weapon
lockReload()91 		void lockReload() { m_flags |= RELOAD_LOCKED; }
92 		//! unlocks the reloading of the weapon
unlockReload()93 		void unlockReload() { m_flags &= ~RELOAD_LOCKED; }
94 		//! returns true, if recharging is locked
rechargeIsLocked() const95 		bool rechargeIsLocked() const { return m_flags & RECHARGE_LOCKED; }
96 		//! locks the recharging of the weapon
lockRecharge()97 		void lockRecharge() { m_flags |= RECHARGE_LOCKED; }
98 		//! unlocks the recharging of the weapon
unlockRecharge()99 		void unlockRecharge() { m_flags &= ~RECHARGE_LOCKED; }
100 		//! returns true, if shooting is locked
shotIsLocked() const101 		bool shotIsLocked() const { return m_flags & SHOT_LOCKED; }
102 		//! locks shooting the weapon
lockShot()103 		void lockShot() { m_flags |= SHOT_LOCKED; }
104 		//! unlocks shooting the weapon
unlockShot()105 		void unlockShot() { m_flags &= ~SHOT_LOCKED; }
106 		//@}
107 
getMaximumAmmo(void) const108 		Uint32 getMaximumAmmo( void ) const { return m_maximumAmmo; }
getReloadTime(void) const109 		real getReloadTime ( void ) const { return m_reloadTime;  }
getChargeTime(void) const110 		Uint32 getChargeTime ( void ) const { return m_chargeTime;  }
111 
setMaximumAmmo(const Uint32 maximumAmmo)112 		void setMaximumAmmo( const Uint32 maximumAmmo ) { m_maximumAmmo = maximumAmmo; rechargeNow(); }
setReloadTime(const real reloadTime)113 		void setReloadTime ( const real reloadTime  ) { m_reloadTime  = reloadTime;  rechargeNow(); }
setChargeTime(const Uint32 chargeTime)114 		void setChargeTime ( const Uint32 chargeTime  ) { m_chargeTime  = chargeTime;  rechargeNow(); }
115 
116 		//! This method should check whether a shot is possible. If shooting is
117 		//! possible, place particles and/or other weapon objects.
118 		//! \note Checking or decreasing the ammo, charge or reload counters is
119 		//! not necessary.
120 		//! \return Return \c true if the weapon could be fired successfully.
121 		//! Otherwise \c false.
122 		virtual bool reallyShoot( World* world, Avatar* avatar,
123 		                          const StationaryGun* gun = NULL ) const = 0;
124 
125 		//! All basic things for handling the weapon counters are handled here.
126 		//! If shooting is possible according to these counters, Weapon::reallyShoot
127 		//! will be called and the shot sample will be played.
128 		virtual void shoot( World* world, Avatar* avatar,
129 		                    const StationaryGun* gun = NULL );
130 
131 		//! Takes care of the weapon counters.
doTimestep(const real dt)132 		virtual void doTimestep( const real dt ) {
133 			if ( !rechargeIsLocked() && m_chargeTimer > 0 && --m_chargeTimer == 0 ) {
134 				m_ammo = m_maximumAmmo;
135 			}
136 
137 			if ( !reloadIsLocked() && !m_reloadTimer.isElapsed() ) {
138 				m_reloadTimer.countDown( dt );
139 			}
140 		}
141 
142 		/*! \brief \return \c true if weapon is recharging; \c false
143 		 *  otherwise. \b Note that recharging can be locked nevertheless.
144 		 */
isCharging() const145 		virtual bool isCharging() const { return m_chargeTimer > 0; }
146 
147 		/*! \brief \return \c true if weapon is reloading; \c false
148 		 *  otherwise. \b Note that reloading can be locked nevertheless
149 		 */
isReloading() const150 		virtual bool isReloading() const { return !m_reloadTimer.isElapsed(); }
151 
152 		//! \return The current amount of ammo.
getCurrentAmmo() const153 		virtual Uint32 getCurrentAmmo() const { return m_ammo; }
154 
155 		//! \return The current charging state between 0 (not charged) and 100
156 		//! (completely charged).
getChargingPercentage() const157 		virtual Uint32 getChargingPercentage() const {;
158 			return 100 - ( 100 * m_chargeTimer ) / m_chargeTime;
159 		}
160 
161 		/*! \brief Sets all weapon counters to a completely charged weapon,
162 		 *  even \b circumventing a locked recharging. Recharging is
163 		 *  unlocked after this call.
164 		 */
rechargeNow()165 		virtual void rechargeNow() {
166 			m_ammo = m_maximumAmmo;
167 			m_reloadTimer = m_chargeTimer = 0;
168 			unlockRecharge();
169 		}
170 
getSerializeBufferSize() const171 		virtual Uint32 getSerializeBufferSize() const {
172 			return 5 * Serialize<Uint32>::sizeOf()
173 			       + Serialize<real>::sizeOf()
174 			       + m_reloadTimer.getSerializeBufferSize();
175 		}
176 
177 		//! static factory method for weapons
178 		static Weapon* newWeapon( const Sint32 ID );
179 
serialize(Uint8 * & bufferPointer) const180 		virtual void serialize( Uint8*& bufferPointer ) const {
181 			Serialize<Uint32>::serialize( m_ammo       , bufferPointer );
182 			m_reloadTimer.serialize( bufferPointer );
183 			Serialize<Uint32>::serialize( m_chargeTimer, bufferPointer );
184 			Serialize<Uint32>::serialize( m_maximumAmmo, bufferPointer );
185 			Serialize<real>::serialize( m_reloadTime , bufferPointer );
186 			Serialize<Uint32>::serialize( m_flags      , bufferPointer );
187 			Serialize<Uint32>::serialize( m_chargeTime , bufferPointer );
188 		}
189 
deserialize(Uint8 * & bufferPointer)190 		virtual void deserialize( Uint8*& bufferPointer ) {
191 			Serialize<Uint32>::deserialize( bufferPointer, m_ammo        );
192 			m_reloadTimer.deserialize( bufferPointer );
193 			Serialize<Uint32>::deserialize( bufferPointer, m_chargeTimer );
194 			Serialize<Uint32>::deserialize( bufferPointer, m_maximumAmmo );
195 			Serialize<real>::deserialize( bufferPointer, m_reloadTime  );
196 			Serialize<Uint32>::deserialize( bufferPointer, m_flags       );
197 			Serialize<Uint32>::deserialize( bufferPointer, m_chargeTime  );
198 		}
199 
200 };
201 
202 #endif // _WEAPON_HPP_
203