2019 lines
51 KiB
C++
2019 lines
51 KiB
C++
// Copyright (C) 2007 Id Software, Inc.
|
|
//
|
|
/*
|
|
|
|
Various utility objects and functions.
|
|
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#include "Misc.h"
|
|
#include "Player.h"
|
|
#include "Camera.h"
|
|
//#include "ai/AI.h"
|
|
#include "Projectile.h"
|
|
#include "WorldSpawn.h"
|
|
#include "ContentMask.h"
|
|
#include "Moveable.h"
|
|
#include "../decllib/declTypeHolder.h"
|
|
#include "../decllib/declImposter.h"
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idSpawnableEntity
|
|
|
|
A simple, spawnable entity with a model and no functionable ability of it's own.
|
|
For example, it can be used as a placeholder during development, for marking
|
|
locations on maps for script, or for simple placed models without any behavior
|
|
that can be bound to other entities. Should not be subclassed.
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, idSpawnableEntity )
|
|
END_CLASS
|
|
|
|
/*
|
|
======================
|
|
idSpawnableEntity::Spawn
|
|
======================
|
|
*/
|
|
void idSpawnableEntity::Spawn() {
|
|
// this just holds dict information
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdModelStatic
|
|
|
|
A simple, spawnable entity with a collision model and no functionable ability of its own.
|
|
|
|
NOTE: this entity is really a hack, and can go as soon as idEntity is cleaned up
|
|
( that is, when it has no renderEntity anymore )
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, sdModelStatic )
|
|
END_CLASS
|
|
|
|
/*
|
|
======================
|
|
sdModelStatic::Spawn
|
|
======================
|
|
*/
|
|
void sdModelStatic::Spawn( void ) {
|
|
Hide();
|
|
memset( &renderEntity, 0, sizeof( renderEntity ) );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdModelStatic::PostMapSpawn
|
|
===============
|
|
*/
|
|
void sdModelStatic::PostMapSpawn( void ) {
|
|
idEntity::PostMapSpawn();
|
|
|
|
sdInstanceCollector< sdLODEntity > lodEntity( false );
|
|
if ( lodEntity.Num() < 1 ) {
|
|
return;
|
|
}
|
|
sdLODEntity* lodEnt = lodEntity[ 0 ];
|
|
|
|
lodEnt->AddClipModel( new idClipModel( GetPhysics()->GetClipModel() ), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
|
|
|
|
PostEventMS( &EV_Remove, 0 );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdModelStatic::InhibitSpawn
|
|
================
|
|
*/
|
|
bool sdModelStatic::InhibitSpawn( const idDict& args ) {
|
|
if ( args.GetBool( "noClipModel" ) ) {
|
|
return true;
|
|
}
|
|
|
|
if ( args.GetBool( "mergecm" ) ) {
|
|
assert( 0 ); // jrad - the map compiler isn't doing its job if we ever get here
|
|
return true;
|
|
}
|
|
|
|
if ( args.GetBool( "inlineCollisionModel" ) ) {
|
|
assert( 0 ); // jrad - the map compiler isn't doing its job if we ever get here
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdDynamicSpawnPoint
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( sdScriptEntity, sdDynamicSpawnPoint )
|
|
END_CLASS
|
|
|
|
/*
|
|
===============
|
|
sdDynamicSpawnPoint::sdDynamicSpawnPoint
|
|
================
|
|
*/
|
|
sdDynamicSpawnPoint::sdDynamicSpawnPoint( void ) : spawnPoint( NULL ) {
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdDynamicSpawnPoint::~sdDynamicSpawnPoint
|
|
================
|
|
*/
|
|
sdDynamicSpawnPoint::~sdDynamicSpawnPoint( void ) {
|
|
gameLocal.UnRegisterSpawnPoint( spawnPoint );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdDynamicSpawnPoint::Spawn
|
|
================
|
|
*/
|
|
void sdDynamicSpawnPoint::Spawn( void ) {
|
|
spawnPoint = &gameLocal.RegisterSpawnPoint( this, vec3_origin, ang_zero );
|
|
spawnPoint->GetRequirements().Load( spawnArgs, "require" );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
sdDynamicSpawnPoint::CanCollide
|
|
==============
|
|
*/
|
|
bool sdDynamicSpawnPoint::CanCollide( const idEntity* other, int traceId ) const {
|
|
if ( traceId == TM_THIRDPERSON_OFFSET ) {
|
|
return false;
|
|
}
|
|
return idEntity::CanCollide( other, traceId );
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idPlayerStart
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, idPlayerStart )
|
|
END_CLASS
|
|
|
|
/*
|
|
===============
|
|
idPlayerStart::idPlayerStart
|
|
================
|
|
*/
|
|
idPlayerStart::idPlayerStart( void ) {
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idPlayerStart::InhibitSpawn
|
|
================
|
|
*/
|
|
bool idPlayerStart::InhibitSpawn( const idDict& args ) {
|
|
return gameLocal.isClient && !gameLocal.serverIsRepeater;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idPlayerStart::PostMapSpawn
|
|
================
|
|
*/
|
|
void idPlayerStart::PostMapSpawn( void ) {
|
|
sdSpawnPoint* spot;
|
|
|
|
idAngles angles;
|
|
|
|
const char* targetName = spawnArgs.GetString( "target" );
|
|
idEntity* target = gameLocal.FindEntity( targetName );
|
|
|
|
const char* ownerName = spawnArgs.GetString( "owner" );
|
|
|
|
bool parachute = spawnArgs.GetBool( "parachute" );
|
|
idVec3 origin = GetPhysics()->GetOrigin();
|
|
if ( parachute ) {
|
|
origin.z += spawnArgs.GetFloat( "parachute_height", "2048" );
|
|
}
|
|
|
|
if ( *ownerName ) {
|
|
idEntity* owner = gameLocal.FindEntity( ownerName );
|
|
if ( !owner ) {
|
|
gameLocal.Error( "idPlayerStart::PostMapSpawn Could not find owner '%s'", ownerName );
|
|
}
|
|
|
|
idVec3 org = ( origin - owner->GetPhysics()->GetOrigin() ) * owner->GetPhysics()->GetAxis().Transpose();
|
|
if ( target ) {
|
|
idVec3 vec = target->GetPhysics()->GetOrigin() - org;
|
|
vec.Normalize();
|
|
angles = vec.ToMat3().ToAngles();
|
|
} else {
|
|
angles = GetPhysics()->GetAxis().ToAngles();
|
|
}
|
|
spot = &gameLocal.RegisterSpawnPoint( owner, org, angles );
|
|
|
|
} else {
|
|
if( target ) {
|
|
idVec3 vec = target->GetPhysics()->GetOrigin() - origin;
|
|
vec.Normalize();
|
|
angles = vec.ToMat3().ToAngles();
|
|
} else {
|
|
angles = GetPhysics()->GetAxis().ToAngles();
|
|
}
|
|
spot = &gameLocal.RegisterSpawnPoint( NULL, origin, angles );
|
|
}
|
|
|
|
spot->GetRequirements().Load( spawnArgs, "require" );
|
|
spot->SetParachute( parachute );
|
|
|
|
PostEventMS( &EV_Remove, 0 );
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idForceField
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
const idEventDef EV_Toggle( "toggle", '\0', DOC_TEXT( "Toggles the state of the force field." ), 0, "Calling $event:activate$ on a force field will toggle the state, then reset it after a set wait period, using $event:toggle$ will not reset." );
|
|
|
|
CLASS_DECLARATION( idEntity, idForceField )
|
|
EVENT( EV_Activate, idForceField::Event_Activate )
|
|
EVENT( EV_Toggle, idForceField::Event_Toggle )
|
|
EVENT( EV_FindTargets, idForceField::Event_FindTargets )
|
|
EVENT( EV_GetMins, idForceField::Event_GetMins )
|
|
EVENT( EV_GetMaxs, idForceField::Event_GetMaxs )
|
|
END_CLASS
|
|
|
|
idCVar g_debugForceFields( "g_debugForceFields", "0", CVAR_GAME | CVAR_BOOL, "" );
|
|
|
|
/*
|
|
===============
|
|
idForceField::Toggle
|
|
================
|
|
*/
|
|
void idForceField::Toggle( void ) {
|
|
active = !active;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idForceField::Think
|
|
================
|
|
*/
|
|
void idForceField::Think( void ) {
|
|
if ( active ) {
|
|
// evaluate force
|
|
forceField.Evaluate( gameLocal.time );
|
|
}
|
|
Present();
|
|
|
|
if ( g_debugForceFields.GetBool() ) {
|
|
gameRenderWorld->DebugBounds( colorBlue, forceField.GetClipModel()->GetBounds(), forceField.GetClipModel()->GetOrigin() );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idForceField::Spawn
|
|
================
|
|
*/
|
|
void idForceField::Spawn( void ) {
|
|
idVec3 uniform;
|
|
float explosion, implosion, randomTorque;
|
|
|
|
if ( spawnArgs.GetVector( "uniform", "0 0 0", uniform ) ) {
|
|
forceField.Uniform( uniform );
|
|
} else if ( spawnArgs.GetFloat( "explosion", "0", explosion ) ) {
|
|
forceField.Explosion( explosion );
|
|
} else if ( spawnArgs.GetFloat( "implosion", "0", implosion ) ) {
|
|
forceField.Implosion( implosion );
|
|
}
|
|
|
|
if ( spawnArgs.GetFloat( "randomTorque", "0", randomTorque ) ) {
|
|
forceField.RandomTorque( randomTorque );
|
|
}
|
|
|
|
if ( spawnArgs.GetBool( "applyForce", "0" ) ) {
|
|
forceField.SetApplyType( FORCEFIELD_APPLY_FORCE );
|
|
} else if ( spawnArgs.GetBool( "applyImpulse", "0" ) ) {
|
|
forceField.SetApplyType( FORCEFIELD_APPLY_IMPULSE );
|
|
} else {
|
|
forceField.SetApplyType( FORCEFIELD_APPLY_VELOCITY );
|
|
}
|
|
|
|
forceField.SetPlayerOnly( spawnArgs.GetBool( "playerOnly", "0" ) );
|
|
forceField.SetMonsterOnly( spawnArgs.GetBool( "monsterOnly", "0" ) );
|
|
|
|
// set the collision model on the force field
|
|
forceField.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ) );
|
|
|
|
// remove the collision model from the physics object
|
|
GetPhysics()->SetClipModel( NULL, 1.0f );
|
|
|
|
active = spawnArgs.GetBool( "start_on" );
|
|
|
|
PostEventMS( &EV_FindTargets, 0 );
|
|
|
|
BecomeActive( TH_THINK );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idForceField::Event_Toggle
|
|
================
|
|
*/
|
|
void idForceField::Event_Toggle( void ) {
|
|
Toggle();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idForceField::Event_Activate
|
|
================
|
|
*/
|
|
void idForceField::Event_Activate( idEntity *activator ) {
|
|
float wait;
|
|
|
|
Toggle();
|
|
if ( spawnArgs.GetFloat( "wait", "0.01", wait ) ) {
|
|
PostEventSec( &EV_Toggle, wait );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idForceField::Event_FindTargets
|
|
================
|
|
*/
|
|
void idForceField::Event_FindTargets( void ) {
|
|
FindTargets();
|
|
RemoveNullTargets();
|
|
if ( targets.Num() ) {
|
|
forceField.Uniform( targets[0].GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idForceField::Event_GetMins
|
|
================
|
|
*/
|
|
void idForceField::Event_GetMins( void ) {
|
|
sdProgram::ReturnVector( forceField.GetClipModel()->GetBounds()[ 0 ] );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idForceField::Event_GetMaxs
|
|
================
|
|
*/
|
|
void idForceField::Event_GetMaxs( void ) {
|
|
sdProgram::ReturnVector( forceField.GetClipModel()->GetBounds()[ 1 ] );
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idAnimated
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
const idEventDefInternal EV_Animated_Start( "internal_start" );
|
|
const idEventDefInternal EV_AnimDone( "internal_animDone", "d" );
|
|
const idEventDef EV_StartRagdoll( "startRagdoll", '\0', DOC_TEXT( "Switches the entity into ragdoll mode from its current animation pose." ), 0, "This will do nothing if the entity does not have an $decl:articulatedFigure$ set up." );
|
|
|
|
CLASS_DECLARATION( idAFEntity_Base, idAnimated )
|
|
EVENT( EV_Activate, idAnimated::Event_Activate )
|
|
EVENT( EV_Animated_Start, idAnimated::Event_Start )
|
|
EVENT( EV_StartRagdoll, idAnimated::Event_StartRagdoll )
|
|
EVENT( EV_AnimDone, idAnimated::Event_AnimDone )
|
|
END_CLASS
|
|
|
|
/*
|
|
===============
|
|
idAnimated::idAnimated
|
|
================
|
|
*/
|
|
idAnimated::idAnimated() {
|
|
anim = 0;
|
|
blendFrames = 0;
|
|
soundJoint = INVALID_JOINT;
|
|
activated = false;
|
|
combatModel = NULL;
|
|
activator = NULL;
|
|
current_anim_index = 0;
|
|
num_anims = 0;
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAnimated::idAnimated
|
|
================
|
|
*/
|
|
idAnimated::~idAnimated() {
|
|
gameLocal.clip.DeleteClipModel( combatModel );
|
|
combatModel = NULL;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAnimated::Spawn
|
|
================
|
|
*/
|
|
void idAnimated::Spawn( void ) {
|
|
idStr animname;
|
|
int anim2;
|
|
float wait;
|
|
const char *joint;
|
|
|
|
joint = spawnArgs.GetString( "sound_bone", "origin" );
|
|
soundJoint = animator.GetJointHandle( joint );
|
|
if ( soundJoint == INVALID_JOINT ) {
|
|
gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString(0), joint );
|
|
}
|
|
|
|
LoadAF();
|
|
|
|
// allow bullets to collide with a combat model
|
|
if ( spawnArgs.GetBool( "combatModel", "0" ) ) {
|
|
combatModel = new idClipModel( modelDefHandle );
|
|
}
|
|
|
|
// allow the entity to take damage
|
|
if ( spawnArgs.GetBool( "takeDamage", "0" ) ) {
|
|
fl.takedamage = true;
|
|
}
|
|
|
|
blendFrames = 0;
|
|
|
|
current_anim_index = 0;
|
|
spawnArgs.GetInt( "num_anims", "0", num_anims );
|
|
|
|
blendFrames = spawnArgs.GetInt( "blend_in" );
|
|
|
|
animname = spawnArgs.GetString( num_anims ? "anim1" : "anim" );
|
|
if ( !animname.Length() ) {
|
|
anim = 0;
|
|
} else {
|
|
anim = animator.GetAnim( animname );
|
|
if ( !anim ) {
|
|
gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animname.c_str() );
|
|
}
|
|
}
|
|
|
|
if ( spawnArgs.GetBool( "hide" ) ) {
|
|
Hide();
|
|
|
|
if ( !num_anims ) {
|
|
blendFrames = 0;
|
|
}
|
|
} else if ( spawnArgs.GetString( "start_anim", "", animname ) ) {
|
|
anim2 = animator.GetAnim( animname );
|
|
if ( !anim2 ) {
|
|
gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animname.c_str() );
|
|
}
|
|
animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, 0 );
|
|
} else if ( anim ) {
|
|
// init joints to the first frame of the animation
|
|
animator.SetFrame( ANIMCHANNEL_ALL, anim, 1, gameLocal.time, 0 );
|
|
|
|
if ( !num_anims ) {
|
|
blendFrames = 0;
|
|
}
|
|
}
|
|
|
|
spawnArgs.GetFloat( "wait", "-1", wait );
|
|
|
|
if ( wait >= 0 ) {
|
|
PostEventSec( &EV_Activate, wait, this );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAnimated::LoadAF
|
|
===============
|
|
*/
|
|
bool idAnimated::LoadAF( void ) {
|
|
idStr fileName;
|
|
|
|
if ( !spawnArgs.GetString( "ragdoll", "*unknown*", fileName ) ) {
|
|
return false;
|
|
}
|
|
af.SetAnimator( GetAnimator() );
|
|
return af.Load( this, fileName );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAnimated::GetPhysicsToSoundTransform
|
|
===============
|
|
*/
|
|
bool idAnimated::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
|
|
animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis );
|
|
axis = renderEntity.axis;
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAnimated::StartRagdoll
|
|
================
|
|
*/
|
|
bool idAnimated::StartRagdoll( void ) {
|
|
// if no AF loaded
|
|
if ( !af.IsLoaded() ) {
|
|
return false;
|
|
}
|
|
|
|
// if the AF is already active
|
|
if ( af.IsActive() ) {
|
|
return true;
|
|
}
|
|
|
|
// disable any collision model used
|
|
GetPhysics()->UnlinkClip();
|
|
|
|
// start using the AF
|
|
af.StartFromCurrentPose( spawnArgs.GetInt( "velocityTime", "0" ) );
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idAnimated::PlayNextAnim
|
|
=====================
|
|
*/
|
|
void idAnimated::PlayNextAnim( void ) {
|
|
const char *animname;
|
|
int len;
|
|
int cycle;
|
|
|
|
if ( current_anim_index >= num_anims ) {
|
|
Hide();
|
|
if ( spawnArgs.GetBool( "remove" ) ) {
|
|
PostEventMS( &EV_Remove, 0 );
|
|
} else {
|
|
current_anim_index = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
Show();
|
|
current_anim_index++;
|
|
|
|
spawnArgs.GetString( va( "anim%d", current_anim_index ), NULL, &animname );
|
|
if ( !animname ) {
|
|
anim = 0;
|
|
animator.Clear( ANIMCHANNEL_ALL, gameLocal.time, FRAME2MS( blendFrames ) );
|
|
return;
|
|
}
|
|
|
|
anim = animator.GetAnim( animname );
|
|
if ( !anim ) {
|
|
gameLocal.Warning( "missing anim '%s' on %s", animname, name.c_str() );
|
|
return;
|
|
}
|
|
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animname );
|
|
}
|
|
|
|
spawnArgs.GetInt( "cycle", "1", cycle );
|
|
if ( ( current_anim_index == num_anims ) && spawnArgs.GetBool( "loop_last_anim" ) ) {
|
|
cycle = -1;
|
|
}
|
|
|
|
animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) );
|
|
animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
|
|
|
|
len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength();
|
|
if ( len >= 0 ) {
|
|
PostEventMS( &EV_AnimDone, len, current_anim_index );
|
|
}
|
|
|
|
// offset the start time of the shader to sync it to the game time
|
|
renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
|
|
|
|
animator.ForceUpdate();
|
|
UpdateAnimation();
|
|
UpdateVisuals();
|
|
Present();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAnimated::Event_StartRagdoll
|
|
================
|
|
*/
|
|
void idAnimated::Event_StartRagdoll( void ) {
|
|
StartRagdoll();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAnimated::Event_AnimDone
|
|
================
|
|
*/
|
|
void idAnimated::Event_AnimDone( int animindex ) {
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
const idAnim *animPtr = animator.GetAnim( anim );
|
|
gameLocal.Printf( "%d: '%s' end anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" );
|
|
}
|
|
|
|
if ( ( animindex >= num_anims ) && spawnArgs.GetBool( "remove" ) ) {
|
|
Hide();
|
|
PostEventMS( &EV_Remove, 0 );
|
|
} else if ( spawnArgs.GetBool( "auto_advance" ) ) {
|
|
PlayNextAnim();
|
|
} else {
|
|
activated = false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAnimated::Event_Activate
|
|
================
|
|
*/
|
|
void idAnimated::Event_Activate( idEntity *_activator ) {
|
|
if ( num_anims ) {
|
|
PlayNextAnim();
|
|
activator = _activator;
|
|
return;
|
|
}
|
|
|
|
if ( activated ) {
|
|
// already activated
|
|
return;
|
|
}
|
|
|
|
activated = true;
|
|
activator = _activator;
|
|
ProcessEvent( &EV_Animated_Start );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAnimated::Event_Start
|
|
================
|
|
*/
|
|
void idAnimated::Event_Start( void ) {
|
|
int cycle;
|
|
int len;
|
|
|
|
Show();
|
|
|
|
if ( num_anims ) {
|
|
PlayNextAnim();
|
|
return;
|
|
}
|
|
|
|
if ( anim ) {
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
const idAnim *animPtr = animator.GetAnim( anim );
|
|
gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" );
|
|
}
|
|
spawnArgs.GetInt( "cycle", "1", cycle );
|
|
animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) );
|
|
animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
|
|
|
|
len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength();
|
|
if ( len >= 0 ) {
|
|
PostEventMS( &EV_AnimDone, len, 1 );
|
|
}
|
|
}
|
|
|
|
// offset the start time of the shader to sync it to the game time
|
|
renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
|
|
|
|
animator.ForceUpdate();
|
|
UpdateAnimation();
|
|
UpdateVisuals();
|
|
Present();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStaticEntityNetworkData::~sdStaticEntityNetworkData
|
|
===============
|
|
*/
|
|
sdStaticEntityNetworkData::~sdStaticEntityNetworkData( void ) {
|
|
delete physicsData;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStaticEntityNetworkData::MakeDefault
|
|
===============
|
|
*/
|
|
void sdStaticEntityNetworkData::MakeDefault( void ) {
|
|
if ( physicsData != NULL ) {
|
|
physicsData->MakeDefault();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStaticEntityNetworkData::Write
|
|
===============
|
|
*/
|
|
void sdStaticEntityNetworkData::Write( idFile* file ) const {
|
|
if ( physicsData != NULL ) {
|
|
physicsData->Write( file );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStaticEntityNetworkData::Read
|
|
===============
|
|
*/
|
|
void sdStaticEntityNetworkData::Read( idFile* file ) {
|
|
if ( physicsData != NULL ) {
|
|
physicsData->Read( file );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStaticEntityNetworkData::MakeDefault
|
|
===============
|
|
*/
|
|
void sdStaticEntityBroadcastData::MakeDefault( void ) {
|
|
if ( physicsData != NULL ) {
|
|
physicsData->MakeDefault();
|
|
}
|
|
hidden = -1;
|
|
forceDisableClip = -1;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStaticEntityBroadcastData::~sdStaticEntityBroadcastData
|
|
===============
|
|
*/
|
|
sdStaticEntityBroadcastData::~sdStaticEntityBroadcastData( void ) {
|
|
delete physicsData;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStaticEntityBroadcastData::Write
|
|
===============
|
|
*/
|
|
void sdStaticEntityBroadcastData::Write( idFile* file ) const {
|
|
if ( physicsData != NULL ) {
|
|
physicsData->Write( file );
|
|
}
|
|
|
|
file->WriteBool( hidden > 0 );
|
|
file->WriteBool( forceDisableClip > 0 );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStaticEntityBroadcastData::Read
|
|
===============
|
|
*/
|
|
void sdStaticEntityBroadcastData::Read( idFile* file ) {
|
|
if ( physicsData != NULL ) {
|
|
physicsData->Read( file );
|
|
}
|
|
|
|
bool temp;
|
|
file->ReadBool( temp );
|
|
hidden = temp ? 1 : 0;
|
|
file->ReadBool( temp );
|
|
forceDisableClip = temp ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idStaticEntity
|
|
|
|
Some static entities may be optimized into inline geometry by dmap
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, idStaticEntity )
|
|
END_CLASS
|
|
|
|
/*
|
|
===============
|
|
idStaticEntity::idStaticEntity
|
|
===============
|
|
*/
|
|
idStaticEntity::idStaticEntity( void ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::~idStaticEntity
|
|
================
|
|
*/
|
|
idStaticEntity::~idStaticEntity( void ) {
|
|
delete []renderEntity.areas;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idStaticEntity::Spawn
|
|
===============
|
|
*/
|
|
void idStaticEntity::Spawn( void ) {
|
|
bool solid = spawnArgs.GetBool( "solid" );
|
|
bool hidden = spawnArgs.GetBool( "hide" );
|
|
bool disableClip = spawnArgs.GetBool( "disableClip" );
|
|
|
|
const char *areas;
|
|
if ( spawnArgs.GetString( "areas", "", &areas ) ) {
|
|
idStrList areaList;
|
|
idSplitStringIntoList( areaList, areas, " " );
|
|
if ( areaList.Num() ) {
|
|
renderEntity.numAreas = areaList.Num();
|
|
renderEntity.areas = new int[ areaList.Num() ];
|
|
for (int i=0; i<areaList.Num(); i++ ) {
|
|
renderEntity.areas[i] = atoi( areaList[i].c_str() );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( solid ) {
|
|
GetPhysics()->SetContents( CONTENTS_SOLID );
|
|
} else {
|
|
GetPhysics()->SetContents( 0 );
|
|
}
|
|
|
|
if ( hidden ) {
|
|
Hide();
|
|
}
|
|
if ( disableClip ) {
|
|
ForceDisableClip();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idStaticEntity::PostMapSpawn
|
|
===============
|
|
*/
|
|
void idStaticEntity::PostMapSpawn( void ) {
|
|
idEntity::PostMapSpawn();
|
|
|
|
if ( !IsNetSynced() && !spawnArgs.GetBool( "dynamic" ) ) {
|
|
sdInstanceCollector< sdLODEntity > lodEntity( false );
|
|
if ( lodEntity.Num() < 1 ) {
|
|
return;
|
|
}
|
|
sdLODEntity* lodEnt = lodEntity[ 0 ];
|
|
|
|
if ( GetPhysics()->GetNumClipModels() > 0 ) {
|
|
lodEnt->AddClipModel( new idClipModel( GetPhysics()->GetClipModel() ), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
|
|
}
|
|
|
|
if ( !IsHidden() && renderEntity.hModel != NULL ) {
|
|
lodEnt->AddRenderEntity( renderEntity, -1 );
|
|
}
|
|
|
|
PostEventMS( &EV_Remove, 0 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::InhibitSpawn
|
|
================
|
|
*/
|
|
bool idStaticEntity::InhibitSpawn( const idDict& args ) {
|
|
assert( gameLocal.world != NULL );
|
|
|
|
// an inline static model will not do anything at all
|
|
if ( args.GetBool( "inline" ) || gameLocal.world->spawnArgs.GetBool( "inlineAllStatics" ) ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::Think
|
|
================
|
|
*/
|
|
void idStaticEntity::Think( void ) {
|
|
idEntity::Think();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::Hide
|
|
================
|
|
*/
|
|
void idStaticEntity::Hide( void ) {
|
|
idEntity::Hide();
|
|
fl.forceDisableClip = true;
|
|
DisableClip();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::Show
|
|
================
|
|
*/
|
|
void idStaticEntity::Show( void ) {
|
|
idEntity::Show();
|
|
fl.forceDisableClip = false;
|
|
EnableClip();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::ApplyNetworkState
|
|
================
|
|
*/
|
|
void idStaticEntity::ApplyNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& newState ) {
|
|
if ( mode == NSM_VISIBLE ) {
|
|
NET_GET_NEW( sdStaticEntityNetworkData );
|
|
NET_APPLY_STATE_PHYSICS;
|
|
} else if ( mode == NSM_BROADCAST ) {
|
|
NET_GET_NEW( sdStaticEntityBroadcastData );
|
|
NET_APPLY_STATE_PHYSICS;
|
|
|
|
if ( newData.hidden > 0 ) {
|
|
Hide();
|
|
} else {
|
|
Show();
|
|
}
|
|
|
|
if ( newData.forceDisableClip > 0 ) {
|
|
ForceDisableClip();
|
|
} else {
|
|
ForceEnableClip();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::ReadNetworkState
|
|
================
|
|
*/
|
|
void idStaticEntity::ReadNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& baseState, sdEntityStateNetworkData& newState, const idBitMsg& msg ) const {
|
|
if ( mode == NSM_VISIBLE ) {
|
|
NET_GET_STATES( sdStaticEntityNetworkData );
|
|
NET_READ_STATE_PHYSICS
|
|
|
|
return;
|
|
}
|
|
if ( mode == NSM_BROADCAST ) {
|
|
NET_GET_STATES( sdStaticEntityBroadcastData );
|
|
NET_READ_STATE_PHYSICS;
|
|
|
|
newData.hidden = msg.ReadBool() ? 1 : 0;
|
|
newData.forceDisableClip = msg.ReadBool() ? 1 : 0;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::WriteNetworkState
|
|
================
|
|
*/
|
|
void idStaticEntity::WriteNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& baseState, sdEntityStateNetworkData& newState, idBitMsg& msg ) const {
|
|
if ( mode == NSM_VISIBLE ) {
|
|
NET_GET_STATES( sdStaticEntityNetworkData );
|
|
NET_WRITE_STATE_PHYSICS
|
|
|
|
return;
|
|
}
|
|
if ( mode == NSM_BROADCAST ) {
|
|
NET_GET_STATES( sdStaticEntityBroadcastData );
|
|
NET_WRITE_STATE_PHYSICS;
|
|
|
|
newData.hidden = fl.hidden ? 1 : 0;
|
|
newData.forceDisableClip = fl.forceDisableClip ? 1 : 0;
|
|
|
|
msg.WriteBool( fl.hidden );
|
|
msg.WriteBool( fl.forceDisableClip );
|
|
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::CheckNetworkStateChanges
|
|
================
|
|
*/
|
|
bool idStaticEntity::CheckNetworkStateChanges( networkStateMode_t mode, const sdEntityStateNetworkData& baseState ) const {
|
|
if ( mode == NSM_VISIBLE ) {
|
|
NET_GET_BASE( sdStaticEntityNetworkData );
|
|
NET_CHECK_STATE_PHYSICS
|
|
|
|
return false;
|
|
}
|
|
if ( mode == NSM_BROADCAST ) {
|
|
NET_GET_BASE( sdStaticEntityBroadcastData );
|
|
NET_CHECK_STATE_PHYSICS
|
|
|
|
if ( ( fl.hidden ? 1 : 0 ) != baseData.hidden ) {
|
|
return true;
|
|
}
|
|
if ( ( fl.forceDisableClip ? 1 : 0 ) != baseData.forceDisableClip ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idStaticEntity::CreateNetworkStructure
|
|
================
|
|
*/
|
|
sdEntityStateNetworkData* idStaticEntity::CreateNetworkStructure( networkStateMode_t mode ) const {
|
|
if ( mode == NSM_VISIBLE ) {
|
|
sdStaticEntityNetworkData* newData = new sdStaticEntityNetworkData();
|
|
|
|
newData->physicsData = GetPhysics()->CreateNetworkStructure( mode );
|
|
|
|
return newData;
|
|
}
|
|
if ( mode == NSM_BROADCAST ) {
|
|
sdStaticEntityBroadcastData* newData = new sdStaticEntityBroadcastData();
|
|
|
|
newData->physicsData = GetPhysics()->CreateNetworkStructure( mode );
|
|
|
|
return newData;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdEnvDefinition
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, sdEnvDefinitionEntity )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
sdEnvDefinition::Spawn
|
|
================
|
|
*/
|
|
void sdEnvDefinitionEntity::Spawn( void ) {
|
|
|
|
sdEnvDefinition env;
|
|
spawnArgs.GetVector( "origin", "0 0 0", env.origin );
|
|
spawnArgs.GetString( "env_name", "", env.name );
|
|
spawnArgs.GetInt( "env_size", "128", env.size );
|
|
|
|
if ( env.name.Length() ) {
|
|
gameLocal.AddEnvDefinition( env );
|
|
} else {
|
|
gameLocal.Warning( "No env_name field specified on environment definition, skipped" );
|
|
}
|
|
PostEventMS( &EV_Remove, 0 );
|
|
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdSpawnController
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( sdScriptEntity, sdSpawnController )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
sdSpawnController::Spawn
|
|
================
|
|
*/
|
|
void sdSpawnController::Spawn( void ) {
|
|
spawnRequirements.Load( spawnArgs, "require_spawn" );
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdLiquid
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, sdLiquid )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
sdLiquid::sdLiquid
|
|
================
|
|
*/
|
|
sdLiquid::sdLiquid( void ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLiquid::Spawn
|
|
================
|
|
*/
|
|
void sdLiquid::Spawn( void ) {
|
|
current = spawnArgs.GetVector( "current" );
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdLODEntity
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, sdLODEntity )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
sdLODEntity::sdLODEntity
|
|
================
|
|
*/
|
|
sdLODEntity::sdLODEntity() {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLODEntity::~sdLODEntity
|
|
================
|
|
*/
|
|
sdLODEntity::~sdLODEntity() {
|
|
FreeModelDefs();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLODEntity::FreeModelDefs
|
|
================
|
|
*/
|
|
void sdLODEntity::FreeModelDefs() {
|
|
for ( int i = 0; i < modelDefHandles.Num(); i++ ) {
|
|
int& modelDefHandle = modelDefHandles[ i ];
|
|
|
|
if ( modelDefHandle != -1 ) {
|
|
renderEntity_t *re = gameRenderWorld->GetRenderEntity( modelDefHandle );
|
|
delete []re->dummies;
|
|
|
|
gameRenderWorld->FreeEntityDef( modelDefHandle );
|
|
modelDefHandle = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLODEntity::AddRenderEntity
|
|
================
|
|
*/
|
|
void sdLODEntity::AddRenderEntity( const renderEntity_t& entity, int ID ) {
|
|
modelDefHandles.Alloc() = gameRenderWorld->AddEntityDef( &entity );
|
|
modelID.Alloc() = ID;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLODEntity::AddClipModel
|
|
================
|
|
*/
|
|
void sdLODEntity::AddClipModel( idClipModel* clipModel, const idVec3& origin, const idMat3& axes ) {
|
|
int numClipModels = physicsObj.GetNumClipModels();
|
|
|
|
physicsObj.SetClipModel( clipModel, 1.0f, numClipModels );
|
|
physicsObj.SetOrigin( origin, numClipModels );
|
|
physicsObj.SetAxis( axes, numClipModels );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLODEntity::Spawn
|
|
================
|
|
*/
|
|
void sdLODEntity::Spawn() {
|
|
physicsObj.SetSelf( this );
|
|
physicsObj.SetOrigin( GetPhysics()->GetOrigin(), 0 );
|
|
physicsObj.SetAxis( GetPhysics()->GetAxis(), 0 );
|
|
|
|
// add models
|
|
const idKeyValue* arg;
|
|
renderEntity_t renderEntity;
|
|
|
|
memset( &renderEntity, 0, sizeof( renderEntity ) );
|
|
renderEntity.spawnID = gameLocal.GetSpawnId( this );//renderEntity.entityNum = entityNumber;
|
|
renderEntity.axis.Identity();
|
|
renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0f;
|
|
|
|
const char* temp = NULL;
|
|
|
|
for ( int i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
|
|
arg = spawnArgs.GetKeyVal( i );
|
|
|
|
if ( !arg->GetKey().Icmpn( "model", idStr::Length( "model" ) ) ) {
|
|
const char* model = arg->GetValue();
|
|
|
|
if ( *model != '\0' ) {
|
|
renderEntity.hModel = renderModelManager->FindModel( model );
|
|
}
|
|
|
|
idStr modelID = ( arg->GetKey().c_str() + idStr::Length( "model" ) );
|
|
|
|
if ( renderEntity.hModel != NULL && !renderEntity.hModel->IsDefaultModel() ) {
|
|
renderEntity.bounds = renderEntity.hModel->Bounds();
|
|
renderEntity.origin = spawnArgs.GetVector( "origin" + modelID );
|
|
renderEntity.shadowVisDistMult = spawnArgs.GetFloat( "shadowVisDistMult" + modelID, "0" );
|
|
renderEntity.maxVisDist = spawnArgs.GetInt( "maxvisdist" + modelID );
|
|
renderEntity.minVisDist = spawnArgs.GetInt( "minvisdist" + modelID );
|
|
renderEntity.visDistFalloff = spawnArgs.GetFloat( "visDistFalloff" + modelID, "0.25" );
|
|
renderEntity.mapId = spawnArgs.GetInt( "mapid" + modelID );
|
|
renderEntity.flags.pushByCenter = spawnArgs.GetBool( "pushByOrigin" + modelID );
|
|
renderEntity.flags.occlusionTest = spawnArgs.GetBool( "occlusionTest" + modelID );
|
|
renderEntity.flags.noShadow = spawnArgs.GetBool( "noShadows" + modelID );
|
|
renderEntity.flags.noSelfShadow = spawnArgs.GetBool( "noSelfShadows" + modelID );
|
|
renderEntity.flags.dontCastFromAtmosLight = spawnArgs.GetBool( "dontCastFromAtmosLight" + modelID );
|
|
renderEntity.dummies = NULL;
|
|
renderEntity.numVisDummies = 0;
|
|
|
|
idStr gpuSpecParam = spawnArgs.GetString( "drawSpec" + modelID, "low" );
|
|
if ( gpuSpecParam.Icmp( "high" ) == 0 ) {
|
|
renderEntity.drawSpec = 2;
|
|
} else if ( gpuSpecParam.Icmp( "med" ) == 0 || gpuSpecParam.Icmp( "medium" ) == 0 ) {
|
|
renderEntity.drawSpec = 1;
|
|
} else if ( gpuSpecParam.Icmp( "low" ) == 0 ) {
|
|
renderEntity.drawSpec = 0;
|
|
} else {
|
|
renderEntity.drawSpec = 0;
|
|
}
|
|
|
|
idStr shadowSpec = spawnArgs.GetString( "shadowSpec" + modelID , "low" );
|
|
if ( shadowSpec.Icmp( "high" ) == 0 ) {
|
|
renderEntity.shadowSpec = 2;
|
|
} else if ( shadowSpec.Icmp( "med" ) == 0 || shadowSpec.Icmp( "medium" ) == 0 ) {
|
|
renderEntity.shadowSpec = 1;
|
|
} else if ( shadowSpec.Icmp( "low" ) == 0 ) {
|
|
renderEntity.shadowSpec = 0;
|
|
} else {
|
|
renderEntity.shadowSpec = 0;
|
|
}
|
|
|
|
temp = spawnArgs.GetString( "ambientCubeMap" + modelID );
|
|
if ( *temp ) {
|
|
renderEntity.ambientCubeMap = declHolder.FindAmbientCubeMap( temp );
|
|
} else {
|
|
renderEntity.ambientCubeMap = NULL;
|
|
}
|
|
|
|
// add to renderer
|
|
AddRenderEntity( renderEntity, atoi( modelID ) );
|
|
|
|
// find inlineCollisionModel value
|
|
if ( !spawnArgs.GetBool( "inlineCollisionModel" + modelID, "1" ) ) {
|
|
// hook up collision model
|
|
AddClipModel( new idClipModel( model ), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
|
|
}
|
|
|
|
// find instanced collision models
|
|
int id = 0;
|
|
const idKeyValue* kv = spawnArgs.FindKey( "cm_model" + modelID + "_0" );
|
|
|
|
while( kv != NULL ) {
|
|
idVec3 origin = spawnArgs.GetVector( va( "cmodel%s_%d_origin", modelID.c_str(), id ), "0 0 0" );
|
|
idMat3 axis = spawnArgs.GetMatrix( va( "cmodel%s_%d_axis", modelID.c_str(), id ), "1 0 0 0 1 0 0 0 1" );
|
|
AddClipModel( new idClipModel( kv->GetValue().c_str() ), origin, axis );
|
|
id++;
|
|
kv = spawnArgs.FindKey( va( "cm_model%s_%d", modelID.c_str(), id ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
physicsObj.SetContents( CONTENTS_SOLID );
|
|
SetPhysics( &physicsObj );
|
|
}
|
|
|
|
void sdLODEntity::PostMapSpawn() {
|
|
idEntity::PostMapSpawn();
|
|
for ( int i = 0; i < modelID.Num(); i++ ) {
|
|
int ID = modelID[i];
|
|
if ( ID != -1 ) {
|
|
renderEntity_t *re = gameRenderWorld->GetRenderEntity( modelDefHandles[i] );
|
|
|
|
idStr value = spawnArgs.GetString( va( "visDummies%d", ID ) );
|
|
|
|
if ( !value.IsEmpty() ) {
|
|
|
|
idStrList strlist;
|
|
idSplitStringIntoList( strlist, value, "," );
|
|
|
|
idList< idEntityPtr<idEntity> > dummies;
|
|
|
|
idList< int > areas;
|
|
for (int j=0; j<strlist.Num(); j++) {
|
|
idEntity *ent = gameLocal.FindEntity( strlist[j] );
|
|
if ( ent ) {
|
|
idVec3 org = ent->GetPhysics()->GetOrigin();
|
|
int areaNum = gameRenderWorld->PointInArea( org );
|
|
if ( areaNum >= 0 ) {
|
|
bool found = areas.FindIndex( areaNum ) != -1;
|
|
|
|
if ( !found ) {
|
|
idEntityPtr<idEntity> &entityPtr = dummies.Alloc();
|
|
entityPtr = ent;
|
|
areas.Alloc() = areaNum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
re->numVisDummies = dummies.Num();
|
|
|
|
if ( re->numVisDummies ) {
|
|
int validcount = 0;
|
|
int c = 0;
|
|
re->dummies = new idVec3[ re->numVisDummies ];
|
|
for (int j=0; j<re->numVisDummies; j++) {
|
|
if ( dummies[j].IsValid() ) {
|
|
re->dummies[c++] = dummies[j].GetEntity()->GetPhysics()->GetOrigin();
|
|
}
|
|
}
|
|
gameRenderWorld->UpdateEntityDef( modelDefHandles[i], re );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdImposterEntity
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, sdImposterEntity )
|
|
END_CLASS
|
|
|
|
|
|
sdImposterEntity::sdImposterEntity() {
|
|
}
|
|
|
|
sdImposterEntity::~sdImposterEntity() {
|
|
FreeModelDefs();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdImposterEntity::FreeModelDefs
|
|
================
|
|
*/
|
|
void sdImposterEntity::FreeModelDefs() {
|
|
for ( int i = 0; i < modelDefHandles.Num(); i++ ) {
|
|
int& modelDefHandle = modelDefHandles[ i ];
|
|
|
|
if ( modelDefHandle != -1 ) {
|
|
renderEntity_t *re = gameRenderWorld->GetRenderEntity( modelDefHandle );
|
|
if ( re->insts != NULL ) {
|
|
delete[] re->insts;
|
|
}
|
|
re->insts = NULL;
|
|
gameRenderWorld->FreeEntityDef( modelDefHandle );
|
|
modelDefHandle = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdImposterEntity::Spawn
|
|
================
|
|
*/
|
|
struct imposterGather_s {
|
|
idStr name;
|
|
int count;
|
|
};
|
|
#if 1
|
|
void sdImposterEntity::Spawn() {
|
|
const char* defaultMaxVisDist = spawnArgs.GetString( "maxvisdist", "0" );
|
|
const int imposterStrLen = idStr::Length( "imposter" );
|
|
idList< imposterGather_s > imposterList;
|
|
for( int i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
|
|
const idKeyValue* imposterKey = spawnArgs.GetKeyVal( i );
|
|
if( imposterKey->GetKey().Icmpn( "imposter", imposterStrLen ) != 0 ) {
|
|
continue;
|
|
}
|
|
bool found = false;
|
|
for (int j=0; j<imposterList.Num(); j++) {
|
|
if ( imposterKey->GetValue().Icmp( imposterList[j].name.c_str() ) == 0 ) {
|
|
imposterList[j].count++;
|
|
found = true;
|
|
}
|
|
}
|
|
if ( !found ) {
|
|
imposterGather_s entry;
|
|
entry.name = imposterKey->GetValue();
|
|
entry.count = 1;
|
|
imposterList.Alloc() = entry;
|
|
}
|
|
}
|
|
|
|
bool errors = false;
|
|
renderEntity_t *renderEntity = new renderEntity_t[ imposterList.Num() ];
|
|
for ( int i=0; i<imposterList.Num(); i++) {
|
|
idDict tempDict;
|
|
tempDict.Set( "forceimposter", "1" );
|
|
tempDict.Set( "model", "_default" );
|
|
tempDict.Set( "imposter", imposterList[i].name );
|
|
gameEdit->ParseSpawnArgsToRenderEntity( tempDict, renderEntity[i] );
|
|
if ( renderEntity[i].imposter == NULL ) {
|
|
common->Warning( "Imposter '%s' not found", imposterList[i].name.c_str() );
|
|
errors = true;
|
|
}
|
|
|
|
renderEntity[i].numInsts = 0;
|
|
renderEntity[i].insts = new sdInstInfo[ imposterList[i].count ];
|
|
renderEntity[i].bounds.Clear();
|
|
renderEntity[i].flags.overridenBounds = true;
|
|
renderEntity[i].flags.pushByInstances = true;
|
|
}
|
|
if ( errors ) {
|
|
common->Error( "sdImposterEntity: imposters not found" );
|
|
}
|
|
|
|
for( int i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
|
|
const idKeyValue* imposterKey = spawnArgs.GetKeyVal( i );
|
|
if( imposterKey->GetKey().Icmpn( "imposter", imposterStrLen ) != 0 ) {
|
|
continue;
|
|
}
|
|
|
|
int found = -1;
|
|
for (int j=0; j<imposterList.Num(); j++) {
|
|
if ( imposterKey->GetValue().Icmp( imposterList[j].name.c_str() ) == 0 ) {
|
|
imposterList[j].count++;
|
|
found = j;
|
|
}
|
|
}
|
|
|
|
if ( found != -1 ) {
|
|
const char* imposterId = imposterKey->GetKey().c_str() + imposterStrLen;
|
|
sdInstInfo &inst = renderEntity[found].insts[ renderEntity[found].numInsts++ ];
|
|
|
|
inst.inst.origin = spawnArgs.GetVector( va( "origin%s", imposterId ), "0 0 0" );
|
|
inst.fadeOrigin = inst.inst.origin;
|
|
inst.inst.axis = spawnArgs.GetMatrix(va( "rotation%s", imposterId ), "1 0 0 0 1 0 0 0 1" );
|
|
inst.maxVisDist = spawnArgs.GetFloat( va( "maxvisdist%s", imposterId ), defaultMaxVisDist );
|
|
inst.minVisDist = 0.f;
|
|
// inst.maxVisDist *= inst.maxVisDist;
|
|
|
|
float scalex = renderEntity[found].imposter->GetScaleX();
|
|
float scaley = renderEntity[found].imposter->GetScaleY();
|
|
idBounds bb;
|
|
bb.Clear();
|
|
bb.AddPoint( idVec3( -scalex, -scalex, -scaley ) );
|
|
bb.AddPoint( idVec3( scalex, scalex, scaley ) );
|
|
bb.RotateSelf( inst.inst.axis );
|
|
bb.TranslateSelf( inst.inst.origin );
|
|
renderEntity[found].bounds.AddBounds( bb );
|
|
|
|
idVec3 fadeOrigin;
|
|
if ( spawnArgs.GetVector( va( "fadeOrigin%s", imposterId ), "0 0 0", fadeOrigin ) ) {
|
|
inst.fadeOrigin = fadeOrigin;
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( int i=0; i<imposterList.Num(); i++) {
|
|
modelDefHandles.Alloc() = gameRenderWorld->AddEntityDef( &renderEntity[i] );
|
|
}
|
|
|
|
delete []renderEntity;
|
|
}
|
|
#else
|
|
void sdImposterEntity::Spawn() {
|
|
renderEntity_t renderEntity;
|
|
idDict tempDict;
|
|
tempDict.Set( "forceimposter", "1" );
|
|
tempDict.Set( "model", "_default" );
|
|
|
|
const char* defaultMaxVisDist = spawnArgs.GetString( "maxvisdist", "0" );
|
|
|
|
const int imposterStrLen = idStr::Length( "imposter" );
|
|
|
|
for( int i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
|
|
const idKeyValue* imposterKey = spawnArgs.GetKeyVal( i );
|
|
if( imposterKey->GetKey().Icmpn( "imposter", imposterStrLen ) != 0 ) {
|
|
continue;
|
|
}
|
|
|
|
const char* imposterId = imposterKey->GetKey().c_str() + imposterStrLen;
|
|
tempDict.Set( "imposter", imposterKey->GetValue() );
|
|
tempDict.Set( "origin", spawnArgs.GetString( va( "origin%s", imposterId ), "0 0 0" ) );
|
|
tempDict.Set( "rotation", spawnArgs.GetString( va( "rotation%s", imposterId ), "1 0 0 0 1 0 0 0 1" ) );
|
|
tempDict.Set( "maxvisdist", spawnArgs.GetString( va( "maxvisdist%s", imposterId ), defaultMaxVisDist ) );
|
|
|
|
idStr fadeOrigin;
|
|
if ( spawnArgs.GetString( va( "fadeOrigin%s", imposterId ), "0 0 0", fadeOrigin ) ) {
|
|
tempDict.Set( "fadeOrigin", fadeOrigin );
|
|
}
|
|
|
|
gameEdit->ParseSpawnArgsToRenderEntity( tempDict, renderEntity );
|
|
modelDefHandles.Alloc() = gameRenderWorld->AddEntityDef( &renderEntity );
|
|
}
|
|
|
|
PostEventMS( &EV_Remove, 0 );
|
|
}
|
|
#endif
|
|
/*
|
|
===============================================================================
|
|
|
|
sdJumpPad
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idTrigger_Multi, sdJumpPad )
|
|
END_CLASS
|
|
|
|
/*
|
|
=========================
|
|
sdJumpPad::Spawn
|
|
=========================
|
|
*/
|
|
void sdJumpPad::Spawn( void ) {
|
|
forceField.SetApplyType( FORCEFIELD_APPLY_VELOCITY );
|
|
forceField.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ) );
|
|
|
|
spawnArgs.GetInt( "trigger_wait", "0", triggerWait );
|
|
|
|
nextTriggerTime = 0;
|
|
}
|
|
|
|
/*
|
|
=========================
|
|
sdJumpPad::OnTouch
|
|
=========================
|
|
*/
|
|
void sdJumpPad::OnTouch( idEntity *other, const trace_t& trace ) {
|
|
if ( gameLocal.time < nextTriggerTime ) {
|
|
return;
|
|
}
|
|
|
|
if ( GetEntityAllegiance( other ) == TA_ENEMY ) {
|
|
return;
|
|
}
|
|
|
|
idPlayer* player = other->Cast< idPlayer >();
|
|
if ( player != NULL && !player->IsSpectator() && player->GetHealth() <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
nextTriggerTime = gameLocal.time + triggerWait;
|
|
forceField.Evaluate( gameLocal.time );
|
|
|
|
StartSound( "snd_jump", SND_MOVER_MOVE, 0, NULL );
|
|
PlayEffect( "fx_jump", idVec3( 1.f, 1.f, 1.f ), NULL, GetPhysics()->GetOrigin(), effectAxis );
|
|
}
|
|
|
|
/*
|
|
=========================
|
|
sdJumpPad::PostMapSpawn
|
|
=========================
|
|
*/
|
|
void sdJumpPad::PostMapSpawn( void ) {
|
|
FindTargets();
|
|
RemoveNullTargets();
|
|
|
|
if ( targets.Num() != 1 ) {
|
|
gameLocal.Warning( "sdJumpPad::PostMapSpawn: jumppad %s should have only 1 target", name.c_str() );
|
|
return;
|
|
}
|
|
|
|
idEntity* target = targets[ 0 ];
|
|
if ( target == NULL ) {
|
|
assert( target != NULL );
|
|
gameLocal.Warning( "sdJumpPad::PostMapSpawn: jumppad %s has a NULL target entity", name.c_str() );
|
|
return;
|
|
}
|
|
|
|
idVec3 diff = target->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
|
|
idVec3 gravity( GetPhysics()->GetGravity() );
|
|
idVec3 gravityNormal( 0, 0, -1.f );
|
|
idVec3 vertical( 0.f, 0.f, diff.z );
|
|
|
|
float time = idMath::Sqrt( vertical.Length() / ( 0.5f * gravity.Length() ) );
|
|
if ( time <= idMath::FLT_EPSILON ) {
|
|
// no point in having the jumppad
|
|
gameLocal.Warning( "sdJumpPad::PostMapSpawn: removing jumppad %s as target too close to trigger", name.c_str() );
|
|
PostEventMS( &EV_Remove, 0 );
|
|
return;
|
|
}
|
|
|
|
// calc the non-vertical velocity
|
|
idVec3 velocity( diff - vertical );
|
|
float distance = velocity.Normalize();
|
|
velocity = velocity * ( distance / time );
|
|
|
|
// add the vertical velocity
|
|
velocity += (gravity * -time);
|
|
|
|
forceField.Uniform( velocity );
|
|
|
|
// calc the effect axis for playing the effect
|
|
diff.Normalize();
|
|
effectAxis = diff.ToMat3();
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdInstStatic
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, sdInstStatic )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
sdInstStatic::sdInstStatic
|
|
================
|
|
*/
|
|
sdInstStatic::sdInstStatic() {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdInstStatic::~sdInstStatic
|
|
================
|
|
*/
|
|
sdInstStatic::~sdInstStatic() {
|
|
FreeModelDefs();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdInstStatic::FreeModelDefs
|
|
================
|
|
*/
|
|
void sdInstStatic::FreeModelDefs() {
|
|
for ( int i = 0; i < modelDefHandles.Num(); i++ ) {
|
|
int& modelDefHandle = modelDefHandles[ i ];
|
|
|
|
if ( modelDefHandle != -1 ) {
|
|
renderEntity_t *re = gameRenderWorld->GetRenderEntity( modelDefHandle );
|
|
if ( re->insts != NULL ) {
|
|
delete[] re->insts;
|
|
}
|
|
re->insts = NULL;
|
|
gameRenderWorld->FreeEntityDef( modelDefHandle );
|
|
modelDefHandle = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdInstStatic::AddRenderEntity
|
|
================
|
|
*/
|
|
void sdInstStatic::AddRenderEntity( const renderEntity_t& entity ) {
|
|
modelDefHandles.Alloc() = gameRenderWorld->AddEntityDef( &entity );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdInstStatic::AddClipModel
|
|
================
|
|
*/
|
|
void sdInstStatic::AddClipModel( idClipModel* clipModel, const idVec3& origin, const idMat3& axes ) {
|
|
int numClipModels = physicsObj.GetNumClipModels();
|
|
|
|
physicsObj.SetClipModel( clipModel, 1.0f, numClipModels );
|
|
physicsObj.SetOrigin( origin, numClipModels );
|
|
physicsObj.SetAxis( axes, numClipModels );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdInstStatic::Spawn
|
|
================
|
|
*/
|
|
void sdInstStatic::Spawn() {
|
|
physicsObj.SetSelf( this );
|
|
physicsObj.SetOrigin( GetPhysics()->GetOrigin(), 0 );
|
|
physicsObj.SetAxis( GetPhysics()->GetAxis(), 0 );
|
|
|
|
// add models
|
|
const idKeyValue* arg;
|
|
renderEntity_t renderEntity;
|
|
const char* modelInstance = spawnArgs.GetString( "model_instance" );
|
|
|
|
memset( &renderEntity, 0, sizeof( renderEntity ) );
|
|
renderEntity.spawnID = gameLocal.GetSpawnId( this );// renderEntity.entityNum = entityNumber;
|
|
renderEntity.axis.Identity();
|
|
renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
|
|
renderEntity.shaderParms[ SHADERPARM_ALPHA ] = 1.0f;
|
|
renderEntity.hModel = renderModelManager->FindModel( modelInstance );
|
|
renderEntity.flags.overridenBounds = true;
|
|
renderEntity.flags.noShadow = true;
|
|
renderEntity.flags.pushByInstances = true;
|
|
renderEntity.flags.pushByCenter = spawnArgs.GetBool( "pushByOrigin" );
|
|
|
|
if ( renderEntity.hModel == NULL ) {
|
|
gameLocal.Warning( "sdInstStatic::Spawn : no model for entity '%s'", GetName() );
|
|
PostEventMS( &EV_Remove, 0 );
|
|
return;
|
|
}
|
|
|
|
const char* temp;
|
|
temp = spawnArgs.GetString( "imposter_instance" );
|
|
if ( *temp != '\0' ) {
|
|
renderEntity.imposter = declHolder.FindImposter( temp );
|
|
}
|
|
|
|
int count = 0;
|
|
for ( int i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
|
|
arg = spawnArgs.GetKeyVal( i );
|
|
char prefix[32];
|
|
sprintf( prefix, "%d ", i );
|
|
if ( spawnArgs.MatchPrefix( prefix ) ) {
|
|
count++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
renderEntity.bounds.Clear();
|
|
renderEntity.numInsts = count;
|
|
renderEntity.insts = new sdInstInfo[ count ];
|
|
|
|
int index = 0;
|
|
const idKeyValue* lastArg = NULL;
|
|
for ( int i = 0; i < count; i++ ) {
|
|
char cprefix[32];
|
|
sprintf(cprefix, "%d ", i );
|
|
idStr prefix;
|
|
prefix = cprefix;
|
|
arg = spawnArgs.MatchPrefix( prefix, lastArg );
|
|
if ( arg ) {
|
|
lastArg = arg;
|
|
arg = spawnArgs.MatchPrefix( prefix, lastArg );
|
|
|
|
sdInstInfo &info = renderEntity.insts[ i ];
|
|
|
|
info.inst.origin = spawnArgs.GetVector( prefix + "origin" );
|
|
info.fadeOrigin = info.inst.origin;
|
|
info.maxVisDist = spawnArgs.GetInt( prefix + "maxVisDist" );
|
|
info.minVisDist = spawnArgs.GetInt( prefix + "minVisDist" );
|
|
info.inst.axis = spawnArgs.GetMatrix( prefix + "rotation", "1 0 0 0 1 0 0 0 1" );
|
|
info.inst.color[0] = 255;
|
|
info.inst.color[1] = 255;
|
|
info.inst.color[2] = 255;
|
|
info.inst.color[3] = 255;
|
|
|
|
idBounds bb;
|
|
bb.FromTransformedBounds( renderEntity.hModel->Bounds(), info.inst.origin, info.inst.axis );
|
|
renderEntity.bounds.AddBounds( bb );
|
|
|
|
idStr cm;
|
|
if ( spawnArgs.GetString( prefix + "cm_model", "", cm ) ) {
|
|
AddClipModel( new idClipModel( cm ), info.inst.origin, info.inst.axis );
|
|
}
|
|
}
|
|
}
|
|
|
|
AddRenderEntity( renderEntity );
|
|
|
|
physicsObj.SetContents( CONTENTS_SOLID );
|
|
SetPhysics( &physicsObj );
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdEnvBounds
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, sdEnvBoundsEntity )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
sdEnvDefinition::Spawn
|
|
================
|
|
*/
|
|
void sdEnvBoundsEntity::Spawn( void ) {
|
|
|
|
idVec3 origin, size;
|
|
idStr name;
|
|
spawnArgs.GetVector( "origin", "0 0 0", origin );
|
|
spawnArgs.GetVector( "size", "8 8 8", size );
|
|
spawnArgs.GetString( "env_name", "", name );
|
|
|
|
if ( name.Length() ) {
|
|
gameRenderWorld->AddEnvBounds( origin, size, name );
|
|
} else {
|
|
gameLocal.Warning( "No env_name field specified on environment definition, skipped" );
|
|
}
|
|
PostEventMS( &EV_Remove, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdLadderEntity
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
CLASS_DECLARATION( idEntity, sdLadderEntity )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
sdLadderEntity::Spawn
|
|
================
|
|
*/
|
|
void sdLadderEntity::Spawn( void ) {
|
|
ladderModel = NULL;
|
|
|
|
idClipModel* model = GetPhysics()->GetClipModel();
|
|
if ( model == NULL ) {
|
|
gameLocal.Error( "sdLadderEntity::Spawn No Collision Model" );
|
|
}
|
|
|
|
bool surfaceFound = false;
|
|
for ( int i = 0; i < model->GetNumCollisionModels(); i++ ) {
|
|
idCollisionModel* cm = model->GetCollisionModel( i );
|
|
for ( int j = 0; j < cm->GetNumPolygons(); j++ ) {
|
|
const idMaterial* material = cm->GetPolygonMaterial( j );
|
|
if ( material == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
if ( !( material->GetSurfaceFlags() & SURF_LADDER ) ) {
|
|
continue;
|
|
}
|
|
|
|
if ( surfaceFound ) {
|
|
gameLocal.Error( "sdLadderEntity::Spawn Multiple Ladder Surfaces" );
|
|
}
|
|
surfaceFound = true;
|
|
|
|
ladderNormal = cm->GetPolygonPlane( j ).Normal();
|
|
|
|
idFixedWinding ladderWinding;
|
|
cm->GetPolygon( j, ladderWinding );
|
|
|
|
idTraceModel trm;
|
|
trm.SetupPolygonPrism( ladderWinding, 16.f );
|
|
|
|
ladderModel = new idClipModel( trm, true );
|
|
}
|
|
}
|
|
if ( !surfaceFound ) {
|
|
gameLocal.Error( "sdLadderEntity::Spawn No Ladder Surface Found" );
|
|
}
|
|
|
|
// BecomeActive( TH_THINK );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLadderEntity::~sdLadderEntity
|
|
================
|
|
*/
|
|
sdLadderEntity::~sdLadderEntity( void ) {
|
|
gameLocal.clip.DeleteClipModel( ladderModel );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLadderEntity::Think
|
|
================
|
|
*/
|
|
void sdLadderEntity::Think( void ) {
|
|
idEntity::Think();
|
|
|
|
// ladderModel->Draw( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdLadderEntity::GetLadderNormal
|
|
================
|
|
*/
|
|
idVec3 sdLadderEntity::GetLadderNormal( void ) const {
|
|
return GetPhysics()->GetAxis() * ladderNormal;
|
|
}
|
|
|
|
#include "botai/BotThreadData.h"
|
|
|
|
CLASS_DECLARATION( idEntity, idAASObstacleEntity )
|
|
EVENT( EV_Activate, idAASObstacleEntity::Event_Activate )
|
|
END_CLASS
|
|
|
|
/*
|
|
===============
|
|
idAASObstacleEntity::idAASObstacleEntity
|
|
================
|
|
*/
|
|
idAASObstacleEntity::idAASObstacleEntity( void ) {
|
|
enabled = false;
|
|
team = 2;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAASObstacleEntity::Spawn
|
|
================
|
|
*/
|
|
void idAASObstacleEntity::Spawn( ) {
|
|
enabled = !spawnArgs.GetBool( "start_on", "1" );
|
|
team = spawnArgs.GetInt( "team", "2" );
|
|
ChangeAreaState();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAASObstacleEntity::Event_Activate
|
|
================
|
|
*/
|
|
void idAASObstacleEntity::Event_Activate( idEntity *activator ) {
|
|
enabled = !enabled;
|
|
ChangeAreaState();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idAASObstacleEntity::ChangeAreaState
|
|
================
|
|
*/
|
|
void idAASObstacleEntity::ChangeAreaState( ) {
|
|
botThreadData.EnableArea( GetPhysics()->GetAbsBounds(), AAS_AREA_CONTENTS_OBSTACLE, team, enabled );
|
|
}
|