3290 lines
75 KiB
C++
3290 lines
75 KiB
C++
|
#include "../idlib/precompiled.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "Game_local.h"
|
||
|
#include "spawner.h"
|
||
|
|
||
|
const idEventDef EV_OnAcceleration( "<onAcceleration>" );
|
||
|
const idEventDef EV_OnDeceleration( "<onDeceleration>" );
|
||
|
const idEventDef EV_OnCruising( "<onCruising>" );
|
||
|
|
||
|
const idEventDef EV_OnStartMoving( "<onStartMoving>" );
|
||
|
const idEventDef EV_OnStopMoving( "<onStopMoving>" );
|
||
|
|
||
|
//=======================================================
|
||
|
//
|
||
|
// rvPhysics_Spline
|
||
|
//
|
||
|
//=======================================================
|
||
|
CLASS_DECLARATION( idPhysics_Base, rvPhysics_Spline )
|
||
|
EVENT( EV_PostRestore, rvPhysics_Spline::Event_PostRestore )
|
||
|
END_CLASS
|
||
|
|
||
|
void splinePState_t::ApplyAccelerationDelta( float timeStepSec ) {
|
||
|
speed = SignZero(idealSpeed) * Min( idMath::Fabs(idealSpeed), idMath::Fabs(speed) + acceleration * timeStepSec );
|
||
|
}
|
||
|
|
||
|
void splinePState_t::ApplyDecelerationDelta( float timeStepSec ) {
|
||
|
speed = SignZero(speed) * Max( idMath::Fabs(idealSpeed), idMath::Fabs(speed) - deceleration * timeStepSec );
|
||
|
}
|
||
|
|
||
|
void splinePState_t::UpdateDist( float timeStepSec ) {
|
||
|
dist += speed * timeStepSec;
|
||
|
}
|
||
|
|
||
|
bool splinePState_t::ShouldAccelerate() const {
|
||
|
if( Sign(idealSpeed) == Sign(speed) ) {
|
||
|
return idMath::Fabs(speed) < idMath::Fabs(idealSpeed);
|
||
|
} else if( !Sign(speed) ) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool splinePState_t::ShouldDecelerate() const {
|
||
|
if( Sign(speed) == Sign(idealSpeed) ) {
|
||
|
return idMath::Fabs(speed) > idMath::Fabs(idealSpeed);
|
||
|
} else if( !Sign(idealSpeed) ) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void splinePState_t::Clear() {
|
||
|
origin.Zero();
|
||
|
localOrigin.Zero();
|
||
|
axis.Identity();
|
||
|
localAxis.Identity();
|
||
|
speed = 0.0f;
|
||
|
idealSpeed = 0.0f;
|
||
|
dist = 0.0f;
|
||
|
acceleration = 0.0f;
|
||
|
deceleration = 0.0f;
|
||
|
}
|
||
|
|
||
|
void splinePState_t::WriteToSnapshot( idBitMsgDelta &msg ) const {
|
||
|
msg.WriteDeltaVec3( vec3_zero, origin );
|
||
|
msg.WriteDeltaVec3( vec3_zero, localOrigin );
|
||
|
msg.WriteDeltaMat3( mat3_identity, axis );
|
||
|
msg.WriteDeltaMat3( mat3_identity, localAxis );
|
||
|
msg.WriteDeltaFloat( 0.0f, speed );
|
||
|
msg.WriteDeltaFloat( 0.0f, idealSpeed );
|
||
|
msg.WriteDeltaFloat( 0.0f, dist );
|
||
|
msg.WriteDeltaFloat( 0.0f, acceleration );
|
||
|
msg.WriteDeltaFloat( 0.0f, deceleration );
|
||
|
}
|
||
|
|
||
|
void splinePState_t::ReadFromSnapshot( const idBitMsgDelta &msg ) {
|
||
|
origin = msg.ReadDeltaVec3( vec3_zero );
|
||
|
localOrigin = msg.ReadDeltaVec3( vec3_zero );
|
||
|
axis = msg.ReadDeltaMat3( mat3_identity );
|
||
|
localAxis = msg.ReadDeltaMat3( mat3_identity );
|
||
|
speed = msg.ReadDeltaFloat( 0.0f );
|
||
|
idealSpeed = msg.ReadDeltaFloat( 0.0f );
|
||
|
dist = msg.ReadDeltaFloat( 0.0f );
|
||
|
acceleration = msg.ReadDeltaFloat( 0.0f );
|
||
|
deceleration = msg.ReadDeltaFloat( 0.0f );
|
||
|
}
|
||
|
|
||
|
void splinePState_t::Save( idSaveGame *savefile ) const {
|
||
|
savefile->WriteVec3( origin );
|
||
|
savefile->WriteVec3( localOrigin );
|
||
|
savefile->WriteMat3( axis );
|
||
|
savefile->WriteMat3( localAxis );
|
||
|
savefile->WriteFloat( speed );
|
||
|
savefile->WriteFloat( idealSpeed );
|
||
|
savefile->WriteFloat( dist );
|
||
|
savefile->WriteFloat( acceleration );
|
||
|
savefile->WriteFloat( deceleration );
|
||
|
}
|
||
|
|
||
|
void splinePState_t::Restore( idRestoreGame *savefile ) {
|
||
|
savefile->ReadVec3( origin );
|
||
|
savefile->ReadVec3( localOrigin );
|
||
|
savefile->ReadMat3( axis );
|
||
|
savefile->ReadMat3( localAxis );
|
||
|
savefile->ReadFloat( speed );
|
||
|
savefile->ReadFloat( idealSpeed );
|
||
|
savefile->ReadFloat( dist );
|
||
|
savefile->ReadFloat( acceleration );
|
||
|
savefile->ReadFloat( deceleration );
|
||
|
}
|
||
|
|
||
|
splinePState_t& splinePState_t::Assign( const splinePState_t* state ) {
|
||
|
SIMDProcessor->Memcpy( this, state, sizeof(splinePState_t) );
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
splinePState_t& splinePState_t::operator=( const splinePState_t& state ) {
|
||
|
return Assign( &state );
|
||
|
}
|
||
|
|
||
|
splinePState_t& splinePState_t::operator=( const splinePState_t* state ) {
|
||
|
return Assign( state );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::rvPhysics_Spline
|
||
|
================
|
||
|
*/
|
||
|
rvPhysics_Spline::rvPhysics_Spline( void ) {
|
||
|
accelDecelStateThread.SetName( "AccelDecel" );
|
||
|
accelDecelStateThread.SetOwner( this );
|
||
|
accelDecelStateThread.SetState( "Cruising" );
|
||
|
|
||
|
clipModel = NULL;
|
||
|
|
||
|
spline = NULL;
|
||
|
SetSplineEntity( NULL );
|
||
|
|
||
|
memset( &pushResults, 0, sizeof(trace_t) );
|
||
|
pushResults.fraction = 1.0f;
|
||
|
|
||
|
current.Clear();
|
||
|
SaveState();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::~rvPhysics_Spline
|
||
|
================
|
||
|
*/
|
||
|
rvPhysics_Spline::~rvPhysics_Spline( void ) {
|
||
|
SAFE_DELETE_PTR( clipModel );
|
||
|
|
||
|
SAFE_DELETE_PTR( spline );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::Save
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::Save( idSaveGame *savefile ) const {
|
||
|
|
||
|
current.Save( savefile );
|
||
|
saved.Save( savefile );
|
||
|
|
||
|
savefile->WriteFloat( splineLength );
|
||
|
// This spline was retored as NULL, so there's no reason to save it.
|
||
|
//savefile->WriteInt(spline != NULL ? spline->GetTime( 0 ) : -1 ); // cnicholson: Added unsaved var
|
||
|
splineEntity.Save( savefile );
|
||
|
|
||
|
savefile->WriteTrace( pushResults );
|
||
|
|
||
|
savefile->WriteClipModel( clipModel );
|
||
|
|
||
|
accelDecelStateThread.Save( savefile );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::Restore
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::Event_PostRestore( void ) {
|
||
|
|
||
|
if( splineEntity.IsValid() ) {
|
||
|
spline = splineEntity->GetSpline();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void rvPhysics_Spline::Restore( idRestoreGame *savefile ) {
|
||
|
|
||
|
current.Restore( savefile );
|
||
|
saved.Restore( savefile );
|
||
|
|
||
|
savefile->ReadFloat( splineLength );
|
||
|
SAFE_DELETE_PTR( spline );
|
||
|
splineEntity.Restore( savefile );
|
||
|
|
||
|
savefile->ReadTrace( pushResults );
|
||
|
|
||
|
savefile->ReadClipModel( clipModel );
|
||
|
|
||
|
accelDecelStateThread.Restore( savefile, this );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SetClipModel
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetClipModel( idClipModel *model, const float density, int id, bool freeOld ) {
|
||
|
|
||
|
assert( self );
|
||
|
assert( model ); // we need a clip model
|
||
|
|
||
|
if ( clipModel && clipModel != model && freeOld ) {
|
||
|
delete clipModel;
|
||
|
}
|
||
|
|
||
|
clipModel = model;
|
||
|
|
||
|
LinkClip();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetClipModel
|
||
|
================
|
||
|
*/
|
||
|
idClipModel *rvPhysics_Spline::GetClipModel( int id ) const {
|
||
|
return clipModel;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SetContents
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetContents( int contents, int id ) {
|
||
|
clipModel->SetContents( contents );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetContents
|
||
|
================
|
||
|
*/
|
||
|
int rvPhysics_Spline::GetContents( int id ) const {
|
||
|
return clipModel->GetContents();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetBounds
|
||
|
================
|
||
|
*/
|
||
|
const idBounds &rvPhysics_Spline::GetBounds( int id ) const {
|
||
|
return clipModel->GetBounds();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetAbsBounds
|
||
|
================
|
||
|
*/
|
||
|
const idBounds &rvPhysics_Spline::GetAbsBounds( int id ) const {
|
||
|
return clipModel->GetAbsBounds();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SetSpline
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetSpline( idCurve_Spline<idVec3>* spline ) {
|
||
|
SAFE_DELETE_PTR( this->spline );
|
||
|
|
||
|
//Keep any left over dist from last spline to minimize hitches
|
||
|
if( GetSpeed() >= 0.0f ) {
|
||
|
current.dist = Max( 0.0f, current.dist - splineLength );
|
||
|
}
|
||
|
|
||
|
if( !spline ) {
|
||
|
splineLength = 0.0f;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this->spline = spline;
|
||
|
|
||
|
splineLength = spline->GetLengthForTime( spline->GetTime(spline->GetNumValues() - 1) );
|
||
|
if( GetSpeed() < 0.0f ) {
|
||
|
current.dist = splineLength - current.dist;
|
||
|
}
|
||
|
|
||
|
Activate();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SetSplineEntity
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetSplineEntity( idSplinePath* spline ) {
|
||
|
splineEntity = spline;
|
||
|
SetSpline( (spline) ? spline->GetSpline() : NULL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::ComputeDecelFromSpline
|
||
|
================
|
||
|
*/
|
||
|
float rvPhysics_Spline::ComputeDecelFromSpline() const {
|
||
|
// FIXME: merge this in better. It seems very special case
|
||
|
float numerator = GetSpeed() * GetSpeed();
|
||
|
float denomonator = 2.0f * ((GetSpeed() >= 0.0f) ? (splineLength - current.dist) : current.dist);
|
||
|
|
||
|
assert( denomonator > VECTOR_EPSILON );
|
||
|
|
||
|
return numerator / denomonator;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SetLinearAcceleration
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetLinearAcceleration( const float accel ) {
|
||
|
current.acceleration = accel;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SetLinearDeceleration
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetLinearDeceleration( const float decel ) {
|
||
|
current.deceleration = decel;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SetSpeed
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetSpeed( float speed ) {
|
||
|
if( IsAtRest() || StoppedMoving() ) {
|
||
|
current.dist = (speed < 0.0f) ? splineLength - current.dist : current.dist;
|
||
|
}
|
||
|
|
||
|
current.idealSpeed = speed;
|
||
|
Activate();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetSpeed
|
||
|
================
|
||
|
*/
|
||
|
float rvPhysics_Spline::GetSpeed() const {
|
||
|
return current.speed;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::Evaluate
|
||
|
================
|
||
|
*/
|
||
|
bool rvPhysics_Spline::Evaluate( int timeStepMSec, int endTimeMSec ) {
|
||
|
idVec3 masterOrigin;
|
||
|
idMat3 masterAxis;
|
||
|
|
||
|
splinePState_t previous = current;
|
||
|
|
||
|
if( HasValidSpline() ) {
|
||
|
if( StoppedMoving() ) {
|
||
|
Rest();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
accelDecelStateThread.Execute();
|
||
|
|
||
|
// FIXME: clean this up
|
||
|
if( IsAtBeginningOfSpline() || IsAtEndOfSpline() ) {
|
||
|
current = previous;
|
||
|
Rest();
|
||
|
self->ProcessEvent( &EV_DoneMoving );
|
||
|
|
||
|
if( gameLocal.program.GetReturnedBool() ) {
|
||
|
current.speed = 0.0f;
|
||
|
return false;
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float currentTime = splineEntity->GetSampledTime ( current.dist );
|
||
|
if ( currentTime == -1.0f ) {
|
||
|
currentTime = spline->GetTimeForLength( Min(current.dist, splineLength), 0.01f );
|
||
|
}
|
||
|
|
||
|
current.axis = spline->GetCurrentFirstDerivative(currentTime).ToAngles().Normalize360().ToMat3();
|
||
|
current.origin = spline->GetCurrentValue( currentTime );
|
||
|
current.localOrigin = current.origin;
|
||
|
current.localAxis = current.axis;
|
||
|
} else if( self->IsBound() ) {
|
||
|
self->GetMasterPosition( masterOrigin, masterAxis );
|
||
|
current.axis = current.localAxis * masterAxis;
|
||
|
current.origin = masterOrigin + current.localOrigin * masterAxis;
|
||
|
} else {
|
||
|
Rest();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
gameLocal.push.ClipPush( pushResults, self, 0, previous.origin, previous.axis, current.origin, current.axis );
|
||
|
if( pushResults.fraction < 1.0f ) {
|
||
|
current = previous;
|
||
|
LinkClip();
|
||
|
current.speed = 0.0f;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
LinkClip();
|
||
|
|
||
|
if( StoppedMoving() && !self->IsBound() ) {
|
||
|
Rest();
|
||
|
self->ProcessEvent( &EV_DoneMoving );
|
||
|
return !gameLocal.program.GetReturnedBool();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::Activate
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::Activate( void ) {
|
||
|
assert( self );
|
||
|
self->BecomeActive( TH_PHYSICS );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::Rest
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::Rest( void ) {
|
||
|
assert( self );
|
||
|
self->BecomeInactive( TH_PHYSICS );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::IsAtRest
|
||
|
================
|
||
|
*/
|
||
|
bool rvPhysics_Spline::IsAtRest( void ) const {
|
||
|
assert( self );
|
||
|
return !self->IsActive( TH_PHYSICS );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::IsAtEndOfSpline
|
||
|
================
|
||
|
*/
|
||
|
bool rvPhysics_Spline::IsAtEndOfSpline( void ) const {
|
||
|
return current.dist >= splineLength;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::IsAtBeginningOfSpline
|
||
|
================
|
||
|
*/
|
||
|
bool rvPhysics_Spline::IsAtBeginningOfSpline( void ) const {
|
||
|
return current.dist <= 0.0f;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::IsPushable
|
||
|
================
|
||
|
*/
|
||
|
bool rvPhysics_Spline::IsPushable( void ) const {
|
||
|
return !HasValidSpline() && idPhysics_Base::IsPushable();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::StartingToMove
|
||
|
================
|
||
|
*/
|
||
|
bool rvPhysics_Spline::StartingToMove( void ) const {
|
||
|
float firstDeltaSpeed = current.acceleration * MS2SEC(gameLocal.GetMSec());
|
||
|
return idMath::Fabs(current.idealSpeed) > VECTOR_EPSILON && idMath::Fabs(current.speed) <= firstDeltaSpeed;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::StoppedMoving
|
||
|
================
|
||
|
*/
|
||
|
bool rvPhysics_Spline::StoppedMoving( void ) const {
|
||
|
return idMath::Fabs(current.idealSpeed) < VECTOR_EPSILON && idMath::Fabs(current.speed) < VECTOR_EPSILON;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::HasValidSpline
|
||
|
================
|
||
|
*/
|
||
|
bool rvPhysics_Spline::HasValidSpline() const {
|
||
|
return spline && splineLength > VECTOR_EPSILON;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SaveState
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SaveState( void ) {
|
||
|
saved = current;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::RestoreState
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::RestoreState( void ) {
|
||
|
current = saved;
|
||
|
|
||
|
LinkClip();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idPhysics::SetOrigin
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetOrigin( const idVec3 &newOrigin, int id ) {
|
||
|
idVec3 masterOrigin;
|
||
|
idMat3 masterAxis;
|
||
|
|
||
|
current.localOrigin = newOrigin;
|
||
|
if( self->IsBound() ) {
|
||
|
self->GetMasterPosition( masterOrigin, masterAxis );
|
||
|
current.origin = masterOrigin + current.localOrigin * masterAxis;
|
||
|
}
|
||
|
else {
|
||
|
current.origin = current.localOrigin;
|
||
|
}
|
||
|
|
||
|
LinkClip();
|
||
|
Activate();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idPhysics::SetAxis
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetAxis( const idMat3 &newAxis, int id ) {
|
||
|
idVec3 masterOrigin;
|
||
|
idMat3 masterAxis;
|
||
|
|
||
|
current.localAxis = newAxis;
|
||
|
if ( self->IsBound() ) {
|
||
|
self->GetMasterPosition( masterOrigin, masterAxis );
|
||
|
current.axis = newAxis * masterAxis;
|
||
|
}
|
||
|
else {
|
||
|
current.axis = newAxis;
|
||
|
}
|
||
|
|
||
|
LinkClip();
|
||
|
Activate();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::Translate
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::Translate( const idVec3 &translation, int id ) {
|
||
|
SetOrigin( GetLocalOrigin() + translation );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::Rotate
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::Rotate( const idRotation &rotation, int id ) {
|
||
|
SetAxis( GetLocalAxis() * rotation.ToMat3() );
|
||
|
SetOrigin( GetLocalOrigin() * rotation );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetOrigin
|
||
|
================
|
||
|
*/
|
||
|
const idVec3 &rvPhysics_Spline::GetOrigin( int id ) const {
|
||
|
return current.origin;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetAxis
|
||
|
================
|
||
|
*/
|
||
|
const idMat3 &rvPhysics_Spline::GetAxis( int id ) const {
|
||
|
return current.axis;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetOrigin
|
||
|
================
|
||
|
*/
|
||
|
idVec3 &rvPhysics_Spline::GetOrigin( int id ) {
|
||
|
return current.origin;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetAxis
|
||
|
================
|
||
|
*/
|
||
|
idMat3 &rvPhysics_Spline::GetAxis( int id ) {
|
||
|
return current.axis;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetLocalOrigin
|
||
|
================
|
||
|
*/
|
||
|
const idVec3 &rvPhysics_Spline::GetLocalOrigin( int id ) const {
|
||
|
return current.localOrigin;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetLocalAxis
|
||
|
================
|
||
|
*/
|
||
|
const idMat3 &rvPhysics_Spline::GetLocalAxis( int id ) const {
|
||
|
return current.localAxis;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetLocalOrigin
|
||
|
================
|
||
|
*/
|
||
|
idVec3 &rvPhysics_Spline::GetLocalOrigin( int id ) {
|
||
|
return current.localOrigin;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetLocalAxis
|
||
|
================
|
||
|
*/
|
||
|
idMat3 &rvPhysics_Spline::GetLocalAxis( int id ) {
|
||
|
return current.localAxis;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::SetMaster
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::SetMaster( idEntity *master, const bool orientated ) {
|
||
|
idVec3 masterOrigin;
|
||
|
idMat3 masterAxis;
|
||
|
|
||
|
if( master ) {
|
||
|
if( self->IsBound() ) {
|
||
|
// transform from world space to master space
|
||
|
self->GetMasterPosition( masterOrigin, masterAxis );
|
||
|
current.localOrigin = ( GetOrigin() - masterOrigin ) * masterAxis.Transpose();
|
||
|
current.localAxis = GetAxis() * masterAxis.Transpose();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::ClipTranslation
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const {
|
||
|
if ( model ) {
|
||
|
gameLocal.TranslationModel( self, results, GetOrigin(), GetOrigin() + translation,
|
||
|
clipModel, GetAxis(), clipMask,
|
||
|
model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
|
||
|
}
|
||
|
else {
|
||
|
gameLocal.Translation( self, results, GetOrigin(), GetOrigin() + translation,
|
||
|
clipModel, GetAxis(), clipMask, self );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::ClipRotation
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const {
|
||
|
if ( model ) {
|
||
|
gameLocal.RotationModel( self, results, GetOrigin(), rotation,
|
||
|
clipModel, GetAxis(), clipMask,
|
||
|
model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
|
||
|
}
|
||
|
else {
|
||
|
gameLocal.Rotation( self, results, GetOrigin(), rotation,
|
||
|
clipModel, GetAxis(), clipMask, self );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::ClipContents
|
||
|
================
|
||
|
*/
|
||
|
int rvPhysics_Spline::ClipContents( const idClipModel *model ) const {
|
||
|
if ( model ) {
|
||
|
// RAVEN BEGIN
|
||
|
// ddynerman: multiple clip worlds
|
||
|
return gameLocal.ContentsModel( self, GetOrigin(), clipModel, GetAxis(), -1,
|
||
|
model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
|
||
|
}
|
||
|
else {
|
||
|
return gameLocal.Contents( self, GetOrigin(), clipModel, GetAxis(), -1, NULL );
|
||
|
// RAVEN END
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::DisableClip
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::DisableClip( void ) {
|
||
|
if( clipModel ) {
|
||
|
clipModel->Disable();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::EnableClip
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::EnableClip( void ) {
|
||
|
if( clipModel ) {
|
||
|
clipModel->Enable();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::UnlinkClip
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::UnlinkClip( void ) {
|
||
|
if( clipModel ) {
|
||
|
clipModel->Unlink();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::LinkClip
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::LinkClip( void ) {
|
||
|
if( clipModel ) {
|
||
|
// RAVEN BEGIN
|
||
|
// ddynerman: multiple clip worlds
|
||
|
clipModel->Link( self, clipModel->GetId(), GetOrigin(), GetAxis() );
|
||
|
// RAVEN END
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetBlockingInfo
|
||
|
================
|
||
|
*/
|
||
|
const trace_t* rvPhysics_Spline::GetBlockingInfo( void ) const {
|
||
|
return (pushResults.fraction < 1.0f) ? &pushResults : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::GetBlockingEntity
|
||
|
================
|
||
|
*/
|
||
|
idEntity* rvPhysics_Spline::GetBlockingEntity( void ) const {
|
||
|
return (pushResults.fraction < 1.0f) ? gameLocal.entities[ pushResults.c.entityNum ] : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::WriteToSnapshot
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::WriteToSnapshot( idBitMsgDelta &msg ) const {
|
||
|
current.WriteToSnapshot( msg );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::ReadFromSnapshot
|
||
|
================
|
||
|
*/
|
||
|
void rvPhysics_Spline::ReadFromSnapshot( const idBitMsgDelta &msg ) {
|
||
|
current.ReadFromSnapshot( msg );
|
||
|
|
||
|
LinkClip();
|
||
|
}
|
||
|
|
||
|
CLASS_STATES_DECLARATION( rvPhysics_Spline )
|
||
|
STATE( "Accelerating", rvPhysics_Spline::State_Accelerating )
|
||
|
STATE( "Decelerating", rvPhysics_Spline::State_Decelerating )
|
||
|
STATE( "Cruising", rvPhysics_Spline::State_Cruising )
|
||
|
END_CLASS_STATES
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::State_Accelerating
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvPhysics_Spline::State_Accelerating( const stateParms_t& parms ) {
|
||
|
stateResult_t returnResult = SRESULT_WAIT;
|
||
|
|
||
|
if( !current.ShouldAccelerate() ) {
|
||
|
accelDecelStateThread.SetState( current.ShouldDecelerate() ? "Decelerating" : "Cruising" );
|
||
|
return SRESULT_DONE;
|
||
|
}
|
||
|
|
||
|
if( !parms.stage ) {
|
||
|
if( StartingToMove() ) {
|
||
|
self->ProcessEvent( &EV_OnStartMoving );
|
||
|
}
|
||
|
self->ProcessEvent( &EV_OnAcceleration );
|
||
|
|
||
|
returnResult = SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
float timeStepSec = MS2SEC( gameLocal.GetMSec() );
|
||
|
current.ApplyAccelerationDelta( timeStepSec );
|
||
|
current.UpdateDist( timeStepSec );
|
||
|
|
||
|
return returnResult;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::State_Decelerating
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvPhysics_Spline::State_Decelerating( const stateParms_t& parms ) {
|
||
|
if( !current.ShouldDecelerate() ) {
|
||
|
accelDecelStateThread.SetState( current.ShouldAccelerate() ? "Accelerating" : "Cruising" );
|
||
|
return SRESULT_DONE;
|
||
|
}
|
||
|
|
||
|
float timeStepSec = MS2SEC( gameLocal.GetMSec() );
|
||
|
current.ApplyDecelerationDelta( timeStepSec );
|
||
|
current.UpdateDist( timeStepSec );
|
||
|
|
||
|
if( !parms.stage ) {
|
||
|
self->ProcessEvent( &EV_OnDeceleration );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
if( StoppedMoving() ) {
|
||
|
self->ProcessEvent( &EV_OnStopMoving );
|
||
|
}
|
||
|
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvPhysics_Spline::State_Cruising
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvPhysics_Spline::State_Cruising( const stateParms_t& parms ) {
|
||
|
if( current.ShouldAccelerate() ) {
|
||
|
accelDecelStateThread.SetState( "Accelerating" );
|
||
|
return SRESULT_DONE;
|
||
|
} else if( current.ShouldDecelerate() ) {
|
||
|
accelDecelStateThread.SetState( "Decelerating" );
|
||
|
return SRESULT_DONE;
|
||
|
}
|
||
|
|
||
|
current.UpdateDist( MS2SEC(gameLocal.GetMSec()) );
|
||
|
|
||
|
if( !parms.stage ) {
|
||
|
self->ProcessEvent( &EV_OnCruising );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
const idEventDef EV_SetSpline( "setSpline", "E" );
|
||
|
|
||
|
const idEventDef EV_SetAccel( "setAccel", "f" );
|
||
|
const idEventDef EV_SetDecel( "setDecel", "f" );
|
||
|
|
||
|
const idEventDef EV_SetSpeed( "setSpeed", "f" );
|
||
|
const idEventDef EV_GetSpeed( "getSpeed", "", 'f' );
|
||
|
|
||
|
const idEventDef EV_TramCar_SetIdealSpeed( "setIdealSpeed", "f" );
|
||
|
const idEventDef EV_TramCar_GetIdealSpeed( "getIdealSpeed", "", 'f' );
|
||
|
|
||
|
const idEventDef EV_TramCar_ApplySpeedScale( "applySpeedScale", "f" );
|
||
|
|
||
|
const idEventDef EV_GetCurrentTrackInfo( "getCurrentTrackInfo", "", 's' );
|
||
|
const idEventDef EV_GetTrackInfo( "getTrackInfo", "e", 's' );
|
||
|
|
||
|
const idEventDef EV_DoneMoving( "<doneMoving>", "", 'd' );
|
||
|
const idEventDef EV_StartSoundPeriodic( "<startSoundPeriodic>", "sddd" );
|
||
|
|
||
|
idLinkList<rvSplineMover> rvSplineMover::splineMovers;
|
||
|
|
||
|
//=======================================================
|
||
|
//
|
||
|
// rvSplineMover
|
||
|
//
|
||
|
//=======================================================
|
||
|
CLASS_DECLARATION( idAnimatedEntity, rvSplineMover )
|
||
|
EVENT( EV_PostSpawn, rvSplineMover::Event_PostSpawn )
|
||
|
EVENT( EV_Activate, rvSplineMover::Event_Activate )
|
||
|
EVENT( EV_SetSpline, rvSplineMover::Event_SetSpline )
|
||
|
EVENT( EV_SetAccel, rvSplineMover::Event_SetAcceleration )
|
||
|
EVENT( EV_SetDecel, rvSplineMover::Event_SetDeceleration )
|
||
|
EVENT( EV_SetSpeed, rvSplineMover::Event_SetSpeed )
|
||
|
EVENT( EV_GetSpeed, rvSplineMover::Event_GetSpeed )
|
||
|
EVENT( EV_Thread_SetCallback, rvSplineMover::Event_SetCallBack )
|
||
|
EVENT( EV_DoneMoving, rvSplineMover::Event_DoneMoving )
|
||
|
EVENT( EV_GetSplineEntity, rvSplineMover::Event_GetSpline )
|
||
|
EVENT( EV_GetCurrentTrackInfo, rvSplineMover::Event_GetCurrentTrackInfo )
|
||
|
EVENT( EV_GetTrackInfo, rvSplineMover::Event_GetTrackInfo )
|
||
|
EVENT( EV_TramCar_SetIdealSpeed, rvSplineMover::Event_SetIdealSpeed )
|
||
|
EVENT( EV_TramCar_GetIdealSpeed, rvSplineMover::Event_GetIdealSpeed )
|
||
|
EVENT( EV_TramCar_ApplySpeedScale, rvSplineMover::Event_ApplySpeedScale )
|
||
|
EVENT( EV_OnAcceleration, rvSplineMover::Event_OnAcceleration )
|
||
|
EVENT( EV_OnDeceleration, rvSplineMover::Event_OnDeceleration )
|
||
|
EVENT( EV_OnCruising, rvSplineMover::Event_OnCruising )
|
||
|
EVENT( EV_OnStartMoving, rvSplineMover::Event_OnStartMoving )
|
||
|
EVENT( EV_OnStopMoving, rvSplineMover::Event_OnStopMoving )
|
||
|
EVENT( EV_StartSoundPeriodic, rvSplineMover::Event_StartSoundPeriodic )
|
||
|
EVENT( EV_PartBlocked, rvSplineMover::Event_PartBlocked )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Spawn
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Spawn() {
|
||
|
waitThreadId = -1;
|
||
|
|
||
|
physicsObj.SetSelf( this );
|
||
|
// RAVEN BEGIN
|
||
|
// mwhitlock: Dynamic memory consolidation
|
||
|
RV_PUSH_HEAP_MEM(this);
|
||
|
// RAVEN END
|
||
|
physicsObj.SetClipModel( new idClipModel(GetPhysics()->GetClipModel()), 1.0f );
|
||
|
// RAVEN BEGIN
|
||
|
// mwhitlock: Dynamic memory consolidation
|
||
|
RV_POP_HEAP();
|
||
|
// RAVEN END
|
||
|
physicsObj.SetContents( spawnArgs.GetBool("solid", "1") ? CONTENTS_SOLID : 0 );
|
||
|
physicsObj.SetClipMask( spawnArgs.GetBool("solidClip") ? CONTENTS_SOLID : 0 );
|
||
|
physicsObj.SetLinearVelocity( GetPhysics()->GetLinearVelocity() );
|
||
|
physicsObj.SetLinearAcceleration( spawnArgs.GetFloat("accel", "50") );
|
||
|
physicsObj.SetLinearDeceleration( spawnArgs.GetFloat("decel", "50") );
|
||
|
physicsObj.SetAxis( GetPhysics()->GetAxis() );
|
||
|
physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
|
||
|
SetPhysics( &physicsObj );
|
||
|
|
||
|
AddSelfToGlobalList();
|
||
|
|
||
|
// This is needed so we get sorted correctly
|
||
|
BecomeInactive( TH_PHYSICS );
|
||
|
BecomeActive( TH_PHYSICS );
|
||
|
|
||
|
PlayAnim( ANIMCHANNEL_ALL, "idle", 0 );
|
||
|
|
||
|
PostEventMS( &EV_PostSpawn, 0 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::~rvSplineMover
|
||
|
================
|
||
|
*/
|
||
|
rvSplineMover::~rvSplineMover() {
|
||
|
RemoveSelfFromGlobalList();
|
||
|
SetPhysics( NULL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::SetSpeed
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::SetSpeed( float newSpeed ) {
|
||
|
physicsObj.SetSpeed( newSpeed );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::GetSpeed
|
||
|
================
|
||
|
*/
|
||
|
float rvSplineMover::GetSpeed() const {
|
||
|
return physicsObj.GetSpeed();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::SetIdealSpeed
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::SetIdealSpeed( float newIdealSpeed ) {
|
||
|
idealSpeed = newIdealSpeed;
|
||
|
SetSpeed( newIdealSpeed );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::GetIdealSpeed
|
||
|
================
|
||
|
*/
|
||
|
float rvSplineMover::GetIdealSpeed() const {
|
||
|
return idealSpeed;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::SetSpline
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::SetSpline( idSplinePath* spline ) {
|
||
|
physicsObj.SetSplineEntity( spline );
|
||
|
CheckSplineForOverrides( physicsObj.GetSpline(), &spline->spawnArgs );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::GetSpline
|
||
|
================
|
||
|
*/
|
||
|
const idSplinePath* rvSplineMover::GetSpline() const {
|
||
|
return physicsObj.GetSplineEntity();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::GetSpline
|
||
|
================
|
||
|
*/
|
||
|
idSplinePath* rvSplineMover::GetSpline() {
|
||
|
return physicsObj.GetSplineEntity();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::SetAcceleration
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::SetAcceleration( float accel ) {
|
||
|
physicsObj.SetLinearAcceleration( accel );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::SetDeceleration
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::SetDeceleration( float decel ) {
|
||
|
physicsObj.SetLinearDeceleration( decel );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::CheckSplineForOverrides
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::CheckSplineForOverrides( const idCurve_Spline<idVec3>* spline, const idDict* args ) {
|
||
|
if( !spline || !args ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int endSpline = args->GetInt( "end_spline" );
|
||
|
if( endSpline && Sign(endSpline) == Sign(GetSpeed()) ) {
|
||
|
physicsObj.SetLinearDeceleration( physicsObj.ComputeDecelFromSpline() );
|
||
|
SetIdealSpeed( 0.0f );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::RestoreFromOverrides
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::RestoreFromOverrides( const idDict* args ) {
|
||
|
if( !args ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
physicsObj.SetLinearDeceleration( args->GetFloat("decel") );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::PlayAnim
|
||
|
================
|
||
|
*/
|
||
|
int rvSplineMover::PlayAnim( int channel, const char* animName, int blendFrames ) {
|
||
|
int animIndex = GetAnimator()->GetAnim( animName );
|
||
|
if( !animIndex ) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
GetAnimator()->PlayAnim( channel, animIndex, gameLocal.GetTime(), FRAME2MS(blendFrames) );
|
||
|
return GetAnimator()->CurrentAnim( channel )->Length();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::CycleAnim
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::CycleAnim( int channel, const char* animName, int blendFrames ) {
|
||
|
int animIndex = GetAnimator()->GetAnim( animName );
|
||
|
if( !animIndex ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GetAnimator()->CycleAnim( channel, animIndex, gameLocal.GetTime(), FRAME2MS(blendFrames) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::ClearChannel
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::ClearChannel( int channel, int clearFrame ) {
|
||
|
GetAnimator()->Clear( channel, gameLocal.GetTime(), FRAME2MS(clearFrame) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::PreBind
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::PreBind() {
|
||
|
idAnimatedEntity::PreBind();
|
||
|
|
||
|
SetSpline( NULL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Save
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Save( idSaveGame *savefile ) const {
|
||
|
savefile->WriteStaticObject( physicsObj );
|
||
|
savefile->WriteFloat( idealSpeed );
|
||
|
savefile->WriteInt( waitThreadId );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Restore
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Restore( idRestoreGame *savefile ) {
|
||
|
savefile->ReadStaticObject( physicsObj );
|
||
|
RestorePhysics( &physicsObj );
|
||
|
|
||
|
savefile->ReadFloat( idealSpeed );
|
||
|
savefile->ReadInt( waitThreadId );
|
||
|
|
||
|
AddSelfToGlobalList();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::WriteToSnapshot
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::WriteToSnapshot( idBitMsgDelta &msg ) const {
|
||
|
physicsObj.WriteToSnapshot( msg );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::ReadFromSnapshot
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::ReadFromSnapshot( const idBitMsgDelta &msg ) {
|
||
|
physicsObj.ReadFromSnapshot( msg );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::AddSelfToGlobalList
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::AddSelfToGlobalList() {
|
||
|
splineMoverNode.SetOwner( this );
|
||
|
|
||
|
if( !InGlobalList() ) {
|
||
|
splineMoverNode.AddToEnd( splineMovers );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::RemoveSelfFromGlobalList
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::RemoveSelfFromGlobalList() {
|
||
|
splineMoverNode.Remove();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::InGlobalList
|
||
|
================
|
||
|
*/
|
||
|
bool rvSplineMover::InGlobalList() const {
|
||
|
return splineMoverNode.InList();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::WhosVisible
|
||
|
================
|
||
|
*/
|
||
|
bool rvSplineMover::WhosVisible( const idFrustum& frustum, idList<rvSplineMover*>& list ) const {
|
||
|
list.Clear();
|
||
|
|
||
|
if( !frustum.IsValid() ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
for( rvSplineMover* node = splineMovers.Next(); node; node = node->splineMoverNode.Next() ) {
|
||
|
if( node == this ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if( frustum.IntersectsBounds(node->GetPhysics()->GetAbsBounds()) ) {
|
||
|
list.AddUnique( node );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return list.Num() > 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::GetTrackInfo
|
||
|
================
|
||
|
*/
|
||
|
idStr rvSplineMover::GetTrackInfo( const idSplinePath* track ) const {
|
||
|
if( !track ) {
|
||
|
return idStr( "" );
|
||
|
}
|
||
|
|
||
|
idStr info( track->GetName() );
|
||
|
return info.Mid( info.Last('_') - 1, 1 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::ConvertToMover
|
||
|
================
|
||
|
*/
|
||
|
rvSplineMover* rvSplineMover::ConvertToMover( idEntity* mover ) const {
|
||
|
return mover && mover->IsType(rvSplineMover::Type) ? static_cast<rvSplineMover*>(mover) : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::ConvertToSplinePath
|
||
|
================
|
||
|
*/
|
||
|
idSplinePath* rvSplineMover::ConvertToSplinePath( idEntity* spline ) const {
|
||
|
return (spline && spline->IsType(idSplinePath::GetClassType())) ? static_cast<idSplinePath*>(spline) : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::PreDoneMoving
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::PreDoneMoving() {
|
||
|
if( waitThreadId >= 0 ) {
|
||
|
idThread::ObjectMoveDone( waitThreadId, this );
|
||
|
waitThreadId = -1;
|
||
|
}
|
||
|
|
||
|
RestoreFromOverrides( &spawnArgs );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::PostDoneMoving
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::PostDoneMoving() {
|
||
|
CallScriptEvents( physicsObj.GetSplineEntity(), "call_doneMoving", this );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
==============
|
||
|
rvSplineMover::CallScriptEvents
|
||
|
==============
|
||
|
*/
|
||
|
// FIXME: very similier code is in the spawner...if possible try and make one function for both to call
|
||
|
void rvSplineMover::CallScriptEvents( const idSplinePath* spline, const char* prefixKey, idEntity* parm ) {
|
||
|
if( !spline || !prefixKey || !prefixKey[0] ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
rvScriptFuncUtility func;
|
||
|
for( const idKeyValue* kv = spline->spawnArgs.MatchPrefix(prefixKey); kv; kv = spline->spawnArgs.MatchPrefix(prefixKey, kv) ) {
|
||
|
if( !kv->GetValue().Length() ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if( func.Init(kv->GetValue()) <= SFU_ERROR ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
func.InsertEntity( spline, 0 );
|
||
|
func.InsertEntity( parm, 1 );
|
||
|
func.CallFunc( &spawnArgs );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_PostSpawn
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_PostSpawn() {
|
||
|
idEntityPtr<idEntity> target;
|
||
|
for( int ix = targets.Num() - 1; ix >= 0; --ix ) {
|
||
|
target = targets[ix];
|
||
|
|
||
|
if( target.IsValid() && target->IsType(idSplinePath::GetClassType()) ) {
|
||
|
SetSpline( static_cast<idSplinePath*>(target.GetEntity()) );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetIdealSpeed( spawnArgs.GetBool("waitForTrigger") ? 0.0f : spawnArgs.GetFloat("speed", "50") );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
rvSplineMover::Event_PartBlocked
|
||
|
===============
|
||
|
*/
|
||
|
void rvSplineMover::Event_PartBlocked( idEntity *blockingEntity ) {
|
||
|
assert( blockingEntity );
|
||
|
|
||
|
float damage = spawnArgs.GetFloat( "damage" );
|
||
|
if( damage > 0.0f ) {
|
||
|
blockingEntity->Damage( this, this, vec3_origin, "damage_moverCrush", damage, INVALID_JOINT );
|
||
|
}
|
||
|
if( g_debugMover.GetBool() ) {
|
||
|
gameLocal.Printf( "%d: '%s' blocked by '%s'\n", gameLocal.GetTime(), GetName(), blockingEntity->GetName() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_SetSpline
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_SetSpline( idEntity* spline ) {
|
||
|
SetSpline( ConvertToSplinePath(spline) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_GetSpline
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_GetSpline() {
|
||
|
idThread::ReturnEntity( GetSpline() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_SetAcceleration
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_SetAcceleration( float accel ) {
|
||
|
SetAcceleration( accel );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_SetDeceleration
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_SetDeceleration( float decel ) {
|
||
|
SetDeceleration( decel );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_SetSpeed
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_SetSpeed( float speed ) {
|
||
|
SetIdealSpeed( speed );
|
||
|
SetSpeed( speed );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_GetSpeed
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_GetSpeed() {
|
||
|
idThread::ReturnFloat( GetSpeed() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_SetIdealSpeed
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_SetIdealSpeed( float speed ) {
|
||
|
SetIdealSpeed( speed );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_GetIdealSpeed
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_GetIdealSpeed() {
|
||
|
idThread::ReturnFloat( GetIdealSpeed() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_ApplySpeedScale
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_ApplySpeedScale( float scale ) {
|
||
|
SetIdealSpeed( spawnArgs.GetFloat("speed", "50") * scale );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_SetCallBack
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_SetCallBack() {
|
||
|
if( waitThreadId >= 0 ) {
|
||
|
idThread::ReturnInt( false );
|
||
|
}
|
||
|
|
||
|
waitThreadId = idThread::CurrentThreadNum();
|
||
|
idThread::ReturnInt( true );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_DoneMoving
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_DoneMoving() {
|
||
|
PreDoneMoving();
|
||
|
PostDoneMoving();
|
||
|
|
||
|
idThread::ReturnInt( !physicsObj.HasValidSpline() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_GetCurrentTrackInfo
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_GetCurrentTrackInfo() {
|
||
|
Event_GetTrackInfo( physicsObj.GetSplineEntity() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_GetTrackInfo
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_GetTrackInfo( idEntity* track ) {
|
||
|
idThread::ReturnString( GetTrackInfo(ConvertToSplinePath(track)) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_Activate
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_Activate( idEntity* activator ) {
|
||
|
// This is for my special case in tram1b
|
||
|
|
||
|
//if( physicsObj.StoppedMoving() ) {
|
||
|
// SetIdealSpeed( spawnArgs.GetFloat("speed", "50") );
|
||
|
//}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_OnAcceleration
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_OnAcceleration() {
|
||
|
StartSound( "snd_accel", SND_CHANNEL_ANY, 0, false, NULL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_OnDeceleration
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_OnDeceleration() {
|
||
|
StartSound( "snd_decel", SND_CHANNEL_ANY, 0, false, NULL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_OnCruising
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_OnCruising() {
|
||
|
idVec2 range( spawnArgs.GetVec2("noisePeriodRange") * idMath::M_SEC2MS );
|
||
|
if( !EventIsPosted(&EV_StartSoundPeriodic) && range.Length() > VECTOR_EPSILON ) {
|
||
|
ProcessEvent( &EV_StartSoundPeriodic, "snd_noise", (int)SND_CHANNEL_ANY, (int)range[0], (int)range[1] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_OnStopMoving
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_OnStopMoving() {
|
||
|
StopSound( SND_CHANNEL_ANY, false );
|
||
|
CancelEvents( &EV_StartSoundPeriodic );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_OnStartMoving
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_OnStartMoving() {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvSplineMover::Event_StartSoundPeriodic
|
||
|
================
|
||
|
*/
|
||
|
void rvSplineMover::Event_StartSoundPeriodic( const char* sndKey, const s_channelType channel, int minDelay, int maxDelay ) {
|
||
|
CancelEvents( &EV_StartSoundPeriodic );
|
||
|
|
||
|
if( physicsObj.StoppedMoving() ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int length;
|
||
|
StartSound( sndKey, channel, 0, false, &length );
|
||
|
|
||
|
PostEventMS( &EV_StartSoundPeriodic, Max(rvRandom::irand(minDelay, maxDelay), length), sndKey, (int)channel, minDelay, maxDelay );
|
||
|
}
|
||
|
|
||
|
|
||
|
const idEventDef EV_TramCar_RadiusDamage( "<tramCar_radiusDamage>", "vs" );
|
||
|
const idEventDef EV_TramCar_SetIdealTrack( "setIdealTrack", "s" );
|
||
|
const idEventDef EV_TramCar_DriverSpeak( "driverSpeak", "s", 'e' );
|
||
|
const idEventDef EV_TramCar_GetDriver( "getDriver", "", 'E' );
|
||
|
|
||
|
const idEventDef EV_TramCar_OpenDoors( "openDoors" );
|
||
|
const idEventDef EV_TramCar_CloseDoors( "closeDoors" );
|
||
|
|
||
|
//=======================================================
|
||
|
//
|
||
|
// rvTramCar
|
||
|
//
|
||
|
//=======================================================
|
||
|
CLASS_DECLARATION( rvSplineMover, rvTramCar )
|
||
|
EVENT( EV_TramCar_DriverSpeak, rvTramCar::Event_DriverSpeak )
|
||
|
EVENT( EV_TramCar_GetDriver, rvTramCar::Event_GetDriver )
|
||
|
EVENT( EV_Activate, rvTramCar::Event_Activate )
|
||
|
EVENT( EV_TramCar_RadiusDamage, rvTramCar::Event_RadiusDamage )
|
||
|
EVENT( EV_TramCar_SetIdealTrack, rvTramCar::Event_SetIdealTrack )
|
||
|
EVENT( EV_OnStartMoving, rvTramCar::Event_OnStartMoving )
|
||
|
EVENT( EV_OnStopMoving, rvTramCar::Event_OnStopMoving )
|
||
|
EVENT( EV_TramCar_OpenDoors, rvTramCar::Event_OpenDoors )
|
||
|
EVENT( EV_TramCar_CloseDoors, rvTramCar::Event_CloseDoors )
|
||
|
EVENT( AI_SetHealth, rvTramCar::Event_SetHealth )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Spawn
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Spawn() {
|
||
|
RegisterStateThread( idealTrackStateThread, "IdealTrack" );
|
||
|
RegisterStateThread( speedSoundEffectsStateThread, "SpeedSoundEffects" );
|
||
|
|
||
|
numTracksOnMap = gameLocal.world->spawnArgs.GetInt( "numTramCarTracks", "1" );
|
||
|
|
||
|
idStr track;
|
||
|
if ( numTracksOnMap == 1 ) {
|
||
|
track += ConvertToTrackLetter( numTracksOnMap - 1 );
|
||
|
} else {
|
||
|
track = spawnArgs.RandomPrefix( "idealTrack", gameLocal.random, "0" );
|
||
|
}
|
||
|
Event_SetIdealTrack( track.c_str() );
|
||
|
idealTrackStateThread.SetState( GetIdealTrack() < 0 ? "RandomTrack" : "AssignedTrack" );
|
||
|
|
||
|
SpawnDriver( "def_driver" );
|
||
|
SpawnWeapons( "def_weapon" );
|
||
|
SpawnOccupants( "def_occupant" );
|
||
|
SpawnDoors();
|
||
|
|
||
|
float dNear = 0.0f, dFar = 0.0f, dLeft = 0.0f, dUp = 0.0f;
|
||
|
const char* frustumKey = spawnArgs.GetString( "collisionFov" );
|
||
|
if( frustumKey[0] ) {
|
||
|
sscanf( frustumKey, "%f %f %f %f", &dNear, &dFar, &dLeft, &dUp );
|
||
|
collisionFov.SetSize( dNear, dFar, dLeft, dUp );
|
||
|
}
|
||
|
|
||
|
fl.takedamage = health > 0;
|
||
|
|
||
|
BecomeActive( TH_THINK );
|
||
|
|
||
|
SetSpline( NULL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SpawnDriver
|
||
|
================
|
||
|
*/
|
||
|
rvTramCar::~rvTramCar() {
|
||
|
SAFE_REMOVE( driver );
|
||
|
occupants.RemoveContents( true );
|
||
|
weapons.RemoveContents( true );
|
||
|
|
||
|
SAFE_REMOVE( leftDoor );
|
||
|
SAFE_REMOVE( rightDoor );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SpawnDriver
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::SpawnDriver( const char* driverKey ) {
|
||
|
driver = (idAI*)SpawnPart( spawnArgs.GetString(driverKey), "def_occupant" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SpawnWeapons
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::SpawnWeapons( const char* partKey ) {
|
||
|
idEntityPtr<rvVehicle> weapon;
|
||
|
|
||
|
for( const idKeyValue* kv = spawnArgs.MatchPrefix(partKey); kv; kv = spawnArgs.MatchPrefix(partKey, kv) ) {
|
||
|
if( !kv->GetValue().Length() ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
weapon = (rvVehicle*)SpawnPart( kv->GetValue().c_str(), partKey );
|
||
|
weapon->IdleAnim( ANIMCHANNEL_LEGS, "idle", 0 );
|
||
|
//if( weapon->GetAnimator()->GetAnim("toFire") && weapon->GetAnimator()->GetAnim("toIdle") ) {
|
||
|
weapons.AddUnique( weapon );
|
||
|
//}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SpawnOccupants
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::SpawnOccupants( const char* partKey ) {
|
||
|
idEntityPtr<idAI> occupant;
|
||
|
|
||
|
for( const idKeyValue* kv = spawnArgs.MatchPrefix(partKey); kv; kv = spawnArgs.MatchPrefix(partKey, kv) ) {
|
||
|
if( !kv->GetValue().Length() ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
occupant = (idAI*)SpawnPart( kv->GetValue().c_str(), partKey );
|
||
|
occupants.AddUnique( occupant );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SpawnPart
|
||
|
================
|
||
|
*/
|
||
|
idEntity* rvTramCar::SpawnPart( const char* partDefName, const char* subPartDefName ) {
|
||
|
idEntity* part = NULL;
|
||
|
idDict entityDef;
|
||
|
const idDict* info = gameLocal.FindEntityDefDict( partDefName, false );
|
||
|
if( !info ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
const idDict* def = gameLocal.FindEntityDefDict( info->GetString(subPartDefName), false );
|
||
|
if( !def ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
entityDef.Copy( *def );
|
||
|
|
||
|
entityDef.SetBool( "trigger", spawnArgs.GetBool("waitForTrigger") );
|
||
|
entityDef.SetVector( "origin", GetPhysics()->GetOrigin() + info->GetVector("spawn_offset") * GetPhysics()->GetAxis() );
|
||
|
entityDef.SetFloat( "angle", info->GetInt("spawn_facing_offset") + spawnArgs.GetFloat("angle") );
|
||
|
entityDef.Set( "bind", GetName() );
|
||
|
gameLocal.SpawnEntityDef( entityDef, &part );
|
||
|
|
||
|
return part;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SpawnDoors
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::SpawnDoors() {
|
||
|
leftDoor = SpawnDoor( "clipModel_doorLeft" );
|
||
|
rightDoor = SpawnDoor( "clipModel_doorRight" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SpawnDoors
|
||
|
================
|
||
|
*/
|
||
|
idMover* rvTramCar::SpawnDoor( const char* key ) {
|
||
|
idDict args;
|
||
|
const idDict* dict = NULL;
|
||
|
idMover* outer = NULL;
|
||
|
idMover* inner = NULL;
|
||
|
|
||
|
dict = gameLocal.FindEntityDefDict( spawnArgs.GetString(key), false );
|
||
|
if( !dict ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
args.Set( "open_rotation", dict->GetString("open_rotation") );
|
||
|
args.Set( "close_rotation", dict->GetString("close_rotation") );
|
||
|
|
||
|
args.Set( "open_dir", dict->GetString("open_dir") );
|
||
|
args.Set( "close_dir", dict->GetString("close_dir") );
|
||
|
|
||
|
args.Set( "distExt", dict->GetString("distExt") );
|
||
|
|
||
|
args.SetVector( "origin", GetPhysics()->GetOrigin() + dict->GetVector("offset") * GetPhysics()->GetAxis() );
|
||
|
args.SetMatrix( "rotation", GetPhysics()->GetAxis() );
|
||
|
args.Set( "clipModel", dict->GetString("clipModel") );
|
||
|
args.Set( "bind", GetName() );
|
||
|
outer = gameLocal.SpawnSafeEntityDef<idMover>( "func_mover", &args );
|
||
|
assert( outer );
|
||
|
|
||
|
args.Set( "clipModel", dict->GetString("clipModelExt") );
|
||
|
args.Set( "bind", outer->GetName() );
|
||
|
inner = gameLocal.SpawnSafeEntityDef<idMover>( "func_mover", &args );
|
||
|
|
||
|
return inner;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Think
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Think() {
|
||
|
RunPhysics();
|
||
|
|
||
|
MidThink();
|
||
|
|
||
|
Present();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::MidThink
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::MidThink() {
|
||
|
if( !physicsObj.StoppedMoving() ) {
|
||
|
LookAround();
|
||
|
TouchTriggers();
|
||
|
speedSoundEffectsStateThread.Execute();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::RegisterStateThread
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::RegisterStateThread( rvStateThread& stateThread, const char* name ) {
|
||
|
stateThread.SetName( name );
|
||
|
stateThread.SetOwner( this );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SetIdealTrack
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::SetIdealTrack( int track ) {
|
||
|
idealTrack = track;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::GetIdealTrack
|
||
|
================
|
||
|
*/
|
||
|
int rvTramCar::GetIdealTrack() const {
|
||
|
return idealTrack;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::AddDamageEffect
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName, idEntity* inflictor ) {
|
||
|
rvSplineMover::AddDamageEffect( collision, velocity, damageDefName, inflictor );
|
||
|
|
||
|
if( GetDamageScale() >= 0.5f && rvRandom::flrand() <= spawnArgs.GetFloat("damageEffectFreq", "0.25") ) {
|
||
|
idVec3 center = GetPhysics()->GetAbsBounds().GetCenter();
|
||
|
idVec3 v = (center - collision.endpos).ToNormal();
|
||
|
float dot = v * collision.c.normal;
|
||
|
PlayEffect( (dot > 0.0f) ? "fx_damage_internal" : "fx_damage_external", collision.endpos, collision.c.normal.ToMat3(2) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Damage
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
|
||
|
if( attacker && GetPhysics()->GetAbsBounds().Contains(attacker->GetPhysics()->GetAbsBounds()) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( attacker && g_debugVehicle.GetInteger() == 3 ) {
|
||
|
gameLocal.Printf( "Was damaged by %s. Current damage scale: %f\n", attacker->GetName(), GetDamageScale() );
|
||
|
}
|
||
|
|
||
|
rvSplineMover::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Killed
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
|
||
|
idVec3 center = GetPhysics()->GetAbsBounds().GetCenter();
|
||
|
|
||
|
fl.takedamage = false;
|
||
|
|
||
|
StopSound( SND_CHANNEL_ANY, false );
|
||
|
|
||
|
//Calling gameLocal's version because we don't want to get bound and hidden
|
||
|
gameLocal.PlayEffect( gameLocal.GetEffect( spawnArgs, "fx_explode" ), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
|
||
|
|
||
|
PostEventMS( &EV_TramCar_RadiusDamage, 0, center, spawnArgs.GetString("def_damage_explode") );
|
||
|
|
||
|
//TODO: think about giving rigid body physics and have it fall from track
|
||
|
Hide();
|
||
|
PostEventMS( &EV_Remove, 0 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::GetDamageScale
|
||
|
================
|
||
|
*/
|
||
|
float rvTramCar::GetDamageScale() const {
|
||
|
return 1.0f - GetHealthScale();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::GetDamageScale
|
||
|
================
|
||
|
*/
|
||
|
float rvTramCar::GetHealthScale() const {
|
||
|
float spawnHealth = spawnArgs.GetFloat( "health" );
|
||
|
return ( idMath::Fabs(spawnHealth) <= VECTOR_EPSILON ) ? 1.0f : (health / spawnHealth);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Save
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Save( idSaveGame *savefile ) const {
|
||
|
savefile->WriteInt( idealTrack );
|
||
|
// savefile->WriteString( idealTrackTag.c_str() ); // cnicholson: FIXME: This has a comment of HACK in the .h file... Not sure how to write a idStr yet
|
||
|
|
||
|
savefile->WriteFrustum( collisionFov );
|
||
|
|
||
|
idealTrackStateThread.Save( savefile );
|
||
|
speedSoundEffectsStateThread.Save( savefile );
|
||
|
|
||
|
driver.Save( savefile );
|
||
|
|
||
|
savefile->WriteInt( occupants.Num() );
|
||
|
for( int ix = occupants.Num() - 1; ix >= 0; --ix ) {
|
||
|
occupants[ix].Save( savefile );
|
||
|
}
|
||
|
|
||
|
savefile->WriteInt( weapons.Num() );
|
||
|
for( int ix = weapons.Num() - 1; ix >= 0; --ix ) {
|
||
|
weapons[ix].Save( savefile );
|
||
|
}
|
||
|
|
||
|
savefile->WriteInt( numTracksOnMap );
|
||
|
|
||
|
leftDoor.Save ( savefile );
|
||
|
rightDoor.Save ( savefile );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Restore
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Restore( idRestoreGame *savefile ) {
|
||
|
savefile->ReadInt( idealTrack );
|
||
|
|
||
|
savefile->ReadFrustum( collisionFov );
|
||
|
|
||
|
idealTrackStateThread.Restore( savefile, this );
|
||
|
speedSoundEffectsStateThread.Restore( savefile, this );
|
||
|
|
||
|
driver.Restore( savefile );
|
||
|
|
||
|
int num = 0;
|
||
|
savefile->ReadInt( num );
|
||
|
occupants.SetNum( num );
|
||
|
for( int ix = occupants.Num() - 1; ix >= 0; --ix ) {
|
||
|
occupants[ix].Restore( savefile );
|
||
|
}
|
||
|
|
||
|
savefile->ReadInt( num );
|
||
|
weapons.SetNum( num );
|
||
|
for( int ix = weapons.Num() - 1; ix >= 0; --ix ) {
|
||
|
weapons[ix].Restore( savefile );
|
||
|
}
|
||
|
|
||
|
savefile->ReadInt( numTracksOnMap );
|
||
|
|
||
|
leftDoor.Restore ( savefile );
|
||
|
rightDoor.Restore ( savefile );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::WriteToSnapshot
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::WriteToSnapshot( idBitMsgDelta &msg ) const {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::ReadFromSnapshot
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::ReadFromSnapshot( const idBitMsgDelta &msg ) {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::HeadTowardsIdealTrack
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::HeadTowardsIdealTrack() {
|
||
|
idSplinePath* ideal = FindSplineToIdealTrack( GetSpline() );
|
||
|
if( !ideal ) {
|
||
|
ideal = GetRandomSpline(GetSpline());
|
||
|
}
|
||
|
|
||
|
SetSpline( ideal );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::FindSplineToTrack
|
||
|
================
|
||
|
*/
|
||
|
enum {
|
||
|
LOOK_LEFT = -1,
|
||
|
LOOK_RIGHT = 1
|
||
|
};
|
||
|
idSplinePath* rvTramCar::FindSplineToTrack( idSplinePath* spline, const idStr& track ) const {
|
||
|
idSplinePath* target = NULL;
|
||
|
idEntity* ent = NULL;
|
||
|
idStr trackInfo;
|
||
|
idList<rvSplineMover*> list;
|
||
|
|
||
|
if( !spline ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
for( int ix = SortSplineTargets(spline) - 1; ix >= 0; --ix ) {
|
||
|
ent = GetSplineTarget( spline, ix );
|
||
|
target = static_cast<idSplinePath*>( ent );
|
||
|
assert( target->IsActive() );
|
||
|
|
||
|
trackInfo = GetTrackInfo( target );
|
||
|
if( -1 >= trackInfo.Find(track) ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// HACK: I hate switch statements
|
||
|
switch( ConvertToTrackNumber(trackInfo) - GetCurrentTrack() ) {
|
||
|
case LOOK_LEFT: {
|
||
|
if( !LookLeft(list) ) {
|
||
|
return target;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LOOK_RIGHT: {
|
||
|
if( !LookRight(list) ) {
|
||
|
return target;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default: {
|
||
|
return target;
|
||
|
}
|
||
|
}
|
||
|
// HACK
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SortSplineTargets
|
||
|
================
|
||
|
*/
|
||
|
int rvTramCar::SortSplineTargets( idSplinePath* spline ) const {
|
||
|
assert( spline );
|
||
|
return (SignZero(GetSpeed()) >= 0) ? spline->SortTargets() : spline->SortBackwardsTargets();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::GetSplineTarget
|
||
|
================
|
||
|
*/
|
||
|
idEntity* rvTramCar::GetSplineTarget( idSplinePath* spline, int index ) const {
|
||
|
assert( spline );
|
||
|
return (SignZero(GetSpeed()) >= 0) ? spline->targets[index].GetEntity() : spline->backwardPathTargets[index].GetEntity();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::FindSplineToIdealTrack
|
||
|
================
|
||
|
*/
|
||
|
idSplinePath* rvTramCar::FindSplineToIdealTrack( idSplinePath* spline ) const {
|
||
|
// HACK
|
||
|
int trackDelta = idMath::ClampInt( -1, 1, GetIdealTrack() - GetCurrentTrack() );
|
||
|
idStr trackLetter( ConvertToTrackLetter(GetCurrentTrack() + trackDelta) );
|
||
|
idSplinePath* s = NULL;
|
||
|
|
||
|
if( idealTrackTag.Length() && !trackDelta ) {// On ideal track
|
||
|
s = FindSplineToTrack( spline, idealTrackTag + trackLetter );
|
||
|
}
|
||
|
if( !s ) {
|
||
|
s = FindSplineToTrack( spline, trackLetter );
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::GetRandomSpline
|
||
|
================
|
||
|
*/
|
||
|
idSplinePath* rvTramCar::GetRandomSpline( idSplinePath* spline ) const {
|
||
|
if( !spline ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int numActiveTargets = SortSplineTargets( spline );
|
||
|
if( !numActiveTargets ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
idEntity* target = GetSplineTarget( spline, rvRandom::irand(0, numActiveTargets - 1) );
|
||
|
return (target && target->IsType(idSplinePath::GetClassType())) ? static_cast<idSplinePath*>(target) : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::GetCurrentTrack
|
||
|
================
|
||
|
*/
|
||
|
int rvTramCar::GetCurrentTrack() const {
|
||
|
return ConvertToTrackNumber( GetTrackInfo(GetSpline()) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::UpdateChannel
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::UpdateChannel( const s_channelType channel, const soundShaderParms_t& parms ) {
|
||
|
idSoundEmitter *emitter = soundSystem->EmitterForIndex( SOUNDWORLD_GAME, refSound.referenceSoundHandle );
|
||
|
if( emitter ) {
|
||
|
emitter->ModifySound( channel, &parms );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::AttenuateTrackChannel
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::AttenuateTrackChannel( float attenuation ) {
|
||
|
soundShaderParms_t parms = refSound.parms;
|
||
|
|
||
|
parms.frequencyShift = attenuation;//idMath::MidPointLerp( 0.0f, 1.0f, 1.1f, attenuation );
|
||
|
|
||
|
UpdateChannel( SND_CHANNEL_BODY, parms );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::AttenuateTramCarChannel
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::AttenuateTramCarChannel( float attenuation ) {
|
||
|
soundShaderParms_t parms = refSound.parms;
|
||
|
|
||
|
parms.volume = (attenuation + 1.0f) * 0.5f;
|
||
|
parms.frequencyShift = Max( 0.4f, attenuation );
|
||
|
|
||
|
UpdateChannel( SND_CHANNEL_BODY2, parms );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::LookForward
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar::LookForward( idList<rvSplineMover*>& list ) const {
|
||
|
collisionFov.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
collisionFov.SetAxis( GetPhysics()->GetAxis() );
|
||
|
|
||
|
Look( collisionFov, list );
|
||
|
|
||
|
for( int ix = list.Num() - 1; ix >= 0; --ix ) {
|
||
|
if( !OnSameTrackAs(list[ix]) ) {
|
||
|
list.Remove( list[ix] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return list.Num() > 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::LookLeft
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar::LookLeft( idList<rvSplineMover*>& list ) const {
|
||
|
collisionFov.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
collisionFov.SetAxis( idAngles(0.0f, 60.0f, 0.0f).ToMat3() * GetPhysics()->GetAxis() );
|
||
|
|
||
|
return Look( collisionFov, list );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::LookRight
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar::LookRight( idList<rvSplineMover*>& list ) const {
|
||
|
collisionFov.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
collisionFov.SetAxis( idAngles(0.0f, -60.0f, 0.0f).ToMat3() * GetPhysics()->GetAxis() );
|
||
|
|
||
|
return Look( collisionFov, list );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::LookLeftForTrackChange
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar::LookLeftForTrackChange( idList<rvSplineMover*>& list ) const {
|
||
|
collisionFov.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
collisionFov.SetAxis( idAngles(0.0f, 45.0f, 0.0f).ToMat3() * GetPhysics()->GetAxis() );
|
||
|
|
||
|
return Look( collisionFov, list );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::LookRightForTrackChange
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar::LookRightForTrackChange( idList<rvSplineMover*>& list ) const {
|
||
|
collisionFov.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
collisionFov.SetAxis( idAngles(0.0f, -45.0f, 0.0f).ToMat3() * GetPhysics()->GetAxis() );
|
||
|
|
||
|
return Look( collisionFov, list );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Look
|
||
|
================
|
||
|
*/
|
||
|
int rvSortByDist( const void* left, const void* right ) {
|
||
|
rvSplineMover* leftMover = *(rvSplineMover**)left;
|
||
|
rvSplineMover* rightMover = *(rvSplineMover**)right;
|
||
|
|
||
|
return rightMover->spawnArgs.GetFloat("distAway") - leftMover->spawnArgs.GetFloat("distAway");
|
||
|
}
|
||
|
bool rvTramCar::Look( const idFrustum& fov, idList<rvSplineMover*>& list ) const {
|
||
|
bool result = WhosVisible( fov, list );
|
||
|
|
||
|
if( g_debugVehicle.GetInteger() == 3 ) {
|
||
|
gameRenderWorld->DebugFrustum( colorRed, fov );
|
||
|
}
|
||
|
|
||
|
for( int ix = list.Num() - 1; ix >= 0; --ix ) {
|
||
|
list[ix]->spawnArgs.SetFloat( "distAway", (list[ix]->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin()).Length() );
|
||
|
}
|
||
|
|
||
|
qsort( list.Ptr(), list.Num(), list.TypeSize(), rvSortByDist );
|
||
|
|
||
|
// Do we need to get rid of these keyvalues?
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::OnSameTrackAs
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar::OnSameTrackAs( const rvSplineMover* tram ) const {
|
||
|
return tram && !GetTrackInfo(GetSpline()).Icmp( GetTrackInfo(tram->GetSpline()) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::SameIdealTrackAs
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar::SameIdealTrackAs( const rvSplineMover* tram ) const {
|
||
|
if( !tram ) {
|
||
|
return false;
|
||
|
}
|
||
|
return GetIdealTrack() == static_cast<const rvTramCar*>(tram)->GetIdealTrack();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::LookAround
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::LookAround() {
|
||
|
idList<rvSplineMover*> moverList;
|
||
|
|
||
|
if( !AdjustSpeed(moverList) ) {
|
||
|
SetSpeed( GetIdealSpeed() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::AdjustSpeed
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar::AdjustSpeed( idList<rvSplineMover*>& moverList ) {
|
||
|
if( LookForward(moverList) ) {
|
||
|
if( g_debugVehicle.GetInteger() ) {
|
||
|
gameRenderWorld->DebugLine( colorRed, GetPhysics()->GetOrigin(), moverList[0]->GetPhysics()->GetOrigin() );
|
||
|
}
|
||
|
|
||
|
//Slow down and try to get onto other track if allowed
|
||
|
SetSpeed( moverList[0]->GetSpeed() * rvRandom::flrand(0.5f, 0.75f) );
|
||
|
|
||
|
// Is this safe if we are on a specified track
|
||
|
SetIdealTrack( (GetIdealTrack() + rvRandom::irand(1, 2)) % numTracksOnMap );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::DriverSpeak
|
||
|
================
|
||
|
*/
|
||
|
idEntity* rvTramCar::DriverSpeak( const char* speechDecl, bool random ) {
|
||
|
if( !driver.IsValid() || driver->IsSpeaking() ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
driver->Speak( speechDecl, random );
|
||
|
return driver;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::OccupantSpeak
|
||
|
================
|
||
|
*/
|
||
|
idEntity* rvTramCar::OccupantSpeak( const char *speechDecl, bool random ) {
|
||
|
idEntityPtr<idAI> occupant;
|
||
|
|
||
|
if( !occupants.Num() ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
occupant = occupants[ rvRandom::irand(0, occupants.Num() - 1) ];
|
||
|
if( !occupant.IsValid() || occupant->IsSpeaking() ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
occupant->Speak( speechDecl, random );
|
||
|
return occupant;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::PostDoneMoving
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::PostDoneMoving() {
|
||
|
rvSplineMover::PostDoneMoving();
|
||
|
|
||
|
HeadTowardsIdealTrack();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::DeployRamp
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::DeployRamp() {
|
||
|
OperateRamp( "open" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::RetractRamp
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::RetractRamp() {
|
||
|
OperateRamp( "close" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::OperateRamp
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::OperateRamp( const char* operation ) {
|
||
|
if( !operation || !operation[0] ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PlayAnim( ANIMCHANNEL_ALL, operation, 0 );
|
||
|
|
||
|
OperateRamp( operation, leftDoor );
|
||
|
OperateRamp( operation, rightDoor );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::OperateRamp
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::OperateRamp( const char* operation, idMover* door ) {
|
||
|
if( !operation || !operation[0] ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
idAngles ang;
|
||
|
idVec3 vec;
|
||
|
if( !door ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( !door->IsBound() ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ang = door->spawnArgs.GetAngles( va("%s%s", operation, "_rotation") );
|
||
|
vec.Set( ang[0], ang[1], ang[2] );
|
||
|
door->GetBindMaster()->ProcessEvent( &EV_RotateOnce, vec );
|
||
|
|
||
|
vec = door->spawnArgs.GetVector(va("%s%s", operation, "_dir")).ToNormal() * door->spawnArgs.GetFloat("distExt");
|
||
|
door->PostEventSec( &EV_MoveAlongVector, 0.5f, vec );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_OnStopMoving
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_OnStopMoving() {
|
||
|
rvSplineMover::Event_OnStopMoving();
|
||
|
|
||
|
speedSoundEffectsStateThread.SetState( "IdleSpeed" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_OnStartMoving
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_OnStartMoving() {
|
||
|
rvSplineMover::Event_OnStartMoving();
|
||
|
|
||
|
speedSoundEffectsStateThread.SetState( "NormalSpeed" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_DriverSpeak
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_DriverSpeak( const char* voKey ) {
|
||
|
idThread::ReturnEntity( DriverSpeak(voKey) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_GetDriver
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_GetDriver() {
|
||
|
idThread::ReturnEntity( driver );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_Activate
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_Activate( idEntity* activator ) {
|
||
|
rvSplineMover::Event_Activate( activator );
|
||
|
|
||
|
// If being activated by a spawner we need to attach to it
|
||
|
if( activator->IsType(rvSpawner::GetClassType()) ) {
|
||
|
static_cast<rvSpawner*>(activator)->Attach( this );
|
||
|
} else {
|
||
|
if( driver.IsValid() ) {
|
||
|
driver->ProcessEvent( &EV_Activate, activator );
|
||
|
}
|
||
|
|
||
|
occupants.RemoveNull();
|
||
|
for( int ix = occupants.Num() - 1; ix >= 0; --ix ) {
|
||
|
occupants[ix]->ProcessEvent( &EV_Activate, activator );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_RadiusDamage
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_RadiusDamage( const idVec3& origin, const char* damageDefName ) {
|
||
|
gameLocal.RadiusDamage( origin, this, this, this, this, damageDefName );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_SetIdealTrack
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_SetIdealTrack( const char* track ) {
|
||
|
idStr ideal = track;
|
||
|
|
||
|
if( ideal.Length() > 1 ) {
|
||
|
idealTrackTag = ideal.Left( ideal.Length() - 1 );
|
||
|
}
|
||
|
|
||
|
idealTrackStateThread.SetState( "AssignedTrack" );
|
||
|
SetIdealTrack( ConvertToTrackNumber(ideal.Right(1)) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_OpenDoors
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_OpenDoors() {
|
||
|
DeployRamp();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_CloseDoors
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_CloseDoors() {
|
||
|
RetractRamp();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::Event_SetHealth
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar::Event_SetHealth ( float health ) {
|
||
|
this->health = health;
|
||
|
}
|
||
|
|
||
|
CLASS_STATES_DECLARATION( rvTramCar )
|
||
|
STATE( "IdleSpeed", rvTramCar::State_Idle )
|
||
|
STATE( "NormalSpeed", rvTramCar::State_NormalSpeed )
|
||
|
STATE( "ExcessiveSpeed", rvTramCar::State_ExcessiveSpeed )
|
||
|
STATE( "RandomTrack", rvTramCar::State_RandomTrack )
|
||
|
STATE( "AssignedTrack", rvTramCar::State_AssignedTrack )
|
||
|
END_CLASS_STATES
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::State_Idle
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar::State_Idle( const stateParms_t& parms ) {
|
||
|
if( !parms.stage ) {
|
||
|
StartSound( "snd_speed_idle_track", SND_CHANNEL_BODY, 0, false, NULL );
|
||
|
StartSound( "snd_speed_idle_tram", SND_CHANNEL_BODY2, 0, false, NULL );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::State_NormalSpeed
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar::State_NormalSpeed( const stateParms_t& parms ) {
|
||
|
if( !parms.stage ) {
|
||
|
StartSound( "snd_speed_normal_track", SND_CHANNEL_BODY, 0, false, NULL );
|
||
|
StartSound( "snd_speed_normal_tram", SND_CHANNEL_BODY2, 0, false, NULL );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
float speedScale = 0.8f + 0.2f * ( GetSpeed() / GetNormalSpeed() );
|
||
|
|
||
|
if( speedScale >= 1.0f ) {
|
||
|
speedSoundEffectsStateThread.SetState( "ExcessiveSpeed" );
|
||
|
return SRESULT_DONE;
|
||
|
}
|
||
|
|
||
|
AttenuateTrackChannel( speedScale );
|
||
|
AttenuateTramCarChannel( speedScale );
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::State_ExcessiveSpeed
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar::State_ExcessiveSpeed( const stateParms_t& parms ) {
|
||
|
if( !parms.stage ) {
|
||
|
StartSound( "snd_speed_excessive_track", SND_CHANNEL_BODY, 0, false, NULL );
|
||
|
StartSound( "snd_speed_excessive_tram", SND_CHANNEL_BODY2, 0, false, NULL );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
float speedScale = GetSpeed() / GetNormalSpeed();
|
||
|
|
||
|
if( speedScale < 1.0f ) {
|
||
|
speedSoundEffectsStateThread.SetState( "NormalSpeed" );
|
||
|
return SRESULT_DONE;
|
||
|
}
|
||
|
|
||
|
AttenuateTrackChannel( speedScale );
|
||
|
AttenuateTramCarChannel( speedScale );
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::State_RandomTrack
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar::State_RandomTrack( const stateParms_t& parms ) {
|
||
|
SetIdealTrack( rvRandom::irand(0, numTracksOnMap - 1) );
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar::State_AssignedTrack
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar::State_AssignedTrack( const stateParms_t& parms ) {
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
//=======================================================
|
||
|
//
|
||
|
// rvTramCar_Marine
|
||
|
//
|
||
|
//=======================================================
|
||
|
const idEventDef EV_TramCar_UseMountedGun( "useMountedGun", "e" );
|
||
|
const idEventDef EV_TramCar_SetPlayerDamageEnt( "setPlayerDamageEnt", "f" );
|
||
|
|
||
|
CLASS_DECLARATION( rvTramCar, rvTramCar_Marine )
|
||
|
EVENT( EV_TramCar_UseMountedGun, rvTramCar_Marine::Event_UseMountedGun )
|
||
|
EVENT( EV_TramCar_SetPlayerDamageEnt, rvTramCar_Marine::Event_SetPlayerDamageEntity )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::Spawn
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::Spawn() {
|
||
|
RegisterStateThread( playerOccupationStateThread, "PlayerOccupation" );
|
||
|
playerOccupationStateThread.SetState( "NotOccupied" );
|
||
|
|
||
|
RegisterStateThread( playerUsingMountedGunStateThread, "MountedGunInUse" );
|
||
|
playerUsingMountedGunStateThread.SetState( "NotUsingMountedGun" );
|
||
|
|
||
|
maxHealth = spawnArgs.GetInt( "health", "0" );
|
||
|
lastHeal = 0;
|
||
|
healDelay = spawnArgs.GetInt( "heal_delay", "15" );
|
||
|
healAmount = spawnArgs.GetInt( "heal_amount", "2" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::MidThink
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::MidThink() {
|
||
|
rvTramCar::MidThink();
|
||
|
|
||
|
if ( healDelay > 0 && lastHeal + healDelay < gameLocal.time && health < maxHealth ) {
|
||
|
health += healAmount;
|
||
|
|
||
|
if ( health > maxHealth ) {
|
||
|
health = maxHealth;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
playerOccupationStateThread.Execute();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::ActivateTramHud
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::ActivateTramHud( idPlayer* player ) {
|
||
|
if( !player ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
idUserInterface* hud = player->GetHud();
|
||
|
if( !hud ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
hud->HandleNamedEvent( "enterTram" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::DeactivateTramHud
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::DeactivateTramHud( idPlayer* player ) {
|
||
|
if( !player ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
idUserInterface* hud = player->GetHud();
|
||
|
if( !hud ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
hud->HandleNamedEvent( "leaveTram" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::UpdateTramHud
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::UpdateTramHud( idPlayer* player ) {
|
||
|
if( !player ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
idUserInterface* hud = player->GetHud();
|
||
|
if( !hud ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
hud->SetStateFloat( "tram_healthpct", GetHealthScale() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
rvTramCar_Marine::Damage
|
||
|
============
|
||
|
*/
|
||
|
void rvTramCar_Marine::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
|
||
|
rvTramCar::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
|
||
|
|
||
|
if( attacker == gameLocal.GetLocalPlayer() ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( fl.takedamage && GetDamageScale() < 0.35f ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( rvRandom::flrand() > spawnArgs.GetFloat("damageWarningFreq", "0.2") ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DriverSpeak( "lipsync_damageWarning", true );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::Killed
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
|
||
|
playerOccupationStateThread.Execute();
|
||
|
|
||
|
idPlayer* player = gameLocal.GetLocalPlayer();
|
||
|
if( player && EntityIsInside(player) ) {
|
||
|
player->SetDamageEntity( NULL );// This should fix the damage from tram car propogation issue
|
||
|
player->ExitVehicle( true );// This should fix the issue that was causing the player to get removed
|
||
|
}
|
||
|
|
||
|
rvTramCar::Killed( inflictor, attacker, damage, dir, location );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::Save
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::Save( idSaveGame *savefile ) const {
|
||
|
savefile->WriteInt( visibleEnemies.Num() );
|
||
|
for( int ix = visibleEnemies.Num() - 1; ix >= 0; --ix ) {
|
||
|
visibleEnemies[ix].Save( savefile );
|
||
|
}
|
||
|
|
||
|
playerOccupationStateThread.Save( savefile );
|
||
|
playerUsingMountedGunStateThread.Save( savefile );
|
||
|
|
||
|
// no need to save this since it's set in the restore
|
||
|
//savefile->WriteInt( maxHealth ); // cnicholson: added unsaved var
|
||
|
savefile->WriteInt( lastHeal );
|
||
|
savefile->WriteInt( healDelay );
|
||
|
savefile->WriteInt( healAmount );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::Restore
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::Restore( idRestoreGame *savefile ) {
|
||
|
int num = 0;
|
||
|
savefile->ReadInt( num );
|
||
|
visibleEnemies.SetNum( num );
|
||
|
for( int ix = visibleEnemies.Num() - 1; ix >= 0; --ix ) {
|
||
|
visibleEnemies[ix].Restore( savefile );
|
||
|
}
|
||
|
|
||
|
playerOccupationStateThread.Restore( savefile, this );
|
||
|
playerUsingMountedGunStateThread.Restore( savefile, this );
|
||
|
|
||
|
savefile->ReadInt( lastHeal );
|
||
|
savefile->ReadInt( healDelay );
|
||
|
savefile->ReadInt( healAmount );
|
||
|
|
||
|
maxHealth = spawnArgs.GetInt( "health", "0" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::LookAround
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::LookAround() {
|
||
|
idList<rvSplineMover*> moverList;
|
||
|
|
||
|
rvTramCar::LookAround();
|
||
|
|
||
|
if( !driver.IsValid() || driver->IsSpeaking() ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( LookOverLeftShoulder(moverList)) {
|
||
|
DriverSpeak( "lipsync_warningLeft", true );
|
||
|
driver->ScriptedAnim( "point_left", 0, false, true );
|
||
|
} else if( LookOverRightShoulder(moverList)) {
|
||
|
DriverSpeak( "lipsync_warningRight", true );
|
||
|
driver->ScriptedAnim( "point_right", 0, false, true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::LookOverLeftShoulder
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar_Marine::LookOverLeftShoulder( idList<rvSplineMover*>& list ) {
|
||
|
collisionFov.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
collisionFov.SetAxis( idAngles(0.0, -120.0f, 0.0f).ToMat3() * GetPhysics()->GetAxis() );
|
||
|
|
||
|
bool newOneFound = false;
|
||
|
Look( collisionFov, list );
|
||
|
|
||
|
// now determine if we've spotted a new enemy
|
||
|
for( int ix = list.Num() - 1; ix >= 0; --ix ) {
|
||
|
if ( !visibleEnemies.Find( list[ix] )) {
|
||
|
newOneFound = true;
|
||
|
visibleEnemies.AddUnique( list[ix] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return newOneFound;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::LookOverRightShoulder
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar_Marine::LookOverRightShoulder( idList<rvSplineMover*>& list ) {
|
||
|
collisionFov.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
collisionFov.SetAxis( idAngles(0.0, 120.0f, 0.0f).ToMat3() * GetPhysics()->GetAxis() );
|
||
|
|
||
|
bool newOneFound = false;
|
||
|
Look( collisionFov, list );
|
||
|
|
||
|
// now determine if we've spotted a new enemy
|
||
|
for( int ix = list.Num() - 1; ix >= 0; --ix ) {
|
||
|
if ( !visibleEnemies.Find( list[ix] )) {
|
||
|
newOneFound = true;
|
||
|
visibleEnemies.AddUnique( list[ix] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return newOneFound;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::EntityIsInside
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar_Marine::EntityIsInside( const idEntity* entity ) const {
|
||
|
assert( entity );
|
||
|
return GetPhysics()->GetAbsBounds().ContainsPoint( entity->GetPhysics()->GetAbsBounds().GetCenter() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::DeployRamp
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::DeployRamp() {
|
||
|
rvTramCar::DeployRamp();
|
||
|
|
||
|
if( weapons.Num() ) {
|
||
|
weapons[0]->Unlock();
|
||
|
weapons[0]->EjectAllDrivers( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::RetractRamp
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::RetractRamp() {
|
||
|
rvTramCar::RetractRamp();
|
||
|
|
||
|
UseMountedGun( gameLocal.GetLocalPlayer() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::UseMountedGun
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::UseMountedGun( idPlayer* player ) {
|
||
|
if( playerOccupationStateThread.CurrentStateIs("Occupied") && EntityIsInside(player) && weapons.Num() ) {
|
||
|
player->EnterVehicle( weapons[0] );
|
||
|
weapons[0]->Lock();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::Event_UseMountedGun
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::Event_UseMountedGun( idEntity* ent ) {
|
||
|
if( !ent || !ent->IsType(idPlayer::GetClassType()) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
UseMountedGun( static_cast<idPlayer*>(ent) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::Event_SetPlayerDamageEntity
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Marine::Event_SetPlayerDamageEntity(float f) {
|
||
|
|
||
|
gameLocal.GetLocalPlayer()->SetDamageEntity( (f? this : NULL) );
|
||
|
}
|
||
|
|
||
|
CLASS_STATES_DECLARATION( rvTramCar_Marine )
|
||
|
STATE( "Occupied", rvTramCar_Marine::State_Occupied )
|
||
|
STATE( "NotOccupied", rvTramCar_Marine::State_NotOccupied )
|
||
|
STATE( "UsingMountedGun", rvTramCar_Marine::State_UsingMountedGun )
|
||
|
STATE( "NotUsingMountedGun",rvTramCar_Marine::State_NotUsingMountedGun )
|
||
|
END_CLASS_STATES
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::State_Occupied
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar_Marine::State_Occupied( const stateParms_t& parms ) {
|
||
|
idPlayer* player = gameLocal.GetLocalPlayer();
|
||
|
|
||
|
if( !parms.stage ) {
|
||
|
//player->ProcessEvent( &EV_Player_DisableWeapon );
|
||
|
ActivateTramHud( player );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
if( !PlayerIsInside() ) {
|
||
|
playerOccupationStateThread.SetState( "NotOccupied" );
|
||
|
//gameLocal.GetLocalPlayer()->SetDamageEntity( NULL );
|
||
|
fl.takedamage = false;
|
||
|
return SRESULT_DONE_WAIT;
|
||
|
}
|
||
|
|
||
|
playerUsingMountedGunStateThread.Execute();
|
||
|
|
||
|
UpdateTramHud( player );
|
||
|
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::State_NotOccupied
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar_Marine::State_NotOccupied( const stateParms_t& parms ) {
|
||
|
if( !parms.stage ) {
|
||
|
//player->ProcessEvent( &EV_Player_EnableWeapon );
|
||
|
DeactivateTramHud( gameLocal.GetLocalPlayer() );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
if( PlayerIsInside() ) {
|
||
|
playerOccupationStateThread.SetState( "Occupied" );
|
||
|
//gameLocal.GetLocalPlayer()->SetDamageEntity( this );
|
||
|
fl.takedamage = true;
|
||
|
return SRESULT_DONE_WAIT;
|
||
|
}
|
||
|
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::State_UsingMountedGun
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar_Marine::State_UsingMountedGun( const stateParms_t& parms ) {
|
||
|
if( !parms.stage ) {
|
||
|
ActivateTramHud( gameLocal.GetLocalPlayer() );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
idPlayer* player = gameLocal.GetLocalPlayer();
|
||
|
if( player && !player->IsInVehicle() ) {
|
||
|
playerUsingMountedGunStateThread.SetState( "NotUsingMountedGun" );
|
||
|
}
|
||
|
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Marine::State_NotUsingMountedGun
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar_Marine::State_NotUsingMountedGun( const stateParms_t& parms ) {
|
||
|
idPlayer* player = gameLocal.GetLocalPlayer();
|
||
|
if( player && player->IsInVehicle() ) {
|
||
|
playerUsingMountedGunStateThread.SetState( "UsingMountedGun" );
|
||
|
}
|
||
|
|
||
|
return SRESULT_WAIT;
|
||
|
}
|
||
|
|
||
|
//=======================================================
|
||
|
//
|
||
|
// rvTramCar_Strogg
|
||
|
//
|
||
|
//=======================================================
|
||
|
CLASS_DECLARATION( rvTramCar, rvTramCar_Strogg )
|
||
|
EVENT( EV_PostSpawn, rvTramCar_Strogg::Event_PostSpawn )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::Spawn
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Strogg::Spawn() {
|
||
|
SetTarget( NULL );
|
||
|
|
||
|
RegisterStateThread( targetSearchStateThread, "targetSearch" );
|
||
|
targetSearchStateThread.SetState( "LookingForTarget" );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::SetTarget
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Strogg::SetTarget( idEntity* newTarget ) {
|
||
|
target = ConvertToMover( newTarget );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::GetTarget
|
||
|
================
|
||
|
*/
|
||
|
const rvSplineMover* rvTramCar_Strogg::GetTarget() const {
|
||
|
return target.GetEntity();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::Save
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Strogg::Save( idSaveGame *savefile ) const {
|
||
|
target.Save( savefile );
|
||
|
targetSearchStateThread.Save( savefile );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::Restore
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Strogg::Restore( idRestoreGame *savefile ) {
|
||
|
target.Restore( savefile );
|
||
|
targetSearchStateThread.Restore( savefile, this );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::WriteToSnapshot
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Strogg::WriteToSnapshot( idBitMsgDelta &msg ) const {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::ReadFromSnapshot
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Strogg::ReadFromSnapshot( const idBitMsgDelta &msg ) {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::Event_PostSpawn
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Strogg::Event_PostSpawn() {
|
||
|
idEntity* enemy = gameLocal.FindEntity( spawnArgs.GetString("enemy") );
|
||
|
|
||
|
SetTarget( enemy );
|
||
|
|
||
|
occupants.RemoveNull();
|
||
|
for( int ix = occupants.Num() - 1; ix >= 0; --ix ) {
|
||
|
occupants[ix]->SetEnemy( enemy );
|
||
|
}
|
||
|
|
||
|
rvTramCar::Event_PostSpawn();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::TargetIsToLeft
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar_Strogg::TargetIsToLeft() {
|
||
|
idList<rvSplineMover*> list;
|
||
|
|
||
|
if( LookLeft(list) ) {
|
||
|
for( int ix = list.Num() - 1; ix >= 0; --ix ) {
|
||
|
if( list[ix] == target ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::TargetIsToRight
|
||
|
================
|
||
|
*/
|
||
|
bool rvTramCar_Strogg::TargetIsToRight() {
|
||
|
idList<rvSplineMover*> list;
|
||
|
|
||
|
if( LookRight(list) ) {
|
||
|
for( int ix = list.Num() - 1; ix >= 0; --ix ) {
|
||
|
if( list[ix] == target ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::LookAround
|
||
|
================
|
||
|
*/
|
||
|
void rvTramCar_Strogg::LookAround() {
|
||
|
targetSearchStateThread.Execute();
|
||
|
}
|
||
|
|
||
|
CLASS_STATES_DECLARATION( rvTramCar_Strogg )
|
||
|
STATE( "LookingForTarget", rvTramCar_Strogg::State_LookingForTarget )
|
||
|
STATE( "TargetInSight", rvTramCar_Strogg::State_TargetInSight )
|
||
|
END_CLASS_STATES
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::State_LookingForTarget
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar_Strogg::State_LookingForTarget( const stateParms_t& parms ) {
|
||
|
static const int MSEC_DELAY = 100;
|
||
|
idList<rvSplineMover*> list;
|
||
|
|
||
|
if( !parms.stage ) {// Go back to random if we are supposed to be random
|
||
|
//idealTrackStateThread.SetState( "RandomTrack" );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
if( AdjustSpeed(list) ) {
|
||
|
return SRESULT_DELAY( MSEC_DELAY );
|
||
|
}
|
||
|
|
||
|
// Could optimise based on what track
|
||
|
if( TargetIsToLeft() || TargetIsToRight() ) {
|
||
|
targetSearchStateThread.SetState( "TargetInSight" );
|
||
|
return SRESULT_DONE;
|
||
|
}
|
||
|
|
||
|
SetSpeed( GetIdealSpeed() );
|
||
|
return SRESULT_DELAY( MSEC_DELAY );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
rvTramCar_Strogg::State_TargetInSight
|
||
|
================
|
||
|
*/
|
||
|
stateResult_t rvTramCar_Strogg::State_TargetInSight( const stateParms_t& parms ) {
|
||
|
static const int MSEC_DELAY = 3000;
|
||
|
|
||
|
if( !target.IsValid() || (!TargetIsToLeft() && !TargetIsToRight()) ) {
|
||
|
targetSearchStateThread.SetState( "LookingForTarget" );
|
||
|
return SRESULT_DONE;
|
||
|
}
|
||
|
|
||
|
if( !parms.stage ) {
|
||
|
SetIdealTrack( GetCurrentTrack() );
|
||
|
SetSpeed( target->GetSpeed() * 0.5f );
|
||
|
idealTrackStateThread.SetState( "AssignedTrack" );
|
||
|
StartSound( "snd_horn", SND_CHANNEL_ANY, 0, false, NULL );
|
||
|
return SRESULT_STAGE( parms.stage + 1 );
|
||
|
}
|
||
|
|
||
|
idList<rvSplineMover*> list;
|
||
|
if( AdjustSpeed(list) ) {
|
||
|
return SRESULT_DELAY( MSEC_DELAY );
|
||
|
}
|
||
|
|
||
|
float dot = GetPhysics()->GetAxis()[0] * (target->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin()).ToNormal();
|
||
|
float deltaSpeed = target->GetIdealSpeed() * rvRandom::flrand(0.0f, 0.1f) * SignZero(dot);
|
||
|
SetSpeed( target->GetIdealSpeed() + deltaSpeed );
|
||
|
|
||
|
return SRESULT_DELAY( MSEC_DELAY );
|
||
|
}
|