/* $Id: ball.cpp,v 1.24.4.2 2006/01/20 11:33:52 chfreund Exp $ */ #include "ball.hpp" #include "world.hpp" #include "particles.hpp" #include "goal.hpp" #include "rope.hpp" #include "random.hpp" #include "color.hpp" /**********************************************************/ Mix_Chunk* Ball::m_explodeSample, * Ball::m_bounceSample, * Ball::m_damageSample; /**********************************************************/ Ball::Ball() { m_health = 1; m_mass = 50.0; m_collRectX = -3; m_collRectY = -3; m_collRectWidth = 7; m_collRectHeight = 7; m_explodeSample = m_bounceSample = m_damageSample = NULL; } /**********************************************************/ Ball::~Ball() { } /**********************************************************/ bool Ball::initialize( const Vector& pos, const Vector& vel, const real initialScoringDelay ) { 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 BALL DATA MEMBERS AFTER THIS POINT return false; } m_pos = pos; m_vel = vel; m_initialScoringDelay = initialScoringDelay; m_scoringDelay.setTimeToLive( initialScoringDelay ); // set ball stencil setCollRect(); return true; } /**********************************************************/ void Ball::update() { preBallistics(); // check for goals bool insideGoal = false; int ballOwner = -1; for( int a = 0; a < getNAttachedObjects(); a++ ) { if( ! insideGoal && getAttachedObject( a )->isGoal() && dynamic_cast( getAttachedObject( a ))->testInside( m_pos )) { insideGoal = true; } if( getAttachedObject( a )->getID() == ROPE ) { const int ropeOwner = dynamic_cast( getAttachedObject( a ))->getOwner(); if( ballOwner == -1 ) ballOwner = ropeOwner; else if( ballOwner != ropeOwner ) { ballOwner = -2; break; } } } if( insideGoal && ballOwner >= 0 ) { const real DT = m_worldPointer->getDT( getPos() ); // generate 'rainbow clock' particles Vector particleSpeed; int numParticles = static_cast( 10 * DT ); for( int p = 0; p < numParticles; p++ ) { real angle = m_scoringDelay.getTimeToLive(); angle *= 2.0 * M_PI; angle /= m_initialScoringDelay; particleSpeed.setAngle( angle, 5.0 ); particleSpeed += m_worldPointer->getRandom().getVector( 2.0 * m_worldPointer->getRandom().getNormedReal() ); m_worldPointer->getParticles()->addParticle( Particles::ParticleData( m_pos, particleSpeed, Particles::BOUNCE_EARTH | Particles::STAIN | Particles::REDUNDANT, 0, 0, 75, 1, Color::HSVToUint32( static_cast( m_scoringDelay.getTimeToLive() ) / m_initialScoringDelay, 1.0, 1.0 ))); } // has the ball been inside the goal long enough? m_scoringDelay.countDown( DT ); if( m_scoringDelay.isElapsed() ) { for( int p = 0; p < 1000; p++ ) { particleSpeed.setAngle( p / 500.0 * M_PI, 5.0 ); particleSpeed += m_worldPointer->getRandom().getVector( 2.0 * m_worldPointer->getRandom().getNormedReal() ); m_worldPointer->getParticles()->addParticle( Particles::ParticleData( m_pos, particleSpeed, Particles::BOUNCE_EARTH | Particles::STAIN | Particles::REDUNDANT, 0, 0, 75, 1, Color::HSVToUint32( p / 1000.0, 1.0, 1.0 ))); } LOG( 1 ) INFO( "Ball::update: player/team %i just scored a goal A\n", ballOwner ); m_worldPointer->getScorekeeper()->playerScoredGoal( this, ballOwner ); LOG( 1 ) INFO( "Ball::update: player/team %i just scored a goal B\n", ballOwner ); //m_removeMeAfterUpdate = true; // keep ball, Tom } } else m_scoringDelay.setTimeToLive( m_initialScoringDelay ); doBallistics(); postBallistics(); } /**********************************************************/ int Ball::applyDamage( const Particles::ParticleData& p ) { const int damage = CollidableObject::applyDamage( p ); if( damage > 50 && m_damageSampleTimeout == 0 ) { Audio::getInstance()->playSound( m_damageSample, m_pos ); m_damageSampleTimeout = 10; } m_health = 1; // indestructible object return damage; } /**********************************************************/ void Ball::serialize( Uint8*& bufferPointer ) const { // expands to a check of the buffer movement START_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer ); CollidableObject::serialize( bufferPointer ); Serialize::serialize( m_initialScoringDelay, bufferPointer ); m_scoringDelay.serialize( bufferPointer ); // expands to tag serialization SERIALIZE_OBJECT_TAG( bufferPointer ); // expands to a check of the buffer movement END_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer, Ball ); } /**********************************************************/ void Ball::deserialize( Uint8*& bufferPointer ) { CollidableObject::deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_initialScoringDelay ); m_scoringDelay.deserialize( bufferPointer ); // expands to tag deserialization INFO( "testing ball object tag\n" ); DESERIALIZE_OBJECT_TAG( bufferPointer ); } /**********************************************************/ /* most likely redundant */ Uint32 Ball::getSerializeBufferSize() const { return CollidableObject::getSerializeBufferSize() + Serialize::sizeOf() + m_scoringDelay.getSerializeBufferSize() PLUS_TAG_SIZE( 1 ); } void Ball::dump( std::ostream& out ) const { using namespace std; out << "### Ball object ###" << endl; CollidableObject::dump( out ); out << "Ball components:" << endl; out << "\tScoring delay: " << m_scoringDelay.getTimeToLive() << endl; }