/* $Id: hook.cpp,v 1.30.4.1 2006/01/20 11:33:52 chfreund Exp $ */ #include "hook.hpp" #include "world.hpp" #include "avatar.hpp" #include "rope.hpp" /**********************************************************/ Mix_Chunk* Hook::m_attachSample, * Hook::m_damageSample; /**********************************************************/ Hook::Hook(): m_firstEarthContact( true ) { m_health = 50000; m_mass = 15.0; m_maxGroundedForce2 = 75000.0; m_maxGroundedForceVert = 1e+30; m_collRectX = -1; m_collRectY = -1; m_collRectWidth = 3; m_collRectHeight = 3; } /**********************************************************/ bool Hook::initialize( const Vector& pos, const Vector& vel, CollidableObject*& hitObject ) { int cx, cy; if( ! m_worldPointer->getMap()->testFilledCollRectCollPos( ROUND( pos.x ) + m_collRectX, ROUND( pos.y ) + m_collRectY, m_collRectWidth, m_collRectHeight, cx, cy ) ) { hitObject = m_worldPointer->getCollidableAt( cx, cy ); m_worldPointer->deleteObject( this ); // ok // DO NOT TOUCH ANY HOOK DATA MEMBERS AFTER THIS POINT return false; } m_pos = pos; m_vel = vel; // set hook stencil setCollRect(); return true; } /**********************************************************/ bool Hook::testGrounded() { return isGrounded() && ! m_worldPointer->getMap()->testPassableSmoothing( m_stickingAtX, m_stickingAtY, Flags::OBSTACLE_EARTH ); } /**********************************************************/ void Hook::update() { preBallistics(); // if nothing is attached or hook is destroyed if( getNAttachedObjects() == 0 || m_health <= 0 ) { m_removeMeAfterUpdate = true; } else { doBallistics(); postBallistics(); } } /**********************************************************/ bool Hook::collidedWithObstacle( const Sint32 colX, const Sint32 colY ) { const Flag hitFlag = m_worldPointer->getMap()->getFlags()->getValueAt( colX, colY ); if( hitFlag & Flags::OBSTACLE_EARTH ) { LOG( 5 ) INFO( "Hook::update: hit earth\n" ); m_stickingAtX = colX; m_stickingAtY = colY; m_vel.set( 0.0, 0.0 ); setState( GROUNDED, true ); if( m_firstEarthContact ) { // set rope length to current length for( int i = 0; i < getNAttachedObjects(); i++ ) { Rope* rope = dynamic_cast( getAttachedObject( i ) ); if( rope ) { rope->setLength( 0.85 * rope->getLength() ); } } m_firstEarthContact = false; } } if( hitFlag & Flags::OBSTACLE_OBJECT ) { LOG( 5 ) INFO( "Hook::update: hit object\n" ); CollidableObject* hitObject = m_worldPointer->getCollidableAt( colX, colY ); if( hitObject ) { for( int i = 0; i < getNAttachedObjects(); i++ ) { const Rope* rope = dynamic_cast( getAttachedObject( i )); DBG( 1 ) CHECK( rope, "Hook::update: attached object is not a rope\n" ); /* only attach if not yet attached */ if( getAttachedObject( i )->getAttachedObjectIndex( hitObject ) == -1 ) { getAttachedObject( i )->attachTo( hitObject ); } else { /* Risky to delete the rope because this would mess up the vector containing the attached ropes. Better let the rope find out that this hook has died and kill itself. delete getAttachedObject( i ); */ } } } // remove hook object m_removeMeAfterUpdate = true; return false; } DBG( 3 ) CHECK( hitFlag & Flags::OBSTACLE_ANY, "Hook::update: hit unknown type\n" ); return true; } /**********************************************************/ int Hook::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; } LOG( 5 ) INFO( "Hook::applyDamage: health: %i\n", m_health ); return damage; } /**********************************************************/ void Hook::serialize( Uint8*& bufferPointer ) const { // expands to a check of the buffer movement START_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer ); CollidableObject::serialize( bufferPointer ); Serialize::serialize( m_stickingAtX , bufferPointer ); Serialize::serialize( m_stickingAtY , bufferPointer ); Serialize::serialize( m_firstEarthContact, bufferPointer ); // expands to tag serialization SERIALIZE_OBJECT_TAG( bufferPointer ); // expands to a check of the buffer movement END_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer, Hook ); } /**********************************************************/ void Hook::deserialize( Uint8*& bufferPointer ) { CollidableObject::deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_stickingAtX ); Serialize::deserialize( bufferPointer, m_stickingAtY ); Serialize::deserialize( bufferPointer, m_firstEarthContact ); // expands to tag deserialization DESERIALIZE_OBJECT_TAG( bufferPointer ); } /**********************************************************/ Uint32 Hook::getSerializeBufferSize() const { return CollidableObject::getSerializeBufferSize() + 2 * Serialize::sizeOf( m_stickingAtX ) + Serialize::sizeOf( m_firstEarthContact ) // adds additional size for debugging (see serialize.hpp), // but only, if the tags are used PLUS_TAG_SIZE( 1 ); } /**********************************************************/ void Hook::dump( std::ostream& out ) const { using namespace std; out << "### Hook object ###" << endl; CollidableObject::dump( out ); }