/* $Id: helicopter.cpp,v 1.16.2.1 2006/01/20 11:33:52 chfreund Exp $ */ #include "helicopter.hpp" #include "world.hpp" #include "avatar.hpp" /**********************************************************/ // minimal, maximal and start angle [degree] #define START_ANGLE -90 #define ANGLE_AMPLITUDE 30 // number of sprite sequences per direction, not including angle 0 #define N_SEQENCES_PER_DIRECTION 6 // angle increment [degree] #define ANGLE_INCREMENT 5 // fuel constants // START_FUEL : total fuel // LIFTOFF_FUEL : maximal fuel used for the lift off // RC_FUEL : fuel, exclusively for the remote control #define START_FUEL 150 #define LIFTOFF_FUEL 8 #define RC_FUEL (START_FUEL - LIFTOFF_FUEL) // mass of the helicopter #define HELICOPTER_MASS 80.0 // number of shrapnels, if the helicopter explodes #define HELICOPTER_NUM_SHRAPNELS 300 // damage of the shrapnels #define HELICOPTER_DAMAGE 20 // the rotor's thrust, if the pilot activates the engine #define HELICOPTER_THRUST 40.0 // the rotor's thrust in idle mode #define HELICOPTER_IDLE_THRUST 5.0 // We do not want the helicopter to fall like a stone. // So the helicopter has an air resistance, but only in // positive y-direction, i.e. slowing down the falling process. #define HELICOPTER_FALLING_RESISTANCE 0.05 #define HELICOPTER_GROUND_SPEED_2 10.0 #define HELICOPTER_BOUNCE_DAMPING 0.3 /**********************************************************/ // dependent settings, do not touch #define MIN_ANGLE (START_ANGLE - ANGLE_AMPLITUDE) #define MAX_ANGLE (START_ANGLE + ANGLE_AMPLITUDE) // total number of sequences #define TOTAL_N_SEQUENCES (2*N_SEQENCES_PER_DIRECTION + 1) /**********************************************************/ Mix_Chunk *Helicopter::m_explodeSample = 0x0, *Helicopter::m_damageSample = 0x0; /**********************************************************/ Helicopter::Helicopter() : m_owner(INVALID_PLAYER_ID), m_ownerHasControl(false), m_angle(START_ANGLE), m_fuel(START_FUEL) { m_bounceThresholdVel2 = 10.0, m_bounceFactorHLVel = 5.0, m_bounceFactorLow = 0.3, m_bounceFactorHigh = 0.3, m_health = 200000; m_mass = HELICOPTER_MASS; m_collRectX = -4; m_collRectY = -4; m_collRectWidth = 9; m_collRectHeight = 9; } /**********************************************************/ Helicopter::~Helicopter() { } /**********************************************************/ bool Helicopter::initialize( const Vector& pos, const Vector& vel, const Uint8 owner ) { 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 DATA MEMBERS AFTER THIS POINT return false; } // initializations of derived member data m_pos = pos; m_vel = vel; // members of class Helicopter m_owner = owner; m_ownerHasControl = true; m_angle = START_ANGLE; m_fuel = START_FUEL; // set collission rectangle setCollRect(); // turn on remote controle mode in the avatar Avatar *const avatar = m_worldPointer->getPlayerByID( m_owner )->getAvatar(); avatar->takeRemoteControl(); setFocusPriority( avatar->getFocusPriority() + FOCUS_PRIO_RC_HELICOPTER ); m_worldPointer->scanObjectsForFocus(); // block recharging of the helicopter weapon avatar->getPlayer()->getActiveWeapon()->lockRecharge(); return true; } /**********************************************************/ void Helicopter::update() { preBallistics(); bool engineIsRunning = false; // get const Player *const pilotPlayer = m_ownerHasControl ? m_worldPointer->getPlayerByID( m_owner ) : 0x0; Avatar *const pilot = pilotPlayer ? pilotPlayer->getAvatar() : 0x0; // initial lift off phase if( m_fuel > RC_FUEL ) { engineIsRunning = true; // remote controle instructions from the pilot } else if( pilot ) { // if an avatar dies, it loses permanently the control // over this helicopter. if( pilot->isLiving() ) { pilot->setStateMask( ~0 ); // decrease angle as far as possible if( pilot->isMovingLeft() ) { if( MIN_ANGLE > (m_angle -= ANGLE_INCREMENT) ) { m_angle = MIN_ANGLE; } } // increase angle as far as possible if( pilot->isMovingRight() ) { if( MAX_ANGLE < (m_angle += ANGLE_INCREMENT) ) { m_angle = MAX_ANGLE; } } // if( pilot->isJumping() && m_fuel > 0 ) { engineIsRunning = true; } // remote controled destruction if( pilot->isShooting() ) m_health = 0; } else { m_ownerHasControl = false; } } // explode? if( m_health <= 0 ) { explode(); } else { if( engineIsRunning ) { setState( GROUNDED, false ); // accelerate in direction of thrust Vector thrust; thrust.setAngle( m_angle*M_PI/180.0, HELICOPTER_THRUST ); m_force += thrust; // consume some fuel m_fuel--; } // add influence of gravitation m_force.y -= HELICOPTER_IDLE_THRUST; //if( m_vel.y > 0.0 ) m_force.y *= 1.0 - HELICOPTER_FALLING_RESISTANCE; doBallistics(); // increment the animation frame if( ++m_Frame >= m_SequenceLength ) m_Frame = 0; // select new missile sprite updateSpriteSelection(); postBallistics(); } } /**********************************************************/ void Helicopter::explode() { // play explosion sound Audio::getInstance()->playSound( m_explodeSample, m_pos ); // create new explosion object m_worldPointer->newObject( EXPLOSION_80 )->setPos( m_pos ); // create shrapnels for( int s = 0; s < HELICOPTER_NUM_SHRAPNELS; s++ ) { m_worldPointer->getParticles()->addParticle( Particles::ParticleData( m_pos, m_worldPointer->getRandom().getVector(15 + 5*m_worldPointer->getRandom().getNormedReal()), Particles::EXPL_EARTH | Particles::EXPL_OBJECT | Particles::DAMAGE | Particles::INVISIBLE, 0, m_owner, 2, HELICOPTER_DAMAGE, 0xffffff ) ); } const Player *const pilotPlayer = m_ownerHasControl ? m_worldPointer->getPlayerByID( m_owner ) : 0x0; Avatar *const pilot = pilotPlayer ? pilotPlayer->getAvatar() : 0x0; if( pilot ) { // turn off remode control mode pilot->dropRemoteControl(); // unlock recharging of the helicopter weapon pilot->getPlayer()->getActiveWeapon()->unlockRecharge(); } m_removeMeAfterUpdate = true; } /**********************************************************/ void Helicopter::updateSpriteSelection() { setSequence( (int)( (m_angle - MIN_ANGLE - 0.5*ANGLE_INCREMENT) / ANGLE_INCREMENT) ); } /**********************************************************/ void Helicopter::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 ); Serialize::serialize( m_ownerHasControl, bufferPointer ); Serialize::serialize( m_angle, bufferPointer ); Serialize::serialize( m_fuel, bufferPointer ); // expands to tag serialization SERIALIZE_OBJECT_TAG( bufferPointer ); // expands to a check of the buffer movement END_OBJECT_SERIALIZED_SIZE_CHECK( bufferPointer, Helicopter ); } /**********************************************************/ void Helicopter::deserialize( Uint8*& bufferPointer ) { CollidableObject::deserialize( bufferPointer ); Serialize::deserialize( bufferPointer, m_owner ); Serialize::deserialize( bufferPointer, m_ownerHasControl ); Serialize::deserialize( bufferPointer, m_angle ); Serialize::deserialize( bufferPointer, m_fuel ); // expands to tag deserialization DESERIALIZE_OBJECT_TAG( bufferPointer ); } /**********************************************************/ Uint32 Helicopter::getSerializeBufferSize() const { return CollidableObject::getSerializeBufferSize() + Serialize::sizeOf( m_owner ) + Serialize::sizeOf( m_ownerHasControl ) + Serialize::sizeOf( m_angle ) + Serialize::sizeOf( m_fuel ) // adds additional size for debugging (see serialize.hpp), // but only, if the tags are used PLUS_TAG_SIZE( 1 ); } /**********************************************************/ void Helicopter::dump( std::ostream& out ) const { using namespace std; out << "### Helicopter object ###" << endl; CollidableObject::dump( out ); out << "Helicopter components:" << endl; out << "\tAngle: " << m_angle << endl; }