/* $Id$ */ #include "bonus.hpp" #include "avatar.hpp" #include "world.hpp" /**********************************************************/ #define ADHESION_MAX_SPEED 5.0 // the default life time of boni in seconds #define DEFAULT_LIFE_TIME 120 /**********************************************************/ Bonus::Bonus() : m_registered( false ), m_updatesPerFrame( 2 ), m_numUpdates( m_updatesPerFrame ), m_timeToLive( (Sint32)(25 * DEFAULT_LIFE_TIME) ) { // default mass for each bonus m_mass = 20.0; // default size for the collission rectangle of boni m_collRectX = -7; m_collRectY = -7; m_collRectWidth = 15; m_collRectHeight = 13; // Each bonus object should be registered first per default, // since it is created from class World and therefore exists // inside the world. But, unfortunately, we cannot do this // here in the constructor of Bonus, because the registration // routine calls the virtual function getID(), and at this // point of the object generation the bonus is not yet // completely built. } /**********************************************************/ Bonus::~Bonus() { } /**********************************************************/ void Bonus::registerAtManager() { m_worldPointer->getBonusManager()->registerBonusEntrance(*this); } /**********************************************************/ void Bonus::unregisterAtManager() { m_worldPointer->getBonusManager()->registerBonusExit(*this); } /**********************************************************/ Avatar* Bonus::checkPicking() { Avatar *avatar = NULL; const Uint8 nPlayers = m_worldPointer->getPlayerList().size(); // check the avatar of each player for( Uint8 p = 0; p < nPlayers; p++ ) { const Avatar* const A = m_worldPointer->getPlayerList()[p]->getAvatar(); // only check living avatars and those, who could // pick up this bonus at the moment if( !A->isLiving() || !canBePickedUpByAvatar(A) ) continue; // check the distance to the avatar const Sint32 cdx = (Sint32)(A->getPosX() - m_pos.x + 0.5), cdy = (Sint32)(A->getPosY() - m_pos.y + 0.5), dx = cdx > 0 ? ( cdx + A->getCollRectX() - getCollRectX() - getCollRectWidth()) : ( - cdx + getCollRectX() - A->getCollRectX() - A->getCollRectWidth() ); // if the avatar is in long distance with respect to // the x-coordinate, we can abort the checking here if( dx > 1 ) continue; const Sint32 dy = cdy > 0 ? ( cdy + A->getCollRectY() - getCollRectY() - getCollRectHeight() ) : ( - cdy + getCollRectY() - A->getCollRectY() - A->getCollRectHeight() ); if( dy <= 1 ) { if( avatar == NULL || (m_worldPointer->getRandom().getUint32() & 1) == 0 ) { avatar = (Avatar*)A; } } } return avatar; } /**********************************************************/ void Bonus::beingPickedUp( const Avatar* const avatar ) { m_worldPointer->newObject(BLUEGLOW_25)->setPos( m_pos ); } /**********************************************************/ void Bonus::update() { preBallistics(); // check destruction of the bonus if( m_health <= 0 || --m_timeToLive <= 0 ) { // some white particles for( int i = 0; i < 100; i++ ) { m_worldPointer->getParticles()->addParticle( Particles::ParticleData( m_pos, m_worldPointer->getRandom().getVector( 0.2 + 5*m_worldPointer->getRandom().getNormedReal()), Particles::BOUNCE_EARTH | Particles::STAIN | Particles::REDUNDANT, 0, 0, 30, 0, m_worldPointer->getRandom().getUint32() & 1 ? 0xffffff : 0xdddddd) ); } m_removeMeAfterUpdate = true; } else { doBallistics(); // check, if the bonus is picked up by an avatar Avatar* const avatar = checkPicking(); // If we found an avatar, who picks up the bonus, pass it // to this avatar. This avatar will unhook it from the world's // control. The collission rectangle is not set at this moment. if( avatar != NULL ) { avatar->pickUp( this ); // IMPORTANT: being picked up by an avatar might delete // the bonus object. Therefore do not touch any bonus data // members after picking up the bonus } else { updateSprite(); postBallistics(); } } } /**********************************************************/ int Bonus::applyDamage( const Particles::ParticleData& p ) { const int damage = CollidableObject::applyDamage( p ); // generate one white particle m_worldPointer->getParticles()->addParticle( Particles::ParticleData( // starting at the position the damaging particle p.pos, // leaping in a randomly perturbated initial speed vector m_vel + m_worldPointer->getRandom().getVector(1 + 7*m_worldPointer->getRandom().getNormedReal()), // initial type of the white particle Particles::BOUNCE_EARTH | Particles::STAIN | Particles::REDUNDANT, // owner and modifier 0, 0, // time to live m_worldPointer->getRandom().getUint32Between( 5, 20 ), // this particle does not harm anything 0, // color == WHITE 0xffffff) ); return damage; } /**********************************************************/ Uint32 Bonus::getSerializeBufferSize() const { return CollidableObject::getSerializeBufferSize() + Serialize::sizeOf( m_registered ) + Serialize::sizeOf( m_updatesPerFrame ) + Serialize::sizeOf( m_numUpdates ) + Serialize::sizeOf( m_timeToLive ) // adds additional size for debugging (see serialize.hpp), // but only, if the tags are used PLUS_TAG_SIZE( 1 ); } /**********************************************************/ void Bonus::serialize( Uint8*& bufferPointer ) const { // expands to a check of the buffer movement START_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer ); CollidableObject::serialize( bufferPointer ); Serialize::serialize( m_registered, bufferPointer ); Serialize::serialize( m_updatesPerFrame, bufferPointer ); Serialize::serialize( m_numUpdates, bufferPointer ); Serialize::serialize( m_timeToLive, bufferPointer ); // expands to tag serialization SERIALIZE_OBJECT_TAG( bufferPointer ); // expands to a check of the buffer movement END_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer, Bonus ); } /**********************************************************/ void Bonus::deserialize( Uint8*& bufferPointer ) { CollidableObject::deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_registered ); Serialize::deserialize( bufferPointer, m_updatesPerFrame ); Serialize::deserialize( bufferPointer, m_numUpdates ); Serialize::deserialize( bufferPointer, m_timeToLive ); // expands to tag deserialization DESERIALIZE_OBJECT_TAG( bufferPointer ); } /**********************************************************/ void Bonus::updateSprite() { if( --m_numUpdates <= 0 ) { if( ++m_Frame >= m_SequenceLength ) m_Frame = 0; m_numUpdates = m_updatesPerFrame; } } /**********************************************************/ void Bonus::dump( std::ostream& out ) const { using namespace std; out << "### Bonus object ###" << std::endl; CollidableObject::dump( out ); }