The-Simpsons-Hit-and-Run/game/code/ai/actor/ufobehaviour.cpp

378 lines
13 KiB
C++

//===========================================================================
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
//
// Component: ufobehaviour
//
// Description:
//
//
// Authors: Michael Riegger
//
//===========================================================================
//---------------------------------------------------------------------------
// Includes
//===========================================================================
#include <ai\actor\ufobehaviour.h>
#include <ai\actor\actor.h>
#include <ai\actor\flyingactor.h>
#include <worldsim\redbrick\vehicle.h>
#include <worldsim\vehiclecentral.h>
#include <render/rendermanager/worldrenderlayer.h>
#include <render/rendermanager/rendermanager.h>
#include <meta/eventlocator.h>
#include <worldsim/character/character.h>
#include <render/breakables/breakablesmanager.h>
#include <radtime.hpp>
#include <worldsim/avatarmanager.h>
#include <mission/statepropcollectible.h>
#include <camera/supercammanager.h>
#include <mission/gameplaymanager.h>
#include <camera/supercamcentral.h>
#include <ai/state.h>
#include <ai/statemanager.h>
#include <worldsim/character/character.h>
#include <worldsim/character/charactercontroller.h>
#include <worldsim/character/charactermanager.h>
#include <ai/sequencer/action.h>
#include <ai/sequencer/actioncontroller.h>
#include <ai/sequencer/sequencer.h>
//===========================================================================
// Local Constants, Typedefs, and Macros
//===========================================================================
// How fast objects move up the beam
const float TRACTOR_BEAM_SUCK_SPEED = 0.003f;
// How close an object being sucked up has to be to the center before it gets sucked up forever
const float UFO_TRACTOR_BEAM_DISAPPEAR_RADIUS_SQR = 25.0f;
const float UFO_TRACTOR_BEAM_RADIUS = 7.5f;
const float UFO_TRACTOR_BEAM_RADIUS_SQR = UFO_TRACTOR_BEAM_RADIUS * UFO_TRACTOR_BEAM_RADIUS;
// The cosine of the angle of the tractor beam
const float TRACTOR_BEAM_ANGLE_COS = 0.94f;
//===========================================================================
// Global Data, Local Data, Local Classes
//===========================================================================
//===========================================================================
// Member Functions
//===========================================================================
UFOBehaviour::UFOBehaviour() :
m_Rotation( 0 )
{
// Lets just make a default respawn position until the designers script one in.
m_RespawnLocator = new EventLocator();
m_RespawnLocator->AddRef();
}
UFOBehaviour::~UFOBehaviour()
{
if ( m_RespawnLocator != NULL )
{
m_RespawnLocator->Release();
m_RespawnLocator = NULL;
}
}
void
UFOBehaviour::Apply( Actor* actor, unsigned int timeInMS )
{
}
void
UFOBehaviour::SetCharacterRespawnPosition( EventLocator* locator )
{
rmt::Vector respawnLocation;
locator->GetLocation( &respawnLocation );
rmt::Matrix matrix;
m_RespawnLocator->SetMatrix( locator->GetMatrix() );
m_RespawnLocator->SetLocation( respawnLocation );
m_RespawnLocator->SetEventType( LocatorEvent::DEATH );
}
bool
UFOBehaviour::WithinTractorBeamRange( const rmt::Vector& position, IEntityDSG* dsg )const
{
if ( dsg == NULL )
return false;
bool withinRange;
rmt::Vector targetPos;
dsg->GetPosition( &targetPos );
// Compare distance in x and z only
float deltaX = targetPos.x - position.x;
float deltaZ = targetPos.z - position.z;
float distSqr = (deltaX*deltaX) + (deltaZ*deltaZ);
if ( distSqr < UFO_TRACTOR_BEAM_RADIUS_SQR )
{
withinRange = true;
}
else
{
withinRange = false;
}
return withinRange;
}
bool
UFOBehaviour::SuckIntoUFO( const rmt::Vector& actorPosition, DynaPhysDSG* pDSG, float timeInMS )
{
bool wasSucked;
sim::SimState* simstate = pDSG->GetSimState();
if ( simstate == NULL )
return false;
const rmt::Matrix& transform = simstate->GetTransform();
const rmt::Vector& objectPos = transform.Row(3);
rmt::Vector toTopOfBeam = actorPosition - objectPos;
toTopOfBeam.Normalize();
// Move position upwards
rmt::Vector velocityVector = timeInMS * TRACTOR_BEAM_SUCK_SPEED * toTopOfBeam;
// Apply a rotation
// rmt::Vector rotationAxis = GetPseudoRandomRotationAxis( reinterpret_cast< int >( pDSG ) );
//
// rmt::Matrix rotationMatrix;
// rotationMatrix.Identity();
// rotationMatrix.FillRotation( rotationAxis, timeInMS * 0.001f );
//rmt::Matrix translation;
//translation.Identity();
// translation.FillTranslate( velocityVector );
rmt::Matrix newTransform = transform;
newTransform.Row(3) += velocityVector;
// newTransform.Mult( rotationMatrix );
int aiRef = pDSG->GetAIRef();
switch (aiRef)
{
case PhysicsAIRef::redBrickVehicle:
{
rAssert( dynamic_cast< Vehicle* >( pDSG ) != NULL );
Vehicle* vehicle = static_cast< Vehicle* >( pDSG );
// Don't let the chase cars get sucked up (JeffP)
if ( vehicle->mVehicleID != VehicleEnum::CBLBART && vehicle->IsVehicleDestroyed() == false
&& vehicle->mVehicleID != VehicleEnum::HUSKA )
{
pDSG->GetSimState()->ResetVelocities();
vehicle->SetTransform( newTransform );
vehicle->SetSimpleShadow( false );
wasSucked = true;
// If we are in bumper cam, we need to force out.
SuperCamCentral* scc = GetSuperCamManager()->GetSCC(0);
if(scc->GetActiveSuperCam()->GetType() == SuperCam::BUMPER_CAM)
{
// Need to switch out of bumper cam.
scc->SelectSuperCam( SuperCam::FAR_FOLLOW_CAM, SuperCamCentral::FORCE | SuperCamCentral::CUT, 0 );
}
if(vehicle->IsUserDrivingCar())
{
Character* c = GetAvatarManager()->GetAvatarForPlayer(0)->GetCharacter();
if(c)
{
c->GetActionController()->Clear();
c->GetStateManager()->SetState<CharacterAi::GetOut>();
}
}
}
else
{
wasSucked = false;
}
}
break;
default:
wasSucked = false;
break;
}
return wasSucked;
}
bool
UFOBehaviour::ReachedTopOfTractorBeam( const rmt::Vector& actorPosition, DynaPhysDSG* pDSG )
{
bool atTop;
rmt::Vector objectPos;
pDSG->GetPosition( &objectPos );
float distToTop = ( actorPosition - objectPos ).MagnitudeSqr();
if ( distToTop < UFO_TRACTOR_BEAM_DISAPPEAR_RADIUS_SQR )
{
atTop = true;
}
else
{
atTop = false;
}
return atTop;
}
bool
UFOBehaviour::DestroyObject( DynaPhysDSG* object )
{
bool damagedUFO = false;
// We need to destroy the object. Perform any cleanup activities required for specific vehicle
// type
int airef = object->GetAIRef();
switch ( airef )
{
case PhysicsAIRef::ActorStateProp:
break;
case PhysicsAIRef::PlayerCharacter:
{
//- GetEventManager()->TriggerEvent( (EventEnum)(EVENT_LOCATOR + LocatorEvent::DEATH) , NULL );
assert(dynamic_cast<Character*>(object));
GetEventManager()->TriggerEvent( EVENT_ABDUCTED, static_cast<Character*>(object) );
if ( !GetAvatarManager()->IsAvatarGettingInOrOutOfCar( 0 ) )
{
// Lets set a default spawn position since the designers aren't here
SetCharacterRespawnPosition( p3d::find< EventLocator >( "Z3D1" ) );
// Character* character = GetAvatarManager()->GetAvatarForPlayer(0)->GetCharacter();
// rAssert( character!= NULL );
// GetAvatarManager()->PutCharacterOnGround(character, vehicle);
m_RespawnLocator->Trigger( 0, true );
}
}
break;
case PhysicsAIRef::redBrickPhizMoveable:
case PhysicsAIRef::StateProp:
case PhysicsAIRef::redBrickPhizMoveableAnim:
// Remove the dynaphys object from the worldsim
{
WorldRenderLayer* pWorldRenderLayer = static_cast< WorldRenderLayer* > (GetRenderManager()->mpLayer( RenderEnums::LevelSlot ));
// Sanity check
rAssert( dynamic_cast<WorldRenderLayer*>(pWorldRenderLayer) != NULL );
pWorldRenderLayer->pWorldScene()->Remove( object );
}
break;
case PhysicsAIRef::redBrickVehicle:
{
rAssert( dynamic_cast< Vehicle* >( object ) != NULL );
Vehicle* vehicle = static_cast< Vehicle* >( object );
// Ok, there are two cases. One is that the vehicle is a player vehicle
// the other is that it is not.
// If the object is a player vehicle
bool characterAbducted = false;
if ( vehicle->IsUserDrivingCar() && vehicle->GetDriver() != NULL && !GetAvatarManager()->IsAvatarGettingInOrOutOfCar( 0 ))
{
// Player got sucked up, better tell, someone. ( NotAbductedCondition uses this )
GetEventManager()->TriggerEvent( EVENT_ABDUCTED, vehicle->GetDriver() );
characterAbducted = true;
// Lets set a default spawn position since the designers aren't here
SetCharacterRespawnPosition( p3d::find< EventLocator >( "Z3D1" ) );
Character* character = GetAvatarManager()->GetAvatarForPlayer(0)->GetCharacter();
rAssert( character!= NULL );
GetAvatarManager()->PutCharacterOnGround(character, vehicle);
m_RespawnLocator->Trigger( 0, true );
}
else
{
vehicle->TriggerDamage( FLT_MAX, false );
}
StatePropCollectible* collectible = vehicle->GetAttachedCollectible();
if ( collectible != NULL )
{
vehicle->DetachCollectible(rmt::Vector(0,0,0), false );
collectible->RemoveFromDSG();
// The vehicle is carrying a collectible.
// Well, there is only one type of collectible in the game
// i.e. the exploding barrels
// so trigger a boss damaged event
// later we may want to switch on collectible type
GetEventManager()->TriggerEvent( EVENT_BOSS_DAMAGED, NULL );
// Note that the FMVs show the vehicle just disappearing, not being blown
// up, so lets just make it go away via RemoveVehicleFromActiveList
GetVehicleCentral()->RemoveVehicleFromActiveList( vehicle );
damagedUFO = true;
}
else
{
// The vehicle is not carrying anything
// So the UFO ate the player's vehicle
// signal the destroybossobjective object that
// the mission has failed
}
rmt::Matrix transform;
transform.Identity();
transform.FillTranslate( object->rPosition() );
GetBreakablesManager()->Play( BreakablesEnum::eCarExplosion, transform );
GetEventManager()->TriggerEvent( EVENT_BIG_BOOM_SOUND, vehicle );
GetEventManager()->TriggerEvent( EVENT_BIG_BOOM_SOUND, vehicle );
}
break;
default:
break;
}
return damagedUFO;
}
void
UFOBehaviour::GetTargetsInTractorRange( rmt::Vector& actorPosition, float maxRange, SwapArray< DynaPhysDSG* >* targetList )
{
targetList->ClearUse();
ReserveArray< DynaPhysDSG* > dynaPhysList(20);
GetIntersectManager()->FindDynaPhysElems( actorPosition, maxRange, dynaPhysList );
// Copy all the characters into the array
for ( int i = 0 ; i < dynaPhysList.mUseSize ; i++ )
{
// Do an angle check to see that its inside the cone formed by the tractor beam
rmt::Vector targetPosition;
dynaPhysList[ i ]->GetPosition( &targetPosition );
rmt::Vector toTarget = targetPosition - actorPosition;
toTarget.Normalize();
// Vector straight down, which is the direction that the tractor beam
// will be facing
rmt::Vector down( 0, -1.0f, 0 );
float distanceToObject = toTarget.MagnitudeSqr();
if ( toTarget.Dot( down ) > TRACTOR_BEAM_ANGLE_COS )
{
targetList->Add( dynaPhysList[i] );
}
}
}
rmt::Vector
UFOBehaviour::GetPseudoRandomRotationAxis( int hash )const
{
unsigned int timeInSec = radTimeGetSeconds();
rmt::Vector axis;
axis.x = static_cast< float >( timeInSec & 0xF0 );
axis.y = static_cast< float >( timeInSec & 0xF00 );
axis.z = static_cast< float >( timeInSec & 0xF000 );
axis.x -= 8.0f;
axis.y -= 8.0f;
axis.z -= 8.0f;
axis.Normalize();
return axis;
}