//============================================================================= // Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. // // File: state.cpp // // Description: Implementation of class State // // History: 6/12/2002 + Created -- NAME // //============================================================================= //======================================== // System Includes //======================================== // Foundation Tech #include //======================================== // Project Includes //======================================== #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include
#include #include #include #include #include #include #include #include #include #include #include #include #include namespace CharacterAi { //****************************************************************************** // // Global Data, Local Data, Local Classes // //****************************************************************************** const int MAX_CLASS_SIZE = 32; // bytes. FBMemoryPool State::sMemoryPool( MAX_CLASS_SIZE, 32, GMA_LEVEL_OTHER ); static const char* sGetOutPassenger[] = { "get_out_of_car_open_door", "get_out_of_car", "get_out_of_car_close_door" }; static const char* sGetOutDriver[] = { "get_out_of_car_open_door_driver", "get_out_of_car_driver", "get_out_of_car_close_door_driver" }; static const char* sGetOutHighPassenger[] = { "get_out_of_car_open_door", "get_out_of_car_high", "get_out_of_car_close_door_high" }; static const char* sGetOutHighDriver[] = { "get_out_of_car_open_door_driver", "get_out_of_car_high_driver", "get_out_of_car_close_door_high_driver" }; static const char* sGetInPassenger[] = { "get_into_car_open_door", "get_into_car", "get_into_car_close_door" }; static const char* sGetInDriver[] = { "get_into_car_open_door_driver", "get_into_car_driver", "get_into_car_close_door_driver" }; static const char* sGetInHighPassenger[] = { "get_into_car_open_door_high", "get_into_car_high", "get_into_car_close_door" }; static const char* sGetInHighDriver[] = { "get_into_car_open_door_high_driver", "get_into_car_high_driver", "get_into_car_close_door_driver" }; //****************************************************************************** // // Public Member Functions // //****************************************************************************** //============================================================================== // State::State //============================================================================== // Description: Constructor. // // Parameters: None. // // Return: N/A. // //============================================================================== State::State( Character* pCharacter ) : mpCharacter( pCharacter ) { } //============================================================================== // State::~State //============================================================================== // Description: Destructor. // // Parameters: None. // // Return: N/A. // //============================================================================== State::~State() { mpCharacter = 0; } /* ============================================================================== InCar::InCar ============================================================================== Description: Comment Parameters:( Character* pCharacter ) Return: InCar ============================================================================= */ InCar::InCar( Character* pCharacter ) : State( pCharacter ) { m_InCarAction = new InCarAction(pCharacter); m_InCarAction->AddRef(); m_GetOutState = GETOUT_NONE; } InCar::~InCar( void ) { m_InCarAction->Release(); } void InCar::Enter( void ) { if(!mpCharacter->GetTargetVehicle()) { return; } mpCharacter->DoGroundIntersect(false); m_GetOutState = GETOUT_NONE; if(mpCharacter == GetCharacterManager()->GetCharacter(0)) { GetVehicleCentral()->ActivateVehicleTriggers(false); } // if we did a git in, in car shoudl already be true, if not, need to force a little if(!mpCharacter->IsInCar()) { mpCharacter->GetActionController()->Clear(); mpCharacter->SetInCar( true ); mpCharacter->UpdateTransformToInCar(); } mIsDriver = (mpCharacter->GetTargetVehicle()->mpDriver == mpCharacter) || (!mpCharacter->GetTargetVehicle()->HasDriver()); rmt::Vector seat = mIsDriver ? mpCharacter->GetTargetVehicle()->GetDriverLocation() : mpCharacter->GetTargetVehicle()->GetPassengerLocation(); bool busy = mpCharacter->GetActionController()->IsBusy(); if(!m_InCarAction->IsRunning()) { m_InCarAction->SetStatus(SLEEPING); } // add the in car action (not very interesting) to the character sequencer Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); pSeq->AddAction( new Position(mpCharacter, seat, 0.0f, true)); if(!busy) { pSeq->AddAction( m_InCarAction); } pSeq->EndSequence(); mpCharacter->SetInCar( true ); if(!mpCharacter->GetTargetVehicle()->mVisibleCharacters) { mpCharacter->RemoveFromWorldScene(); } else { mpCharacter->SetScale(mpCharacter->GetTargetVehicle()->mCharacterScale); } mpCharacter->RemoveFromPhysics(); } void InCar::Exit( void ) { if(mpCharacter == GetCharacterManager()->GetCharacter(0)) { Vehicle::sDoBounce = false; } this->m_InCarAction->Done(); this->m_InCarAction->Clear(); mpCharacter->AddToPhysics(); if( mpCharacter->GetTargetVehicle() != NULL ) { if( (mpCharacter->GetTargetVehicle()->GetDriver() == mpCharacter) && (mpCharacter->GetRole() == Character::ROLE_PEDESTRIAN)) { mpCharacter->GetTargetVehicle()->SetDriver(NULL); } } } void InCar::SequenceAction( void ) { Vehicle* pVehicle = mpCharacter->GetTargetVehicle( ); if(!pVehicle) { return; } rAssert(pVehicle); if(!m_InCarAction->IsRunning()) { m_InCarAction->SetStatus(SLEEPING); } // add the in car action (not very interesting) to the character sequencer Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); pSeq->AddAction( m_InCarAction); pSeq->EndSequence(); rmt::Vector localPos = mpCharacter->GetPuppet()->GetPosition(); rmt::Vector seatPos; if(mIsDriver) { seatPos = pVehicle->GetDriverLocation(); } else { seatPos = pVehicle->GetPassengerLocation(); } seatPos.y = localPos.y; mpCharacter->GetPuppet()->SetPosition(seatPos); if(mpCharacter == GetCharacterManager()->GetCharacter(0)) { Vehicle::sDoBounce = true; } } void InCar::Update( float timeins ) { Vehicle* pVehicle = mpCharacter->GetTargetVehicle( ); if((!pVehicle) || ((pVehicle->mVehicleDestroyed) && (GetGameFlow()->GetCurrentContext() != CONTEXT_DEMO) && (GetGameFlow()->GetCurrentContext() != CONTEXT_SUPERSPRINT))) { mpCharacter->GetActionController()->Clear(); mpCharacter->GetStateManager()->SetState(); return; } CharacterController::eIntention theIntention = CharacterController::NONE; bool actionDown = false; if(!GetHitnRunManager()->IsWaitingForReset()) { theIntention = mpCharacter->GetController()->GetIntention(); #ifdef RAD_WIN32 actionDown = mpCharacter->GetController()->IsButtonDown(CharacterController::GetOutCar); #else actionDown = mpCharacter->GetController()->IsButtonDown(CharacterController::DoAction); #endif } bool brake = false; if( GetGameFlow()->GetCurrentContext() != CONTEXT_SUPERSPRINT ) { switch(m_GetOutState) { case GETOUT_NONE: { #ifdef RAD_WIN32 if (theIntention == CharacterController::GetOutCar) #else if (theIntention == CharacterController::DoAction) #endif { m_GetOutState = (pVehicle->GetSpeedKmh() < 30.0f) ? GETOUT_COMITTED : GETOUT_TRYING; mpCharacter->GetTargetVehicle()->mGeometryVehicle->ShowBrakeLights(); } } break; case GETOUT_TRYING : { if(!actionDown) { m_GetOutState = GETOUT_NONE; mpCharacter->GetTargetVehicle()->mGeometryVehicle->HideBrakeLights(); VehicleController* controller = GetVehicleCentral()->GetVehicleController(GetVehicleCentral()->GetVehicleId(pVehicle)); if(controller) { rAssert(dynamic_cast(controller)); static_cast(controller)->GetMappable()->GetButton(VehicleMappable::Brake)->SetValue(0.0f); static_cast(controller)->GetMappable()->GetButton(VehicleMappable::HandBrake)->SetValue(0.0f); } break; } if ( pVehicle->GetSpeedKmh() < 30.0f && !pVehicle->IsUnstable() && !pVehicle->IsAirborn() ) { m_GetOutState = GETOUT_COMITTED; } brake = true; } break; case GETOUT_COMITTED : { if ( pVehicle->GetSpeedKmh() < 3.0f ) { mpCharacter->GetActionController()->Clear(); VehicleController* controller = GetVehicleCentral()->GetVehicleController(GetVehicleCentral()->GetVehicleId(pVehicle)); if(controller) { rAssert(dynamic_cast(controller)); static_cast(controller)->GetMappable()->GetButton(VehicleMappable::Gas)->SetValue(0.0f); static_cast(controller)->GetMappable()->GetButton(VehicleMappable::Brake)->SetValue(0.0f); static_cast(controller)->GetMappable()->GetButton(VehicleMappable::HandBrake)->SetValue(1.0f); } mpCharacter->GetTargetVehicle()->mGeometryVehicle->HideBrakeLights(); mpCharacter->GetStateManager()->SetState(); return; } else { VehicleController* v = GetVehicleCentral()->GetVehicleController(GetVehicleCentral()->GetVehicleId(pVehicle)); if(v && (v->GetGas() > 0.0f)) { m_GetOutState = GETOUT_NONE; mpCharacter->GetTargetVehicle()->mGeometryVehicle->HideBrakeLights(); VehicleController* controller = GetVehicleCentral()->GetVehicleController(GetVehicleCentral()->GetVehicleId(pVehicle)); static_cast(controller)->GetMappable()->GetButton(VehicleMappable::HandBrake)->SetValue(0.0f); } else { brake = true; } } } break; break; } } if(brake) { VehicleController* controller = GetVehicleCentral()->GetVehicleController(GetVehicleCentral()->GetVehicleId(pVehicle)); if(controller) { rAssert(dynamic_cast(controller)); static_cast(controller)->GetMappable()->GetButton(VehicleMappable::Gas)->SetValue(0.0f); static_cast(controller)->GetMappable()->GetButton(VehicleMappable::HandBrake)->SetValue(1.0f); } } if(m_InCarAction->IsRunning()) { /* if(mpCharacter->GetController()->IsButtonDown(CharacterController::Attack) && (m_GetOutState == GETOUT_NONE) ) { m_InCarAction->IWannaRock(true); } */ VehicleController* v = GetVehicleCentral()->GetVehicleController(GetVehicleCentral()->GetVehicleId(mpCharacter->GetTargetVehicle(), false)); if(v) { bool duh; float steer = v->GetSteering(duh); Action* action = NULL; float speed = mpCharacter->GetTargetVehicle()->GetSpeedKmh(); if(mIsDriver) { if((rmt::Abs(steer) > 0.5) && (speed > 5.0f)) { action = new SteerAction(mpCharacter, (steer < 0) ? "turn_left_driver" : "turn_right_driver", 10.0f); } else if (mpCharacter->GetTargetVehicle()->IsInReverse()) { action = new ReverseAction(mpCharacter, "look_back_driver", 25.0f); } else if ((mpCharacter->GetTargetVehicle()->GetAccelMss() > 8.0f) && (speed < 20.0f)) { action = new AccelAction(mpCharacter, "accelerate_driver", 15.0f); } else if((mpCharacter->GetTargetVehicle()->GetAccelMss() < -10.0f) && (speed > 50.0f)) { action = new DecelAction(mpCharacter, "decelerate_driver", 15.0f); } else if(mpCharacter->GetTargetVehicle()->GetAccelMss() < -25.0f) { if(mpCharacter->GetTargetVehicle()->mVelocityCM.DotProduct(mpCharacter->GetTargetVehicle()->mVehicleFacing) > 0.0f) { action = new PlayAnimationAction(mpCharacter, "crash_driver"); } } } else // passenger { if((rmt::Abs(steer) > 0.5) && (speed > 50.0f)) { action = new SteerAction(mpCharacter, (steer < 0) ? "sway_right" : "sway_left", 20.0f); } } if(action) { m_InCarAction->Done(); m_InCarAction->Clear(); mpCharacter->GetActionController()->SequenceSingleAction(action); } } } if( theIntention == CharacterController::CelebrateSmall ) { m_InCarAction->Done(); m_InCarAction->Clear(); mpCharacter->GetActionController()->SequenceSingleAction( new PlayAnimationAction( mpCharacter, mIsDriver ? "in_car_victory_small_driver" : "in_car_victory_small")); return; } if( theIntention == CharacterController::CelebrateBig ) { m_InCarAction->Done(); m_InCarAction->Clear(); mpCharacter->GetActionController()->SequenceSingleAction(new PlayAnimationAction( mpCharacter, mIsDriver ? "in_car_victory_large_driver" : "in_car_victory_large")); return; } if( theIntention == CharacterController::WaveHello) { m_InCarAction->Done(); m_InCarAction->Clear(); mpCharacter->GetActionController()->SequenceSingleAction( new PlayAnimationAction( mpCharacter, "wave_driver")); return; } if( theIntention == CharacterController::WaveGoodbye) { m_InCarAction->Done(); m_InCarAction->Clear(); mpCharacter->GetActionController()->SequenceSingleAction( new PlayAnimationAction( mpCharacter, "wave_goodbye_driver")); return; } } /* ============================================================================== Loco::Loco ============================================================================== Description: Comment Parameters( Character* pCharacter ) Returns: ============================================================================= */ Loco::Loco( Character* pCharacter ) : State( pCharacter ), mLastActionFrame(0) { } Loco::~Loco( void ) { } void Loco::Enter( void ) { if( mpCharacter->GetRole() != Character::ROLE_PEDESTRIAN ) { mpCharacter->AddToWorldScene(); } mpCharacter->SetScale(1.0f); mpCharacter->UpdateTransformToLoco(); mpCharacter->DoGroundIntersect(true); mpCharacter->SetInCar( false ); mpCharacter->SetTargetVehicle( NULL ); mpCharacter->GetWalkerLocomotionAction()->PlayDriver(); if(mpCharacter == GetCharacterManager()->GetCharacter(0)) { GetVehicleCentral()->ActivateVehicleTriggers(true); } if(!mpCharacter->GetActionController()->IsBusy()) { SequenceAction(); } } void Loco::Exit( void ) { mpCharacter->GetWalkerLocomotionAction()->StopDriver(); mpCharacter->GetWalkerLocomotionAction()->Done();; mpCharacter->GetWalkerLocomotionAction()->AllowIdle(false); mpCharacter->SetSimpleLoco(false); } void Loco::SequenceAction( void ) { mpCharacter->SetSimpleLoco(false); mpCharacter->GetWalkerLocomotionAction()->AllowIdle(false); CharacterController::eIntention theIntention = mpCharacter->GetController()->GetIntention(); if((theIntention == CharacterController::Attack) && GetCheatInputSystem()->IsCheatEnabled(CHEAT_ID_KICK_TOGGLES_CHARACTER_MODEL)) { mpCharacter->GetController()->SetIntention(CharacterController::NONE); GetCharacterManager()->NextCheatModel(); return; } // if we are doing a kick, and in the action range of a power coupling, // turn the kick into an aciton // Wow, is this ever a hack. if(( theIntention == CharacterController::Attack) && mpCharacter->GetActionButtonHandler( )) { if(dynamic_cast(mpCharacter->GetActionButtonHandler( ))) { theIntention = CharacterController::DoAction; mpCharacter->GetController()->SetIntention(theIntention); } } // give the actionbutton handler (if any) a crack at things if ( (mpCharacter->GetActionButtonHandler( ) != (ActionButton::ButtonHandler*)0) && ((mLastActionFrame + 3) < GetGame()->GetFrameCount()) ) { if ( mpCharacter->GetActionButtonHandler()->ButtonPressed( mpCharacter ) ) { mLastActionFrame = GetGame()->GetFrameCount(); return; } } mpCharacter->GetController()->ClearIntention(); // Sequence in the Dodge animation if( theIntention == CharacterController::Dodge ) { Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); if( mpCharacter->IsNPC() ) // change NPC controller state when dodging is done { pSeq->BeginSequence(); pSeq->AddAction(new ChangeNPCControllerState(mpCharacter, NPCController::DODGING)); pSeq->EndSequence(); } pSeq->BeginSequence(); Action* pAction = new DodgeAction( mpCharacter ); pSeq->AddAction( pAction ); pSeq->EndSequence(); if( mpCharacter->IsNPC() ) // change NPC controller state when dodging is done { pSeq->BeginSequence(); pSeq->AddAction(new ChangeNPCControllerState(mpCharacter, NPCController::FOLLOWING_PATH)); pSeq->EndSequence(); } mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } // Sequence in the jump animation if ( theIntention == CharacterController::Jump && !GetInteriorManager()->IsInside()) { if( !mpCharacter->IsNPC() && mpCharacter->GetSimState()->GetControl() == sim::simSimulationCtrl ) { // if player character is in simulation control and jump button was pressed, // we transit him back to AI control mpCharacter->GetSimState()->SetControl( sim::simAICtrl ); mpCharacter->GetSimState()->ResetVelocities(); mpCharacter->OnTransitToAICtrl(); } else { Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); JumpAction* pAction = mpCharacter->GetJumpLocomotionAction(); pAction->Reset(CharacterTune::sfJumpHeight, false); pSeq->AddAction( pAction ); pSeq->EndSequence(); mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } } // Sequence in the Cringe animation if( theIntention == CharacterController::Cringe ) { Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); if( mpCharacter->IsNPC() ) { pSeq->BeginSequence(); pSeq->AddAction(new ChangeNPCControllerState(mpCharacter, NPCController::CRINGING)); pSeq->EndSequence(); } pSeq->BeginSequence(); Action* pAction = new CringeAction( mpCharacter ); pSeq->AddAction( pAction ); pSeq->EndSequence(); if( mpCharacter->IsNPC() ) { pSeq->BeginSequence(); pSeq->AddAction(new ChangeNPCControllerState(mpCharacter, NPCController::FOLLOWING_PATH)); pSeq->EndSequence(); } mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } // Sequence in the TurnRight anim if( theIntention == CharacterController::TurnRight ) { Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); Action* pAction = new PlayAnimationAction( mpCharacter, "turn60_CW" ); //, 50.0f ); pSeq->AddAction( pAction ); pSeq->EndSequence(); mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } // Sequence in the TurnLeft anim if( theIntention == CharacterController::TurnLeft ) { Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); Action* pAction = new PlayAnimationAction( mpCharacter, "turn60_CCW" );//, 50.0f ); pSeq->AddAction( pAction ); pSeq->EndSequence(); mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } // Sequence in the attack anim if( theIntention == CharacterController::Attack ) { Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); pSeq->AddAction( new PlayAnimationAction( mpCharacter, "break_quick" )); pSeq->AddAction( new KickAction( mpCharacter, 0.25f )); pSeq->EndSequence(); mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } if( theIntention == CharacterController::CelebrateSmall ) { Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); PlayAnimationAction* action = new PlayAnimationAction( mpCharacter, "victory_small" ); action->AbortWhenMovementOccurs(true); pSeq->AddAction(action); pSeq->EndSequence(); mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } if( theIntention == CharacterController::CelebrateBig ) { Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); pSeq->AddAction( new PlayAnimationAction( mpCharacter, "victory_large" )); pSeq->EndSequence(); mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } // Only do the test for turbo when we are not jumping. // if ( mpCharacter->GetController()->IsButtonDown( CharacterController::Dash ) && !GetInteriorManager()->IsInside()) { mpCharacter->SetTurbo( true ); } else { mpCharacter->SetTurbo( false ); } if ( mpCharacter->IsInCollision() ) { // Only play the animation if the character is running fast enough. // if ( false ) //mpCharacter->IsTurbo() && mpCharacter->GetDesiredSpeed() > 0.0f ) { // Speed is good, now check the hit angle. // [6/26/2002] // if ( mpCharacter->CanStaggerCollision( ) ) { mpCharacter->GetActionController()->Clear(); Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); Action* pAction = 0; // Play run_into_object. // pSeq->BeginSequence(); pAction = new PlayAnimationAction( mpCharacter, "run_into_object" ); pSeq->AddAction( pAction ); pSeq->EndSequence( ); mpCharacter->ResetSpeed( ); mpCharacter->GetWalkerLocomotionAction()->StopDriver(); return; } } } // nothing else got sequenced, do the default if(mpCharacter->GetWalkerLocomotionAction()->GetStatus() != RUNNING) { mpCharacter->GetWalkerLocomotionAction()->SetStatus(SLEEPING); } mpCharacter->GetWalkerLocomotionAction()->AllowIdle(true); mpCharacter->GetWalkerLocomotionAction()->PlayDriver(); Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); pSeq->AddAction( mpCharacter->GetWalkerLocomotionAction()); pSeq->EndSequence(); mpCharacter->SetSimpleLoco(true); } void Loco::Update( float timeins ) { } /* ============================================================================== GetIn ============================================================================== */ GetIn::GetIn( Character* pCharacter ) : State( pCharacter ), mObstructed(false), mFirst(true), mCollisionFailure(4) { } GetIn::~GetIn( void ) { } void GetIn::Enter( void ) { if(mFirst) { GetEventManager()->TriggerEvent( EVENT_GETINTOVEHICLE_START, mpCharacter ); mFirst = false; } if(!mpCharacter->GetTargetVehicle()->mIrisTransition && !mObstructed && (mpCharacter->GetTargetVehicle()->GetSpeedKmh() <= 1.0f)) { if(mpCharacter->GetWalkerLocomotionAction()->GetStatus() != RUNNING) { mpCharacter->GetWalkerLocomotionAction()->SetStatus(SLEEPING); } mpCharacter->GetWalkerLocomotionAction()->PlayDriver(); if(mpCharacter == GetCharacterManager()->GetCharacter(0)) { GetVehicleCentral()->ActivateVehicleTriggers(false); } // figure out how to get into the car int nWaypoints; rmt::Vector waypoints[4]; bool slide; bool jump; CalcGetInPath(&nWaypoints, waypoints, &slide, &jump); if(jump) { mObstructed = true; mpCharacter->GetActionController()->Clear(); Enter(); /* Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); pSeq->AddAction( new FragileArrive( mpCharacter, waypoints[0]) ); mpCharacter->GetJumpLocomotionAction()->Reset(1.9f); pSeq->AddAction(mpCharacter->GetJumpLocomotionAction()); pSeq->EndSequence( ); */ return; } rmt::Vector getinPosition = waypoints[nWaypoints - 1]; if( ( nWaypoints >= 3 ) && ( mpCharacter->GetTargetVehicle()->mpDriver != NULL ) ) { GetEventManager()->TriggerEvent( EVENT_WRONG_SIDE_DUMBASS, static_cast(mpCharacter->GetTargetVehicle()) ); } Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); bool isDriver = mpCharacter->GetTargetVehicle()->HasDriver() ? false : true; Vehicle::Door door = (isDriver && !slide) ? Vehicle::DOOR_DRIVER : Vehicle::DOOR_PASSENGER; Action* pAction = 0; mpCharacter->GetTargetVehicle()->UpdateDoorState(); bool high = false; if(isDriver) { high = mpCharacter->GetTargetVehicle()->GetDriverLocation().y > CharacterTune::sGetInHeightThreshold; } else { high = mpCharacter->GetTargetVehicle()->GetPassengerLocation().y > CharacterTune::sGetInHeightThreshold; } const char** anims = NULL; if(high) { if(isDriver && !slide) { anims = sGetInHighDriver; } else { anims = sGetInHighPassenger; } } else { if(isDriver && !slide) { anims = sGetInDriver; } else { anims = sGetInPassenger; } } // add actions for all the get in waypoints for(int i = 0; i < nWaypoints; i++) { pSeq->BeginSequence(); pAction = new Arrive( mpCharacter, waypoints[i], i == nWaypoints - 1 ); pSeq->AddAction( pAction ); // SlaveLoco // pAction = 0; pAction = mpCharacter->GetWalkerLocomotionAction(); pSeq->AddAction( mpCharacter->GetWalkerLocomotionAction() ); pSeq->EndSequence( ); } // Orient // pSeq->BeginSequence(); rmt::Matrix mat = mpCharacter->GetTargetVehicle( )->GetTransform(); pAction = new Orient( mpCharacter, mat.Row( 2 ) ); pSeq->AddAction( pAction ); // SlaveLoco // pAction = 0; pAction = mpCharacter->GetWalkerLocomotionAction(); pSeq->AddAction( pAction ); pSeq->EndSequence( ); // Open Door Anim // if(mpCharacter->GetTargetVehicle()->NeedToOpenDoor(door)) { float delay = CharacterTune::sGetInOpenDelay; float time = CharacterTune::sGetInOpenSpeed; float scale = 30.0f / CharacterTune::sfGetInOutOfCarAnimSpeed; pSeq->BeginSequence(); pAction = new PlayAnimationAction( mpCharacter, anims[ 0 ], CharacterTune::sfGetInOutOfCarAnimSpeed); pSeq->AddAction( pAction ); pSeq->AddAction( new CarDoorAction(mpCharacter->GetTargetVehicle(), Vehicle::DOORACTION_OPEN, door, delay * scale, time * scale)); pSeq->EndSequence( ); } // Get In Car Anim // pSeq->BeginSequence(); pAction = new PlayAnimationAction( mpCharacter, anims[ 1 ], CharacterTune::sfGetInOutOfCarAnimSpeed); pSeq->AddAction( pAction ); pSeq->EndSequence( ); rmt::Vector seat; if(isDriver && !slide) { seat = mpCharacter->GetTargetVehicle()->GetDriverLocation(); } else { seat = mpCharacter->GetTargetVehicle()->GetPassengerLocation(); } pSeq->BeginSequence(); pSeq->AddAction( new ChangeLocomotion(mpCharacter, ChangeLocomotion::INCAR) ); pSeq->AddAction( new ChangeState(mpCharacter)); pSeq->AddAction( new TriggerEventAction(EVENT_GETINTOVEHICLE_END, mpCharacter)); pSeq->EndSequence( ); pSeq->BeginSequence(); pSeq->AddAction( new DelayAction(0.05f)); pSeq->EndSequence( ); pSeq->BeginSequence(); pSeq->AddAction( new Position(mpCharacter, seat, 0.0f, true)); pSeq->AddAction( new PlayAnimationAction( mpCharacter, "in_car_idle", 300.0f)); pSeq->EndSequence( ); // Close Door Anim // if(mpCharacter->GetTargetVehicle()->HasActiveDoor(door) || mpCharacter->GetTargetVehicle()->NeedToCloseDoor(door)) { float delay = CharacterTune::sGetInCloseDelay; float time = CharacterTune::sGetInCloseSpeed; float scale = 30.0f / CharacterTune::sfGetInOutOfCarAnimSpeed; pSeq->BeginSequence(); pAction = new PlayAnimationAction( mpCharacter, anims[ 2 ], CharacterTune::sfGetInOutOfCarAnimSpeed); pSeq->AddAction( new CarDoorAction(mpCharacter->GetTargetVehicle(), Vehicle::DOORACTION_CLOSE, door, delay * scale, time * scale)); pSeq->AddAction( pAction ); pSeq->EndSequence( ); } if(slide) { rmt::Vector seatDist = mpCharacter->GetTargetVehicle()->GetPassengerLocation() - mpCharacter->GetTargetVehicle()->GetDriverLocation(); bool seatClose = seatDist.Magnitude() < 0.1f; rmt::Vector v = mpCharacter->GetTargetVehicle()->GetPassengerLocation(); pSeq->BeginSequence(); pSeq->AddAction( new Position(mpCharacter, v, 0.0f, true)); pSeq->EndSequence( ); v = mpCharacter->GetTargetVehicle()->GetDriverLocation(); pSeq->BeginSequence(); pSeq->AddAction( new Position(mpCharacter, v, 0.5f, true)); if(!seatClose) { pSeq->AddAction( new PlayAnimationAction(mpCharacter, "seatmove")); } pSeq->EndSequence( ); if(mpCharacter->GetTargetVehicle()->NeedToCloseDoor(Vehicle::DOOR_DRIVER)) { float delay = CharacterTune::sGetInCloseDelay; float time = CharacterTune::sGetInCloseSpeed; float scale = 30.0f / CharacterTune::sfGetInOutOfCarAnimSpeed; pSeq->BeginSequence(); pAction = new PlayAnimationAction( mpCharacter, "get_into_car_close_door_driver", CharacterTune::sfGetInOutOfCarAnimSpeed); pSeq->AddAction( new CarDoorAction(mpCharacter->GetTargetVehicle(), Vehicle::DOORACTION_CLOSE, Vehicle::DOOR_DRIVER, delay * scale, time * scale)); pSeq->AddAction( pAction ); pSeq->EndSequence( ); } } pSeq->BeginSequence(); pSeq->AddAction( new ReleaseDoorsAction(mpCharacter->GetTargetVehicle())); pSeq->EndSequence( ); } else { //Do an iris wipe in GetGuiSystem()->HandleMessage( GUI_MSG_START_IRIS_WIPE_CLOSE ); //Set the speed of the wipe CGuiScreenIrisWipe* iw = static_cast(GetGuiSystem()->GetInGameManager()->FindWindowByID( CGuiWindow::GUI_SCREEN_ID_IRIS_WIPE )); const float speed = 1.0f; iw->SetRelativeSpeed( speed ); //add listener GetEventManager()->AddListener( this, EVENT_GUI_IRIS_WIPE_CLOSED ); //Pause gameplay GetGameFlow()->GetContext( CONTEXT_GAMEPLAY )->Suspend(); } } void GetIn::HandleEvent( EventEnum id, void* pUserData ) { if ( id == EVENT_GUI_IRIS_WIPE_CLOSED ) { mpCharacter->RemoveFromPhysics(); GetEventManager()->RemoveListener( this, EVENT_GUI_IRIS_WIPE_CLOSED ); Vehicle* pVehicle = mpCharacter->GetTargetVehicle(); rAssert( pVehicle ); rmt::Vector pos; pVehicle->GetPosition( &pos ); GetAvatarManager()->PutCharacterInCar( mpCharacter, pVehicle ); if(!pVehicle->mVisibleCharacters) { mpCharacter->RemoveFromWorldScene(); } GetSuperCamManager()->GetSCC( 0 )->SelectSuperCam( SuperCam::FOLLOW_CAM, SuperCamCentral::CUT, 0 ); //Override the auto one //TODO: SWITCH MODELS //Wipe out when we are finished moving. GetGuiSystem()->HandleMessage( GUI_MSG_START_IRIS_WIPE_OPEN ); GetGameFlow()->GetContext( CONTEXT_GAMEPLAY )->Resume(); GetEventManager()->TriggerEvent( EVENT_GETINTOVEHICLE_END, mpCharacter ); pVehicle->MoveDoor(Vehicle::DOOR_DRIVER, Vehicle::DOORACTION_CLOSE, 0.0f); pVehicle->MoveDoor(Vehicle::DOOR_PASSENGER, Vehicle::DOORACTION_CLOSE, 0.0f); } } // figure out how to get into the car from an arbitrary location void GetIn::CalcGetInPath(int* nWaypoints, rmt::Vector* waypoints, bool* doingSlide, bool* jump) { const float origedge = 0.75f; // how far want to be from the car at the nav points ( TODO : make this tunable?) const float edge = origedge / 1.414f; // x & z need to be sacled by sqrt(2) to make the diagonal distance right ; rmt::Vector box = mpCharacter->GetTargetVehicle()->GetExtents(); bool isDriver = mpCharacter->GetTargetVehicle()->HasDriver() ? false : true; // grab matrices to get from car space to world space (we do all our work in car space) rmt::Matrix carToWorld = mpCharacter->GetTargetVehicle( )->GetTransform(); rmt::Matrix worldToCar = mpCharacter->GetTargetVehicle( )->GetTransform(); worldToCar.Invert(); // get character position in car space rmt::Vector characterPosition; mpCharacter->GetPosition(characterPosition); characterPosition.Transform(worldToCar); *doingSlide = false; *jump = false; *nWaypoints = 0; if((characterPosition.y > (-box.y / 2)) && (characterPosition.x < box.x) && (characterPosition.x > -box.x) && (characterPosition.z < box.z) && (characterPosition.z > -box.z)) { // get in position (car space) rmt::Vector getinPosition = CharacterTune::sGetInPosition; getinPosition = -getinPosition; getinPosition.Add(mpCharacter->GetTargetVehicle( )->GetDriverLocation()); // swap get in poistion for driver characterPosition.x = getinPosition.x - 0.5f; // add final get in position to waypoints characterPosition.Transform( carToWorld ); waypoints[(*nWaypoints)++] = characterPosition; *jump = true; return; } if(isDriver && mpCharacter->GetTargetVehicle()->mAllowSlide) { rmt::Vector driverPosition = CharacterTune::sGetInPosition; driverPosition.x = -driverPosition .x; driverPosition.Add(mpCharacter->GetTargetVehicle( )->GetDriverLocation()); rmt::Vector passPosition = CharacterTune::sGetInPosition; passPosition.Add(mpCharacter->GetTargetVehicle( )->GetPassengerLocation()); driverPosition.Sub(characterPosition); passPosition.Sub(characterPosition); if(characterPosition.x > (box.x - 0.5f)) { isDriver = false; *doingSlide = true; } } // these are the edges of the car from a walking perspective float carFront = box.z + (edge); float carRear = -box.z - (edge);; float carNearSide = (box.x + edge) * (isDriver ? -1 : 1); float carFarSide = (box.x + edge) * (isDriver ? 1 : -1); // get in position (car space) rmt::Vector getinPosition = CharacterTune::sGetInPosition; // swap get in poistion for driver if ( isDriver ) { // mirror over x. getinPosition.x = -getinPosition.x; getinPosition.Add(mpCharacter->GetTargetVehicle( )->GetDriverLocation()); } else { getinPosition.Add(mpCharacter->GetTargetVehicle( )->GetPassengerLocation()); } // are we in fron of the car or behind bool front = characterPosition.z > 0; bool onside = true; if(((characterPosition.z > box.z) || (characterPosition.z < -box.z)) && (isDriver ? (characterPosition.x > -(box.x - (edge / 2))) : (characterPosition.x < (box.x - (edge / 2))) )) { onside = false; } if(((characterPosition.z < box.z) && (characterPosition.z > -box.z)) && (isDriver ? (characterPosition.x > 0) : (characterPosition.x < 0))) { onside = false; } if(!onside) { // we are offside, need some more nav points // are we on the other side of the car if((characterPosition.z < box.z) && (characterPosition.z > -box.z)) { // add far corner to waypoints rmt::Vector tmpPosition(0,0,0); tmpPosition.z += front ? carFront : carRear; tmpPosition.x += carFarSide; tmpPosition.Transform( carToWorld ); waypoints[(*nWaypoints)++] = tmpPosition; } // add near corner to waypoints rmt::Vector tmpPosition(0,0,0); tmpPosition.z += front ? carFront : carRear; tmpPosition.x += carNearSide; tmpPosition.Transform( carToWorld ); waypoints[(*nWaypoints)++] = tmpPosition; } // add final get in position to waypoints getinPosition.Transform( carToWorld ); waypoints[(*nWaypoints)++] = getinPosition; } void GetIn::SequenceAction( void ) { Enter(); } void GetIn::Update( float timeins ) { if(mpCharacter->CollidedThisFrame() && (mCollisionFailure == 0) && !mpCharacter->GetJumpLocomotionAction()->IsInJump()) { mObstructed = true; mpCharacter->GetActionController()->Clear(); Enter(); } if(mCollisionFailure) { mCollisionFailure--; } } void GetIn::Exit( void ) { if(!mpCharacter->GetTargetVehicle()->mVisibleCharacters) { mpCharacter->RemoveFromWorldScene(); } mpCharacter->GetWalkerLocomotionAction()->StopDriver(); mpCharacter->GetWalkerLocomotionAction()->Done();; } /* ============================================================================== GetOut ============================================================================== */ GetOut::GetOut( Character* pCharacter ) : State( pCharacter ), mObstructed(false), mFirst(true), mPanic(false) { } GetOut::~GetOut( void ) { } void GetOut::Enter( void ) { bool destroyed = !mpCharacter->GetTargetVehicle() || mpCharacter->GetTargetVehicle()->mVehicleDestroyed; bool iris = !destroyed && (mObstructed || mpCharacter->GetTargetVehicle()->mIrisTransition); if(mFirst) { mFirst = false; GetEventManager()->TriggerEvent( EVENT_GETOUTOFVEHICLE_START, mpCharacter ); } if ( !iris || mpCharacter != GetCharacterManager()->GetCharacter(0)) { mpCharacter->AddToWorldScene(); mpCharacter->SetScale(1.0f); DoGetOut(); } else { //Do an iris wipe in GetGuiSystem()->HandleMessage( GUI_MSG_START_IRIS_WIPE_CLOSE ); //Set the speed of the wipe CGuiScreenIrisWipe* iw = static_cast(GetGuiSystem()->GetInGameManager()->FindWindowByID( CGuiWindow::GUI_SCREEN_ID_IRIS_WIPE )); const float speed = 1.0f; iw->SetRelativeSpeed( speed ); //add listener GetEventManager()->AddListener( this, EVENT_GUI_IRIS_WIPE_CLOSED ); //Pause gameplay GetGameFlow()->GetContext( CONTEXT_GAMEPLAY )->Suspend(); if(mpCharacter->GetTargetVehicle()) { mpCharacter->GetTargetVehicle()->SetOutOfCarSimState(); } } } static sim::TArray< sim::RayIntersectionInfo > sIntersectInfo( 64 ); void GetOut::HandleEvent( EventEnum id, void* pUserData ) { if ( id == EVENT_GUI_IRIS_WIPE_CLOSED ) { GetEventManager()->RemoveListener( this, EVENT_GUI_IRIS_WIPE_CLOSED ); Character* character = GetAvatarManager()->GetAvatarForPlayer( 0 )->GetCharacter(); Vehicle* car = GetAvatarManager()->GetAvatarForPlayer( 0 )->GetVehicle(); GetEventManager()->TriggerEvent( EVENT_GETOUTOFVEHICLE_END, character ); car->MoveDoor(Vehicle::DOOR_DRIVER, Vehicle::DOORACTION_CLOSE, 0.0f); car->MoveDoor(Vehicle::DOOR_PASSENGER, Vehicle::DOORACTION_CLOSE, 0.0f); character->SetInCar( false ); character->SetTargetVehicle( NULL ); character->AddToWorldScene(); mpCharacter->SetScale(1.0f); // get in position (car space) rmt::Vector getOutPosition = CharacterTune::sGetInPosition; int isDriver = car->HasDriver() ? 0 : 1; if(!mObstructed) { // swap get in poistion for driver if ( isDriver ) { // mirror over x. getOutPosition.x = -getOutPosition.x; getOutPosition.Add( car->GetDriverLocation() ); } else { getOutPosition.Add( car->GetPassengerLocation() ); } getOutPosition.Transform( car->GetTransform() ); rmt::Vector carPos; car->GetPosition(&carPos); getOutPosition.y = carPos.y - car->GetExtents().y; // check if point we want to teleport to is objstructed sIntersectInfo.Clear(); float fOldRayThickness = sim::RayIntersectionInfo::sRayThickness; static float sfCharacterRayThickness = 0.3f; sim::RayIntersectionInfo::sRayThickness = sfCharacterRayThickness; bool bFoundIntersect = false; float outDist = VERY_LARGE; float currentDist = outDist; HeapMgr()->PushHeap( GMA_TEMP ); // adds in the list the collision object interfering with the ray and ordered according to their distance to the source. // use sim::RayIntersectionInfo::SetMethod(method) to set the method // use sim::RayIntersectionInfo::SetReturnClosestOnly(true/false) if you need only the closest object // nb. if SetReturnClosestOnly(true) is used, the previous returned list can be used as a cache. sim::RayIntersectionInfo::SetReturnClosestOnly( false ); sim::RayIntersectionInfo::SetMethod( sim::RayIntersectionVolume ); rmt::Vector rayOrg; mpCharacter->GetPosition(rayOrg); rmt::Vector rayEnd = getOutPosition; HeapMgr()->PopHeap( GMA_TEMP ); // Test ray against remaining collision objects. // GetWorldPhysicsManager()->mCollisionManager->DetectRayIntersection(sIntersectInfo, rayOrg, rayEnd, false, car->mCollisionAreaIndex ); for ( int i = 0; i < sIntersectInfo.GetSize( ); i++ ) { if ( sIntersectInfo[ i ].mCollisionVolume && (sIntersectInfo[ i ].mCollisionVolume->GetCollisionObject()->GetSimState()->mAIRefPointer != mpCharacter ) && (sIntersectInfo[ i ].mCollisionVolume->GetCollisionObject()->GetSimState()->mAIRefPointer != car )) { mObstructed = true; break; } } sim::RayIntersectionInfo::sRayThickness = fOldRayThickness; } if(mObstructed) { car->GetPosition(&getOutPosition); getOutPosition.y += car->GetExtents().y + 0.2f; } rmt::Vector facing = car->GetTransform().Row(0); if(isDriver) { facing.Scale(-1.0f); } GetAvatarManager()->PutCharacterOnGround( character, car ); character->RelocateAndReset( getOutPosition, choreo::GetWorldAngle(facing.x, facing.z), true, true ); character->SnapToGround(); rmt::Vector newPos; character->GetPosition(&newPos); float dist = mObstructed ? 3.0f : 1.0f; if(rmt::Abs(getOutPosition.y - newPos.y) > dist) { car->GetPosition(&getOutPosition); getOutPosition.y += car->GetExtents().y + 0.2f; character->RelocateAndReset( getOutPosition, choreo::GetWorldAngle(facing.x, facing.z), true, true ); } GetVehicleCentral()->ActivateVehicleTriggers(true); #ifdef RAD_WIN32 GetSuperCamManager()->GetSCC( 0 )->SelectSuperCam( SuperCam::ON_FOOT_CAM, SuperCamCentral::CUT, 0 ); #else GetSuperCamManager()->GetSCC( 0 )->SelectSuperCam( SuperCam::WALKER_CAM, SuperCamCentral::CUT, 0 ); #endif //Wipe out when we are finished moving. GetGuiSystem()->HandleMessage( GUI_MSG_START_IRIS_WIPE_OPEN ); GetGameFlow()->GetContext( CONTEXT_GAMEPLAY )->Resume(); } } void GetOut::Exit( void ) { } void GetOut::SequenceAction( void ) { Enter(); } void GetOut::Update( float timeins ) { if(mpCharacter->CollidedThisFrame() && !mPanic) { mObstructed = true; mpCharacter->GetActionController()->Clear(); Enter(); } } void GetOut::DoGetOut( void ) { mPanic = !mpCharacter->GetTargetVehicle() || mpCharacter->GetTargetVehicle()->mVehicleDestroyed; bool mIsDriver; if(mpCharacter->GetTargetVehicle()) { mIsDriver = (mpCharacter->GetTargetVehicle()->mpDriver == mpCharacter) || ((mpCharacter->GetTargetVehicle()->mVehicleType != VT_TRAFFIC) && (mpCharacter->GetTargetVehicle()->mpDriver == NULL)); } else { mIsDriver = false; } Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); if(mPanic) { mpCharacter->AddToWorldScene(); if(mpCharacter->GetRole() == Character::ROLE_DRIVER) { GetCharacterManager()->SetGarbage(mpCharacter, true); } mpCharacter->SetFacingDir( mIsDriver ? (rmt::PI / 2) : -(rmt::PI / 2)); mpCharacter->SetDesiredDir( mIsDriver ? (rmt::PI / 2) : -(rmt::PI / 2)); pSeq->BeginSequence(); pSeq->AddAction( new DelayAction(0.5f)); pSeq->EndSequence( ); pSeq->BeginSequence(); pSeq->AddAction( new GroundSnap(mpCharacter)); pSeq->EndSequence( ); pSeq->BeginSequence(); pSeq->AddAction( new ChangeLocomotion(mpCharacter, ChangeLocomotion::WALKING) ); pSeq->EndSequence( ); pSeq->BeginSequence(); pSeq->AddAction( new DodgeAction(mpCharacter) ); pSeq->EndSequence( ); pSeq->BeginSequence(); pSeq->AddAction( new ChangeState(mpCharacter)); pSeq->AddAction( new TriggerEventAction(EVENT_GETOUTOFVEHICLE_END, mpCharacter)); pSeq->EndSequence( ); } else { int isDriver = mpCharacter->GetTargetVehicle()->HasDriver() ? 0 : 1; Vehicle::Door door = isDriver ? Vehicle::DOOR_DRIVER : Vehicle::DOOR_PASSENGER; Action* pAction = 0; mpCharacter->GetTargetVehicle()->UpdateDoorState(); bool high = true; rmt::Vector seat; if(isDriver) { high = mpCharacter->GetTargetVehicle()->GetDriverLocation().y > CharacterTune::sGetInHeightThreshold; seat = mpCharacter->GetTargetVehicle()->GetDriverLocation(); } else { high = mpCharacter->GetTargetVehicle()->GetPassengerLocation().y > CharacterTune::sGetInHeightThreshold; seat = mpCharacter->GetTargetVehicle()->GetPassengerLocation(); } const char** anims = NULL; if(high) { if(isDriver) { anims = sGetOutHighDriver; } else { anims = sGetOutHighPassenger; } } else { if(isDriver) { anims = sGetOutDriver; } else { anims = sGetOutPassenger; } } Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); pSeq->AddAction( new DelayAction(0.1f)); pSeq->EndSequence( ); pSeq->BeginSequence(); pSeq->AddAction( new Position(mpCharacter, seat, 0.0f, true)); pSeq->EndSequence( ); // Play get_out_of_car_open_door if(mpCharacter->GetTargetVehicle()->NeedToOpenDoor(door)) { float delay = CharacterTune::sGetOutOpenDelay; float time = CharacterTune::sGetOutOpenSpeed; float scale = 30.0f / CharacterTune::sfGetInOutOfCarAnimSpeed; pSeq->BeginSequence(); pAction = new PlayAnimationAction( mpCharacter, anims[ 0 ], CharacterTune::sfGetInOutOfCarAnimSpeed ); pSeq->AddAction( new CarDoorAction(mpCharacter->GetTargetVehicle(), Vehicle::DOORACTION_OPEN, door, delay * scale, time * scale)); pSeq->AddAction( pAction ); pSeq->EndSequence( ); } if(0) { pSeq->BeginSequence(); pSeq->AddAction( new DelayAction(2.0f)); pSeq->EndSequence( ); } // Play get_out_of_car // pSeq->BeginSequence(); pSeq->AddAction( new ChangeLocomotion(mpCharacter, ChangeLocomotion::WALKING) ); pSeq->EndSequence( ); if(0) { pSeq->BeginSequence(); pSeq->AddAction( new DelayAction(0.5f)); pSeq->EndSequence( ); } pSeq->BeginSequence(); pSeq->AddAction( new GroundSnap(mpCharacter)); pAction = new PlayAnimationAction( mpCharacter, anims[ 1 ], CharacterTune::sfGetInOutOfCarAnimSpeed); pSeq->AddAction( pAction ); pSeq->EndSequence( ); if(0) { pSeq->BeginSequence(); pSeq->AddAction( new DelayAction(2.0f)); pSeq->EndSequence( ); } pSeq->BeginSequence(); pSeq->AddAction( new ChangeState(mpCharacter)); pSeq->AddAction( new TriggerEventAction(EVENT_GETOUTOFVEHICLE_END, mpCharacter)); // Play get_out_of_car_close_door if(mpCharacter->GetTargetVehicle()->HasActiveDoor(door)) { float delay = CharacterTune::sGetOutCloseDelay; float time = CharacterTune::sGetOutCloseSpeed; float scale = 30.0f / CharacterTune::sfGetInOutOfCarAnimSpeed; PlayAnimationAction* pAction = new PlayAnimationAction( mpCharacter, anims [ 2 ], CharacterTune::sfGetInOutOfCarAnimSpeed); pAction->AbortWhenMovementOccurs(true); pSeq->AddAction( new CarDoorAction(mpCharacter->GetTargetVehicle(), Vehicle::DOORACTION_CLOSE, door, delay * scale, time * scale, mpCharacter, pSeq)); pSeq->AddAction( pAction ); } pSeq->EndSequence( ); } } /* ============================================================================== InSim::InSim ============================================================================== Description: Comment Parameters( Character* pCharacter ) Returns: ============================================================================= */ InSim::InSim( Character* pCharacter ) : State( pCharacter ) { } InSim::~InSim( void ) { } void InSim::Enter( void ) { // clear previous actions mpCharacter->GetActionController()->Clear(); // Sequence in the flail and get-up actions Sequencer* pSeq = mpCharacter->GetActionController()->GetNextSequencer(); pSeq->BeginSequence(); pSeq->AddAction( new FlailAction( mpCharacter ) ); pSeq->EndSequence(); pSeq->BeginSequence(); pSeq->AddAction( new GetUpAction( mpCharacter ) ); pSeq->EndSequence(); /* pSeq->BeginSequence(); pSeq->AddAction( new ChangeState( mpCharacter ) ); pSeq->EndSequence(); */ return; } void InSim::Exit( void ) { } void InSim::SequenceAction( void ) { // SequenceAction gets called when no other actions are left to do. // In this state, it means that we're just done "getting up"... // so time to transit back to Loco state... mpCharacter->GetStateManager()->SetState(); } void InSim::Update( float timeins ) { } };