/* $Id: weapon.hpp,v 1.16 2005/10/20 19:46:52 chfreund Exp $ */ #ifndef _WEAPON_HPP_ #define _WEAPON_HPP_ #include "constants.hpp" #include "serializable.hpp" #include "serialize.hpp" #include "audio.hpp" #include "counter.hpp" class World; class Avatar; class StationaryGun; /*! This class provides the basic functionality for a vanilla weapon. There are four pure virtual methods which have to be overloaded: - Weapon::reallyShoot These methods do not have to take care of the weapon counters like remaining ammo, reloading, ... This is done in other base classes. To create a new weapon it is best to start from an already existing weapon like WeaponShotgun or WeaponGrenade and alter its behavior. There are two requirements for all new Weapon class contructors: - \a rechargeNow must be called - \a m_shotSample must be initialized as is the following example: \code m_shotSample = Audio::getInstance()->loadSound( "sound/weapons/shotgun/shotgun.wav" ); \endcode */ class Weapon : public Serializable { protected: Weapon(); //! the weapon ID, defined in constants.hpp Sint32 m_ID; //! The maximum amount of ammo. Uint32 m_maximumAmmo; //! The required number of frames for preparing the next shot. real m_reloadTime; //! The required number of frames for recharging a completely empty weapon. Uint32 m_chargeTime; //! The remaining number of frames until the empty weapon is recharged. Uint32 m_chargeTimer; //! The remaining number of frames until the weapon can fire the next shot. Counter m_reloadTimer; //! flags for special states Uint32 m_flags; //! The remaining amount of ammo. Uint32 m_ammo; //! This sample is played after a successful shot. Mix_Chunk* m_shotSample; //! enumeration constants for member m_flags enum { NO_FLAG = 0, RELOAD_LOCKED = 1<<0, RECHARGE_LOCKED = 1<<2, SHOT_LOCKED = 1<<3 }; public: //! \name IDs and nomenclature of weapons //@{ //! returns the weapon's ID Sint32 getID() const { return m_ID; } //! returns the weapon's ID string const char* getIDString() const { DBG(3) ASSERT( INVALID_WEAPON < getID() && getID() < NUMBER_OF_WEAPON_IDs, "Weapon::getIDString: %d is not a valid weapon ID " "from range [0,%d]\n", getID(), NUMBER_OF_WEAPON_IDs-1 ); return getIDString(getID()); } //! static method, that maps a weapon ID (constants.hpp) to its string static const char* getIDString( const Sint32 id ) { ASSERT( INVALID_WEAPON < id && id < NUMBER_OF_WEAPON_IDs, "Weapon::getIDString(%d): %d is not a valid weapon ID in " "range [0,%d]\n", id, id, NUMBER_OF_WEAPON_IDs ); return WeaponIDString[id]; } //@} //! \name special weapon controls //@{ //! returns true, if reloading is locked bool reloadIsLocked() const { return m_flags & RELOAD_LOCKED; } //! locks the reloading of the weapon void lockReload() { m_flags |= RELOAD_LOCKED; } //! unlocks the reloading of the weapon void unlockReload() { m_flags &= ~RELOAD_LOCKED; } //! returns true, if recharging is locked bool rechargeIsLocked() const { return m_flags & RECHARGE_LOCKED; } //! locks the recharging of the weapon void lockRecharge() { m_flags |= RECHARGE_LOCKED; } //! unlocks the recharging of the weapon void unlockRecharge() { m_flags &= ~RECHARGE_LOCKED; } //! returns true, if shooting is locked bool shotIsLocked() const { return m_flags & SHOT_LOCKED; } //! locks shooting the weapon void lockShot() { m_flags |= SHOT_LOCKED; } //! unlocks shooting the weapon void unlockShot() { m_flags &= ~SHOT_LOCKED; } //@} Uint32 getMaximumAmmo( void ) const { return m_maximumAmmo; } real getReloadTime ( void ) const { return m_reloadTime; } Uint32 getChargeTime ( void ) const { return m_chargeTime; } void setMaximumAmmo( const Uint32 maximumAmmo ) { m_maximumAmmo = maximumAmmo; rechargeNow(); } void setReloadTime ( const real reloadTime ) { m_reloadTime = reloadTime; rechargeNow(); } void setChargeTime ( const Uint32 chargeTime ) { m_chargeTime = chargeTime; rechargeNow(); } //! This method should check whether a shot is possible. If shooting is //! possible, place particles and/or other weapon objects. //! \note Checking or decreasing the ammo, charge or reload counters is //! not necessary. //! \return Return \c true if the weapon could be fired successfully. //! Otherwise \c false. virtual bool reallyShoot( World* world, Avatar* avatar, const StationaryGun* gun = NULL ) const = 0; //! All basic things for handling the weapon counters are handled here. //! If shooting is possible according to these counters, Weapon::reallyShoot //! will be called and the shot sample will be played. virtual void shoot( World* world, Avatar* avatar, const StationaryGun* gun = NULL ); //! Takes care of the weapon counters. virtual void doTimestep( const real dt ) { if ( !rechargeIsLocked() && m_chargeTimer > 0 && --m_chargeTimer == 0 ) { m_ammo = m_maximumAmmo; } if ( !reloadIsLocked() && !m_reloadTimer.isElapsed() ) { m_reloadTimer.countDown( dt ); } } /*! \brief \return \c true if weapon is recharging; \c false * otherwise. \b Note that recharging can be locked nevertheless. */ virtual bool isCharging() const { return m_chargeTimer > 0; } /*! \brief \return \c true if weapon is reloading; \c false * otherwise. \b Note that reloading can be locked nevertheless */ virtual bool isReloading() const { return !m_reloadTimer.isElapsed(); } //! \return The current amount of ammo. virtual Uint32 getCurrentAmmo() const { return m_ammo; } //! \return The current charging state between 0 (not charged) and 100 //! (completely charged). virtual Uint32 getChargingPercentage() const {; return 100 - ( 100 * m_chargeTimer ) / m_chargeTime; } /*! \brief Sets all weapon counters to a completely charged weapon, * even \b circumventing a locked recharging. Recharging is * unlocked after this call. */ virtual void rechargeNow() { m_ammo = m_maximumAmmo; m_reloadTimer = m_chargeTimer = 0; unlockRecharge(); } virtual Uint32 getSerializeBufferSize() const { return 5 * Serialize::sizeOf() + Serialize::sizeOf() + m_reloadTimer.getSerializeBufferSize(); } //! static factory method for weapons static Weapon* newWeapon( const Sint32 ID ); virtual void serialize( Uint8*& bufferPointer ) const { Serialize::serialize( m_ammo , bufferPointer ); m_reloadTimer.serialize( bufferPointer ); Serialize::serialize( m_chargeTimer, bufferPointer ); Serialize::serialize( m_maximumAmmo, bufferPointer ); Serialize::serialize( m_reloadTime , bufferPointer ); Serialize::serialize( m_flags , bufferPointer ); Serialize::serialize( m_chargeTime , bufferPointer ); } virtual void deserialize( Uint8*& bufferPointer ) { Serialize::deserialize( bufferPointer, m_ammo ); m_reloadTimer.deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_chargeTimer ); Serialize::deserialize( bufferPointer, m_maximumAmmo ); Serialize::deserialize( bufferPointer, m_reloadTime ); Serialize::deserialize( bufferPointer, m_flags ); Serialize::deserialize( bufferPointer, m_chargeTime ); } }; #endif // _WEAPON_HPP_