/* $Id: rope.cpp,v 1.28 2005/10/17 15:13:39 pohlt Exp $ */ #include "rope.hpp" #include "global.hpp" #include "world.hpp" #include "avatar.hpp" #include "hook.hpp" #include "serialize.hpp" /******************************************************************************/ Rope::Rope() { setState( VISIBLE, false ), setCharged( false ); } /******************************************************************************/ void Rope::initialize( AttachableObject* o1, AttachableObject* o2, const Uint8 owner, const real length, const Uint32 color ) { attachTo( o1 ); attachTo( o2 ); m_startPos = o1->getPos(); m_endPos = o2->getPos(); m_length = length; m_oldLength = 0; m_color = color; m_owner = owner; m_ttl = 25*30; // half a minute } /******************************************************************************/ void Rope::update() { DBG( 2 ) CHECK( getNAttachedObjects() <= 2, "Rope::update: too many attached objects\n" ); Sint32 attachedObjectID0 = INVALID_OBJECT, attachedObjectID1 = INVALID_OBJECT; if( getNAttachedObjects() == 2 ) { attachedObjectID0 = getAttachedObject( 0 )->getID(); attachedObjectID1 = getAttachedObject( 1 )->getID(); } // not attached to exactly two objects? => destroy rope if( m_ttl <= 0 || attachedObjectID0 == INVALID_OBJECT || ( attachedObjectID0 == HOOK && attachedObjectID1 == HOOK && dynamic_cast( getAttachedObject( 0 ))->isGrounded() && dynamic_cast( getAttachedObject( 1 ))->isGrounded()) ) { DBG( 5 ) INFO( "Rope::update: deleting rope\n" ); m_removeMeAfterUpdate = true; } else { const bool minOneBall = attachedObjectID0 == BALL || attachedObjectID1 == BALL, bothBalls = attachedObjectID0 == BALL && attachedObjectID1 == BALL, minOneHook = attachedObjectID0 == HOOK || attachedObjectID1 == HOOK; if( minOneBall && minOneHook ) m_ttl--; else if( bothBalls ) m_ttl -= 2; else if( (getAttachedObject( 0 )->isAvatar() && dynamic_cast( getAttachedObject( 0 ))->getPlayer()->getPlayerOrTeamID() != getOwner()) || (getAttachedObject( 1 )->isAvatar() && dynamic_cast( getAttachedObject( 1 ))->getPlayer()->getPlayerOrTeamID() != getOwner()) ) { m_ttl--; } CollidableObject* const obj1 = dynamic_cast( getAttachedObject( 0 ) ), * const obj2 = dynamic_cast( getAttachedObject( 1 ) ); DBG( 3 ) ASSERT( obj1 && obj2, "Rope::update: attached objects are not collidable objects\n" ); m_startPos = obj1->getPos(); m_endPos = obj2->getPos(); // check attached avatars for ROPE_IN or ROPE_OUT event for( int obj = 0; obj < 2; obj++ ) { const Avatar* avatar = dynamic_cast( getAttachedObject( obj )); if( avatar && avatar->getPlayer()->getPlayerOrTeamID() == m_owner ) { if( avatar->isSetRopeIn() ) { DBG( 5 ) INFO( "Rope::update: ROPE_IN event\n" ); if( m_length > 4.0 ) m_length -= 4.0; } if( avatar->isSetRopeOut() ) { DBG( 5 ) INFO( "Rope::update: ROPE_OUT event\n" ); if( m_length < 300.0 ) m_length += 4.0; } } } // calculate force Vector dist ( m_endPos - m_startPos ), normedDist( dist.getNorm() ); const real currentLength = dist.abs(); DBG( 5 ) INFO( "Rope::update: currentLength: %f, set length: %f\n", currentLength, m_length ); if( currentLength > m_length ) { const real drag = 2.0 * (currentLength-m_length) + 3.0 * (currentLength-m_oldLength); DBG( 5 ) INFO( "Rope::update: drag: %f\n", drag ); const Vector force( normedDist*drag ); obj1->addForce( force ); obj2->addForce( -force ); } m_oldLength = currentLength; } } /******************************************************************************/ AttachableObject* Rope::getOtherAttachedObject( const AttachableObject* a ) const { // not attached to exactly two objects? => destroy rope if( getNAttachedObjects() != 2 ) { DBG( 1 ) CHECK( false, "Rope::getOtherAttachedObject: not attached to two objects\n" ); return NULL; } if( getAttachedObject( 0 ) == a ) return getAttachedObject( 1 ); else return getAttachedObject( 0 ); } /******************************************************************************/ void Rope::serialize( Uint8*& bufferPointer ) const { // expands to a check of the buffer movement START_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer ); NonCollidableObject::serialize( bufferPointer ); Serialize::serialize( m_startPos , bufferPointer ); Serialize::serialize( m_endPos , bufferPointer ); Serialize::serialize( m_length , bufferPointer ); Serialize::serialize( m_oldLength, bufferPointer ); Serialize::serialize( m_color , bufferPointer ); Serialize::serialize( m_owner , bufferPointer ); Serialize::serialize( m_isCharged, bufferPointer ); Serialize::serialize( m_ttl , bufferPointer ); // expands to tag serialization SERIALIZE_OBJECT_TAG( bufferPointer ); // expands to a check of the buffer movement END_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer, Rope ); } /******************************************************************************/ void Rope::deserialize( Uint8*& bufferPointer ) { NonCollidableObject::deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_startPos ); Serialize::deserialize( bufferPointer, m_endPos ); Serialize::deserialize( bufferPointer, m_length ); Serialize::deserialize( bufferPointer, m_oldLength ); Serialize::deserialize( bufferPointer, m_color ); Serialize::deserialize( bufferPointer, m_owner ); Serialize::deserialize( bufferPointer, m_isCharged ); Serialize::deserialize( bufferPointer, m_ttl ); // expands to tag deserialization DESERIALIZE_OBJECT_TAG( bufferPointer ); } /******************************************************************************/ Uint32 Rope::getSerializeBufferSize() const { return NonCollidableObject::getSerializeBufferSize() + Serialize::sizeOf( m_startPos ) + Serialize::sizeOf( m_endPos ) + Serialize::sizeOf( m_length ) + Serialize::sizeOf( m_oldLength ) + Serialize::sizeOf( m_color ) + Serialize::sizeOf( m_owner ) + Serialize::sizeOf( m_isCharged ) + Serialize::sizeOf( m_ttl ) // adds additional size for debugging (see serialize.hpp), // but only, if the tags are used PLUS_TAG_SIZE( 1 ); } /******************************************************************************/