doom3-bfg/neo/d3xp/Entity.h

781 lines
28 KiB
C++

/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __GAME_ENTITY_H__
#define __GAME_ENTITY_H__
/*
===============================================================================
Game entity base class.
===============================================================================
*/
static const int DELAY_DORMANT_TIME = 3000;
extern const idEventDef EV_PostSpawn;
extern const idEventDef EV_FindTargets;
extern const idEventDef EV_Touch;
extern const idEventDef EV_Use;
extern const idEventDef EV_Activate;
extern const idEventDef EV_ActivateTargets;
extern const idEventDef EV_Hide;
extern const idEventDef EV_Show;
extern const idEventDef EV_GetShaderParm;
extern const idEventDef EV_SetShaderParm;
extern const idEventDef EV_SetOwner;
extern const idEventDef EV_GetAngles;
extern const idEventDef EV_SetAngles;
extern const idEventDef EV_SetLinearVelocity;
extern const idEventDef EV_SetAngularVelocity;
extern const idEventDef EV_SetSkin;
extern const idEventDef EV_StartSoundShader;
extern const idEventDef EV_StopSound;
extern const idEventDef EV_CacheSoundShader;
// Think flags
enum
{
TH_ALL = -1,
TH_THINK = 1, // run think function each frame
TH_PHYSICS = 2, // run physics each frame
TH_ANIMATE = 4, // update animation each frame
TH_UPDATEVISUALS = 8, // update renderEntity
TH_UPDATEPARTICLES = 16
};
//
// Signals
// make sure to change script/doom_defs.script if you add any, or change their order
//
typedef enum
{
SIG_TOUCH, // object was touched
SIG_USE, // object was used
SIG_TRIGGER, // object was activated
SIG_REMOVED, // object was removed from the game
SIG_DAMAGE, // object was damaged
SIG_BLOCKED, // object was blocked
SIG_MOVER_POS1, // mover at position 1 (door closed)
SIG_MOVER_POS2, // mover at position 2 (door open)
SIG_MOVER_1TO2, // mover changing from position 1 to 2
SIG_MOVER_2TO1, // mover changing from position 2 to 1
NUM_SIGNALS
} signalNum_t;
// FIXME: At some point we may want to just limit it to one thread per signal, but
// for now, I'm allowing multiple threads. We should reevaluate this later in the project
#define MAX_SIGNAL_THREADS 16 // probably overkill, but idList uses a granularity of 16
struct signal_t
{
int threadnum;
const function_t* function;
};
class signalList_t
{
public:
idList<signal_t, TAG_ENTITY> signal[ NUM_SIGNALS ];
};
/*
================================================
idNetEvent
Utility for detecting a bool state change:
-server calls ::Set
-client ::Get will return true (once only)
Useful because:
-Hides client from having to manually declare "last" state and manually checking against it
-using int counter prevents problems w/ dropped snapshots
(ie if we just serialized a bool to true for a single ss, if that ss is dropped,skipped,whatever
the client would never handle it. By incrementing a wrapped counter, we are guaranteed to detect
the state change no matter what happens at the net layer).
================================================
*/
template < int max >
struct idNetEvent
{
idNetEvent() : count( 0 ), lastCount( 0 ) { }
void Set()
{
count = ( ( count + 1 ) % max );
}
bool Get()
{
if( count != lastCount )
{
lastCount = count;
return true;
}
return false;
}
void Serialize( idSerializer& ser )
{
if( count >= max )
{
idLib::Warning( "idNetEvent. count %d > max %d", count, max );
}
ser.SerializeUMax( count, max );
}
public:
static const int Maximum = max;
int count;
int lastCount;
};
typedef idNetEvent< 7 > netBoolEvent_t;
inline void WriteToBitMsg( const netBoolEvent_t& netEvent, idBitMsg& msg )
{
msg.WriteBits( netEvent.count, idMath::BitsForInteger( netBoolEvent_t::Maximum ) );
assert( netEvent.count <= netBoolEvent_t::Maximum );
}
inline void ReadFromBitMsg( netBoolEvent_t& netEvent, const idBitMsg& msg )
{
netEvent.count = msg.ReadBits( idMath::BitsForInteger( netBoolEvent_t::Maximum ) );
assert( netEvent.count <= netBoolEvent_t::Maximum );
}
class idEntity : public idClass
{
public:
static const int MAX_PVS_AREAS = 4;
static const uint32 INVALID_PREDICTION_KEY = 0xFFFFFFFF;
int entityNumber; // index into the entity list
int entityDefNumber; // index into the entity def list
idLinkList<idEntity> spawnNode; // for being linked into spawnedEntities list
idLinkList<idEntity> activeNode; // for being linked into activeEntities list
idLinkList<idEntity> aimAssistNode; // linked into gameLocal.aimAssistEntities
idLinkList<idEntity> snapshotNode; // for being linked into snapshotEntities list
int snapshotChanged; // used to detect snapshot state changes
int snapshotBits; // number of bits this entity occupied in the last snapshot
bool snapshotStale; // Set to true if this entity is considered stale in the snapshot
idStr name; // name of entity
idDict spawnArgs; // key/value pairs used to spawn and initialize entity
idScriptObject scriptObject; // contains all script defined data for this entity
int thinkFlags; // TH_? flags
int dormantStart; // time that the entity was first closed off from player
bool cinematic; // during cinematics, entity will only think if cinematic is set
renderView_t* renderView; // for camera views from this entity
idEntity* cameraTarget; // any remoteRenderMap shaders will use this
idList< idEntityPtr<idEntity>, TAG_ENTITY > targets; // when this entity is activated these entities entity are activated
int health; // FIXME: do all objects really need health?
struct entityFlags_s
{
bool notarget : 1; // if true never attack or target this entity
bool noknockback : 1; // if true no knockback from hits
bool takedamage : 1; // if true this entity can be damaged
bool hidden : 1; // if true this entity is not visible
bool bindOrientated : 1; // if true both the master orientation is used for binding
bool solidForTeam : 1; // if true this entity is considered solid when a physics team mate pushes entities
bool forcePhysicsUpdate : 1; // if true always update from the physics whether the object moved or not
bool selected : 1; // if true the entity is selected for editing
bool neverDormant : 1; // if true the entity never goes dormant
bool isDormant : 1; // if true the entity is dormant
bool hasAwakened : 1; // before a monster has been awakened the first time, use full PVS for dormant instead of area-connected
bool networkSync : 1; // if true the entity is synchronized over the network
bool grabbed : 1; // if true object is currently being grabbed
bool skipReplication : 1; // don't replicate this entity over the network.
} fl;
int timeGroup;
bool noGrab;
renderEntity_t xrayEntity;
qhandle_t xrayEntityHandle;
const idDeclSkin* xraySkin;
void DetermineTimeGroup( bool slowmo );
void SetGrabbedState( bool grabbed );
bool IsGrabbed();
public:
ABSTRACT_PROTOTYPE( idEntity );
idEntity();
~idEntity();
void Spawn();
void Save( idSaveGame* savefile ) const;
void Restore( idRestoreGame* savefile );
const char* GetEntityDefName() const;
void SetName( const char* name );
const char* GetName() const;
virtual void UpdateChangeableSpawnArgs( const idDict* source );
int GetEntityNumber() const
{
return entityNumber;
}
// clients generate views based on all the player specific options,
// cameras have custom code, and everything else just uses the axis orientation
virtual renderView_t* GetRenderView();
// thinking
virtual void Think();
bool CheckDormant(); // dormant == on the active list, but out of PVS
virtual void DormantBegin(); // called when entity becomes dormant
virtual void DormantEnd(); // called when entity wakes from being dormant
bool IsActive() const;
void BecomeActive( int flags );
void BecomeInactive( int flags );
void UpdatePVSAreas( const idVec3& pos );
void BecomeReplicated();
// visuals
virtual void Present();
virtual renderEntity_t* GetRenderEntity();
virtual int GetModelDefHandle();
virtual void SetModel( const char* modelname );
void SetSkin( const idDeclSkin* skin );
const idDeclSkin* GetSkin() const;
void SetShaderParm( int parmnum, float value );
virtual void SetColor( float red, float green, float blue );
virtual void SetColor( const idVec3& color );
virtual void GetColor( idVec3& out ) const;
virtual void SetColor( const idVec4& color );
virtual void GetColor( idVec4& out ) const;
virtual void FreeModelDef();
virtual void FreeLightDef();
virtual void Hide();
virtual void Show();
bool IsHidden() const;
void UpdateVisuals();
void UpdateModel();
void UpdateModelTransform();
virtual void ProjectOverlay( const idVec3& origin, const idVec3& dir, float size, const char* material );
int GetNumPVSAreas();
const int* GetPVSAreas();
void ClearPVSAreas();
bool PhysicsTeamInPVS( pvsHandle_t pvsHandle );
// animation
virtual bool UpdateAnimationControllers();
bool UpdateRenderEntity( renderEntity_s* renderEntity, const renderView_t* renderView );
static bool ModelCallback( renderEntity_s* renderEntity, const renderView_t* renderView );
virtual idAnimator* GetAnimator(); // returns animator object used by this entity
// sound
virtual bool CanPlayChatterSounds() const;
bool StartSound( const char* soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int* length );
bool StartSoundShader( const idSoundShader* shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int* length );
void StopSound( const s_channelType channel, bool broadcast ); // pass SND_CHANNEL_ANY to stop all sounds
void SetSoundVolume( float volume );
void UpdateSound();
int GetListenerId() const;
idSoundEmitter* GetSoundEmitter() const;
void FreeSoundEmitter( bool immediate );
// entity binding
virtual void PreBind();
virtual void PostBind();
virtual void PreUnbind();
virtual void PostUnbind();
void JoinTeam( idEntity* teammember );
void Bind( idEntity* master, bool orientated );
void BindToJoint( idEntity* master, const char* jointname, bool orientated );
void BindToJoint( idEntity* master, jointHandle_t jointnum, bool orientated );
void BindToBody( idEntity* master, int bodyId, bool orientated );
void Unbind();
bool IsBound() const;
bool IsBoundTo( idEntity* master ) const;
idEntity* GetBindMaster() const;
jointHandle_t GetBindJoint() const;
int GetBindBody() const;
idEntity* GetTeamMaster() const;
idEntity* GetNextTeamEntity() const;
void ConvertLocalToWorldTransform( idVec3& offset, idMat3& axis );
idVec3 GetLocalVector( const idVec3& vec ) const;
idVec3 GetLocalCoordinates( const idVec3& vec ) const;
idVec3 GetWorldVector( const idVec3& vec ) const;
idVec3 GetWorldCoordinates( const idVec3& vec ) const;
bool GetMasterPosition( idVec3& masterOrigin, idMat3& masterAxis ) const;
void GetWorldVelocities( idVec3& linearVelocity, idVec3& angularVelocity ) const;
// physics
// set a new physics object to be used by this entity
void SetPhysics( idPhysics* phys );
// get the physics object used by this entity
idPhysics* GetPhysics() const;
// restore physics pointer for save games
void RestorePhysics( idPhysics* phys );
// run the physics for this entity
bool RunPhysics();
// Interpolates the physics, used on MP clients.
void InterpolatePhysics( const float fraction );
// InterpolatePhysics actually calls evaluate, this version doesn't.
void InterpolatePhysicsOnly( const float fraction, bool updateTeam = false );
// set the origin of the physics object (relative to bindMaster if not NULL)
void SetOrigin( const idVec3& org );
// set the axis of the physics object (relative to bindMaster if not NULL)
void SetAxis( const idMat3& axis );
// use angles to set the axis of the physics object (relative to bindMaster if not NULL)
void SetAngles( const idAngles& ang );
// get the floor position underneath the physics object
bool GetFloorPos( float max_dist, idVec3& floorpos ) const;
// retrieves the transformation going from the physics origin/axis to the visual origin/axis
virtual bool GetPhysicsToVisualTransform( idVec3& origin, idMat3& axis );
// retrieves the transformation going from the physics origin/axis to the sound origin/axis
virtual bool GetPhysicsToSoundTransform( idVec3& origin, idMat3& axis );
// called from the physics object when colliding, should return true if the physics simulation should stop
virtual bool Collide( const trace_t& collision, const idVec3& velocity );
// retrieves impact information, 'ent' is the entity retrieving the info
virtual void GetImpactInfo( idEntity* ent, int id, const idVec3& point, impactInfo_t* info );
// apply an impulse to the physics object, 'ent' is the entity applying the impulse
virtual void ApplyImpulse( idEntity* ent, int id, const idVec3& point, const idVec3& impulse );
// add a force to the physics object, 'ent' is the entity adding the force
virtual void AddForce( idEntity* ent, int id, const idVec3& point, const idVec3& force );
// activate the physics object, 'ent' is the entity activating this entity
virtual void ActivatePhysics( idEntity* ent );
// returns true if the physics object is at rest
virtual bool IsAtRest() const;
// returns the time the physics object came to rest
virtual int GetRestStartTime() const;
// add a contact entity
virtual void AddContactEntity( idEntity* ent );
// remove a touching entity
virtual void RemoveContactEntity( idEntity* ent );
// damage
// returns true if this entity can be damaged from the given origin
virtual bool CanDamage( const idVec3& origin, idVec3& damagePoint ) const;
// applies damage to this entity
virtual void Damage( idEntity* inflictor, idEntity* attacker, const idVec3& dir, const char* damageDefName, const float damageScale, const int location );
// adds a damage effect like overlays, blood, sparks, debris etc.
virtual void AddDamageEffect( const trace_t& collision, const idVec3& velocity, const char* damageDefName );
// callback function for when another entity received damage from this entity. damage can be adjusted and returned to the caller.
virtual void DamageFeedback( idEntity* victim, idEntity* inflictor, int& damage );
// notifies this entity that it is in pain
virtual bool Pain( idEntity* inflictor, idEntity* attacker, int damage, const idVec3& dir, int location );
// notifies this entity that is has been killed
virtual void Killed( idEntity* inflictor, idEntity* attacker, int damage, const idVec3& dir, int location );
// scripting
virtual bool ShouldConstructScriptObjectAtSpawn() const;
virtual idThread* ConstructScriptObject();
virtual void DeconstructScriptObject();
void SetSignal( signalNum_t signalnum, idThread* thread, const function_t* function );
void ClearSignal( idThread* thread, signalNum_t signalnum );
void ClearSignalThread( signalNum_t signalnum, idThread* thread );
bool HasSignal( signalNum_t signalnum ) const;
void Signal( signalNum_t signalnum );
void SignalEvent( idThread* thread, signalNum_t signalnum );
// gui
void TriggerGuis();
bool HandleGuiCommands( idEntity* entityGui, const char* cmds );
virtual bool HandleSingleGuiCommand( idEntity* entityGui, idLexer* src );
// targets
void FindTargets();
void RemoveNullTargets();
void ActivateTargets( idEntity* activator ) const;
// misc
virtual void Teleport( const idVec3& origin, const idAngles& angles, idEntity* destination );
bool TouchTriggers() const;
idCurve_Spline<idVec3>* GetSpline() const;
virtual void ShowEditingDialog();
enum
{
EVENT_STARTSOUNDSHADER,
EVENT_STOPSOUNDSHADER,
EVENT_MAXEVENTS
};
// Called on clients in an MP game, does the actual interpolation for the entity.
// This function will eventually replace ClientPredictionThink completely.
virtual void ClientThink( const int curTime, const float fraction, const bool predict );
virtual void ClientPredictionThink();
virtual void WriteToSnapshot( idBitMsg& msg ) const;
void ReadFromSnapshot_Ex( const idBitMsg& msg );
virtual void ReadFromSnapshot( const idBitMsg& msg );
virtual bool ServerReceiveEvent( int event, int time, const idBitMsg& msg );
virtual bool ClientReceiveEvent( int event, int time, const idBitMsg& msg );
void WriteBindToSnapshot( idBitMsg& msg ) const;
void ReadBindFromSnapshot( const idBitMsg& msg );
void WriteColorToSnapshot( idBitMsg& msg ) const;
void ReadColorFromSnapshot( const idBitMsg& msg );
void WriteGUIToSnapshot( idBitMsg& msg ) const;
void ReadGUIFromSnapshot( const idBitMsg& msg );
void ServerSendEvent( int eventId, const idBitMsg* msg, bool saveEvent, lobbyUserID_t excluding = lobbyUserID_t() ) const;
void ClientSendEvent( int eventId, const idBitMsg* msg ) const;
void SetUseClientInterpolation( bool use )
{
useClientInterpolation = use;
}
void SetSkipReplication( const bool skip )
{
fl.skipReplication = skip;
}
bool GetSkipReplication() const
{
return fl.skipReplication;
}
bool IsReplicated() const
{
return GetEntityNumber() < ENTITYNUM_FIRST_NON_REPLICATED;
}
void CreateDeltasFromOldOriginAndAxis( const idVec3& oldOrigin, const idMat3& oldAxis );
void DecayOriginAndAxisDelta();
uint32 GetPredictedKey()
{
return predictionKey;
}
void SetPredictedKey( uint32 key_ )
{
predictionKey = key_;
}
void FlagNewSnapshot();
idEntity* GetTeamChain()
{
return teamChain;
}
// It is only safe to interpolate if this entity has received two snapshots.
enum interpolationBehavior_t
{
USE_NO_INTERPOLATION,
USE_LATEST_SNAP_ONLY,
USE_INTERPOLATION
};
interpolationBehavior_t GetInterpolationBehavior() const
{
return interpolationBehavior;
}
unsigned int GetNumSnapshotsReceived() const
{
return snapshotsReceived;
}
protected:
renderEntity_t renderEntity; // used to present a model to the renderer
int modelDefHandle; // handle to static renderer model
refSound_t refSound; // used to present sound to the audio engine
idVec3 GetOriginDelta() const
{
return originDelta;
}
idMat3 GetAxisDelta() const
{
return axisDelta;
}
private:
idPhysics_Static defaultPhysicsObj; // default physics object
idPhysics* physics; // physics used for this entity
idEntity* bindMaster; // entity bound to if unequal NULL
jointHandle_t bindJoint; // joint bound to if unequal INVALID_JOINT
int bindBody; // body bound to if unequal -1
idEntity* teamMaster; // master of the physics team
idEntity* teamChain; // next entity in physics team
bool useClientInterpolation; // disables interpolation for some objects (handy for weapon world models)
int numPVSAreas; // number of renderer areas the entity covers
int PVSAreas[MAX_PVS_AREAS]; // numbers of the renderer areas the entity covers
signalList_t* signals;
int mpGUIState; // local cache to avoid systematic SetStateInt
uint32 predictionKey; // Unique key used to sync predicted ents (projectiles) in MP.
// Delta values that are set when the server or client disagree on where the render model should be. If this happens,
// they resolve it through DecayOriginAndAxisDelta()
idVec3 originDelta;
idMat3 axisDelta;
interpolationBehavior_t interpolationBehavior;
unsigned int snapshotsReceived;
private:
void FixupLocalizedStrings();
bool DoDormantTests(); // dormant == on the active list, but out of PVS
// physics
// initialize the default physics
void InitDefaultPhysics( const idVec3& origin, const idMat3& axis );
// update visual position from the physics
void UpdateFromPhysics( bool moveBack );
// get physics timestep
virtual int GetPhysicsTimeStep() const;
// entity binding
bool InitBind( idEntity* master ); // initialize an entity binding
void FinishBind(); // finish an entity binding
void RemoveBinds(); // deletes any entities bound to this object
void QuitTeam(); // leave the current team
void UpdatePVSAreas();
// events
void Event_GetName();
void Event_SetName( const char* name );
void Event_FindTargets();
void Event_ActivateTargets( idEntity* activator );
void Event_NumTargets();
void Event_GetTarget( float index );
void Event_RandomTarget( const char* ignore );
void Event_Bind( idEntity* master );
void Event_BindPosition( idEntity* master );
void Event_BindToJoint( idEntity* master, const char* jointname, float orientated );
void Event_Unbind();
void Event_RemoveBinds();
void Event_SpawnBind();
void Event_SetOwner( idEntity* owner );
void Event_SetModel( const char* modelname );
void Event_SetSkin( const char* skinname );
void Event_GetShaderParm( int parmnum );
void Event_SetShaderParm( int parmnum, float value );
void Event_SetShaderParms( float parm0, float parm1, float parm2, float parm3 );
void Event_SetColor( float red, float green, float blue );
void Event_GetColor();
void Event_IsHidden();
void Event_Hide();
void Event_Show();
void Event_CacheSoundShader( const char* soundName );
void Event_StartSoundShader( const char* soundName, int channel );
void Event_StopSound( int channel, int netSync );
void Event_StartSound( const char* soundName, int channel, int netSync );
void Event_FadeSound( int channel, float to, float over );
void Event_GetWorldOrigin();
void Event_SetWorldOrigin( idVec3 const& org );
void Event_GetOrigin();
void Event_SetOrigin( const idVec3& org );
void Event_GetAngles();
void Event_SetAngles( const idAngles& ang );
void Event_SetLinearVelocity( const idVec3& velocity );
void Event_GetLinearVelocity();
void Event_SetAngularVelocity( const idVec3& velocity );
void Event_GetAngularVelocity();
void Event_SetSize( const idVec3& mins, const idVec3& maxs );
void Event_GetSize();
void Event_GetMins();
void Event_GetMaxs();
void Event_Touches( idEntity* ent );
void Event_SetGuiParm( const char* key, const char* val );
void Event_SetGuiFloat( const char* key, float f );
void Event_GetNextKey( const char* prefix, const char* lastMatch );
void Event_SetKey( const char* key, const char* value );
void Event_GetKey( const char* key );
void Event_GetIntKey( const char* key );
void Event_GetFloatKey( const char* key );
void Event_GetVectorKey( const char* key );
void Event_GetEntityKey( const char* key );
void Event_RestorePosition();
void Event_UpdateCameraTarget();
void Event_DistanceTo( idEntity* ent );
void Event_DistanceToPoint( const idVec3& point );
void Event_StartFx( const char* fx );
void Event_WaitFrame();
void Event_Wait( float time );
void Event_HasFunction( const char* name );
void Event_CallFunction( const char* name );
void Event_SetNeverDormant( int enable );
void Event_SetGui( int guiNum, const char* guiName );
void Event_PrecacheGui( const char* guiName );
void Event_GetGuiParm( int guiNum, const char* key );
void Event_GetGuiParmFloat( int guiNum, const char* key );
void Event_GuiNamedEvent( int guiNum, const char* event );
};
/*
===============================================================================
Animated entity base class.
===============================================================================
*/
typedef struct damageEffect_s
{
jointHandle_t jointNum;
idVec3 localOrigin;
idVec3 localNormal;
int time;
const idDeclParticle* type;
struct damageEffect_s* next;
} damageEffect_t;
class idAnimatedEntity : public idEntity
{
public:
CLASS_PROTOTYPE( idAnimatedEntity );
idAnimatedEntity();
~idAnimatedEntity();
void Save( idSaveGame* savefile ) const;
void Restore( idRestoreGame* savefile );
virtual void ClientPredictionThink();
virtual void ClientThink( const int curTime, const float fraction, const bool predict );
virtual void Think();
void UpdateAnimation();
virtual idAnimator* GetAnimator();
virtual void SetModel( const char* modelname );
bool GetJointWorldTransform( jointHandle_t jointHandle, int currentTime, idVec3& offset, idMat3& axis );
bool GetJointTransformForAnim( jointHandle_t jointHandle, int animNum, int currentTime, idVec3& offset, idMat3& axis ) const;
virtual int GetDefaultSurfaceType() const;
virtual void AddDamageEffect( const trace_t& collision, const idVec3& velocity, const char* damageDefName );
void AddLocalDamageEffect( jointHandle_t jointNum, const idVec3& localPoint, const idVec3& localNormal, const idVec3& localDir, const idDeclEntityDef* def, const idMaterial* collisionMaterial );
void UpdateDamageEffects();
virtual bool ClientReceiveEvent( int event, int time, const idBitMsg& msg );
enum
{
EVENT_ADD_DAMAGE_EFFECT = idEntity::EVENT_MAXEVENTS,
EVENT_MAXEVENTS
};
protected:
idAnimator animator;
damageEffect_t* damageEffects;
private:
void Event_GetJointHandle( const char* jointname );
void Event_ClearAllJoints();
void Event_ClearJoint( jointHandle_t jointnum );
void Event_SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3& pos );
void Event_SetJointAngle( jointHandle_t jointnum, jointModTransform_t transform_type, const idAngles& angles );
void Event_GetJointPos( jointHandle_t jointnum );
void Event_GetJointAngle( jointHandle_t jointnum );
};
class SetTimeState
{
bool activated;
bool previousFast;
bool fast;
public:
SetTimeState();
SetTimeState( int timeGroup );
~SetTimeState();
void PushState( int timeGroup );
};
ID_INLINE SetTimeState::SetTimeState()
{
activated = false;
}
ID_INLINE SetTimeState::SetTimeState( int timeGroup )
{
activated = false;
PushState( timeGroup );
}
ID_INLINE void SetTimeState::PushState( int timeGroup )
{
// Don't mess with time in Multiplayer
if( !common->IsMultiplayer() )
{
activated = true;
// determine previous fast setting
if( gameLocal.time == gameLocal.slow.time )
{
previousFast = false;
}
else
{
previousFast = true;
}
// determine new fast setting
if( timeGroup )
{
fast = true;
}
else
{
fast = false;
}
// set correct time
gameLocal.SelectTimeGroup( timeGroup );
}
}
ID_INLINE SetTimeState::~SetTimeState()
{
if( activated && !common->IsMultiplayer() )
{
// set previous correct time
gameLocal.SelectTimeGroup( previousFast );
}
}
#endif /* !__GAME_ENTITY_H__ */