10337 lines
315 KiB
C++
Raw Normal View History

2013-12-02 19:31:46 -08:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The base class from which all game entities are derived.
//
//===========================================================================//
#include "cbase.h"
#include "globalstate.h"
#include "isaverestore.h"
#include "client.h"
#include "decals.h"
#include "gamerules.h"
#include "entityapi.h"
#include "entitylist.h"
#include "eventqueue.h"
#include "hierarchy.h"
#include "basecombatweapon.h"
#include "const.h"
#include "player.h" // For debug draw sending
#include "ndebugoverlay.h"
#include "physics.h"
#include "model_types.h"
#include "team.h"
#include "sendproxy.h"
#include "IEffects.h"
#include "vstdlib/random.h"
#include "baseentity.h"
#include "collisionutils.h"
#include "coordsize.h"
#include "animation.h"
#include "tier1/strtools.h"
#include "engine/IEngineSound.h"
#include "physics_saverestore.h"
#include "saverestore_utlvector.h"
#include "bone_setup.h"
#include "vcollide_parse.h"
#include "filters.h"
#include "te_effect_dispatch.h"
#include "AI_Criteria.h"
#include "AI_ResponseSystem.h"
#include "world.h"
#include "globals.h"
#include "saverestoretypes.h"
#include "SkyCamera.h"
#include "sceneentity.h"
#include "game.h"
#include "tier0/vprof.h"
#include "ai_basenpc.h"
#include "iservervehicle.h"
#include "eventlist.h"
#include "scriptevent.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#include "UtlCachedFileData.h"
#include "utlbuffer.h"
#include "positionwatcher.h"
#include "movetype_push.h"
#include "tier0/icommandline.h"
#include "vphysics/friction.h"
#include <ctype.h>
#include "datacache/imdlcache.h"
#include "ModelSoundsCache.h"
#include "env_debughistory.h"
#include "tier1/utlstring.h"
#include "utlhashtable.h"
#ifdef MAPBASE
#include "mapbase/matchers.h"
#include "mapbase/datadesc_mod.h"
#endif
Mapbase v4.3 - Fixed a crash with multiple trigger_look targets - Fixed an issue where some zombie submodel server ragdolls are not solid to the world - Fixed a crash with certain instance classes being loaded in a savegame before the class is registered - Added some of Tony Sergi's missing Source 2007 fixes (contributed by Kris) - Added "ClientCommand" hook for VScript to allow handling of unknown console commands - Added "PlayerRunCommand" hook for VScript to control player movement - Added new button-related script functions for players (GetButtons, DisableButtons, etc.) - Added CUserCmd accessor in VScript for the "PlayerRunCommand" hook - Added "GetWaterLevel" function for VScript - Exposed "Ignite" to VScript for controlling how a fire starts - Fixed NPCs being unable to unholster weapons - Fixed Mapbase crashing when Steam isn't running - Fixed issues with angled/updating sky_camera save/restore - Added VBSP "-skyboxcubemap" parameter to enable skybox default cubemaps + "-defaultcubemapres" to control their resolution - Added ability to disable VScript in a map (and fixed a few potential complications from disabling VScript) - Made clientside VScript only initialize after world is spawned in order to receive serverside script language in time - Added tons of VScript functions to CBaseAnimating related to bodygroups, sequences, etc. - Added VScript functions to players for getting user ID and player name, similar to logic_playerinfo - Added a few L4D2 script functions missing from the ASW SDK - Added "Localize" singleton with a single "GetTokenAsUTF8" function for getting localization strings - Disabled r_hunkalloclightmaps by the request of various users (apparently this completely removes the "Engine hunk overflow" error and allows for really high-res lightmaps) - Fixed npc_antlionguard NPC_TranslateActivity not hooking into base class (allows for VScript manipulation) - Added various unused antlion guard activities to npc_antlionguard AI, allowing for usage as registered activities - Added keyvalue to set LOS mask on combine_mine - Added +USE bounding box limiter to prop_interactable
2020-07-16 15:43:30 +00:00
#ifdef MAPBASE_VSCRIPT
#include "mapbase/vscript_funcs_math.h"
#endif
2013-12-02 19:31:46 -08:00
#if defined( TF_DLL )
#include "tf_gamerules.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool g_bTestMoveTypeStepSimulation;
extern ConVar sv_vehicle_autoaim_scale;
// Init static class variables
bool CBaseEntity::m_bInDebugSelect = false; // Used for selection in debug overlays
int CBaseEntity::m_nDebugPlayer = -1; // Player doing the selection
// This can be set before creating an entity to force it to use a particular edict.
edict_t *g_pForceAttachEdict = NULL;
bool CBaseEntity::m_bDebugPause = false; // Whether entity i/o is paused.
int CBaseEntity::m_nDebugSteps = 1; // Number of entity outputs to fire before pausing again.
bool CBaseEntity::sm_bDisableTouchFuncs = false; // Disables PhysicsTouch and PhysicsStartTouch function calls
bool CBaseEntity::sm_bAccurateTriggerBboxChecks = true; // set to false for legacy behavior in ep1
int CBaseEntity::m_nPredictionRandomSeed = -1;
CBasePlayer *CBaseEntity::m_pPredictionPlayer = NULL;
// Used to make sure nobody calls UpdateTransmitState directly.
int g_nInsideDispatchUpdateTransmitState = 0;
// When this is false, throw an assert in debug when GetAbsAnything is called. Used when hierachy is incomplete/invalid.
bool CBaseEntity::s_bAbsQueriesValid = true;
ConVar sv_netvisdist( "sv_netvisdist", "10000", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Test networking visibility distance" );
ConVar sv_script_think_interval("sv_script_think_interval", "0.1");
2013-12-02 19:31:46 -08:00
// This table encodes edict data.
void SendProxy_AnimTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID )
{
CBaseEntity *pEntity = (CBaseEntity *)pStruct;
#if defined( _DEBUG )
CBaseAnimating *pAnimating = pEntity->GetBaseAnimating();
Assert( pAnimating );
if ( pAnimating )
{
Assert( !pAnimating->IsUsingClientSideAnimation() );
}
#endif
int ticknumber = TIME_TO_TICKS( pEntity->m_flAnimTime );
// Tickbase is current tick rounded down to closes 100 ticks
int tickbase = gpGlobals->GetNetworkBase( gpGlobals->tickcount, pEntity->entindex() );
int addt = 0;
// If it's within the last tick interval through the current one, then we can encode it
if ( ticknumber >= ( tickbase - 100 ) )
{
addt = ( ticknumber - tickbase ) & 0xFF;
}
pOut->m_Int = addt;
}
// This table encodes edict data.
void SendProxy_SimulationTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID )
{
CBaseEntity *pEntity = (CBaseEntity *)pStruct;
int ticknumber = TIME_TO_TICKS( pEntity->m_flSimulationTime );
// tickbase is current tick rounded down to closest 100 ticks
int tickbase = gpGlobals->GetNetworkBase( gpGlobals->tickcount, pEntity->entindex() );
int addt = 0;
if ( ticknumber >= tickbase )
{
addt = ( ticknumber - tickbase ) & 0xff;
}
pOut->m_Int = addt;
}
void* SendProxy_ClientSideAnimation( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
{
CBaseEntity *pEntity = (CBaseEntity *)pStruct;
CBaseAnimating *pAnimating = pEntity->GetBaseAnimating();
if ( pAnimating && !pAnimating->IsUsingClientSideAnimation() )
return (void*)pVarData;
else
return NULL; // Don't send animtime unless the client needs it.
}
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_ClientSideAnimation );
BEGIN_SEND_TABLE_NOBASE( CBaseEntity, DT_AnimTimeMustBeFirst )
// NOTE: Animtime must be sent before origin and angles ( from pev ) because it has a
// proxy on the client that stores off the old values before writing in the new values and
// if it is sent after the new values, then it will only have the new origin and studio model, etc.
// interpolation will be busted
SendPropInt (SENDINFO(m_flAnimTime), 8, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN|SPROP_ENCODED_AGAINST_TICKCOUNT, SendProxy_AnimTime),
END_SEND_TABLE()
#if !defined( NO_ENTITY_PREDICTION )
BEGIN_SEND_TABLE_NOBASE( CBaseEntity, DT_PredictableId )
SendPropPredictableId( SENDINFO( m_PredictableID ) ),
SendPropInt( SENDINFO( m_bIsPlayerSimulated ), 1, SPROP_UNSIGNED ),
END_SEND_TABLE()
static void* SendProxy_SendPredictableId( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
{
CBaseEntity *pEntity = (CBaseEntity *)pStruct;
if ( !pEntity || !pEntity->m_PredictableID->IsActive() )
return NULL;
int id_player_index = pEntity->m_PredictableID->GetPlayer();
pRecipients->SetOnly( id_player_index );
return ( void * )pVarData;
}
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendPredictableId );
#endif
void SendProxy_Origin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
{
CBaseEntity *entity = (CBaseEntity*)pStruct;
Assert( entity );
const Vector *v;
if ( !entity->UseStepSimulationNetworkOrigin( &v ) )
{
v = &entity->GetLocalOrigin();
}
pOut->m_Vector[ 0 ] = v->x;
pOut->m_Vector[ 1 ] = v->y;
pOut->m_Vector[ 2 ] = v->z;
}
//--------------------------------------------------------------------------------------------------------
// Used when breaking up origin, note we still have to deal with StepSimulation
//--------------------------------------------------------------------------------------------------------
void SendProxy_OriginXY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
{
CBaseEntity *entity = (CBaseEntity*)pStruct;
Assert( entity );
const Vector *v;
if ( !entity->UseStepSimulationNetworkOrigin( &v ) )
{
v = &entity->GetLocalOrigin();
}
pOut->m_Vector[ 0 ] = v->x;
pOut->m_Vector[ 1 ] = v->y;
}
//--------------------------------------------------------------------------------------------------------
// Used when breaking up origin, note we still have to deal with StepSimulation
//--------------------------------------------------------------------------------------------------------
void SendProxy_OriginZ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
{
CBaseEntity *entity = (CBaseEntity*)pStruct;
Assert( entity );
const Vector *v;
if ( !entity->UseStepSimulationNetworkOrigin( &v ) )
{
v = &entity->GetLocalOrigin();
}
pOut->m_Float = v->z;
}
void SendProxy_Angles( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
{
CBaseEntity *entity = (CBaseEntity*)pStruct;
Assert( entity );
const QAngle *a;
if ( !entity->UseStepSimulationNetworkAngles( &a ) )
{
a = &entity->GetLocalAngles();
}
pOut->m_Vector[ 0 ] = anglemod( a->x );
pOut->m_Vector[ 1 ] = anglemod( a->y );
pOut->m_Vector[ 2 ] = anglemod( a->z );
}
// This table encodes the CBaseEntity data.
IMPLEMENT_SERVERCLASS_ST_NOBASE( CBaseEntity, DT_BaseEntity )
SendPropDataTable( "AnimTimeMustBeFirst", 0, &REFERENCE_SEND_TABLE(DT_AnimTimeMustBeFirst), SendProxy_ClientSideAnimation ),
SendPropInt (SENDINFO(m_flSimulationTime), SIMULATION_TIME_WINDOW_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN|SPROP_ENCODED_AGAINST_TICKCOUNT, SendProxy_SimulationTime),
#if PREDICTION_ERROR_CHECK_LEVEL > 1
SendPropVector (SENDINFO(m_vecOrigin), -1, SPROP_NOSCALE|SPROP_CHANGES_OFTEN, 0.0f, HIGH_DEFAULT, SendProxy_Origin ),
#else
SendPropVector (SENDINFO(m_vecOrigin), -1, SPROP_COORD|SPROP_CHANGES_OFTEN, 0.0f, HIGH_DEFAULT, SendProxy_Origin ),
#endif
SendPropInt (SENDINFO( m_ubInterpolationFrame ), NOINTERP_PARITY_MAX_BITS, SPROP_UNSIGNED ),
SendPropModelIndex(SENDINFO(m_nModelIndex)),
SendPropDataTable( SENDINFO_DT( m_Collision ), &REFERENCE_SEND_TABLE(DT_CollisionProperty) ),
SendPropInt (SENDINFO(m_nRenderFX), 8, SPROP_UNSIGNED ),
SendPropInt (SENDINFO(m_nRenderMode), 8, SPROP_UNSIGNED ),
SendPropInt (SENDINFO(m_fEffects), EF_MAX_BITS, SPROP_UNSIGNED),
SendPropInt (SENDINFO(m_clrRender), 32, SPROP_UNSIGNED),
Merged dev changes 9/28/2019 - Experimental RPC stuff for the future - Fixed players running over allies with vehicles (kind of) - Modified redirect filter infrastructure to support when there's no target filter (meaning it will just make sure the entity exists) - Fixed SDK_EyeRefract - Fixed env_beam SetStart/EndEntity - New "OnStateChange" output on NPCs - scripted_face removed (use generic facing VCDs instead) - Fixed RPC - View ID nodraw keyvalue + reflective glass view ID fix - CopyAnimationDataFrom expansion (more variables copied) - Fixed pre-Mapbase env_projectedtextures not updating after loading a save - Fixed(?) player companion grenade throwing being interrupted - Added convars for secondary and NPC shotgun pellet amounts - NPC fade distance/scale transfers to its ragdoll - Made node graph rebuild occur sooner after map load - Added option to disable "node graph out of date" message - Fixed ent_fire delay (decimals discarded before) - "SetFilter" on func_clip_vphysics - Fixed func_tank zero barrel (untested) - Fixed npc_turret_ground parenting fix - Added toggle-able weapon_crossbow experimental hit location code - Fixed ally grenades being considered Combine grenades - Added SDK_MonitorScreen and SDK_UnlitTwoTexture - Updated README - Added !activator/!caller support to logic_collision_pair - Fixed ortho not working in script_intro - Added Nbc66's closed captioning language fix - Applied fade fix to server ragdolls - Added combine_mine friend/foe filters - Fixed env_starfield pausing - Reworked PickupWeapon/Item inputs - Fixed context response system $ usage - Fixed env_break_shooter velocity/speed - Made func_breakable "Spawn on break" support other entities - Fixed OnThrowGrenade > point_entity_replace blip - Added mapname to logic_externaldata - Added "Random Template" to point_template - Added "Use LOS" to trigger_look - Added flags based on L4D(2) to trigger_playermovement - Added npc_combine_s "Alternate Capable" keyvalue that enables both grenades and alt-fire at the same time regardless of elite status - Fixed npc_combine_s DropGrenade input - Miscellaneous code and comment changes
2019-09-28 22:56:52 +00:00
#ifdef MAPBASE
// Keep consistent with VIEW_ID_COUNT in viewrender.h
SendPropInt (SENDINFO(m_iViewHideFlags), 9, SPROP_UNSIGNED ),
#endif
2013-12-02 19:31:46 -08:00
SendPropInt (SENDINFO(m_iTeamNum), TEAMNUM_NUM_BITS, 0),
SendPropInt (SENDINFO(m_CollisionGroup), 5, SPROP_UNSIGNED),
SendPropFloat (SENDINFO(m_flElasticity), 0, SPROP_COORD),
SendPropFloat (SENDINFO(m_flShadowCastDistance), 12, SPROP_UNSIGNED ),
SendPropEHandle (SENDINFO(m_hOwnerEntity)),
SendPropEHandle (SENDINFO(m_hEffectEntity)),
SendPropEHandle (SENDINFO_NAME(m_hMoveParent, moveparent)),
SendPropInt (SENDINFO(m_iParentAttachment), NUM_PARENTATTACHMENT_BITS, SPROP_UNSIGNED),
SendPropStringT( SENDINFO( m_iName ) ),
2013-12-02 19:31:46 -08:00
SendPropInt (SENDINFO_NAME( m_MoveType, movetype ), MOVETYPE_MAX_BITS, SPROP_UNSIGNED ),
SendPropInt (SENDINFO_NAME( m_MoveCollide, movecollide ), MOVECOLLIDE_MAX_BITS, SPROP_UNSIGNED ),
#if PREDICTION_ERROR_CHECK_LEVEL > 1
SendPropVector (SENDINFO(m_angRotation), -1, SPROP_NOSCALE|SPROP_CHANGES_OFTEN, 0, HIGH_DEFAULT, SendProxy_Angles ),
#else
SendPropQAngles (SENDINFO(m_angRotation), 13, SPROP_CHANGES_OFTEN, SendProxy_Angles ),
#endif
SendPropInt ( SENDINFO( m_iTextureFrameIndex ), 8, SPROP_UNSIGNED ),
#if !defined( NO_ENTITY_PREDICTION )
SendPropDataTable( "predictable_id", 0, &REFERENCE_SEND_TABLE( DT_PredictableId ), SendProxy_SendPredictableId ),
#endif
// FIXME: Collapse into another flag field?
SendPropInt (SENDINFO(m_bSimulatedEveryTick), 1, SPROP_UNSIGNED ),
SendPropInt (SENDINFO(m_bAnimatedEveryTick), 1, SPROP_UNSIGNED ),
SendPropBool( SENDINFO( m_bAlternateSorting )),
#ifdef TF_DLL
SendPropArray3( SENDINFO_ARRAY3(m_nModelIndexOverrides), SendPropInt( SENDINFO_ARRAY(m_nModelIndexOverrides), SP_MODEL_INDEX_BITS, 0 ) ),
2013-12-02 19:31:46 -08:00
#endif
END_SEND_TABLE()
// dynamic models
class CBaseEntityModelLoadProxy
{
protected:
class Handler : public IModelLoadCallback
{
public:
explicit Handler( CBaseEntity *pEntity ) : m_pEntity(pEntity) { }
virtual void OnModelLoadComplete( const model_t *pModel );
CBaseEntity* m_pEntity;
};
Handler* m_pHandler;
public:
explicit CBaseEntityModelLoadProxy( CBaseEntity *pEntity ) : m_pHandler( new Handler( pEntity ) ) { }
~CBaseEntityModelLoadProxy() { delete m_pHandler; }
void Register( int nModelIndex ) const { modelinfo->RegisterModelLoadCallback( nModelIndex, m_pHandler ); }
operator CBaseEntity * () const { return m_pHandler->m_pEntity; }
private:
CBaseEntityModelLoadProxy( const CBaseEntityModelLoadProxy& );
CBaseEntityModelLoadProxy& operator=( const CBaseEntityModelLoadProxy& );
};
static CUtlHashtable< CBaseEntityModelLoadProxy, empty_t, PointerHashFunctor, PointerEqualFunctor, CBaseEntity * > sg_DynamicLoadHandlers;
void CBaseEntityModelLoadProxy::Handler::OnModelLoadComplete( const model_t *pModel )
{
m_pEntity->OnModelLoadComplete( pModel );
sg_DynamicLoadHandlers.Remove( m_pEntity ); // NOTE: destroys *this!
}
CBaseEntity::CBaseEntity( bool bServerOnly )
{
COMPILE_TIME_ASSERT( MOVETYPE_LAST < (1 << MOVETYPE_MAX_BITS) );
COMPILE_TIME_ASSERT( MOVECOLLIDE_COUNT < (1 << MOVECOLLIDE_MAX_BITS) );
#ifdef _DEBUG
// necessary since in debug, we initialize vectors to NAN for debugging
m_vecAngVelocity.Init();
// m_vecAbsAngVelocity.Init();
m_vecViewOffset.Init();
m_vecBaseVelocity.GetForModify().Init();
m_vecVelocity.Init();
m_vecAbsVelocity.Init();
#endif
m_bAlternateSorting = false;
m_CollisionGroup = COLLISION_GROUP_NONE;
m_iParentAttachment = 0;
CollisionProp()->Init( this );
NetworkProp()->Init( this );
// NOTE: THIS MUST APPEAR BEFORE ANY SetMoveType() or SetNextThink() calls
AddEFlags( EFL_NO_THINK_FUNCTION | EFL_NO_GAME_PHYSICS_SIMULATION | EFL_USE_PARTITION_WHEN_NOT_SOLID );
// clear debug overlays
m_debugOverlays = 0;
m_pTimedOverlay = NULL;
m_pPhysicsObject = NULL;
m_flElasticity = 1.0f;
m_flShadowCastDistance = m_flDesiredShadowCastDistance = 0;
SetRenderColor( 255, 255, 255, 255 );
m_iTeamNum = m_iInitialTeamNum = TEAM_UNASSIGNED;
m_nLastThinkTick = gpGlobals->tickcount;
m_nSimulationTick = -1;
SetIdentityMatrix( m_rgflCoordinateFrame );
m_pBlocker = NULL;
#if _DEBUG
m_iCurrentThinkContext = NO_THINK_CONTEXT;
#endif
m_nWaterTouch = m_nSlimeTouch = 0;
SetSolid( SOLID_NONE );
ClearSolidFlags();
m_nModelIndex = 0;
m_bDynamicModelAllowed = false;
m_bDynamicModelPending = false;
m_bDynamicModelSetBounds = false;
SetMoveType( MOVETYPE_NONE );
SetOwnerEntity( NULL );
SetCheckUntouch( false );
SetModelIndex( 0 );
SetModelName( NULL_STRING );
m_nTransmitStateOwnedCounter = 0;
SetCollisionBounds( vec3_origin, vec3_origin );
ClearFlags();
SetFriction( 1.0f );
if ( bServerOnly )
{
AddEFlags( EFL_SERVER_ONLY );
}
NetworkProp()->MarkPVSInformationDirty();
#ifndef _XBOX
AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Scale up our physics hull and test against the new one
// Input : *pNewCollide - New collision hull
//-----------------------------------------------------------------------------
void CBaseEntity::SetScaledPhysics( IPhysicsObject *pNewObject )
{
if ( pNewObject )
{
AddSolidFlags( FSOLID_CUSTOMBOXTEST | FSOLID_CUSTOMRAYTEST );
}
else
{
RemoveSolidFlags( FSOLID_CUSTOMBOXTEST | FSOLID_CUSTOMRAYTEST );
}
}
extern bool g_bDisableEhandleAccess;
//-----------------------------------------------------------------------------
// Purpose: See note below
//-----------------------------------------------------------------------------
CBaseEntity::~CBaseEntity( )
{
// FIXME: This can't be called from UpdateOnRemove! There's at least one
// case where friction sounds are added between the call to UpdateOnRemove + ~CBaseEntity
PhysCleanupFrictionSounds( this );
Assert( !IsDynamicModelIndex( m_nModelIndex ) );
Verify( !sg_DynamicLoadHandlers.Remove( this ) );
// In debug make sure that we don't call delete on an entity without setting
// the disable flag first!
// EHANDLE accessors will check, in debug, for access to entities during destruction of
// another entity.
// That kind of operation should only occur in UpdateOnRemove calls
// Deletion should only occur via UTIL_Remove(Immediate) calls, not via naked delete calls
Assert( g_bDisableEhandleAccess );
VPhysicsDestroyObject();
// Need to remove references to this entity before EHANDLES go null
{
g_bDisableEhandleAccess = false;
CBaseEntity::PhysicsRemoveTouchedList( this );
CBaseEntity::PhysicsRemoveGroundList( this );
SetGroundEntity( NULL ); // remove us from the ground entity if we are on it
DestroyAllDataObjects();
g_bDisableEhandleAccess = true;
// Remove this entity from the ent list (NOTE: This Makes EHANDLES go NULL)
gEntList.RemoveEntity( GetRefEHandle() );
}
}
void CBaseEntity::PostConstructor( const char *szClassname )
{
if ( szClassname )
{
SetClassname(szClassname);
}
Assert( m_iClassname != NULL_STRING && STRING(m_iClassname) != NULL );
// Possibly get an edict, and add self to global list of entites.
if ( IsEFlagSet( EFL_SERVER_ONLY ) )
{
gEntList.AddNonNetworkableEntity( this );
}
else
{
// Certain entities set up their edicts in the constructor
if ( !IsEFlagSet( EFL_NO_AUTO_EDICT_ATTACH ) )
{
NetworkProp()->AttachEdict( g_pForceAttachEdict );
g_pForceAttachEdict = NULL;
}
// Some ents like the player override the AttachEdict function and do it at a different time.
// While precaching, they don't ever have an edict, so we don't need to add them to
// the entity list in that case.
if ( edict() )
{
gEntList.AddNetworkableEntity( this, entindex() );
// Cache our IServerNetworkable pointer for the engine for fast access.
if ( edict() )
edict()->m_pNetworkable = NetworkProp();
}
}
CheckHasThinkFunction( false );
CheckHasGamePhysicsSimulation();
}
//-----------------------------------------------------------------------------
// Purpose: Called after player becomes active in the game
//-----------------------------------------------------------------------------
void CBaseEntity::PostClientActive( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Verifies that this entity's data description is valid in debug builds.
//-----------------------------------------------------------------------------
#ifdef _DEBUG
typedef CUtlVector< const char * > KeyValueNameList_t;
static void AddDataMapFieldNamesToList( KeyValueNameList_t &list, datamap_t *pDataMap )
{
while (pDataMap != NULL)
{
for (int i = 0; i < pDataMap->dataNumFields; i++)
{
typedescription_t *pField = &pDataMap->dataDesc[i];
if (pField->fieldType == FIELD_EMBEDDED)
{
AddDataMapFieldNamesToList( list, pField->td );
continue;
}
if (pField->flags & FTYPEDESC_KEY)
{
list.AddToTail( pField->externalName );
}
}
pDataMap = pDataMap->baseMap;
}
}
void CBaseEntity::ValidateDataDescription(void)
{
// Multiple key fields that have the same name are not allowed - it creates an
// ambiguity when trying to parse keyvalues and outputs.
datamap_t *pDataMap = GetDataDescMap();
if ((pDataMap == NULL) || pDataMap->bValidityChecked)
return;
pDataMap->bValidityChecked = true;
// Let's generate a list of all keyvalue strings in the entire hierarchy...
KeyValueNameList_t names(128);
AddDataMapFieldNamesToList( names, pDataMap );
for (int i = names.Count(); --i > 0; )
{
for (int j = i - 1; --j >= 0; )
{
if (!Q_stricmp(names[i], names[j]))
{
DevMsg( "%s has multiple data description entries for \"%s\"\n", STRING(m_iClassname), names[i]);
break;
}
}
}
}
#endif // _DEBUG
//-----------------------------------------------------------------------------
// Sets the collision bounds + the size
//-----------------------------------------------------------------------------
void CBaseEntity::SetCollisionBounds( const Vector& mins, const Vector &maxs )
{
m_Collision.SetCollisionBounds( mins, maxs );
}
void CBaseEntity::StopFollowingEntity( )
{
if( !IsFollowingEntity() )
{
// Assert( IsEffectActive( EF_BONEMERGE ) == 0 );
return;
}
SetParent( NULL );
RemoveEffects( EF_BONEMERGE );
RemoveSolidFlags( FSOLID_NOT_SOLID );
SetMoveType( MOVETYPE_NONE );
CollisionRulesChanged();
}
bool CBaseEntity::IsFollowingEntity()
{
return IsEffectActive( EF_BONEMERGE ) && (GetMoveType() == MOVETYPE_NONE) && GetMoveParent();
}
CBaseEntity *CBaseEntity::GetFollowedEntity()
{
if (!IsFollowingEntity())
return NULL;
return GetMoveParent();
}
void CBaseEntity::SetClassname( const char *className )
{
m_iClassname = AllocPooledString( className );
}
void CBaseEntity::SetModelIndex( int index )
{
if ( IsDynamicModelIndex( index ) && !(GetBaseAnimating() && m_bDynamicModelAllowed) )
{
AssertMsg( false, "dynamic model support not enabled on server entity" );
index = -1;
}
if ( index != m_nModelIndex )
{
if ( m_bDynamicModelPending )
{
sg_DynamicLoadHandlers.Remove( this );
}
modelinfo->ReleaseDynamicModel( m_nModelIndex );
modelinfo->AddRefDynamicModel( index );
m_nModelIndex = index;
m_bDynamicModelSetBounds = false;
if ( IsDynamicModelIndex( index ) )
{
m_bDynamicModelPending = true;
sg_DynamicLoadHandlers[ sg_DynamicLoadHandlers.Insert( this ) ].Register( index );
}
else
{
m_bDynamicModelPending = false;
OnNewModel();
}
}
DispatchUpdateTransmitState();
}
void CBaseEntity::ClearModelIndexOverrides( void )
{
#ifdef TF_DLL
for ( int index = 0 ; index < MAX_VISION_MODES ; index++ )
{
m_nModelIndexOverrides.Set( index, 0 );
}
#endif
}
void CBaseEntity::SetModelIndexOverride( int index, int nValue )
{
#ifdef TF_DLL
if ( ( index >= VISION_MODE_NONE ) && ( index < MAX_VISION_MODES ) )
{
if ( nValue != m_nModelIndexOverrides[index] )
{
m_nModelIndexOverrides.Set( index, nValue );
}
}
#endif
}
// position to shoot at
Vector CBaseEntity::BodyTarget( const Vector &posSrc, bool bNoisy)
{
return WorldSpaceCenter( );
}
// return the position of my head. someone's trying to attack it.
Vector CBaseEntity::HeadTarget( const Vector &posSrc )
{
return EyePosition();
}
struct TimedOverlay_t
{
char *msg;
int msgEndTime;
int msgStartTime;
TimedOverlay_t *pNextTimedOverlay;
};
//-----------------------------------------------------------------------------
// Purpose: Display an error message on the entity
// Input :
// Output :
//-----------------------------------------------------------------------------
void CBaseEntity::AddTimedOverlay( const char *msg, int endTime )
{
TimedOverlay_t *pNewTO = new TimedOverlay_t;
int len = strlen(msg);
pNewTO->msg = new char[len + 1];
Q_strncpy(pNewTO->msg,msg, len+1);
pNewTO->msgEndTime = gpGlobals->curtime + endTime;
pNewTO->msgStartTime = gpGlobals->curtime;
pNewTO->pNextTimedOverlay = m_pTimedOverlay;
m_pTimedOverlay = pNewTO;
}
//-----------------------------------------------------------------------------
// Purpose: Send debug overlay box to the client
// Input :
// Output :
//-----------------------------------------------------------------------------
void CBaseEntity::DrawBBoxOverlay( float flDuration )
{
if (edict())
{
NDebugOverlay::EntityBounds(this, 255, 100, 0, 0, flDuration );
if ( CollisionProp()->IsSolidFlagSet( FSOLID_USE_TRIGGER_BOUNDS ) )
{
Vector vecTriggerMins, vecTriggerMaxs;
CollisionProp()->WorldSpaceTriggerBounds( &vecTriggerMins, &vecTriggerMaxs );
Vector center = 0.5f * (vecTriggerMins + vecTriggerMaxs);
Vector extents = vecTriggerMaxs - center;
NDebugOverlay::Box(center, -extents, extents, 0, 255, 255, 0, flDuration );
}
}
}
void CBaseEntity::DrawAbsBoxOverlay()
{
int red = 0;
int green = 200;
if ( VPhysicsGetObject() && VPhysicsGetObject()->IsAsleep() )
{
red = 90;
green = 120;
}
if (edict())
{
// Surrounding boxes are axially aligned, so ignore angles
Vector vecSurroundMins, vecSurroundMaxs;
CollisionProp()->WorldSpaceSurroundingBounds( &vecSurroundMins, &vecSurroundMaxs );
Vector center = 0.5f * (vecSurroundMins + vecSurroundMaxs);
Vector extents = vecSurroundMaxs - center;
NDebugOverlay::Box(center, -extents, extents, red, green, 0, 0 ,0);
}
}
void CBaseEntity::DrawRBoxOverlay()
{
}
//-----------------------------------------------------------------------------
// Purpose: Draws an axis overlay at the origin and angles of the entity
//-----------------------------------------------------------------------------
void CBaseEntity::SendDebugPivotOverlay( void )
{
if ( edict() )
{
NDebugOverlay::Axis( GetAbsOrigin(), GetAbsAngles(), 20, true, 0 );
}
}
//------------------------------------------------------------------------------
// Purpose : Add new entity positioned overlay text
// Input : How many lines to offset text from origin
// The text to print
// How long to display text
// The color of the text
// Output :
//------------------------------------------------------------------------------
void CBaseEntity::EntityText( int text_offset, const char *text, float duration, int r, int g, int b, int a )
{
Vector origin;
Vector vecLocalCenter;
VectorAdd( m_Collision.OBBMins(), m_Collision.OBBMaxs(), vecLocalCenter );
vecLocalCenter *= 0.5f;
if ( ( m_Collision.GetCollisionAngles() == vec3_angle ) || ( vecLocalCenter == vec3_origin ) )
{
VectorAdd( vecLocalCenter, m_Collision.GetCollisionOrigin(), origin );
}
else
{
VectorTransform( vecLocalCenter, m_Collision.CollisionToWorldTransform(), origin );
}
NDebugOverlay::EntityTextAtPosition( origin, text_offset, text, duration, r, g, b, a );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseEntity::DrawTimedOverlays(void)
{
// Draw name first if I have an overlay or am in message mode
if ((m_debugOverlays & OVERLAY_MESSAGE_BIT))
{
char tempstr[512];
Q_snprintf( tempstr, sizeof( tempstr ), "[%s]", GetDebugName() );
EntityText(0,tempstr, 0);
}
// Now draw overlays
TimedOverlay_t* pTO = m_pTimedOverlay;
TimedOverlay_t* pNextTO = NULL;
TimedOverlay_t* pLastTO = NULL;
int nCount = 1; // Offset by one
while (pTO)
{
pNextTO = pTO->pNextTimedOverlay;
// Remove old messages unless messages are paused
if ((!CBaseEntity::Debug_IsPaused() && gpGlobals->curtime > pTO->msgEndTime) ||
(nCount > 10))
{
if (pLastTO)
{
pLastTO->pNextTimedOverlay = pNextTO;
}
else
{
m_pTimedOverlay = pNextTO;
}
delete pTO->msg;
delete pTO;
}
else
{
int nAlpha = 0;
// If messages aren't paused fade out
if (!CBaseEntity::Debug_IsPaused())
{
nAlpha = 255*((gpGlobals->curtime - pTO->msgStartTime)/(pTO->msgEndTime - pTO->msgStartTime));
}
int r = 185;
int g = 145;
int b = 145;
// Brighter when new message
if (nAlpha < 50)
{
r = 255;
g = 205;
b = 205;
}
if (nAlpha < 0) nAlpha = 0;
EntityText(nCount,pTO->msg, 0.0, r, g, b, 255-nAlpha);
nCount++;
pLastTO = pTO;
}
pTO = pNextTO;
}
}
//-----------------------------------------------------------------------------
// Purpose: Draw all overlays (should be implemented by subclass to add
// any additional non-text overlays)
// Input :
// Output : Current text offset from the top
//-----------------------------------------------------------------------------
void CBaseEntity::DrawDebugGeometryOverlays(void)
{
DrawTimedOverlays();
DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_NAME_BIT)
{
EntityText(0,GetDebugName(), 0);
}
if (m_debugOverlays & OVERLAY_BBOX_BIT)
{
DrawBBoxOverlay();
}
if (m_debugOverlays & OVERLAY_ABSBOX_BIT )
{
DrawAbsBoxOverlay();
}
if (m_debugOverlays & OVERLAY_PIVOT_BIT)
{
SendDebugPivotOverlay();
}
if( m_debugOverlays & OVERLAY_RBOX_BIT )
{
DrawRBoxOverlay();
}
if ( m_debugOverlays & (OVERLAY_BBOX_BIT|OVERLAY_PIVOT_BIT) )
{
// draw mass center
if ( VPhysicsGetObject() )
{
Vector massCenter = VPhysicsGetObject()->GetMassCenterLocalSpace();
Vector worldPos;
VPhysicsGetObject()->LocalToWorld( &worldPos, massCenter );
NDebugOverlay::Cross3D( worldPos, 12, 255, 0, 0, false, 0 );
DebugDrawContactPoints(VPhysicsGetObject());
if ( GetMoveType() != MOVETYPE_VPHYSICS )
{
Vector pos;
QAngle angles;
VPhysicsGetObject()->GetPosition( &pos, &angles );
float dist = (pos - GetAbsOrigin()).Length();
Vector axis;
float deltaAngle;
RotationDeltaAxisAngle( angles, GetAbsAngles(), axis, deltaAngle );
if ( dist > 2 || fabsf(deltaAngle) > 2 )
{
Vector mins, maxs;
physcollision->CollideGetAABB( &mins, &maxs, VPhysicsGetObject()->GetCollide(), vec3_origin, vec3_angle );
NDebugOverlay::BoxAngles( pos, mins, maxs, angles, 255, 255, 0, 16, 0 );
}
}
}
}
if ( m_debugOverlays & OVERLAY_SHOW_BLOCKSLOS )
{
if ( BlocksLOS() )
{
NDebugOverlay::EntityBounds(this, 255, 255, 255, 0, 0 );
}
}
if ( m_debugOverlays & OVERLAY_AUTOAIM_BIT && (GetFlags()&FL_AIMTARGET) && AI_GetSinglePlayer() != NULL )
{
// Crude, but it gets the point across.
Vector vecCenter = GetAutoAimCenter();
Vector vecRight, vecUp, vecDiag;
CBasePlayer *pPlayer = AI_GetSinglePlayer();
float radius = GetAutoAimRadius();
QAngle angles = pPlayer->EyeAngles();
AngleVectors( angles, NULL, &vecRight, &vecUp );
int r,g,b;
if( ((int)gpGlobals->curtime) % 2 == 1 )
{
r = 255;
g = 255;
b = 255;
if( pPlayer->GetActiveWeapon() != NULL )
radius *= pPlayer->GetActiveWeapon()->WeaponAutoAimScale();
}
else
{
r = 255;g=0;b=0;
if( !ShouldAttractAutoAim(pPlayer) )
{
g = 255;
}
}
if( pPlayer->IsInAVehicle() )
{
radius *= sv_vehicle_autoaim_scale.GetFloat();
}
NDebugOverlay::Line( vecCenter, vecCenter + vecRight * radius, r, g, b, true, 0.1 );
NDebugOverlay::Line( vecCenter, vecCenter - vecRight * radius, r, g, b, true, 0.1 );
NDebugOverlay::Line( vecCenter, vecCenter + vecUp * radius, r, g, b, true, 0.1 );
NDebugOverlay::Line( vecCenter, vecCenter - vecUp * radius, r, g, b, true, 0.1 );
vecDiag = vecRight + vecUp;
VectorNormalize( vecDiag );
NDebugOverlay::Line( vecCenter - vecDiag * radius, vecCenter + vecDiag * radius, r, g, b, true, 0.1 );
vecDiag = vecRight - vecUp;
VectorNormalize( vecDiag );
NDebugOverlay::Line( vecCenter - vecDiag * radius, vecCenter + vecDiag * radius, r, g, b, true, 0.1 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Draw any text overlays (override in subclass to add additional text)
// Output : Current text offset from the top
//-----------------------------------------------------------------------------
int CBaseEntity::DrawDebugTextOverlays(void)
{
int offset = 1;
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
char tempstr[512];
Q_snprintf( tempstr, sizeof(tempstr), "(%d) Name: %s (%s)", entindex(), GetDebugName(), GetClassname() );
EntityText(offset,tempstr, 0);
offset++;
if( m_iGlobalname != NULL_STRING )
{
Q_snprintf( tempstr, sizeof(tempstr), "GLOBALNAME: %s", STRING(m_iGlobalname) );
EntityText(offset,tempstr, 0);
offset++;
}
Vector vecOrigin = GetAbsOrigin();
Q_snprintf( tempstr, sizeof(tempstr), "Position: %0.1f, %0.1f, %0.1f\n", vecOrigin.x, vecOrigin.y, vecOrigin.z );
EntityText( offset, tempstr, 0 );
offset++;
if( GetModelName() != NULL_STRING || GetBaseAnimating() )
{
Q_snprintf(tempstr, sizeof(tempstr), "Model:%s", STRING(GetModelName()) );
EntityText(offset,tempstr,0);
offset++;
}
if( m_hDamageFilter.Get() != NULL )
{
Q_snprintf( tempstr, sizeof(tempstr), "DAMAGE FILTER:%s", m_hDamageFilter->GetDebugName() );
EntityText( offset,tempstr,0 );
offset++;
}
#ifdef MAPBASE
if (m_ResponseContexts.Count() > 0)
{
const char *contexts = UTIL_VarArgs("%s:%s", STRING(m_ResponseContexts[0].m_iszName), STRING(m_ResponseContexts[0].m_iszValue));
for (int i = 1; i < GetContextCount(); i++)
{
contexts = UTIL_VarArgs("%s,%s:%s", contexts, STRING(m_ResponseContexts[i].m_iszName), STRING(m_ResponseContexts[i].m_iszValue));
}
Q_snprintf(tempstr, sizeof(tempstr), "Response Contexts:%s", contexts);
EntityText(offset, tempstr, 0);
offset++;
}
#endif
2013-12-02 19:31:46 -08:00
}
if (m_debugOverlays & OVERLAY_VIEWOFFSET)
{
NDebugOverlay::Cross3D( EyePosition(), 16, 255, 0, 0, true, 0.05f );
}
return offset;
}
void CBaseEntity::SetParent( string_t newParent, CBaseEntity *pActivator, int iAttachment )
{
// find and notify the new parent
#ifdef MAPBASE
CBaseEntity *pParent = gEntList.FindEntityByName( NULL, newParent, this, pActivator );
#else
2013-12-02 19:31:46 -08:00
CBaseEntity *pParent = gEntList.FindEntityByName( NULL, newParent, NULL, pActivator );
#endif
2013-12-02 19:31:46 -08:00
// debug check
if ( newParent != NULL_STRING && pParent == NULL )
{
Msg( "Entity %s(%s) has bad parent %s\n", STRING(m_iClassname), GetDebugName(), STRING(newParent) );
}
else
{
// make sure there isn't any ambiguity
#ifdef MAPBASE
if ( gEntList.FindEntityByName( pParent, newParent, this, pActivator ) )
#else
2013-12-02 19:31:46 -08:00
if ( gEntList.FindEntityByName( pParent, newParent, NULL, pActivator ) )
#endif
2013-12-02 19:31:46 -08:00
{
Msg( "Entity %s(%s) has ambigious parent %s\n", STRING(m_iClassname), GetDebugName(), STRING(newParent) );
}
SetParent( pParent, iAttachment );
}
}
//-----------------------------------------------------------------------------
// Purpose: Move our points from parent to worldspace
// Input : *pParent - Parent to use as reference
//-----------------------------------------------------------------------------
void CBaseEntity::TransformStepData_ParentToWorld( CBaseEntity *pParent )
{
// Fix up our step simulation points to be in the proper local space
StepSimulationData *step = (StepSimulationData *) GetDataObject( STEPSIMULATION );
if ( step != NULL )
{
// Convert our positions
UTIL_ParentToWorldSpace( pParent, step->m_Previous2.vecOrigin, step->m_Previous2.qRotation );
UTIL_ParentToWorldSpace( pParent, step->m_Previous.vecOrigin, step->m_Previous.qRotation );
}
}
//-----------------------------------------------------------------------------
// Purpose: Move step data between two parent-spaces
// Input : *pOldParent - parent we were attached to
// *pNewParent - parent we're now attached to
//-----------------------------------------------------------------------------
void CBaseEntity::TransformStepData_ParentToParent( CBaseEntity *pOldParent, CBaseEntity *pNewParent )
{
// Fix up our step simulation points to be in the proper local space
StepSimulationData *step = (StepSimulationData *) GetDataObject( STEPSIMULATION );
if ( step != NULL )
{
// Convert our positions
UTIL_ParentToWorldSpace( pOldParent, step->m_Previous2.vecOrigin, step->m_Previous2.qRotation );
UTIL_WorldToParentSpace( pNewParent, step->m_Previous2.vecOrigin, step->m_Previous2.qRotation );
UTIL_ParentToWorldSpace( pOldParent, step->m_Previous.vecOrigin, step->m_Previous.qRotation );
UTIL_WorldToParentSpace( pNewParent, step->m_Previous.vecOrigin, step->m_Previous.qRotation );
}
}
//-----------------------------------------------------------------------------
// Purpose: After parenting to an object, we need to also correctly translate our
// step stimulation positions and angles into that parent space. Otherwise
// we end up splining between two different world spaces.
//-----------------------------------------------------------------------------
void CBaseEntity::TransformStepData_WorldToParent( CBaseEntity *pParent )
{
// Fix up our step simulation points to be in the proper local space
StepSimulationData *step = (StepSimulationData *) GetDataObject( STEPSIMULATION );
if ( step != NULL )
{
// Convert our positions
UTIL_WorldToParentSpace( pParent, step->m_Previous2.vecOrigin, step->m_Previous2.qRotation );
UTIL_WorldToParentSpace( pParent, step->m_Previous.vecOrigin, step->m_Previous.qRotation );
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the movement parent of this entity. This entity will be moved
// to a local coordinate calculated from its current absolute offset
// from the parent entity and will then follow the parent entity.
// Input : pParentEntity - This entity's new parent in the movement hierarchy.
//-----------------------------------------------------------------------------
void CBaseEntity::SetParent( CBaseEntity *pParentEntity, int iAttachment )
{
// If they didn't specify an attachment, use our current
if ( iAttachment == -1 )
{
iAttachment = m_iParentAttachment;
}
bool bWasNotParented = ( GetParent() == NULL );
CBaseEntity *pOldParent = m_pParent;
// notify the old parent of the loss
UnlinkFromParent( this );
// set the new name
m_pParent = pParentEntity;
if ( m_pParent == this )
{
// should never set parent to 'this' - makes no sense
Assert(0);
m_pParent = NULL;
}
if ( m_pParent == NULL )
{
m_iParent = NULL_STRING;
// Transform step data from parent to worldspace
TransformStepData_ParentToWorld( pOldParent );
return;
}
m_iParent = m_pParent->m_iName;
RemoveSolidFlags( FSOLID_ROOT_PARENT_ALIGNED );
if ( pParentEntity )
{
if ( const_cast<CBaseEntity *>(pParentEntity)->GetRootMoveParent()->GetSolid() == SOLID_BSP )
{
AddSolidFlags( FSOLID_ROOT_PARENT_ALIGNED );
}
else
{
if ( GetSolid() == SOLID_BSP )
{
// Must be SOLID_VPHYSICS because parent might rotate
SetSolid( SOLID_VPHYSICS );
}
}
}
// set the move parent if we have one
if ( edict() )
{
// add ourselves to the list
LinkChild( m_pParent, this );
m_iParentAttachment = (char)iAttachment;
EntityMatrix matrix, childMatrix;
matrix.InitFromEntity( const_cast<CBaseEntity *>(pParentEntity), m_iParentAttachment ); // parent->world
childMatrix.InitFromEntityLocal( this ); // child->world
Vector localOrigin = matrix.WorldToLocal( GetLocalOrigin() );
// I have the axes of local space in world space. (childMatrix)
// I want to compute those world space axes in the parent's local space
// and set that transform (as angles) on the child's object so the net
// result is that the child is now in parent space, but still oriented the same way
VMatrix tmp = matrix.Transpose(); // world->parent
tmp.MatrixMul( childMatrix, matrix ); // child->parent
QAngle angles;
MatrixToAngles( matrix, angles );
SetLocalAngles( angles );
UTIL_SetOrigin( this, localOrigin );
// Move our step data into the correct space
if ( bWasNotParented )
{
// Transform step data from world to parent-space
TransformStepData_WorldToParent( this );
}
else
{
// Transform step data between parent-spaces
TransformStepData_ParentToParent( pOldParent, this );
}
}
if ( VPhysicsGetObject() )
{
if ( VPhysicsGetObject()->IsStatic())
{
if ( VPhysicsGetObject()->IsAttachedToConstraint(false) )
{
Warning("SetParent on static object, all constraints attached to %s (%s)will now be broken!\n", GetDebugName(), GetClassname() );
}
VPhysicsDestroyObject();
VPhysicsInitShadow(false, false);
}
}
CollisionRulesChanged();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseEntity::ValidateEntityConnections()
{
if ( m_target == NULL_STRING )
return;
if ( ClassMatches( "scripted_*" ) ||
ClassMatches( "trigger_relay" ) ||
ClassMatches( "trigger_auto" ) ||
ClassMatches( "path_*" ) ||
ClassMatches( "monster_*" ) ||
ClassMatches( "trigger_teleport" ) ||
ClassMatches( "func_train" ) ||
ClassMatches( "func_tracktrain" ) ||
ClassMatches( "func_plat*" ) ||
ClassMatches( "npc_*" ) ||
ClassMatches( "info_big*" ) ||
ClassMatches( "env_texturetoggle" ) ||
ClassMatches( "env_render" ) ||
ClassMatches( "func_areaportalwindow") ||
ClassMatches( "point_view*") ||
ClassMatches( "func_traincontrols" ) ||
ClassMatches( "multisource" ) ||
ClassMatches( "xen_plant*" ) )
return;
datamap_t *dmap = GetDataDescMap();
while ( dmap )
{
int fields = dmap->dataNumFields;
for ( int i = 0; i < fields; i++ )
{
typedescription_t *dataDesc = &dmap->dataDesc[i];
if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) )
{
CBaseEntityOutput *pOutput = (CBaseEntityOutput *)((int)this + (int)dataDesc->fieldOffset[0]);
if ( pOutput->NumberOfElements() )
return;
}
}
dmap = dmap->baseMap;
}
Vector vecLoc = WorldSpaceCenter();
Warning("---------------------------------\n");
Warning( "Entity %s - (%s) has a target and NO OUTPUTS\n", GetDebugName(), GetClassname() );
Warning( "Location %f %f %f\n", vecLoc.x, vecLoc.y, vecLoc.z );
Warning("---------------------------------\n");
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseEntity::FireNamedOutput( const char *pszOutput, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller, float flDelay )
{
if ( pszOutput == NULL )
return;
CBaseEntityOutput *pOutput = FindNamedOutput( pszOutput );
if ( pOutput )
{
pOutput->FireOutput( variant, pActivator, pCaller, flDelay );
return;
}
}
CBaseEntityOutput *CBaseEntity::FindNamedOutput( const char *pszOutput )
{
if ( pszOutput == NULL )
return NULL;
2013-12-02 19:31:46 -08:00
datamap_t *dmap = GetDataDescMap();
while ( dmap )
{
int fields = dmap->dataNumFields;
for ( int i = 0; i < fields; i++ )
{
typedescription_t *dataDesc = &dmap->dataDesc[i];
if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) )
{
CBaseEntityOutput *pOutput = ( CBaseEntityOutput * )( ( int )this + ( int )dataDesc->fieldOffset[0] );
2013-12-02 19:31:46 -08:00
if ( !Q_stricmp( dataDesc->externalName, pszOutput ) )
{
return pOutput;
2013-12-02 19:31:46 -08:00
}
}
}
dmap = dmap->baseMap;
}
return NULL;
2013-12-02 19:31:46 -08:00
}
void CBaseEntity::Activate( void )
{
#ifdef DEBUG
extern bool g_bCheckForChainedActivate;
extern bool g_bReceivedChainedActivate;
if ( g_bCheckForChainedActivate && g_bReceivedChainedActivate )
{
Assert( !"Multiple calls to base class Activate()\n" );
}
g_bReceivedChainedActivate = true;
#endif
// NOTE: This forces a team change so that stuff in the level
// that starts out on a team correctly changes team
if (m_iInitialTeamNum)
{
ChangeTeam( m_iInitialTeamNum );
}
// Get a handle to my damage filter entity if there is one.
if ( m_iszDamageFilterName != NULL_STRING )
{
m_hDamageFilter = gEntList.FindEntityByName( NULL, m_iszDamageFilterName );
}
// Add any non-null context strings to our context vector
if ( m_iszResponseContext != NULL_STRING )
{
AddContext( m_iszResponseContext.ToCStr() );
}
#ifdef HL1_DLL
ValidateEntityConnections();
#endif //HL1_DLL
}
//////////////////////////// old CBaseEntity stuff ///////////////////////////////////
// give health.
// Returns the amount of health actually taken.
int CBaseEntity::TakeHealth( float flHealth, int bitsDamageType )
{
if ( !edict() || m_takedamage < DAMAGE_YES )
return 0;
int iMax = GetMaxHealth();
// heal
if ( m_iHealth >= iMax )
return 0;
const int oldHealth = m_iHealth;
m_iHealth += flHealth;
if (m_iHealth > iMax)
m_iHealth = iMax;
return m_iHealth - oldHealth;
}
// inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH
int CBaseEntity::OnTakeDamage( const CTakeDamageInfo &info )
{
Vector vecTemp;
if ( !edict() || !m_takedamage )
return 0;
if ( info.GetInflictor() )
{
vecTemp = info.GetInflictor()->WorldSpaceCenter() - ( WorldSpaceCenter() );
}
else
{
vecTemp.Init( 1, 0, 0 );
}
// this global is still used for glass and other non-NPC killables, along with decals.
g_vecAttackDir = vecTemp;
VectorNormalize(g_vecAttackDir);
// save damage based on the target's armor level
// figure momentum add (don't let hurt brushes or other triggers move player)
// physics objects have their own calcs for this: (don't let fire move things around!)
if ( !IsEFlagSet( EFL_NO_DAMAGE_FORCES ) )
{
if ( ( GetMoveType() == MOVETYPE_VPHYSICS ) )
{
VPhysicsTakeDamage( info );
}
else
{
if ( info.GetInflictor() && (GetMoveType() == MOVETYPE_WALK || GetMoveType() == MOVETYPE_STEP) &&
!info.GetAttacker()->IsSolidFlagSet(FSOLID_TRIGGER) )
{
Vector vecDir, vecInflictorCentroid;
vecDir = WorldSpaceCenter( );
vecInflictorCentroid = info.GetInflictor()->WorldSpaceCenter( );
vecDir -= vecInflictorCentroid;
VectorNormalize( vecDir );
float flForce = info.GetDamage() * ((32 * 32 * 72.0) / (WorldAlignSize().x * WorldAlignSize().y * WorldAlignSize().z)) * 5;
if (flForce > 1000.0)
flForce = 1000.0;
ApplyAbsVelocityImpulse( vecDir * flForce );
}
}
}
if ( m_takedamage != DAMAGE_EVENTS_ONLY )
{
// do the damage
m_iHealth -= info.GetDamage();
if (m_iHealth <= 0)
{
Event_Killed( info );
return 0;
}
}
return 1;
}
//-----------------------------------------------------------------------------
// Purpose: Scale damage done and call OnTakeDamage
//-----------------------------------------------------------------------------
void CBaseEntity::TakeDamage( const CTakeDamageInfo &inputInfo )
{
if ( !g_pGameRules )
return;
bool bHasPhysicsForceDamage = !g_pGameRules->Damage_NoPhysicsForce( inputInfo.GetDamageType() );
if ( bHasPhysicsForceDamage && inputInfo.GetDamageType() != DMG_GENERIC )
{
// If you hit this assert, you've called TakeDamage with a damage type that requires a physics damage
// force & position without specifying one or both of them. Decide whether your damage that's causing
// this is something you believe should impart physics force on the receiver. If it is, you need to
// setup the damage force & position inside the CTakeDamageInfo (Utility functions for this are in
// takedamageinfo.cpp. If you think the damage shouldn't cause force (unlikely!) then you can set the
// damage type to DMG_GENERIC, or | DMG_CRUSH if you need to preserve the damage type for purposes of HUD display.
if ( inputInfo.GetDamageForce() == vec3_origin || inputInfo.GetDamagePosition() == vec3_origin )
{
static int warningCount = 0;
if ( ++warningCount < 10 )
{
if ( inputInfo.GetDamageForce() == vec3_origin )
{
DevWarning( "CBaseEntity::TakeDamage: with inputInfo.GetDamageForce() == vec3_origin\n" );
}
if ( inputInfo.GetDamagePosition() == vec3_origin )
{
DevWarning( "CBaseEntity::TakeDamage: with inputInfo.GetDamagePosition() == vec3_origin\n" );
}
}
}
}
#ifndef MAPBASE // Moved below the gamerules AllowDamage() check
2013-12-02 19:31:46 -08:00
// Make sure our damage filter allows the damage.
if ( !PassesDamageFilter( inputInfo ))
{
return;
}
#endif
2013-12-02 19:31:46 -08:00
if( !g_pGameRules->AllowDamage(this, inputInfo) )
{
return;
}
#ifdef MAPBASE
// Make sure our damage filter allows the damage.
if ( !PassesFinalDamageFilter( inputInfo ))
{
return;
}
#endif
2013-12-02 19:31:46 -08:00
if ( PhysIsInCallback() )
{
PhysCallbackDamage( this, inputInfo );
}
else
{
CTakeDamageInfo info = inputInfo;
// Scale the damage by the attacker's modifier.
if ( info.GetAttacker() )
{
info.ScaleDamage( info.GetAttacker()->GetAttackDamageScale( this ) );
}
// Scale the damage by my own modifiers
info.ScaleDamage( GetReceivedDamageScale( info.GetAttacker() ) );
//Msg("%s took %.2f Damage, at %.2f\n", GetClassname(), info.GetDamage(), gpGlobals->curtime );
#ifdef MAPBASE
// Modify damage if we have a filter that does that
DamageFilterDamageMod(info);
#endif
2013-12-02 19:31:46 -08:00
OnTakeDamage( info );
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns a value that scales all damage done by this entity.
//-----------------------------------------------------------------------------
float CBaseEntity::GetAttackDamageScale( CBaseEntity *pVictim )
{
float flScale = 1;
FOR_EACH_LL( m_DamageModifiers, i )
{
if ( !m_DamageModifiers[i]->IsDamageDoneToMe() )
{
flScale *= m_DamageModifiers[i]->GetModifier();
}
}
return flScale;
}
//-----------------------------------------------------------------------------
// Purpose: Returns a value that scales all damage done to this entity
//-----------------------------------------------------------------------------
float CBaseEntity::GetReceivedDamageScale( CBaseEntity *pAttacker )
{
float flScale = 1;
FOR_EACH_LL( m_DamageModifiers, i )
{
if ( m_DamageModifiers[i]->IsDamageDoneToMe() )
{
flScale *= m_DamageModifiers[i]->GetModifier();
}
}
return flScale;
}
//-----------------------------------------------------------------------------
// Purpose: Applies forces to our physics object in response to damage.
//-----------------------------------------------------------------------------
int CBaseEntity::VPhysicsTakeDamage( const CTakeDamageInfo &info )
{
// don't let physics impacts or fire cause objects to move (again)
bool bNoPhysicsForceDamage = g_pGameRules->Damage_NoPhysicsForce( info.GetDamageType() );
if ( bNoPhysicsForceDamage || info.GetDamageType() == DMG_GENERIC )
return 1;
Assert(VPhysicsGetObject() != NULL);
if ( VPhysicsGetObject() )
{
Vector force = info.GetDamageForce();
Vector offset = info.GetDamagePosition();
// If you hit this assert, you've called TakeDamage with a damage type that requires a physics damage
// force & position without specifying one or both of them. Decide whether your damage that's causing
// this is something you believe should impart physics force on the receiver. If it is, you need to
// setup the damage force & position inside the CTakeDamageInfo (Utility functions for this are in
// takedamageinfo.cpp. If you think the damage shouldn't cause force (unlikely!) then you can set the
// damage type to DMG_GENERIC, or | DMG_CRUSH if you need to preserve the damage type for purposes of HUD display.
#if !defined( TF_DLL )
Assert( force != vec3_origin && offset != vec3_origin );
#else
// this was spamming the console for Payload maps in TF (trigger_hurt entity on the front of the cart)
if ( !TFGameRules() || TFGameRules()->GetGameType() != TF_GAMETYPE_ESCORT )
{
Assert( force != vec3_origin && offset != vec3_origin );
}
#endif
unsigned short gameFlags = VPhysicsGetObject()->GetGameFlags();
if ( gameFlags & FVPHYSICS_PLAYER_HELD )
{
// if the player is holding the object, use it's real mass (player holding reduced the mass)
Mapbase v4.3 - Fixed a crash with multiple trigger_look targets - Fixed an issue where some zombie submodel server ragdolls are not solid to the world - Fixed a crash with certain instance classes being loaded in a savegame before the class is registered - Added some of Tony Sergi's missing Source 2007 fixes (contributed by Kris) - Added "ClientCommand" hook for VScript to allow handling of unknown console commands - Added "PlayerRunCommand" hook for VScript to control player movement - Added new button-related script functions for players (GetButtons, DisableButtons, etc.) - Added CUserCmd accessor in VScript for the "PlayerRunCommand" hook - Added "GetWaterLevel" function for VScript - Exposed "Ignite" to VScript for controlling how a fire starts - Fixed NPCs being unable to unholster weapons - Fixed Mapbase crashing when Steam isn't running - Fixed issues with angled/updating sky_camera save/restore - Added VBSP "-skyboxcubemap" parameter to enable skybox default cubemaps + "-defaultcubemapres" to control their resolution - Added ability to disable VScript in a map (and fixed a few potential complications from disabling VScript) - Made clientside VScript only initialize after world is spawned in order to receive serverside script language in time - Added tons of VScript functions to CBaseAnimating related to bodygroups, sequences, etc. - Added VScript functions to players for getting user ID and player name, similar to logic_playerinfo - Added a few L4D2 script functions missing from the ASW SDK - Added "Localize" singleton with a single "GetTokenAsUTF8" function for getting localization strings - Disabled r_hunkalloclightmaps by the request of various users (apparently this completely removes the "Engine hunk overflow" error and allows for really high-res lightmaps) - Fixed npc_antlionguard NPC_TranslateActivity not hooking into base class (allows for VScript manipulation) - Added various unused antlion guard activities to npc_antlionguard AI, allowing for usage as registered activities - Added keyvalue to set LOS mask on combine_mine - Added +USE bounding box limiter to prop_interactable
2020-07-16 15:43:30 +00:00
CBasePlayer *pPlayer = NULL;
if ( AI_IsSinglePlayer() )
{
pPlayer = UTIL_GetLocalPlayer();
}
else
{
// See which MP player is holding the physics object and then use that player to get the real mass of the object.
// This is ugly but better than having linkage between an object and its "holding" player.
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *tempPlayer = UTIL_PlayerByIndex( i );
if ( tempPlayer && (tempPlayer->GetHeldObject() == this ) )
{
pPlayer = tempPlayer;
break;
}
}
}
2013-12-02 19:31:46 -08:00
if ( pPlayer )
{
float mass = pPlayer->GetHeldObjectMass( VPhysicsGetObject() );
if ( mass != 0.0f )
{
float ratio = VPhysicsGetObject()->GetMass() / mass;
force *= ratio;
}
}
}
else if ( (gameFlags & FVPHYSICS_PART_OF_RAGDOLL) && (gameFlags & FVPHYSICS_CONSTRAINT_STATIC) )
{
IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
int count = VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
for ( int i = 0; i < count; i++ )
{
if ( !(pList[i]->GetGameFlags() & FVPHYSICS_CONSTRAINT_STATIC) )
{
pList[i]->ApplyForceOffset( force, offset );
return 1;
}
}
}
VPhysicsGetObject()->ApplyForceOffset( force, offset );
}
return 1;
}
// Character killed (only fired once)
void CBaseEntity::Event_Killed( const CTakeDamageInfo &info )
{
if( info.GetAttacker() )
{
info.GetAttacker()->Event_KilledOther(this, info);
}
m_takedamage = DAMAGE_NO;
m_lifeState = LIFE_DEAD;
UTIL_Remove( this );
}
//-----------------------------------------------------------------------------
// Purpose: helper method to send a game event when this entity is killed. Note:
// gets called specifically for particular entities (mostly NPC), this
// does not get called for every entity
//-----------------------------------------------------------------------------
void CBaseEntity::SendOnKilledGameEvent( const CTakeDamageInfo &info )
{
IGameEvent *event = gameeventmanager->CreateEvent( "entity_killed" );
if ( event )
{
event->SetInt( "entindex_killed", entindex() );
if ( info.GetAttacker())
{
event->SetInt( "entindex_attacker", info.GetAttacker()->entindex() );
}
if ( info.GetInflictor())
{
event->SetInt( "entindex_inflictor", info.GetInflictor()->entindex() );
}
event->SetInt( "damagebits", info.GetDamageType() );
gameeventmanager->FireEvent( event );
}
}
bool CBaseEntity::HasTarget( string_t targetname )
{
if( targetname != NULL_STRING && m_target != NULL_STRING )
return FStrEq(STRING(targetname), STRING(m_target) );
else
return false;
}
CBaseEntity *CBaseEntity::GetNextTarget( void )
{
if ( !m_target )
return NULL;
return gEntList.FindEntityByName( NULL, m_target );
}
class CThinkContextsSaveDataOps : public CDefSaveRestoreOps
{
virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
{
AssertMsg( fieldInfo.pTypeDesc->fieldSize == 1, "CThinkContextsSaveDataOps does not support arrays");
// Write out the vector
CUtlVector< thinkfunc_t > *pUtlVector = (CUtlVector< thinkfunc_t > *)fieldInfo.pField;
SaveUtlVector( pSave, pUtlVector, FIELD_EMBEDDED );
// Get our owner
CBaseEntity *pOwner = (CBaseEntity*)fieldInfo.pOwner;
pSave->StartBlock();
// Now write out all the functions
for ( int i = 0; i < pUtlVector->Size(); i++ )
{
#ifdef WIN32
void **ppV = (void**)&((*pUtlVector)[i].m_pfnThink);
#else
BASEPTR *ppV = &((*pUtlVector)[i].m_pfnThink);
#endif
bool bHasFunc = (*ppV != NULL);
pSave->WriteBool( &bHasFunc, 1 );
if ( bHasFunc )
{
pSave->WriteFunction( pOwner->GetDataDescMap(), "m_pfnThink", (inputfunc_t **)ppV, 1 );
}
}
pSave->EndBlock();
}
virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
{
AssertMsg( fieldInfo.pTypeDesc->fieldSize == 1, "CThinkContextsSaveDataOps does not support arrays");
// Read in the vector
CUtlVector< thinkfunc_t > *pUtlVector = (CUtlVector< thinkfunc_t > *)fieldInfo.pField;
RestoreUtlVector( pRestore, pUtlVector, FIELD_EMBEDDED );
// Get our owner
CBaseEntity *pOwner = (CBaseEntity*)fieldInfo.pOwner;
pRestore->StartBlock();
// Now read in all the functions
for ( int i = 0; i < pUtlVector->Size(); i++ )
{
bool bHasFunc;
pRestore->ReadBool( &bHasFunc, 1 );
#ifdef WIN32
void **ppV = (void**)&((*pUtlVector)[i].m_pfnThink);
#else
BASEPTR *ppV = &((*pUtlVector)[i].m_pfnThink);
Q_memset( (void *)ppV, 0x0, sizeof(inputfunc_t) );
#endif
if ( bHasFunc )
{
SaveRestoreRecordHeader_t header;
pRestore->ReadHeader( &header );
pRestore->ReadFunction( pOwner->GetDataDescMap(), (inputfunc_t **)ppV, 1, header.size );
}
else
{
*ppV = NULL;
}
}
pRestore->EndBlock();
}
virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
{
CUtlVector< thinkfunc_t > *pUtlVector = (CUtlVector< thinkfunc_t > *)fieldInfo.pField;
return ( pUtlVector->Count() == 0 );
}
virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
{
BASEPTR pFunc = *((BASEPTR*)fieldInfo.pField);
pFunc = NULL;
}
};
CThinkContextsSaveDataOps g_ThinkContextsSaveDataOps;
ISaveRestoreOps *thinkcontextFuncs = &g_ThinkContextsSaveDataOps;
BEGIN_SIMPLE_DATADESC( thinkfunc_t )
DEFINE_FIELD( m_iszContext, FIELD_STRING ),
// DEFINE_FIELD( m_pfnThink, FIELD_FUNCTION ), // Manually written
DEFINE_FIELD( m_nNextThinkTick, FIELD_TICK ),
DEFINE_FIELD( m_nLastThinkTick, FIELD_TICK ),
END_DATADESC()
BEGIN_SIMPLE_DATADESC( ResponseContext_t )
DEFINE_FIELD( m_iszName, FIELD_STRING ),
DEFINE_FIELD( m_iszValue, FIELD_STRING ),
DEFINE_FIELD( m_fExpirationTime, FIELD_TIME ),
END_DATADESC()
BEGIN_DATADESC_NO_BASE( CBaseEntity )
DEFINE_KEYFIELD( m_iClassname, FIELD_STRING, "classname" ),
DEFINE_GLOBAL_KEYFIELD( m_iGlobalname, FIELD_STRING, "globalname" ),
DEFINE_KEYFIELD( m_iParent, FIELD_STRING, "parentname" ),
DEFINE_KEYFIELD( m_iHammerID, FIELD_INTEGER, "hammerid" ), // save ID numbers so that entities can be tracked between save/restore and vmf
DEFINE_KEYFIELD( m_flSpeed, FIELD_FLOAT, "speed" ),
DEFINE_KEYFIELD( m_nRenderFX, FIELD_CHARACTER, "renderfx" ),
DEFINE_KEYFIELD( m_nRenderMode, FIELD_CHARACTER, "rendermode" ),
// Consider moving to CBaseAnimating?
DEFINE_FIELD( m_flPrevAnimTime, FIELD_TIME ),
DEFINE_FIELD( m_flAnimTime, FIELD_TIME ),
DEFINE_FIELD( m_flSimulationTime, FIELD_TIME ),
DEFINE_FIELD( m_nLastThinkTick, FIELD_TICK ),
DEFINE_FIELD(m_iszScriptId, FIELD_STRING),
// m_ScriptScope;
// m_hScriptInstance;
DEFINE_KEYFIELD(m_iszVScripts, FIELD_STRING, "vscripts"),
DEFINE_KEYFIELD(m_iszScriptThinkFunction, FIELD_STRING, "thinkfunction"),
2013-12-02 19:31:46 -08:00
DEFINE_KEYFIELD( m_nNextThinkTick, FIELD_TICK, "nextthink" ),
DEFINE_KEYFIELD( m_fEffects, FIELD_INTEGER, "effects" ),
DEFINE_KEYFIELD( m_clrRender, FIELD_COLOR32, "rendercolor" ),
DEFINE_GLOBAL_KEYFIELD( m_nModelIndex, FIELD_SHORT, "modelindex" ),
Merged dev changes 9/28/2019 - Experimental RPC stuff for the future - Fixed players running over allies with vehicles (kind of) - Modified redirect filter infrastructure to support when there's no target filter (meaning it will just make sure the entity exists) - Fixed SDK_EyeRefract - Fixed env_beam SetStart/EndEntity - New "OnStateChange" output on NPCs - scripted_face removed (use generic facing VCDs instead) - Fixed RPC - View ID nodraw keyvalue + reflective glass view ID fix - CopyAnimationDataFrom expansion (more variables copied) - Fixed pre-Mapbase env_projectedtextures not updating after loading a save - Fixed(?) player companion grenade throwing being interrupted - Added convars for secondary and NPC shotgun pellet amounts - NPC fade distance/scale transfers to its ragdoll - Made node graph rebuild occur sooner after map load - Added option to disable "node graph out of date" message - Fixed ent_fire delay (decimals discarded before) - "SetFilter" on func_clip_vphysics - Fixed func_tank zero barrel (untested) - Fixed npc_turret_ground parenting fix - Added toggle-able weapon_crossbow experimental hit location code - Fixed ally grenades being considered Combine grenades - Added SDK_MonitorScreen and SDK_UnlitTwoTexture - Updated README - Added !activator/!caller support to logic_collision_pair - Fixed ortho not working in script_intro - Added Nbc66's closed captioning language fix - Applied fade fix to server ragdolls - Added combine_mine friend/foe filters - Fixed env_starfield pausing - Reworked PickupWeapon/Item inputs - Fixed context response system $ usage - Fixed env_break_shooter velocity/speed - Made func_breakable "Spawn on break" support other entities - Fixed OnThrowGrenade > point_entity_replace blip - Added mapname to logic_externaldata - Added "Random Template" to point_template - Added "Use LOS" to trigger_look - Added flags based on L4D(2) to trigger_playermovement - Added npc_combine_s "Alternate Capable" keyvalue that enables both grenades and alt-fire at the same time regardless of elite status - Fixed npc_combine_s DropGrenade input - Miscellaneous code and comment changes
2019-09-28 22:56:52 +00:00
#ifdef MAPBASE
DEFINE_KEYFIELD( m_iViewHideFlags, FIELD_INTEGER, "viewhideflags" ),
#endif
2013-12-02 19:31:46 -08:00
#if !defined( NO_ENTITY_PREDICTION )
// DEFINE_FIELD( m_PredictableID, CPredictableId ),
#endif
DEFINE_FIELD( touchStamp, FIELD_INTEGER ),
DEFINE_CUSTOM_FIELD( m_aThinkFunctions, thinkcontextFuncs ),
// m_iCurrentThinkContext (not saved, debug field only, and think transient to boot)
DEFINE_UTLVECTOR(m_ResponseContexts, FIELD_EMBEDDED),
DEFINE_KEYFIELD( m_iszResponseContext, FIELD_STRING, "ResponseContext" ),
DEFINE_FIELD( m_pfnThink, FIELD_FUNCTION ),
DEFINE_FIELD( m_pfnTouch, FIELD_FUNCTION ),
DEFINE_FIELD( m_pfnUse, FIELD_FUNCTION ),
DEFINE_FIELD( m_pfnBlocked, FIELD_FUNCTION ),
DEFINE_FIELD( m_pfnMoveDone, FIELD_FUNCTION ),
DEFINE_FIELD( m_lifeState, FIELD_CHARACTER ),
DEFINE_FIELD( m_takedamage, FIELD_CHARACTER ),
DEFINE_KEYFIELD( m_iMaxHealth, FIELD_INTEGER, "max_health" ),
DEFINE_KEYFIELD( m_iHealth, FIELD_INTEGER, "health" ),
// DEFINE_FIELD( m_pLink, FIELD_CLASSPTR ),
DEFINE_KEYFIELD( m_target, FIELD_STRING, "target" ),
DEFINE_KEYFIELD( m_iszDamageFilterName, FIELD_STRING, "damagefilter" ),
DEFINE_FIELD( m_hDamageFilter, FIELD_EHANDLE ),
DEFINE_FIELD( m_debugOverlays, FIELD_INTEGER ),
DEFINE_GLOBAL_FIELD( m_pParent, FIELD_EHANDLE ),
DEFINE_FIELD( m_iParentAttachment, FIELD_CHARACTER ),
DEFINE_GLOBAL_FIELD( m_hMoveParent, FIELD_EHANDLE ),
DEFINE_GLOBAL_FIELD( m_hMoveChild, FIELD_EHANDLE ),
DEFINE_GLOBAL_FIELD( m_hMovePeer, FIELD_EHANDLE ),
DEFINE_FIELD( m_iEFlags, FIELD_INTEGER ),
DEFINE_FIELD( m_iName, FIELD_STRING ),
DEFINE_EMBEDDED( m_Collision ),
DEFINE_EMBEDDED( m_Network ),
DEFINE_FIELD( m_MoveType, FIELD_CHARACTER ),
DEFINE_FIELD( m_MoveCollide, FIELD_CHARACTER ),
#ifdef MAPBASE
DEFINE_KEYFIELD( m_hOwnerEntity, FIELD_EHANDLE, "OwnerEntity" ),
#else
2013-12-02 19:31:46 -08:00
DEFINE_FIELD( m_hOwnerEntity, FIELD_EHANDLE ),
#endif
2013-12-02 19:31:46 -08:00
DEFINE_FIELD( m_CollisionGroup, FIELD_INTEGER ),
DEFINE_PHYSPTR( m_pPhysicsObject),
DEFINE_FIELD( m_flElasticity, FIELD_FLOAT ),
DEFINE_KEYFIELD( m_flShadowCastDistance, FIELD_FLOAT, "shadowcastdist" ),
DEFINE_FIELD( m_flDesiredShadowCastDistance, FIELD_FLOAT ),
DEFINE_INPUT( m_iInitialTeamNum, FIELD_INTEGER, "TeamNum" ),
DEFINE_FIELD( m_iTeamNum, FIELD_INTEGER ),
// DEFINE_FIELD( m_bSentLastFrame, FIELD_INTEGER ),
DEFINE_FIELD( m_hGroundEntity, FIELD_EHANDLE ),
DEFINE_FIELD( m_flGroundChangeTime, FIELD_TIME ),
DEFINE_GLOBAL_KEYFIELD( m_ModelName, FIELD_MODELNAME, "model" ),
DEFINE_KEYFIELD( m_vecBaseVelocity, FIELD_VECTOR, "basevelocity" ),
DEFINE_FIELD( m_vecAbsVelocity, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_vecAngVelocity, FIELD_VECTOR, "avelocity" ),
// DEFINE_FIELD( m_vecAbsAngVelocity, FIELD_VECTOR ),
DEFINE_ARRAY( m_rgflCoordinateFrame, FIELD_FLOAT, 12 ), // NOTE: MUST BE IN LOCAL SPACE, NOT POSITION_VECTOR!!! (see CBaseEntity::Restore)
DEFINE_KEYFIELD( m_nWaterLevel, FIELD_CHARACTER, "waterlevel" ),
DEFINE_FIELD( m_nWaterType, FIELD_CHARACTER ),
DEFINE_FIELD( m_pBlocker, FIELD_EHANDLE ),
DEFINE_KEYFIELD( m_flGravity, FIELD_FLOAT, "gravity" ),
DEFINE_KEYFIELD( m_flFriction, FIELD_FLOAT, "friction" ),
// Local time is local to each object. It doesn't need to be re-based if the clock
// changes. Therefore it is saved as a FIELD_FLOAT, not a FIELD_TIME
DEFINE_KEYFIELD( m_flLocalTime, FIELD_FLOAT, "ltime" ),
DEFINE_FIELD( m_flVPhysicsUpdateLocalTime, FIELD_FLOAT ),
DEFINE_FIELD( m_flMoveDoneTime, FIELD_FLOAT ),
// DEFINE_FIELD( m_nPushEnumCount, FIELD_INTEGER ),
DEFINE_FIELD( m_vecAbsOrigin, FIELD_POSITION_VECTOR ),
DEFINE_KEYFIELD( m_vecVelocity, FIELD_VECTOR, "velocity" ),
DEFINE_KEYFIELD( m_iTextureFrameIndex, FIELD_CHARACTER, "texframeindex" ),
DEFINE_FIELD( m_bSimulatedEveryTick, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bAnimatedEveryTick, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bAlternateSorting, FIELD_BOOLEAN ),
DEFINE_KEYFIELD( m_spawnflags, FIELD_INTEGER, "spawnflags" ),
DEFINE_FIELD( m_nTransmitStateOwnedCounter, FIELD_CHARACTER ),
DEFINE_FIELD( m_angAbsRotation, FIELD_VECTOR ),
DEFINE_FIELD( m_vecOrigin, FIELD_VECTOR ), // NOTE: MUST BE IN LOCAL SPACE, NOT POSITION_VECTOR!!! (see CBaseEntity::Restore)
DEFINE_FIELD( m_angRotation, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_vecViewOffset, FIELD_VECTOR, "view_ofs" ),
#ifdef MAPBASE
// You know, m_fFlags access
DEFINE_KEYFIELD( m_fFlags, FIELD_INTEGER, "m_fFlags" ),
#else
2013-12-02 19:31:46 -08:00
DEFINE_FIELD( m_fFlags, FIELD_INTEGER ),
#endif
2013-12-02 19:31:46 -08:00
#if !defined( NO_ENTITY_PREDICTION )
// DEFINE_FIELD( m_bIsPlayerSimulated, FIELD_INTEGER ),
// DEFINE_FIELD( m_hPlayerSimulationOwner, FIELD_EHANDLE ),
#endif
// DEFINE_FIELD( m_pTimedOverlay, TimedOverlay_t* ),
DEFINE_FIELD( m_nSimulationTick, FIELD_TICK ),
// DEFINE_FIELD( m_RefEHandle, CBaseHandle ),
// DEFINE_FIELD( m_nWaterTouch, FIELD_INTEGER ),
// DEFINE_FIELD( m_nSlimeTouch, FIELD_INTEGER ),
DEFINE_FIELD( m_flNavIgnoreUntilTime, FIELD_TIME ),
// DEFINE_FIELD( m_bToolRecording, FIELD_BOOLEAN ),
// DEFINE_FIELD( m_ToolHandle, FIELD_INTEGER ),
// NOTE: This is tricky. TeamNum must be saved, but we can't directly
// read it in, because we can only set it after the team entity has been read in,
// which may or may not actually occur before the entity is parsed.
// Therefore, we set the TeamNum from the InitialTeamNum in Activate
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetTeam", InputSetTeam ),
DEFINE_INPUTFUNC( FIELD_VOID, "Kill", InputKill ),
DEFINE_INPUTFUNC( FIELD_VOID, "KillHierarchy", InputKillHierarchy ),
DEFINE_INPUTFUNC( FIELD_VOID, "Use", InputUse ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "Alpha", InputAlpha ),
DEFINE_INPUTFUNC( FIELD_BOOLEAN, "AlternativeSorting", InputAlternativeSorting ),
DEFINE_INPUTFUNC( FIELD_COLOR32, "Color", InputColor ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetParent", InputSetParent ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetParentAttachment", InputSetParentAttachment ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetParentAttachmentMaintainOffset", InputSetParentAttachmentMaintainOffset ),
DEFINE_INPUTFUNC( FIELD_VOID, "ClearParent", InputClearParent ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetDamageFilter", InputSetDamageFilter ),
DEFINE_INPUTFUNC( FIELD_VOID, "EnableDamageForces", InputEnableDamageForces ),
DEFINE_INPUTFUNC( FIELD_VOID, "DisableDamageForces", InputDisableDamageForces ),
DEFINE_INPUTFUNC( FIELD_STRING, "DispatchEffect", InputDispatchEffect ),
DEFINE_INPUTFUNC( FIELD_STRING, "DispatchResponse", InputDispatchResponse ),
// Entity I/O methods to alter context
DEFINE_INPUTFUNC( FIELD_STRING, "AddContext", InputAddContext ),
DEFINE_INPUTFUNC( FIELD_STRING, "RemoveContext", InputRemoveContext ),
DEFINE_INPUTFUNC( FIELD_STRING, "ClearContext", InputClearContext ),
DEFINE_INPUTFUNC( FIELD_VOID, "DisableShadow", InputDisableShadow ),
DEFINE_INPUTFUNC( FIELD_VOID, "EnableShadow", InputEnableShadow ),
DEFINE_INPUTFUNC( FIELD_STRING, "AddOutput", InputAddOutput ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_STRING, "ChangeVariable", InputChangeVariable ),
#endif
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_INPUT, "PassUser1", InputPassUser1 ),
DEFINE_INPUTFUNC( FIELD_INPUT, "PassUser2", InputPassUser2 ),
DEFINE_INPUTFUNC( FIELD_INPUT, "PassUser3", InputPassUser3 ),
DEFINE_INPUTFUNC( FIELD_INPUT, "PassUser4", InputPassUser4 ),
DEFINE_INPUTFUNC( FIELD_VOID, "FireUser1", InputFireUser1 ),
DEFINE_INPUTFUNC( FIELD_VOID, "FireUser2", InputFireUser2 ),
DEFINE_INPUTFUNC( FIELD_VOID, "FireUser3", InputFireUser3 ),
DEFINE_INPUTFUNC( FIELD_VOID, "FireUser4", InputFireUser4 ),
2013-12-02 19:31:46 -08:00
DEFINE_INPUTFUNC( FIELD_VOID, "FireRandomUser", InputFireRandomUser ),
DEFINE_INPUTFUNC( FIELD_INPUT, "PassRandomUser", InputPassRandomUser ),
#else
2013-12-02 19:31:46 -08:00
DEFINE_INPUTFUNC( FIELD_STRING, "FireUser1", InputFireUser1 ),
DEFINE_INPUTFUNC( FIELD_STRING, "FireUser2", InputFireUser2 ),
DEFINE_INPUTFUNC( FIELD_STRING, "FireUser3", InputFireUser3 ),
DEFINE_INPUTFUNC( FIELD_STRING, "FireUser4", InputFireUser4 ),
#endif
DEFINE_INPUTFUNC(FIELD_STRING, "RunScriptFile", InputRunScriptFile),
DEFINE_INPUTFUNC(FIELD_STRING, "RunScriptCode", InputRunScript),
DEFINE_INPUTFUNC(FIELD_STRING, "CallScriptFunction", InputCallScriptFunction),
#ifdef MAPBASE_VSCRIPT
DEFINE_INPUTFUNC(FIELD_STRING, "RunScriptCodeQuotable", InputRunScriptQuotable),
DEFINE_INPUTFUNC(FIELD_VOID, "ClearScriptScope", InputClearScriptScope),
#endif
#ifdef MAPBASE
DEFINE_OUTPUT( m_OutUser1, "OutUser1" ),
DEFINE_OUTPUT( m_OutUser2, "OutUser2" ),
DEFINE_OUTPUT( m_OutUser3, "OutUser3" ),
DEFINE_OUTPUT( m_OutUser4, "OutUser4" ),
#endif
2013-12-02 19:31:46 -08:00
DEFINE_OUTPUT( m_OnUser1, "OnUser1" ),
DEFINE_OUTPUT( m_OnUser2, "OnUser2" ),
DEFINE_OUTPUT( m_OnUser3, "OnUser3" ),
DEFINE_OUTPUT( m_OnUser4, "OnUser4" ),
#ifdef MAPBASE
Mapbase v3.0 - Overhauled matcher system and added expanded wildcard support, meaning "text", "te?t", "blah_test", etc. are now supported instead of only trailing * - Added support for regular expression matching - Added the missing matrixinvert.h file, which prevented programmers from compiling vbsp - Fixed env_global_light brightness - Added info_player_view_proxy, an entity which mimics a player's view (created for script_intro) - New UnZoomWithRate and SetZoomRate inputs on env_zoom - New "Don't change target's angles" flag on logic_measure_movement - Fixed logic_measure_movement not using ignore origin flags correctly - Fixed filter_damage_mod secondary filter not recognizing mode correctly - Fixed DisableGeigerCounter causing NPCs to ignore player, and possibly fixed other adverse effects in similar code - Added SetEntityName input for setting an entity's targetname - Added "SetTarget" support to point_posecontroller - Added "sk_alyx_health" convar for adjustable npc_alyx health, restored/fixed "sk_barney_health" for adjustable npc_barney health - Added ignore flags and several direction-related inputs to math_vector - Added pose parameter stuff to logic_modelinfo - Fixed ChangeWeapon not changing during combat - Fixed holster/unholster on NPCs without holster/unholster animations - Fixed func_tank and other "player in the way" code ignoring notarget - Added SetPoseParameter input to animating entities - Introduced an experimental chapter system which allows for custom chapter title/restriction management - Added SetChapterTitle input to worldspawn for dynamic title changing - Fixed func_tankairboatgun damage credit, added ability to use its damage keyvalues - Fixed mapbase_rpc_enabled not actually affecting RPC - Moved some newly found Combine soldier grenade code to ai_grenade for other grenade users - Fixed some problems with the new shared activities - Restored an old Mapbase entity as "prop_interactable", an entity which contains all of the functionality of a func_button/func_door in a prop entity - Added env_microphone pitch scale for scaling the pitch of transmitted sounds - Added experimental, long-overdue code for scenes to be able to access !target#'s and other scene-related names through AI_INPUT - Added "mat_specular_disable_on_missing", which "disables" specular reflections when the cubemap texture is missing - Fixed $envmapmasktransform and $bumptransform on VertexLitGeneric and related shaders - Areaportal leaks now stop compilation in leaktest - Replaced "-nodefaultcubemap" with "-defaultcubemap" as the shader changes allow maps to compile without default cubemaps by default with little effect
2020-02-05 19:08:49 +00:00
DEFINE_INPUTFUNC( FIELD_STRING, "SetEntityName", InputSetEntityName ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget", InputSetTarget ),
DEFINE_INPUTFUNC( FIELD_EHANDLE, "SetOwnerEntity", InputSetOwnerEntity ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetHealth", InputSetHealth ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "AddHealth", InputAddHealth ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "RemoveHealth", InputRemoveHealth ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxHealth", InputSetMaxHealth ),
DEFINE_INPUTFUNC( FIELD_STRING, "FireOutput", InputFireOutput ),
DEFINE_INPUTFUNC( FIELD_STRING, "RemoveOutput", InputRemoveOutput ),
//DEFINE_INPUTFUNC( FIELD_STRING, "CancelOutput", InputCancelOutput ), // Find a way to implement this
DEFINE_INPUTFUNC( FIELD_STRING, "ReplaceOutput", InputReplaceOutput ),
DEFINE_INPUTFUNC( FIELD_STRING, "AcceptInput", InputAcceptInput ),
DEFINE_INPUTFUNC( FIELD_VOID, "CancelPending", InputCancelPending ),
DEFINE_INPUTFUNC( FIELD_VOID, "FreeChildren", InputFreeChildren ),
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetLocalOrigin", InputSetLocalOrigin ),
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetLocalAngles", InputSetLocalAngles ),
Mapbase v2.0; bulk commit - Added custom map compile tools (vbsp, vvis, vrad) - Changed blink fix (shouldn't change anything in-game) - Added auto-completion to ent_create, npc_create, and the main set of "npc_" debug commands - Added ent_create_aimed, an ent_create equivalent of npc_create_aimed - Made hunters start using the "vs. player" melee animation against smaller NPCs that look weird with the "stab" attack - Added "explosion_sparks" convar, which fixes broken code for giving explosions sparks (disabled by default because of how different it looks) - Made interaction code capable of being dispatched on any entity, not just combat characters - Added npc_barnacle_ignite convar, which lets barnacles be ignited by flares - Fixed certain NPCs getting out of the way for the player when they hate them - Fixed auto-generated "speak" scene responses not using parameters that work on real VCDs - Made "stop_on_nonidle" capable of being used in any mod, not just HL2 episodic mods - Selectable color for ragdoll boogie/point_ragdollboogie - Fixed PickupWeaponInstant not firing weapon pickup outputs - Introduced inputs and keyvalues for "lerping" to math_counter_advanced - Fixed ClearConsole on logic_console - logic_convar should now detect client convars correctly - New NormalizeAngles input on math_vector - logic_modelinfo LookupActivity input - math_generate fixed and expanded to be more like math_counter - Added a WIP game logging system for playtesting maps - Introduced logic_playerinfo, an entity that can read a player's name or ID - Fixed some new filters not working with filter_multi - Added radius pickup spawnflag to func_physbox - Added "Preserve name" spawnflag to weapons - Added cc_achievement_debug message for when an achievement doesn't exist - Made npc_combine_s not speak while in logic_choreographed_scenes - Fixed zombie torsos/legs/headcrabs not being serverside when zombie is forced to server ragdoll - Expanded and cleaned up npc_zombie_custom - Fixed func_commandredirects not cleaning up correctly and sometimes crashing the game - Allowed player squad commands to go through +USE-held objects - Added a bunch of I/O/KV to trigger_waterydeath for better configuration - Changed save comment system to use the chapter title from world properties, and the ability to suppress the title popup that normally results from it - Adjusted game_convar_mod for MP planning - Removed the func_precipitation custom particle/splash code for now, as it was causing problems - Fixed env_global_light not accepting lightcolor - Added "Additional Buttons" to player_speedmod - Added save comment to RPC - Added env_projectedtexture attenuation - Added scripted_sequence OnPreIdleSequence - Added OnCrab to zombies - Added skill_changed game event (may need further testing) - Added a fix for viewmodels flipping under extreme FOV values - Added code that allows mappers to change the skin on shotgunners without it usually flipping back randomly - Fixed a very, very, very major shader performance issue - New SetAbsOrigin/Angles inputs on all entities, analogous to SetLocalOrigin/Angles - Code improvements for I/O involving angles - logic_entity_position improvements/fixes, including a new OutAngles output that outputs the angles on position calls - Alternate collision/player avoidance spawnflag obsoletion enforcement disabled - Enable/DisableHazardLights inputs on the EP2 jalopy, equivalent to the keyvalue - Miscellaneous shader formatting adjustments and fixes - Fixed AlwaysDrawOff on env_projectedtexture not being a valid input
2019-12-14 04:20:02 +00:00
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetAbsOrigin", InputSetAbsOrigin ),
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetAbsAngles", InputSetAbsAngles ),
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetLocalVelocity", InputSetLocalVelocity ),
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetLocalAngularVelocity", InputSetLocalAngularVelocity ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "AddSpawnFlags", InputAddSpawnFlags ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "RemoveSpawnFlags", InputRemoveSpawnFlags ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetRenderMode", InputSetRenderMode ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetRenderFX", InputSetRenderFX ),
Merged dev changes 9/28/2019 - Experimental RPC stuff for the future - Fixed players running over allies with vehicles (kind of) - Modified redirect filter infrastructure to support when there's no target filter (meaning it will just make sure the entity exists) - Fixed SDK_EyeRefract - Fixed env_beam SetStart/EndEntity - New "OnStateChange" output on NPCs - scripted_face removed (use generic facing VCDs instead) - Fixed RPC - View ID nodraw keyvalue + reflective glass view ID fix - CopyAnimationDataFrom expansion (more variables copied) - Fixed pre-Mapbase env_projectedtextures not updating after loading a save - Fixed(?) player companion grenade throwing being interrupted - Added convars for secondary and NPC shotgun pellet amounts - NPC fade distance/scale transfers to its ragdoll - Made node graph rebuild occur sooner after map load - Added option to disable "node graph out of date" message - Fixed ent_fire delay (decimals discarded before) - "SetFilter" on func_clip_vphysics - Fixed func_tank zero barrel (untested) - Fixed npc_turret_ground parenting fix - Added toggle-able weapon_crossbow experimental hit location code - Fixed ally grenades being considered Combine grenades - Added SDK_MonitorScreen and SDK_UnlitTwoTexture - Updated README - Added !activator/!caller support to logic_collision_pair - Fixed ortho not working in script_intro - Added Nbc66's closed captioning language fix - Applied fade fix to server ragdolls - Added combine_mine friend/foe filters - Fixed env_starfield pausing - Reworked PickupWeapon/Item inputs - Fixed context response system $ usage - Fixed env_break_shooter velocity/speed - Made func_breakable "Spawn on break" support other entities - Fixed OnThrowGrenade > point_entity_replace blip - Added mapname to logic_externaldata - Added "Random Template" to point_template - Added "Use LOS" to trigger_look - Added flags based on L4D(2) to trigger_playermovement - Added npc_combine_s "Alternate Capable" keyvalue that enables both grenades and alt-fire at the same time regardless of elite status - Fixed npc_combine_s DropGrenade input - Miscellaneous code and comment changes
2019-09-28 22:56:52 +00:00
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetViewHideFlags", InputSetViewHideFlags ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "AddEffects", InputAddEffects ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "RemoveEffects", InputRemoveEffects ),
DEFINE_INPUTFUNC( FIELD_VOID, "EnableDraw", InputDrawEntity ),
DEFINE_INPUTFUNC( FIELD_VOID, "DisableDraw", InputUndrawEntity ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "AddEFlags", InputAddEFlags ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "RemoveEFlags", InputRemoveEFlags ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "AddSolidFlags", InputAddSolidFlags ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "RemoveSolidFlags", InputRemoveSolidFlags ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMoveType", InputSetMoveType ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetCollisionGroup", InputSetCollisionGroup ),
DEFINE_INPUTFUNC( FIELD_EHANDLE, "Touch", InputTouch ),
DEFINE_INPUTFUNC( FIELD_INPUT, "KilledNPC", InputKilledNPC ),
DEFINE_INPUTFUNC( FIELD_VOID, "KillIfNotVisible", InputKillIfNotVisible ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "KillWhenNotVisible", InputKillWhenNotVisible ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetThinkNull", InputSetThinkNull ),
DEFINE_OUTPUT( m_OnKilled, "OnKilled" ),
#endif
2013-12-02 19:31:46 -08:00
// Function Pointers
DEFINE_FUNCTION( SUB_Remove ),
DEFINE_FUNCTION( SUB_DoNothing ),
DEFINE_FUNCTION( SUB_StartFadeOut ),
DEFINE_FUNCTION( SUB_StartFadeOutInstant ),
DEFINE_FUNCTION( SUB_FadeOut ),
DEFINE_FUNCTION( SUB_Vanish ),
DEFINE_FUNCTION( SUB_CallUseToggle ),
DEFINE_THINKFUNC( ShadowCastDistThink ),
DEFINE_THINKFUNC( ScriptThink ),
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
DEFINE_THINKFUNC( ScriptThinkH ),
#endif
2013-12-02 19:31:46 -08:00
#ifdef MAPBASE
DEFINE_FUNCTION( SUB_RemoveWhenNotVisible ),
#endif
2013-12-02 19:31:46 -08:00
DEFINE_FIELD( m_hEffectEntity, FIELD_EHANDLE ),
//DEFINE_FIELD( m_DamageModifiers, FIELD_?? ), // can't save?
// DEFINE_FIELD( m_fDataObjectTypes, FIELD_INTEGER ),
#ifdef TF_DLL
DEFINE_ARRAY( m_nModelIndexOverrides, FIELD_INTEGER, MAX_VISION_MODES ),
#endif
END_DATADESC()
BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" )
DEFINE_SCRIPT_INSTANCE_HELPER( &g_BaseEntityScriptInstanceHelper )
DEFINE_SCRIPTFUNC_NAMED( ConnectOutputToScript, "ConnectOutput", "Adds an I/O connection that will call the named function when the specified output fires" )
DEFINE_SCRIPTFUNC_NAMED( DisconnectOutputFromScript, "DisconnectOutput", "Removes a connected script function from an I/O event." )
DEFINE_SCRIPTFUNC( GetHealth, "" )
DEFINE_SCRIPTFUNC( SetHealth, "" )
DEFINE_SCRIPTFUNC( GetMaxHealth, "" )
DEFINE_SCRIPTFUNC( SetMaxHealth, "" )
DEFINE_SCRIPTFUNC( SetModel, "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelName, "GetModelName", "Returns the name of the model" )
DEFINE_SCRIPTFUNC_NAMED( ScriptEmitSound, "EmitSound", "Plays a sound from this entity." )
DEFINE_SCRIPTFUNC_NAMED( VScriptPrecacheScriptSound, "PrecacheSoundScript", "Precache a sound for later playing." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSoundDuration, "GetSoundDuration", "Returns float duration of the sound. Takes soundname and optional actormodelname.")
DEFINE_SCRIPTFUNC( GetClassname, "" )
DEFINE_SCRIPTFUNC_NAMED( GetEntityNameAsCStr, "GetName", "" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC( GetDebugName, "If name exists returns name, otherwise returns classname" )
DEFINE_SCRIPTFUNC_NAMED( SetNameAsCStr, "SetName", "" )
#endif
DEFINE_SCRIPTFUNC( GetPreTemplateName, "Get the entity name stripped of template unique decoration" )
DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" )
DEFINE_SCRIPTFUNC( SetAbsOrigin, "SetAbsOrigin" )
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC( SetAbsAngles, "SetAbsAngles" )
DEFINE_SCRIPTFUNC( GetLocalOrigin, "GetLocalOrigin" )
DEFINE_SCRIPTFUNC( SetLocalOrigin, "SetLocalOrigin" )
DEFINE_SCRIPTFUNC( GetLocalAngles, "GetLocalAngles" )
DEFINE_SCRIPTFUNC( SetLocalAngles, "SetLocalAngles" )
#endif
DEFINE_SCRIPTFUNC_NAMED( ScriptSetOrigin, "SetOrigin", "" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
DEFINE_SCRIPTFUNC_NAMED( ScriptSetForward, "SetForwardVector", "Set the orientation of the entity to have this forward vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRight, "GetRightVector", "Get the right vector of the entity" )
#endif
2020-09-01 20:31:22 +03:00
DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" )
#ifdef MAPBASE_VSCRIPT
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
DEFINE_SCRIPTFUNC_NAMED( ScriptSetOriginAngles, "SetOriginAngles", "Set both the origin and the angles" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetOriginAnglesVelocity, "SetOriginAnglesVelocity", "Set the origin, the angles, and the velocity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptEntityToWorldTransform, "EntityToWorldTransform", "Get the entity's transform" )
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
DEFINE_SCRIPTFUNC_NAMED( ScriptGetPhysicsObject, "GetPhysicsObject", "Get the entity's physics object if it has one" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
DEFINE_SCRIPTFUNC( ApplyAbsVelocityImpulse, "" )
DEFINE_SCRIPTFUNC( ApplyLocalAngularVelocityImpulse, "" )
#endif
DEFINE_SCRIPTFUNC_NAMED( GetAbsVelocity, "GetVelocity", "" )
DEFINE_SCRIPTFUNC_NAMED( SetAbsVelocity, "SetVelocity", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetLocalAngularVelocity, "SetAngularVelocity", "Set the local angular velocity - takes float pitch,yaw,roll velocities" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetLocalAngularVelocity, "GetAngularVelocity", "Get the local angular velocity - returns a vector of pitch,yaw,roll" )
DEFINE_SCRIPTFUNC_NAMED( WorldSpaceCenter, "GetCenter", "Get vector to center of object - absolute coords")
DEFINE_SCRIPTFUNC_NAMED( ScriptEyePosition, "EyePosition", "Get vector to eye position - absolute coords")
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptEyeAngles, "EyeAngles", "Get eye pitch, yaw, roll as a vector" )
#endif
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAngles, "SetAngles", "Set entity pitch, yaw, roll")
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector")
DEFINE_SCRIPTFUNC_NAMED( ScriptSetSize, "SetSize", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMins, "GetBoundingMins", "Get a vector containing min bounds, centered on object")
DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMaxs, "GetBoundingMaxs", "Get a vector containing max bounds, centered on object")
DEFINE_SCRIPTFUNC_NAMED( ScriptUtilRemove, "Destroy", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetOwner, "SetOwner", "" )
DEFINE_SCRIPTFUNC_NAMED( GetTeamNumber, "GetTeam", "" )
DEFINE_SCRIPTFUNC_NAMED( ChangeTeam, "SetTeam", "" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptSetParent, "SetParent", "" )
#endif
DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveParent, "GetMoveParent", "If in hierarchy, retrieves the entity's parent" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRootMoveParent, "GetRootMoveParent", "If in hierarchy, walks up the hierarchy to find the root parent" )
DEFINE_SCRIPTFUNC_NAMED( ScriptFirstMoveChild, "FirstMoveChild", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptNextMovePeer, "NextMovePeer", "" )
DEFINE_SCRIPTFUNC_NAMED( KeyValueFromString, "__KeyValueFromString", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( KeyValueFromFloat, "__KeyValueFromFloat", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( KeyValueFromInt, "__KeyValueFromInt", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( KeyValueFromVector, "__KeyValueFromVector", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelKeyValues, "GetModelKeyValues", "Get a KeyValue class instance on this entity's model")
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptIsVisible, "IsVisible", "Check if the specified position can be visible to this entity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptIsEntVisible, "IsEntVisible", "Check if the specified entity can be visible to this entity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptIsVisibleWithMask, "IsVisibleWithMask", "Check if the specified position can be visible to this entity with a specific trace mask." )
DEFINE_SCRIPTFUNC_NAMED( ScriptTakeDamage, "TakeDamage", "Apply damage to this entity with a given info handle" )
DEFINE_SCRIPTFUNC_NAMED( ScriptFireBullets, "FireBullets", "Fire bullets from entity with a given info handle" )
DEFINE_SCRIPTFUNC( TakeHealth, "Give this entity health" )
DEFINE_SCRIPTFUNC( IsAlive, "Return true if this entity is alive" )
Mapbase v4.3 - Fixed a crash with multiple trigger_look targets - Fixed an issue where some zombie submodel server ragdolls are not solid to the world - Fixed a crash with certain instance classes being loaded in a savegame before the class is registered - Added some of Tony Sergi's missing Source 2007 fixes (contributed by Kris) - Added "ClientCommand" hook for VScript to allow handling of unknown console commands - Added "PlayerRunCommand" hook for VScript to control player movement - Added new button-related script functions for players (GetButtons, DisableButtons, etc.) - Added CUserCmd accessor in VScript for the "PlayerRunCommand" hook - Added "GetWaterLevel" function for VScript - Exposed "Ignite" to VScript for controlling how a fire starts - Fixed NPCs being unable to unholster weapons - Fixed Mapbase crashing when Steam isn't running - Fixed issues with angled/updating sky_camera save/restore - Added VBSP "-skyboxcubemap" parameter to enable skybox default cubemaps + "-defaultcubemapres" to control their resolution - Added ability to disable VScript in a map (and fixed a few potential complications from disabling VScript) - Made clientside VScript only initialize after world is spawned in order to receive serverside script language in time - Added tons of VScript functions to CBaseAnimating related to bodygroups, sequences, etc. - Added VScript functions to players for getting user ID and player name, similar to logic_playerinfo - Added a few L4D2 script functions missing from the ASW SDK - Added "Localize" singleton with a single "GetTokenAsUTF8" function for getting localization strings - Disabled r_hunkalloclightmaps by the request of various users (apparently this completely removes the "Engine hunk overflow" error and allows for really high-res lightmaps) - Fixed npc_antlionguard NPC_TranslateActivity not hooking into base class (allows for VScript manipulation) - Added various unused antlion guard activities to npc_antlionguard AI, allowing for usage as registered activities - Added keyvalue to set LOS mask on combine_mine - Added +USE bounding box limiter to prop_interactable
2020-07-16 15:43:30 +00:00
DEFINE_SCRIPTFUNC( GetWaterLevel, "Get current level of water submergence" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetContext, "GetContext", "Get a response context value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddContext, "AddContext", "Add a response context value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptClassify, "Classify", "Get Class_T class ID" )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddOutput, "AddOutput", "Add an output" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValue, "GetKeyValue", "Get a keyvalue" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetRenderColorVector", "Get the render color as a vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetRenderColorR", "Get the render color's R value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetRenderColorG", "Get the render color's G value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorB, "GetRenderColorB", "Get the render color's B value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAlpha, "GetRenderAlpha", "Get the render color's alpha value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorVector, "SetRenderColorVector", "Set the render color as a vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColor, "SetRenderColor", "Set the render color" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorR, "SetRenderColorR", "Set the render color's R value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorG, "SetRenderColorG", "Set the render color's G value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetRenderColorB", "Set the render color's B value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetRenderAlpha", "Set the render color's alpha value" )
2020-09-01 20:31:22 +03:00
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetColorVector", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetColorR", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetColorG", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorB, "GetColorB", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAlpha, "GetAlpha", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorVector, "SetColorVector", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorR, "SetColorR", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorG, "SetColorG", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetColorB", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetAlpha", SCRIPT_HIDE )
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRenderMode, "GetRenderMode", "Get render mode" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetRenderMode, "SetRenderMode", "Set render mode" )
DEFINE_SCRIPTFUNC( GetSpawnFlags, "Get spawnflags" )
DEFINE_SCRIPTFUNC( AddSpawnFlags, "Add spawnflag(s)" )
DEFINE_SCRIPTFUNC( RemoveSpawnFlags, "Remove spawnflag(s)" )
DEFINE_SCRIPTFUNC( ClearSpawnFlags, "Clear spawnflag(s)" )
DEFINE_SCRIPTFUNC( HasSpawnFlags, "Check if the entity has specific spawnflag(s) ticked" )
DEFINE_SCRIPTFUNC( GetEffects, "Get effects" )
DEFINE_SCRIPTFUNC( AddEffects, "Add effect(s)" )
DEFINE_SCRIPTFUNC( RemoveEffects, "Remove effect(s)" )
DEFINE_SCRIPTFUNC( ClearEffects, "Clear effect(s)" )
DEFINE_SCRIPTFUNC( SetEffects, "Set effect(s)" )
DEFINE_SCRIPTFUNC( IsEffectActive, "Check if an effect is active" )
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
DEFINE_SCRIPTFUNC( GetEFlags, "Get Eflags" )
DEFINE_SCRIPTFUNC( AddEFlags, "Add Eflags" )
DEFINE_SCRIPTFUNC( RemoveEFlags, "Remove Eflags" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveType, "GetMoveType", "Get the move type" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetMoveType, "SetMoveType", "Set the move type" )
DEFINE_SCRIPTFUNC( GetCollisionGroup, "Get the collision group" )
DEFINE_SCRIPTFUNC( SetCollisionGroup, "Set the collision group" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
DEFINE_SCRIPTFUNC( GetGravity, "" )
DEFINE_SCRIPTFUNC( SetGravity, "" )
DEFINE_SCRIPTFUNC( GetFriction, "" )
DEFINE_SCRIPTFUNC( SetFriction, "" )
DEFINE_SCRIPTFUNC( GetMass, "" )
DEFINE_SCRIPTFUNC( SetMass, "" )
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
DEFINE_SCRIPTFUNC( GetSolidFlags, "Get solid flags" )
DEFINE_SCRIPTFUNC( AddSolidFlags, "Add solid flags" )
DEFINE_SCRIPTFUNC( RemoveSolidFlags, "Remove solid flags" )
DEFINE_SCRIPTFUNC( IsPlayer, "Returns true if this entity is a player." )
DEFINE_SCRIPTFUNC( IsNPC, "Returns true if this entity is a NPC." )
DEFINE_SCRIPTFUNC( IsCombatCharacter, "Returns true if this entity is a combat character (player or NPC)." )
DEFINE_SCRIPTFUNC_NAMED( IsBaseCombatWeapon, "IsWeapon", "Returns true if this entity is a weapon." )
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
DEFINE_SCRIPTFUNC( IsWorld, "Returns true if this entity is the world." )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
// DEFINE_SCRIPTFUNC( IsMarkedForDeletion, "Returns true if the entity is valid and marked for deletion." )
#endif
DEFINE_SCRIPTFUNC( ValidateScriptScope, "Ensure that an entity's script scope has been created" )
DEFINE_SCRIPTFUNC( GetScriptScope, "Retrieve the script-side data associated with an entity" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC( GetOrCreatePrivateScriptScope, "Create and retrieve the script-side data associated with an entity" )
#endif
DEFINE_SCRIPTFUNC( GetScriptId, "Retrieve the unique identifier used to refer to the entity within the scripting system" )
DEFINE_SCRIPTFUNC_NAMED( GetScriptOwnerEntity, "GetOwner", "Gets this entity's owner" )
DEFINE_SCRIPTFUNC_NAMED( SetScriptOwnerEntity, "SetOwner", "Sets this entity's owner" )
DEFINE_SCRIPTFUNC( entindex, "" )
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptSetThinkFunction, "SetThinkFunction", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptStopThinkFunction, "StopThinkFunction", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetThink, "SetThink", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptStopThink, "StopThink", "" )
#endif
END_SCRIPTDESC();
2013-12-02 19:31:46 -08:00
// For code error checking
extern bool g_bReceivedChainedUpdateOnRemove;
//-----------------------------------------------------------------------------
// Purpose: Called just prior to object destruction
// Entities that need to unlink themselves from other entities should do the unlinking
// here rather than in their destructor. The reason why is that when the global entity list
// is told to Clear(), it first takes a pass through all active entities and calls UTIL_Remove
// on each such entity. Then it calls the delete function on each deleted entity in the list.
// In the old code, the objects were simply destroyed in order and there was no guarantee that the
// destructor of one object would not try to access another object that might already have been
// destructed (especially since the entity list order is more or less random!).
// NOTE: You should never call delete directly on an entity (there's an assert now), see note
// at CBaseEntity::~CBaseEntity for more information.
//
// NOTE: You should chain to BaseClass::UpdateOnRemove after doing your own cleanup code, e.g.:
//
// void CDerived::UpdateOnRemove( void )
// {
// ... cleanup code
// ...
//
// BaseClass::UpdateOnRemove();
// }
//
// In general, this function updates global tables that need to know about entities being removed
//-----------------------------------------------------------------------------
void CBaseEntity::UpdateOnRemove( void )
{
g_bReceivedChainedUpdateOnRemove = true;
// Virtual call to shut down any looping sounds.
StopLoopingSounds();
// Notifies entity listeners, etc
gEntList.NotifyRemoveEntity( GetRefEHandle() );
if ( edict() )
{
AddFlag( FL_KILLME );
if ( GetFlags() & FL_GRAPHED )
{
/* <<TODO>>
// this entity was a LinkEnt in the world node graph, so we must remove it from
// the graph since we are removing it from the world.
for ( int i = 0 ; i < WorldGraph.m_cLinks ; i++ )
{
if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev )
{
// if this link has a link ent which is the same ent that is removing itself, remove it!
WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL;
}
}
*/
}
}
if ( m_iGlobalname != NULL_STRING )
{
// NOTE: During level shutdown the global list will suppress this
// it assumes your changing levels or the game will end
// causing the whole list to be flushed
GlobalEntity_SetState( m_iGlobalname, GLOBAL_DEAD );
}
VPhysicsDestroyObject();
// This is only here to allow the MOVETYPE_NONE to be set without the
// assertion triggering. Why do we bother setting the MOVETYPE to none here?
RemoveEffects( EF_BONEMERGE );
SetMoveType(MOVETYPE_NONE);
// If we have a parent, unlink from it.
UnlinkFromParent( this );
// Any children still connected are orphans, mark all for delete
CUtlVector<CBaseEntity *> childrenList;
GetAllChildren( this, childrenList );
if ( childrenList.Count() )
{
DevMsg( 2, "Warning: Deleting orphaned children of %s\n", GetClassname() );
for ( int i = childrenList.Count()-1; i >= 0; --i )
{
UTIL_Remove( childrenList[i] );
}
}
SetGroundEntity( NULL );
if ( m_bDynamicModelPending )
{
sg_DynamicLoadHandlers.Remove( this );
}
if ( IsDynamicModelIndex( m_nModelIndex ) )
{
modelinfo->ReleaseDynamicModel( m_nModelIndex ); // no-op if not dynamic
m_nModelIndex = -1;
}
if ( m_hScriptInstance )
{
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
HSCRIPT hFunc = LookupScriptFunction("UpdateOnRemove");
if ( hFunc )
{
CallScriptFunctionHandle( hFunc, NULL );
}
#endif
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// capabilities
//-----------------------------------------------------------------------------
int CBaseEntity::ObjectCaps( void )
{
#if 1
model_t *pModel = GetModel();
bool bIsBrush = ( pModel && modelinfo->GetModelType( pModel ) == mod_brush );
// We inherit our parent's use capabilities so that we can forward use commands
// to our parent.
CBaseEntity *pParent = GetParent();
if ( pParent )
{
int caps = pParent->ObjectCaps();
if ( !bIsBrush )
caps &= ( FCAP_ACROSS_TRANSITION | FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE | FCAP_DIRECTIONAL_USE );
else
caps &= ( FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE | FCAP_DIRECTIONAL_USE );
if ( pParent->IsPlayer() )
caps |= FCAP_ACROSS_TRANSITION;
return caps;
}
else if ( !bIsBrush )
{
return FCAP_ACROSS_TRANSITION;
}
return 0;
#else
// We inherit our parent's use capabilities so that we can forward use commands
// to our parent.
int parentCaps = 0;
if (GetParent())
{
parentCaps = GetParent()->ObjectCaps();
parentCaps &= ( FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE | FCAP_DIRECTIONAL_USE );
}
model_t *pModel = GetModel();
if ( pModel && modelinfo->GetModelType( pModel ) == mod_brush )
return parentCaps;
return FCAP_ACROSS_TRANSITION | parentCaps;
#endif
}
void CBaseEntity::StartTouch( CBaseEntity *pOther )
{
// notify parent
if ( m_pParent != NULL )
m_pParent->StartTouch( pOther );
}
void CBaseEntity::Touch( CBaseEntity *pOther )
{
if ( m_pfnTouch )
(this->*m_pfnTouch)( pOther );
// notify parent of touch
if ( m_pParent != NULL )
m_pParent->Touch( pOther );
}
void CBaseEntity::EndTouch( CBaseEntity *pOther )
{
// notify parent
if ( m_pParent != NULL )
{
m_pParent->EndTouch( pOther );
}
}
//-----------------------------------------------------------------------------
// Purpose: Dispatches blocked events to this entity's blocked handler, set via SetBlocked.
// Input : pOther - The entity that is blocking us.
//-----------------------------------------------------------------------------
void CBaseEntity::Blocked( CBaseEntity *pOther )
{
if ( m_pfnBlocked )
{
(this->*m_pfnBlocked)( pOther );
}
//
// Forward the blocked event to our parent, if any.
//
if ( m_pParent != NULL )
{
m_pParent->Blocked( pOther );
}
}
//-----------------------------------------------------------------------------
// Purpose: Dispatches use events to this entity's use handler, set via SetUse.
// Input : pActivator -
// pCaller -
// useType -
// value -
//-----------------------------------------------------------------------------
void CBaseEntity::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( m_pfnUse != NULL )
{
(this->*m_pfnUse)( pActivator, pCaller, useType, value );
}
else
{
//
// We don't handle use events. Forward to our parent, if any.
//
if ( m_pParent != NULL )
{
m_pParent->Use( pActivator, pCaller, useType, value );
}
}
}
static CBaseEntity *FindPhysicsBlocker( IPhysicsObject *pPhysics, physicspushlist_t &list, const Vector &pushVel )
{
IPhysicsFrictionSnapshot *pSnapshot = pPhysics->CreateFrictionSnapshot();
CBaseEntity *pBlocker = NULL;
float maxForce = 0;
while ( pSnapshot->IsValid() )
{
IPhysicsObject *pOther = pSnapshot->GetObject(1);
CBaseEntity *pOtherEntity = static_cast<CBaseEntity *>(pOther->GetGameData());
bool inList = false;
for ( int i = 0; i < list.pushedCount; i++ )
{
if ( pOtherEntity == list.pushedEnts[i] )
{
inList = true;
break;
}
}
Vector normal;
pSnapshot->GetSurfaceNormal(normal);
float dot = DotProduct( pushVel, pSnapshot->GetNormalForce() * normal );
if ( !pBlocker || (!inList && dot > maxForce) )
{
pBlocker = pOtherEntity;
if ( !inList )
{
maxForce = dot;
}
}
pSnapshot->NextFrictionData();
}
pPhysics->DestroyFrictionSnapshot( pSnapshot );
return pBlocker;
}
struct pushblock_t
{
physicspushlist_t *pList;
CBaseEntity *pRootParent;
CBaseEntity *pBlockedEntity;
float moveBackFraction;
float movetime;
};
static void ComputePushStartMatrix( matrix3x4_t &start, CBaseEntity *pEntity, const pushblock_t &params )
{
Vector localOrigin;
QAngle localAngles;
if ( params.pList )
{
localOrigin = params.pList->localOrigin;
localAngles = params.pList->localAngles;
}
else
{
localOrigin = params.pRootParent->GetAbsOrigin() - params.pRootParent->GetAbsVelocity() * params.movetime;
localAngles = params.pRootParent->GetAbsAngles() - params.pRootParent->GetLocalAngularVelocity() * params.movetime;
}
matrix3x4_t xform, delta;
AngleMatrix( localAngles, localOrigin, xform );
matrix3x4_t srcInv;
// xform = src(-1) * dest
MatrixInvert( params.pRootParent->EntityToWorldTransform(), srcInv );
ConcatTransforms( xform, srcInv, delta );
ConcatTransforms( delta, pEntity->EntityToWorldTransform(), start );
}
#define DEBUG_PUSH_MESSAGES 0
static void CheckPushedEntity( CBaseEntity *pEntity, pushblock_t &params )
{
IPhysicsObject *pPhysics = pEntity->VPhysicsGetObject();
if ( !pPhysics )
return;
// somehow we've got a static or motion disabled physics object in hierarchy!
// This is not allowed! Don't test blocking in that case.
Assert(pPhysics->IsMoveable());
if ( !pPhysics->IsMoveable() || !pPhysics->GetShadowController() )
{
#if DEBUG_PUSH_MESSAGES
Msg("Blocking %s, not moveable!\n", pEntity->GetClassname());
#endif
return;
}
bool checkrot = true;
bool checkmove = true;
Vector origin;
QAngle angles;
pPhysics->GetShadowPosition( &origin, &angles );
float fraction = -1.0f;
matrix3x4_t parentDelta;
if ( pEntity == params.pRootParent )
{
if ( pEntity->GetLocalAngularVelocity() == vec3_angle )
checkrot = false;
if ( pEntity->GetLocalVelocity() == vec3_origin)
checkmove = false;
}
else
{
#if DEBUG_PUSH_MESSAGES
if ( pPhysics->IsAttachedToConstraint(false))
{
Msg("Warning, hierarchical entity is attached to a constraint %s\n", pEntity->GetClassname());
}
#endif
}
if ( checkmove )
{
// project error onto the axis of movement
Vector dir = pEntity->GetAbsVelocity();
float speed = VectorNormalize(dir);
Vector targetPos;
pPhysics->GetShadowController()->GetTargetPosition( &targetPos, NULL );
float targetAmount = DotProduct(targetPos, dir);
float currentAmount = DotProduct(origin, dir);
float entityAmount = DotProduct(pEntity->GetAbsOrigin(), dir);
// if target and entity origin are not in sync, then the position of the entity was updated
// by something outside of push physics
if ( (targetAmount - entityAmount) > 1 )
{
pEntity->UpdatePhysicsShadowToCurrentPosition(0);
#if DEBUG_PUSH_MESSAGES
Warning("Someone slammed the position of a %s\n", pEntity->GetClassname() );
#endif
}
else
{
float dist = targetAmount - currentAmount;
if ( dist > 1 )
{
#if DEBUG_PUSH_MESSAGES
const char *pName = pEntity->GetClassname();
Msg( "%s blocked by %.2f units\n", pName, dist );
#endif
float movementAmount = targetAmount - (speed * params.movetime);
if ( pEntity == params.pRootParent )
{
if ( params.pList )
{
Vector localVel = pEntity->GetLocalVelocity();
VectorNormalize(localVel);
float localTargetAmt = DotProduct(pEntity->GetLocalOrigin(), localVel);
movementAmount = targetAmount + DotProduct(params.pList->localOrigin, localVel) - localTargetAmt;
}
}
else
{
matrix3x4_t start;
ComputePushStartMatrix( start, pEntity, params );
Vector startPos;
MatrixPosition( start, startPos );
movementAmount = DotProduct(startPos, dir);
}
float expectedDist = targetAmount - movementAmount;
// compute the fraction to move back the AI to match the physics
if ( expectedDist <= 0 )
{
fraction = 1;
}
else
{
fraction = dist / expectedDist;
fraction = clamp(fraction, 0.f, 1.f);
}
}
}
}
if ( checkrot )
{
Vector axis;
float deltaAngle;
RotationDeltaAxisAngle( angles, pEntity->GetAbsAngles(), axis, deltaAngle );
if ( fabsf(deltaAngle) > 0.5f )
{
Vector targetAxis;
QAngle targetRot;
float deltaTargetAngle;
pPhysics->GetShadowController()->GetTargetPosition( NULL, &targetRot );
RotationDeltaAxisAngle( angles, targetRot, targetAxis, deltaTargetAngle );
if ( fabsf(deltaTargetAngle) > 0.01f )
{
float expectedDist = deltaAngle;
#if DEBUG_PUSH_MESSAGES
const char *pName = pEntity->GetClassname();
Msg( "%s blocked by %.2f degrees\n", pName, deltaAngle );
if ( pPhysics->IsAsleep() )
{
Msg("Asleep while blocked?\n");
}
if ( pPhysics->GetGameFlags() & FVPHYSICS_PENETRATING )
{
Msg("Blocking for penetration!\n");
}
#endif
if ( pEntity == params.pRootParent )
{
expectedDist = pEntity->GetLocalAngularVelocity().Length() * params.movetime;
}
else
{
matrix3x4_t start;
ComputePushStartMatrix( start, pEntity, params );
Vector startAxis;
float startAngle;
Vector startPos;
QAngle startAngles;
MatrixAngles( start, startAngles, startPos );
RotationDeltaAxisAngle( startAngles, pEntity->GetAbsAngles(), startAxis, startAngle );
expectedDist = startAngle * DotProduct( startAxis, axis );
}
float t = expectedDist != 0.0f ? fabsf(deltaAngle / expectedDist) : 1.0f;
t = clamp(t,0.f,1.f);
fraction = MAX(fraction, t);
}
else
{
pEntity->UpdatePhysicsShadowToCurrentPosition(0);
#if DEBUG_PUSH_MESSAGES
Warning("Someone slammed the position of a %s\n", pEntity->GetClassname() );
#endif
}
}
}
if ( fraction >= params.moveBackFraction )
{
params.moveBackFraction = fraction;
params.pBlockedEntity = pEntity;
}
}
void CBaseEntity::VPhysicsUpdatePusher( IPhysicsObject *pPhysics )
{
float movetime = m_flLocalTime - m_flVPhysicsUpdateLocalTime;
if (movetime <= 0)
return;
// only reconcile pushers on the final vphysics tick
if ( !PhysIsFinalTick() )
return;
Vector origin;
QAngle angles;
// physics updated the shadow, so check to see if I got blocked
// NOTE: SOLID_BSP cannont compute consistent collisions wrt vphysics, so
// don't allow vphysics to block. Assume game physics has handled it.
if ( GetSolid() != SOLID_BSP && pPhysics->GetShadowPosition( &origin, &angles ) )
{
CUtlVector<CBaseEntity *> list;
GetAllInHierarchy( this, list );
//NDebugOverlay::BoxAngles( origin, CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), angles, 255,0,0,0, gpGlobals->frametime);
physicspushlist_t *pList = NULL;
if ( HasDataObjectType(PHYSICSPUSHLIST) )
{
pList = (physicspushlist_t *)GetDataObject( PHYSICSPUSHLIST );
Assert(pList);
}
bool checkrot = (GetLocalAngularVelocity() != vec3_angle) ? true : false;
bool checkmove = (GetLocalVelocity() != vec3_origin) ? true : false;
pushblock_t params;
params.pRootParent = this;
params.pList = pList;
params.pBlockedEntity = NULL;
params.moveBackFraction = 0.0f;
params.movetime = movetime;
for ( int i = 0; i < list.Count(); i++ )
{
if ( list[i]->IsSolid() )
{
CheckPushedEntity( list[i], params );
}
}
float physLocalTime = m_flLocalTime;
if ( params.pBlockedEntity )
{
float moveback = movetime * params.moveBackFraction;
if ( moveback > 0 )
{
physLocalTime = m_flLocalTime - moveback;
// add 1% noise for bouncing in collision.
if ( physLocalTime <= (m_flVPhysicsUpdateLocalTime + movetime * 0.99f) )
{
CBaseEntity *pBlocked = NULL;
IPhysicsObject *pOther;
if ( params.pBlockedEntity->VPhysicsGetObject()->GetContactPoint( NULL, &pOther ) )
{
pBlocked = static_cast<CBaseEntity *>(pOther->GetGameData());
}
// UNDONE: Need to traverse hierarchy here? Shouldn't.
if ( pList )
{
SetLocalOrigin( pList->localOrigin );
SetLocalAngles( pList->localAngles );
physLocalTime = pList->localMoveTime;
for ( int i = 0; i < pList->pushedCount; i++ )
{
CBaseEntity *pEntity = pList->pushedEnts[i];
if ( !pEntity )
continue;
pEntity->SetAbsOrigin( pEntity->GetAbsOrigin() - pList->pushVec[i] );
}
CBaseEntity *pPhysicsBlocker = FindPhysicsBlocker( VPhysicsGetObject(), *pList, pList->pushVec[0] );
if ( pPhysicsBlocker )
{
pBlocked = pPhysicsBlocker;
}
}
else
{
Vector origin = GetLocalOrigin();
QAngle angles = GetLocalAngles();
if ( checkmove )
{
origin -= GetLocalVelocity() * moveback;
}
if ( checkrot )
{
// BUGBUG: This is pretty hack-tastic!
angles -= GetLocalAngularVelocity() * moveback;
}
SetLocalOrigin( origin );
SetLocalAngles( angles );
}
if ( pBlocked )
{
Blocked( pBlocked );
}
m_flLocalTime = physLocalTime;
}
}
}
}
// this data is no longer useful, free the memory
if ( HasDataObjectType(PHYSICSPUSHLIST) )
{
DestroyDataObject( PHYSICSPUSHLIST );
}
m_flVPhysicsUpdateLocalTime = m_flLocalTime;
if ( m_flMoveDoneTime <= m_flLocalTime && m_flMoveDoneTime > 0 )
{
SetMoveDoneTime( -1 );
MoveDone();
}
}
void CBaseEntity::SetMoveDoneTime( float flDelay )
{
if (flDelay >= 0)
{
m_flMoveDoneTime = GetLocalTime() + flDelay;
}
else
{
m_flMoveDoneTime = -1;
}
CheckHasGamePhysicsSimulation();
}
//-----------------------------------------------------------------------------
// Purpose: Relinks all of a parents children into the collision tree
//-----------------------------------------------------------------------------
void CBaseEntity::PhysicsRelinkChildren( float dt )
{
CBaseEntity *child;
// iterate through all children
for ( child = FirstMoveChild(); child != NULL; child = child->NextMovePeer() )
{
if ( child->IsSolid() || child->IsSolidFlagSet(FSOLID_TRIGGER) )
{
child->PhysicsTouchTriggers();
}
//
// Update their physics shadows. We should never have any children of
// movetype VPHYSICS.
//
if ( child->GetMoveType() != MOVETYPE_VPHYSICS )
{
child->UpdatePhysicsShadowToCurrentPosition( dt );
}
else if ( child->GetOwnerEntity() != this )
{
// the only case where this is valid is if this entity is an attached ragdoll.
// So assert here to catch the non-ragdoll case.
Assert( 0 );
}
if ( child->FirstMoveChild() )
{
child->PhysicsRelinkChildren(dt);
}
}
}
void CBaseEntity::PhysicsTouchTriggers( const Vector *pPrevAbsOrigin )
{
edict_t *pEdict = edict();
if ( pEdict && !IsWorld() )
{
Assert(CollisionProp());
bool isTriggerCheckSolids = IsSolidFlagSet( FSOLID_TRIGGER );
bool isSolidCheckTriggers = IsSolid() && !isTriggerCheckSolids; // NOTE: Moving triggers (items, ammo etc) are not
// checked against other triggers to reduce the number of touchlinks created
if ( !(isSolidCheckTriggers || isTriggerCheckSolids) )
return;
if ( GetSolid() == SOLID_BSP )
{
if ( !GetModel() && Q_strlen( STRING( GetModelName() ) ) == 0 )
{
Warning( "Inserted %s with no model\n", GetClassname() );
return;
}
}
SetCheckUntouch( true );
if ( isSolidCheckTriggers )
{
engine->SolidMoved( pEdict, CollisionProp(), pPrevAbsOrigin, sm_bAccurateTriggerBboxChecks );
}
if ( isTriggerCheckSolids )
{
engine->TriggerMoved( pEdict, sm_bAccurateTriggerBboxChecks );
}
}
}
void CBaseEntity::VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent )
{
}
void CBaseEntity::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
{
// filter out ragdoll props hitting other parts of itself too often
// UNDONE: Store a sound time for this entity (not just this pair of objects)
// and filter repeats on that?
int otherIndex = !index;
CBaseEntity *pHitEntity = pEvent->pEntities[otherIndex];
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
#ifdef MAPBASE_VSCRIPT
if (HSCRIPT hFunc = LookupScriptFunction("VPhysicsCollision"))
{
// TODO: Unique class for collision events
g_pScriptVM->SetValue( "entity", ScriptVariant_t( pHitEntity->GetScriptInstance() ) );
g_pScriptVM->SetValue( "speed", pEvent->collisionSpeed );
Vector vecContactPoint;
pEvent->pInternalData->GetContactPoint( vecContactPoint );
g_pScriptVM->SetValue( "point", vecContactPoint );
Vector vecSurfaceNormal;
pEvent->pInternalData->GetSurfaceNormal( vecSurfaceNormal );
g_pScriptVM->SetValue( "normal", vecSurfaceNormal );
CallScriptFunctionHandle( hFunc, NULL );
g_pScriptVM->ClearValue( "entity" );
g_pScriptVM->ClearValue( "speed" );
g_pScriptVM->ClearValue( "point" );
g_pScriptVM->ClearValue( "normal" );
}
#endif
2013-12-02 19:31:46 -08:00
// Don't make sounds / effects if neither entity is MOVETYPE_VPHYSICS. The game
// physics should have done so.
if ( GetMoveType() != MOVETYPE_VPHYSICS && pHitEntity->GetMoveType() != MOVETYPE_VPHYSICS )
return;
if ( pEvent->deltaCollisionTime < 0.5 && (pHitEntity == this) )
return;
// don't make noise for hidden/invisible/sky materials
surfacedata_t *phit = physprops->GetSurfaceData( pEvent->surfaceProps[otherIndex] );
const surfacedata_t *pprops = physprops->GetSurfaceData( pEvent->surfaceProps[index] );
if ( phit->game.material == 'X' || pprops->game.material == 'X' )
return;
if ( pHitEntity == this )
{
PhysCollisionSound( this, pEvent->pObjects[index], CHAN_BODY, pEvent->surfaceProps[index], pEvent->surfaceProps[otherIndex], pEvent->deltaCollisionTime, pEvent->collisionSpeed );
}
else
{
PhysCollisionSound( this, pEvent->pObjects[index], CHAN_STATIC, pEvent->surfaceProps[index], pEvent->surfaceProps[otherIndex], pEvent->deltaCollisionTime, pEvent->collisionSpeed );
}
PhysCollisionScreenShake( pEvent, index );
#if HL2_EPISODIC
// episodic does something different for when advisor shields are struck
if ( phit->game.material == 'Z' || pprops->game.material == 'Z')
{
PhysCollisionWarpEffect( pEvent, phit );
}
else
{
PhysCollisionDust( pEvent, phit );
}
#else
PhysCollisionDust( pEvent, phit );
#endif
}
void CBaseEntity::VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit )
{
PhysFrictionSound( this, pObject, energy, surfaceProps, surfacePropsHit );
}
void CBaseEntity::VPhysicsSwapObject( IPhysicsObject *pSwap )
{
if ( !pSwap )
{
PhysRemoveShadow(this);
}
if ( !m_pPhysicsObject )
{
Warning( "Bad vphysics swap for %s\n", STRING(m_iClassname) );
}
m_pPhysicsObject = pSwap;
}
// Tells the physics shadow to update it's target to the current position
void CBaseEntity::UpdatePhysicsShadowToCurrentPosition( float deltaTime )
{
if ( GetMoveType() != MOVETYPE_VPHYSICS )
{
IPhysicsObject *pPhys = VPhysicsGetObject();
if ( pPhys )
{
pPhys->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, deltaTime );
}
}
}
int CBaseEntity::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax )
{
IPhysicsObject *pPhys = VPhysicsGetObject();
if ( pPhys )
{
// multi-object entities must implement this function
Assert( !(pPhys->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) );
if ( listMax > 0 )
{
pList[0] = pPhys;
return 1;
}
}
return 0;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CBaseEntity::VPhysicsIsFlesh( void )
{
IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
int count = VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
for ( int i = 0; i < count; i++ )
{
int material = pList[i]->GetMaterialIndex();
const surfacedata_t *pSurfaceData = physprops->GetSurfaceData( material );
// Is flesh ?, don't allow pickup
if ( pSurfaceData->game.material == CHAR_TEX_ANTLION || pSurfaceData->game.material == CHAR_TEX_FLESH || pSurfaceData->game.material == CHAR_TEX_BLOODYFLESH || pSurfaceData->game.material == CHAR_TEX_ALIENFLESH )
return true;
}
return false;
}
bool CBaseEntity::Intersects( CBaseEntity *pOther )
{
if ( !edict() || !pOther->edict() )
return false;
CCollisionProperty *pMyProp = CollisionProp();
CCollisionProperty *pOtherProp = pOther->CollisionProp();
return IsOBBIntersectingOBB(
pMyProp->GetCollisionOrigin(), pMyProp->GetCollisionAngles(), pMyProp->OBBMins(), pMyProp->OBBMaxs(),
pOtherProp->GetCollisionOrigin(), pOtherProp->GetCollisionAngles(), pOtherProp->OBBMins(), pOtherProp->OBBMaxs() );
}
extern ConVar ai_LOS_mode;
//=========================================================
// FVisible - returns true if a line can be traced from
// the caller's eyes to the target
//=========================================================
bool CBaseEntity::FVisible( CBaseEntity *pEntity, int traceMask, CBaseEntity **ppBlocker )
{
VPROF( "CBaseEntity::FVisible" );
if ( pEntity->GetFlags() & FL_NOTARGET )
return false;
#if HL1_DLL
// FIXME: only block LOS through opaque water
// don't look through water
if ((m_nWaterLevel != 3 && pEntity->m_nWaterLevel == 3)
|| (m_nWaterLevel == 3 && pEntity->m_nWaterLevel == 0))
return false;
#endif
Vector vecLookerOrigin = EyePosition();//look through the caller's 'eyes'
Vector vecTargetOrigin = pEntity->EyePosition();
trace_t tr;
if ( !IsXbox() && ai_LOS_mode.GetBool() )
{
UTIL_TraceLine(vecLookerOrigin, vecTargetOrigin, traceMask, this, COLLISION_GROUP_NONE, &tr);
}
else
{
// If we're doing an LOS search, include NPCs.
if ( traceMask == MASK_BLOCKLOS )
{
traceMask = MASK_BLOCKLOS_AND_NPCS;
}
// Player sees through nodraw
if ( IsPlayer() )
{
traceMask &= ~CONTENTS_BLOCKLOS;
}
// Use the custom LOS trace filter
CTraceFilterLOS traceFilter( this, COLLISION_GROUP_NONE, pEntity );
UTIL_TraceLine( vecLookerOrigin, vecTargetOrigin, traceMask, &traceFilter, &tr );
}
if (tr.fraction != 1.0 || tr.startsolid )
{
// If we hit the entity we're looking for, it's visible
if ( tr.m_pEnt == pEntity )
return true;
// Got line of sight on the vehicle the player is driving!
if ( pEntity && pEntity->IsPlayer() )
{
CBasePlayer *pPlayer = assert_cast<CBasePlayer*>( pEntity );
if ( tr.m_pEnt == pPlayer->GetVehicleEntity() )
return true;
}
if (ppBlocker)
{
*ppBlocker = tr.m_pEnt;
}
return false;// Line of sight is not established
}
return true;// line of sight is valid.
}
//=========================================================
// FVisible - returns true if a line can be traced from
// the caller's eyes to the wished position.
//=========================================================
bool CBaseEntity::FVisible( const Vector &vecTarget, int traceMask, CBaseEntity **ppBlocker )
{
#if HL1_DLL
// don't look through water
// FIXME: only block LOS through opaque water
bool inWater = ( UTIL_PointContents( vecTarget ) & (CONTENTS_SLIME|CONTENTS_WATER) ) ? true : false;
// Don't allow it if we're straddling two areas
if ( ( m_nWaterLevel == 3 && !inWater ) || ( m_nWaterLevel != 3 && inWater ) )
return false;
#endif
trace_t tr;
Vector vecLookerOrigin = EyePosition();// look through the caller's 'eyes'
if ( ai_LOS_mode.GetBool() )
{
UTIL_TraceLine( vecLookerOrigin, vecTarget, traceMask, this, COLLISION_GROUP_NONE, &tr);
}
else
{
// If we're doing an LOS search, include NPCs.
if ( traceMask == MASK_BLOCKLOS )
{
traceMask = MASK_BLOCKLOS_AND_NPCS;
}
// Player sees through nodraw and blocklos
if ( IsPlayer() )
{
traceMask |= CONTENTS_IGNORE_NODRAW_OPAQUE;
traceMask &= ~CONTENTS_BLOCKLOS;
}
// Use the custom LOS trace filter
CTraceFilterLOS traceFilter( this, COLLISION_GROUP_NONE );
UTIL_TraceLine( vecLookerOrigin, vecTarget, traceMask, &traceFilter, &tr );
}
if (tr.fraction != 1.0)
{
if (ppBlocker)
{
*ppBlocker = tr.m_pEnt;
}
return false;// Line of sight is not established
}
return true;// line of sight is valid.
}
extern ConVar ai_debug_los;
//-----------------------------------------------------------------------------
// Purpose: Turn on prop LOS debugging mode
//-----------------------------------------------------------------------------
void CC_AI_LOS_Debug( IConVar *var, const char *pOldString, float flOldValue )
{
int iLOSMode = ai_debug_los.GetInt();
for ( CBaseEntity *pEntity = gEntList.FirstEnt(); pEntity != NULL; pEntity = gEntList.NextEnt(pEntity) )
{
if ( iLOSMode == 1 && pEntity->IsSolid() )
{
pEntity->m_debugOverlays |= OVERLAY_SHOW_BLOCKSLOS;
}
else if ( iLOSMode == 2 )
{
pEntity->m_debugOverlays |= OVERLAY_SHOW_BLOCKSLOS;
}
else
{
pEntity->m_debugOverlays &= ~OVERLAY_SHOW_BLOCKSLOS;
}
}
}
ConVar ai_debug_los("ai_debug_los", "0", FCVAR_CHEAT, "NPC Line-Of-Sight debug mode. If 1, solid entities that block NPC LOC will be highlighted with white bounding boxes. If 2, it'll show non-solid entities that would do it if they were solid.", CC_AI_LOS_Debug );
Class_T CBaseEntity::Classify ( void )
{
return CLASS_NONE;
}
float CBaseEntity::GetAutoAimRadius()
{
if( g_pGameRules->GetAutoAimMode() == AUTOAIM_ON_CONSOLE )
return 48.0f;
else
return 24.0f;
}
//-----------------------------------------------------------------------------
// Changes the shadow cast distance over time
//-----------------------------------------------------------------------------
void CBaseEntity::ShadowCastDistThink( )
{
SetShadowCastDistance( m_flDesiredShadowCastDistance );
SetContextThink( NULL, gpGlobals->curtime, "ShadowCastDistThink" );
}
void CBaseEntity::SetShadowCastDistance( float flDesiredDistance, float flDelay )
{
m_flDesiredShadowCastDistance = flDesiredDistance;
if ( m_flDesiredShadowCastDistance != m_flShadowCastDistance )
{
SetContextThink( &CBaseEntity::ShadowCastDistThink, gpGlobals->curtime + flDelay, "ShadowCastDistThink" );
}
}
/*
================
TraceAttack
================
*/
//-----------------------------------------------------------------------------
// Purpose: Returns whether a damage info can damage this entity.
//-----------------------------------------------------------------------------
bool CBaseEntity::PassesDamageFilter( const CTakeDamageInfo &info )
{
if (m_hDamageFilter)
{
CBaseFilter *pFilter = (CBaseFilter *)(m_hDamageFilter.Get());
#ifdef MAPBASE
return pFilter->PassesDamageFilter(this, info);
#else
2013-12-02 19:31:46 -08:00
return pFilter->PassesDamageFilter(info);
#endif
}
return true;
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: A damage filter pass for when this is most certainly the part where we might actually take damage.
// Made for the "damage" family of filters, including filter_damage_transfer.
//-----------------------------------------------------------------------------
bool CBaseEntity::PassesFinalDamageFilter( const CTakeDamageInfo &info )
{
if (!PassesDamageFilter(info))
return false;
if (m_hDamageFilter)
{
CBaseFilter *pFilter = (CBaseFilter *)(m_hDamageFilter.Get());
if (!pFilter->PassesFinalDamageFilter(this, info))
{
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: A hack for damage transfers.
//-----------------------------------------------------------------------------
bool CBaseEntity::DamageFilterAllowsBlood( const CTakeDamageInfo &info )
{
if (m_hDamageFilter)
{
CBaseFilter *pFilter = (CBaseFilter *)(m_hDamageFilter.Get());
if (!pFilter->BloodAllowed(this, info))
{
return false;
}
2013-12-02 19:31:46 -08:00
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Modifies damage taken. Returns true if damage was successfully modded.
//-----------------------------------------------------------------------------
bool CBaseEntity::DamageFilterDamageMod( CTakeDamageInfo &info )
{
if (m_hDamageFilter)
{
CBaseFilter *pFilter = (CBaseFilter *)(m_hDamageFilter.Get());
if (pFilter->DamageMod(this, info))
{
return true;
}
}
return false;
}
#endif
2013-12-02 19:31:46 -08:00
FORCEINLINE bool NamesMatch( const char *pszQuery, string_t nameToMatch )
{
#ifdef MAPBASE
// NamesMatch has been turned into Matcher_NamesMatch in matchers.h
// for a wider range of accessibility and flexibility.
return Matcher_NamesMatch(pszQuery, STRING(nameToMatch));
#else
2013-12-02 19:31:46 -08:00
if ( nameToMatch == NULL_STRING )
return (!pszQuery || *pszQuery == 0 || *pszQuery == '*');
const char *pszNameToMatch = STRING(nameToMatch);
// If the pointers are identical, we're identical
if ( pszNameToMatch == pszQuery )
return true;
while ( *pszNameToMatch && *pszQuery )
{
unsigned char cName = *pszNameToMatch;
unsigned char cQuery = *pszQuery;
// simple ascii case conversion
if ( cName == cQuery )
;
else if ( cName - 'A' <= (unsigned char)'Z' - 'A' && cName - 'A' + 'a' == cQuery )
;
else if ( cName - 'a' <= (unsigned char)'z' - 'a' && cName - 'a' + 'A' == cQuery )
;
else
break;
++pszNameToMatch;
++pszQuery;
}
if ( *pszQuery == 0 && *pszNameToMatch == 0 )
return true;
// @TODO (toml 03-18-03): Perhaps support real wildcards. Right now, only thing supported is trailing *
if ( *pszQuery == '*' )
return true;
return false;
#endif
2013-12-02 19:31:46 -08:00
}
bool CBaseEntity::NameMatchesComplex( const char *pszNameOrWildcard )
{
if ( !Q_stricmp( "!player", pszNameOrWildcard) )
return IsPlayer();
return NamesMatch( pszNameOrWildcard, m_iName );
}
bool CBaseEntity::ClassMatchesComplex( const char *pszClassOrWildcard )
{
return NamesMatch( pszClassOrWildcard, m_iClassname );
}
void CBaseEntity::MakeDormant( void )
{
AddEFlags( EFL_DORMANT );
// disable thinking for dormant entities
SetThink( NULL );
if ( !edict() )
return;
SETBITS( m_iEFlags, EFL_DORMANT );
// Don't touch
AddSolidFlags( FSOLID_NOT_SOLID );
// Don't move
SetMoveType( MOVETYPE_NONE );
// Don't draw
AddEffects( EF_NODRAW );
// Don't think
SetNextThink( TICK_NEVER_THINK );
}
int CBaseEntity::IsDormant( void )
{
return IsEFlagSet( EFL_DORMANT );
}
bool CBaseEntity::IsInWorld( void ) const
{
if ( !edict() )
return true;
// position
if (GetAbsOrigin().x >= MAX_COORD_INTEGER) return false;
if (GetAbsOrigin().y >= MAX_COORD_INTEGER) return false;
if (GetAbsOrigin().z >= MAX_COORD_INTEGER) return false;
if (GetAbsOrigin().x <= MIN_COORD_INTEGER) return false;
if (GetAbsOrigin().y <= MIN_COORD_INTEGER) return false;
if (GetAbsOrigin().z <= MIN_COORD_INTEGER) return false;
// speed
if (GetAbsVelocity().x >= 2000) return false;
if (GetAbsVelocity().y >= 2000) return false;
if (GetAbsVelocity().z >= 2000) return false;
if (GetAbsVelocity().x <= -2000) return false;
if (GetAbsVelocity().y <= -2000) return false;
if (GetAbsVelocity().z <= -2000) return false;
return true;
}
bool CBaseEntity::IsViewable( void )
{
if ( IsEffectActive( EF_NODRAW ) )
{
return false;
}
if (IsBSPModel())
{
if (GetMoveType() != MOVETYPE_NONE)
{
return true;
}
}
else if (GetModelIndex() != 0)
{
// check for total transparency???
return true;
}
return false;
}
int CBaseEntity::ShouldToggle( USE_TYPE useType, int currentState )
{
if ( useType != USE_TOGGLE && useType != USE_SET )
{
if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) )
return 0;
}
return 1;
}
// NOTE: szName must be a pointer to constant memory, e.g. "NPC_class" because the entity
// will keep a pointer to it after this call.
CBaseEntity *CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner )
{
CBaseEntity *pEntity = CreateNoSpawn( szName, vecOrigin, vecAngles, pOwner );
DispatchSpawn( pEntity );
return pEntity;
}
// NOTE: szName must be a pointer to constant memory, e.g. "NPC_class" because the entity
// will keep a pointer to it after this call.
CBaseEntity * CBaseEntity::CreateNoSpawn( const char *szName, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner )
{
CBaseEntity *pEntity = CreateEntityByName( szName );
if ( !pEntity )
{
Assert( !"CreateNoSpawn: only works for CBaseEntities" );
return NULL;
}
pEntity->SetLocalOrigin( vecOrigin );
pEntity->SetLocalAngles( vecAngles );
pEntity->SetOwnerEntity( pOwner );
gEntList.NotifyCreateEntity( pEntity );
return pEntity;
}
Vector CBaseEntity::GetSoundEmissionOrigin() const
{
return WorldSpaceCenter();
}
//-----------------------------------------------------------------------------
// Purpose: Saves the current object out to disk, by iterating through the objects
// data description hierarchy
// Input : &save - save buffer which the class data is written to
// Output : int - 0 if the save failed, 1 on success
//-----------------------------------------------------------------------------
int CBaseEntity::Save( ISave &save )
{
// loop through the data description list, saving each data desc block
int status = SaveDataDescBlock( save, GetDataDescMap() );
return status;
}
//-----------------------------------------------------------------------------
// Purpose: Recursively saves all the classes in an object, in reverse order (top down)
// Output : int 0 on failure, 1 on success
//-----------------------------------------------------------------------------
int CBaseEntity::SaveDataDescBlock( ISave &save, datamap_t *dmap )
{
return save.WriteAll( this, dmap );
}
//-----------------------------------------------------------------------------
// Purpose: Restores the current object from disk, by iterating through the objects
// data description hierarchy
// Input : &restore - restore buffer which the class data is read from
// Output : int - 0 if the restore failed, 1 on success
//-----------------------------------------------------------------------------
int CBaseEntity::Restore( IRestore &restore )
{
// This is essential to getting the spatial partition info correct
CollisionProp()->DestroyPartitionHandle();
// loops through the data description list, restoring each data desc block in order
int status = RestoreDataDescBlock( restore, GetDataDescMap() );
// ---------------------------------------------------------------
// HACKHACK: We don't know the space of these vectors until now
// if they are worldspace, fix them up.
// ---------------------------------------------------------------
{
CGameSaveRestoreInfo *pGameInfo = restore.GetGameSaveRestoreInfo();
Vector parentSpaceOffset = pGameInfo->modelSpaceOffset;
if ( !GetParent() )
{
// parent is the world, so parent space is worldspace
// so update with the worldspace leveltransition transform
parentSpaceOffset += pGameInfo->GetLandmark();
}
// NOTE: Do *not* use GetAbsOrigin() here because it will
// try to recompute m_rgflCoordinateFrame!
MatrixSetColumn( m_vecAbsOrigin, 3, m_rgflCoordinateFrame );
m_vecOrigin += parentSpaceOffset;
}
// Gotta do this after the coordframe is set up as it depends on it.
// By definition, the surrounding bounds are dirty
// Also, twiddling with the flags here ensures it gets added to the KD tree dirty list
// (We don't want to use the saved version of this flag)
RemoveEFlags( EFL_DIRTY_SPATIAL_PARTITION );
CollisionProp()->MarkSurroundingBoundsDirty();
if ( edict() && GetModelIndex() != 0 && GetModelName() != NULL_STRING && restore.GetPrecacheMode() )
{
PrecacheModel( STRING( GetModelName() ) );
//Adrian: We should only need to do this after we precache. No point in setting the model again.
SetModelIndex( modelinfo->GetModelIndex( STRING(GetModelName() ) ) );
}
// Restablish ground entity
if ( m_hGroundEntity != NULL )
{
m_hGroundEntity->AddEntityToGroundList( this );
}
return status;
}
//-----------------------------------------------------------------------------
// handler to do stuff before you are saved
//-----------------------------------------------------------------------------
void CBaseEntity::OnSave( IEntitySaveUtils *pUtils )
{
// Here, we must force recomputation of all abs data so it gets saved correctly
// We can't leave the dirty bits set because the loader can't cope with it.
CalcAbsolutePosition();
CalcAbsoluteVelocity();
}
//-----------------------------------------------------------------------------
// handler to do stuff after you are restored
//-----------------------------------------------------------------------------
void CBaseEntity::OnRestore()
{
#ifndef MAPBASE // It's your fault if you're trying to load old, broken saves from a possibly closed 2013 beta in Mapbase.
2013-12-02 19:31:46 -08:00
#if defined( PORTAL ) || defined( HL2_EPISODIC ) || defined ( HL2_DLL ) || defined( HL2_LOSTCOAST )
// We had a short period during the 2013 beta where the FL_* flags had a bogus value near the top, so detect
// these bad saves and just give up. Only saves from the short beta period should have been effected.
if ( GetFlags() & FL_FAKECLIENT )
{
char szMsg[256];
V_snprintf( szMsg, sizeof(szMsg), "\nInvalid save, unable to load. Please run \"map %s\" to restart this level manually\n\n", gpGlobals->mapname.ToCStr() );
Msg( "%s", szMsg );
engine->ServerCommand("wait;wait;disconnect;showconsole\n");
}
#endif
2013-12-02 19:31:46 -08:00
#endif
SimThink_EntityChanged( this );
// touchlinks get recomputed
if ( IsEFlagSet( EFL_CHECK_UNTOUCH ) )
{
RemoveEFlags( EFL_CHECK_UNTOUCH );
SetCheckUntouch( true );
}
// disable touch functions while we recreate the touch links between entities
// NOTE: We don't do this on transitions, because we'd miss the OnStartTouch call!
#if !defined(HL2_DLL) || ( defined(HL2_DLL) && defined(HL2_EPISODIC) )
CBaseEntity::sm_bDisableTouchFuncs = ( gpGlobals->eLoadType != MapLoad_Transition );
PhysicsTouchTriggers();
CBaseEntity::sm_bDisableTouchFuncs = false;
#endif // HL2_EPISODIC
//Adrian: If I'm restoring with these fields it means I've become a client side ragdoll.
//Don't create another one, just wait until is my time of being removed.
if ( GetFlags() & FL_TRANSRAGDOLL )
{
m_nRenderFX = kRenderFxNone;
AddEffects( EF_NODRAW );
RemoveFlag( FL_DISSOLVING | FL_ONFIRE );
}
if ( m_pParent )
{
CBaseEntity *pChild = m_pParent->FirstMoveChild();
while ( pChild )
{
if ( pChild == this )
break;
pChild = pChild->NextMovePeer();
}
if ( pChild != this )
{
#if _DEBUG
// generally this means you've got something marked FCAP_DONT_SAVE
// in a hierarchy. That's probably ok given this fixup, but the hierarhcy
// linked list is just saved/loaded in-place
Warning("Fixing up parent on %s\n", GetClassname() );
#endif
// We only need to be back in the parent's list because we're already in the right place and with the right data
LinkChild( m_pParent, this );
}
}
// We're not save/loading the PVS dirty state. Assume everything is dirty after a restore
NetworkProp()->MarkPVSInformationDirty();
}
//-----------------------------------------------------------------------------
// Purpose: Recursively restores all the classes in an object, in reverse order (top down)
// Output : int 0 on failure, 1 on success
//-----------------------------------------------------------------------------
int CBaseEntity::RestoreDataDescBlock( IRestore &restore, datamap_t *dmap )
{
return restore.ReadAll( this, dmap );
}
//-----------------------------------------------------------------------------
bool CBaseEntity::ShouldSavePhysics()
{
return true;
}
//-----------------------------------------------------------------------------
#include "tier0/memdbgoff.h"
//-----------------------------------------------------------------------------
// CBaseEntity new/delete
// allocates and frees memory for itself from the engine->
// All fields in the object are all initialized to 0.
//-----------------------------------------------------------------------------
void *CBaseEntity::operator new( size_t stAllocateBlock )
{
// call into engine to get memory
Assert( stAllocateBlock != 0 );
return engine->PvAllocEntPrivateData(stAllocateBlock);
};
void *CBaseEntity::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
{
// call into engine to get memory
Assert( stAllocateBlock != 0 );
return engine->PvAllocEntPrivateData(stAllocateBlock);
}
void CBaseEntity::operator delete( void *pMem )
{
// get the engine to free the memory
engine->FreeEntPrivateData( pMem );
}
#include "tier0/memdbgon.h"
#ifdef _DEBUG
void CBaseEntity::FunctionCheck( void *pFunction, const char *name )
{
#ifdef USES_SAVERESTORE
// Note, if you crash here and your class is using multiple inheritance, it is
// probably the case that CBaseEntity (or a descendant) is not the first
// class in your list of ancestors, which it must be.
if (pFunction && !UTIL_FunctionToName( GetDataDescMap(), (inputfunc_t *)pFunction ) )
{
Warning( "FUNCTION NOT IN TABLE!: %s:%s (%08lx)\n", STRING(m_iClassname), name, (unsigned long)pFunction );
Assert(0);
}
#endif
}
#endif
bool CBaseEntity::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
{
return false;
}
//-----------------------------------------------------------------------------
// Perform hitbox test, returns true *if hitboxes were tested at all*!!
//-----------------------------------------------------------------------------
bool CBaseEntity::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
{
return false;
}
void CBaseEntity::SetOwnerEntity( CBaseEntity* pOwner )
{
if ( m_hOwnerEntity.Get() != pOwner )
{
m_hOwnerEntity = pOwner;
CollisionRulesChanged();
}
}
void CBaseEntity::SetMoveType( MoveType_t val, MoveCollide_t moveCollide )
{
#ifdef _DEBUG
// Make sure the move type + move collide are compatible...
if ((val != MOVETYPE_FLY) && (val != MOVETYPE_FLYGRAVITY))
{
Assert( moveCollide == MOVECOLLIDE_DEFAULT );
}
if ( m_MoveType == MOVETYPE_VPHYSICS && val != m_MoveType )
{
if ( VPhysicsGetObject() && val != MOVETYPE_NONE )
{
// What am I supposed to do with the physics object if
// you're changing away from MOVETYPE_VPHYSICS without making the object
// shadow? This isn't likely to work, assert.
// You probably meant to call VPhysicsInitShadow() instead of VPhysicsInitNormal()!
Assert( VPhysicsGetObject()->GetShadowController() );
}
}
#endif
if ( m_MoveType == val )
{
m_MoveCollide = moveCollide;
return;
}
// This is needed to the removal of MOVETYPE_FOLLOW:
// We can't transition from follow to a different movetype directly
// or the leaf code will break.
Assert( !IsEffectActive( EF_BONEMERGE ) );
m_MoveType = val;
m_MoveCollide = moveCollide;
CollisionRulesChanged();
switch( m_MoveType )
{
case MOVETYPE_WALK:
{
SetSimulatedEveryTick( true );
SetAnimatedEveryTick( true );
}
break;
case MOVETYPE_STEP:
{
// This will probably go away once I remove the cvar that controls the test code
SetSimulatedEveryTick( g_bTestMoveTypeStepSimulation ? true : false );
SetAnimatedEveryTick( false );
}
break;
case MOVETYPE_FLY:
case MOVETYPE_FLYGRAVITY:
{
// Initialize our water state, because these movetypes care about transitions in/out of water
UpdateWaterState();
}
break;
default:
{
SetSimulatedEveryTick( true );
SetAnimatedEveryTick( false );
}
}
// This will probably go away or be handled in a better way once I remove the cvar that controls the test code
CheckStepSimulationChanged();
CheckHasGamePhysicsSimulation();
}
void CBaseEntity::Spawn( void )
{
}
CBaseEntity* CBaseEntity::Instance( const CBaseHandle &hEnt )
{
return gEntList.GetBaseEntity( hEnt );
}
int CBaseEntity::GetTransmitState( void )
{
edict_t *ed = edict();
if ( !ed )
return 0;
return ed->m_fStateFlags;
}
int CBaseEntity::SetTransmitState( int nFlag)
{
edict_t *ed = edict();
if ( !ed )
return 0;
// clear current flags = check ShouldTransmit()
ed->ClearTransmitState();
int oldFlags = ed->m_fStateFlags;
ed->m_fStateFlags |= nFlag;
// Tell the engine (used for a network backdoor optimization).
if ( (oldFlags & FL_EDICT_DONTSEND) != (ed->m_fStateFlags & FL_EDICT_DONTSEND) )
engine->NotifyEdictFlagsChange( entindex() );
return ed->m_fStateFlags;
}
int CBaseEntity::UpdateTransmitState()
{
// If you get this assert, you should be calling DispatchUpdateTransmitState
// instead of UpdateTransmitState.
Assert( g_nInsideDispatchUpdateTransmitState > 0 );
// If an object is the moveparent of something else, don't skip it just because it's marked EF_NODRAW or else
// the client won't have a proper origin for the child since the hierarchy won't be correctly transmitted down
if ( IsEffectActive( EF_NODRAW ) &&
!m_hMoveChild.Get() )
{
return SetTransmitState( FL_EDICT_DONTSEND );
}
if ( !IsEFlagSet( EFL_FORCE_CHECK_TRANSMIT ) )
{
if ( !GetModelIndex() || !GetModelName() )
{
return SetTransmitState( FL_EDICT_DONTSEND );
}
}
// Always send the world
if ( GetModelIndex() == 1 )
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
if ( IsEFlagSet( EFL_IN_SKYBOX ) )
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
// by default cull against PVS
return SetTransmitState( FL_EDICT_PVSCHECK );
}
int CBaseEntity::DispatchUpdateTransmitState()
{
edict_t *ed = edict();
if ( m_nTransmitStateOwnedCounter != 0 )
return ed ? ed->m_fStateFlags : 0;
g_nInsideDispatchUpdateTransmitState++;
int ret = UpdateTransmitState();
g_nInsideDispatchUpdateTransmitState--;
return ret;
}
//-----------------------------------------------------------------------------
// Purpose: Note, an entity can override the send table ( e.g., to send less data or to send minimal data for
// objects ( prob. players ) that are not in the pvs.
// Input : **ppSendTable -
// *recipient -
// *pvs -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
int CBaseEntity::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
int fFlags = DispatchUpdateTransmitState();
if ( fFlags & FL_EDICT_PVSCHECK )
{
return FL_EDICT_PVSCHECK;
}
else if ( fFlags & FL_EDICT_ALWAYS )
{
return FL_EDICT_ALWAYS;
}
else if ( fFlags & FL_EDICT_DONTSEND )
{
return FL_EDICT_DONTSEND;
}
// if ( IsToolRecording() )
// {
// return FL_EDICT_ALWAYS;
// }
CBaseEntity *pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
Assert( pRecipientEntity->IsPlayer() );
CBasePlayer *pRecipientPlayer = static_cast<CBasePlayer*>( pRecipientEntity );
// FIXME: Refactor once notion of "team" is moved into HL2 code
// Team rules may tell us that we should
if ( pRecipientPlayer->GetTeam() )
{
if ( pRecipientPlayer->GetTeam()->ShouldTransmitToPlayer( pRecipientPlayer, this ))
return FL_EDICT_ALWAYS;
}
/*#ifdef INVASION_DLL
// Check test network vis distance stuff. Eventually network LOD will do this.
float flTestDistSqr = pRecipientEntity->GetAbsOrigin().DistToSqr( WorldSpaceCenter() );
if ( flTestDistSqr > sv_netvisdist.GetFloat() * sv_netvisdist.GetFloat() )
return TRANSMIT_NO; // TODO doesn't work with HLTV
#endif*/
// by default do a PVS check
return FL_EDICT_PVSCHECK;
}
//-----------------------------------------------------------------------------
// Rules about which entities need to transmit along with me
//-----------------------------------------------------------------------------
void CBaseEntity::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
{
int index = entindex();
// Are we already marked for transmission?
if ( pInfo->m_pTransmitEdict->Get( index ) )
return;
CServerNetworkProperty *pNetworkParent = NetworkProp()->GetNetworkParent();
pInfo->m_pTransmitEdict->Set( index );
// HLTV/Replay need to know if this entity is culled by PVS limits
if ( pInfo->m_pTransmitAlways )
{
// in HLTV/Replay mode always transmit entitys with move-parents
// HLTV/Replay can't resolve the mode-parents relationships
if ( bAlways || pNetworkParent )
{
// tell HLTV/Replay that this entity is always transmitted
pInfo->m_pTransmitAlways->Set( index );
}
else
{
// HLTV/Replay will PVS cull this entity, so update the
// node/cluster infos if necessary
m_Network.RecomputePVSInformation();
}
}
// Force our aiment and move parent to be sent.
if ( pNetworkParent )
{
CBaseEntity *pMoveParent = pNetworkParent->GetBaseEntity();
pMoveParent->SetTransmit( pInfo, bAlways );
}
}
//-----------------------------------------------------------------------------
// Returns which skybox the entity is in
//-----------------------------------------------------------------------------
CSkyCamera *CBaseEntity::GetEntitySkybox()
{
int area = engine->GetArea( WorldSpaceCenter() );
CSkyCamera *pCur = GetSkyCameraList();
while ( pCur )
{
if ( engine->CheckAreasConnected( area, pCur->m_skyboxData.area ) )
return pCur;
pCur = pCur->m_pNext;
}
return NULL;
}
bool CBaseEntity::DetectInSkybox()
{
if ( GetEntitySkybox() != NULL )
{
AddEFlags( EFL_IN_SKYBOX );
return true;
}
RemoveEFlags( EFL_IN_SKYBOX );
return false;
}
//------------------------------------------------------------------------------
// Computes a world-aligned bounding box that surrounds everything in the entity
//------------------------------------------------------------------------------
void CBaseEntity::ComputeWorldSpaceSurroundingBox( Vector *pMins, Vector *pMaxs )
{
// Should never get here.. only use USE_GAME_CODE with bounding boxes
// if you have an implementation for this method
Assert( 0 );
}
//------------------------------------------------------------------------------
// Purpose : If name exists returns name, otherwise returns classname
// Input :
// Output :
//------------------------------------------------------------------------------
const char *CBaseEntity::GetDebugName(void)
{
if ( this == NULL )
return "<<null>>";
if ( m_iName.Get() != NULL_STRING )
2013-12-02 19:31:46 -08:00
{
return STRING(m_iName.Get());
2013-12-02 19:31:46 -08:00
}
else
{
return STRING(m_iClassname);
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseEntity::DrawInputOverlay(const char *szInputName, CBaseEntity *pCaller, variant_t Value)
{
char bigstring[1024];
if ( Value.FieldType() == FIELD_INTEGER )
{
Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s,%d) <-- (%s)\n", gpGlobals->curtime, szInputName, Value.Int(), pCaller ? pCaller->GetDebugName() : NULL);
}
else if ( Value.FieldType() == FIELD_STRING )
{
Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s,%s) <-- (%s)\n", gpGlobals->curtime, szInputName, Value.String(), pCaller ? pCaller->GetDebugName() : NULL);
}
else
{
Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s) <-- (%s)\n", gpGlobals->curtime, szInputName, pCaller ? pCaller->GetDebugName() : NULL);
}
AddTimedOverlay(bigstring, 10.0);
if ( Value.FieldType() == FIELD_INTEGER )
{
DevMsg( 2, "input: (%s,%d) -> (%s,%s), from (%s)\n", szInputName, Value.Int(), STRING(m_iClassname), GetDebugName(), pCaller ? pCaller->GetDebugName() : NULL);
}
else if ( Value.FieldType() == FIELD_STRING )
{
DevMsg( 2, "input: (%s,%s) -> (%s,%s), from (%s)\n", szInputName, Value.String(), STRING(m_iClassname), GetDebugName(), pCaller ? pCaller->GetDebugName() : NULL);
}
else
DevMsg( 2, "input: (%s) -> (%s,%s), from (%s)\n", szInputName, STRING(m_iClassname), GetDebugName(), pCaller ? pCaller->GetDebugName() : NULL);
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseEntity::DrawOutputOverlay(CEventAction *ev)
{
// Print to entity
char bigstring[1024];
if ( ev->m_flDelay )
{
Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s) --> (%s),%.1f) \n", gpGlobals->curtime, STRING(ev->m_iTargetInput), STRING(ev->m_iTarget), ev->m_flDelay);
}
else
{
Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s) --> (%s)\n", gpGlobals->curtime, STRING(ev->m_iTargetInput), STRING(ev->m_iTarget));
}
AddTimedOverlay(bigstring, 10.0);
// Now print to the console
if ( ev->m_flDelay )
{
DevMsg( 2, "output: (%s,%s) -> (%s,%s,%.1f)\n", STRING(m_iClassname), GetDebugName(), STRING(ev->m_iTarget), STRING(ev->m_iTargetInput), ev->m_flDelay );
}
else
{
DevMsg( 2, "output: (%s,%s) -> (%s,%s)\n", STRING(m_iClassname), GetDebugName(), STRING(ev->m_iTarget), STRING(ev->m_iTargetInput) );
}
}
//-----------------------------------------------------------------------------
// Entity events... these are events targetted to a particular entity
// Each event defines its own well-defined event data structure
//-----------------------------------------------------------------------------
void CBaseEntity::OnEntityEvent( EntityEvent_t event, void *pEventData )
{
switch( event )
{
case ENTITY_EVENT_WATER_TOUCH:
{
int nContents = (int)pEventData;
if ( !nContents || (nContents & CONTENTS_WATER) )
{
++m_nWaterTouch;
}
if ( nContents & CONTENTS_SLIME )
{
++m_nSlimeTouch;
}
}
break;
case ENTITY_EVENT_WATER_UNTOUCH:
{
int nContents = (int)pEventData;
if ( !nContents || (nContents & CONTENTS_WATER) )
{
--m_nWaterTouch;
}
if ( nContents & CONTENTS_SLIME )
{
--m_nSlimeTouch;
}
}
break;
default:
return;
}
// Only do this for vphysics objects
if ( GetMoveType() != MOVETYPE_VPHYSICS )
return;
int nNewContents = 0;
if ( m_nWaterTouch > 0 )
{
nNewContents |= CONTENTS_WATER;
}
if ( m_nSlimeTouch > 0 )
{
nNewContents |= CONTENTS_SLIME;
}
if (( nNewContents & MASK_WATER ) == 0)
{
SetWaterLevel( 0 );
SetWaterType( CONTENTS_EMPTY );
return;
}
SetWaterLevel( 1 );
SetWaterType( nNewContents );
}
ConVar ent_messages_draw( "ent_messages_draw", "0", FCVAR_CHEAT, "Visualizes all entity input/output activity." );
//-----------------------------------------------------------------------------
// Purpose: calls the appropriate message mapped function in the entity according
// to the fired action.
// Input : char *szInputName - input destination
// *pActivator - entity which initiated this sequence of actions
// *pCaller - entity from which this event is sent
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID )
{
if ( ent_messages_draw.GetBool() )
{
if ( pCaller != NULL )
{
NDebugOverlay::Line( pCaller->GetAbsOrigin(), GetAbsOrigin(), 255, 255, 255, false, 3 );
NDebugOverlay::Box( pCaller->GetAbsOrigin(), Vector(-4, -4, -4), Vector(4, 4, 4), 255, 0, 0, 0, 3 );
}
NDebugOverlay::Text( GetAbsOrigin(), szInputName, false, 3 );
NDebugOverlay::Box( GetAbsOrigin(), Vector(-4, -4, -4), Vector(4, 4, 4), 0, 255, 0, 0, 3 );
}
// loop through the data description list, restoring each data desc block
for ( datamap_t *dmap = GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
// search through all the actions in the data description, looking for a match
for ( int i = 0; i < dmap->dataNumFields; i++ )
{
if ( dmap->dataDesc[i].flags & FTYPEDESC_INPUT )
{
if ( !Q_stricmp(dmap->dataDesc[i].externalName, szInputName) )
{
// found a match
// mapper debug message
DevMsg( 2, "(%0.2f) input %s: %s.%s(%s)\n", gpGlobals->curtime, pCaller ? STRING(pCaller->m_iName.Get()) : "<NULL>", GetDebugName(), szInputName, Value.String() );
2013-12-02 19:31:46 -08:00
ADD_DEBUG_HISTORY( HISTORY_ENTITY_IO, szBuffer );
if (m_debugOverlays & OVERLAY_MESSAGE_BIT)
{
DrawInputOverlay(szInputName,pCaller,Value);
}
// convert the value if necessary
if ( Value.FieldType() != dmap->dataDesc[i].fieldType )
{
if ( !(Value.FieldType() == FIELD_VOID && dmap->dataDesc[i].fieldType == FIELD_STRING) ) // allow empty strings
{
#ifdef MAPBASE
// Activator, etc. support for EHANDLE convert
if ( !Value.Convert( (fieldtype_t)dmap->dataDesc[i].fieldType, this, pActivator, pCaller ) )
{
bool bBadConversion = true;
// Attempt to convert to string and back.
// Almost all field types support being converted to a string, and many support being parsed from a string too.
fieldtype_t originalfield = Value.FieldType();
if (Value.Convert(FIELD_STRING))
{
bBadConversion = !(Value.Convert((fieldtype_t)dmap->dataDesc[i].fieldType, this, pActivator, pCaller));
if (!bBadConversion)
{
// Actual support should be added for each field, but if it works, it works.
// Warning against it only matters if you're a programmer and want to add support for each field.
// Only send a warning in dev mode.
DevWarning("!! Had to convert to string and back\n"
"!! Source Field Type: %i, Target Field Type: %i\n",
originalfield, dmap->dataDesc[i].fieldType);
}
}
if (bBadConversion)
{
Warning( "!! ERROR: bad input/output link:\n!! Unable to convert value \"%s\" from %s (%s) to field type %i\n!! Target Entity: %s (%s), Input: %s\n",
Value.GetDebug(),
( pCaller != NULL ) ? STRING(pCaller->m_iClassname) : "<null>",
( pCaller != NULL ) ? STRING(pCaller->m_iName.Get()) : "<null>",
dmap->dataDesc[i].fieldType,
STRING(m_iClassname), GetDebugName(), szInputName );
return false;
}
}
#else
2013-12-02 19:31:46 -08:00
if ( !Value.Convert( (fieldtype_t)dmap->dataDesc[i].fieldType ) )
{
// bad conversion
Warning( "!! ERROR: bad input/output link:\n!! %s(%s,%s) doesn't match type from %s(%s)\n",
STRING(m_iClassname), GetDebugName(), szInputName,
( pCaller != NULL ) ? STRING(pCaller->m_iClassname) : "<null>",
( pCaller != NULL ) ? STRING(pCaller->m_iName.Get()) : "<null>" );
2013-12-02 19:31:46 -08:00
return false;
}
#endif
2013-12-02 19:31:46 -08:00
}
}
// call the input handler, or if there is none just set the value
inputfunc_t pfnInput = dmap->dataDesc[i].inputFunc;
if ( pfnInput )
{
// Package the data into a struct for passing to the input handler.
inputdata_t data;
data.pActivator = pActivator;
data.pCaller = pCaller;
data.value = Value;
data.nOutputID = outputID;
// Now, see if there's a function named Input<Name of Input> in this entity's script file.
// If so, execute it and let it decide whether to allow the default behavior to also execute.
bool bCallInputFunc = true; // Always assume default behavior (do call the input function)
ScriptVariant_t functionReturn;
if ( m_ScriptScope.IsInitialized() )
{
char szScriptFunctionName[255];
Q_strcpy( szScriptFunctionName, "Input" );
Q_strcat( szScriptFunctionName, szInputName, 255 );
g_pScriptVM->SetValue( "activator", ( pActivator ) ? ScriptVariant_t( pActivator->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
g_pScriptVM->SetValue( "caller", ( pCaller ) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
#ifdef MAPBASE_VSCRIPT
Value.SetScriptVariant( functionReturn );
g_pScriptVM->SetValue( "parameter", functionReturn );
#endif
if( CallScriptFunction( szScriptFunctionName, &functionReturn ) )
{
bCallInputFunc = functionReturn.m_bool;
}
}
if( bCallInputFunc )
{
(this->*pfnInput)( data );
}
if ( m_ScriptScope.IsInitialized() )
{
g_pScriptVM->ClearValue( "activator" );
g_pScriptVM->ClearValue( "caller" );
#ifdef MAPBASE_VSCRIPT
g_pScriptVM->ClearValue( "parameter" );
#endif
}
2013-12-02 19:31:46 -08:00
}
else if ( dmap->dataDesc[i].flags & FTYPEDESC_KEY )
{
// set the value directly
Value.SetOther( ((char*)this) + dmap->dataDesc[i].fieldOffset[ TD_OFFSET_NORMAL ]);
// TODO: if this becomes evil and causes too many full entity updates, then we should make
// a macro like this:
//
// define MAKE_INPUTVAR(x) void Note##x##Modified() { x.GetForModify(); }
//
// Then the datadesc points at that function and we call it here. The only pain is to add
// that function for all the DEFINE_INPUT calls.
NetworkStateChanged();
}
return true;
}
}
}
}
DevMsg( 2, "unhandled input: (%s) -> (%s,%s)\n", szInputName, STRING(m_iClassname), GetDebugName()/*,", from (%s,%s)" STRING(pCaller->m_iClassname), STRING(pCaller->m_iName.Get())*/ );
2013-12-02 19:31:46 -08:00
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for the entity alpha.
// Input : nAlpha - Alpha value (0 - 255).
//-----------------------------------------------------------------------------
void CBaseEntity::InputAlpha( inputdata_t &inputdata )
{
SetRenderColorA( clamp( inputdata.value.Int(), 0, 255 ) );
}
//-----------------------------------------------------------------------------
// Activate alternative sorting
//-----------------------------------------------------------------------------
void CBaseEntity::InputAlternativeSorting( inputdata_t &inputdata )
{
m_bAlternateSorting = inputdata.value.Bool();
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for the entity color. Ignores alpha since that is handled
// by a separate input handler.
// Input : Color32 new value for color (alpha is ignored).
//-----------------------------------------------------------------------------
void CBaseEntity::InputColor( inputdata_t &inputdata )
{
color32 clr = inputdata.value.Color32();
SetRenderColor( clr.r, clr.g, clr.b );
}
//-----------------------------------------------------------------------------
// Purpose: Called whenever the entity is 'Used'. This can be when a player hits
// use, or when an entity targets it without an output name (legacy entities)
//-----------------------------------------------------------------------------
void CBaseEntity::InputUse( inputdata_t &inputdata )
{
Use( inputdata.pActivator, inputdata.pCaller, (USE_TYPE)inputdata.nOutputID, 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Reads an output variable, by string name, from an entity
// Input : char *varName - the string name of the variable
// variant_t *var - the value is stored here
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseEntity::ReadKeyField( const char *varName, variant_t *var )
{
if ( !varName )
return false;
// loop through the data description list, restoring each data desc block
for ( datamap_t *dmap = GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
// search through all the readable fields in the data description, looking for a match
for ( int i = 0; i < dmap->dataNumFields; i++ )
{
if ( dmap->dataDesc[i].flags & (FTYPEDESC_OUTPUT | FTYPEDESC_KEY) )
{
if ( !Q_stricmp(dmap->dataDesc[i].externalName, varName) )
{
var->Set( dmap->dataDesc[i].fieldType, ((char*)this) + dmap->dataDesc[i].fieldOffset[ TD_OFFSET_NORMAL ] );
return true;
}
}
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the damage filter on the object
//-----------------------------------------------------------------------------
void CBaseEntity::InputEnableDamageForces( inputdata_t &inputdata )
{
RemoveEFlags( EFL_NO_DAMAGE_FORCES );
}
void CBaseEntity::InputDisableDamageForces( inputdata_t &inputdata )
{
AddEFlags( EFL_NO_DAMAGE_FORCES );
}
//-----------------------------------------------------------------------------
// Purpose: Sets the damage filter on the object
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetDamageFilter( inputdata_t &inputdata )
{
// Get a handle to my damage filter entity if there is one.
m_iszDamageFilterName = inputdata.value.StringID();
if ( m_iszDamageFilterName != NULL_STRING )
{
m_hDamageFilter = gEntList.FindEntityByName( NULL, m_iszDamageFilterName );
}
else
{
m_hDamageFilter = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose: Dispatch effects on this entity
//-----------------------------------------------------------------------------
void CBaseEntity::InputDispatchEffect( inputdata_t &inputdata )
{
const char *sEffect = inputdata.value.String();
if ( sEffect && sEffect[0] )
{
CEffectData data;
GetInputDispatchEffectPosition( sEffect, data.m_vOrigin, data.m_vAngles );
AngleVectors( data.m_vAngles, &data.m_vNormal );
data.m_vStart = data.m_vOrigin;
data.m_nEntIndex = entindex();
// Clip off leading attachment point numbers
while ( sEffect[0] >= '0' && sEffect[0] <= '9' )
{
sEffect++;
}
DispatchEffect( sEffect, data );
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the origin at which to play an inputted dispatcheffect
//-----------------------------------------------------------------------------
void CBaseEntity::GetInputDispatchEffectPosition( const char *sInputString, Vector &pOrigin, QAngle &pAngles )
{
pOrigin = GetAbsOrigin();
pAngles = GetAbsAngles();
}
//-----------------------------------------------------------------------------
// Purpose: Marks the entity for deletion
//-----------------------------------------------------------------------------
void CBaseEntity::InputKill( inputdata_t &inputdata )
{
// tell owner ( if any ) that we're dead.This is mostly for NPCMaker functionality.
CBaseEntity *pOwner = GetOwnerEntity();
if ( pOwner )
{
pOwner->DeathNotice( this );
SetOwnerEntity( NULL );
}
#ifdef MAPBASE
m_OnKilled.FireOutput( inputdata.pActivator, this );
#endif
2013-12-02 19:31:46 -08:00
UTIL_Remove( this );
}
void CBaseEntity::InputKillHierarchy( inputdata_t &inputdata )
{
CBaseEntity *pChild, *pNext;
for ( pChild = FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
pChild->InputKillHierarchy( inputdata );
}
// tell owner ( if any ) that we're dead. This is mostly for NPCMaker functionality.
CBaseEntity *pOwner = GetOwnerEntity();
if ( pOwner )
{
pOwner->DeathNotice( this );
SetOwnerEntity( NULL );
}
#ifdef MAPBASE
m_OnKilled.FireOutput( inputdata.pActivator, this );
#endif
2013-12-02 19:31:46 -08:00
UTIL_Remove( this );
}
//------------------------------------------------------------------------------
// Purpose: Input handler for changing this entity's movement parent.
//------------------------------------------------------------------------------
void CBaseEntity::InputSetParent( inputdata_t &inputdata )
{
// If we had a parent attachment, clear it, because it's no longer valid.
if ( m_iParentAttachment )
{
m_iParentAttachment = 0;
}
SetParent( inputdata.value.StringID(), inputdata.pActivator );
}
//------------------------------------------------------------------------------
// Purpose:
//------------------------------------------------------------------------------
void CBaseEntity::SetParentAttachment( const char *szInputName, const char *szAttachment, bool bMaintainOffset )
{
// Must have a parent
if ( !m_pParent )
{
Warning("ERROR: Tried to %s for entity %s (%s), but it has no parent.\n", szInputName, GetClassname(), GetDebugName() );
return;
}
// Valid only on CBaseAnimating
CBaseAnimating *pAnimating = m_pParent->GetBaseAnimating();
if ( !pAnimating )
{
Warning("ERROR: Tried to %s for entity %s (%s), but its parent has no model.\n", szInputName, GetClassname(), GetDebugName() );
return;
}
// Lookup the attachment
int iAttachment = pAnimating->LookupAttachment( szAttachment );
if ( iAttachment <= 0 )
{
Warning("ERROR: Tried to %s for entity %s (%s), but it has no attachment named %s.\n", szInputName, GetClassname(), GetDebugName(), szAttachment );
return;
}
m_iParentAttachment = iAttachment;
SetParent( m_pParent, m_iParentAttachment );
// Now move myself directly onto the attachment point
SetMoveType( MOVETYPE_NONE );
if ( !bMaintainOffset )
{
SetLocalOrigin( vec3_origin );
SetLocalAngles( vec3_angle );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for changing this entity's movement parent's attachment point
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetParentAttachment( inputdata_t &inputdata )
{
SetParentAttachment( "SetParentAttachment", inputdata.value.String(), false );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for changing this entity's movement parent's attachment point
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetParentAttachmentMaintainOffset( inputdata_t &inputdata )
{
SetParentAttachment( "SetParentAttachmentMaintainOffset", inputdata.value.String(), true );
}
//------------------------------------------------------------------------------
// Purpose: Input handler for clearing this entity's movement parent.
//------------------------------------------------------------------------------
void CBaseEntity::InputClearParent( inputdata_t &inputdata )
{
SetParent( NULL );
}
//------------------------------------------------------------------------------
// Purpose : Returns velcocity of base entity. If physically simulated gets
// velocity from physics object
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseEntity::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
{
if (GetMoveType()==MOVETYPE_VPHYSICS && m_pPhysicsObject)
{
m_pPhysicsObject->GetVelocity(vVelocity,vAngVelocity);
}
else
{
if (vVelocity != NULL)
{
*vVelocity = GetAbsVelocity();
}
if (vAngVelocity != NULL)
{
QAngle tmp = GetLocalAngularVelocity();
QAngleToAngularImpulse( tmp, *vAngVelocity );
}
}
}
bool CBaseEntity::IsMoving()
{
Vector velocity;
GetVelocity( &velocity, NULL );
return velocity != vec3_origin;
}
//-----------------------------------------------------------------------------
// Purpose: Retrieves the coordinate frame for this entity.
// Input : forward - Receives the entity's forward vector.
// right - Receives the entity's right vector.
// up - Receives the entity's up vector.
//-----------------------------------------------------------------------------
void CBaseEntity::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const
{
// This call is necessary to cause m_rgflCoordinateFrame to be recomputed
const matrix3x4_t &entityToWorld = EntityToWorldTransform();
if (pForward != NULL)
{
MatrixGetColumn( entityToWorld, 0, *pForward );
}
if (pRight != NULL)
{
MatrixGetColumn( entityToWorld, 1, *pRight );
*pRight *= -1.0f;
}
if (pUp != NULL)
{
MatrixGetColumn( entityToWorld, 2, *pUp );
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the model, validates that it's of the appropriate type
// Input : *szModelName -
//-----------------------------------------------------------------------------
void CBaseEntity::SetModel( const char *szModelName )
{
int modelIndex = modelinfo->GetModelIndex( szModelName );
const model_t *model = modelinfo->GetModel( modelIndex );
if ( model && modelinfo->GetModelType( model ) != mod_brush )
{
Msg( "Setting CBaseEntity to non-brush model %s\n", szModelName );
}
UTIL_SetModel( this, szModelName );
}
//------------------------------------------------------------------------------
CStudioHdr *CBaseEntity::OnNewModel()
{
// Do nothing.
return NULL;
}
//================================================================================
// TEAM HANDLING
//================================================================================
void CBaseEntity::InputSetTeam( inputdata_t &inputdata )
{
ChangeTeam( inputdata.value.Int() );
}
//-----------------------------------------------------------------------------
// Purpose: Put the entity in the specified team
//-----------------------------------------------------------------------------
void CBaseEntity::ChangeTeam( int iTeamNum )
{
m_iTeamNum = iTeamNum;
}
//-----------------------------------------------------------------------------
// Get the Team this entity is on
//-----------------------------------------------------------------------------
CTeam *CBaseEntity::GetTeam( void ) const
{
return GetGlobalTeam( m_iTeamNum );
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if these players are both in at least one team together
//-----------------------------------------------------------------------------
bool CBaseEntity::InSameTeam( CBaseEntity *pEntity ) const
{
if ( !pEntity )
return false;
return ( pEntity->GetTeam() == GetTeam() );
}
//-----------------------------------------------------------------------------
// Purpose: Returns the string name of the players team
//-----------------------------------------------------------------------------
const char *CBaseEntity::TeamID( void ) const
{
if ( GetTeam() == NULL )
return "";
return GetTeam()->GetName();
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if the player is on the same team
//-----------------------------------------------------------------------------
bool CBaseEntity::IsInTeam( CTeam *pTeam ) const
{
return ( GetTeam() == pTeam );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseEntity::GetTeamNumber( void ) const
{
return m_iTeamNum;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseEntity::IsInAnyTeam( void ) const
{
return ( GetTeam() != NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Returns the type of damage that this entity inflicts.
//-----------------------------------------------------------------------------
int CBaseEntity::GetDamageType() const
{
return DMG_GENERIC;
}
//-----------------------------------------------------------------------------
// process notification
//-----------------------------------------------------------------------------
void CBaseEntity::NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params )
{
}
//-----------------------------------------------------------------------------
// Purpose: Holds an entity's previous abs origin and angles at the time of
// teleportation. Used for child & constrained entity fixup to prevent
// lazy updates of abs origins and angles from messing things up.
//-----------------------------------------------------------------------------
struct TeleportListEntry_t
{
CBaseEntity *pEntity;
Vector prevAbsOrigin;
QAngle prevAbsAngles;
};
static void TeleportEntity( CBaseEntity *pSourceEntity, TeleportListEntry_t &entry, const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
{
CBaseEntity *pTeleport = entry.pEntity;
Vector prevOrigin = entry.prevAbsOrigin;
QAngle prevAngles = entry.prevAbsAngles;
int nSolidFlags = pTeleport->GetSolidFlags();
pTeleport->AddSolidFlags( FSOLID_NOT_SOLID );
// I'm teleporting myself
if ( pSourceEntity == pTeleport )
{
if ( newAngles )
{
pTeleport->SetLocalAngles( *newAngles );
if ( pTeleport->IsPlayer() )
{
CBasePlayer *pPlayer = (CBasePlayer *)pTeleport;
pPlayer->SnapEyeAngles( *newAngles );
}
}
if ( newVelocity )
{
pTeleport->SetAbsVelocity( *newVelocity );
pTeleport->SetBaseVelocity( vec3_origin );
}
if ( newPosition )
{
pTeleport->IncrementInterpolationFrame();
UTIL_SetOrigin( pTeleport, *newPosition );
}
}
else
{
// My parent is teleporting, just update my position & physics
pTeleport->CalcAbsolutePosition();
}
IPhysicsObject *pPhys = pTeleport->VPhysicsGetObject();
bool rotatePhysics = false;
// handle physics objects / shadows
if ( pPhys )
{
if ( newVelocity )
{
pPhys->SetVelocity( newVelocity, NULL );
}
const QAngle *rotAngles = &pTeleport->GetAbsAngles();
// don't rotate physics on players or bbox entities
if (pTeleport->IsPlayer() || pTeleport->GetSolid() == SOLID_BBOX )
{
rotAngles = &vec3_angle;
}
else
{
rotatePhysics = true;
}
pPhys->SetPosition( pTeleport->GetAbsOrigin(), *rotAngles, true );
}
g_pNotify->ReportTeleportEvent( pTeleport, prevOrigin, prevAngles, rotatePhysics );
pTeleport->SetSolidFlags( nSolidFlags );
}
//-----------------------------------------------------------------------------
// Purpose: Recurses an entity hierarchy and fills out a list of all entities
// in the hierarchy with their current origins and angles.
//
// This list is necessary to keep lazy updates of abs origins and angles
// from messing up our child/constrained entity fixup.
//-----------------------------------------------------------------------------
static void BuildTeleportList_r( CBaseEntity *pTeleport, CUtlVector<TeleportListEntry_t> &teleportList )
{
TeleportListEntry_t entry;
entry.pEntity = pTeleport;
entry.prevAbsOrigin = pTeleport->GetAbsOrigin();
entry.prevAbsAngles = pTeleport->GetAbsAngles();
teleportList.AddToTail( entry );
CBaseEntity *pList = pTeleport->FirstMoveChild();
while ( pList )
{
BuildTeleportList_r( pList, teleportList );
pList = pList->NextMovePeer();
}
}
static CUtlVector<CBaseEntity *> g_TeleportStack;
void CBaseEntity::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
{
if ( g_TeleportStack.Find( this ) >= 0 )
return;
int index = g_TeleportStack.AddToTail( this );
CUtlVector<TeleportListEntry_t> teleportList;
BuildTeleportList_r( this, teleportList );
int i;
for ( i = 0; i < teleportList.Count(); i++)
{
TeleportEntity( this, teleportList[i], newPosition, newAngles, newVelocity );
}
for (i = 0; i < teleportList.Count(); i++)
{
teleportList[i].pEntity->CollisionRulesChanged();
}
if ( IsPlayer() )
{
// Tell the client being teleported
IGameEvent *event = gameeventmanager->CreateEvent( "base_player_teleported" );
if ( event )
{
event->SetInt( "entindex", entindex() );
gameeventmanager->FireEventClientSide( event );
}
}
2013-12-02 19:31:46 -08:00
Assert( g_TeleportStack[index] == this );
g_TeleportStack.FastRemove( index );
// FIXME: add an initializer function to StepSimulationData
StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
if (step)
{
Q_memset( step, 0, sizeof( *step ) );
}
}
// Stuff implemented for weapon prediction code
void CBaseEntity::SetSize( const Vector &vecMin, const Vector &vecMax )
{
UTIL_SetSize( this, vecMin, vecMax );
}
CStudioHdr *ModelSoundsCache_LoadModel( const char *filename )
{
// Load the file
int idx = engine->PrecacheModel( filename, true );
if ( idx != -1 )
{
model_t *mdl = (model_t *)modelinfo->GetModel( idx );
if ( mdl )
{
CStudioHdr *studioHdr = new CStudioHdr( modelinfo->GetStudiomodel( mdl ), mdlcache );
if ( studioHdr->IsValid() )
{
return studioHdr;
}
}
}
return NULL;
}
void ModelSoundsCache_FinishModel( CStudioHdr *hdr )
{
Assert( hdr );
delete hdr;
}
void ModelSoundsCache_PrecacheScriptSound( const char *soundname )
{
CBaseEntity::PrecacheScriptSound( soundname );
}
static CUtlCachedFileData< CModelSoundsCache > g_ModelSoundsCache( "modelsounds.cache", MODELSOUNDSCACHE_VERSION, 0, UTL_CACHED_FILE_USE_FILESIZE, false );
void ClearModelSoundsCache()
{
if ( IsX360() )
{
return;
}
g_ModelSoundsCache.Reload();
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool ModelSoundsCacheInit()
{
if ( IsX360() )
{
return true;
}
return g_ModelSoundsCache.Init();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void ModelSoundsCacheShutdown()
{
if ( IsX360() )
{
return;
}
g_ModelSoundsCache.Shutdown();
}
static CUtlSymbolTable g_ModelSoundsSymbolHelper( 0, 32, true );
class CModelSoundsCacheSaver: public CAutoGameSystem
{
public:
CModelSoundsCacheSaver( const char *name ) : CAutoGameSystem( name )
{
}
virtual void LevelInitPostEntity()
{
if ( IsX360() )
{
return;
}
if ( g_ModelSoundsCache.IsDirty() )
{
g_ModelSoundsCache.Save();
}
}
virtual void LevelShutdownPostEntity()
{
if ( IsX360() )
{
// Unforunate that this table must persist through duration of level.
// It is the common case that PrecacheModel() still gets called (and needs this table),
// after LevelInitPostEntity, as PrecacheModel() redundantly precaches.
g_ModelSoundsSymbolHelper.RemoveAll();
return;
}
if ( g_ModelSoundsCache.IsDirty() )
{
g_ModelSoundsCache.Save();
}
}
};
static CModelSoundsCacheSaver g_ModelSoundsCacheSaver( "CModelSoundsCacheSaver" );
//#define WATCHACCESS
#if defined( WATCHACCESS )
static bool g_bWatching = true;
void ModelLogFunc( const char *fileName, const char *accessType )
{
if ( g_bWatching && !CBaseEntity::IsPrecacheAllowed() )
{
if ( Q_stristr( fileName, ".vcd" ) )
{
Msg( "%s\n", fileName );
}
}
}
class CWatchForModelAccess: public CAutoGameSystem
{
public:
virtual bool Init()
{
filesystem->AddLoggingFunc(&ModelLogFunc);
return true;
}
virtual void Shutdown()
{
filesystem->RemoveLoggingFunc(&ModelLogFunc);
}
};
static CWatchForModelAccess g_WatchForModels;
#endif
// HACK: This must match the #define in cl_animevent.h in the client .dll code!!!
#define CL_EVENT_SOUND 5004
#define CL_EVENT_FOOTSTEP_LEFT 6004
#define CL_EVENT_FOOTSTEP_RIGHT 6005
#define CL_EVENT_MFOOTSTEP_LEFT 6006
#define CL_EVENT_MFOOTSTEP_RIGHT 6007
//-----------------------------------------------------------------------------
// Precache model sound. Requires a local symbol table to prevent
// a very expensive call to PrecacheScriptSound().
//-----------------------------------------------------------------------------
void CBaseEntity::PrecacheSoundHelper( const char *pName )
{
if ( !IsX360() )
{
// 360 only
Assert( 0 );
return;
}
if ( !pName || !pName[0] )
{
return;
}
if ( UTL_INVAL_SYMBOL == g_ModelSoundsSymbolHelper.Find( pName ) )
{
g_ModelSoundsSymbolHelper.AddString( pName );
// very expensive, only call when required
PrecacheScriptSound( pName );
}
}
//-----------------------------------------------------------------------------
// Precache model components
//-----------------------------------------------------------------------------
void CBaseEntity::PrecacheModelComponents( int nModelIndex )
{
model_t *pModel = (model_t *)modelinfo->GetModel( nModelIndex );
if ( !pModel || modelinfo->GetModelType( pModel ) != mod_studio )
{
return;
}
// sounds
if ( IsPC() )
{
const char *name = modelinfo->GetModelName( pModel );
if ( !g_ModelSoundsCache.EntryExists( name ) )
{
char extension[ 8 ];
Q_ExtractFileExtension( name, extension, sizeof( extension ) );
if ( Q_stristr( extension, "mdl" ) )
{
DevMsg( 2, "Late precache of %s, need to rebuild modelsounds.cache\n", name );
}
else
{
if ( !extension[ 0 ] )
{
Warning( "Precache of %s ambigious (no extension specified)\n", name );
}
else
{
Warning( "Late precache of %s (file missing?)\n", name );
}
return;
}
}
CModelSoundsCache *entry = g_ModelSoundsCache.Get( name );
Assert( entry );
if ( entry )
{
entry->PrecacheSoundList();
}
}
// particles
{
// Check keyvalues for auto-emitting particles
KeyValues *pModelKeyValues = new KeyValues("");
KeyValues::AutoDelete autodelete_pModelKeyValues( pModelKeyValues );
if ( pModelKeyValues->LoadFromBuffer( modelinfo->GetModelName( pModel ), modelinfo->GetModelKeyValueText( pModel ) ) )
{
KeyValues *pParticleEffects = pModelKeyValues->FindKey("Particles");
if ( pParticleEffects )
{
// Start grabbing the sounds and slotting them in
for ( KeyValues *pSingleEffect = pParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() )
{
const char *pParticleEffectName = pSingleEffect->GetString( "name", "" );
PrecacheParticleSystem( pParticleEffectName );
}
}
}
}
// model anim event owned components
{
// Check animevents for particle events
CStudioHdr studioHdr( modelinfo->GetStudiomodel( pModel ), mdlcache );
if ( studioHdr.IsValid() )
{
// force animation event resolution!!!
VerifySequenceIndex( &studioHdr );
int nSeqCount = studioHdr.GetNumSeq();
for ( int i = 0; i < nSeqCount; ++i )
{
mstudioseqdesc_t &seq = studioHdr.pSeqdesc( i );
int nEventCount = seq.numevents;
for ( int j = 0; j < nEventCount; ++j )
{
mstudioevent_t *pEvent = seq.pEvent( j );
if ( !( pEvent->type & AE_TYPE_NEWEVENTSYSTEM ) || ( pEvent->type & AE_TYPE_CLIENT ) )
{
if ( pEvent->event == AE_CL_CREATE_PARTICLE_EFFECT )
{
char token[256];
const char *pOptions = pEvent->pszOptions();
nexttoken( token, pOptions, ' ', sizeof( token ) );
2013-12-02 19:31:46 -08:00
if ( token )
{
PrecacheParticleSystem( token );
}
continue;
}
}
// 360 precaches the model sounds now at init time, the cost is now ~250 msecs worst case.
// The disk based solution was not needed. Now at runtime partly due to already crawling the sequences
// for the particles and the expensive part was redundant PrecacheScriptSound(), which is now prevented
// by a local symbol table.
if ( IsX360() )
{
switch ( pEvent->event )
{
default:
{
if ( ( pEvent->type & AE_TYPE_NEWEVENTSYSTEM ) && ( pEvent->event == AE_SV_PLAYSOUND ) )
{
PrecacheSoundHelper( pEvent->pszOptions() );
}
}
break;
case CL_EVENT_FOOTSTEP_LEFT:
case CL_EVENT_FOOTSTEP_RIGHT:
{
char soundname[256];
char const *options = pEvent->pszOptions();
if ( !options || !options[0] )
{
options = "NPC_CombineS";
}
Q_snprintf( soundname, sizeof( soundname ), "%s.RunFootstepLeft", options );
PrecacheSoundHelper( soundname );
Q_snprintf( soundname, sizeof( soundname ), "%s.RunFootstepRight", options );
PrecacheSoundHelper( soundname );
Q_snprintf( soundname, sizeof( soundname ), "%s.FootstepLeft", options );
PrecacheSoundHelper( soundname );
Q_snprintf( soundname, sizeof( soundname ), "%s.FootstepRight", options );
PrecacheSoundHelper( soundname );
}
break;
case AE_CL_PLAYSOUND:
{
if ( !( pEvent->type & AE_TYPE_CLIENT ) )
break;
if ( pEvent->pszOptions()[0] )
{
PrecacheSoundHelper( pEvent->pszOptions() );
}
else
{
Warning( "-- Error --: empty soundname, .qc error on AE_CL_PLAYSOUND in model %s, sequence %s, animevent # %i\n",
studioHdr.GetRenderHdr()->pszName(), seq.pszLabel(), j+1 );
}
}
break;
case CL_EVENT_SOUND:
case SCRIPT_EVENT_SOUND:
case SCRIPT_EVENT_SOUND_VOICE:
{
PrecacheSoundHelper( pEvent->pszOptions() );
}
break;
}
}
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Add model to level precache list
// Input : *name - model name
// Output : int -- model index for model
//-----------------------------------------------------------------------------
int CBaseEntity::PrecacheModel( const char *name, bool bPreload )
{
if ( !name || !*name )
{
Msg( "Attempting to precache model, but model name is NULL\n");
return -1;
}
// Warn on out of order precache
if ( !CBaseEntity::IsPrecacheAllowed() )
{
if ( !engine->IsModelPrecached( name ) )
{
Assert( !"CBaseEntity::PrecacheModel: too late" );
Warning( "Late precache of %s\n", name );
}
}
#if defined( WATCHACCESS )
else
{
g_bWatching = false;
}
#endif
int idx = engine->PrecacheModel( name, bPreload );
if ( idx != -1 )
{
PrecacheModelComponents( idx );
}
#if defined( WATCHACCESS )
g_bWatching = true;
#endif
return idx;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseEntity::Remove( )
{
UTIL_Remove( this );
}
// Entity degugging console commands
extern CBaseEntity *FindPickerEntity( CBasePlayer *pPlayer );
extern void SetDebugBits( CBasePlayer* pPlayer, const char *name, int bit );
extern CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent );
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void ConsoleFireTargets( CBasePlayer *pPlayer, const char *name)
{
// If no name was given use the picker
if (FStrEq(name,""))
{
CBaseEntity *pEntity = FindPickerEntity( pPlayer );
if ( pEntity && !pEntity->IsMarkedForDeletion())
{
Msg( "[%03d] Found: %s, firing\n", gpGlobals->tickcount%1000, pEntity->GetDebugName());
pEntity->Use( pPlayer, pPlayer, USE_TOGGLE, 0 );
return;
}
}
// Otherwise use name or classname
FireTargets( name, pPlayer, pPlayer, USE_TOGGLE, 0 );
}
#ifdef MAPBASE
inline bool UtlStringLessFunc( const CUtlString &lhs, const CUtlString &rhs )
{
return Q_stricmp( lhs.String(), rhs.String() ) < 0;
}
//------------------------------------------------------------------------------
// Purpose : More concommands needed access to entities, so this has been moved to its own function.
// Input : cmdname - The name of the command.
// &commands - Where the complete autocompletes should be sent to.
// substring - The current search query. (only pool entities that start with this)
// checklen - The number of characters to check.
// Output : A pointer to a cUtlRBTRee containing all of the entities.
//------------------------------------------------------------------------------
static int AutoCompleteEntities(const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0)
{
CBaseEntity *pos = NULL;
while ((pos = gEntList.NextEnt(pos)) != NULL)
{
const char *name = pos->GetClassname();
if (pos->GetEntityName() == NULL_STRING || Q_strnicmp(STRING(pos->GetEntityName()), substring, checklen))
{
if (Q_strnicmp(pos->GetClassname(), substring, checklen))
continue;
}
else
name = STRING(pos->GetEntityName());
CUtlString sym = name;
int idx = symbols.Find(sym);
if (idx == symbols.InvalidIndex())
{
symbols.Insert(sym);
}
// Too many
if (symbols.Count() >= COMMAND_COMPLETION_MAXITEMS)
break;
}
// Now fill in the results
for (int i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder(i))
{
const char *name = symbols[i].String();
char buf[512];
Q_strncpy(buf, name, sizeof(buf));
Q_strlower(buf);
CUtlString command;
command = CFmtStr("%s %s", cmdname, buf);
commands.AddToTail(command);
}
return symbols.Count();
}
#endif
2013-12-02 19:31:46 -08:00
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Ent_Name( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_NAME_BIT);
}
static ConCommand ent_name("ent_name", CC_Ent_Name, 0, FCVAR_CHEAT);
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void DumpScriptScope(CBasePlayer* pPlayer, const char* name)
{
CBaseEntity* pEntity = NULL;
while ((pEntity = GetNextCommandEntity(pPlayer, name, pEntity)) != NULL)
{
if (pEntity->m_ScriptScope.IsInitialized())
{
Msg("----Script Dump for entity %s\n", pEntity->GetDebugName());
HSCRIPT hDumpScopeFunc = g_pScriptVM->LookupFunction("__DumpScope");
g_pScriptVM->Call(hDumpScopeFunc, NULL, true, NULL, 1, (HSCRIPT)pEntity->m_ScriptScope);
Msg("----End Script Dump\n");
}
else
{
DevWarning("ent_script_dump: Entity %s has no script scope!\n", pEntity->GetDebugName());
}
}
}
//------------------------------------------------------------------------------
void CC_Ent_Script_Dump( const CCommand& args )
{
DumpScriptScope(UTIL_GetCommandClient(),args[1]);
}
static ConCommand ent_script_dump("ent_script_dump", CC_Ent_Script_Dump, "Dumps the names and values of this entity's script scope to the console\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
2013-12-02 19:31:46 -08:00
//------------------------------------------------------------------------------
#ifdef MAPBASE
class CEntTextAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback
{
public:
virtual void CommandCallback( const CCommand &command )
{
SetDebugBits(UTIL_GetCommandClient(), command.Arg(1), OVERLAY_TEXT_BIT);
}
virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands )
{
if ( !g_pGameRules )
{
return 0;
}
const char *cmdname = "ent_text";
char *substring = (char *)partial;
if ( Q_strstr( partial, cmdname ) )
{
substring = (char *)partial + strlen( cmdname ) + 1;
}
int checklen = Q_strlen( substring );
CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
return AutoCompleteEntities(cmdname, commands, symbols, substring, checklen);
}
};
static CEntTextAutoCompletionFunctor g_EntTextAutoComplete;
static ConCommand ent_text("ent_text", &g_EntTextAutoComplete, "Displays text debugging information about the given entity(ies) on top of the entity (See Overlay Text)\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT, &g_EntTextAutoComplete);
#else
2013-12-02 19:31:46 -08:00
void CC_Ent_Text( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_TEXT_BIT);
}
static ConCommand ent_text("ent_text", CC_Ent_Text, "Displays text debugging information about the given entity(ies) on top of the entity (See Overlay Text)\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
#endif
2013-12-02 19:31:46 -08:00
//------------------------------------------------------------------------------
void CC_Ent_BBox( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_BBOX_BIT);
}
static ConCommand ent_bbox("ent_bbox", CC_Ent_BBox, "Displays the movement bounding box for the given entity(ies) in orange. Some entites will also display entity specific overlays.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Ent_AbsBox( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_ABSBOX_BIT);
}
static ConCommand ent_absbox("ent_absbox", CC_Ent_AbsBox, "Displays the total bounding box for the given entity(s) in green. Some entites will also display entity specific overlays.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Ent_RBox( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_RBOX_BIT);
}
static ConCommand ent_rbox("ent_rbox", CC_Ent_RBox, "Displays the total bounding box for the given entity(s) in green. Some entites will also display entity specific overlays.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Ent_AttachmentPoints( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_ATTACHMENTS_BIT);
}
static ConCommand ent_attachments("ent_attachments", CC_Ent_AttachmentPoints, "Displays the attachment points on an entity.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Ent_ViewOffset( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_VIEWOFFSET);
}
static ConCommand ent_viewoffset("ent_viewoffset", CC_Ent_ViewOffset, "Displays the eye position for the given entity(ies) in red.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Ent_Remove( const CCommand& args )
{
CBaseEntity *pEntity = NULL;
// If no name was given set bits based on the picked
if ( FStrEq( args[1],"") )
{
pEntity = FindPickerEntity( UTIL_GetCommandClient() );
}
else
{
int index = atoi( args[1] );
if ( index )
{
pEntity = CBaseEntity::Instance( index );
}
else
{
// Otherwise set bits based on name or classname
CBaseEntity *ent = NULL;
while ( (ent = gEntList.NextEnt(ent)) != NULL )
{
if ( (ent->GetEntityName() != NULL_STRING && FStrEq(args[1], STRING(ent->GetEntityName()))) ||
(ent->m_iClassname != NULL_STRING && FStrEq(args[1], STRING(ent->m_iClassname))) ||
(ent->GetClassname()!=NULL && FStrEq(args[1], ent->GetClassname())))
{
pEntity = ent;
break;
}
}
}
}
// Found one?
if ( pEntity )
{
Msg( "Removed %s(%s)\n", STRING(pEntity->m_iClassname), pEntity->GetDebugName() );
UTIL_Remove( pEntity );
}
}
static ConCommand ent_remove("ent_remove", CC_Ent_Remove, "Removes the given entity(s)\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Ent_RemoveAll( const CCommand& args )
{
// If no name was given remove based on the picked
if ( args.ArgC() < 2 )
{
Msg( "Removes all entities of the specified type\n\tArguments: {entity_name} / {class_name}\n" );
}
else
{
// Otherwise remove based on name or classname
int iCount = 0;
CBaseEntity *ent = NULL;
while ( (ent = gEntList.NextEnt(ent)) != NULL )
{
if ( (ent->GetEntityName() != NULL_STRING && FStrEq(args[1], STRING(ent->GetEntityName()))) ||
(ent->m_iClassname != NULL_STRING && FStrEq(args[1], STRING(ent->m_iClassname))) ||
(ent->GetClassname()!=NULL && FStrEq(args[1], ent->GetClassname())))
{
UTIL_Remove( ent );
iCount++;
}
}
if ( iCount )
{
Msg( "Removed %d %s's\n", iCount, args[1] );
}
else
{
Msg( "No %s found.\n", args[1] );
}
}
}
static ConCommand ent_remove_all("ent_remove_all", CC_Ent_RemoveAll, "Removes all entities of the specified type\n\tArguments: {entity_name} / {class_name} ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Ent_SetName( const CCommand& args )
{
CBaseEntity *pEntity = NULL;
if ( args.ArgC() < 1 )
{
CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
if (!pPlayer)
return;
ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_setname <new name> <entity name>\n" );
}
else
{
// If no name was given set bits based on the picked
if ( FStrEq( args[2],"") )
{
pEntity = FindPickerEntity( UTIL_GetCommandClient() );
}
else
{
// Otherwise set bits based on name or classname
CBaseEntity *ent = NULL;
while ( (ent = gEntList.NextEnt(ent)) != NULL )
{
if ( (ent->GetEntityName() != NULL_STRING && FStrEq(args[1], STRING(ent->GetEntityName()))) ||
(ent->m_iClassname != NULL_STRING && FStrEq(args[1], STRING(ent->m_iClassname))) ||
(ent->GetClassname()!=NULL && FStrEq(args[1], ent->GetClassname())))
{
pEntity = ent;
break;
}
}
}
// Found one?
if ( pEntity )
{
Msg( "Set the name of %s to %s\n", STRING(pEntity->m_iClassname), args[1] );
pEntity->SetName( AllocPooledString( args[1] ) );
}
}
}
static ConCommand ent_setname("ent_setname", CC_Ent_SetName, "Sets the targetname of the given entity(s)\n\tArguments: {new entity name} {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Find_Ent( const CCommand& args )
{
if ( args.ArgC() < 2 )
{
Msg( "Total entities: %d (%d edicts)\n", gEntList.NumberOfEntities(), gEntList.NumberOfEdicts() );
Msg( "Format: find_ent <substring>\n" );
return;
}
int iCount = 0;
const char *pszSubString = args[1];
Msg("Searching for entities with class/target name containing substring: '%s'\n", pszSubString );
CBaseEntity *ent = NULL;
while ( (ent = gEntList.NextEnt(ent)) != NULL )
{
const char *pszClassname = ent->GetClassname();
const char *pszTargetname = STRING(ent->GetEntityName());
bool bMatches = false;
if ( pszClassname && pszClassname[0] )
{
if ( Q_stristr( pszClassname, pszSubString ) )
{
bMatches = true;
}
}
if ( !bMatches && pszTargetname && pszTargetname[0] )
{
if ( Q_stristr( pszTargetname, pszSubString ) )
{
bMatches = true;
}
}
if ( bMatches )
{
iCount++;
Msg(" '%s' : '%s' (entindex %d) \n", ent->GetClassname(), ent->GetEntityName().ToCStr(), ent->entindex() );
}
}
Msg("Found %d matches.\n", iCount);
}
static ConCommand find_ent("find_ent", CC_Find_Ent, "Find and list all entities with classnames or targetnames that contain the specified substring.\nFormat: find_ent <substring>\n", FCVAR_CHEAT);
//------------------------------------------------------------------------------
void CC_Find_Ent_Index( const CCommand& args )
{
if ( args.ArgC() < 2 )
{
Msg( "Format: find_ent_index <index>\n" );
return;
}
int iIndex = atoi(args[1]);
CBaseEntity *pEnt = UTIL_EntityByIndex( iIndex );
if ( pEnt )
{
Msg(" '%s' : '%s' (entindex %d) \n", pEnt->GetClassname(), pEnt->GetEntityName().ToCStr(), iIndex );
}
else
{
Msg("Found no entity at %d.\n", iIndex);
}
}
static ConCommand find_ent_index("find_ent_index", CC_Find_Ent_Index, "Display data for entity matching specified index.\nFormat: find_ent_index <index>\n", FCVAR_CHEAT);
// Purpose :
//------------------------------------------------------------------------------
void CC_Ent_Dump( const CCommand& args )
{
CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
if (!pPlayer)
{
return;
}
if ( args.ArgC() < 2 )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_dump <entity name>\n" );
}
else
{
// iterate through all the ents of this name, printing out their details
CBaseEntity *ent = NULL;
bool bFound = false;
while ( ( ent = gEntList.FindEntityByName(ent, args[1] ) ) != NULL )
{
bFound = true;
for ( datamap_t *dmap = ent->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
// search through all the actions in the data description, printing out details
for ( int i = 0; i < dmap->dataNumFields; i++ )
{
variant_t var;
if ( ent->ReadKeyField( dmap->dataDesc[i].externalName, &var) )
{
char buf[256];
buf[0] = 0;
switch( var.FieldType() )
{
case FIELD_STRING:
Q_strncpy( buf, var.String() ,sizeof(buf));
break;
case FIELD_INTEGER:
if ( var.Int() )
Q_snprintf( buf,sizeof(buf), "%d", var.Int() );
break;
case FIELD_FLOAT:
if ( var.Float() )
Q_snprintf( buf,sizeof(buf), "%.2f", var.Float() );
break;
case FIELD_EHANDLE:
{
// get the entities name
if ( var.Entity() )
{
Q_snprintf( buf,sizeof(buf), "%s", STRING(var.Entity()->GetEntityName()) );
}
}
break;
}
// don't print out the duplicate keys
if ( !Q_stricmp("parentname",dmap->dataDesc[i].externalName) || !Q_stricmp("targetname",dmap->dataDesc[i].externalName) )
continue;
// don't print out empty keys
if ( buf[0] )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs(" %s: %s\n", dmap->dataDesc[i].externalName, buf) );
}
}
}
}
}
if ( !bFound )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, "ent_dump: no such entity" );
}
}
}
static ConCommand ent_dump("ent_dump", CC_Ent_Dump, "Usage:\n ent_dump <entity name>\n", FCVAR_CHEAT);
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Ent_FireTarget( const CCommand& args )
{
ConsoleFireTargets(UTIL_GetCommandClient(),args[1]);
}
static ConCommand firetarget("firetarget", CC_Ent_FireTarget, 0, FCVAR_CHEAT);
#ifndef MAPBASE
2013-12-02 19:31:46 -08:00
static bool UtlStringLessFunc( const CUtlString &lhs, const CUtlString &rhs )
{
return Q_stricmp( lhs.String(), rhs.String() ) < 0;
}
#endif
2013-12-02 19:31:46 -08:00
class CEntFireAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback
{
public:
virtual void CommandCallback( const CCommand &command )
{
CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
if (!pPlayer)
{
return;
}
// fires a command from the console
if ( command.ArgC() < 2 )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_fire <target> [action] [value] [delay]\n" );
}
else
{
const char *target = "", *action = "Use";
variant_t value;
Merged dev changes 9/28/2019 - Experimental RPC stuff for the future - Fixed players running over allies with vehicles (kind of) - Modified redirect filter infrastructure to support when there's no target filter (meaning it will just make sure the entity exists) - Fixed SDK_EyeRefract - Fixed env_beam SetStart/EndEntity - New "OnStateChange" output on NPCs - scripted_face removed (use generic facing VCDs instead) - Fixed RPC - View ID nodraw keyvalue + reflective glass view ID fix - CopyAnimationDataFrom expansion (more variables copied) - Fixed pre-Mapbase env_projectedtextures not updating after loading a save - Fixed(?) player companion grenade throwing being interrupted - Added convars for secondary and NPC shotgun pellet amounts - NPC fade distance/scale transfers to its ragdoll - Made node graph rebuild occur sooner after map load - Added option to disable "node graph out of date" message - Fixed ent_fire delay (decimals discarded before) - "SetFilter" on func_clip_vphysics - Fixed func_tank zero barrel (untested) - Fixed npc_turret_ground parenting fix - Added toggle-able weapon_crossbow experimental hit location code - Fixed ally grenades being considered Combine grenades - Added SDK_MonitorScreen and SDK_UnlitTwoTexture - Updated README - Added !activator/!caller support to logic_collision_pair - Fixed ortho not working in script_intro - Added Nbc66's closed captioning language fix - Applied fade fix to server ragdolls - Added combine_mine friend/foe filters - Fixed env_starfield pausing - Reworked PickupWeapon/Item inputs - Fixed context response system $ usage - Fixed env_break_shooter velocity/speed - Made func_breakable "Spawn on break" support other entities - Fixed OnThrowGrenade > point_entity_replace blip - Added mapname to logic_externaldata - Added "Random Template" to point_template - Added "Use LOS" to trigger_look - Added flags based on L4D(2) to trigger_playermovement - Added npc_combine_s "Alternate Capable" keyvalue that enables both grenades and alt-fire at the same time regardless of elite status - Fixed npc_combine_s DropGrenade input - Miscellaneous code and comment changes
2019-09-28 22:56:52 +00:00
#ifdef MAPBASE
float delay = 0;
#else
2013-12-02 19:31:46 -08:00
int delay = 0;
Merged dev changes 9/28/2019 - Experimental RPC stuff for the future - Fixed players running over allies with vehicles (kind of) - Modified redirect filter infrastructure to support when there's no target filter (meaning it will just make sure the entity exists) - Fixed SDK_EyeRefract - Fixed env_beam SetStart/EndEntity - New "OnStateChange" output on NPCs - scripted_face removed (use generic facing VCDs instead) - Fixed RPC - View ID nodraw keyvalue + reflective glass view ID fix - CopyAnimationDataFrom expansion (more variables copied) - Fixed pre-Mapbase env_projectedtextures not updating after loading a save - Fixed(?) player companion grenade throwing being interrupted - Added convars for secondary and NPC shotgun pellet amounts - NPC fade distance/scale transfers to its ragdoll - Made node graph rebuild occur sooner after map load - Added option to disable "node graph out of date" message - Fixed ent_fire delay (decimals discarded before) - "SetFilter" on func_clip_vphysics - Fixed func_tank zero barrel (untested) - Fixed npc_turret_ground parenting fix - Added toggle-able weapon_crossbow experimental hit location code - Fixed ally grenades being considered Combine grenades - Added SDK_MonitorScreen and SDK_UnlitTwoTexture - Updated README - Added !activator/!caller support to logic_collision_pair - Fixed ortho not working in script_intro - Added Nbc66's closed captioning language fix - Applied fade fix to server ragdolls - Added combine_mine friend/foe filters - Fixed env_starfield pausing - Reworked PickupWeapon/Item inputs - Fixed context response system $ usage - Fixed env_break_shooter velocity/speed - Made func_breakable "Spawn on break" support other entities - Fixed OnThrowGrenade > point_entity_replace blip - Added mapname to logic_externaldata - Added "Random Template" to point_template - Added "Use LOS" to trigger_look - Added flags based on L4D(2) to trigger_playermovement - Added npc_combine_s "Alternate Capable" keyvalue that enables both grenades and alt-fire at the same time regardless of elite status - Fixed npc_combine_s DropGrenade input - Miscellaneous code and comment changes
2019-09-28 22:56:52 +00:00
#endif
2013-12-02 19:31:46 -08:00
target = STRING( AllocPooledString(command.Arg( 1 ) ) );
// Don't allow them to run anything on a point_servercommand unless they're the host player. Otherwise they can ent_fire
// and run any command on the server. Admittedly, they can only do the ent_fire if sv_cheats is on, but
// people complained about users resetting the rcon password if the server briefly turned on cheats like this:
// give point_servercommand
// ent_fire point_servercommand command "rcon_password mynewpassword"
//
// Robin: Unfortunately, they get around point_servercommand checks with this:
// ent_create point_servercommand; ent_setname mine; ent_fire mine command "rcon_password mynewpassword"
// So, I'm removing the ability for anyone to execute ent_fires on dedicated servers (we can't check to see if
// this command is going to connect with a point_servercommand entity here, because they could delay the event and create it later).
if ( engine->IsDedicatedServer() )
{
// We allow people with disabled autokick to do it, because they already have rcon.
if ( pPlayer->IsAutoKickDisabled() == false )
return;
}
else if ( gpGlobals->maxClients > 1 )
{
// On listen servers with more than 1 player, only allow the host to issue ent_fires.
CBasePlayer *pHostPlayer = UTIL_GetListenServerHost();
if ( pPlayer != pHostPlayer )
return;
}
if ( command.ArgC() >= 3 )
{
action = STRING( AllocPooledString(command.Arg( 2 )) );
}
if ( command.ArgC() >= 4 )
{
value.SetString( AllocPooledString(command.Arg( 3 )) );
}
if ( command.ArgC() >= 5 )
{
Merged dev changes 9/28/2019 - Experimental RPC stuff for the future - Fixed players running over allies with vehicles (kind of) - Modified redirect filter infrastructure to support when there's no target filter (meaning it will just make sure the entity exists) - Fixed SDK_EyeRefract - Fixed env_beam SetStart/EndEntity - New "OnStateChange" output on NPCs - scripted_face removed (use generic facing VCDs instead) - Fixed RPC - View ID nodraw keyvalue + reflective glass view ID fix - CopyAnimationDataFrom expansion (more variables copied) - Fixed pre-Mapbase env_projectedtextures not updating after loading a save - Fixed(?) player companion grenade throwing being interrupted - Added convars for secondary and NPC shotgun pellet amounts - NPC fade distance/scale transfers to its ragdoll - Made node graph rebuild occur sooner after map load - Added option to disable "node graph out of date" message - Fixed ent_fire delay (decimals discarded before) - "SetFilter" on func_clip_vphysics - Fixed func_tank zero barrel (untested) - Fixed npc_turret_ground parenting fix - Added toggle-able weapon_crossbow experimental hit location code - Fixed ally grenades being considered Combine grenades - Added SDK_MonitorScreen and SDK_UnlitTwoTexture - Updated README - Added !activator/!caller support to logic_collision_pair - Fixed ortho not working in script_intro - Added Nbc66's closed captioning language fix - Applied fade fix to server ragdolls - Added combine_mine friend/foe filters - Fixed env_starfield pausing - Reworked PickupWeapon/Item inputs - Fixed context response system $ usage - Fixed env_break_shooter velocity/speed - Made func_breakable "Spawn on break" support other entities - Fixed OnThrowGrenade > point_entity_replace blip - Added mapname to logic_externaldata - Added "Random Template" to point_template - Added "Use LOS" to trigger_look - Added flags based on L4D(2) to trigger_playermovement - Added npc_combine_s "Alternate Capable" keyvalue that enables both grenades and alt-fire at the same time regardless of elite status - Fixed npc_combine_s DropGrenade input - Miscellaneous code and comment changes
2019-09-28 22:56:52 +00:00
#ifdef MAPBASE
delay = atof( command.Arg( 4 ) );
#else
2013-12-02 19:31:46 -08:00
delay = atoi( command.Arg( 4 ) );
Merged dev changes 9/28/2019 - Experimental RPC stuff for the future - Fixed players running over allies with vehicles (kind of) - Modified redirect filter infrastructure to support when there's no target filter (meaning it will just make sure the entity exists) - Fixed SDK_EyeRefract - Fixed env_beam SetStart/EndEntity - New "OnStateChange" output on NPCs - scripted_face removed (use generic facing VCDs instead) - Fixed RPC - View ID nodraw keyvalue + reflective glass view ID fix - CopyAnimationDataFrom expansion (more variables copied) - Fixed pre-Mapbase env_projectedtextures not updating after loading a save - Fixed(?) player companion grenade throwing being interrupted - Added convars for secondary and NPC shotgun pellet amounts - NPC fade distance/scale transfers to its ragdoll - Made node graph rebuild occur sooner after map load - Added option to disable "node graph out of date" message - Fixed ent_fire delay (decimals discarded before) - "SetFilter" on func_clip_vphysics - Fixed func_tank zero barrel (untested) - Fixed npc_turret_ground parenting fix - Added toggle-able weapon_crossbow experimental hit location code - Fixed ally grenades being considered Combine grenades - Added SDK_MonitorScreen and SDK_UnlitTwoTexture - Updated README - Added !activator/!caller support to logic_collision_pair - Fixed ortho not working in script_intro - Added Nbc66's closed captioning language fix - Applied fade fix to server ragdolls - Added combine_mine friend/foe filters - Fixed env_starfield pausing - Reworked PickupWeapon/Item inputs - Fixed context response system $ usage - Fixed env_break_shooter velocity/speed - Made func_breakable "Spawn on break" support other entities - Fixed OnThrowGrenade > point_entity_replace blip - Added mapname to logic_externaldata - Added "Random Template" to point_template - Added "Use LOS" to trigger_look - Added flags based on L4D(2) to trigger_playermovement - Added npc_combine_s "Alternate Capable" keyvalue that enables both grenades and alt-fire at the same time regardless of elite status - Fixed npc_combine_s DropGrenade input - Miscellaneous code and comment changes
2019-09-28 22:56:52 +00:00
#endif
2013-12-02 19:31:46 -08:00
}
g_EventQueue.AddEvent( target, action, value, delay, pPlayer, pPlayer );
}
}
virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands )
{
if ( !g_pGameRules )
{
return 0;
}
const char *cmdname = "ent_fire";
char *substring = (char *)partial;
if ( Q_strstr( partial, cmdname ) )
{
substring = (char *)partial + strlen( cmdname ) + 1;
}
int checklen = 0;
char *space = Q_strstr( substring, " " );
if ( space )
{
return EntFire_AutoCompleteInput( partial, commands );;
}
else
{
checklen = Q_strlen( substring );
}
#ifdef MAPBASE
CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
return AutoCompleteEntities(cmdname, commands, symbols, substring, checklen);
#else
2013-12-02 19:31:46 -08:00
CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
CBaseEntity *pos = NULL;
while ( ( pos = gEntList.NextEnt( pos ) ) != NULL )
{
// Check target name against partial string
if ( pos->GetEntityName() == NULL_STRING )
continue;
if ( Q_strnicmp( STRING( pos->GetEntityName() ), substring, checklen ) )
continue;
CUtlString sym = STRING( pos->GetEntityName() );
int idx = symbols.Find( sym );
if ( idx == symbols.InvalidIndex() )
{
symbols.Insert( sym );
}
// Too many
if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
break;
}
// Now fill in the results
for ( int i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder( i ) )
{
const char *name = symbols[ i ].String();
char buf[ 512 ];
Q_strncpy( buf, name, sizeof( buf ) );
Q_strlower( buf );
CUtlString command;
command = CFmtStr( "%s %s", cmdname, buf );
commands.AddToTail( command );
}
return symbols.Count();
#endif
2013-12-02 19:31:46 -08:00
}
private:
int EntFire_AutoCompleteInput( const char *partial, CUtlVector< CUtlString > &commands )
{
const char *cmdname = "ent_fire";
char *substring = (char *)partial;
if ( Q_strstr( partial, cmdname ) )
{
substring = (char *)partial + strlen( cmdname ) + 1;
}
int checklen = 0;
char *space = Q_strstr( substring, " " );
if ( !space )
{
Assert( !"CC_EntFireAutoCompleteInputFunc is broken\n" );
return 0;
}
checklen = Q_strlen( substring );
char targetEntity[ 256 ];
targetEntity[0] = 0;
int nEntityNameLength = (space-substring);
Q_strncat( targetEntity, substring, sizeof( targetEntity ), nEntityNameLength );
// Find the target entity by name
#ifdef MAPBASE
CBasePlayer *pPlayer = UTIL_GetCommandClient();
CBaseEntity *target = gEntList.FindEntityGeneric( NULL, targetEntity, pPlayer, pPlayer, pPlayer );
#else
2013-12-02 19:31:46 -08:00
CBaseEntity *target = gEntList.FindEntityByName( NULL, targetEntity );
#endif
2013-12-02 19:31:46 -08:00
if ( target == NULL )
return 0;
CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
// Find the next portion of the text chain, if any (removing space)
int nInputNameLength = (checklen-nEntityNameLength-1);
// Starting past the last space, this is the remainder of the string
char *inputPartial = ( checklen > nEntityNameLength ) ? (space+1) : NULL;
for ( datamap_t *dmap = target->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
// Make sure we don't keep adding things in if the satisfied the limit
if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
break;
int c = dmap->dataNumFields;
for ( int i = 0; i < c; i++ )
{
typedescription_t *field = &dmap->dataDesc[ i ];
// Only want inputs
if ( !( field->flags & FTYPEDESC_INPUT ) )
continue;
#ifndef MAPBASE // What did input variables ever do to you?
2013-12-02 19:31:46 -08:00
// Only want input functions
if ( field->flags & FTYPEDESC_SAVE )
continue;
#endif
2013-12-02 19:31:46 -08:00
// See if we've got a partial string for the input name already
if ( inputPartial != NULL )
{
if ( Q_strnicmp( inputPartial, field->externalName, nInputNameLength ) )
continue;
}
CUtlString sym = field->externalName;
int idx = symbols.Find( sym );
if ( idx == symbols.InvalidIndex() )
{
symbols.Insert( sym );
}
// Too many items have been added
if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
break;
}
}
// Now fill in the results
for ( int i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder( i ) )
{
const char *name = symbols[ i ].String();
char buf[ 512 ];
Q_strncpy( buf, name, sizeof( buf ) );
Q_strlower( buf );
CUtlString command;
command = CFmtStr( "%s %s %s", cmdname, targetEntity, buf );
commands.AddToTail( command );
}
return symbols.Count();
}
};
static CEntFireAutoCompletionFunctor g_EntFireAutoComplete;
static ConCommand ent_fire("ent_fire", &g_EntFireAutoComplete, "Usage:\n ent_fire <target> [action] [value] [delay]\n", FCVAR_CHEAT, &g_EntFireAutoComplete );
void CC_Ent_CancelPendingEntFires( const CCommand& args )
{
if ( !UTIL_IsCommandIssuedByServerAdmin() )
return;
CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
if (!pPlayer)
return;
g_EventQueue.CancelEvents( pPlayer );
}
static ConCommand ent_cancelpendingentfires("ent_cancelpendingentfires", CC_Ent_CancelPendingEntFires, "Cancels all ent_fire created outputs that are currently waiting for their delay to expire." );
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Ent_Info( const CCommand& args )
{
CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
if (!pPlayer)
{
return;
}
if ( args.ArgC() < 2 )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_info <class name>\n" );
}
else
{
// iterate through all the ents printing out their details
CBaseEntity *ent = CreateEntityByName( args[1] );
if ( ent )
{
datamap_t *dmap;
for ( dmap = ent->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
// search through all the actions in the data description, printing out details
for ( int i = 0; i < dmap->dataNumFields; i++ )
{
if ( dmap->dataDesc[i].flags & FTYPEDESC_OUTPUT )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs(" output: %s\n", dmap->dataDesc[i].externalName) );
}
}
}
for ( dmap = ent->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
// search through all the actions in the data description, printing out details
for ( int i = 0; i < dmap->dataNumFields; i++ )
{
if ( dmap->dataDesc[i].flags & FTYPEDESC_INPUT )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs(" input: %s\n", dmap->dataDesc[i].externalName) );
}
}
}
delete ent;
}
else
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs("no such entity %s\n", args[1]) );
}
}
}
static ConCommand ent_info("ent_info", CC_Ent_Info, "Usage:\n ent_info <class name>\n", FCVAR_CHEAT);
#ifdef MAPBASE
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Ent_Info_Datatable( const CCommand& args )
{
CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
if (!pPlayer)
{
return;
}
if ( args.ArgC() < 2 )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_info_datatable <class name>\n" );
}
else
{
// Each element corresponds to a specific field type.
// Hey, if you've got a better idea, be my guest.
static const char *g_FieldStrings[FIELD_TYPECOUNT] =
{
"VOID",
"FLOAT",
"STRING",
"VECTOR",
"QUATERNION",
"INTEGER",
"BOOLEAN",
"SHORT",
"CHARACTER",
"COLOR32",
"EMBEDDED",
"CUSTOM",
"CLASSPTR",
"EHANDLE",
"EDICT",
"POSITION_VECTOR",
"TIME",
"TICK",
"MODELNAME",
"SOUNDNAME",
"INPUT",
"FUNCTION",
"VMATRIX",
"VMATRIX_WORLDSPACE",
"MATRIX3X4_WORLDSPACE",
"INTERVAL",
"MODELINDEX",
"MATERIALINDEX",
"VECTOR2D",
};
// iterate through all the ents printing out their details
CBaseEntity *ent = CreateEntityByName( args[1] );
if ( ent )
{
#define ENT_INFO_BY_HIERARCHY 1
#ifdef ENT_INFO_BY_HIERARCHY
CUtlVector<const char*> dmap_namelist;
CUtlVector< CUtlVector<const char*> > dmap_fieldlist;
CUtlVector< CUtlVector<int> > dmap_fieldtypelist;
datamap_t *dmap;
int dmapnum = 0;
for ( dmap = ent->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
dmap_fieldlist.AddToTail();
dmap_fieldtypelist.AddToTail();
// search through all the actions in the data description, printing out details
for ( int i = 0; i < dmap->dataNumFields; i++ )
{
dmap_fieldlist[dmapnum].AddToTail(dmap->dataDesc[i].fieldName);
dmap_fieldtypelist[dmapnum].AddToTail(dmap->dataDesc[i].fieldType);
}
dmapnum++;
dmap_namelist.AddToTail(dmap->dataClassName);
}
char offset[64] = { 0 }; // Needed so garbage isn't spewed at the beginning
for ( int i = 0; i < dmapnum; i++ )
{
Q_strncat(offset, " ", sizeof(offset));
// Header for each class
ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs("%s=========| %s |=========\n", offset, dmap_namelist[i]) );
Q_strncat(offset, " ", sizeof(offset));
int iFieldCount = dmap_fieldlist[i].Count();
for ( int index = 0; index < iFieldCount; index++ )
{
int iType = dmap_fieldtypelist[i][index];
ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs("%s%s (%i): %s\n", offset, g_FieldStrings[iType], iType, dmap_fieldlist[i][index]) );
}
// Clean up after ourselves
dmap_fieldlist[i].RemoveAll();
dmap_fieldtypelist[i].RemoveAll();
}
#else // This sorts by field type instead
CUtlVector<const char*> fieldlist[FIELD_TYPECOUNT];
datamap_t *dmap;
for ( dmap = ent->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
// search through all the actions in the data description, printing out details
for ( int i = 0; i < dmap->dataNumFields; i++ )
{
fieldlist[dmap->dataDesc[i].fieldType].AddToTail(dmap->dataDesc[i].fieldName);
}
}
for ( int i = 0; i < FIELD_TYPECOUNT; i++ )
{
const char *typestring = g_FieldStrings[i];
for ( int index = 0; index < fieldlist[i].Count(); index++ )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs(" %s (%i): %s\n", typestring, i, fieldlist[i][index]) );
}
// Clean up after ourselves
fieldlist[i].RemoveAll();
}
#endif
delete ent;
}
else
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs("no such entity %s\n", args[1]) );
}
}
}
static ConCommand ent_info_datatable("ent_info_datatable", CC_Ent_Info_Datatable, "Usage:\n ent_info_datatable <class name>\n", FCVAR_CHEAT);
#endif
2013-12-02 19:31:46 -08:00
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Ent_Messages( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_MESSAGE_BIT);
}
static ConCommand ent_messages("ent_messages", CC_Ent_Messages ,"Toggles input/output message display for the selected entity(ies). The name of the entity will be displayed as well as any messages that it sends or receives.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at", FCVAR_CHEAT);
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Ent_Pause( void )
{
if (CBaseEntity::Debug_IsPaused())
{
Msg( "Resuming entity I/O events\n" );
CBaseEntity::Debug_Pause(false);
}
else
{
Msg( "Pausing entity I/O events\n" );
CBaseEntity::Debug_Pause(true);
}
}
static ConCommand ent_pause("ent_pause", CC_Ent_Pause, "Toggles pausing of input/output message processing for entities. When turned on processing of all message will stop. Any messages displayed with 'ent_messages' will stop fading and be displayed indefinitely. To step through the messages one by one use 'ent_step'.", FCVAR_CHEAT);
//------------------------------------------------------------------------------
// Purpose : Enables the entity picker, revelaing debug information about the
// entity under the crosshair.
// Input : an optional command line argument "full" enables all debug info.
// Output :
//------------------------------------------------------------------------------
void CC_Ent_Picker( void )
{
CBaseEntity::m_bInDebugSelect = CBaseEntity::m_bInDebugSelect ? false : true;
// Remember the player that's making this request
CBaseEntity::m_nDebugPlayer = UTIL_GetCommandClientIndex();
}
static ConCommand picker("picker", CC_Ent_Picker, "Toggles 'picker' mode. When picker is on, the bounding box, pivot and debugging text is displayed for whatever entity the player is looking at.\n\tArguments: full - enables all debug information", FCVAR_CHEAT);
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Ent_Pivot( const CCommand& args )
{
SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_PIVOT_BIT);
}
static ConCommand ent_pivot("ent_pivot", CC_Ent_Pivot, "Displays the pivot for the given entity(ies).\n\t(y=up=green, z=forward=blue, x=left=red). \n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Ent_Step( const CCommand& args )
{
int nSteps = atoi(args[1]);
if (nSteps <= 0)
{
nSteps = 1;
}
CBaseEntity::Debug_SetSteps(nSteps);
}
static ConCommand ent_step("ent_step", CC_Ent_Step, "When 'ent_pause' is set this will step through one waiting input / output message at a time.", FCVAR_CHEAT);
void CBaseEntity::SetCheckUntouch( bool check )
{
// Invalidate touchstamp
if ( check )
{
touchStamp++;
if ( !IsEFlagSet( EFL_CHECK_UNTOUCH ) )
{
AddEFlags( EFL_CHECK_UNTOUCH );
EntityTouch_Add( this );
}
}
else
{
RemoveEFlags( EFL_CHECK_UNTOUCH );
}
}
model_t *CBaseEntity::GetModel( void )
{
return (model_t *)modelinfo->GetModel( GetModelIndex() );
}
//-----------------------------------------------------------------------------
// Purpose: Calculates the absolute position of an edict in the world
// assumes the parent's absolute origin has already been calculated
//-----------------------------------------------------------------------------
void CBaseEntity::CalcAbsolutePosition( void )
{
if (!IsEFlagSet( EFL_DIRTY_ABSTRANSFORM ))
return;
RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
// Plop the entity->parent matrix into m_rgflCoordinateFrame
AngleMatrix( m_angRotation, m_vecOrigin, m_rgflCoordinateFrame );
CBaseEntity *pMoveParent = GetMoveParent();
if ( !pMoveParent )
{
// no move parent, so just copy existing values
m_vecAbsOrigin = m_vecOrigin;
m_angAbsRotation = m_angRotation;
if ( HasDataObjectType( POSITIONWATCHER ) )
{
ReportPositionChanged( this );
}
return;
}
// concatenate with our parent's transform
matrix3x4_t tmpMatrix, scratchSpace;
ConcatTransforms( GetParentToWorldTransform( scratchSpace ), m_rgflCoordinateFrame, tmpMatrix );
MatrixCopy( tmpMatrix, m_rgflCoordinateFrame );
// pull our absolute position out of the matrix
MatrixGetColumn( m_rgflCoordinateFrame, 3, m_vecAbsOrigin );
// if we have any angles, we have to extract our absolute angles from our matrix
if (( m_angRotation == vec3_angle ) && ( m_iParentAttachment == 0 ))
{
// just copy our parent's absolute angles
VectorCopy( pMoveParent->GetAbsAngles(), m_angAbsRotation );
}
else
{
MatrixAngles( m_rgflCoordinateFrame, m_angAbsRotation );
}
if ( HasDataObjectType( POSITIONWATCHER ) )
{
ReportPositionChanged( this );
}
}
void CBaseEntity::CalcAbsoluteVelocity()
{
if (!IsEFlagSet( EFL_DIRTY_ABSVELOCITY ))
return;
RemoveEFlags( EFL_DIRTY_ABSVELOCITY );
CBaseEntity *pMoveParent = GetMoveParent();
if ( !pMoveParent )
{
m_vecAbsVelocity = m_vecVelocity;
return;
}
// This transforms the local velocity into world space
VectorRotate( m_vecVelocity, pMoveParent->EntityToWorldTransform(), m_vecAbsVelocity );
// Now add in the parent abs velocity
m_vecAbsVelocity += pMoveParent->GetAbsVelocity();
}
// FIXME: While we're using (dPitch, dYaw, dRoll) as our local angular velocity
// representation, we can't actually solve this problem
/*
void CBaseEntity::CalcAbsoluteAngularVelocity()
{
if (!IsEFlagSet( EFL_DIRTY_ABSANGVELOCITY ))
return;
RemoveEFlags( EFL_DIRTY_ABSANGVELOCITY );
CBaseEntity *pMoveParent = GetMoveParent();
if ( !pMoveParent )
{
m_vecAbsAngVelocity = m_vecAngVelocity;
return;
}
// This transforms the local ang velocity into world space
matrix3x4_t angVelToParent, angVelToWorld;
AngleMatrix( m_vecAngVelocity, angVelToParent );
ConcatTransforms( pMoveParent->EntityToWorldTransform(), angVelToParent, angVelToWorld );
MatrixAngles( angVelToWorld, m_vecAbsAngVelocity );
}
*/
//-----------------------------------------------------------------------------
// Computes the abs position of a point specified in local space
//-----------------------------------------------------------------------------
void CBaseEntity::ComputeAbsPosition( const Vector &vecLocalPosition, Vector *pAbsPosition )
{
CBaseEntity *pMoveParent = GetMoveParent();
if ( !pMoveParent )
{
*pAbsPosition = vecLocalPosition;
}
else
{
VectorTransform( vecLocalPosition, pMoveParent->EntityToWorldTransform(), *pAbsPosition );
}
}
//-----------------------------------------------------------------------------
// Computes the abs position of a point specified in local space
//-----------------------------------------------------------------------------
void CBaseEntity::ComputeAbsDirection( const Vector &vecLocalDirection, Vector *pAbsDirection )
{
CBaseEntity *pMoveParent = GetMoveParent();
if ( !pMoveParent )
{
*pAbsDirection = vecLocalDirection;
}
else
{
VectorRotate( vecLocalDirection, pMoveParent->EntityToWorldTransform(), *pAbsDirection );
}
}
matrix3x4_t& CBaseEntity::GetParentToWorldTransform( matrix3x4_t &tempMatrix )
{
CBaseEntity *pMoveParent = GetMoveParent();
if ( !pMoveParent )
{
Assert( false );
SetIdentityMatrix( tempMatrix );
return tempMatrix;
}
if ( m_iParentAttachment != 0 )
{
MDLCACHE_CRITICAL_SECTION();
CBaseAnimating *pAnimating = pMoveParent->GetBaseAnimating();
if ( pAnimating && pAnimating->GetAttachment( m_iParentAttachment, tempMatrix ) )
{
return tempMatrix;
}
}
// If we fall through to here, then just use the move parent's abs origin and angles.
return pMoveParent->EntityToWorldTransform();
}
//-----------------------------------------------------------------------------
// These methods recompute local versions as well as set abs versions
//-----------------------------------------------------------------------------
void CBaseEntity::SetAbsOrigin( const Vector& absOrigin )
{
AssertMsg( absOrigin.IsValid(), "Invalid origin set" );
// This is necessary to get the other fields of m_rgflCoordinateFrame ok
CalcAbsolutePosition();
if ( m_vecAbsOrigin == absOrigin )
return;
// All children are invalid, but we are not
InvalidatePhysicsRecursive( POSITION_CHANGED );
RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
m_vecAbsOrigin = absOrigin;
MatrixSetColumn( absOrigin, 3, m_rgflCoordinateFrame );
Vector vecNewOrigin;
CBaseEntity *pMoveParent = GetMoveParent();
if (!pMoveParent)
{
vecNewOrigin = absOrigin;
}
else
{
matrix3x4_t tempMat;
matrix3x4_t &parentTransform = GetParentToWorldTransform( tempMat );
// Moveparent case: transform the abs position into local space
VectorITransform( absOrigin, parentTransform, vecNewOrigin );
}
if (m_vecOrigin != vecNewOrigin)
{
m_vecOrigin = vecNewOrigin;
SetSimulationTime( gpGlobals->curtime );
}
}
void CBaseEntity::SetAbsAngles( const QAngle& absAngles )
{
// This is necessary to get the other fields of m_rgflCoordinateFrame ok
CalcAbsolutePosition();
// FIXME: The normalize caused problems in server code like momentary_rot_button that isn't
// handling things like +/-180 degrees properly. This should be revisited.
//QAngle angleNormalize( AngleNormalize( absAngles.x ), AngleNormalize( absAngles.y ), AngleNormalize( absAngles.z ) );
if ( m_angAbsRotation == absAngles )
return;
// All children are invalid, but we are not
InvalidatePhysicsRecursive( ANGLES_CHANGED );
RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
m_angAbsRotation = absAngles;
AngleMatrix( absAngles, m_rgflCoordinateFrame );
MatrixSetColumn( m_vecAbsOrigin, 3, m_rgflCoordinateFrame );
QAngle angNewRotation;
CBaseEntity *pMoveParent = GetMoveParent();
if (!pMoveParent)
{
angNewRotation = absAngles;
}
else
{
if ( m_angAbsRotation == pMoveParent->GetAbsAngles() )
{
angNewRotation.Init( );
}
else
{
// Moveparent case: transform the abs transform into local space
matrix3x4_t worldToParent, localMatrix;
MatrixInvert( pMoveParent->EntityToWorldTransform(), worldToParent );
ConcatTransforms( worldToParent, m_rgflCoordinateFrame, localMatrix );
MatrixAngles( localMatrix, angNewRotation );
}
}
if (m_angRotation != angNewRotation)
{
m_angRotation = angNewRotation;
SetSimulationTime( gpGlobals->curtime );
}
}
void CBaseEntity::SetAbsVelocity( const Vector &vecAbsVelocity )
{
if ( m_vecAbsVelocity == vecAbsVelocity )
return;
// The abs velocity won't be dirty since we're setting it here
// All children are invalid, but we are not
InvalidatePhysicsRecursive( VELOCITY_CHANGED );
RemoveEFlags( EFL_DIRTY_ABSVELOCITY );
m_vecAbsVelocity = vecAbsVelocity;
// NOTE: Do *not* do a network state change in this case.
// m_vecVelocity is only networked for the player, which is not manual mode
CBaseEntity *pMoveParent = GetMoveParent();
if (!pMoveParent)
{
m_vecVelocity = vecAbsVelocity;
return;
}
// First subtract out the parent's abs velocity to get a relative
// velocity measured in world space
Vector relVelocity;
VectorSubtract( vecAbsVelocity, pMoveParent->GetAbsVelocity(), relVelocity );
// Transform relative velocity into parent space
Vector vNew;
VectorIRotate( relVelocity, pMoveParent->EntityToWorldTransform(), vNew );
m_vecVelocity = vNew;
}
// FIXME: While we're using (dPitch, dYaw, dRoll) as our local angular velocity
// representation, we can't actually solve this problem
/*
void CBaseEntity::SetAbsAngularVelocity( const QAngle &vecAbsAngVelocity )
{
// The abs velocity won't be dirty since we're setting it here
// All children are invalid, but we are not
InvalidatePhysicsRecursive( EFL_DIRTY_ABSANGVELOCITY );
RemoveEFlags( EFL_DIRTY_ABSANGVELOCITY );
m_vecAbsAngVelocity = vecAbsAngVelocity;
CBaseEntity *pMoveParent = GetMoveParent();
if (!pMoveParent)
{
m_vecAngVelocity = vecAbsAngVelocity;
return;
}
// NOTE: We *can't* subtract out parent ang velocity, it's nonsensical
matrix3x4_t entityToWorld;
AngleMatrix( vecAbsAngVelocity, entityToWorld );
// Moveparent case: transform the abs relative angular vel into local space
matrix3x4_t worldToParent, localMatrix;
MatrixInvert( pMoveParent->EntityToWorldTransform(), worldToParent );
ConcatTransforms( worldToParent, entityToWorld, localMatrix );
MatrixAngles( localMatrix, m_vecAngVelocity );
}
*/
//-----------------------------------------------------------------------------
// Methods that modify local physics state, and let us know to compute abs state later
//-----------------------------------------------------------------------------
void CBaseEntity::SetLocalOrigin( const Vector& origin )
{
// Safety check against NaN's or really huge numbers
if ( !IsEntityPositionReasonable( origin ) )
{
if ( CheckEmitReasonablePhysicsSpew() )
{
Warning( "Bad SetLocalOrigin(%f,%f,%f) on %s\n", origin.x, origin.y, origin.z, GetDebugName() );
}
Assert( false );
return;
}
// if ( !origin.IsValid() )
// {
// AssertMsg( 0, "Bad origin set" );
// return;
// }
if (m_vecOrigin != origin)
{
// Sanity check to make sure the origin is valid.
#ifdef _DEBUG
float largeVal = 1024 * 128;
Assert( origin.x >= -largeVal && origin.x <= largeVal );
Assert( origin.y >= -largeVal && origin.y <= largeVal );
Assert( origin.z >= -largeVal && origin.z <= largeVal );
#endif
InvalidatePhysicsRecursive( POSITION_CHANGED );
m_vecOrigin = origin;
SetSimulationTime( gpGlobals->curtime );
}
}
void CBaseEntity::SetLocalAngles( const QAngle& angles )
{
// NOTE: The angle normalize is a little expensive, but we can save
// a bunch of time in interpolation if we don't have to invalidate everything
// and sometimes it's off by a normalization amount
// FIXME: The normalize caused problems in server code like momentary_rot_button that isn't
// handling things like +/-180 degrees properly. This should be revisited.
//QAngle angleNormalize( AngleNormalize( angles.x ), AngleNormalize( angles.y ), AngleNormalize( angles.z ) );
// Safety check against NaN's or really huge numbers
if ( !IsEntityQAngleReasonable( angles ) )
{
if ( CheckEmitReasonablePhysicsSpew() )
{
Warning( "Bad SetLocalAngles(%f,%f,%f) on %s\n", angles.x, angles.y, angles.z, GetDebugName() );
}
Assert( false );
return;
}
if (m_angRotation != angles)
{
InvalidatePhysicsRecursive( ANGLES_CHANGED );
m_angRotation = angles;
SetSimulationTime( gpGlobals->curtime );
}
}
void CBaseEntity::SetLocalVelocity( const Vector &inVecVelocity )
{
Vector vecVelocity = inVecVelocity;
// Safety check against receive a huge impulse, which can explode physics
switch ( CheckEntityVelocity( vecVelocity ) )
{
case -1:
Warning( "Discarding SetLocalVelocity(%f,%f,%f) on %s\n", vecVelocity.x, vecVelocity.y, vecVelocity.z, GetDebugName() );
Assert( false );
return;
case 0:
if ( CheckEmitReasonablePhysicsSpew() )
{
Warning( "Clamping SetLocalVelocity(%f,%f,%f) on %s\n", inVecVelocity.x, inVecVelocity.y, inVecVelocity.z, GetDebugName() );
}
break;
}
if (m_vecVelocity != vecVelocity)
{
InvalidatePhysicsRecursive( VELOCITY_CHANGED );
m_vecVelocity = vecVelocity;
}
}
void CBaseEntity::SetLocalAngularVelocity( const QAngle &vecAngVelocity )
{
// Safety check against NaN's or really huge numbers
if ( !IsEntityQAngleVelReasonable( vecAngVelocity ) )
{
if ( CheckEmitReasonablePhysicsSpew() )
{
Warning( "Bad SetLocalAngularVelocity(%f,%f,%f) on %s\n", vecAngVelocity.x, vecAngVelocity.y, vecAngVelocity.z, GetDebugName() );
}
Assert( false );
return;
}
if (m_vecAngVelocity != vecAngVelocity)
{
// InvalidatePhysicsRecursive( EFL_DIRTY_ABSANGVELOCITY );
m_vecAngVelocity = vecAngVelocity;
}
}
//-----------------------------------------------------------------------------
// Sets the local position from a transform
//-----------------------------------------------------------------------------
void CBaseEntity::SetLocalTransform( const matrix3x4_t &localTransform )
{
// FIXME: Should angles go away? Should we just use transforms?
Vector vecLocalOrigin;
QAngle vecLocalAngles;
MatrixGetColumn( localTransform, 3, vecLocalOrigin );
MatrixAngles( localTransform, vecLocalAngles );
SetLocalOrigin( vecLocalOrigin );
SetLocalAngles( vecLocalAngles );
}
//-----------------------------------------------------------------------------
// Is the entity floating?
//-----------------------------------------------------------------------------
bool CBaseEntity::IsFloating()
{
if ( !IsEFlagSet(EFL_TOUCHING_FLUID) )
return false;
IPhysicsObject *pObject = VPhysicsGetObject();
if ( !pObject )
return false;
int nMaterialIndex = pObject->GetMaterialIndex();
float flDensity;
float flThickness;
float flFriction;
float flElasticity;
physprops->GetPhysicsProperties( nMaterialIndex, &flDensity,
&flThickness, &flFriction, &flElasticity );
// FIXME: This really only works for water at the moment..
// Owing the check for density == 1000
return (flDensity < 1000.0f);
}
//-----------------------------------------------------------------------------
// Purpose: Created predictable and sets up Id. Note that persist is ignored on the server.
// Input : *classname -
// *module -
// line -
// persist -
// Output : CBaseEntity
//-----------------------------------------------------------------------------
CBaseEntity *CBaseEntity::CreatePredictedEntityByName( const char *classname, const char *module, int line, bool persist /* = false */ )
{
#if !defined( NO_ENTITY_PREDICTION )
CBasePlayer *player = CBaseEntity::GetPredictionPlayer();
Assert( player );
CBaseEntity *ent = NULL;
int command_number = player->CurrentCommandNumber();
int player_index = player->entindex() - 1;
CPredictableId testId;
testId.Init( player_index, command_number, classname, module, line );
ent = CreateEntityByName( classname );
// No factory???
if ( !ent )
return NULL;
ent->SetPredictionEligible( true );
// Set up "shared" id number
ent->m_PredictableID.GetForModify().SetRaw( testId.GetRaw() );
return ent;
#else
return NULL;
#endif
}
void CBaseEntity::SetPredictionEligible( bool canpredict )
{
// Nothing in game code m_bPredictionEligible = canpredict;
}
//-----------------------------------------------------------------------------
// These could be virtual, but only the player is overriding them
// NOTE: If you make any of these virtual, remove this implementation!!!
//-----------------------------------------------------------------------------
void CBaseEntity::AddPoints( int score, bool bAllowNegativeScore )
{
CBasePlayer *pPlayer = ToBasePlayer(this);
if ( pPlayer )
{
pPlayer->CBasePlayer::AddPoints( score, bAllowNegativeScore );
}
}
void CBaseEntity::AddPointsToTeam( int score, bool bAllowNegativeScore )
{
CBasePlayer *pPlayer = ToBasePlayer(this);
if ( pPlayer )
{
pPlayer->CBasePlayer::AddPointsToTeam( score, bAllowNegativeScore );
}
}
void CBaseEntity::ViewPunch( const QAngle &angleOffset )
{
CBasePlayer *pPlayer = ToBasePlayer(this);
if ( pPlayer )
{
pPlayer->CBasePlayer::ViewPunch( angleOffset );
}
}
void CBaseEntity::VelocityPunch( const Vector &vecForce )
{
CBasePlayer *pPlayer = ToBasePlayer(this);
if ( pPlayer )
{
pPlayer->CBasePlayer::VelocityPunch( vecForce );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Tell clients to remove all decals from this entity
//-----------------------------------------------------------------------------
void CBaseEntity::RemoveAllDecals( void )
{
EntityMessageBegin( this );
WRITE_BYTE( BASEENTITY_MSG_REMOVE_DECALS );
MessageEnd();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : set -
//-----------------------------------------------------------------------------
void CBaseEntity::ModifyOrAppendCriteria( AI_CriteriaSet& set )
{
// TODO
// Append chapter/day?
set.AppendCriteria( "randomnum", UTIL_VarArgs("%d", RandomInt(0,100)) );
// Append map name
set.AppendCriteria( "map", gpGlobals->mapname.ToCStr() );
// Append our classname and game name
set.AppendCriteria( "classname", GetClassname() );
set.AppendCriteria( "name", GetEntityName().ToCStr() );
// Append our health
set.AppendCriteria( "health", UTIL_VarArgs( "%i", GetHealth() ) );
float healthfrac = 0.0f;
if ( GetMaxHealth() > 0 )
{
healthfrac = (float)GetHealth() / (float)GetMaxHealth();
}
set.AppendCriteria( "healthfrac", UTIL_VarArgs( "%.3f", healthfrac ) );
// Go through all the global states and append them
for ( int i = 0; i < GlobalEntity_GetNumGlobals(); i++ )
{
const char *szGlobalName = GlobalEntity_GetName(i);
int iGlobalState = (int)GlobalEntity_GetStateByIndex(i);
set.AppendCriteria( szGlobalName, UTIL_VarArgs( "%i", iGlobalState ) );
}
#ifndef MAPBASE // We do this later now so contexts can override criteria. I originally didn't want to remove it here in case there would be problems, but I think I have all of the bases covered.
2013-12-02 19:31:46 -08:00
// Append anything from I/O or keyvalues pairs
AppendContextToCriteria( set );
#endif
2013-12-02 19:31:46 -08:00
if( hl2_episodic.GetBool() )
{
set.AppendCriteria( "episodic", "1" );
}
// Append anything from world I/O/keyvalues with "world" as prefix
#ifdef MAPBASE
CWorld *world = GetWorldEntity();
#else
2013-12-02 19:31:46 -08:00
CWorld *world = dynamic_cast< CWorld * >( CBaseEntity::Instance( engine->PEntityOfEntIndex( 0 ) ) );
#endif
2013-12-02 19:31:46 -08:00
if ( world )
{
world->AppendContextToCriteria( set, "world" );
}
#ifdef MAPBASE
// Append base stuff
set.AppendCriteria("spawnflags", UTIL_VarArgs("%i", GetSpawnFlags()));
set.AppendCriteria("flags", UTIL_VarArgs("%i", GetFlags()));
#endif
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : set -
// "" -
//-----------------------------------------------------------------------------
void CBaseEntity::AppendContextToCriteria( AI_CriteriaSet& set, const char *prefix /*= ""*/ )
{
RemoveExpiredConcepts();
int c = GetContextCount();
int i;
char sz[ 128 ];
for ( i = 0; i < c; i++ )
{
const char *name = GetContextName( i );
const char *value = GetContextValue( i );
Q_snprintf( sz, sizeof( sz ), "%s%s", prefix, name );
set.AppendCriteria( sz, value );
}
}
#ifdef MAPBASE
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose:
// Input : set -
// "" -
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
void CBaseEntity::ReAppendContextCriteria( AI_CriteriaSet& set )
{
// Append contexts again. This allows it to override standard criteria, including that of derived classes.
CWorld *world = GetWorldEntity();
if ( world )
{
// I didn't know this until recently, but world contexts are actually prefixed by "world".
// I'm changing this here to reduce confusion and allow greater potential.
// (e.g. disabling combine soldier episodic on/off in Episodic binaries with world context "episodic:0", even though that's not happening anymore)
// The old prefixed ones still exist. They're just not appended again.
world->AppendContextToCriteria( set );
}
AppendContextToCriteria( set );
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Removes expired concepts from list
// Output :
//-----------------------------------------------------------------------------
void CBaseEntity::RemoveExpiredConcepts( void )
2013-12-02 19:31:46 -08:00
{
int c = GetContextCount();
int i;
for ( i = 0; i < c; i++ )
{
if ( ContextExpired( i ) )
{
m_ResponseContexts.Remove( i );
c--;
i--;
continue;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Get current context count
// Output : int
//-----------------------------------------------------------------------------
int CBaseEntity::GetContextCount() const
{
return m_ResponseContexts.Count();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : const char
//-----------------------------------------------------------------------------
const char *CBaseEntity::GetContextName( int index ) const
{
if ( index < 0 || index >= m_ResponseContexts.Count() )
{
Assert( 0 );
return "";
}
return m_ResponseContexts[ index ].m_iszName.ToCStr();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : const char
//-----------------------------------------------------------------------------
const char *CBaseEntity::GetContextValue( int index ) const
{
if ( index < 0 || index >= m_ResponseContexts.Count() )
{
Assert( 0 );
return "";
}
return m_ResponseContexts[ index ].m_iszValue.ToCStr();
}
//-----------------------------------------------------------------------------
// Purpose: Check if context has expired
// Input : index -
// Output : bool
//-----------------------------------------------------------------------------
bool CBaseEntity::ContextExpired( int index ) const
{
if ( index < 0 || index >= m_ResponseContexts.Count() )
{
Assert( 0 );
return true;
}
if ( !m_ResponseContexts[ index ].m_fExpirationTime )
{
return false;
}
return ( m_ResponseContexts[ index ].m_fExpirationTime <= gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose: Search for index of named context string
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int CBaseEntity::FindContextByName( const char *name ) const
{
int c = m_ResponseContexts.Count();
for ( int i = 0; i < c; i++ )
{
if ( FStrEq( name, GetContextName( i ) ) )
return i;
}
return -1;
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Searches entity for named context string and/or value.
// Intended to be called by entities rather than the conventional response system.
// Input : *name - Context name.
// *value - Context value. (optional)
// Output : bool
//-----------------------------------------------------------------------------
bool CBaseEntity::HasContext( const char *name, const char *value ) const
{
int c = m_ResponseContexts.Count();
for ( int i = 0; i < c; i++ )
{
if ( Matcher_NamesMatch( name, STRING(m_ResponseContexts[i].m_iszName) ) )
{
if (value == NULL)
return true;
else
Mapbase v3.0 - Overhauled matcher system and added expanded wildcard support, meaning "text", "te?t", "blah_test", etc. are now supported instead of only trailing * - Added support for regular expression matching - Added the missing matrixinvert.h file, which prevented programmers from compiling vbsp - Fixed env_global_light brightness - Added info_player_view_proxy, an entity which mimics a player's view (created for script_intro) - New UnZoomWithRate and SetZoomRate inputs on env_zoom - New "Don't change target's angles" flag on logic_measure_movement - Fixed logic_measure_movement not using ignore origin flags correctly - Fixed filter_damage_mod secondary filter not recognizing mode correctly - Fixed DisableGeigerCounter causing NPCs to ignore player, and possibly fixed other adverse effects in similar code - Added SetEntityName input for setting an entity's targetname - Added "SetTarget" support to point_posecontroller - Added "sk_alyx_health" convar for adjustable npc_alyx health, restored/fixed "sk_barney_health" for adjustable npc_barney health - Added ignore flags and several direction-related inputs to math_vector - Added pose parameter stuff to logic_modelinfo - Fixed ChangeWeapon not changing during combat - Fixed holster/unholster on NPCs without holster/unholster animations - Fixed func_tank and other "player in the way" code ignoring notarget - Added SetPoseParameter input to animating entities - Introduced an experimental chapter system which allows for custom chapter title/restriction management - Added SetChapterTitle input to worldspawn for dynamic title changing - Fixed func_tankairboatgun damage credit, added ability to use its damage keyvalues - Fixed mapbase_rpc_enabled not actually affecting RPC - Moved some newly found Combine soldier grenade code to ai_grenade for other grenade users - Fixed some problems with the new shared activities - Restored an old Mapbase entity as "prop_interactable", an entity which contains all of the functionality of a func_button/func_door in a prop entity - Added env_microphone pitch scale for scaling the pitch of transmitted sounds - Added experimental, long-overdue code for scenes to be able to access !target#'s and other scene-related names through AI_INPUT - Added "mat_specular_disable_on_missing", which "disables" specular reflections when the cubemap texture is missing - Fixed $envmapmasktransform and $bumptransform on VertexLitGeneric and related shaders - Areaportal leaks now stop compilation in leaktest - Replaced "-nodefaultcubemap" with "-defaultcubemap" as the shader changes allow maps to compile without default cubemaps by default with little effect
2020-02-05 19:08:49 +00:00
return Matcher_Match(STRING(m_ResponseContexts[i].m_iszValue), value);
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Searches entity for named context string and/or value.
// Intended to be called by entities rather than the conventional response system.
// Input : *name - Context name.
// *value - Context value. (optional)
// Output : bool
//-----------------------------------------------------------------------------
bool CBaseEntity::HasContext( string_t name, string_t value ) const
{
int c = m_ResponseContexts.Count();
for ( int i = 0; i < c; i++ )
{
if ( name == m_ResponseContexts[i].m_iszName )
{
if (value == NULL_STRING)
return true;
else
return value == m_ResponseContexts[i].m_iszValue;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Searches entity for named context string and/or value.
// Intended to be called by entities rather than the conventional response system.
// Input : *nameandvalue - Context name and value.
// Output : bool
//-----------------------------------------------------------------------------
bool CBaseEntity::HasContext( const char *nameandvalue ) const
{
char key[ 128 ];
char value[ 128 ];
const char *p = nameandvalue;
while ( p )
{
p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL );
return HasContext( key, value );
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : const char
//-----------------------------------------------------------------------------
const char *CBaseEntity::GetContextValue( const char *contextName ) const
{
int idx = FindContextByName( contextName );
if ( idx == -1 )
Mapbase v2.0; bulk commit - Added custom map compile tools (vbsp, vvis, vrad) - Changed blink fix (shouldn't change anything in-game) - Added auto-completion to ent_create, npc_create, and the main set of "npc_" debug commands - Added ent_create_aimed, an ent_create equivalent of npc_create_aimed - Made hunters start using the "vs. player" melee animation against smaller NPCs that look weird with the "stab" attack - Added "explosion_sparks" convar, which fixes broken code for giving explosions sparks (disabled by default because of how different it looks) - Made interaction code capable of being dispatched on any entity, not just combat characters - Added npc_barnacle_ignite convar, which lets barnacles be ignited by flares - Fixed certain NPCs getting out of the way for the player when they hate them - Fixed auto-generated "speak" scene responses not using parameters that work on real VCDs - Made "stop_on_nonidle" capable of being used in any mod, not just HL2 episodic mods - Selectable color for ragdoll boogie/point_ragdollboogie - Fixed PickupWeaponInstant not firing weapon pickup outputs - Introduced inputs and keyvalues for "lerping" to math_counter_advanced - Fixed ClearConsole on logic_console - logic_convar should now detect client convars correctly - New NormalizeAngles input on math_vector - logic_modelinfo LookupActivity input - math_generate fixed and expanded to be more like math_counter - Added a WIP game logging system for playtesting maps - Introduced logic_playerinfo, an entity that can read a player's name or ID - Fixed some new filters not working with filter_multi - Added radius pickup spawnflag to func_physbox - Added "Preserve name" spawnflag to weapons - Added cc_achievement_debug message for when an achievement doesn't exist - Made npc_combine_s not speak while in logic_choreographed_scenes - Fixed zombie torsos/legs/headcrabs not being serverside when zombie is forced to server ragdoll - Expanded and cleaned up npc_zombie_custom - Fixed func_commandredirects not cleaning up correctly and sometimes crashing the game - Allowed player squad commands to go through +USE-held objects - Added a bunch of I/O/KV to trigger_waterydeath for better configuration - Changed save comment system to use the chapter title from world properties, and the ability to suppress the title popup that normally results from it - Adjusted game_convar_mod for MP planning - Removed the func_precipitation custom particle/splash code for now, as it was causing problems - Fixed env_global_light not accepting lightcolor - Added "Additional Buttons" to player_speedmod - Added save comment to RPC - Added env_projectedtexture attenuation - Added scripted_sequence OnPreIdleSequence - Added OnCrab to zombies - Added skill_changed game event (may need further testing) - Added a fix for viewmodels flipping under extreme FOV values - Added code that allows mappers to change the skin on shotgunners without it usually flipping back randomly - Fixed a very, very, very major shader performance issue - New SetAbsOrigin/Angles inputs on all entities, analogous to SetLocalOrigin/Angles - Code improvements for I/O involving angles - logic_entity_position improvements/fixes, including a new OutAngles output that outputs the angles on position calls - Alternate collision/player avoidance spawnflag obsoletion enforcement disabled - Enable/DisableHazardLights inputs on the EP2 jalopy, equivalent to the keyvalue - Miscellaneous shader formatting adjustments and fixes - Fixed AlwaysDrawOff on env_projectedtexture not being a valid input
2019-12-14 04:20:02 +00:00
return "";
return m_ResponseContexts[ idx ].m_iszValue.ToCStr();
}
//-----------------------------------------------------------------------------
// Purpose: Internal method or removing contexts and can remove multiple contexts in one call
// Input : *contextName -
//-----------------------------------------------------------------------------
void CBaseEntity::RemoveContext( const char *contextName )
{
char key[ 128 ];
char value[ 128 ];
float duration;
const char *p = contextName;
while ( p )
{
duration = 0.0f;
p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), &duration );
if ( duration )
{
duration += gpGlobals->curtime;
}
int iIndex = FindContextByName( key );
if ( iIndex != -1 )
{
m_ResponseContexts.Remove( iIndex );
}
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CBaseEntity::InputAddContext( inputdata_t& inputdata )
{
const char *contextName = inputdata.value.String();
AddContext( contextName );
}
//-----------------------------------------------------------------------------
// Purpose: User inputs. These fire the corresponding user outputs, and are
// a means of forwarding messages through !activator to a target known
// known by !activator but not by the targetting entity.
//
// For example, say you have three identical trains, following the same
// path. Each train has a sprite in hierarchy with it that needs to
// toggle on/off as it passes each path_track. You would hook each train's
// OnUser1 output to it's sprite's Toggle input, then connect each path_track's
// OnPass output to !activator's FireUser1 input.
//-----------------------------------------------------------------------------
void CBaseEntity::InputFireUser1( inputdata_t& inputdata )
{
m_OnUser1.FireOutput( inputdata.pActivator, this );
}
void CBaseEntity::InputFireUser2( inputdata_t& inputdata )
{
m_OnUser2.FireOutput( inputdata.pActivator, this );
}
void CBaseEntity::InputFireUser3( inputdata_t& inputdata )
{
m_OnUser3.FireOutput( inputdata.pActivator, this );
}
void CBaseEntity::InputFireUser4( inputdata_t& inputdata )
{
m_OnUser4.FireOutput( inputdata.pActivator, this );
}
#ifdef MAPBASE
void CBaseEntity::InputPassUser1( inputdata_t& inputdata )
{
m_OutUser1.Set( inputdata.value, inputdata.pActivator, this );
}
void CBaseEntity::InputPassUser2( inputdata_t& inputdata )
{
m_OutUser2.Set( inputdata.value, inputdata.pActivator, this );
}
void CBaseEntity::InputPassUser3( inputdata_t& inputdata )
{
m_OutUser3.Set( inputdata.value, inputdata.pActivator, this );
}
void CBaseEntity::InputPassUser4( inputdata_t& inputdata )
{
m_OutUser4.Set( inputdata.value, inputdata.pActivator, this );
}
void CBaseEntity::InputFireRandomUser( inputdata_t& inputdata )
{
switch (RandomInt(1, 4))
{
case 1: m_OnUser1.FireOutput( inputdata.pActivator, this ); break;
case 2: m_OnUser2.FireOutput( inputdata.pActivator, this ); break;
case 3: m_OnUser3.FireOutput( inputdata.pActivator, this ); break;
case 4: m_OnUser4.FireOutput( inputdata.pActivator, this ); break;
}
}
void CBaseEntity::InputPassRandomUser( inputdata_t& inputdata )
{
switch (RandomInt(1, 4))
{
case 1: m_OutUser1.Set( inputdata.value, inputdata.pActivator, this ); break;
case 2: m_OutUser2.Set( inputdata.value, inputdata.pActivator, this ); break;
case 3: m_OutUser3.Set( inputdata.value, inputdata.pActivator, this ); break;
case 4: m_OutUser4.Set( inputdata.value, inputdata.pActivator, this ); break;
}
}
#endif
#ifdef MAPBASE
Mapbase v3.0 - Overhauled matcher system and added expanded wildcard support, meaning "text", "te?t", "blah_test", etc. are now supported instead of only trailing * - Added support for regular expression matching - Added the missing matrixinvert.h file, which prevented programmers from compiling vbsp - Fixed env_global_light brightness - Added info_player_view_proxy, an entity which mimics a player's view (created for script_intro) - New UnZoomWithRate and SetZoomRate inputs on env_zoom - New "Don't change target's angles" flag on logic_measure_movement - Fixed logic_measure_movement not using ignore origin flags correctly - Fixed filter_damage_mod secondary filter not recognizing mode correctly - Fixed DisableGeigerCounter causing NPCs to ignore player, and possibly fixed other adverse effects in similar code - Added SetEntityName input for setting an entity's targetname - Added "SetTarget" support to point_posecontroller - Added "sk_alyx_health" convar for adjustable npc_alyx health, restored/fixed "sk_barney_health" for adjustable npc_barney health - Added ignore flags and several direction-related inputs to math_vector - Added pose parameter stuff to logic_modelinfo - Fixed ChangeWeapon not changing during combat - Fixed holster/unholster on NPCs without holster/unholster animations - Fixed func_tank and other "player in the way" code ignoring notarget - Added SetPoseParameter input to animating entities - Introduced an experimental chapter system which allows for custom chapter title/restriction management - Added SetChapterTitle input to worldspawn for dynamic title changing - Fixed func_tankairboatgun damage credit, added ability to use its damage keyvalues - Fixed mapbase_rpc_enabled not actually affecting RPC - Moved some newly found Combine soldier grenade code to ai_grenade for other grenade users - Fixed some problems with the new shared activities - Restored an old Mapbase entity as "prop_interactable", an entity which contains all of the functionality of a func_button/func_door in a prop entity - Added env_microphone pitch scale for scaling the pitch of transmitted sounds - Added experimental, long-overdue code for scenes to be able to access !target#'s and other scene-related names through AI_INPUT - Added "mat_specular_disable_on_missing", which "disables" specular reflections when the cubemap texture is missing - Fixed $envmapmasktransform and $bumptransform on VertexLitGeneric and related shaders - Areaportal leaks now stop compilation in leaktest - Replaced "-nodefaultcubemap" with "-defaultcubemap" as the shader changes allow maps to compile without default cubemaps by default with little effect
2020-02-05 19:08:49 +00:00
//-----------------------------------------------------------------------------
// Purpose: Sets the entity's targetname.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetEntityName( inputdata_t& inputdata )
{
SetName( inputdata.value.StringID() );
}
//-----------------------------------------------------------------------------
// Purpose: Sets the generic target field.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetTarget( inputdata_t& inputdata )
{
m_target = inputdata.value.StringID();
Activate();
}
//-----------------------------------------------------------------------------
// Purpose: Sets our owner entity.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetOwnerEntity( inputdata_t& inputdata )
{
SetOwnerEntity(inputdata.value.Entity());
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for adding to the entity's health.
// Input : Integer health points to add.
//-----------------------------------------------------------------------------
void CBaseEntity::InputAddHealth( inputdata_t &inputdata )
{
TakeHealth( abs(inputdata.value.Int()), DMG_GENERIC );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for removing health from the entity.
// Input : Integer health points to remove.
//-----------------------------------------------------------------------------
void CBaseEntity::InputRemoveHealth( inputdata_t &inputdata )
{
TakeDamage( CTakeDamageInfo( this, this, abs(inputdata.value.Int()), DMG_GENERIC ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetHealth( inputdata_t &inputdata )
{
int iNewHealth = inputdata.value.Int();
int iDelta = abs(GetHealth() - iNewHealth);
if ( iNewHealth > GetHealth() )
{
TakeHealth( iDelta, DMG_GENERIC );
}
else if ( iNewHealth < GetHealth() )
{
TakeDamage( CTakeDamageInfo( this, this, iDelta, DMG_GENERIC ) );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetMaxHealth( inputdata_t &inputdata )
{
int iNewMaxHealth = inputdata.value.Int();
SetMaxHealth(iNewMaxHealth);
if (GetHealth() > iNewMaxHealth)
{
SetHealth(iNewMaxHealth);
}
}
//-----------------------------------------------------------------------------
// Purpose: Forces the named output to fire.
// In addition to the output itself, parameter may include !activator, !caller, and what to pass.
//-----------------------------------------------------------------------------
void CBaseEntity::InputFireOutput( inputdata_t& inputdata )
{
char sParameter[MAX_PATH];
Q_strncpy( sParameter, inputdata.value.String(), sizeof(sParameter) );
if ( sParameter )
{
int iter = 0;
char *data[5] = {sParameter};
char *sToken = strtok( sParameter, ":" );
while ( sToken && iter < 5 )
{
data[iter] = sToken;
iter++;
sToken = strtok( NULL, ":" );
}
//DevMsg("data[0]: %s\ndata[1]: %s\ndata[2]: %s\ndata[3]: %s\ndata[4]: %s\n", data[0], data[1], data[2], data[3], data[4]);
// Format: <output name>:<activator>:<caller>:<parameter>:<delay>
//
// data[0] = Output Name
// data[1] = Activator
// data[2] = Caller
// data[3] = Parameter
// data[4] = Delay
//
CBaseEntity *pActivator = inputdata.pActivator;
if (data[1])
pActivator = gEntList.FindEntityByName(NULL, data[1], this, inputdata.pActivator, inputdata.pCaller);
CBaseEntity *pCaller = this;
if (data[2])
pCaller = gEntList.FindEntityByName(NULL, data[2], this, inputdata.pActivator, inputdata.pCaller);
variant_t parameter;
if (data[3])
{
parameter.SetString(MAKE_STRING(data[3]));
}
float flDelay = 0.0f;
if (data[4])
flDelay = atof(data[4]);
FireNamedOutput(data[0], parameter, pActivator, pCaller, flDelay);
//Msg("Output Name: %s, Activator: %s, Caller: %s, Data: %s, Delay: %f\n", data[0], pActivator->GetDebugName(), pCaller->GetDebugName(), parameter.String(), flDelay);
}
else
{
Warning("FireOutput input fired with bad parameter. Format: <output name>:<activator>:<caller>:<parameter>:<delay>\n");
}
}
//-----------------------------------------------------------------------------
// Purpose: Removes all outputs of the specified name.
//-----------------------------------------------------------------------------
void CBaseEntity::InputRemoveOutput( inputdata_t& inputdata )
{
const char *szOutput = inputdata.value.String();
datamap_t *dmap = GetDataDescMap();
while ( dmap )
{
int fields = dmap->dataNumFields;
for ( int i = 0; i < fields; i++ )
{
typedescription_t *dataDesc = &dmap->dataDesc[i];
if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) )
{
// If our names match, remove
if (Matcher_NamesMatch(szOutput, dataDesc->externalName))
{
CBaseEntityOutput *pOutput = (CBaseEntityOutput *)((int)this + (int)dataDesc->fieldOffset[0]);
pOutput->DeleteAllElements();
}
}
}
dmap = dmap->baseMap;
}
}
// Find a way to implement this
/*
//------------------------------------------------------------------------------
// Purpose: Cancels all I/O events of a specific output.
//------------------------------------------------------------------------------
void CBaseEntity::InputCancelOutput( inputdata_t &inputdata )
{
}
*/
//-----------------------------------------------------------------------------
// Purpose: Replaces all outputs of the specified name.
//-----------------------------------------------------------------------------
void CBaseEntity::InputReplaceOutput( inputdata_t& inputdata )
{
char sParameter[128];
Q_strncpy( sParameter, inputdata.value.String(), sizeof(sParameter) );
if (!sParameter)
return;
int iter = 0;
char *data[2];
char *sToken = strtok( sParameter, ": " );
while ( sToken && iter < 2 )
{
data[iter] = sToken;
iter++;
sToken = strtok( NULL, ": " );
}
const char *szOutput = data[0];
const char *szNewOutput = data[1];
if (!szOutput || !szNewOutput)
{
Warning("ReplaceOutput input fired with bad parameter. Format: <old output name>:<new output name>\n");
return;
}
int iOutputsReplaced = 0;
datamap_t *dmap = GetDataDescMap();
while ( dmap )
{
int fields = dmap->dataNumFields;
for ( int i = 0; i < fields; i++ )
{
typedescription_t *dataDesc = &dmap->dataDesc[i];
if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) )
{
// If our names match, replace
if (Matcher_NamesMatch(szOutput, dataDesc->externalName))
{
CBaseEntityOutput *pOutput = (CBaseEntityOutput *)((int)this + (int)dataDesc->fieldOffset[0]);
const char *szTarget;
const char *szInputName;
const char *szParam;
float flDelay;
int iNumTimes;
char szData[256];
for ( CEventAction *ev = pOutput->GetActionList(); ev != NULL; ev = ev->m_pNext )
{
// This is the only way I think we could do this. Accomplishes the job more or less anyway
szTarget = STRING(ev->m_iTarget);
szInputName = STRING(ev->m_iTargetInput);
szParam = ev->m_iParameter == NULL_STRING ? "" : STRING(ev->m_iParameter);
flDelay = ev->m_flDelay;
iNumTimes = ev->m_nTimesToFire;
Q_snprintf(szData, sizeof(szData), "%s,%s,%s,%f,%i", szTarget, szInputName, szParam, flDelay, iNumTimes);
KeyValue(szNewOutput, szData);
DevMsg("ReplaceOutput: %s %s\n", szNewOutput, szData);
iOutputsReplaced++;
}
pOutput->DeleteAllElements();
}
}
}
dmap = dmap->baseMap;
}
if (iOutputsReplaced == 0)
{
Warning("ReplaceOutput unable to find %s on %s\n", szOutput, GetDebugName());
}
else
{
DevMsg("Replaced %i instances of %s with %s on %s\n", iOutputsReplaced, szOutput, szNewOutput, GetDebugName());
}
}
//-----------------------------------------------------------------------------
// Purpose: Forces the named input to fire...what?
// Inputception...or is it just "Inception"? Whatever.
// True inception would be using this input to fire AcceptInput.
// (it would probably crash, I haven't tested it)
//
// In addition to the input itself, parameter may include !activator, !caller, and what to pass.
//-----------------------------------------------------------------------------
void CBaseEntity::InputAcceptInput( inputdata_t& inputdata )
{
char sParameter[MAX_PATH];
Q_strncpy( sParameter, inputdata.value.String(), sizeof(sParameter) );
if ( sParameter )
{
int iter = 0;
char *data[5] = {sParameter};
char *sToken = strtok( sParameter, ":" );
while ( sToken && iter < 5 )
{
data[iter] = sToken;
iter++;
sToken = strtok( NULL, ":" );
}
//DevMsg("data[0]: %s\ndata[1]: %s\ndata[2]: %s\ndata[3]: %s\ndata[4]: %s\n", data[0], data[1], data[2], data[3], data[4]);
// Format: <input name>:<parameter>:<activator>:<caller>:<output ID>
//
// data[0] = Input Name
// data[1] = Parameter
// data[2] = Activator
// data[3] = Caller
// data[4] = Output ID
//
variant_t parameter;
if (data[1])
{
parameter.SetString(MAKE_STRING(data[1]));
}
CBaseEntity *pActivator = inputdata.pActivator;
if (data[2])
pActivator = gEntList.FindEntityByName(NULL, data[2], this, inputdata.pActivator, inputdata.pCaller);
CBaseEntity *pCaller = this;
if (data[3])
pCaller = gEntList.FindEntityByName(NULL, data[3], this, inputdata.pActivator, inputdata.pCaller);
int iOutputID = -1;
if (data[4])
iOutputID = atoi(data[4]);
AcceptInput(data[0], pActivator, pCaller, parameter, iOutputID);
Msg("Input Name: %s, Activator: %s, Caller: %s, Data: %s, Output ID: %i\n", data[0], pActivator ? pActivator->GetDebugName() : "None", pCaller ? pCaller->GetDebugName() : "None", parameter.String(), iOutputID);
}
else
{
Warning("AcceptInput input fired with bad parameter. Format: <input name>:<parameter>:<activator>:<caller>:<output ID>\n");
}
}
//------------------------------------------------------------------------------
// Purpose: Cancels any I/O events in the queue that were fired by this entity.
//------------------------------------------------------------------------------
void CBaseEntity::InputCancelPending( inputdata_t &inputdata )
{
g_EventQueue.CancelEvents( this );
}
//-----------------------------------------------------------------------------
// Purpose: Frees all of our children, entities parented to this entity.
//-----------------------------------------------------------------------------
void CBaseEntity::InputFreeChildren( inputdata_t& inputdata )
{
UnlinkAllChildren( this );
}
//-----------------------------------------------------------------------------
// Purpose: Sets our origin.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetLocalOrigin( inputdata_t& inputdata )
{
Vector vec;
inputdata.value.Vector3D(vec);
SetLocalOrigin(vec);
}
//-----------------------------------------------------------------------------
// Purpose: Sets our angles.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetLocalAngles( inputdata_t& inputdata )
Mapbase v2.0; bulk commit - Added custom map compile tools (vbsp, vvis, vrad) - Changed blink fix (shouldn't change anything in-game) - Added auto-completion to ent_create, npc_create, and the main set of "npc_" debug commands - Added ent_create_aimed, an ent_create equivalent of npc_create_aimed - Made hunters start using the "vs. player" melee animation against smaller NPCs that look weird with the "stab" attack - Added "explosion_sparks" convar, which fixes broken code for giving explosions sparks (disabled by default because of how different it looks) - Made interaction code capable of being dispatched on any entity, not just combat characters - Added npc_barnacle_ignite convar, which lets barnacles be ignited by flares - Fixed certain NPCs getting out of the way for the player when they hate them - Fixed auto-generated "speak" scene responses not using parameters that work on real VCDs - Made "stop_on_nonidle" capable of being used in any mod, not just HL2 episodic mods - Selectable color for ragdoll boogie/point_ragdollboogie - Fixed PickupWeaponInstant not firing weapon pickup outputs - Introduced inputs and keyvalues for "lerping" to math_counter_advanced - Fixed ClearConsole on logic_console - logic_convar should now detect client convars correctly - New NormalizeAngles input on math_vector - logic_modelinfo LookupActivity input - math_generate fixed and expanded to be more like math_counter - Added a WIP game logging system for playtesting maps - Introduced logic_playerinfo, an entity that can read a player's name or ID - Fixed some new filters not working with filter_multi - Added radius pickup spawnflag to func_physbox - Added "Preserve name" spawnflag to weapons - Added cc_achievement_debug message for when an achievement doesn't exist - Made npc_combine_s not speak while in logic_choreographed_scenes - Fixed zombie torsos/legs/headcrabs not being serverside when zombie is forced to server ragdoll - Expanded and cleaned up npc_zombie_custom - Fixed func_commandredirects not cleaning up correctly and sometimes crashing the game - Allowed player squad commands to go through +USE-held objects - Added a bunch of I/O/KV to trigger_waterydeath for better configuration - Changed save comment system to use the chapter title from world properties, and the ability to suppress the title popup that normally results from it - Adjusted game_convar_mod for MP planning - Removed the func_precipitation custom particle/splash code for now, as it was causing problems - Fixed env_global_light not accepting lightcolor - Added "Additional Buttons" to player_speedmod - Added save comment to RPC - Added env_projectedtexture attenuation - Added scripted_sequence OnPreIdleSequence - Added OnCrab to zombies - Added skill_changed game event (may need further testing) - Added a fix for viewmodels flipping under extreme FOV values - Added code that allows mappers to change the skin on shotgunners without it usually flipping back randomly - Fixed a very, very, very major shader performance issue - New SetAbsOrigin/Angles inputs on all entities, analogous to SetLocalOrigin/Angles - Code improvements for I/O involving angles - logic_entity_position improvements/fixes, including a new OutAngles output that outputs the angles on position calls - Alternate collision/player avoidance spawnflag obsoletion enforcement disabled - Enable/DisableHazardLights inputs on the EP2 jalopy, equivalent to the keyvalue - Miscellaneous shader formatting adjustments and fixes - Fixed AlwaysDrawOff on env_projectedtexture not being a valid input
2019-12-14 04:20:02 +00:00
{
QAngle ang;
inputdata.value.Angle3D(ang);
SetLocalAngles(ang);
}
//-----------------------------------------------------------------------------
// Purpose: Sets our origin.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetAbsOrigin( inputdata_t& inputdata )
{
Vector vec;
inputdata.value.Vector3D(vec);
Mapbase v2.0; bulk commit - Added custom map compile tools (vbsp, vvis, vrad) - Changed blink fix (shouldn't change anything in-game) - Added auto-completion to ent_create, npc_create, and the main set of "npc_" debug commands - Added ent_create_aimed, an ent_create equivalent of npc_create_aimed - Made hunters start using the "vs. player" melee animation against smaller NPCs that look weird with the "stab" attack - Added "explosion_sparks" convar, which fixes broken code for giving explosions sparks (disabled by default because of how different it looks) - Made interaction code capable of being dispatched on any entity, not just combat characters - Added npc_barnacle_ignite convar, which lets barnacles be ignited by flares - Fixed certain NPCs getting out of the way for the player when they hate them - Fixed auto-generated "speak" scene responses not using parameters that work on real VCDs - Made "stop_on_nonidle" capable of being used in any mod, not just HL2 episodic mods - Selectable color for ragdoll boogie/point_ragdollboogie - Fixed PickupWeaponInstant not firing weapon pickup outputs - Introduced inputs and keyvalues for "lerping" to math_counter_advanced - Fixed ClearConsole on logic_console - logic_convar should now detect client convars correctly - New NormalizeAngles input on math_vector - logic_modelinfo LookupActivity input - math_generate fixed and expanded to be more like math_counter - Added a WIP game logging system for playtesting maps - Introduced logic_playerinfo, an entity that can read a player's name or ID - Fixed some new filters not working with filter_multi - Added radius pickup spawnflag to func_physbox - Added "Preserve name" spawnflag to weapons - Added cc_achievement_debug message for when an achievement doesn't exist - Made npc_combine_s not speak while in logic_choreographed_scenes - Fixed zombie torsos/legs/headcrabs not being serverside when zombie is forced to server ragdoll - Expanded and cleaned up npc_zombie_custom - Fixed func_commandredirects not cleaning up correctly and sometimes crashing the game - Allowed player squad commands to go through +USE-held objects - Added a bunch of I/O/KV to trigger_waterydeath for better configuration - Changed save comment system to use the chapter title from world properties, and the ability to suppress the title popup that normally results from it - Adjusted game_convar_mod for MP planning - Removed the func_precipitation custom particle/splash code for now, as it was causing problems - Fixed env_global_light not accepting lightcolor - Added "Additional Buttons" to player_speedmod - Added save comment to RPC - Added env_projectedtexture attenuation - Added scripted_sequence OnPreIdleSequence - Added OnCrab to zombies - Added skill_changed game event (may need further testing) - Added a fix for viewmodels flipping under extreme FOV values - Added code that allows mappers to change the skin on shotgunners without it usually flipping back randomly - Fixed a very, very, very major shader performance issue - New SetAbsOrigin/Angles inputs on all entities, analogous to SetLocalOrigin/Angles - Code improvements for I/O involving angles - logic_entity_position improvements/fixes, including a new OutAngles output that outputs the angles on position calls - Alternate collision/player avoidance spawnflag obsoletion enforcement disabled - Enable/DisableHazardLights inputs on the EP2 jalopy, equivalent to the keyvalue - Miscellaneous shader formatting adjustments and fixes - Fixed AlwaysDrawOff on env_projectedtexture not being a valid input
2019-12-14 04:20:02 +00:00
SetAbsOrigin(vec);
}
//-----------------------------------------------------------------------------
// Purpose: Sets our angles.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetAbsAngles( inputdata_t& inputdata )
{
QAngle ang;
inputdata.value.Angle3D(ang);
SetAbsAngles(ang);
}
//-----------------------------------------------------------------------------
// Purpose: Sets our velocity.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetLocalVelocity( inputdata_t& inputdata )
{
Vector vec;
inputdata.value.Vector3D(vec);
SetLocalVelocity(vec);
}
//-----------------------------------------------------------------------------
// Purpose: Sets our angular velocity.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetLocalAngularVelocity( inputdata_t& inputdata )
{
Vector vec;
inputdata.value.Vector3D(vec);
SetLocalAngularVelocity(QAngle(vec.x, vec.y, vec.z));
}
//-----------------------------------------------------------------------------
// Purpose: Adds spawn flags.
//-----------------------------------------------------------------------------
void CBaseEntity::InputAddSpawnFlags( inputdata_t& inputdata )
{
AddSpawnFlags(inputdata.value.Int());
}
//-----------------------------------------------------------------------------
// Purpose: Removes spawn flags.
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
void CBaseEntity::InputRemoveSpawnFlags( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
RemoveSpawnFlags(inputdata.value.Int());
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose: Sets our render mode.
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetRenderMode( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
SetRenderMode((RenderMode_t)inputdata.value.Int());
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose: Sets our render FX.
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetRenderFX( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
m_nRenderFX = inputdata.value.Int();
2013-12-02 19:31:46 -08:00
}
Merged dev changes 9/28/2019 - Experimental RPC stuff for the future - Fixed players running over allies with vehicles (kind of) - Modified redirect filter infrastructure to support when there's no target filter (meaning it will just make sure the entity exists) - Fixed SDK_EyeRefract - Fixed env_beam SetStart/EndEntity - New "OnStateChange" output on NPCs - scripted_face removed (use generic facing VCDs instead) - Fixed RPC - View ID nodraw keyvalue + reflective glass view ID fix - CopyAnimationDataFrom expansion (more variables copied) - Fixed pre-Mapbase env_projectedtextures not updating after loading a save - Fixed(?) player companion grenade throwing being interrupted - Added convars for secondary and NPC shotgun pellet amounts - NPC fade distance/scale transfers to its ragdoll - Made node graph rebuild occur sooner after map load - Added option to disable "node graph out of date" message - Fixed ent_fire delay (decimals discarded before) - "SetFilter" on func_clip_vphysics - Fixed func_tank zero barrel (untested) - Fixed npc_turret_ground parenting fix - Added toggle-able weapon_crossbow experimental hit location code - Fixed ally grenades being considered Combine grenades - Added SDK_MonitorScreen and SDK_UnlitTwoTexture - Updated README - Added !activator/!caller support to logic_collision_pair - Fixed ortho not working in script_intro - Added Nbc66's closed captioning language fix - Applied fade fix to server ragdolls - Added combine_mine friend/foe filters - Fixed env_starfield pausing - Reworked PickupWeapon/Item inputs - Fixed context response system $ usage - Fixed env_break_shooter velocity/speed - Made func_breakable "Spawn on break" support other entities - Fixed OnThrowGrenade > point_entity_replace blip - Added mapname to logic_externaldata - Added "Random Template" to point_template - Added "Use LOS" to trigger_look - Added flags based on L4D(2) to trigger_playermovement - Added npc_combine_s "Alternate Capable" keyvalue that enables both grenades and alt-fire at the same time regardless of elite status - Fixed npc_combine_s DropGrenade input - Miscellaneous code and comment changes
2019-09-28 22:56:52 +00:00
//-----------------------------------------------------------------------------
// Purpose: Sets our view hide flags.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetViewHideFlags( inputdata_t& inputdata )
{
m_iViewHideFlags = inputdata.value.Int();
}
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose: Adds effects.
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
void CBaseEntity::InputAddEffects( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
AddEffects(inputdata.value.Int());
}
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose: Removes effects.
//-----------------------------------------------------------------------------
void CBaseEntity::InputRemoveEffects( inputdata_t& inputdata )
{
RemoveEffects(inputdata.value.Int());
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose: Shortcut for removing nodraw.
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
void CBaseEntity::InputDrawEntity( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
RemoveEffects(EF_NODRAW);
}
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose: Shortcut to adding nodraw.
//-----------------------------------------------------------------------------
void CBaseEntity::InputUndrawEntity( inputdata_t& inputdata )
{
AddEffects(EF_NODRAW);
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose: Adds eflags.
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
void CBaseEntity::InputAddEFlags( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
AddEFlags(inputdata.value.Int());
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose: Removes eflags.
//-----------------------------------------------------------------------------
void CBaseEntity::InputRemoveEFlags( inputdata_t& inputdata )
{
RemoveEFlags(inputdata.value.Int());
}
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose: Adds solid flags.
//-----------------------------------------------------------------------------
void CBaseEntity::InputAddSolidFlags( inputdata_t& inputdata )
{
AddSolidFlags(inputdata.value.Int());
}
//-----------------------------------------------------------------------------
// Purpose: Removes solid flags.
//-----------------------------------------------------------------------------
void CBaseEntity::InputRemoveSolidFlags( inputdata_t& inputdata )
{
RemoveSolidFlags(inputdata.value.Int());
}
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose: Sets the movetype.
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetMoveType( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
SetMoveType((MoveType_t)inputdata.value.Int());
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose: Sets the collision group.
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetCollisionGroup( inputdata_t& inputdata )
{
SetCollisionGroup(inputdata.value.Int());
}
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose: Touch touch :)
//-----------------------------------------------------------------------------
void CBaseEntity::InputTouch( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
if (inputdata.value.Entity())
Touch( inputdata.value.Entity() );
else
Warning( "%s InputTouch: Can't touch null entity", GetDebugName() );
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose: Passes KilledNPC to our possibly more capable parents.
//-----------------------------------------------------------------------------
void CBaseEntity::InputKilledNPC( inputdata_t &inputdata )
{
// Don't get stuck in an endless loop
if (inputdata.value.Int() > 16)
return;
else
inputdata.value.SetInt(inputdata.value.Int() + 1);
2013-12-02 19:31:46 -08:00
if (GetOwnerEntity())
{
GetOwnerEntity()->AcceptInput("KilledNPC", inputdata.pActivator, inputdata.pCaller, inputdata.value, inputdata.nOutputID);
}
else if (HasPhysicsAttacker(4.0f))
{
HasPhysicsAttacker(4.0f)->AcceptInput("KilledNPC", inputdata.pActivator, inputdata.pCaller, inputdata.value, inputdata.nOutputID);
}
else if (GetMoveParent())
{
GetMoveParent()->AcceptInput("KilledNPC", inputdata.pActivator, inputdata.pCaller, inputdata.value, inputdata.nOutputID);
}
}
//-----------------------------------------------------------------------------
// Purpose: Remove if not visible by any players
//-----------------------------------------------------------------------------
void CBaseEntity::InputKillIfNotVisible( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
#ifdef MAPBASE_MP
// Go through each client and check if we're in their viewcone.
// If we're in someone's viewcone, return immediately.
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
if ( pPlayer && pPlayer->FInViewCone( this ) )
return;
}
#else
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
if ( !pPlayer || !pPlayer->FInViewCone( this ) )
#endif
{
m_OnKilled.FireOutput(inputdata.pActivator, this);
UTIL_Remove(this);
}
2013-12-02 19:31:46 -08:00
}
//-----------------------------------------------------------------------------
// Purpose: Remove when not visible by any players
//-----------------------------------------------------------------------------
void CBaseEntity::InputKillWhenNotVisible( inputdata_t& inputdata )
{
SetContextThink( &CBaseEntity::SUB_RemoveWhenNotVisible, gpGlobals->curtime + inputdata.value.Float(), "SUB_RemoveWhenNotVisible" );
//SetRenderColorA( 255 );
//m_nRenderMode = kRenderNormal;
}
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose: Stop thinking
//-----------------------------------------------------------------------------
void CBaseEntity::InputSetThinkNull( inputdata_t& inputdata )
2013-12-02 19:31:46 -08:00
{
const char *szContext = inputdata.value.String();
if (szContext && szContext[0] != '\0')
{
SetContextThink( NULL, TICK_NEVER_THINK, szContext );
}
else
{
SetThink( NULL );
SetNextThink( TICK_NEVER_THINK );
}
2013-12-02 19:31:46 -08:00
}
#endif
2013-12-02 19:31:46 -08:00
//---------------------------------------------------------
// Use the string as the filename of a script file
// that should be loaded from disk, compiled, and run.
//---------------------------------------------------------
void CBaseEntity::InputRunScriptFile(inputdata_t& inputdata)
{
RunScriptFile(inputdata.value.String());
}
//---------------------------------------------------------
// Send the string to the VM as source code and execute it
//---------------------------------------------------------
void CBaseEntity::InputRunScript(inputdata_t& inputdata)
{
RunScript(inputdata.value.String(), "InputRunScript");
}
//---------------------------------------------------------
// Make an explicit function call.
//---------------------------------------------------------
void CBaseEntity::InputCallScriptFunction(inputdata_t& inputdata)
{
CallScriptFunction(inputdata.value.String(), NULL);
}
#ifdef MAPBASE_VSCRIPT
//---------------------------------------------------------
// Send the string to the VM as source code and execute it
//---------------------------------------------------------
void CBaseEntity::InputRunScriptQuotable(inputdata_t& inputdata)
{
char szQuotableCode[1024];
if (V_StrSubst( inputdata.value.String(), "''", "\"", szQuotableCode, sizeof( szQuotableCode ), false ))
{
RunScript( szQuotableCode, "InputRunScriptQuotable" );
}
else
{
RunScript( inputdata.value.String(), "InputRunScriptQuotable" );
}
}
//---------------------------------------------------------
// Clear this entity's script scope
//---------------------------------------------------------
void CBaseEntity::InputClearScriptScope(inputdata_t& inputdata)
{
m_ScriptScope.Term();
}
#endif
// #define VMPROFILE // define to profile vscript calls
#ifdef VMPROFILE
float g_debugCumulativeTime = 0.0;
float g_debugCounter = 0;
#define START_VMPROFILE float debugStartTime = Plat_FloatTime();
#define UPDATE_VMPROFILE \
g_debugCumulativeTime += Plat_FloatTime() - debugStartTime; \
g_debugCounter++; \
if ( g_debugCounter >= 500 ) \
{ \
DevMsg("***VSCRIPT PROFILE***: %s %s: %6.4f milliseconds\n", "500 vscript function calls", "", g_debugCumulativeTime*1000.0 ); \
g_debugCounter = 0; \
g_debugCumulativeTime = 0.0; \
} \
#else
#define START_VMPROFILE
#define UPDATE_VMPROFILE
#endif // VMPROFILE
//-----------------------------------------------------------------------------
// Returns true if the function was located and called. false otherwise.
// NOTE: Assumes the function takes no parameters at the moment.
//-----------------------------------------------------------------------------
bool CBaseEntity::CallScriptFunction(const char* pFunctionName, ScriptVariant_t* pFunctionReturn)
{
START_VMPROFILE
if (!ValidateScriptScope())
{
DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
return false;
}
HSCRIPT hFunc = m_ScriptScope.LookupFunction(pFunctionName);
if (hFunc)
{
m_ScriptScope.Call(hFunc, pFunctionReturn);
m_ScriptScope.ReleaseFunction(hFunc);
UPDATE_VMPROFILE
return true;
}
return false;
}
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
// Gets a function handle
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::LookupScriptFunction(const char* pFunctionName)
{
START_VMPROFILE
if (!m_ScriptScope.IsInitialized())
{
return NULL;
}
return m_ScriptScope.LookupFunction(pFunctionName);
}
//-----------------------------------------------------------------------------
// Calls and releases a function handle (ASSUMES SCRIPT SCOPE AND FUNCTION ARE VALID!)
//-----------------------------------------------------------------------------
bool CBaseEntity::CallScriptFunctionHandle(HSCRIPT hFunc, ScriptVariant_t* pFunctionReturn)
{
m_ScriptScope.Call(hFunc, pFunctionReturn);
m_ScriptScope.ReleaseFunction(hFunc);
UPDATE_VMPROFILE
return true;
}
#endif
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ConnectOutputToScript(const char* pszOutput, const char* pszScriptFunc)
{
CBaseEntityOutput* pOutput = FindNamedOutput(pszOutput);
if (!pOutput)
{
DevMsg(2, "Script failed to find output \"%s\"\n", pszOutput);
return;
}
string_t iszSelf = AllocPooledString("!self"); // @TODO: cache this [4/25/2008 tom]
CEventAction* pAction = pOutput->GetActionList();
while (pAction)
{
if (pAction->m_iTarget == iszSelf &&
pAction->m_flDelay == 0 &&
pAction->m_nTimesToFire == EVENT_FIRE_ALWAYS &&
V_strcmp(STRING(pAction->m_iTargetInput), "CallScriptFunction") == 0 &&
V_strcmp(STRING(pAction->m_iParameter), pszScriptFunc) == 0)
{
return;
}
pAction = pAction->m_pNext;
}
pAction = new CEventAction(NULL);
pAction->m_iTarget = iszSelf;
pAction->m_iTargetInput = AllocPooledString("CallScriptFunction");
pAction->m_iParameter = AllocPooledString(pszScriptFunc);
pOutput->AddEventAction(pAction);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::DisconnectOutputFromScript(const char* pszOutput, const char* pszScriptFunc)
{
CBaseEntityOutput* pOutput = FindNamedOutput(pszOutput);
if (!pOutput)
{
DevMsg(2, "Script failed to find output \"%s\"\n", pszOutput);
return;
}
string_t iszSelf = AllocPooledString("!self"); // @TODO: cache this [4/25/2008 tom]
CEventAction* pAction = pOutput->GetActionList();
while (pAction)
{
if (pAction->m_iTarget == iszSelf &&
pAction->m_flDelay == 0 &&
pAction->m_nTimesToFire == EVENT_FIRE_ALWAYS &&
V_strcmp(STRING(pAction->m_iTargetInput), "CallScriptFunction") == 0 &&
V_strcmp(STRING(pAction->m_iParameter), pszScriptFunc) == 0)
{
pOutput->RemoveEventAction(pAction);
delete pAction;
return;
}
pAction = pAction->m_pNext;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptThink(void)
{
ScriptVariant_t varThinkRetVal;
if (CallScriptFunction(m_iszScriptThinkFunction.ToCStr(), &varThinkRetVal))
{
float flThinkFrequency = 0.0f;
if (!varThinkRetVal.AssignTo(&flThinkFrequency))
{
// use default think interval if script think function doesn't provide one
flThinkFrequency = sv_script_think_interval.GetFloat();
}
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
SetNextThink( gpGlobals->curtime + flThinkFrequency, "ScriptThink" );
}
else
{
DevWarning("%s FAILED to call script think function %s!\n", GetDebugName(), STRING(m_iszScriptThinkFunction));
}
}
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptSetThinkFunction(const char *szFunc, float time)
{
// Empty string stops thinking
if (!szFunc || szFunc[0] == '\0')
{
ScriptStopThinkFunction();
}
else
{
m_iszScriptThinkFunction = AllocPooledString(szFunc);
SetContextThink( &CBaseEntity::ScriptThink, gpGlobals->curtime + time, "ScriptThink" );
}
}
void CBaseEntity::ScriptStopThinkFunction()
{
m_iszScriptThinkFunction = NULL_STRING;
SetContextThink( NULL, TICK_NEVER_THINK, "ScriptThink" );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptThinkH()
{
if (m_hfnThink)
{
ScriptVariant_t varThinkRetVal;
if (g_pScriptVM->ExecuteFunction(m_hfnThink, NULL, 0, &varThinkRetVal, NULL, true) == SCRIPT_ERROR)
{
DevWarning("%s FAILED to call script think function (invalid closure)!\n", GetDebugName());
ScriptStopThink();
return;
}
float flThinkFrequency = 0.f;
if (!varThinkRetVal.AssignTo(&flThinkFrequency))
{
// no return value stops thinking
ScriptStopThink();
return;
}
SetNextThink(gpGlobals->curtime + flThinkFrequency, "ScriptThinkH");
}
else
{
DevWarning("%s FAILED to call script think function (invalid closure)!\n", GetDebugName());
}
}
void CBaseEntity::ScriptSetThink(HSCRIPT hFunc, float time)
{
if (hFunc)
{
if (m_hfnThink)
{
// release old func
ScriptStopThink();
}
// no type check here, print error on call instead
m_hfnThink = hFunc;
SetContextThink( &CBaseEntity::ScriptThinkH, gpGlobals->curtime + time, "ScriptThinkH" );
}
else
{
ScriptStopThink();
}
}
void CBaseEntity::ScriptStopThink()
{
if (m_hfnThink)
{
g_pScriptVM->ReleaseScript(m_hfnThink);
m_hfnThink = NULL;
}
SetContextThink( NULL, TICK_NEVER_THINK, "ScriptThinkH" );
}
#endif // MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char* CBaseEntity::GetScriptId()
{
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#ifdef MAPBASE_VSCRIPT
return STRING(m_iszScriptId);
#else
return STRING(m_iszScriptThinkFunction);
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
#endif
}
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
//-----------------------------------------------------------------------------
// Recreate the old behaviour of GetScriptId under a new function
//-----------------------------------------------------------------------------
// const char* CBaseEntity::GetScriptThinkFunction()
// {
// return STRING(m_iszScriptThinkFunction);
// }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::GetScriptScope()
{
return m_ScriptScope;
}
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#ifdef MAPBASE_VSCRIPT
HSCRIPT CBaseEntity::GetOrCreatePrivateScriptScope()
{
ValidateScriptScope();
return m_ScriptScope;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptSetParent(HSCRIPT hParent, const char *szAttachment)
{
CBaseEntity *pParent = ToEnt(hParent);
if ( !pParent )
{
SetParent(NULL);
return;
}
// if an attachment is specified, the parent needs to be CBaseAnimating
if ( szAttachment && szAttachment[0] != '\0' )
{
CBaseAnimating *pAnimating = pParent->GetBaseAnimating();
if ( !pAnimating )
{
Warning("ERROR: Tried to set parent for entity %s (%s), but its parent has no model.\n", GetClassname(), GetDebugName());
return;
}
int iAttachment = pAnimating->LookupAttachment(szAttachment);
if ( iAttachment <= 0 )
{
Warning("ERROR: Tried to set parent for entity %s (%s), but it has no attachment named %s.\n", GetClassname(), GetDebugName(), szAttachment);
return;
}
SetParent(pParent, iAttachment);
SetMoveType(MOVETYPE_NONE);
return;
}
SetParent(pParent);
}
#endif
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetMoveParent(void)
{
return ToHScript(GetMoveParent());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetRootMoveParent()
{
return ToHScript(GetRootMoveParent());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptFirstMoveChild(void)
{
return ToHScript(FirstMoveChild());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptNextMovePeer(void)
{
return ToHScript(NextMovePeer());
}
//-----------------------------------------------------------------------------
// Purpose: Load, compile, and run a script file from disk.
// Input : *pScriptFile - The filename of the script file.
// bUseRootScope - If true, runs this script in the root scope, not
// in this entity's private scope.
//-----------------------------------------------------------------------------
bool CBaseEntity::RunScriptFile(const char* pScriptFile, bool bUseRootScope)
{
if (!ValidateScriptScope())
{
DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
return false;
}
if (bUseRootScope)
{
return VScriptRunScript(pScriptFile);
}
else
{
return VScriptRunScript(pScriptFile, m_ScriptScope, true);
}
}
//-----------------------------------------------------------------------------
// Purpose: Compile and execute a discrete string of script source code
// Input : *pScriptText - A string containing script code to compile and run
//-----------------------------------------------------------------------------
bool CBaseEntity::RunScript(const char* pScriptText, const char* pDebugFilename)
{
if (!ValidateScriptScope())
{
DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
return false;
}
if (m_ScriptScope.Run(pScriptText, pDebugFilename) == SCRIPT_ERROR)
{
DevWarning(" Entity %s encountered an error in RunScript()\n", GetDebugName());
}
return true;
}
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose:
// Input : *contextName -
//-----------------------------------------------------------------------------
void CBaseEntity::AddContext( const char *contextName )
{
char key[ 128 ];
char value[ 128 ];
float duration;
const char *p = contextName;
while ( p )
{
duration = 0.0f;
p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), &duration );
if ( duration )
{
duration += gpGlobals->curtime;
}
int iIndex = FindContextByName( key );
if ( iIndex != -1 )
{
// Set the existing context to the new value
m_ResponseContexts[iIndex].m_iszValue = AllocPooledString( value );
m_ResponseContexts[iIndex].m_fExpirationTime = duration;
continue;
}
ResponseContext_t newContext;
newContext.m_iszName = AllocPooledString( key );
newContext.m_iszValue = AllocPooledString( value );
newContext.m_fExpirationTime = duration;
m_ResponseContexts.AddToTail( newContext );
}
}
#ifdef MAPBASE
void CBaseEntity::AddContext( const char *name, const char *value, float duration )
{
int iIndex = FindContextByName( name );
if ( iIndex != -1 )
{
// Set the existing context to the new value
m_ResponseContexts[iIndex].m_iszValue = AllocPooledString( value );
m_ResponseContexts[iIndex].m_fExpirationTime = duration;
return;
}
ResponseContext_t newContext;
newContext.m_iszName = AllocPooledString( name );
newContext.m_iszValue = AllocPooledString( value );
newContext.m_fExpirationTime = duration;
m_ResponseContexts.AddToTail( newContext );
}
#endif
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CBaseEntity::InputRemoveContext( inputdata_t& inputdata )
{
const char *contextName = inputdata.value.String();
int idx = FindContextByName( contextName );
if ( idx == -1 )
return;
m_ResponseContexts.Remove( idx );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CBaseEntity::InputClearContext( inputdata_t& inputdata )
{
m_ResponseContexts.RemoveAll();
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : IResponseSystem
//-----------------------------------------------------------------------------
IResponseSystem *CBaseEntity::GetResponseSystem()
{
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CBaseEntity::InputDispatchResponse( inputdata_t& inputdata )
{
DispatchResponse( inputdata.value.String() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::InputDisableShadow( inputdata_t &inputdata )
{
AddEffects( EF_NOSHADOW );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::InputEnableShadow( inputdata_t &inputdata )
{
RemoveEffects( EF_NOSHADOW );
}
//-----------------------------------------------------------------------------
// Purpose: An input to add a new connection from this entity
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CBaseEntity::InputAddOutput( inputdata_t &inputdata )
{
char sOutputName[MAX_PATH];
Q_strncpy( sOutputName, inputdata.value.String(), sizeof(sOutputName) );
char *sChar = strchr( sOutputName, ' ' );
if ( sChar )
{
*sChar = '\0';
// Now replace all the :'s in the string with ,'s.
// Has to be done this way because Hammer doesn't allow ,'s inside parameters.
char *sColon = strchr( sChar+1, ':' );
while ( sColon )
{
*sColon = ',';
sColon = strchr( sChar+1, ':' );
}
KeyValue( sOutputName, sChar+1 );
}
else
{
Warning("AddOutput input fired with bad string. Format: <output name> <targetname>,<inputname>,<parameter>,<delay>,<max times to fire (-1 == infinite)>\n");
}
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CBaseEntity::InputChangeVariable( inputdata_t &inputdata )
{
const char *szKeyName = NULL;
const char *szValue = NULL;
char sOutputName[MAX_PATH];
Q_strncpy( sOutputName, inputdata.value.String(), sizeof(sOutputName) );
char *sChar = strchr( sOutputName, ' ' );
if ( sChar )
{
*sChar = '\0';
// Now replace all the :'s in the string with ,'s.
// Has to be done this way because Hammer doesn't allow ,'s inside parameters.
char *sColon = strchr( sChar+1, ':' );
while ( sColon )
{
*sColon = ',';
sColon = strchr( sChar+1, ':' );
}
szKeyName = sOutputName;
szValue = sChar + 1;
}
else
{
Warning("ChangeVariable input fired with bad string. Format: <output name> <targetname>,<inputname>,<parameter>,<delay>,<max times to fire (-1 == infinite)>\n");
return;
}
if (szKeyName == NULL)
return;
for ( datamap_t *dmap = GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
{
// search through all the readable fields in the data description, looking for a match
for ( int i = 0; i < dmap->dataNumFields; i++ )
{
if ( dmap->dataDesc[i].flags & (FTYPEDESC_SAVE | FTYPEDESC_KEY) )
{
if ( Matcher_NamesMatch(szKeyName, dmap->dataDesc[i].fieldName) )
{
// Copied from ::ParseKeyvalue...or technically logic_datadesc_accessor...
typedescription_t *pField = &dmap->dataDesc[i];
char *data = Datadesc_SetFieldString( szValue, this, pField, NULL );
if (!data)
{
Warning( "%s cannot set field of type %i.\n", GetDebugName(), dmap->dataDesc[i].fieldType );
}
}
}
}
}
}
#endif
2013-12-02 19:31:46 -08:00
//-----------------------------------------------------------------------------
// Purpose:
// Input : *conceptName -
//-----------------------------------------------------------------------------
void CBaseEntity::DispatchResponse( const char *conceptName )
{
IResponseSystem *rs = GetResponseSystem();
if ( !rs )
return;
AI_CriteriaSet set;
// Always include the concept name
set.AppendCriteria( "concept", conceptName, CONCEPT_WEIGHT );
// Let NPC fill in most match criteria
ModifyOrAppendCriteria( set );
// Append local player criteria to set,too
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
if( pPlayer )
pPlayer->ModifyOrAppendPlayerCriteria( set );
#ifdef MAPBASE
ReAppendContextCriteria( set );
#endif
2013-12-02 19:31:46 -08:00
// Now that we have a criteria set, ask for a suitable response
AI_Response result;
bool found = rs->FindBestResponse( set, result );
if ( !found )
{
return;
}
// Handle the response here...
char response[ 256 ];
result.GetResponse( response, sizeof( response ) );
#ifdef MAPBASE
if (response[0] == '$')
{
const char *context = response + 1;
const char *replace = GetContextValue(context);
if (replace)
{
DevMsg("Replacing %s with %s...\n", response, replace);
Q_strncpy(response, replace, sizeof(response));
// Precache it now because it may not have been precached before
switch ( result.GetType() )
{
case RESPONSE_SPEAK:
{
PrecacheScriptSound( response );
}
break;
case RESPONSE_SCENE:
{
// TODO: Gender handling?
PrecacheInstancedScene( response );
}
break;
}
}
}
#endif
2013-12-02 19:31:46 -08:00
switch ( result.GetType() )
{
case RESPONSE_SPEAK:
{
EmitSound( response );
}
break;
case RESPONSE_SENTENCE:
{
#ifdef MAPBASE
if (response[0] != '!')
{
SENTENCEG_PlayRndSz( edict(), response, 1, result.GetSoundLevel(), 0, PITCH_NORM );
break;
}
#endif
2013-12-02 19:31:46 -08:00
int sentenceIndex = SENTENCEG_Lookup( response );
if( sentenceIndex == -1 )
{
// sentence not found
break;
}
// FIXME: Get pitch from npc?
CPASAttenuationFilter filter( this );
CBaseEntity::EmitSentenceByIndex( filter, entindex(), CHAN_VOICE, sentenceIndex, 1, result.GetSoundLevel(), 0, PITCH_NORM );
}
break;
case RESPONSE_SCENE:
{
#ifdef MAPBASE
// Most flexing actors that use scenes override DispatchResponse via CAI_Expresser in ai_speech.
// So, in order for non-actors to use scenes by themselves, they actually don't really use them at all.
// Most scenes that would be used as responses only have one sound, so we take the first sound in a scene and emit it manually.
//
// Of course, env_speaker uses scenes without using itself as an actor, but that overrides DispatchResponse in Mapbase
// with the original code intact. Hopefully no other entity uses this like that...
//if (!ClassMatches("env_speaker"))
{
// Expand gender string
GenderExpandString( response, response, sizeof( response ) );
// Trust that it's been precached
const char *pszSound = GetFirstSoundInScene(response);
EmitSound(pszSound);
}
//else
// InstancedScriptedScene(NULL, response);
#else
2013-12-02 19:31:46 -08:00
// Try to fire scene w/o an actor
InstancedScriptedScene( NULL, response );
#endif
2013-12-02 19:31:46 -08:00
}
break;
case RESPONSE_PRINT:
{
}
break;
default:
// Don't know how to handle .vcds!!!
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseEntity::DumpResponseCriteria( void )
{
Msg("----------------------------------------------\n");
Msg("RESPONSE CRITERIA FOR: %s (%s)\n", GetClassname(), GetDebugName() );
AI_CriteriaSet set;
// Let NPC fill in most match criteria
ModifyOrAppendCriteria( set );
// Append local player criteria to set,too
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
if ( pPlayer )
{
pPlayer->ModifyOrAppendPlayerCriteria( set );
}
#ifdef MAPBASE
ReAppendContextCriteria( set );
#endif
2013-12-02 19:31:46 -08:00
// Now dump it all to console
set.Describe();
}
//------------------------------------------------------------------------------
void CC_Ent_Show_Response_Criteria( const CCommand& args )
{
CBaseEntity *pEntity = NULL;
while ( (pEntity = GetNextCommandEntity( UTIL_GetCommandClient(), args[1], pEntity )) != NULL )
{
pEntity->DumpResponseCriteria();
}
}
static ConCommand ent_show_response_criteria("ent_show_response_criteria", CC_Ent_Show_Response_Criteria, "Print, to the console, an entity's current criteria set used to select responses.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
//------------------------------------------------------------------------------
// Purpose: Show an entity's autoaim radius
//------------------------------------------------------------------------------
void CC_Ent_Autoaim( const CCommand& args )
{
SetDebugBits( UTIL_GetCommandClient(),args[1], OVERLAY_AUTOAIM_BIT );
}
static ConCommand ent_autoaim("ent_autoaim", CC_Ent_Autoaim, "Displays the entity's autoaim radius.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CAI_BaseNPC *CBaseEntity::MyNPCPointer( void )
{
if ( IsNPC() )
return assert_cast<CAI_BaseNPC *>(this);
return NULL;
}
ConVar step_spline( "step_spline", "0" );
//-----------------------------------------------------------------------------
// Purpose: Run one tick's worth of faked simulation
// Input : *step -
//-----------------------------------------------------------------------------
void CBaseEntity::ComputeStepSimulationNetwork( StepSimulationData *step )
{
if ( !step )
{
Assert( !"ComputeStepSimulationNetworkOriginAndAngles with NULL step\n" );
return;
}
// Don't run again if we've already calculated this tick
if ( step->m_nLastProcessTickCount == gpGlobals->tickcount )
{
return;
}
step->m_nLastProcessTickCount = gpGlobals->tickcount;
// Origin
// It's inactive
if ( step->m_bOriginActive )
{
// First see if any external code moved the entity
if ( GetStepOrigin() != step->m_Next.vecOrigin )
{
step->m_bOriginActive = false;
}
else
{
// Compute interpolated info based on tick interval
float frac = 1.0f;
int tickdelta = step->m_Next.nTickCount - step->m_Previous.nTickCount;
if ( tickdelta > 0 )
{
frac = (float)( gpGlobals->tickcount - step->m_Previous.nTickCount ) / (float) tickdelta;
frac = clamp( frac, 0.0f, 1.0f );
}
if (step->m_Previous2.nTickCount == 0 || step->m_Previous2.nTickCount >= step->m_Previous.nTickCount)
{
Vector delta = step->m_Next.vecOrigin - step->m_Previous.vecOrigin;
VectorMA( step->m_Previous.vecOrigin, frac, delta, step->m_vecNetworkOrigin );
}
else if (!step_spline.GetBool())
{
StepSimulationStep *pOlder = &step->m_Previous;
StepSimulationStep *pNewer = &step->m_Next;
if (step->m_Discontinuity.nTickCount > step->m_Previous.nTickCount)
{
if (gpGlobals->tickcount > step->m_Discontinuity.nTickCount)
{
pOlder = &step->m_Discontinuity;
}
else
{
pNewer = &step->m_Discontinuity;
}
tickdelta = pNewer->nTickCount - pOlder->nTickCount;
if ( tickdelta > 0 )
{
frac = (float)( gpGlobals->tickcount - pOlder->nTickCount ) / (float) tickdelta;
frac = clamp( frac, 0.0f, 1.0f );
}
}
Vector delta = pNewer->vecOrigin - pOlder->vecOrigin;
VectorMA( pOlder->vecOrigin, frac, delta, step->m_vecNetworkOrigin );
}
else
{
Hermite_Spline( step->m_Previous2.vecOrigin, step->m_Previous.vecOrigin, step->m_Next.vecOrigin, frac, step->m_vecNetworkOrigin );
}
}
}
// Angles
if ( step->m_bAnglesActive )
{
// See if external code changed the orientation of the entity
if ( GetStepAngles() != step->m_angNextRotation )
{
step->m_bAnglesActive = false;
}
else
{
// Compute interpolated info based on tick interval
float frac = 1.0f;
int tickdelta = step->m_Next.nTickCount - step->m_Previous.nTickCount;
if ( tickdelta > 0 )
{
frac = (float)( gpGlobals->tickcount - step->m_Previous.nTickCount ) / (float) tickdelta;
frac = clamp( frac, 0.0f, 1.0f );
}
if (step->m_Previous2.nTickCount == 0 || step->m_Previous2.nTickCount >= step->m_Previous.nTickCount)
{
// Pure blend between start/end orientations
Quaternion outangles;
QuaternionBlend( step->m_Previous.qRotation, step->m_Next.qRotation, frac, outangles );
QuaternionAngles( outangles, step->m_angNetworkAngles );
}
else if (!step_spline.GetBool())
{
StepSimulationStep *pOlder = &step->m_Previous;
StepSimulationStep *pNewer = &step->m_Next;
if (step->m_Discontinuity.nTickCount > step->m_Previous.nTickCount)
{
if (gpGlobals->tickcount > step->m_Discontinuity.nTickCount)
{
pOlder = &step->m_Discontinuity;
}
else
{
pNewer = &step->m_Discontinuity;
}
tickdelta = pNewer->nTickCount - pOlder->nTickCount;
if ( tickdelta > 0 )
{
frac = (float)( gpGlobals->tickcount - pOlder->nTickCount ) / (float) tickdelta;
frac = clamp( frac, 0.0f, 1.0f );
}
}
// Pure blend between start/end orientations
Quaternion outangles;
QuaternionBlend( pOlder->qRotation, pNewer->qRotation, frac, outangles );
QuaternionAngles( outangles, step->m_angNetworkAngles );
}
else
{
// FIXME: enable spline interpolation when turning is debounced.
Quaternion outangles;
Hermite_Spline( step->m_Previous2.qRotation, step->m_Previous.qRotation, step->m_Next.qRotation, frac, outangles );
QuaternionAngles( outangles, step->m_angNetworkAngles );
}
}
}
}
//-----------------------------------------------------------------------------
bool CBaseEntity::UseStepSimulationNetworkOrigin( const Vector **out_v )
{
Assert( out_v );
if ( g_bTestMoveTypeStepSimulation &&
GetMoveType() == MOVETYPE_STEP &&
HasDataObjectType( STEPSIMULATION ) )
{
StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
ComputeStepSimulationNetwork( step );
*out_v = &step->m_vecNetworkOrigin;
return step->m_bOriginActive;
}
return false;
}
//-----------------------------------------------------------------------------
bool CBaseEntity::UseStepSimulationNetworkAngles( const QAngle **out_a )
{
Assert( out_a );
if ( g_bTestMoveTypeStepSimulation &&
GetMoveType() == MOVETYPE_STEP &&
HasDataObjectType( STEPSIMULATION ) )
{
StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
ComputeStepSimulationNetwork( step );
*out_a = &step->m_angNetworkAngles;
return step->m_bAnglesActive;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseEntity::AddStepDiscontinuity( float flTime, const Vector &vecOrigin, const QAngle &vecAngles )
{
if ((GetMoveType() != MOVETYPE_STEP ) || !HasDataObjectType( STEPSIMULATION ) )
{
return false;
}
StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
if (!step)
{
Assert( 0 );
return false;
}
step->m_Discontinuity.nTickCount = TIME_TO_TICKS( flTime );
step->m_Discontinuity.vecOrigin = vecOrigin;
AngleQuaternion( vecAngles, step->m_Discontinuity.qRotation );
return true;
}
Vector CBaseEntity::GetStepOrigin( void ) const
{
return GetLocalOrigin();
}
QAngle CBaseEntity::GetStepAngles( void ) const
{
return GetLocalAngles();
}
//-----------------------------------------------------------------------------
// Purpose: For each client who appears to be a valid recipient, checks the client has disabled CC and if so, removes them from
// the recipient list.
// Input : filter -
//-----------------------------------------------------------------------------
void CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( CRecipientFilter& filter )
{
int c = filter.GetRecipientCount();
for ( int i = c - 1; i >= 0; --i )
{
int playerIndex = filter.GetRecipientIndex( i );
CBasePlayer *player = static_cast< CBasePlayer * >( CBaseEntity::Instance( playerIndex ) );
if ( !player )
continue;
#if !defined( _XBOX )
const char *cvarvalue = engine->GetClientConVarValue( playerIndex, "closecaption" );
Assert( cvarvalue );
if ( !cvarvalue[ 0 ] )
continue;
int value = atoi( cvarvalue );
#else
static ConVar *s_pCloseCaption = NULL;
if ( !s_pCloseCaption )
{
s_pCloseCaption = cvar->FindVar( "closecaption" );
if ( !s_pCloseCaption )
{
Error( "XBOX couldn't find closecaption convar!!!" );
}
}
int value = s_pCloseCaption->GetInt();
#endif
// No close captions?
if ( value == 0 )
{
filter.RemoveRecipient( player );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Wrapper to emit a sentence and also a close caption token for the sentence as appropriate.
// Input : filter -
// iEntIndex -
// iChannel -
// iSentenceIndex -
// flVolume -
// iSoundlevel -
// iFlags -
// iPitch -
// bUpdatePositions -
// soundtime -
//-----------------------------------------------------------------------------
void CBaseEntity::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex,
float flVolume, soundlevel_t iSoundlevel, int iFlags /*= 0*/, int iPitch /*=PITCH_NORM*/,
const Vector *pOrigin /*=NULL*/, const Vector *pDirection /*=NULL*/,
bool bUpdatePositions /*=true*/, float soundtime /*=0.0f*/ )
{
CUtlVector< Vector > dummy;
enginesound->EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex,
flVolume, iSoundlevel, iFlags, iPitch, 0, pOrigin, pDirection, &dummy, bUpdatePositions, soundtime );
}
void CBaseEntity::SetRefEHandle( const CBaseHandle &handle )
{
m_RefEHandle = handle;
if ( edict() )
{
COMPILE_TIME_ASSERT( NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS <= 8*sizeof( edict()->m_NetworkSerialNumber ) );
edict()->m_NetworkSerialNumber = (m_RefEHandle.GetSerialNumber() & (1 << NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS) - 1);
}
}
bool CPointEntity::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "mins" ) || FStrEq( szKeyName, "maxs" ) )
{
Warning("Warning! Can't specify mins/maxs for point entities! (%s)\n", GetClassname() );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
bool CServerOnlyPointEntity::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "mins" ) || FStrEq( szKeyName, "maxs" ) )
{
Warning("Warning! Can't specify mins/maxs for point entities! (%s)\n", GetClassname() );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
bool CLogicalEntity::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "mins" ) || FStrEq( szKeyName, "maxs" ) )
{
Warning("Warning! Can't specify mins/maxs for point entities! (%s)\n", GetClassname() );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//-----------------------------------------------------------------------------
// Purpose: Sets the entity invisible, and makes it remove itself on the next frame
//-----------------------------------------------------------------------------
void CBaseEntity::RemoveDeferred( void )
{
// Set our next think to remove us
SetThink( &CBaseEntity::SUB_Remove );
SetNextThink( gpGlobals->curtime + 0.1f );
// Hide us completely
AddEffects( EF_NODRAW );
AddSolidFlags( FSOLID_NOT_SOLID );
SetMoveType( MOVETYPE_NONE );
}
#define MIN_CORPSE_FADE_TIME 10.0
#define MIN_CORPSE_FADE_DIST 256.0
#define MAX_CORPSE_FADE_DIST 1500.0
//
// fade out - slowly fades a entity out, then removes it.
//
// DON'T USE ME FOR GIBS AND STUFF IN MULTIPLAYER!
// SET A FUTURE THINK AND A RENDERMODE!!
void CBaseEntity::SUB_StartFadeOut( float delay, bool notSolid )
{
SetThink( &CBaseEntity::SUB_FadeOut );
SetNextThink( gpGlobals->curtime + delay );
SetRenderColorA( 255 );
m_nRenderMode = kRenderNormal;
if ( notSolid )
{
AddSolidFlags( FSOLID_NOT_SOLID );
SetLocalAngularVelocity( vec3_angle );
}
}
void CBaseEntity::SUB_StartFadeOutInstant()
{
SUB_StartFadeOut( 0, true );
}
//-----------------------------------------------------------------------------
// Purpose: Vanish when players aren't looking
//-----------------------------------------------------------------------------
void CBaseEntity::SUB_Vanish( void )
{
//Always think again next frame
SetNextThink( gpGlobals->curtime + 0.1f );
CBasePlayer *pPlayer;
//Get all players
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
//Get the next client
if ( ( pPlayer = UTIL_PlayerByIndex( i ) ) != NULL )
{
Vector corpseDir = (GetAbsOrigin() - pPlayer->WorldSpaceCenter() );
float flDistSqr = corpseDir.LengthSqr();
//If the player is close enough, don't fade out
if ( flDistSqr < (MIN_CORPSE_FADE_DIST*MIN_CORPSE_FADE_DIST) )
return;
// If the player's far enough away, we don't care about looking at it
if ( flDistSqr < (MAX_CORPSE_FADE_DIST*MAX_CORPSE_FADE_DIST) )
{
VectorNormalize( corpseDir );
Vector plForward;
pPlayer->EyeVectors( &plForward );
float dot = plForward.Dot( corpseDir );
if ( dot > 0.0f )
return;
}
}
}
//If we're here, then we can vanish safely
m_iHealth = 0;
SetThink( &CBaseEntity::SUB_Remove );
}
void CBaseEntity::SUB_PerformFadeOut( void )
{
float dt = gpGlobals->frametime;
if ( dt > 0.1f )
{
dt = 0.1f;
}
m_nRenderMode = kRenderTransTexture;
int speed = MAX(1,256*dt); // fade out over 1 second
SetRenderColorA( UTIL_Approach( 0, m_clrRender->a, speed ) );
}
bool CBaseEntity::SUB_AllowedToFade( void )
{
if( VPhysicsGetObject() )
{
if( VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD || GetEFlags() & EFL_IS_BEING_LIFTED_BY_BARNACLE )
return false;
}
// on Xbox, allow these to fade out
#ifndef _XBOX
CBasePlayer *pPlayer = ( AI_IsSinglePlayer() ) ? UTIL_GetLocalPlayer() : NULL;
if ( pPlayer && pPlayer->FInViewCone( this ) )
return false;
#endif
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Fade out slowly
//-----------------------------------------------------------------------------
void CBaseEntity::SUB_FadeOut( void )
{
if ( SUB_AllowedToFade() == false )
{
SetNextThink( gpGlobals->curtime + 1 );
SetRenderColorA( 255 );
return;
}
SUB_PerformFadeOut();
if ( m_clrRender->a == 0 )
{
#ifdef MAPBASE
// This was meant for KillWhenNotVisible before it used its own function,
// but there's not really any harm for keeping this here.
m_OnKilled.FireOutput(this, this);
#endif
2013-12-02 19:31:46 -08:00
UTIL_Remove(this);
}
else
{
SetNextThink( gpGlobals->curtime );
}
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: For KillWhenNotVisible, based off of SUB_FadeOut
//-----------------------------------------------------------------------------
void CBaseEntity::SUB_RemoveWhenNotVisible( void )
{
if ( SUB_AllowedToFade() == false )
{
SetNextThink( gpGlobals->curtime + 1, "SUB_RemoveWhenNotVisible" );
SetRenderColorA( 255 );
return;
}
SetRenderColorA( m_clrRender->a - 1 );
if ( m_clrRender->a == 0 )
{
m_OnKilled.FireOutput(this, this);
UTIL_Remove(this);
}
else
{
SetNextThink( gpGlobals->curtime, "SUB_RemoveWhenNotVisible" );
}
}
#endif
2013-12-02 19:31:46 -08:00
inline bool AnyPlayersInHierarchy_R( CBaseEntity *pEnt )
{
if ( pEnt->IsPlayer() )
return true;
for ( CBaseEntity *pCur = pEnt->FirstMoveChild(); pCur; pCur=pCur->NextMovePeer() )
{
if ( AnyPlayersInHierarchy_R( pCur ) )
return true;
}
return false;
}
void CBaseEntity::RecalcHasPlayerChildBit()
{
if ( AnyPlayersInHierarchy_R( this ) )
AddEFlags( EFL_HAS_PLAYER_CHILD );
else
RemoveEFlags( EFL_HAS_PLAYER_CHILD );
}
bool CBaseEntity::DoesHavePlayerChild()
{
return IsEFlagSet( EFL_HAS_PLAYER_CHILD );
}
//------------------------------------------------------------------------------
void CBaseEntity::IncrementInterpolationFrame()
{
m_ubInterpolationFrame = (m_ubInterpolationFrame + 1) % NOINTERP_PARITY_MAX;
}
//------------------------------------------------------------------------------
void CBaseEntity::OnModelLoadComplete( const model_t* model )
{
Assert( m_bDynamicModelPending && IsDynamicModelIndex( m_nModelIndex ) );
Assert( model == modelinfo->GetModel( m_nModelIndex ) );
m_bDynamicModelPending = false;
if ( m_bDynamicModelSetBounds )
{
m_bDynamicModelSetBounds = false;
SetCollisionBoundsFromModel();
}
OnNewModel();
}
//------------------------------------------------------------------------------
void CBaseEntity::SetCollisionBoundsFromModel()
{
if ( IsDynamicModelLoading() )
{
m_bDynamicModelSetBounds = true;
return;
}
if ( const model_t *pModel = GetModel() )
{
Vector mns, mxs;
modelinfo->GetModelBounds( pModel, mns, mxs );
UTIL_SetSize( this, mns, mxs );
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::GetScriptInstance()
{
if (!m_hScriptInstance)
{
if (m_iszScriptId == NULL_STRING)
{
char* szName = (char*)stackalloc(1024);
g_pScriptVM->GenerateUniqueKey((m_iName.Get() != NULL_STRING) ? STRING(GetEntityName()) : GetClassname(), szName, 1024);
m_iszScriptId = AllocPooledString(szName);
}
m_hScriptInstance = g_pScriptVM->RegisterInstance(GetScriptDesc(), this);
g_pScriptVM->SetInstanceUniqeId(m_hScriptInstance, STRING(m_iszScriptId));
}
return m_hScriptInstance;
}
//-----------------------------------------------------------------------------
// Using my edict, cook up a unique VScript scope that's private to me, and
// persistent.
//-----------------------------------------------------------------------------
bool CBaseEntity::ValidateScriptScope()
{
if (!m_ScriptScope.IsInitialized())
{
if (scriptmanager == NULL)
{
ExecuteOnce(DevMsg("Cannot execute script because scripting is disabled (-scripting)\n"));
return false;
}
if (g_pScriptVM == NULL)
{
ExecuteOnce(DevMsg(" Cannot execute script because there is no available VM\n"));
return false;
}
// Force instance creation
GetScriptInstance();
EHANDLE hThis;
hThis.Set(this);
bool bResult = m_ScriptScope.Init(STRING(m_iszScriptId));
if (!bResult)
{
DevMsg("%s couldn't create ScriptScope!\n", GetDebugName());
return false;
}
g_pScriptVM->SetValue(m_ScriptScope, "self", GetScriptInstance());
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Run all of the vscript files that are set in this entity's VSCRIPTS
// field in Hammer. The list is space-delimited.
//-----------------------------------------------------------------------------
void CBaseEntity::RunVScripts()
{
if (m_iszVScripts == NULL_STRING)
{
return;
}
ValidateScriptScope();
// All functions we want to have call chained instead of overwritten
// by other scripts in this entities list.
static const char* sCallChainFunctions[] =
{
"OnPostSpawn",
"Precache"
};
ScriptLanguage_t language = g_pScriptVM->GetLanguage();
// Make a call chainer for each in this entities scope
for (int j = 0; j < ARRAYSIZE(sCallChainFunctions); ++j)
{
if (language == SL_PYTHON)
{
// UNDONE - handle call chaining in python
;
}
else if (language == SL_SQUIRREL)
{
//TODO: For perf, this should be precompiled and the %s should be passed as a parameter
HSCRIPT hCreateChainScript = g_pScriptVM->CompileScript(CFmtStr("%sCallChain <- CSimpleCallChainer(\"%s\", self.GetScriptScope(), true)", sCallChainFunctions[j], sCallChainFunctions[j]));
g_pScriptVM->Run(hCreateChainScript, (HSCRIPT)m_ScriptScope);
}
}
char szScriptsList[255];
Q_strcpy(szScriptsList, STRING(m_iszVScripts));
CUtlStringList szScripts;
V_SplitString(szScriptsList, " ", szScripts);
for (int i = 0; i < szScripts.Count(); i++)
{
Log( "%s executing script: %s\n", GetDebugName(), szScripts[i]);
RunScriptFile(szScripts[i], IsWorld());
for (int j = 0; j < ARRAYSIZE(sCallChainFunctions); ++j)
{
if (language == SL_PYTHON)
{
// UNDONE - handle call chaining in python
;
}
else if (language == SL_SQUIRREL)
{
//TODO: For perf, this should be precompiled and the %s should be passed as a parameter.
HSCRIPT hRunPostScriptExecute = g_pScriptVM->CompileScript(CFmtStr("%sCallChain.PostScriptExecute()", sCallChainFunctions[j]));
g_pScriptVM->Run(hRunPostScriptExecute, (HSCRIPT)m_ScriptScope);
}
}
}
if (m_iszScriptThinkFunction != NULL_STRING)
{
SetContextThink(&CBaseEntity::ScriptThink, gpGlobals->curtime + sv_script_think_interval.GetFloat(), "ScriptThink");
}
}
//--------------------------------------------------------------------------------------------------
// This is called during entity spawning and after restore to allow scripts to precache any
// resources they need.
//--------------------------------------------------------------------------------------------------
void CBaseEntity::RunPrecacheScripts(void)
{
if (m_iszVScripts == NULL_STRING)
{
return;
}
HSCRIPT hScriptPrecache = m_ScriptScope.LookupFunction("DispatchPrecache");
if (hScriptPrecache)
{
g_pScriptVM->Call(hScriptPrecache, m_ScriptScope);
m_ScriptScope.ReleaseFunction(hScriptPrecache);
}
}
void CBaseEntity::RunOnPostSpawnScripts(void)
{
if (m_iszVScripts == NULL_STRING)
{
return;
}
HSCRIPT hFuncConnect = g_pScriptVM->LookupFunction("ConnectOutputs");
if (hFuncConnect)
{
g_pScriptVM->Call(hFuncConnect, NULL, true, NULL, (HSCRIPT)m_ScriptScope);
g_pScriptVM->ReleaseFunction(hFuncConnect);
}
HSCRIPT hFuncDisp = m_ScriptScope.LookupFunction("DispatchOnPostSpawn");
if (hFuncDisp)
{
variant_t variant;
variant.SetString(MAKE_STRING("DispatchOnPostSpawn"));
g_EventQueue.AddEvent(this, "CallScriptFunction", variant, 0, this, this);
m_ScriptScope.ReleaseFunction(hFuncDisp);
}
}
HSCRIPT CBaseEntity::GetScriptOwnerEntity()
{
return ToHScript(GetOwnerEntity());
}
void CBaseEntity::SetScriptOwnerEntity(HSCRIPT pOwner)
{
SetOwnerEntity(ToEnt(pOwner));
}
//-----------------------------------------------------------------------------
// VScript access to model's key values
// for iteration and value access, use:
// ScriptFindKey, ScriptGetFirstSubKey, ScriptGetString,
// ScriptGetInt, ScriptGetFloat, ScriptGetNextKey
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetModelKeyValues( void )
{
KeyValues *pModelKeyValues = new KeyValues("");
HSCRIPT hScript = NULL;
const char *pszModelName = modelinfo->GetModelName( GetModel() );
const char *pBuffer = modelinfo->GetModelKeyValueText( GetModel() ) ;
if ( pModelKeyValues->LoadFromBuffer( pszModelName, pBuffer ) )
{
// UNDONE: how does destructor get called on this
m_pScriptModelKeyValues = new CScriptKeyValues( pModelKeyValues );
// UNDONE: who calls ReleaseInstance on this??? Does name need to be unique???
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
#ifdef MAPBASE_VSCRIPT
// Allow VScript to delete this when the instance is removed.
hScript = g_pScriptVM->RegisterInstance( m_pScriptModelKeyValues, true );
#else
hScript = g_pScriptVM->RegisterInstance( m_pScriptModelKeyValues );
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
#endif
/*
KeyValues *pParticleEffects = pModelKeyValues->FindKey("Particles");
if ( pParticleEffects )
{
// Start grabbing the sounds and slotting them in
for ( KeyValues *pSingleEffect = pParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() )
{
const char *pParticleEffectName = pSingleEffect->GetString( "name", "" );
PrecacheParticleSystem( pParticleEffectName );
}
}
*/
}
return hScript;
}
void CBaseEntity::ScriptSetLocalAngularVelocity(float pitchVel, float yawVel, float rollVel)
{
QAngle qa;
qa.Init(pitchVel, yawVel, rollVel);
SetLocalAngularVelocity(qa);
}
const Vector& CBaseEntity::ScriptGetLocalAngularVelocity(void)
{
QAngle qa = GetLocalAngularVelocity();
static Vector v;
v.x = qa.x;
v.y = qa.y;
v.z = qa.z;
return v;
}
//-----------------------------------------------------------------------------
// Vscript: Gets the min collision bounds, centered on object
//-----------------------------------------------------------------------------
const Vector& CBaseEntity::ScriptGetBoundingMins(void)
{
return m_Collision.OBBMins();
}
//-----------------------------------------------------------------------------
// Vscript: Gets the max collision bounds, centered on object
//-----------------------------------------------------------------------------
const Vector& CBaseEntity::ScriptGetBoundingMaxs(void)
{
return m_Collision.OBBMaxs();
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CBaseEntity::ScriptTakeDamage( HSCRIPT pInfo )
{
if (pInfo)
{
CTakeDamageInfo *info = HScriptToClass<CTakeDamageInfo>( pInfo ); //ToDamageInfo( pInfo );
if (info)
{
return OnTakeDamage( *info );
}
}
return 0;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptFireBullets( HSCRIPT pInfo )
{
if (pInfo)
{
extern FireBulletsInfo_t *GetFireBulletsInfoFromInfo( HSCRIPT hBulletsInfo );
FireBulletsInfo_t *info = GetFireBulletsInfoFromInfo( pInfo );
if (info)
{
FireBullets( *info );
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptAddContext( const char *name, const char *value, float duration )
{
AddContext( name, value, duration );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char *CBaseEntity::ScriptGetContext( const char *name )
{
return GetContextValue( name );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CBaseEntity::ScriptClassify( void )
{
return (int)Classify();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CBaseEntity::ScriptAddOutput( const char *pszOutputName, const char *pszTarget, const char *pszAction, const char *pszParameter, float flDelay, int iMaxTimes )
{
const char *pszValue = UTIL_VarArgs("%s,%s,%s,%f,%i", pszTarget, pszAction, pszParameter, flDelay, iMaxTimes);
return KeyValue( pszOutputName, pszValue );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char *CBaseEntity::ScriptGetKeyValue( const char *pszKeyName )
{
static char szValue[128];
GetKeyValue( pszKeyName, szValue, sizeof(szValue) );
return szValue;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const Vector& CBaseEntity::ScriptGetColorVector()
{
static Vector vecColor;
vecColor.Init( m_clrRender.GetR(), m_clrRender.GetG(), m_clrRender.GetB() );
return vecColor;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptSetColorVector( const Vector& vecColor )
{
SetRenderColor( vecColor.x, vecColor.y, vecColor.z );
}
Mapbase v4.3 - Fixed a crash with multiple trigger_look targets - Fixed an issue where some zombie submodel server ragdolls are not solid to the world - Fixed a crash with certain instance classes being loaded in a savegame before the class is registered - Added some of Tony Sergi's missing Source 2007 fixes (contributed by Kris) - Added "ClientCommand" hook for VScript to allow handling of unknown console commands - Added "PlayerRunCommand" hook for VScript to control player movement - Added new button-related script functions for players (GetButtons, DisableButtons, etc.) - Added CUserCmd accessor in VScript for the "PlayerRunCommand" hook - Added "GetWaterLevel" function for VScript - Exposed "Ignite" to VScript for controlling how a fire starts - Fixed NPCs being unable to unholster weapons - Fixed Mapbase crashing when Steam isn't running - Fixed issues with angled/updating sky_camera save/restore - Added VBSP "-skyboxcubemap" parameter to enable skybox default cubemaps + "-defaultcubemapres" to control their resolution - Added ability to disable VScript in a map (and fixed a few potential complications from disabling VScript) - Made clientside VScript only initialize after world is spawned in order to receive serverside script language in time - Added tons of VScript functions to CBaseAnimating related to bodygroups, sequences, etc. - Added VScript functions to players for getting user ID and player name, similar to logic_playerinfo - Added a few L4D2 script functions missing from the ASW SDK - Added "Localize" singleton with a single "GetTokenAsUTF8" function for getting localization strings - Disabled r_hunkalloclightmaps by the request of various users (apparently this completely removes the "Engine hunk overflow" error and allows for really high-res lightmaps) - Fixed npc_antlionguard NPC_TranslateActivity not hooking into base class (allows for VScript manipulation) - Added various unused antlion guard activities to npc_antlionguard AI, allowing for usage as registered activities - Added keyvalue to set LOS mask on combine_mine - Added +USE bounding box limiter to prop_interactable
2020-07-16 15:43:30 +00:00
vscript changes: c_baseentity.h c_baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed GetTeamNumber to GetTeam baseentity.h baseentity.cpp - Renamed GetLeftVector to GetRightVector - Renamed Get/SetRender functions (GetAlpha -> GetRenderAlpha) - Fixed CBaseEntity::GetScriptId - Added hook CBaseEntity::UpdateOnRemove - Added CBaseEntity::GetOrCreatePrivateScriptScope - Added CBaseEntity::GetDebugName - Added CBaseEntity::GetGravity - Added CBaseEntity::SetGravity - Added CBaseEntity::GetFriction - Added CBaseEntity::SetFriction - Added CBaseEntity::GetMass - Added CBaseEntity::SetMass - Added CBaseEntity::SetName (SetNameAsCStr) - Added CBaseEntity::SetParent (ScriptSetParent) - Added CBaseEntity::SetThink (ScriptSetThink) - Added CBaseEntity::StopThink (ScriptStopThink) - Added CBaseEntity::SetThinkFunction (ScriptSetThinkFunction) - Added CBaseEntity::StopThinkFunction (ScriptStopThinkFunction) - Added CBaseEntity::ApplyAbsVelocityImpulse - Added CBaseEntity::ApplyLocalAngularVelocityImpulse player.h player.cpp - Renamed GetPlayerUserId to GetUserID - Added CBasePlayer::GetFOV - Added CBasePlayer::GetFOVOwner (ScriptGetFOVOwner) - Added CBasePlayer::SetFOV (ScriptSetFOV) vscript_consts_shared.cpp -Added RAD2DEG, DEG2RAD, MAX_COORD_FLOAT, MAX_TRACE_LENGTH vscript_funcs_shared.cpp - Renamed IsClientScript,IsServerScript to IsClient,IsServer - Added IsDedicatedServer - Added NPrint (Con_NPrintf) - Removed DebugDrawBoxDirection (debugoverlay.BoxDirection) - Removed DebugDrawText (debugoverlay.Text) vscript_server.cpp - Added CDebugOverlayScriptHelper (debugoverlay) - Added CEntities::GetLocalPlayer - Added DispatchParticleEffect (ScriptDispatchParticleEffect) - Removed DebugDrawBox (debugoverlay.Box) - Removed DebugDrawLine (debugoverlay.Line) vscript_squirrel.cpp - Changed stub error messages for consistency and clarity - Changed errorfunc output to Warning instead of Msg - Added Msg, Warning - Added clamp, min, max, RemapVal, RemapValClamped - Added sqstdtime.h - Added clock, time, date
2020-08-30 15:58:34 +03:00
void CBaseEntity::ScriptSetColor( int r, int g, int b )
{
SetRenderColor( r, g, b );
}
Mapbase v4.3 - Fixed a crash with multiple trigger_look targets - Fixed an issue where some zombie submodel server ragdolls are not solid to the world - Fixed a crash with certain instance classes being loaded in a savegame before the class is registered - Added some of Tony Sergi's missing Source 2007 fixes (contributed by Kris) - Added "ClientCommand" hook for VScript to allow handling of unknown console commands - Added "PlayerRunCommand" hook for VScript to control player movement - Added new button-related script functions for players (GetButtons, DisableButtons, etc.) - Added CUserCmd accessor in VScript for the "PlayerRunCommand" hook - Added "GetWaterLevel" function for VScript - Exposed "Ignite" to VScript for controlling how a fire starts - Fixed NPCs being unable to unholster weapons - Fixed Mapbase crashing when Steam isn't running - Fixed issues with angled/updating sky_camera save/restore - Added VBSP "-skyboxcubemap" parameter to enable skybox default cubemaps + "-defaultcubemapres" to control their resolution - Added ability to disable VScript in a map (and fixed a few potential complications from disabling VScript) - Made clientside VScript only initialize after world is spawned in order to receive serverside script language in time - Added tons of VScript functions to CBaseAnimating related to bodygroups, sequences, etc. - Added VScript functions to players for getting user ID and player name, similar to logic_playerinfo - Added a few L4D2 script functions missing from the ASW SDK - Added "Localize" singleton with a single "GetTokenAsUTF8" function for getting localization strings - Disabled r_hunkalloclightmaps by the request of various users (apparently this completely removes the "Engine hunk overflow" error and allows for really high-res lightmaps) - Fixed npc_antlionguard NPC_TranslateActivity not hooking into base class (allows for VScript manipulation) - Added various unused antlion guard activities to npc_antlionguard AI, allowing for usage as registered activities - Added keyvalue to set LOS mask on combine_mine - Added +USE bounding box limiter to prop_interactable
2020-07-16 15:43:30 +00:00
//-----------------------------------------------------------------------------
// Vscript: Gets the entity matrix transform
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptEntityToWorldTransform( void )
{
return ScriptCreateMatrixInstance( EntityToWorldTransform() );
}
Mapbase v5.0 - Added keyvalue to hl2_gamerules which allows respawning in singleplayer - Added the game instructor system (including env_instructor_hint) from later Valve games using a VDC tutorial which adjusts the version from the Alien Swarm SDK to FPS rules and a Source 2013 environment; Also added new KV and icons for further control from mappers (tutorial mentioned by Maestra Fenix) - Added L4D/TF2 glows + point_glow entity as an all-purpose SDK-based off-shoot of tf_glow - Fixed weapon pickup sound not playing (reported by Sl0th and later Cvoxulary) - Fixed env_projectedtextures not updating on save/load - Added func_fake_worldportal, a spatial point_camera inspired by linked_portal_door based on SDK code alone (WIP, may be changed a lot in future updates) - Added option for point_camera and func_reflective_glass to use different render targets, therefore allowing multiple cameras and mirrors to be active at the same time - Added additional RT camera textures to choose from with a default of 3, but also controllable through a -numcameratextures command line param - Added adjustable convars for main view NearZ and skybox NearZ (suggested by someone recently, also suggested by Klems over a year ago) - Fixed map-specific localization files, cleaned up map-specific file code - Added a new block to gameinfo.txt which allows mods to automatically append their own command line parameters - Fixed math_lightpattern corruption when setting pattern/style while active - Fixed the "Touch" input crashing when given no entity - Added a way to add EFlags via keyvalue (suggested by Niker107) - Fixed ai_script_conditions not working without a NPC actor (reported by MetroHam) - Fixed point_radiation_source causing huge problems when intensity is 0, even though it was already advised against (reported by beefbacon) - Added "Mapbase" header to Mapbase-specific code files - Fixed an issue with updating sky_camera not obtaining area correctly, causing some entities to not draw in the skybox - Added "CopyFogController" and "CopyFogControllerWithScale" inputs to sky_camera, which copy fog parameters directly from a fog controller - Added "SetScale" input to sky_camera for live scale changing - Added convar to control player crouch speed multiplier (suggested by ArtyIF) - Added a ton of fixes for people running the Debug configuration of the codebase (partial credit to stepa2) - Added support for pre-defined enums and constants in VScript, starting with various values from the SDK code (damage types, trace masks, etc.) - Added limited support for Valve's Quaternion class in VScript - Added new instance helper capabilities, destructible game instances, and other misc. changes to VScript library - Replaced most of the VScript "accessor" classes with direct references to the original classes, as they were getting complicated fast and adding new VScript-only functions to the original classes might not be as bad as previously thought - Added base NPC hooks for AI sensing in VScript (allows control over sight and hearing), also exposed CSound for it - Added various functions and hooks for VPhysics integration in VScript - Added VScript-based custom suit devices - Expanded trace info exposed to VScript to allow plane and surface access (suggested by krassell) - Added ability to insert localization strings through VScript - Added various misc. VScript functions with various purposes, including reading/writing EFlags, movetypes, collision groups, etc. - Fixed VBSP not being able to correctly parse parallax corrected cubemaps in maps with instances
2020-08-14 21:21:25 +00:00
//-----------------------------------------------------------------------------
// Vscript: Gets the entity's physics object if it has one
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void )
{
if (VPhysicsGetObject())
return g_pScriptVM->RegisterInstance( VPhysicsGetObject() );
else
return NULL;
}
#endif
Mapbase v2.0; bulk commit - Added custom map compile tools (vbsp, vvis, vrad) - Changed blink fix (shouldn't change anything in-game) - Added auto-completion to ent_create, npc_create, and the main set of "npc_" debug commands - Added ent_create_aimed, an ent_create equivalent of npc_create_aimed - Made hunters start using the "vs. player" melee animation against smaller NPCs that look weird with the "stab" attack - Added "explosion_sparks" convar, which fixes broken code for giving explosions sparks (disabled by default because of how different it looks) - Made interaction code capable of being dispatched on any entity, not just combat characters - Added npc_barnacle_ignite convar, which lets barnacles be ignited by flares - Fixed certain NPCs getting out of the way for the player when they hate them - Fixed auto-generated "speak" scene responses not using parameters that work on real VCDs - Made "stop_on_nonidle" capable of being used in any mod, not just HL2 episodic mods - Selectable color for ragdoll boogie/point_ragdollboogie - Fixed PickupWeaponInstant not firing weapon pickup outputs - Introduced inputs and keyvalues for "lerping" to math_counter_advanced - Fixed ClearConsole on logic_console - logic_convar should now detect client convars correctly - New NormalizeAngles input on math_vector - logic_modelinfo LookupActivity input - math_generate fixed and expanded to be more like math_counter - Added a WIP game logging system for playtesting maps - Introduced logic_playerinfo, an entity that can read a player's name or ID - Fixed some new filters not working with filter_multi - Added radius pickup spawnflag to func_physbox - Added "Preserve name" spawnflag to weapons - Added cc_achievement_debug message for when an achievement doesn't exist - Made npc_combine_s not speak while in logic_choreographed_scenes - Fixed zombie torsos/legs/headcrabs not being serverside when zombie is forced to server ragdoll - Expanded and cleaned up npc_zombie_custom - Fixed func_commandredirects not cleaning up correctly and sometimes crashing the game - Allowed player squad commands to go through +USE-held objects - Added a bunch of I/O/KV to trigger_waterydeath for better configuration - Changed save comment system to use the chapter title from world properties, and the ability to suppress the title popup that normally results from it - Adjusted game_convar_mod for MP planning - Removed the func_precipitation custom particle/splash code for now, as it was causing problems - Fixed env_global_light not accepting lightcolor - Added "Additional Buttons" to player_speedmod - Added save comment to RPC - Added env_projectedtexture attenuation - Added scripted_sequence OnPreIdleSequence - Added OnCrab to zombies - Added skill_changed game event (may need further testing) - Added a fix for viewmodels flipping under extreme FOV values - Added code that allows mappers to change the skin on shotgunners without it usually flipping back randomly - Fixed a very, very, very major shader performance issue - New SetAbsOrigin/Angles inputs on all entities, analogous to SetLocalOrigin/Angles - Code improvements for I/O involving angles - logic_entity_position improvements/fixes, including a new OutAngles output that outputs the angles on position calls - Alternate collision/player avoidance spawnflag obsoletion enforcement disabled - Enable/DisableHazardLights inputs on the EP2 jalopy, equivalent to the keyvalue - Miscellaneous shader formatting adjustments and fixes - Fixed AlwaysDrawOff on env_projectedtexture not being a valid input
2019-12-14 04:20:02 +00:00
#ifdef MAPBASE
extern int EntityFactory_AutoComplete( const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0 );
//------------------------------------------------------------------------------
// Purpose: Create an entity of the given type
//------------------------------------------------------------------------------
class CEntCreateAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback
{
public:
virtual bool CreateAimed() { return false; }
virtual void CommandCallback( const CCommand &args )
{
MDLCACHE_CRITICAL_SECTION();
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if (!pPlayer)
{
return;
}
// Don't allow regular users to create point_servercommand entities for the same reason as blocking ent_fire
if ( !Q_stricmp( args[1], "point_servercommand" ) )
{
if ( engine->IsDedicatedServer() )
{
// We allow people with disabled autokick to do it, because they already have rcon.
if ( pPlayer->IsAutoKickDisabled() == false )
return;
}
else if ( gpGlobals->maxClients > 1 )
{
// On listen servers with more than 1 player, only allow the host to create point_servercommand.
CBasePlayer *pHostPlayer = UTIL_GetListenServerHost();
if ( pPlayer != pHostPlayer )
return;
}
}
bool allowPrecache = CBaseEntity::IsPrecacheAllowed();
CBaseEntity::SetAllowPrecache( true );
// Try to create entity
CBaseEntity *entity = dynamic_cast< CBaseEntity * >( CreateEntityByName(args[1]) );
if (entity)
{
// Pass in any additional parameters.
for ( int i = 2; i + 1 < args.ArgC(); i += 2 )
{
const char *pKeyName = args[i];
const char *pValue = args[i+1];
entity->KeyValue( pKeyName, pValue );
}
DispatchSpawn(entity);
// Now attempt to drop into the world
trace_t tr;
Vector forward;
pPlayer->EyeVectors( &forward );
// Pass through the player's vehicle
CTraceFilterSkipTwoEntities filter( pPlayer, pPlayer->GetVehicleEntity(), COLLISION_GROUP_NONE );
Mapbase v2.0; bulk commit - Added custom map compile tools (vbsp, vvis, vrad) - Changed blink fix (shouldn't change anything in-game) - Added auto-completion to ent_create, npc_create, and the main set of "npc_" debug commands - Added ent_create_aimed, an ent_create equivalent of npc_create_aimed - Made hunters start using the "vs. player" melee animation against smaller NPCs that look weird with the "stab" attack - Added "explosion_sparks" convar, which fixes broken code for giving explosions sparks (disabled by default because of how different it looks) - Made interaction code capable of being dispatched on any entity, not just combat characters - Added npc_barnacle_ignite convar, which lets barnacles be ignited by flares - Fixed certain NPCs getting out of the way for the player when they hate them - Fixed auto-generated "speak" scene responses not using parameters that work on real VCDs - Made "stop_on_nonidle" capable of being used in any mod, not just HL2 episodic mods - Selectable color for ragdoll boogie/point_ragdollboogie - Fixed PickupWeaponInstant not firing weapon pickup outputs - Introduced inputs and keyvalues for "lerping" to math_counter_advanced - Fixed ClearConsole on logic_console - logic_convar should now detect client convars correctly - New NormalizeAngles input on math_vector - logic_modelinfo LookupActivity input - math_generate fixed and expanded to be more like math_counter - Added a WIP game logging system for playtesting maps - Introduced logic_playerinfo, an entity that can read a player's name or ID - Fixed some new filters not working with filter_multi - Added radius pickup spawnflag to func_physbox - Added "Preserve name" spawnflag to weapons - Added cc_achievement_debug message for when an achievement doesn't exist - Made npc_combine_s not speak while in logic_choreographed_scenes - Fixed zombie torsos/legs/headcrabs not being serverside when zombie is forced to server ragdoll - Expanded and cleaned up npc_zombie_custom - Fixed func_commandredirects not cleaning up correctly and sometimes crashing the game - Allowed player squad commands to go through +USE-held objects - Added a bunch of I/O/KV to trigger_waterydeath for better configuration - Changed save comment system to use the chapter title from world properties, and the ability to suppress the title popup that normally results from it - Adjusted game_convar_mod for MP planning - Removed the func_precipitation custom particle/splash code for now, as it was causing problems - Fixed env_global_light not accepting lightcolor - Added "Additional Buttons" to player_speedmod - Added save comment to RPC - Added env_projectedtexture attenuation - Added scripted_sequence OnPreIdleSequence - Added OnCrab to zombies - Added skill_changed game event (may need further testing) - Added a fix for viewmodels flipping under extreme FOV values - Added code that allows mappers to change the skin on shotgunners without it usually flipping back randomly - Fixed a very, very, very major shader performance issue - New SetAbsOrigin/Angles inputs on all entities, analogous to SetLocalOrigin/Angles - Code improvements for I/O involving angles - logic_entity_position improvements/fixes, including a new OutAngles output that outputs the angles on position calls - Alternate collision/player avoidance spawnflag obsoletion enforcement disabled - Enable/DisableHazardLights inputs on the EP2 jalopy, equivalent to the keyvalue - Miscellaneous shader formatting adjustments and fixes - Fixed AlwaysDrawOff on env_projectedtexture not being a valid input
2019-12-14 04:20:02 +00:00
UTIL_TraceLine(pPlayer->EyePosition(),
pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_SOLID,
&filter, &tr );
Mapbase v2.0; bulk commit - Added custom map compile tools (vbsp, vvis, vrad) - Changed blink fix (shouldn't change anything in-game) - Added auto-completion to ent_create, npc_create, and the main set of "npc_" debug commands - Added ent_create_aimed, an ent_create equivalent of npc_create_aimed - Made hunters start using the "vs. player" melee animation against smaller NPCs that look weird with the "stab" attack - Added "explosion_sparks" convar, which fixes broken code for giving explosions sparks (disabled by default because of how different it looks) - Made interaction code capable of being dispatched on any entity, not just combat characters - Added npc_barnacle_ignite convar, which lets barnacles be ignited by flares - Fixed certain NPCs getting out of the way for the player when they hate them - Fixed auto-generated "speak" scene responses not using parameters that work on real VCDs - Made "stop_on_nonidle" capable of being used in any mod, not just HL2 episodic mods - Selectable color for ragdoll boogie/point_ragdollboogie - Fixed PickupWeaponInstant not firing weapon pickup outputs - Introduced inputs and keyvalues for "lerping" to math_counter_advanced - Fixed ClearConsole on logic_console - logic_convar should now detect client convars correctly - New NormalizeAngles input on math_vector - logic_modelinfo LookupActivity input - math_generate fixed and expanded to be more like math_counter - Added a WIP game logging system for playtesting maps - Introduced logic_playerinfo, an entity that can read a player's name or ID - Fixed some new filters not working with filter_multi - Added radius pickup spawnflag to func_physbox - Added "Preserve name" spawnflag to weapons - Added cc_achievement_debug message for when an achievement doesn't exist - Made npc_combine_s not speak while in logic_choreographed_scenes - Fixed zombie torsos/legs/headcrabs not being serverside when zombie is forced to server ragdoll - Expanded and cleaned up npc_zombie_custom - Fixed func_commandredirects not cleaning up correctly and sometimes crashing the game - Allowed player squad commands to go through +USE-held objects - Added a bunch of I/O/KV to trigger_waterydeath for better configuration - Changed save comment system to use the chapter title from world properties, and the ability to suppress the title popup that normally results from it - Adjusted game_convar_mod for MP planning - Removed the func_precipitation custom particle/splash code for now, as it was causing problems - Fixed env_global_light not accepting lightcolor - Added "Additional Buttons" to player_speedmod - Added save comment to RPC - Added env_projectedtexture attenuation - Added scripted_sequence OnPreIdleSequence - Added OnCrab to zombies - Added skill_changed game event (may need further testing) - Added a fix for viewmodels flipping under extreme FOV values - Added code that allows mappers to change the skin on shotgunners without it usually flipping back randomly - Fixed a very, very, very major shader performance issue - New SetAbsOrigin/Angles inputs on all entities, analogous to SetLocalOrigin/Angles - Code improvements for I/O involving angles - logic_entity_position improvements/fixes, including a new OutAngles output that outputs the angles on position calls - Alternate collision/player avoidance spawnflag obsoletion enforcement disabled - Enable/DisableHazardLights inputs on the EP2 jalopy, equivalent to the keyvalue - Miscellaneous shader formatting adjustments and fixes - Fixed AlwaysDrawOff on env_projectedtexture not being a valid input
2019-12-14 04:20:02 +00:00
if ( tr.fraction != 1.0 )
{
// Raise the end position a little up off the floor, place the npc and drop him down
tr.endpos.z += 12;
if (CreateAimed())
{
QAngle angles;
VectorAngles( forward, angles );
angles.x = 0;
angles.z = 0;
entity->Teleport( &tr.endpos, &angles, NULL );
}
else
{
entity->Teleport( &tr.endpos, NULL, NULL );
}
UTIL_DropToFloor( entity, MASK_SOLID );
}
entity->Activate();
}
CBaseEntity::SetAllowPrecache( allowPrecache );
}
virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands )
{
if ( !g_pGameRules )
{
return 0;
}
const char *cmdname = CreateAimed() ? "ent_create_aimed" : "ent_create";
char *substring = (char *)partial;
if ( Q_strstr( partial, cmdname ) )
{
substring = (char *)partial + strlen( cmdname ) + 1;
}
int checklen = Q_strlen( substring );
CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
return EntityFactory_AutoComplete( cmdname, commands, symbols, substring, checklen );
}
};
static CEntCreateAutoCompletionFunctor g_EntCreateAutoComplete;
static ConCommand ent_create("ent_create", &g_EntCreateAutoComplete, "Creates an entity of the given type where the player is looking. Additional parameters can be passed in in the form: ent_create <entity name> <param 1 name> <param 1> <param 2 name> <param 2>...<param N name> <param N>", FCVAR_GAMEDLL | FCVAR_CHEAT, &g_EntCreateAutoComplete);
class CEntCreateAimedAutoCompletionFunctor : public CEntCreateAutoCompletionFunctor
{
public:
virtual bool CreateAimed() { return true; }
};
static CEntCreateAimedAutoCompletionFunctor g_EntCreateAimedAutoComplete;
static ConCommand ent_create_aimed("ent_create_aimed", &g_EntCreateAimedAutoComplete, "Creates an entity of the given type where the player is looking. Additional parameters can be passed in in the form: ent_create_aimed <entity name> <param 1 name> <param 1> <param 2 name> <param 2>...<param N name> <param N>", FCVAR_CHEAT, &g_EntCreateAimedAutoComplete);
#else
2013-12-02 19:31:46 -08:00
//------------------------------------------------------------------------------
// Purpose: Create an NPC of the given type
//------------------------------------------------------------------------------
void CC_Ent_Create( const CCommand& args )
{
MDLCACHE_CRITICAL_SECTION();
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if (!pPlayer)
{
return;
}
// Don't allow regular users to create point_servercommand entities for the same reason as blocking ent_fire
if ( !Q_stricmp( args[1], "point_servercommand" ) )
{
if ( engine->IsDedicatedServer() )
{
// We allow people with disabled autokick to do it, because they already have rcon.
if ( pPlayer->IsAutoKickDisabled() == false )
return;
}
else if ( gpGlobals->maxClients > 1 )
{
// On listen servers with more than 1 player, only allow the host to create point_servercommand.
CBasePlayer *pHostPlayer = UTIL_GetListenServerHost();
if ( pPlayer != pHostPlayer )
return;
}
}
bool allowPrecache = CBaseEntity::IsPrecacheAllowed();
CBaseEntity::SetAllowPrecache( true );
// Try to create entity
CBaseEntity *entity = dynamic_cast< CBaseEntity * >( CreateEntityByName(args[1]) );
if (entity)
{
entity->Precache();
// Pass in any additional parameters.
for ( int i = 2; i + 1 < args.ArgC(); i += 2 )
{
const char *pKeyName = args[i];
const char *pValue = args[i+1];
entity->KeyValue( pKeyName, pValue );
}
DispatchSpawn(entity);
// Now attempt to drop into the world
trace_t tr;
Vector forward;
pPlayer->EyeVectors( &forward );
UTIL_TraceLine(pPlayer->EyePosition(),
pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_SOLID,
pPlayer, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction != 1.0 )
{
// Raise the end position a little up off the floor, place the npc and drop him down
tr.endpos.z += 12;
entity->Teleport( &tr.endpos, NULL, NULL );
UTIL_DropToFloor( entity, MASK_SOLID );
}
entity->Activate();
}
CBaseEntity::SetAllowPrecache( allowPrecache );
}
static ConCommand ent_create("ent_create", CC_Ent_Create, "Creates an entity of the given type where the player is looking. Additional parameters can be passed in in the form: ent_create <entity name> <param 1 name> <param 1> <param 2 name> <param 2>...<param N name> <param N>", FCVAR_GAMEDLL | FCVAR_CHEAT);
Mapbase v2.0; bulk commit - Added custom map compile tools (vbsp, vvis, vrad) - Changed blink fix (shouldn't change anything in-game) - Added auto-completion to ent_create, npc_create, and the main set of "npc_" debug commands - Added ent_create_aimed, an ent_create equivalent of npc_create_aimed - Made hunters start using the "vs. player" melee animation against smaller NPCs that look weird with the "stab" attack - Added "explosion_sparks" convar, which fixes broken code for giving explosions sparks (disabled by default because of how different it looks) - Made interaction code capable of being dispatched on any entity, not just combat characters - Added npc_barnacle_ignite convar, which lets barnacles be ignited by flares - Fixed certain NPCs getting out of the way for the player when they hate them - Fixed auto-generated "speak" scene responses not using parameters that work on real VCDs - Made "stop_on_nonidle" capable of being used in any mod, not just HL2 episodic mods - Selectable color for ragdoll boogie/point_ragdollboogie - Fixed PickupWeaponInstant not firing weapon pickup outputs - Introduced inputs and keyvalues for "lerping" to math_counter_advanced - Fixed ClearConsole on logic_console - logic_convar should now detect client convars correctly - New NormalizeAngles input on math_vector - logic_modelinfo LookupActivity input - math_generate fixed and expanded to be more like math_counter - Added a WIP game logging system for playtesting maps - Introduced logic_playerinfo, an entity that can read a player's name or ID - Fixed some new filters not working with filter_multi - Added radius pickup spawnflag to func_physbox - Added "Preserve name" spawnflag to weapons - Added cc_achievement_debug message for when an achievement doesn't exist - Made npc_combine_s not speak while in logic_choreographed_scenes - Fixed zombie torsos/legs/headcrabs not being serverside when zombie is forced to server ragdoll - Expanded and cleaned up npc_zombie_custom - Fixed func_commandredirects not cleaning up correctly and sometimes crashing the game - Allowed player squad commands to go through +USE-held objects - Added a bunch of I/O/KV to trigger_waterydeath for better configuration - Changed save comment system to use the chapter title from world properties, and the ability to suppress the title popup that normally results from it - Adjusted game_convar_mod for MP planning - Removed the func_precipitation custom particle/splash code for now, as it was causing problems - Fixed env_global_light not accepting lightcolor - Added "Additional Buttons" to player_speedmod - Added save comment to RPC - Added env_projectedtexture attenuation - Added scripted_sequence OnPreIdleSequence - Added OnCrab to zombies - Added skill_changed game event (may need further testing) - Added a fix for viewmodels flipping under extreme FOV values - Added code that allows mappers to change the skin on shotgunners without it usually flipping back randomly - Fixed a very, very, very major shader performance issue - New SetAbsOrigin/Angles inputs on all entities, analogous to SetLocalOrigin/Angles - Code improvements for I/O involving angles - logic_entity_position improvements/fixes, including a new OutAngles output that outputs the angles on position calls - Alternate collision/player avoidance spawnflag obsoletion enforcement disabled - Enable/DisableHazardLights inputs on the EP2 jalopy, equivalent to the keyvalue - Miscellaneous shader formatting adjustments and fixes - Fixed AlwaysDrawOff on env_projectedtexture not being a valid input
2019-12-14 04:20:02 +00:00
#endif
2013-12-02 19:31:46 -08:00
//------------------------------------------------------------------------------
// Purpose: Teleport a specified entity to where the player is looking
//------------------------------------------------------------------------------
bool CC_GetCommandEnt( const CCommand& args, CBaseEntity **ent, Vector *vecTargetPoint, QAngle *vecPlayerAngle )
{
// Find the entity
*ent = NULL;
// First try using it as an entindex
int iEntIndex = atoi( args[1] );
if ( iEntIndex )
{
*ent = CBaseEntity::Instance( iEntIndex );
}
else
{
// Try finding it by name
*ent = gEntList.FindEntityByName( NULL, args[1] );
if ( !*ent )
{
// Finally, try finding it by classname
*ent = gEntList.FindEntityByClassname( NULL, args[1] );
}
}
if ( !*ent )
{
Msg( "Couldn't find any entity named '%s'\n", args[1] );
return false;
}
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if ( vecTargetPoint )
{
trace_t tr;
Vector forward;
pPlayer->EyeVectors( &forward );
UTIL_TraceLine(pPlayer->EyePosition(),
pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_NPCSOLID,
pPlayer, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction != 1.0 )
{
*vecTargetPoint = tr.endpos;
}
}
if ( vecPlayerAngle )
{
*vecPlayerAngle = pPlayer->EyeAngles();
}
return true;
}
#ifdef MAPBASE
class CEntTeleportAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback
{
public:
virtual void CommandCallback( const CCommand &command )
{
if ( command.ArgC() < 2 )
{
Msg( "Format: ent_teleport <entity name>\n" );
return;
}
CBaseEntity *pEnt;
Vector vecTargetPoint;
if ( CC_GetCommandEnt( command, &pEnt, &vecTargetPoint, NULL ) )
{
pEnt->Teleport( &vecTargetPoint, NULL, NULL );
}
}
virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands )
{
if ( !g_pGameRules )
{
return 0;
}
const char *cmdname = "ent_teleport";
char *substring = (char *)partial;
if ( Q_strstr( partial, cmdname ) )
{
substring = (char *)partial + strlen( cmdname ) + 1;
}
int checklen = Q_strlen( substring );
CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
return AutoCompleteEntities(cmdname, commands, symbols, substring, checklen);
}
};
static CEntTeleportAutoCompletionFunctor g_EntTeleportAutoComplete;
static ConCommand ent_teleport("ent_teleport", &g_EntTeleportAutoComplete, "Teleport the specified entity to where the player is looking.\n\tFormat: ent_teleport <entity name>", FCVAR_CHEAT, &g_EntTeleportAutoComplete);
#else
2013-12-02 19:31:46 -08:00
//------------------------------------------------------------------------------
// Purpose: Teleport a specified entity to where the player is looking
//------------------------------------------------------------------------------
void CC_Ent_Teleport( const CCommand& args )
{
if ( args.ArgC() < 2 )
{
Msg( "Format: ent_teleport <entity name>\n" );
return;
}
CBaseEntity *pEnt;
Vector vecTargetPoint;
if ( CC_GetCommandEnt( args, &pEnt, &vecTargetPoint, NULL ) )
{
pEnt->Teleport( &vecTargetPoint, NULL, NULL );
}
}
static ConCommand ent_teleport("ent_teleport", CC_Ent_Teleport, "Teleport the specified entity to where the player is looking.\n\tFormat: ent_teleport <entity name>", FCVAR_CHEAT);
#endif
2013-12-02 19:31:46 -08:00
//------------------------------------------------------------------------------
// Purpose: Orient a specified entity to match the player's angles
//------------------------------------------------------------------------------
void CC_Ent_Orient( const CCommand& args )
{
if ( args.ArgC() < 2 )
{
Msg( "Format: ent_orient <entity name> <optional: allangles>\n" );
return;
}
CBaseEntity *pEnt;
QAngle vecPlayerAngles;
if ( CC_GetCommandEnt( args, &pEnt, NULL, &vecPlayerAngles ) )
{
QAngle vecEntAngles = pEnt->GetAbsAngles();
if ( args.ArgC() == 3 && !Q_strncmp( args[2], "allangles", 9 ) )
{
vecEntAngles = vecPlayerAngles;
}
else
{
vecEntAngles[YAW] = vecPlayerAngles[YAW];
}
pEnt->SetAbsAngles( vecEntAngles );
}
}
static ConCommand ent_orient("ent_orient", CC_Ent_Orient, "Orient the specified entity to match the player's angles. By default, only orients target entity's YAW. Use the 'allangles' option to orient on all axis.\n\tFormat: ent_orient <entity name> <optional: allangles>", FCVAR_CHEAT);