/* $Id: grenade.cpp,v 1.39.4.1 2006/01/20 11:33:52 chfreund Exp $ */ #include "grenade.hpp" #include "world.hpp" #include "particles.hpp" #include "random.hpp" #include "map.hpp" /**********************************************************/ Mix_Chunk* Grenade::m_explodeSample, * Grenade::m_bounceSample, * Grenade::m_damageSample; /**********************************************************/ Grenade::Grenade() { m_health = 180000; m_mass = 50.0; m_collRectX = -2; m_collRectY = -2; m_collRectWidth = 6; m_collRectHeight = 6; } /**********************************************************/ bool Grenade::initialize( const Vector& pos, const Vector& vel, const Uint8 owner, const Uint32 type, const real ttl, const Sint32 nShrapnels, const Sint32 damage ) { if( ! m_worldPointer->getMap()->testFilledCollRect( ROUND( pos.x ) + m_collRectX, ROUND( pos.y ) + m_collRectY, m_collRectWidth, m_collRectHeight ) ) { m_worldPointer->deleteObject( this ); // ok // DO NOT TOUCH ANY GRENADE DATA MEMBERS AFTER THIS POINT return false; } m_pos = pos; m_vel = vel; m_owner = owner; m_type = type; m_ttl.setTimeToLive( ttl ); m_nShrapnels = nShrapnels; m_damage = damage; // set grenade stencil setCollRect(); return true; } /**********************************************************/ void Grenade::update() { preBallistics(); m_ttl.countDown( m_worldPointer->getDT( m_pos ) ); if( m_health <= 0 || ((m_type & TIME_TRIGGERED) && m_ttl.isElapsed() ) ) { explode(); } else { doBallistics(); postBallistics(); } } /**********************************************************/ bool Grenade::collidedWithObstacle( const Sint32 colX, const Sint32 colY ) { if( m_firstUpdate || ! (m_type & CONTACT_TRIGGERED) ) { Audio::getInstance()->playSound( m_bounceSample, m_pos ); CollidableObject::collidedWithObstacle( colX, colY ); return true; } else { explode(); return false; } } /**********************************************************/ void Grenade::explode() { Audio::getInstance()->playSound( m_explodeSample, m_pos ); m_worldPointer->newObject( EXPLOSION_60 )->setPos( m_pos ); if( m_type & SHRAPNELS ) { for( int s = 0; s < m_nShrapnels; s++ ) { real length = 5 * m_worldPointer->getRandom().getNormedReal(); length += 25; m_worldPointer->getParticles()->addParticle( Particles::ParticleData( m_pos, m_vel + m_worldPointer->getRandom().getVector( length ), Particles::EXPL_EARTH | Particles::EXPL_OBJECT | Particles::DAMAGE | Particles::EXPL_GEN_SPARKS, 0, m_owner, 5, m_damage, 0x009900 )); } } if( m_type & DIRT ) { m_worldPointer->getMap()->makeStone( ROUND( m_pos.x ), ROUND( m_pos.y ), m_worldPointer->getRandom().getUint32Between( 15, 23 ), Flags::OBSTACLE_EARTH, Flags::OBSTACLE_ANY ); } m_removeMeAfterUpdate = true; } /**********************************************************/ int Grenade::applyDamage( const Particles::ParticleData& p ) { const int damage = CollidableObject::applyDamage( p ); // create sparks for( int i = 0; i < 2; i++ ) { m_worldPointer->getParticles()->addParticle( Particles::ParticleData( p.pos, m_vel + m_worldPointer->getRandom().getVector( 1 + 7*m_worldPointer->getRandom().getNormedReal() ), Particles::BOUNCE_EARTH | Particles::BOUNCE_OBJECT | Particles::REDUNDANT | Particles::SPARK, 0, 0, Particles::m_N_SPARK_COLORS/2 + (m_worldPointer->getRandom().getUint32() % (Particles::m_N_SPARK_COLORS/2+1)), 0, 0xffffff)); } if( damage > 50 && m_damageSampleTimeout == 0 ) { Audio::getInstance()->playSound( m_damageSample, m_pos ); m_damageSampleTimeout = 10; } return damage; } /**********************************************************/ void Grenade::serialize( Uint8*& bufferPointer ) const { // expands to a check of the buffer movement START_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer ); CollidableObject::serialize( bufferPointer ); Serialize::serialize( m_owner, bufferPointer ); Serialize::serialize( m_type, bufferPointer ); m_ttl.serialize( bufferPointer ); Serialize::serialize( m_nShrapnels, bufferPointer ); Serialize::serialize( m_damage, bufferPointer ); // expands to tag serialization SERIALIZE_OBJECT_TAG( bufferPointer ); // expands to a check of the buffer movement END_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer, Grenade ); } /**********************************************************/ void Grenade::deserialize( Uint8*& bufferPointer ) { CollidableObject::deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_owner ); Serialize::deserialize( bufferPointer, m_type ); m_ttl.deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_nShrapnels ); Serialize::deserialize( bufferPointer, m_damage ); // expands to tag deserialization DESERIALIZE_OBJECT_TAG( bufferPointer ); } /**********************************************************/ Uint32 Grenade::getSerializeBufferSize() const { return CollidableObject::getSerializeBufferSize() + Serialize::sizeOf( m_owner ) + Serialize::sizeOf( m_type ) + m_ttl.getSerializeBufferSize() + Serialize::sizeOf( m_nShrapnels ) + Serialize::sizeOf( m_damage ) // adds additional size for debugging (see serialize.hpp), // but only, if the tags are used PLUS_TAG_SIZE( 1 ); } /**********************************************************/ void Grenade::dump( std::ostream& out ) const { using namespace std; out << "### Grenade object ###" << endl; CollidableObject::dump( out ); out << "Grenade components:" << endl; out << "\tTTL: " << m_ttl.getTimeToLive() << endl; }