/* $Id: mine.cpp,v 1.23.4.1 2006/01/20 11:33:52 chfreund Exp $ */ #include "mine.hpp" #include "world.hpp" #include "particles.hpp" #include "random.hpp" /**********************************************************/ Mix_Chunk* Mine::m_explodeSample, * Mine::m_bounceSample, * Mine::m_triggerSample, * Mine::m_damageSample; /**********************************************************/ Mine::Mine() { m_health = 150000; m_mass = 40.0; m_collRectX = -2; m_collRectY = -1; m_collRectWidth = 5; m_collRectHeight = 2; } /**********************************************************/ bool Mine::initialize( const Vector& pos, const Vector& vel, const Uint8 owner, const real deadTime, 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 MINE DATA MEMBERS AFTER THIS POINT return false; } m_pos = pos; m_vel = vel; m_owner = owner; m_deadTime.setTimeToLive( deadTime ); m_triggered = false; m_nShrapnels = nShrapnels; m_damage = damage; // set mine stencil setCollRect(); return true; } /**********************************************************/ void Mine::update() { preBallistics(); const real DT = m_worldPointer->getDT( m_pos ); // if dead time is over look for nearby enemies if( m_deadTime.isElapsed() && !m_triggered ) { std::vector& collidable = *(m_worldPointer->getCollidables()); for( unsigned int i = 0; i < collidable.size(); i++ ) { if( collidable[i]->isAvatar() && collidable[i]->isWeaponVisible() && (collidable[i]->getPos() - m_pos).abs2() < 1500 ) { m_triggered = true; m_jumpTimer.setTimeToLive( 13.0 ); m_force.y -= 3.5 * m_mass / DT; setState( GROUNDED, false ); Audio::getInstance()->playSound( m_triggerSample, m_pos ); break; } } } else m_deadTime.countDown( DT ); // explode? if( m_health <= 0 || ( m_triggered && m_jumpTimer.countDown( DT ) ) ) { explode(); } else { doBallistics(); postBallistics(); } } /**********************************************************/ bool Mine::collidedWithObstacle( const Sint32 colX, const Sint32 colY ) { Audio::getInstance()->playSound( m_bounceSample, m_pos ); CollidableObject::collidedWithObstacle( colX, colY ); return true; } /**********************************************************/ void Mine::explode() { Audio::getInstance()->playSound( m_explodeSample, m_pos ); m_worldPointer->newObject( EXPLOSION_60 )->setPos( m_pos ); for( int s = 0; s < m_nShrapnels; s++ ) { m_worldPointer->getParticles()->addParticle( Particles::ParticleData( m_pos, m_worldPointer->getRandom().getVector( 25 + 5*m_worldPointer->getRandom().getNormedReal() ) /* + getSpeed() avoids "shooting" of mines */, Particles::EXPL_EARTH | Particles::EXPL_OBJECT | Particles::DAMAGE | Particles::EXPL_GEN_SPARKS, 0, m_owner, 5, m_damage, 0x009900 )); } m_removeMeAfterUpdate = true; } /**********************************************************/ int Mine::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 Mine::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 ); m_deadTime.serialize( bufferPointer ); m_jumpTimer.serialize( bufferPointer ); Serialize::serialize( m_triggered, 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, Mine ); } /**********************************************************/ void Mine::deserialize( Uint8*& bufferPointer ) { CollidableObject::deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_owner ); m_deadTime.deserialize( bufferPointer ); m_jumpTimer.deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_triggered ); Serialize::deserialize( bufferPointer, m_nShrapnels ); Serialize::deserialize( bufferPointer, m_damage ); // expands to tag deserialization DESERIALIZE_OBJECT_TAG( bufferPointer ); } /**********************************************************/ Uint32 Mine::getSerializeBufferSize() const { return CollidableObject::getSerializeBufferSize() + Serialize::sizeOf( m_owner ) + m_deadTime.getSerializeBufferSize() + m_jumpTimer.getSerializeBufferSize() + Serialize::sizeOf() + 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 Mine::dump( std::ostream& out ) const { using namespace std; out << "### Mine object ###" << endl; CollidableObject::dump( out ); out << "Mine components:" << endl; out << "\tDead time: " << m_deadTime.getTimeToLive() << endl; out << "\tJump time: " << m_jumpTimer.getTimeToLive() << endl; }