Mapbase v4.0; VScript support

VScript support in Mapbase
This commit is contained in:
Blixibon 2020-06-13 16:06:05 -05:00 committed by GitHub
commit 0c0a26dea6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
266 changed files with 38931 additions and 142 deletions

12
.gitignore vendored
View File

@ -53,6 +53,7 @@ config.cfg
# shader files
*.tmp
*.vcs
# Unnecessary files
*.lib
@ -75,3 +76,14 @@ sp/src/game/server/Release_mod_episodic/
sp/src/game/server/Release_mod_hl2/
sp/src/*/Debug/
sp/src/*/Release/
sp/game/*.dll
sp/game/*.pdb
sp/game/*.exe
sp/src/utils/*.dll
sp/src/utils/*.pdb
sp/src/utils/*.exe
sp/src/utils/*.res
sp/src/materialsystem/*.dll
sp/src/materialsystem/*.pdb
sp/src/vgui2/*.dll
sp/src/vgui2/*.pdb

1
README
View File

@ -8,6 +8,7 @@ The Alien Swarm-based radial fog and rope code as well as the multiple skybox su
The dynamic RTT shadow angles code is from Saul Rennison on the VDC. (https://developer.valvesoftware.com/wiki/Dynamic_RTT_shadow_angles_in_Source_2007)
The vortigaunt LOS fix is from Half-Life 2: Community Edition (dky.tehkingd.u in particular). (https://gitlab.com/RaraCerberus/HL2CE)
The parallax corrected cubemap code was originally created by Brian Charles. (https://developer.valvesoftware.com/wiki/Parallax_Corrected_Cubemaps)
The custom VScript library was created by reductor for Mapbase. (https://github.com/mapbase-source/source-sdk-2013/pull/5)
Various other code and contributions were based off of pull requests in the Source 2013 SDK (https://github.com/ValveSoftware/source-sdk-2013/pulls) and snippets on the Valve Developer Community (http://developer.valvesoftware.com/).
All of the work mentioned above was open source when it was borrowed.

View File

@ -281,6 +281,11 @@ BEGIN_DATADESC( C_ClientRagdoll )
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetPoseParameter, "SetPoseParameter", "Set the specified pose parameter to the specified value" )
DEFINE_SCRIPTFUNC( IsSequenceFinished, "Ask whether the main sequence is done playing" )
END_SCRIPTDESC();
C_ClientRagdoll::C_ClientRagdoll( bool bRestoring )
{
m_iCurrentFriction = 0;
@ -1403,6 +1408,15 @@ float C_BaseAnimating::ClampCycle( float flCycle, bool isLooping )
return flCycle;
}
void C_BaseAnimating::ScriptSetPoseParameter(const char* szName, float fValue)
{
CStudioHdr* pHdr = GetModelPtr();
if (pHdr == NULL)
return;
int iPoseParam = LookupPoseParameter(pHdr, szName);
SetPoseParameter(pHdr, iPoseParam, fValue);
}
void C_BaseAnimating::GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out )
{

View File

@ -95,6 +95,7 @@ public:
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
DECLARE_INTERPOLATION();
DECLARE_ENT_SCRIPTDESC();
enum
{
@ -445,6 +446,7 @@ public:
virtual bool IsViewModel() const;
void ScriptSetPoseParameter(const char* szName, float fValue);
protected:
// View models scale their attachment positions to account for FOV. To get the unmodified
// attachment position (like if you're rendering something else during the view model's DrawModel call),

View File

@ -44,6 +44,8 @@
#include "viewrender.h"
#endif
#include "gamestringpool.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -423,6 +425,42 @@ BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_AnimTimeMustBeFirst )
RecvPropInt( RECVINFO(m_flAnimTime), 0, RecvProxy_AnimTime ),
END_RECV_TABLE()
BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities" )
DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" )
DEFINE_SCRIPTFUNC( GetTeamNumber, "Gets this entity's team" )
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC( GetHealth, "" )
DEFINE_SCRIPTFUNC( GetMaxHealth, "" )
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( GetEntityName, "GetName", "" )
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" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector" )
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( 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( GetEffects, "Get effects" )
DEFINE_SCRIPTFUNC( IsEffectActive, "Check if an effect is active" )
#endif
END_SCRIPTDESC();
#ifndef NO_ENTITY_PREDICTION
BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_PredictableId )
@ -466,6 +504,8 @@ BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity)
RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ),
RecvPropInt( RECVINFO( m_iParentAttachment ) ),
RecvPropString(RECVINFO(m_iName)),
RecvPropInt( "movetype", 0, SIZEOF_IGNORE, 0, RecvProxy_MoveType ),
RecvPropInt( "movecollide", 0, SIZEOF_IGNORE, 0, RecvProxy_MoveCollide ),
RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
@ -1095,6 +1135,8 @@ bool C_BaseEntity::Init( int entnum, int iSerialNum )
m_nCreationTick = gpGlobals->tickcount;
m_hScriptInstance = NULL;
return true;
}
@ -1165,6 +1207,7 @@ void C_BaseEntity::Term()
g_Predictables.RemoveFromPredictablesList( GetClientHandle() );
}
// If it's play simulated, remove from simulation list if the player still exists...
if ( IsPlayerSimulated() && C_BasePlayer::GetLocalPlayer() )
{
@ -1201,6 +1244,12 @@ void C_BaseEntity::Term()
RemoveFromLeafSystem();
RemoveFromAimEntsList();
if ( m_hScriptInstance )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
}
@ -6442,6 +6491,55 @@ int C_BaseEntity::GetCreationTick() const
return m_nCreationTick;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::GetScriptInstance()
{
if (!m_hScriptInstance)
{
if (m_iszScriptId == NULL_STRING)
{
char* szName = (char*)stackalloc(1024);
g_pScriptVM->GenerateUniqueKey((m_iName != 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;
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::ScriptGetMoveParent( void )
{
return ToHScript( GetMoveParent() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::ScriptGetRootMoveParent()
{
return ToHScript( GetRootMoveParent() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::ScriptFirstMoveChild( void )
{
return ToHScript( FirstMoveChild() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT C_BaseEntity::ScriptNextMovePeer( void )
{
return ToHScript( NextMovePeer() );
}
#endif
//------------------------------------------------------------------------------
void CC_CL_Find_Ent( const CCommand& args )
{

View File

@ -36,6 +36,9 @@
#include "toolframework/itoolentity.h"
#include "tier0/threadtools.h"
#include "vscript/ivscript.h"
#include "vscript_shared.h"
class C_Team;
class IPhysicsObject;
class IClientVehicle;
@ -183,6 +186,8 @@ public:
DECLARE_DATADESC();
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
// script description
DECLARE_ENT_SCRIPTDESC();
C_BaseEntity();
virtual ~C_BaseEntity();
@ -256,6 +261,11 @@ public:
string_t m_iClassname;
HSCRIPT GetScriptInstance();
HSCRIPT m_hScriptInstance;
string_t m_iszScriptId;
// IClientUnknown overrides.
public:
@ -1119,6 +1129,30 @@ public:
virtual int GetBody() { return 0; }
virtual int GetSkin() { return 0; }
const Vector& ScriptGetForward(void) { static Vector vecForward; GetVectors(&vecForward, NULL, NULL); return vecForward; }
const Vector& ScriptGetLeft(void) { static Vector vecLeft; GetVectors(NULL, &vecLeft, NULL); return vecLeft; }
const Vector& ScriptGetUp(void) { static Vector vecUp; GetVectors(NULL, NULL, &vecUp); return vecUp; }
#ifdef MAPBASE_VSCRIPT
const char* ScriptGetModelName( void ) const { return STRING(GetModelName()); }
void ScriptEmitSound(const char* soundname);
float ScriptSoundDuration(const char* soundname, const char* actormodel);
void VScriptPrecacheScriptSound(const char* soundname);
const Vector& ScriptEyePosition(void) { static Vector vec; vec = EyePosition(); return vec; }
const Vector& ScriptGetAngles(void) { static Vector vec; QAngle qa = GetAbsAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; }
const Vector& ScriptGetBoundingMins( void ) { return m_Collision.OBBMins(); }
const Vector& ScriptGetBoundingMaxs( void ) { return m_Collision.OBBMaxs(); }
HSCRIPT ScriptGetMoveParent( void );
HSCRIPT ScriptGetRootMoveParent();
HSCRIPT ScriptFirstMoveChild( void );
HSCRIPT ScriptNextMovePeer( void );
#endif
// Stubs on client
void NetworkStateManualMode( bool activate ) { }
void NetworkStateChanged() { }
@ -1266,6 +1300,7 @@ public:
void SetRenderMode( RenderMode_t nRenderMode, bool bForceUpdate = false );
RenderMode_t GetRenderMode() const;
const char* GetEntityName();
public:
// Determine what entity this corresponds to
@ -1648,6 +1683,8 @@ private:
// The owner!
EHANDLE m_hOwnerEntity;
EHANDLE m_hEffectEntity;
char m_iName[MAX_PATH];
// This is a random seed used by the networking code to allow client - side prediction code
// randon number generators to spit out the same random numbers on both sides for a particular
@ -2203,6 +2240,12 @@ inline bool C_BaseEntity::ShouldRecordInTools() const
#endif
}
inline const char *C_BaseEntity::GetEntityName()
{
return m_iName;
}
C_BaseEntity *CreateEntityByName( const char *className );
#endif // C_BASEENTITY_H

View File

@ -1480,7 +1480,7 @@ bool C_BaseFlex::ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool can
// expression -
// duration -
//-----------------------------------------------------------------------------
void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget, bool bClientSide )
void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget, bool bClientSide, C_SceneEntity* pSceneEntity)
{
if ( !scene || !event )
{
@ -1505,6 +1505,7 @@ void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseE
info.m_hTarget = pTarget;
info.m_bStarted = false;
info.m_bClientSide = bClientSide;
info.m_hSceneEntity = pSceneEntity;
if (StartSceneEvent( &info, scene, event, actor, pTarget ))
{

View File

@ -214,7 +214,7 @@ public:
virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled );
// Add the event to the queue for this actor
void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false );
void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false, C_SceneEntity* pSceneEntity = NULL);
// Remove the event from the queue for this actor
void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill );

View File

@ -480,6 +480,13 @@ C_BasePlayer::~C_BasePlayer()
s_pLocalPlayer = NULL;
}
#ifdef MAPBASE_VSCRIPT
if ( IsLocalPlayer() && g_pScriptVM )
{
g_pScriptVM->SetValue( "player", SCRIPT_VARIANT_NULL );
}
#endif
delete m_pFlashlight;
}
@ -974,6 +981,16 @@ void C_BasePlayer::OnRestore()
input->ClearInputButton( IN_ATTACK | IN_ATTACK2 );
// GetButtonBits() has to be called for the above to take effect
input->GetButtonBits( 0 );
#ifdef MAPBASE_VSCRIPT
// HACK: (03/25/09) Then the player goes across a transition it doesn't spawn and register
// it's instance. We're hacking around this for now, but this will go away when we get around to
// having entities cross transitions and keep their script state.
if ( g_pScriptVM )
{
g_pScriptVM->SetValue( "player", GetScriptInstance() );
}
#endif
}
// For ammo history icons to current value so they don't flash on level transtions

View File

@ -674,7 +674,7 @@ void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor,
es.m_pSoundName = event->GetParameters();
EmitSound( filter, actor->entindex(), es );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
// Close captioning only on master token no matter what...
if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
@ -964,7 +964,7 @@ void C_SceneEntity::UnloadScene( void )
//-----------------------------------------------------------------------------
void C_SceneEntity::DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
{
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -984,7 +984,7 @@ void C_SceneEntity::DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *a
//-----------------------------------------------------------------------------
void C_SceneEntity::DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
{
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -1008,7 +1008,7 @@ void C_SceneEntity::DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor
if ( !Q_stricmp( event->GetName(), "NULL" ) )
return;
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -1023,7 +1023,7 @@ void C_SceneEntity::DispatchProcessGesture( CChoreoScene *scene, C_BaseFlex *act
return;
actor->RemoveSceneEvent( scene, event, false );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -1046,7 +1046,7 @@ void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor,
//-----------------------------------------------------------------------------
void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
{
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------
@ -1056,7 +1056,7 @@ void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor
void C_SceneEntity::DispatchProcessSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
{
actor->RemoveSceneEvent( scene, event, false );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
}
//-----------------------------------------------------------------------------

View File

@ -62,6 +62,9 @@ BEGIN_RECV_TABLE( C_World, DT_World )
#ifdef MAPBASE
RecvPropString(RECVINFO(m_iszChapterTitle)),
#endif
#ifdef MAPBASE_VSCRIPT
RecvPropInt(RECVINFO(m_iScriptLanguage)),
#endif
END_RECV_TABLE()

View File

@ -41,6 +41,10 @@ public:
float GetWaveHeight() const;
const char *GetDetailSpriteMaterial() const;
#ifdef MAPBASE_VSCRIPT
ScriptLanguage_t GetScriptLanguage() { return (ScriptLanguage_t)m_iScriptLanguage; }
#endif
public:
enum
{
@ -59,6 +63,9 @@ public:
#ifdef MAPBASE
char m_iszChapterTitle[64];
#endif
#ifdef MAPBASE_VSCRIPT
int m_iScriptLanguage;
#endif
private:
void RegisterSharedActivities( void );

View File

@ -223,6 +223,8 @@ IReplaySystem *g_pReplay = NULL;
IVEngineServer *serverengine = NULL;
#endif
IScriptManager *scriptmanager = NULL;
IHaptics* haptics = NULL;// NVNT haptics system interface singleton
//=============================================================================
@ -964,6 +966,16 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi
if (!g_pMatSystemSurface)
return false;
if ( !CommandLine()->CheckParm( "-noscripting") )
{
scriptmanager = (IScriptManager *)appSystemFactory( VSCRIPT_INTERFACE_VERSION, NULL );
if (scriptmanager == nullptr)
{
scriptmanager = (IScriptManager*)Sys_GetFactoryThis()(VSCRIPT_INTERFACE_VERSION, NULL);
}
}
#ifdef WORKSHOP_IMPORT_ENABLED
if ( !ConnectDataModel( appSystemFactory ) )
return false;

View File

@ -493,6 +493,11 @@ $Project
$File "viewrender.cpp"
$File "$SRCDIR\game\shared\voice_banmgr.cpp"
$File "$SRCDIR\game\shared\voice_status.cpp"
$File "vscript_client.cpp"
$File "vscript_client.h"
$File "vscript_client.nut"
$File "$SRCDIR\game\shared\vscript_shared.cpp"
$File "$SRCDIR\game\shared\vscript_shared.h"
$File "warp_overlay.cpp"
$File "WaterLODMaterialProxy.cpp"
$File "$SRCDIR\game\shared\weapon_parse.cpp"

View File

@ -31,6 +31,9 @@ $Project
$File "$SRCDIR\game\shared\mapbase\MapEdit.h"
$File "$SRCDIR\game\shared\mapbase\matchers.cpp"
$File "$SRCDIR\game\shared\mapbase\matchers.h"
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_math.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_hl2.cpp" [$MAPBASE_VSCRIPT]
$File "mapbase\c_func_clientclip.cpp"
}
@ -51,4 +54,9 @@ $Project
}
}
}
$Folder "Link Libraries"
{
$Lib "vscript" [$MAPBASE_VSCRIPT]
}
}

View File

@ -0,0 +1,592 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "vscript_client.h"
#include "icommandline.h"
#include "tier1/utlbuffer.h"
#include "tier1/fmtstr.h"
#include "filesystem.h"
#include "characterset.h"
#include "isaverestore.h"
#include "gamerules.h"
#include "vscript_client.nut"
#ifdef MAPBASE_VSCRIPT
#include "mapbase/matchers.h"
#include "c_world.h"
#include "proxyentity.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imaterialvar.h"
#endif
extern IScriptManager *scriptmanager;
extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
// #define VMPROFILE 1
#ifdef VMPROFILE
#define VMPROF_START float debugStartTime = Plat_FloatTime();
#define VMPROF_SHOW( funcname, funcdesc ) DevMsg("***VSCRIPT PROFILE***: %s %s: %6.4f milliseconds\n", (##funcname), (##funcdesc), (Plat_FloatTime() - debugStartTime)*1000.0 );
#else // !VMPROFILE
#define VMPROF_START
#define VMPROF_SHOW
#endif // VMPROFILE
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
// Purpose: A clientside variant of CScriptEntityIterator.
//-----------------------------------------------------------------------------
class CScriptClientEntityIterator
{
public:
HSCRIPT First() { return Next(NULL); }
HSCRIPT Next( HSCRIPT hStartEntity )
{
return ToHScript( ClientEntityList().NextBaseEntity( ToEnt( hStartEntity ) ) );
}
HSCRIPT CreateByClassname( const char *className )
{
return ToHScript( CreateEntityByName( className ) );
}
HSCRIPT FindByClassname( HSCRIPT hStartEntity, const char *szName )
{
const CEntInfo *pInfo = hStartEntity ? ClientEntityList().GetEntInfoPtr( ToEnt( hStartEntity )->GetRefEHandle() )->m_pNext : ClientEntityList().FirstEntInfo();
for ( ;pInfo; pInfo = pInfo->m_pNext )
{
C_BaseEntity *ent = (C_BaseEntity *)pInfo->m_pEntity;
if ( !ent )
continue;
if ( Matcher_Match( szName, ent->GetClassname() ) )
return ToHScript( ent );
}
return NULL;
}
HSCRIPT FindByName( HSCRIPT hStartEntity, const char *szName )
{
const CEntInfo *pInfo = hStartEntity ? ClientEntityList().GetEntInfoPtr( ToEnt( hStartEntity )->GetRefEHandle() )->m_pNext : ClientEntityList().FirstEntInfo();
for ( ;pInfo; pInfo = pInfo->m_pNext )
{
C_BaseEntity *ent = (C_BaseEntity *)pInfo->m_pEntity;
if ( !ent )
continue;
if ( Matcher_Match( szName, ent->GetEntityName() ) )
return ToHScript( ent );
}
return NULL;
}
private:
} g_ScriptEntityIterator;
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptClientEntityIterator, "CEntities", SCRIPT_SINGLETON "The global list of entities" )
DEFINE_SCRIPTFUNC( First, "Begin an iteration over the list of entities" )
DEFINE_SCRIPTFUNC( Next, "Continue an iteration over the list of entities, providing reference to a previously found entity" )
DEFINE_SCRIPTFUNC( CreateByClassname, "Creates an entity by classname" )
DEFINE_SCRIPTFUNC( FindByClassname, "Find entities by class name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByName, "Find entities by name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
END_SCRIPTDESC();
//-----------------------------------------------------------------------------
// Purpose: A base class for VScript-utilizing clientside classes which can persist
// across levels, requiring their scripts to be shut down manually.
//-----------------------------------------------------------------------------
abstract_class IClientScriptPersistable
{
public:
virtual void TermScript() = 0;
};
CUtlVector<IClientScriptPersistable*> g_ScriptPersistableList;
#define SCRIPT_MAT_PROXY_MAX_VARS 8
//-----------------------------------------------------------------------------
// Purpose: A material proxy which runs a VScript and allows it to read/write
// to material variables.
//-----------------------------------------------------------------------------
class CScriptMaterialProxy : public IMaterialProxy, public IClientScriptPersistable
{
public:
CScriptMaterialProxy();
virtual ~CScriptMaterialProxy();
virtual void Release( void );
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
virtual void OnBind( void *pRenderable );
virtual IMaterial *GetMaterial() { return NULL; }
// Proxies can persist across levels and aren't bound to a loaded map.
// The VM, however, is bound to the loaded map, so the proxy's script variables persisting
// causes problems when they're used in a new level with a new VM.
// As a result, we call InitScript() and TermScript() during OnBind and when the level is unloaded respectively.
bool InitScript();
void TermScript();
bool ValidateIndex(int i)
{
if (i > SCRIPT_MAT_PROXY_MAX_VARS || i < 0)
{
Warning("VScriptProxy: %i out of range", i);
return false;
}
return true;
}
const char *GetVarString( int i );
int GetVarInt( int i );
float GetVarFloat( int i );
const Vector& GetVarVector( int i );
void SetVarString( int i, const char *value );
void SetVarInt( int i, int value );
void SetVarFloat( int i, float value );
void SetVarVector( int i, const Vector &value );
private:
IMaterialVar *m_MaterialVars[SCRIPT_MAT_PROXY_MAX_VARS];
// Save the keyvalue string for InitScript()
char m_szFilePath[MAX_PATH];
CScriptScope m_ScriptScope;
HSCRIPT m_hScriptInstance;
HSCRIPT m_hFuncOnBind;
};
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptMaterialProxy, "CScriptMaterialProxy", "Material proxy for VScript" )
DEFINE_SCRIPTFUNC( GetVarString, "Gets a material var's string value" )
DEFINE_SCRIPTFUNC( GetVarInt, "Gets a material var's int value" )
DEFINE_SCRIPTFUNC( GetVarFloat, "Gets a material var's float value" )
DEFINE_SCRIPTFUNC( GetVarVector, "Gets a material var's vector value" )
DEFINE_SCRIPTFUNC( SetVarString, "Sets a material var's string value" )
DEFINE_SCRIPTFUNC( SetVarInt, "Sets a material var's int value" )
DEFINE_SCRIPTFUNC( SetVarFloat, "Sets a material var's float value" )
DEFINE_SCRIPTFUNC( SetVarVector, "Sets a material var's vector value" )
END_SCRIPTDESC();
CScriptMaterialProxy::CScriptMaterialProxy()
{
m_hScriptInstance = NULL;
m_hFuncOnBind = NULL;
}
CScriptMaterialProxy::~CScriptMaterialProxy()
{
}
//-----------------------------------------------------------------------------
// Cleanup
//-----------------------------------------------------------------------------
void CScriptMaterialProxy::Release( void )
{
if ( m_hScriptInstance && g_pScriptVM )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
delete this;
}
bool CScriptMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
{
for (KeyValues *pKey = pKeyValues->GetFirstSubKey(); pKey != NULL; pKey = pKey->GetNextKey())
{
// Get each variable we're looking for
if (Q_strnicmp( pKey->GetName(), "var", 3 ) == 0)
{
int index = atoi(pKey->GetName() + 3);
if (index > SCRIPT_MAT_PROXY_MAX_VARS)
{
Warning("VScript material proxy only supports 8 vars (not %i)\n", index);
continue;
}
bool foundVar;
m_MaterialVars[index] = pMaterial->FindVar( pKey->GetString(), &foundVar );
// Don't init if we didn't find the var
if (!foundVar)
return false;
}
else if (FStrEq( pKey->GetName(), "scriptfile" ))
{
Q_strncpy( m_szFilePath, pKey->GetString(), sizeof( m_szFilePath ) );
}
}
return true;
}
bool CScriptMaterialProxy::InitScript()
{
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;
}
char* iszScriptId = (char*)stackalloc( 1024 );
g_pScriptVM->GenerateUniqueKey("VScriptProxy", iszScriptId, 1024);
m_hScriptInstance = g_pScriptVM->RegisterInstance( GetScriptDescForClass( CScriptMaterialProxy ), this );
g_pScriptVM->SetInstanceUniqeId( m_hScriptInstance, iszScriptId );
bool bResult = m_ScriptScope.Init( iszScriptId );
if (!bResult)
{
DevMsg("VScriptProxy couldn't create ScriptScope!\n");
return false;
}
g_pScriptVM->SetValue( m_ScriptScope, "self", m_hScriptInstance );
}
// Don't init if we can't run the script
if (!VScriptRunScript( m_szFilePath, m_ScriptScope, true ))
return false;
m_hFuncOnBind = m_ScriptScope.LookupFunction( "OnBind" );
if (!m_hFuncOnBind)
{
// Don't init if we can't find our func
Warning("VScript material proxy can't find OnBind function\n");
return false;
}
g_ScriptPersistableList.AddToTail( this );
return true;
}
void CScriptMaterialProxy::TermScript()
{
if ( m_hScriptInstance )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
m_hFuncOnBind = NULL;
m_ScriptScope.Term();
}
void CScriptMaterialProxy::OnBind( void *pRenderable )
{
if( !pRenderable )
return;
if (m_hFuncOnBind != NULL)
{
IClientRenderable *pRend = ( IClientRenderable* )pRenderable;
C_BaseEntity *pEnt = pRend->GetIClientUnknown()->GetBaseEntity();
if ( pEnt )
{
g_pScriptVM->SetValue( m_ScriptScope, "entity", pEnt->GetScriptInstance() );
}
else
{
// Needs to register as a null value so the script doesn't break if it looks for an entity
g_pScriptVM->SetValue( m_ScriptScope, "entity", SCRIPT_VARIANT_NULL );
}
m_ScriptScope.Call( m_hFuncOnBind, NULL );
g_pScriptVM->ClearValue( m_ScriptScope, "entity" );
}
else
{
// The VM might not exist if we do it from Init(), so we have to do it here.
// TODO: We have no handling for if this fails, how do you cancel a proxy?
if (InitScript())
OnBind( pRenderable );
}
}
const char *CScriptMaterialProxy::GetVarString( int i )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return NULL;
return m_MaterialVars[i]->GetStringValue();
}
int CScriptMaterialProxy::GetVarInt( int i )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return 0;
return m_MaterialVars[i]->GetIntValue();
}
float CScriptMaterialProxy::GetVarFloat( int i )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return 0.0f;
return m_MaterialVars[i]->GetFloatValue();
}
const Vector& CScriptMaterialProxy::GetVarVector( int i )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return vec3_origin;
if (m_MaterialVars[i]->GetType() != MATERIAL_VAR_TYPE_VECTOR)
return vec3_origin;
// This is really bad. Too bad!
return *(reinterpret_cast<const Vector*>(m_MaterialVars[i]->GetVecValue()));
}
void CScriptMaterialProxy::SetVarString( int i, const char *value )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return;
return m_MaterialVars[i]->SetStringValue( value );
}
void CScriptMaterialProxy::SetVarInt( int i, int value )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return;
return m_MaterialVars[i]->SetIntValue( value );
}
void CScriptMaterialProxy::SetVarFloat( int i, float value )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return;
return m_MaterialVars[i]->SetFloatValue( value );
}
void CScriptMaterialProxy::SetVarVector( int i, const Vector &value )
{
if (!ValidateIndex( i ) || !m_MaterialVars[i])
return;
return m_MaterialVars[i]->SetVecValue( value.Base(), 3 );
}
EXPOSE_INTERFACE( CScriptMaterialProxy, IMaterialProxy, "VScriptProxy" IMATERIAL_PROXY_INTERFACE_VERSION );
#endif
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static float Time()
{
return gpGlobals->curtime;
}
static const char *GetMapName()
{
return engine->GetLevelName();
}
static const char *DoUniqueString( const char *pszBase )
{
static char szBuf[512];
g_pScriptVM->GenerateUniqueKey( pszBase, szBuf, ARRAYSIZE(szBuf) );
return szBuf;
}
bool DoIncludeScript( const char *pszScript, HSCRIPT hScope )
{
if ( !VScriptRunScript( pszScript, hScope, true ) )
{
g_pScriptVM->RaiseException( CFmtStr( "Failed to include script \"%s\"", ( pszScript ) ? pszScript : "unknown" ) );
return false;
}
return true;
}
bool VScriptClientInit()
{
VMPROF_START
if( scriptmanager != NULL )
{
ScriptLanguage_t scriptLanguage = SL_DEFAULT;
char const *pszScriptLanguage;
#ifdef MAPBASE_VSCRIPT
if (GetClientWorldEntity()->GetScriptLanguage() != SL_NONE)
{
// Allow world entity to override script language
scriptLanguage = GetClientWorldEntity()->GetScriptLanguage();
}
else
#endif
if ( CommandLine()->CheckParm( "-scriptlang", &pszScriptLanguage ) )
{
if( !Q_stricmp(pszScriptLanguage, "gamemonkey") )
{
scriptLanguage = SL_GAMEMONKEY;
}
else if( !Q_stricmp(pszScriptLanguage, "squirrel") )
{
scriptLanguage = SL_SQUIRREL;
}
else if( !Q_stricmp(pszScriptLanguage, "python") )
{
scriptLanguage = SL_PYTHON;
}
else
{
DevWarning("-scriptlang does not recognize a language named '%s'. virtual machine did NOT start.\n", pszScriptLanguage );
scriptLanguage = SL_NONE;
}
}
if( scriptLanguage != SL_NONE )
{
if ( g_pScriptVM == NULL )
g_pScriptVM = scriptmanager->CreateVM( scriptLanguage );
if( g_pScriptVM )
{
Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() );
ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map.");
ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" );
ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" );
if ( GameRules() )
{
GameRules()->RegisterScriptFunctions();
}
#ifdef MAPBASE_VSCRIPT
g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" );
IGameSystem::RegisterVScriptAllSystems();
RegisterSharedScriptFunctions();
#else
//g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" );
#endif
if (scriptLanguage == SL_SQUIRREL)
{
g_pScriptVM->Run( g_Script_vscript_client );
}
VScriptRunScript( "mapspawn", false );
VMPROF_SHOW( pszScriptLanguage, "virtual machine startup" );
return true;
}
else
{
DevWarning("VM Did not start!\n");
}
}
}
else
{
Log( "\nVSCRIPT: Scripting is disabled.\n" );
}
g_pScriptVM = NULL;
return false;
}
void VScriptClientTerm()
{
if( g_pScriptVM != NULL )
{
#ifdef MAPBASE_VSCRIPT
// Things like proxies can persist across levels, so we have to shut down their scripts manually
for (int i = g_ScriptPersistableList.Count()-1; i >= 0; i--)
{
if (g_ScriptPersistableList[i])
{
g_ScriptPersistableList[i]->TermScript();
g_ScriptPersistableList.FastRemove( i );
}
}
#endif
if( g_pScriptVM )
{
scriptmanager->DestroyVM( g_pScriptVM );
g_pScriptVM = NULL;
}
}
}
class CVScriptGameSystem : public CAutoGameSystemPerFrame
{
public:
// Inherited from IAutoServerSystem
virtual void LevelInitPreEntity( void )
{
m_bAllowEntityCreationInScripts = true;
VScriptClientInit();
}
virtual void LevelInitPostEntity( void )
{
m_bAllowEntityCreationInScripts = false;
#ifdef MAPBASE_VSCRIPT
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if (pPlayer)
{
g_pScriptVM->SetValue( "player", pPlayer->GetScriptInstance() );
}
#endif
}
virtual void LevelShutdownPostEntity( void )
{
VScriptClientTerm();
}
virtual void FrameUpdatePostEntityThink()
{
if ( g_pScriptVM )
g_pScriptVM->Frame( gpGlobals->frametime );
}
bool m_bAllowEntityCreationInScripts;
};
CVScriptGameSystem g_VScriptGameSystem;
bool IsEntityCreationAllowedInScripts( void )
{
return g_VScriptGameSystem.m_bAllowEntityCreationInScripts;
}

View File

@ -0,0 +1,22 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#ifndef VSCRIPT_SERVER_H
#define VSCRIPT_SERVER_H
#include "vscript/ivscript.h"
#include "vscript_shared.h"
#if defined( _WIN32 )
#pragma once
#endif
extern IScriptVM * g_pScriptVM;
// Only allow scripts to create entities during map initialization
bool IsEntityCreationAllowedInScripts( void );
#endif // VSCRIPT_SERVER_H

View File

@ -0,0 +1,22 @@
static char g_Script_vscript_client[] = R"vscript(
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
function UniqueString( string = "" )
{
return DoUniqueString( string.tostring() );
}
function IncludeScript( name, scope = null )
{
if ( scope == null )
{
scope = this;
}
return ::DoIncludeScript( name, scope );
}
)vscript";

View File

@ -98,6 +98,15 @@ BEGIN_DATADESC( CAI_BaseActor )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CAI_BaseActor, CAI_BaseNPC, "The base class for NPCs which act in complex choreo scenes." )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddLookTarget, "AddLookTarget", "Add a potential look target for this actor." )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddLookTargetPos, "AddLookTargetPos", "Add a potential look target position for this actor." )
END_SCRIPTDESC();
#endif
BEGIN_SIMPLE_DATADESC( CAI_InterestTarget_t )
DEFINE_FIELD( m_eType, FIELD_INTEGER ),

View File

@ -170,6 +170,15 @@ public:
void ClearExpression();
const char * GetExpression();
#ifdef MAPBASE_VSCRIPT
//---------------------------------
void ScriptAddLookTarget( HSCRIPT pTarget, float flImportance, float flDuration, float flRamp = 0.0 ) { AddLookTarget(ToEnt(pTarget), flImportance, flDuration, flRamp); }
void ScriptAddLookTargetPos( const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 ) { AddLookTarget(vecPosition, flImportance, flDuration, flRamp); }
//---------------------------------
#endif
enum
{
SCENE_AI_BLINK = 1,
@ -190,6 +199,9 @@ public:
DECLARE_DATADESC();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
private:
enum
{

View File

@ -689,6 +689,131 @@ void CAI_BaseNPC::InputSetFriendlyFire( inputdata_t &inputdata )
}
#endif
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptGetEnemy()
{
return ToHScript( GetEnemy() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_BaseNPC::VScriptSetEnemy( HSCRIPT pEnemy )
{
SetEnemy( ToEnt( pEnemy ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
Vector CAI_BaseNPC::VScriptGetEnemyLKP()
{
return GetEnemyLKP();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptFindEnemyMemory( HSCRIPT pEnemy )
{
HSCRIPT hScript = NULL;
AI_EnemyInfo_t *info = GetEnemies()->Find( ToEnt(pEnemy) );
if (info)
{
hScript = g_pScriptVM->RegisterInstance( info );
}
return hScript;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CAI_BaseNPC::VScriptGetState()
{
return (int)GetState();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptGetHintNode()
{
return ToHScript( GetHintNode() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char *CAI_BaseNPC::VScriptGetSchedule()
{
const char *pName = NULL;
pName = GetCurSchedule()->GetName();
if (!pName)
pName = "Unknown";
return pName;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CAI_BaseNPC::VScriptGetScheduleID()
{
int iSched = GetCurSchedule()->GetId();
// Local IDs are needed to correspond with user-friendly enums
if ( AI_IdIsGlobal( iSched ) )
{
iSched = GetClassScheduleIdSpace()->ScheduleGlobalToLocal(iSched);
}
return iSched;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_BaseNPC::VScriptSetSchedule( const char *szSchedule )
{
SetSchedule( GetScheduleID( szSchedule ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char *CAI_BaseNPC::VScriptGetTask()
{
const Task_t *pTask = GetTask();
const char *pName = NULL;
if (pTask)
pName = TaskName( pTask->iTask );
else
pName = "None";
return pName;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CAI_BaseNPC::VScriptGetTaskID()
{
const Task_t *pTask = GetTask();
int iID = -1;
if (pTask)
iID = GetTaskID( TaskName( pTask->iTask ) );
return iID;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CAI_BaseNPC::VScriptGetExpresser()
{
HSCRIPT hScript = NULL;
CAI_Expresser *pExpresser = GetExpresser();
if (pExpresser)
{
hScript = g_pScriptVM->RegisterInstance( pExpresser );
}
return hScript;
}
#endif
bool CAI_BaseNPC::PassesDamageFilter( const CTakeDamageInfo &info )
{
if ( ai_block_damage.GetBool() )
@ -6403,6 +6528,34 @@ Activity CAI_BaseNPC::NPC_TranslateActivity( Activity eNewActivity )
break;
}
}
#ifdef MAPBASE_VSCRIPT
if ( m_ScriptScope.IsInitialized() )
{
g_pScriptVM->SetValue( "activity", GetActivityName(eNewActivity) );
g_pScriptVM->SetValue( "activity_id", (int)eNewActivity );
ScriptVariant_t functionReturn;
if( CallScriptFunction( "NPC_TranslateActivity", &functionReturn ) )
{
if (functionReturn.m_type == FIELD_INTEGER)
{
Activity activity = (Activity)functionReturn.m_int;
if (activity != ACT_INVALID)
eNewActivity = (Activity)functionReturn.m_int;
}
else
{
Activity activity = (Activity)GetActivityID( functionReturn.m_pszString );
if (activity != ACT_INVALID)
eNewActivity = activity;
}
}
g_pScriptVM->ClearValue( "activity" );
g_pScriptVM->ClearValue( "activity_id" );
}
#endif
#else
Assert( eNewActivity != ACT_INVALID );
@ -11758,6 +11911,56 @@ BEGIN_DATADESC( CAI_BaseNPC )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPCs derive from." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetEnemy, "GetEnemy", "Get the NPC's current enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetEnemy, "SetEnemy", "Set the NPC's current enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetEnemyLKP, "GetEnemyLKP", "Get the last known position of the NPC's current enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptFindEnemyMemory, "FindEnemyMemory", "Get information about the NPC's current enemy." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetState, "GetNPCState", "Get the NPC's current state." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetHintGroup, "GetHintGroup", "Get the name of the NPC's hint group." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetHintNode, "GetHintNode", "Get the NPC's current AI hint." )
DEFINE_SCRIPTFUNC( CapabilitiesGet, "Get the capabilities the NPC currently possesses." )
DEFINE_SCRIPTFUNC( CapabilitiesAdd, "Add capabilities to the NPC." )
DEFINE_SCRIPTFUNC( CapabilitiesRemove, "Remove capabilities from the NPC." )
DEFINE_SCRIPTFUNC( CapabilitiesClear, "Clear capabilities for the NPC." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetActivity, "GetActivity", "Get the NPC's current activity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetActivityID, "GetActivityID", "Get the NPC's current activity ID." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetActivity, "SetActivity", "Set the NPC's current activity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetActivityID, "SetActivityID", "Set the NPC's current activity ID." )
DEFINE_SCRIPTFUNC( ResetActivity, "Reset the NPC's current activity." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetSchedule, "GetSchedule", "Get the NPC's current schedule." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetScheduleID, "GetScheduleID", "Get the NPC's current schedule ID." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetSchedule, "SetSchedule", "Set the NPC's current schedule." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetScheduleID, "SetScheduleID", "Set the NPC's current schedule ID." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetTask, "GetTask", "Get the NPC's current task." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetTaskID, "GetTaskID", "Get the NPC's current task ID." )
DEFINE_SCRIPTFUNC( ClearSchedule, "Clear the NPC's current schedule for the specified reason." )
DEFINE_SCRIPTFUNC_NAMED( VScriptHasCondition, "HasCondition", "Get whether the NPC has a condition." )
DEFINE_SCRIPTFUNC_NAMED( VScriptHasConditionID, "HasConditionID", "Get whether the NPC has a condition ID." )
DEFINE_SCRIPTFUNC_NAMED( VScriptSetCondition, "SetCondition", "Set a condition on the NPC." )
DEFINE_SCRIPTFUNC_NAMED( SetCondition, "SetConditionID", "Set a condition on the NPC by ID." )
DEFINE_SCRIPTFUNC_NAMED( VScriptClearCondition, "ClearCondition", "Clear a condition on the NPC." )
DEFINE_SCRIPTFUNC_NAMED( ClearCondition, "ClearConditionID", "Clear a condition on the NPC by ID." )
DEFINE_SCRIPTFUNC( IsMoving, "Check if the NPC is moving." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetExpresser, "GetExpresser", "Get a handle for this NPC's expresser." )
DEFINE_SCRIPTFUNC( IsCommandable, "Check if the NPC is commandable." )
DEFINE_SCRIPTFUNC( IsInPlayerSquad, "Check if the NPC is in the player's squad." )
END_SCRIPTDESC();
#endif
BEGIN_SIMPLE_DATADESC( AIScheduleState_t )
DEFINE_FIELD( iCurTask, FIELD_INTEGER ),
DEFINE_FIELD( fTaskStatus, FIELD_INTEGER ),

View File

@ -547,6 +547,9 @@ public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
virtual int Save( ISave &save );
virtual int Restore( IRestore &restore );
@ -1207,6 +1210,40 @@ public:
virtual void AddGrenades( int inc, CBaseEntity *pLastGrenade = NULL ) { ; }
#endif
#ifdef MAPBASE_VSCRIPT
// VScript stuff uses "VScript" instead of just "Script" to avoid
// confusion with NPC_STATE_SCRIPT or StartScripting
HSCRIPT VScriptGetEnemy();
void VScriptSetEnemy( HSCRIPT pEnemy );
Vector VScriptGetEnemyLKP();
HSCRIPT VScriptFindEnemyMemory( HSCRIPT pEnemy );
int VScriptGetState();
const char* VScriptGetHintGroup() { return STRING( GetHintGroup() ); }
HSCRIPT VScriptGetHintNode();
const char* ScriptGetActivity() { return GetActivityName( GetActivity() ); }
int ScriptGetActivityID() { return GetActivity(); }
void ScriptSetActivity( const char *szActivity ) { SetActivity( (Activity)GetActivityID( szActivity ) ); }
void ScriptSetActivityID( int iActivity ) { SetActivity((Activity)iActivity); }
const char* VScriptGetSchedule();
int VScriptGetScheduleID();
void VScriptSetSchedule( const char *szSchedule );
void VScriptSetScheduleID( int iSched ) { SetSchedule( iSched ); }
const char* VScriptGetTask();
int VScriptGetTaskID();
bool VScriptHasCondition( const char *szCondition ) { return HasCondition( GetConditionID( szCondition ) ); }
bool VScriptHasConditionID( int iCondition ) { return HasCondition( iCondition ); }
void VScriptSetCondition( const char *szCondition ) { SetCondition( GetConditionID( szCondition ) ); }
void VScriptClearCondition( const char *szCondition ) { ClearCondition( GetConditionID( szCondition ) ); }
HSCRIPT VScriptGetExpresser();
#endif
//-----------------------------------------------------
// Dynamic scripted NPC interactions
//-----------------------------------------------------

View File

@ -386,6 +386,44 @@ CAI_Schedule *CAI_BaseNPC::GetScheduleOfType( int scheduleType )
scheduleType = TranslateSchedule( scheduleType );
AI_PROFILE_SCOPE_END();
#ifdef MAPBASE_VSCRIPT
if ( m_ScriptScope.IsInitialized() )
{
// Some of this code should know if there's a function first, so look
// up the function beforehand instead of using CallScriptFunction()
HSCRIPT hFunc = m_ScriptScope.LookupFunction( "NPC_TranslateSchedule" );
if (hFunc)
{
int newSchedule = scheduleType;
if ( AI_IdIsLocal( newSchedule ) )
{
newSchedule = GetClassScheduleIdSpace()->ScheduleLocalToGlobal(newSchedule);
}
g_pScriptVM->SetValue( "schedule", GetSchedulingSymbols()->ScheduleIdToSymbol( newSchedule ) );
g_pScriptVM->SetValue( "schedule_id", scheduleType ); // Use the local ID
ScriptVariant_t functionReturn;
m_ScriptScope.Call( hFunc, &functionReturn );
if (functionReturn.m_type == FIELD_INTEGER)
{
newSchedule = functionReturn.m_int;
}
else
{
newSchedule = GetScheduleID( functionReturn.m_pszString );
}
if (newSchedule != scheduleType && newSchedule > -1)
scheduleType = newSchedule;
g_pScriptVM->ClearValue( "schedule" );
g_pScriptVM->ClearValue( "schedule_id" );
}
}
#endif
// Get a pointer to that schedule
CAI_Schedule *schedule = GetSchedule(scheduleType);

View File

@ -38,6 +38,15 @@ BEGIN_DATADESC( CAI_GoalEntity )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CAI_GoalEntity, CBaseEntity, "The base class for goal entities used to control NPC behavior." )
DEFINE_SCRIPTFUNC( IsActive, "Check if the goal entity is active." )
DEFINE_SCRIPTFUNC( NumActors, "Get the number of actors using this goal entity." )
END_SCRIPTDESC();
#endif
//-------------------------------------

View File

@ -27,6 +27,9 @@ class CAI_GoalEntity : public CBaseEntity,
public IEntityListener
{
DECLARE_CLASS( CAI_GoalEntity, CBaseEntity );
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
public:
CAI_GoalEntity()
: m_iszActor(NULL_STRING),

View File

@ -900,6 +900,23 @@ BEGIN_DATADESC( CAI_Hint )
END_DATADESC( );
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CAI_Hint, CBaseEntity, "An entity which gives contextual pointers for NPCs." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetHintType, "GetHintType", "Get the hint's type ID." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetUser, "GetUser", "Get the hint's current user." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetHintGroup, "GetHintGroup", "Get the name of the hint's group." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetHintActivity, "GetHintActivity", "Get the name of the hint activity." )
DEFINE_SCRIPTFUNC( IsDisabled, "Check if the hint is disabled." )
DEFINE_SCRIPTFUNC( IsLocked, "Check if the hint is locked." )
DEFINE_SCRIPTFUNC( GetNodeId, "Get the hint's node ID." )
DEFINE_SCRIPTFUNC( Yaw, "Get the hint's yaw." )
DEFINE_SCRIPTFUNC( GetDirection, "Get the hint's direction." )
END_SCRIPTDESC();
#endif
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------

View File

@ -312,6 +312,13 @@ public:
void NPCHandleStartNav( CAI_BaseNPC *pNPC, bool bDefaultFacing );
#endif
#ifdef MAPBASE_VSCRIPT
int ScriptGetHintType() { return (int)HintType(); }
HSCRIPT ScriptGetUser() { return ToHScript( User() ); }
const char* ScriptGetHintGroup() { return STRING( GetGroup() ); }
const char* ScriptGetHintActivity() { return STRING( HintActivityName() ); }
#endif
private:
void Spawn( void );
virtual void Activate();
@ -343,6 +350,9 @@ private:
friend class CAI_HintManager;
DECLARE_DATADESC();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
};
#define SF_ALLOW_JUMP_UP 65536

View File

@ -146,6 +146,29 @@ BEGIN_SIMPLE_DATADESC( AI_EnemyInfo_t )
// NOT SAVED nextEMemory
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
#define DEFINE_ENEMY_INFO_SCRIPTFUNCS(name, desc) \
DEFINE_SCRIPTFUNC_NAMED( Get##name, #name, "Get " desc ) \
DEFINE_SCRIPTFUNC( Set##name, "Set " desc )
BEGIN_SCRIPTDESC_ROOT( AI_EnemyInfo_t, "Accessor for information about an enemy." )
DEFINE_SCRIPTFUNC( Enemy, "Get the enemy." )
DEFINE_SCRIPTFUNC( SetEnemy, "Set the enemy." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastKnownLocation, "the enemy's last known location." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastSeenLocation, "the enemy's last seen location." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastSeen, "the last time the enemy was seen." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeFirstSeen, "the first time the enemy was seen." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReacquired, "the last time the enemy was reaquired." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeValidEnemy, "the time at which the enemy can be selected (reaction delay)." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReceivedDamageFrom, "the last time damage was received from this enemy." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeAtFirstHand, "the time at which the enemy was seen firsthand." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( DangerMemory, "the memory of danger position w/o enemy pointer." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( EludedMe, "whether the enemy is not at the last known location." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( Unforgettable, "whether the enemy is unfortgettable." )
DEFINE_ENEMY_INFO_SCRIPTFUNCS( MobbedMe, "whether the enemy was part of a mob at some point." )
END_SCRIPTDESC();
#endif
//-----------------------------------------------------------------------------
CAI_Enemies::CAI_Enemies(void)

View File

@ -45,6 +45,29 @@ struct AI_EnemyInfo_t
bool bUnforgettable;
bool bMobbedMe; // True if enemy was part of a mob at some point
#ifdef MAPBASE_VSCRIPT
// Script functions.
#define ENEMY_INFO_SCRIPT_FUNCS(type, name, var) \
type Get##name() { return var; } \
void Set##name( type v ) { var = v; }
HSCRIPT Enemy() { return ToHScript(hEnemy); }
void SetEnemy( HSCRIPT ent ) { hEnemy = ToEnt(ent); }
ENEMY_INFO_SCRIPT_FUNCS( Vector, LastKnownLocation, vLastKnownLocation );
ENEMY_INFO_SCRIPT_FUNCS( Vector, LastSeenLocation, vLastSeenLocation );
ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastSeen, timeLastSeen );
ENEMY_INFO_SCRIPT_FUNCS( float, TimeFirstSeen, timeFirstSeen );
ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastReacquired, timeLastReacquired );
ENEMY_INFO_SCRIPT_FUNCS( float, TimeValidEnemy, timeValidEnemy );
ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastReceivedDamageFrom, timeLastReceivedDamageFrom );
ENEMY_INFO_SCRIPT_FUNCS( float, TimeAtFirstHand, timeAtFirstHand );
ENEMY_INFO_SCRIPT_FUNCS( bool, DangerMemory, bDangerMemory );
ENEMY_INFO_SCRIPT_FUNCS( bool, EludedMe, bEludedMe );
ENEMY_INFO_SCRIPT_FUNCS( bool, Unforgettable, bUnforgettable );
ENEMY_INFO_SCRIPT_FUNCS( bool, MobbedMe, bMobbedMe );
#endif
DECLARE_SIMPLE_DATADESC();
};

View File

@ -16,6 +16,9 @@
#include "ai_navigator.h"
#include "world.h"
#include "ai_moveprobe.h"
#ifdef MAPBASE_VSCRIPT
#include "ai_hint.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -31,6 +34,53 @@ extern float MOVE_HEIGHT_EPSILON;
// later point we will probabaly have multiple AINetworkds per level
CAI_Network* g_pBigAINet;
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CAI_Network, SCRIPT_SINGLETON "The global list of AI nodes." )
DEFINE_SCRIPTFUNC( NumNodes, "Number of nodes in the level" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetNodePosition, "GetNodePosition", "Get position of node using a generic human hull" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetNodePositionWithHull, "GetNodePositionWithHull", "Get position of node using the specified hull" )
DEFINE_SCRIPTFUNC( GetNodeYaw, "Get yaw of node" )
DEFINE_SCRIPTFUNC_NAMED( ScriptNearestNodeToPoint, "NearestNodeToPoint", "Get ID of nearest node" )
DEFINE_SCRIPTFUNC_NAMED( ScriptNearestNodeToPointWithNPC, "NearestNodeToPointForNPC", "Get ID of nearest node using the specified NPC's properties" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetNodeType, "GetNodeType", "Get a node's type" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetNodeHint, "GetNodeHint", "Get a node's hint" )
END_SCRIPTDESC();
HSCRIPT CAI_Network::ScriptGetNodeHint( int nodeID )
{
CAI_Node *pNode = GetNode( nodeID );
if (!pNode)
return NULL;
return ToHScript( pNode->GetHint() );
}
int CAI_Network::ScriptGetNodeType( int nodeID )
{
CAI_Node *pNode = GetNode( nodeID );
if (!pNode)
return NULL;
return (int)pNode->GetType();
}
int CAI_Network::ScriptNearestNodeToPointWithNPC( HSCRIPT hNPC, const Vector &vecPosition, bool bCheckVisibility )
{
CBaseEntity *pEnt = ToEnt( hNPC );
if (!pEnt || !pEnt->MyNPCPointer())
{
Warning("vscript: NearestNodeToPointWithNPC - Invalid NPC\n");
return NO_NODE;
}
return NearestNodeToPoint( pEnt->MyNPCPointer(), vecPosition, bCheckVisibility );
}
#endif
//-----------------------------------------------------------------------------
abstract_class INodeListFilter

View File

@ -127,6 +127,17 @@ public:
}
CAI_Node** AccessNodes() const { return m_pAInode; }
#ifdef MAPBASE_VSCRIPT
Vector ScriptGetNodePosition( int nodeID ) { return GetNodePosition( HULL_HUMAN, nodeID ); }
Vector ScriptGetNodePositionWithHull( int nodeID, int hull ) { return GetNodePosition( (Hull_t)hull, nodeID ); }
int ScriptNearestNodeToPoint( const Vector &vecPosition, bool bCheckVisibility = true ) { return NearestNodeToPoint( NULL, vecPosition, bCheckVisibility ); }
int ScriptNearestNodeToPointWithNPC( HSCRIPT hNPC, const Vector &vecPosition, bool bCheckVisibility = true );
HSCRIPT ScriptGetNodeHint( int nodeID );
int ScriptGetNodeType( int nodeID );
#endif
private:
friend class CAI_NetworkManager;

View File

@ -948,6 +948,13 @@ void CAI_NetworkManager::InitializeAINetworks()
}
}
#ifdef MAPBASE_VSCRIPT
if (g_pScriptVM)
{
g_pScriptVM->RegisterInstance( g_pBigAINet, "AINetwork" );
}
#endif
// Reset node counter used during load
CNodeEnt::m_nNodeCount = 0;

View File

@ -184,6 +184,20 @@ BEGIN_SIMPLE_DATADESC( CAI_Expresser )
DEFINE_FIELD( m_flLastTimeAcceptedSpeak, FIELD_TIME ),
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CAI_Expresser, "Expresser class for complex speech." )
DEFINE_SCRIPTFUNC( IsSpeaking, "Check if the actor is speaking." )
DEFINE_SCRIPTFUNC( CanSpeak, "Check if the actor can speak." )
DEFINE_SCRIPTFUNC( BlockSpeechUntil, "Block speech for a certain amount of time. This is stored in curtime." )
DEFINE_SCRIPTFUNC( ForceNotSpeaking, "If the actor is speaking, force the system to recognize them as not speaking." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSpeakRawScene, "SpeakRawScene", "Speak a raw, instanced VCD scene as though it were played through the Response System. Return whether the scene successfully plays." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSpeakAutoGeneratedScene, "SpeakAutoGeneratedScene", "Speak an automatically generated, instanced VCD scene for this sound as though it were played through the Response System. Return whether the scene successfully plays." )
END_SCRIPTDESC();
#endif
//-------------------------------------
bool CAI_Expresser::SemaphoreIsAvailable( CBaseEntity *pTalker )

View File

@ -203,6 +203,12 @@ public:
// Force the NPC to release the semaphore & clear next speech time
void ForceNotSpeaking( void );
#ifdef MAPBASE_VSCRIPT
bool ScriptSpeakRawScene( char const *soundname, float delay ) { return SpeakRawScene( soundname, delay, NULL ); }
bool ScriptSpeakAutoGeneratedScene( char const *soundname, float delay ) { return SpeakAutoGeneratedScene( soundname, delay ); }
bool ScriptSpeak( AIConcept_t concept, const char *modifiers ) { return Speak( concept, modifiers ); }
#endif
protected:
CAI_TimedSemaphore *GetMySpeechSemaphore( CBaseEntity *pNpc );

View File

@ -282,6 +282,17 @@ IMPLEMENT_SERVERCLASS_ST(CBaseAnimating, DT_BaseAnimating)
END_SEND_TABLE()
BEGIN_ENT_SCRIPTDESC( CBaseAnimating, CBaseEntity, "Animating models" )
DEFINE_SCRIPTFUNC( LookupAttachment, "Get the named attachement id" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentOrigin, "GetAttachmentOrigin", "Get the attachement id's origin vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentAngles, "GetAttachmentAngles", "Get the attachement id's angles as a p,y,r vector" )
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentMatrix, "GetAttachmentMatrix", "Get the attachement id's matrix transform" )
#endif
DEFINE_SCRIPTFUNC( IsSequenceFinished, "Ask whether the main sequence is done playing" )
DEFINE_SCRIPTFUNC( SetBodygroup, "Sets a bodygroup")
END_SCRIPTDESC();
CBaseAnimating::CBaseAnimating()
{
@ -2117,6 +2128,45 @@ bool CBaseAnimating::GetAttachment( int iAttachment, Vector &absOrigin, Vector *
return bRet;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the world location and world angles of an attachment to vscript caller
// Input : attachment name
// Output : location and angles
//-----------------------------------------------------------------------------
const Vector& CBaseAnimating::ScriptGetAttachmentOrigin( int iAttachment )
{
static Vector absOrigin;
static QAngle qa;
CBaseAnimating::GetAttachment( iAttachment, absOrigin, qa );
return absOrigin;
}
const Vector& CBaseAnimating::ScriptGetAttachmentAngles( int iAttachment )
{
static Vector absOrigin;
static Vector absAngles;
static QAngle qa;
CBaseAnimating::GetAttachment( iAttachment, absOrigin, qa );
absAngles.x = qa.x;
absAngles.y = qa.y;
absAngles.z = qa.z;
return absAngles;
}
#ifdef MAPBASE_VSCRIPT
HSCRIPT CBaseAnimating::ScriptGetAttachmentMatrix( int iAttachment )
{
static matrix3x4_t matrix;
CBaseAnimating::GetAttachment( iAttachment, matrix );
return ScriptCreateMatrixInstance( matrix );
}
#endif
//-----------------------------------------------------------------------------
// Returns the attachment in local space

View File

@ -44,6 +44,7 @@ public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
DECLARE_ENT_SCRIPTDESC();
virtual void SetModel( const char *szModelName );
virtual void Activate();
@ -186,6 +187,11 @@ public:
bool GetAttachment( int iAttachment, Vector &absOrigin, QAngle &absAngles );
int GetAttachmentBone( int iAttachment );
virtual bool GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld );
const Vector& ScriptGetAttachmentOrigin(int iAttachment);
const Vector& ScriptGetAttachmentAngles(int iAttachment);
#ifdef MAPBASE_VSCRIPT
HSCRIPT ScriptGetAttachmentMatrix(int iAttachment);
#endif
// These return the attachment in the space of the entity
bool GetAttachmentLocal( const char *szName, Vector &origin, QAngle &angles );

View File

@ -150,6 +150,44 @@ BEGIN_DATADESC( CBaseCombatCharacter )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CBaseCombatCharacter, CBaseFlex, "The base class shared by players and NPCs." )
DEFINE_SCRIPTFUNC_NAMED( GetScriptActiveWeapon, "GetActiveWeapon", "Get the character's active weapon entity." )
DEFINE_SCRIPTFUNC( WeaponCount, "Get the number of weapons a character possesses." )
DEFINE_SCRIPTFUNC_NAMED( GetScriptWeaponIndex, "GetWeapon", "Get a specific weapon in the character's inventory." )
DEFINE_SCRIPTFUNC_NAMED( GetScriptWeaponByType, "FindWeapon", "Find a specific weapon in the character's inventory by its classname." )
DEFINE_SCRIPTFUNC_NAMED( Weapon_ShootPosition, "ShootPosition", "Get the character's shoot position." )
DEFINE_SCRIPTFUNC_NAMED( Weapon_DropAll, "DropAllWeapons", "Make the character drop all of its weapons." )
DEFINE_SCRIPTFUNC_NAMED( ScriptEquipWeapon, "EquipWeapon", "Make the character equip the specified weapon entity. If they don't already own the weapon, they will acquire it instantly." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAmmoCount, "GetAmmoCount", "Get the ammo count of the specified ammo type." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAmmoCount, "SetAmmoCount", "Set the ammo count of the specified ammo type." )
DEFINE_SCRIPTFUNC_NAMED( ScriptRelationType, "GetRelationship", "Get a character's relationship to a specific entity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptRelationPriority, "GetRelationPriority", "Get a character's relationship priority for a specific entity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetRelationship, "SetRelationship", "Set a character's relationship with a specific entity." )
DEFINE_SCRIPTFUNC_NAMED( GetScriptVehicleEntity, "GetVehicleEntity", "Get the entity for a character's current vehicle if they're in one." )
DEFINE_SCRIPTFUNC_NAMED( ScriptInViewCone, "InViewCone", "Check if the specified position is in the character's viewcone." )
DEFINE_SCRIPTFUNC_NAMED( ScriptEntInViewCone, "EntInViewCone", "Check if the specified entity is in the character's viewcone." )
DEFINE_SCRIPTFUNC_NAMED( ScriptInAimCone, "InAimCone", "Check if the specified position is in the character's aim cone." )
DEFINE_SCRIPTFUNC_NAMED( ScriptEntInViewCone, "EntInAimCone", "Check if the specified entity is in the character's aim cone." )
DEFINE_SCRIPTFUNC_NAMED( ScriptBodyAngles, "BodyAngles", "Get the body's angles." )
DEFINE_SCRIPTFUNC( BodyDirection2D, "Get the body's 2D direction." )
DEFINE_SCRIPTFUNC( BodyDirection3D, "Get the body's 3D direction." )
DEFINE_SCRIPTFUNC( HeadDirection2D, "Get the head's 2D direction." )
DEFINE_SCRIPTFUNC( HeadDirection3D, "Get the head's 3D direction." )
DEFINE_SCRIPTFUNC( EyeDirection2D, "Get the eyes' 2D direction." )
DEFINE_SCRIPTFUNC( EyeDirection3D, "Get the eyes' 3D direction." )
END_SCRIPTDESC();
#endif
BEGIN_SIMPLE_DATADESC( Relationship_t )
DEFINE_FIELD( entity, FIELD_EHANDLE ),
@ -4317,6 +4355,114 @@ void CBaseCombatCharacter::DoMuzzleFlash()
}
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseCombatCharacter::GetScriptActiveWeapon()
{
return ToHScript( GetActiveWeapon() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseCombatCharacter::GetScriptWeaponIndex( int i )
{
return ToHScript( GetWeapon( i ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseCombatCharacter::GetScriptWeaponByType( const char *pszWeapon, int iSubType )
{
return ToHScript( Weapon_OwnsThisType( pszWeapon, iSubType ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseCombatCharacter::ScriptEquipWeapon( HSCRIPT hWeapon )
{
CBaseEntity *pEntity = ToEnt( hWeapon );
CBaseCombatWeapon *pWeapon = pEntity->MyCombatWeaponPointer();
if (!pEntity || !pWeapon)
return;
if (pWeapon->GetOwner() == this)
{
// Switch to this weapon
Weapon_Switch( pWeapon );
}
else
{
if (CBaseCombatWeapon *pExistingWeapon = Weapon_OwnsThisType( pWeapon->GetClassname() ))
{
// Drop our existing weapon then!
Weapon_Drop( pExistingWeapon );
}
if (IsNPC())
{
Weapon_Equip( pWeapon );
MyNPCPointer()->OnGivenWeapon( pWeapon );
}
else
{
Weapon_Equip( pWeapon );
}
pWeapon->OnPickedUp( this );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CBaseCombatCharacter::ScriptGetAmmoCount( const char *szName ) const
{
return GetAmmoCount( GetAmmoDef()->Index(szName) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseCombatCharacter::ScriptSetAmmoCount( const char *szName, int iCount )
{
int iType = GetAmmoDef()->Index( szName );
if (iType == -1)
{
Warning("\"%s\" is not a valid ammo type\n", szName);
return;
}
return SetAmmoCount( iCount, iType );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CBaseCombatCharacter::ScriptRelationType( HSCRIPT pTarget )
{
return (int)IRelationType( ToEnt( pTarget ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CBaseCombatCharacter::ScriptRelationPriority( HSCRIPT pTarget )
{
return IRelationPriority( ToEnt( pTarget ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseCombatCharacter::ScriptSetRelationship( HSCRIPT pTarget, int disposition, int priority )
{
AddEntityRelationship( ToEnt( pTarget ), (Disposition_t)disposition, priority );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseCombatCharacter::GetScriptVehicleEntity()
{
return ToHScript( GetVehicleEntity() );
}
#endif
//-----------------------------------------------------------------------------
// Purpose: return true if given target cant be seen because of fog
//-----------------------------------------------------------------------------

View File

@ -119,6 +119,9 @@ public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
DECLARE_PREDICTABLE();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
public:
@ -407,6 +410,31 @@ public:
virtual float GetSpreadBias( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget );
virtual void DoMuzzleFlash();
#ifdef MAPBASE_VSCRIPT // DO NOT COMMIT; WAIT UNTIL FULL MERGE (5/15/2020)
HSCRIPT GetScriptActiveWeapon();
HSCRIPT GetScriptWeaponIndex( int i );
HSCRIPT GetScriptWeaponByType( const char *pszWeapon, int iSubType = 0 );
void ScriptEquipWeapon( HSCRIPT hWeapon );
int ScriptGetAmmoCount( const char *szName ) const;
void ScriptSetAmmoCount( const char *szName, int iCount );
int ScriptRelationType( HSCRIPT pTarget );
int ScriptRelationPriority( HSCRIPT pTarget );
void ScriptSetRelationship( HSCRIPT pTarget, int disposition, int priority );
HSCRIPT GetScriptVehicleEntity();
bool ScriptInViewCone( const Vector &vecSpot ) { return FInViewCone( vecSpot ); }
bool ScriptEntInViewCone( HSCRIPT pEntity ) { return FInViewCone( ToEnt( pEntity ) ); }
bool ScriptInAimCone( const Vector &vecSpot ) { return FInAimCone( vecSpot ); }
bool ScriptEntInAimCone( HSCRIPT pEntity ) { return FInAimCone( ToEnt( pEntity ) ); }
const Vector& ScriptBodyAngles( void ) { static Vector vec; QAngle qa = BodyAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; }
#endif
// Interactions
static void InitInteractionSystem();

View File

@ -101,6 +101,9 @@ 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");
// This table encodes edict data.
void SendProxy_AnimTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID )
{
@ -291,6 +294,8 @@ IMPLEMENT_SERVERCLASS_ST_NOBASE( CBaseEntity, DT_BaseEntity )
SendPropEHandle (SENDINFO_NAME(m_hMoveParent, moveparent)),
SendPropInt (SENDINFO(m_iParentAttachment), NUM_PARENTATTACHMENT_BITS, SPROP_UNSIGNED),
SendPropStringT( SENDINFO( m_iName ) ),
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
@ -1313,6 +1318,19 @@ void CBaseEntity::FireNamedOutput( const char *pszOutput, variant_t variant, CBa
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;
datamap_t *dmap = GetDataDescMap();
while ( dmap )
{
@ -1325,14 +1343,13 @@ void CBaseEntity::FireNamedOutput( const char *pszOutput, variant_t variant, CBa
CBaseEntityOutput *pOutput = ( CBaseEntityOutput * )( ( int )this + ( int )dataDesc->fieldOffset[0] );
if ( !Q_stricmp( dataDesc->externalName, pszOutput ) )
{
pOutput->FireOutput( variant, pActivator, pCaller, flDelay );
return;
return pOutput;
}
}
}
dmap = dmap->baseMap;
}
return NULL;
}
void CBaseEntity::Activate( void )
@ -1822,6 +1839,12 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
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"),
DEFINE_KEYFIELD( m_nNextThinkTick, FIELD_TICK, "nextthink" ),
DEFINE_KEYFIELD( m_fEffects, FIELD_INTEGER, "effects" ),
DEFINE_KEYFIELD( m_clrRender, FIELD_COLOR32, "rendercolor" ),
@ -2004,6 +2027,14 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
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" ),
@ -2081,6 +2112,7 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
DEFINE_FUNCTION( SUB_Vanish ),
DEFINE_FUNCTION( SUB_CallUseToggle ),
DEFINE_THINKFUNC( ShadowCastDistThink ),
DEFINE_THINKFUNC( ScriptThink ),
#ifdef MAPBASE
DEFINE_FUNCTION( SUB_RemoveWhenNotVisible ),
@ -2097,6 +2129,122 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity )
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", "" )
DEFINE_SCRIPTFUNC( GetPreTemplateName, "Get the entity name stripped of template unique decoration" )
DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" )
DEFINE_SCRIPTFUNC( SetAbsOrigin, "SetAbsOrigin" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetOrigin, "SetOrigin", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" )
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptEntityToWorldTransform, "EntityToWorldTransform", "Get the entity's transform" )
#endif
DEFINE_SCRIPTFUNC_NAMED( ScriptSetForward, "SetForwardVector", "Set the orientation of the entity to have this forward vector" )
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", "" )
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_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( ScriptGetKeyValue, "GetKeyValue", "Get a keyvalue" )
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" )
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." )
#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" )
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, "" )
END_SCRIPTDESC();
// For code error checking
extern bool g_bReceivedChainedUpdateOnRemove;
@ -2196,6 +2344,12 @@ void CBaseEntity::UpdateOnRemove( void )
modelinfo->ReleaseDynamicModel( m_nModelIndex ); // no-op if not dynamic
m_nModelIndex = -1;
}
if ( m_hScriptInstance )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
}
//-----------------------------------------------------------------------------
@ -3925,9 +4079,9 @@ const char *CBaseEntity::GetDebugName(void)
if ( this == NULL )
return "<<null>>";
if ( m_iName != NULL_STRING )
if ( m_iName.Get() != NULL_STRING )
{
return STRING(m_iName);
return STRING(m_iName.Get());
}
else
{
@ -4108,7 +4262,7 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
// mapper debug message
if (pCaller != NULL)
{
Q_snprintf( szBuffer, sizeof(szBuffer), "(%0.2f) input %s: %s.%s(%s)\n", gpGlobals->curtime, STRING(pCaller->m_iName), GetDebugName(), szInputName, Value.String() );
Q_snprintf( szBuffer, sizeof(szBuffer), "(%0.2f) input %s: %s.%s(%s)\n", gpGlobals->curtime, STRING(pCaller->m_iName.Get()), GetDebugName(), szInputName, Value.String() );
}
else
{
@ -4155,7 +4309,7 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
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) : "<null>",
( pCaller != NULL ) ? STRING(pCaller->m_iName.Get()) : "<null>",
dmap->dataDesc[i].fieldType,
STRING(m_iClassname), GetDebugName(), szInputName );
return false;
@ -4168,7 +4322,7 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
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) : "<null>" );
( pCaller != NULL ) ? STRING(pCaller->m_iName.Get()) : "<null>" );
return false;
}
#endif
@ -4187,7 +4341,44 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
data.value = Value;
data.nOutputID = outputID;
(this->*pfnInput)( data );
// 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
}
}
else if ( dmap->dataDesc[i].flags & FTYPEDESC_KEY )
{
@ -4210,7 +4401,7 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator,
}
}
DevMsg( 2, "unhandled input: (%s) -> (%s,%s)\n", szInputName, STRING(m_iClassname), GetDebugName()/*,", from (%s,%s)" STRING(pCaller->m_iClassname), STRING(pCaller->m_iName)*/ );
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())*/ );
return false;
}
@ -5300,6 +5491,36 @@ void CC_Ent_Name( const CCommand& args )
}
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);
//------------------------------------------------------------------------------
#ifdef MAPBASE
class CEntTextAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback
@ -6978,6 +7199,7 @@ const char *CBaseEntity::GetContextValue( int index ) const
}
return m_ResponseContexts[ index ].m_iszValue.ToCStr();
}
//-----------------------------------------------------------------------------
@ -7223,7 +7445,6 @@ void CBaseEntity::InputPassRandomUser( inputdata_t& inputdata )
}
#endif
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Sets the entity's targetname.
@ -7820,6 +8041,282 @@ void CBaseEntity::InputSetThinkNull( inputdata_t& inputdata )
#endif
//---------------------------------------------------------
// 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;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
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();
}
SetContextThink(&CBaseEntity::ScriptThink,
gpGlobals->curtime + flThinkFrequency, "ScriptThink");
}
else
{
DevWarning("%s FAILED to call script think function %s!\n", GetDebugName(), STRING(m_iszScriptThinkFunction));
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char* CBaseEntity::GetScriptId()
{
return STRING(m_iszScriptThinkFunction);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::GetScriptScope()
{
return m_ScriptScope;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
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;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *contextName -
@ -8796,6 +9293,329 @@ void CBaseEntity::SetCollisionBoundsFromModel()
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
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???
hScript = g_pScriptVM->RegisterInstance( m_pScriptModelKeyValues );
/*
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();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char *CBaseEntity::ScriptGetKeyValue( const char *pszKeyName )
{
static char szValue[128];
GetKeyValue( pszKeyName, szValue, sizeof(szValue) );
return szValue;
}
#endif
#ifdef MAPBASE
extern int EntityFactory_AutoComplete( const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0 );

View File

@ -21,6 +21,9 @@
#include "shareddefs.h"
#include "engine/ivmodelinfo.h"
#include "vscript/ivscript.h"
#include "vscript_server.h"
class CDamageModifier;
class CDmgAccumulator;
@ -311,11 +314,13 @@ a list of all CBaseEntitys is kept in gEntList
CBaseEntity *CreateEntityByName( const char *className, int iForceEdictIndex = -1 );
CBaseNetworkable *CreateNetworkableByName( const char *className );
CBaseEntity* ToEnt(HSCRIPT hScript);
// creates an entity and calls all the necessary spawn functions
extern void SpawnEntityByName( const char *className, CEntityMapData *mapData = NULL );
// calls the spawn functions for an entity
extern int DispatchSpawn( CBaseEntity *pEntity );
extern int DispatchSpawn( CBaseEntity *pEntity, bool bRunVScripts = true);
inline CBaseEntity *GetContainingEntity( edict_t *pent );
@ -379,6 +384,8 @@ public:
DECLARE_SERVERCLASS();
// data description
DECLARE_DATADESC();
// script description
DECLARE_ENT_SCRIPTDESC();
// memory handling
void *operator new( size_t stAllocateBlock );
@ -493,6 +500,8 @@ public:
virtual void SetOwnerEntity( CBaseEntity* pOwner );
void SetEffectEntity( CBaseEntity *pEffectEnt );
CBaseEntity *GetEffectEntity() const;
HSCRIPT GetScriptOwnerEntity();
virtual void SetScriptOwnerEntity(HSCRIPT pOwner);
// Only CBaseEntity implements these. CheckTransmit calls the virtual ShouldTransmit to see if the
// entity wants to be sent. If so, it calls SetTransmit, which will mark any dependents for transmission too.
@ -563,9 +572,14 @@ public:
virtual bool KeyValue( const char *szKeyName, float flValue );
virtual bool KeyValue( const char *szKeyName, const Vector &vecValue );
virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen );
bool KeyValueFromString( const char *szKeyName, const char *szValue ) { return KeyValue( szKeyName, szValue ); }
bool KeyValueFromFloat( const char *szKeyName, float flValue ) { return KeyValue( szKeyName, flValue ); }
bool KeyValueFromInt( const char *szKeyName, int nValue ) { return KeyValue( szKeyName, nValue ); }
bool KeyValueFromVector( const char *szKeyName, const Vector &vecValue ) { return KeyValue( szKeyName, vecValue ); }
void ValidateEntityConnections();
void FireNamedOutput( const char *pszOutput, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller, float flDelay = 0.0f );
CBaseEntityOutput *FindNamedOutput( const char *pszOutput );
// Activate - called for each entity after each load game and level load
virtual void Activate( void );
@ -588,6 +602,8 @@ public:
int GetParentAttachment();
string_t GetEntityName();
const char* GetEntityNameAsCStr(); // This method is temporary for VSCRIPT functionality until we figure out what to do with string_t (sjb)
const char* GetPreTemplateName(); // Not threadsafe. Get the name stripped of template unique decoration
bool NameMatches( const char *pszNameOrWildcard );
bool ClassMatches( const char *pszClassOrWildcard );
@ -735,6 +751,18 @@ public:
COutputEvent m_OnKilled;
#endif
void InputRunScript(inputdata_t& inputdata);
void InputRunScriptFile(inputdata_t& inputdata);
void InputCallScriptFunction(inputdata_t& inputdata);
#ifdef MAPBASE_VSCRIPT
void InputRunScriptQuotable(inputdata_t& inputdata);
void InputClearScriptScope(inputdata_t& inputdata);
#endif
bool RunScriptFile(const char* pScriptFile, bool bUseRootScope = false);
bool RunScript(const char* pScriptText, const char* pDebugFilename = "CBaseEntity::RunScript");
// Returns the origin at which to play an inputted dispatcheffect
virtual void GetInputDispatchEffectPosition( const char *sInputString, Vector &pOrigin, QAngle &pAngles );
@ -1715,7 +1743,7 @@ private:
// was pev->flags
CNetworkVarForDerived( int, m_fFlags );
string_t m_iName; // name used to identify this entity
CNetworkVar( string_t, m_iName ); // name used to identify this entity
// Damage modifiers
friend class CDamageModifier;
@ -1920,6 +1948,85 @@ public:
{
return s_bAbsQueriesValid;
}
// VSCRIPT
HSCRIPT GetScriptInstance();
bool ValidateScriptScope();
virtual void RunVScripts();
bool CallScriptFunction(const char* pFunctionName, ScriptVariant_t* pFunctionReturn);
void ConnectOutputToScript(const char* pszOutput, const char* pszScriptFunc);
void DisconnectOutputFromScript(const char* pszOutput, const char* pszScriptFunc);
void ScriptThink();
const char* GetScriptId();
HSCRIPT GetScriptScope();
void RunPrecacheScripts(void);
void RunOnPostSpawnScripts(void);
HSCRIPT ScriptGetMoveParent(void);
HSCRIPT ScriptGetRootMoveParent();
HSCRIPT ScriptFirstMoveChild(void);
HSCRIPT ScriptNextMovePeer(void);
const Vector& ScriptEyePosition(void) { static Vector vec; vec = EyePosition(); return vec; }
#ifdef MAPBASE_VSCRIPT
const QAngle& ScriptEyeAngles(void) { static QAngle ang; ang = EyeAngles(); return ang; }
void ScriptSetAngles(const QAngle angles) { Teleport(NULL, &angles, NULL); }
const QAngle& ScriptGetAngles(void) { return GetAbsAngles(); }
#else
void ScriptSetAngles(float fPitch, float fYaw, float fRoll) { QAngle angles(fPitch, fYaw, fRoll); Teleport(NULL, &angles, NULL); }
const Vector& ScriptGetAngles(void) { static Vector vec; QAngle qa = GetAbsAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; }
#endif
void ScriptSetSize(const Vector& mins, const Vector& maxs) { UTIL_SetSize(this, mins, maxs); }
void ScriptUtilRemove(void) { UTIL_Remove(this); }
void ScriptSetOwner(HSCRIPT hEntity) { SetOwnerEntity(ToEnt(hEntity)); }
void ScriptSetOrigin(const Vector& v) { Teleport(&v, NULL, NULL); }
void ScriptSetForward(const Vector& v) { QAngle angles; VectorAngles(v, angles); Teleport(NULL, &angles, NULL); }
const Vector& ScriptGetForward(void) { static Vector vecForward; GetVectors(&vecForward, NULL, NULL); return vecForward; }
const Vector& ScriptGetLeft(void) { static Vector vecLeft; GetVectors(NULL, &vecLeft, NULL); return vecLeft; }
const Vector& ScriptGetUp(void) { static Vector vecUp; GetVectors(NULL, NULL, &vecUp); return vecUp; }
#ifdef MAPBASE_VSCRIPT
HSCRIPT ScriptEntityToWorldTransform(void) { return ScriptCreateMatrixInstance( EntityToWorldTransform() ); }
#endif
const char* ScriptGetModelName(void) const;
HSCRIPT ScriptGetModelKeyValues(void);
void ScriptEmitSound(const char* soundname);
float ScriptSoundDuration(const char* soundname, const char* actormodel);
void VScriptPrecacheScriptSound(const char* soundname);
const Vector& ScriptGetLocalAngularVelocity( void );
void ScriptSetLocalAngularVelocity( float pitchVel, float yawVel, float rollVel );
const Vector& ScriptGetBoundingMins(void);
const Vector& ScriptGetBoundingMaxs(void);
#ifdef MAPBASE_VSCRIPT
bool ScriptIsVisible( const Vector &vecSpot ) { return FVisible( vecSpot ); }
bool ScriptIsEntVisible( HSCRIPT pEntity ) { return FVisible( ToEnt( pEntity ) ); }
bool ScriptIsVisibleWithMask( const Vector &vecSpot, int traceMask ) { return FVisible( vecSpot, traceMask ); }
int ScriptTakeDamage( HSCRIPT pInfo );
void ScriptFireBullets( HSCRIPT pInfo );
void ScriptAddContext( const char *name, const char *value, float duration = 0.0f );
const char *ScriptGetContext( const char *name );
int ScriptClassify(void);
const char *ScriptGetKeyValue( const char *pszKeyName );
#endif
string_t m_iszVScripts;
string_t m_iszScriptThinkFunction;
CScriptScope m_ScriptScope;
HSCRIPT m_hScriptInstance;
string_t m_iszScriptId;
CScriptKeyValues* m_pScriptModelKeyValues;
};
// Send tables exposed in this module.
@ -2048,6 +2155,21 @@ inline string_t CBaseEntity::GetEntityName()
return m_iName;
}
inline const char *CBaseEntity::GetEntityNameAsCStr()
{
return STRING(m_iName.Get());
}
inline const char *CBaseEntity::GetPreTemplateName()
{
const char *pszDelimiter = V_strrchr( STRING(m_iName.Get()), '&' );
if ( !pszDelimiter )
return STRING( m_iName.Get() );
static char szStrippedName[128];
V_strncpy( szStrippedName, STRING( m_iName.Get() ), MIN( ARRAYSIZE(szStrippedName), pszDelimiter - STRING( m_iName.Get() ) + 1 ) );
return szStrippedName;
}
inline void CBaseEntity::SetName( string_t newName )
{
m_iName = newName;
@ -2726,6 +2848,14 @@ inline void CBaseEntity::FireBullets( int cShots, const Vector &vecSrc,
FireBullets( info );
}
//-----------------------------------------------------------------------------
// VScript
//-----------------------------------------------------------------------------
inline const char* CBaseEntity::ScriptGetModelName(void) const
{
return STRING(m_ModelName);
}
// Ugly technique to override base member functions
// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a
// member function of a base class. static_cast is a sleezy way around that problem.

View File

@ -95,6 +95,10 @@ BEGIN_DATADESC( CBaseFlex )
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( CBaseFlex, CBaseAnimating, "Animated characters who have vertex flex capability." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetOldestScene, "GetCurrentScene", "Returns the instance of the oldest active scene entity (if any)." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSceneByIndex, "GetSceneByIndex", "Returns the instance of the scene entity at the specified index." )
END_SCRIPTDESC();
LINK_ENTITY_TO_CLASS( funCBaseFlex, CBaseFlex ); // meaningless independant class!!
@ -421,7 +425,8 @@ void CBaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEn
info.m_pEvent = event;
info.m_pScene = scene;
info.m_hTarget = pTarget;
info.m_bStarted = false;
info.m_bStarted = false;
info.m_hSceneEntity = pSceneEnt;
#ifdef MAPBASE
if (StartSceneEvent( &info, scene, event, actor, pTarget, pSceneEnt ))
@ -2029,6 +2034,37 @@ float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname )
#endif
//--------------------------------------------------------------------------------------------------
// Returns the script instance of the scene entity associated with our oldest ("top level") scene event
//--------------------------------------------------------------------------------------------------
HSCRIPT CBaseFlex::ScriptGetOldestScene( void )
{
if ( m_SceneEvents.Count() > 0 )
{
CSceneEventInfo curScene = m_SceneEvents.Head();
return ToHScript( (CBaseEntity*)(curScene.m_hSceneEntity.Get()) );
}
else
{
return NULL;
}
}
//--------------------------------------------------------------------------------------------------
// Returns the script instance of the scene at the specified index, or null if index >= count
//--------------------------------------------------------------------------------------------------
HSCRIPT CBaseFlex::ScriptGetSceneByIndex( int index )
{
if ( m_SceneEvents.IsValidIndex( index ) )
{
CSceneEventInfo curScene = m_SceneEvents.Element( index );
return ToHScript( (CBaseEntity*)(curScene.m_hSceneEntity.Get()) );
}
else
{
return NULL;
}
}
// FIXME: move to CBaseActor

View File

@ -46,6 +46,8 @@ public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
DECLARE_PREDICTABLE();
// script description
DECLARE_ENT_SCRIPTDESC();
// Construction
CBaseFlex( void );
@ -130,6 +132,10 @@ public:
virtual float PlayAutoGeneratedSoundScene( const char *soundname );
#endif
// Returns the script instance of the scene entity associated with our oldest ("top level") scene event
virtual HSCRIPT ScriptGetOldestScene( void );
virtual HSCRIPT ScriptGetSceneByIndex( int index );
virtual int GetSpecialDSP( void ) { return 0; }
protected:

View File

@ -396,6 +396,28 @@ void CBaseEntityOutput::AddEventAction( CEventAction *pEventAction )
m_ActionList = pEventAction;
}
void CBaseEntityOutput::RemoveEventAction( CEventAction *pEventAction )
{
CEventAction *pAction = GetActionList();
CEventAction *pPrevAction = NULL;
while ( pAction )
{
if ( pAction == pEventAction )
{
if ( !pPrevAction )
{
m_ActionList = NULL;
}
else
{
pPrevAction->m_pNext = pAction->m_pNext;
}
return;
}
pAction = pAction->m_pNext;
}
}
// save data description for the event queue
BEGIN_SIMPLE_DATADESC( CBaseEntityOutput )

View File

@ -26,6 +26,7 @@ class IDataCache;
class IMDLCache;
class IServerEngineTools;
class IXboxSystem;
class IScriptManager;
class CSteamAPIContext;
class CSteamGameServerAPIContext;
@ -43,6 +44,7 @@ extern IDataCache *datacache;
extern IMDLCache *mdlcache;
extern IServerEngineTools *serverenginetools;
extern IXboxSystem *xboxsystem; // 360 only
extern IScriptManager *scriptmanager;
extern CSteamAPIContext *steamapicontext; // available on game clients
extern CSteamGameServerAPIContext *steamgameserverapicontext; //available on game servers

View File

@ -667,7 +667,7 @@ CBaseEntity *CGlobalEntityList::FindEntityByName( CBaseEntity *pStartEntity, con
continue;
}
if ( !ent->m_iName )
if ( !ent->m_iName.Get() )
continue;
if ( ent->NameMatches( szName ) )

View File

@ -63,6 +63,7 @@ public:
void ParseEventAction( const char *EventData );
void AddEventAction( CEventAction *pEventAction );
void RemoveEventAction( CEventAction *pEventAction );
int Save( ISave &save );
int Restore( IRestore &restore, int elementCount );

View File

@ -30,6 +30,7 @@ class CEnvEntityMaker : public CPointEntity
DECLARE_CLASS( CEnvEntityMaker, CPointEntity );
public:
DECLARE_DATADESC();
DECLARE_ENT_SCRIPTDESC();
virtual void Spawn( void );
virtual void Activate( void );
@ -43,6 +44,10 @@ public:
void InputForceSpawnAtPosition( inputdata_t &inputdata );
#endif
void SpawnEntityFromScript();
void SpawnEntityAtEntityOriginFromScript(HSCRIPT hEntity);
void SpawnEntityAtNamedEntityOriginFromScript(const char* pszName);
void SpawnEntityAtLocationFromScript(const Vector& vecAlternateOrigin, const Vector& vecAlternateAngles);
private:
CPointTemplate *FindTemplate();
@ -102,6 +107,13 @@ BEGIN_DATADESC( CEnvEntityMaker )
DEFINE_THINKFUNC( CheckSpawnThink ),
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( CEnvEntityMaker, CBaseEntity, "env_entity_maker" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityFromScript, "SpawnEntity", "Create an entity at the location of the maker" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtEntityOriginFromScript, "SpawnEntityAtEntityOrigin", "Create an entity at the location of a specified entity instance" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtNamedEntityOriginFromScript, "SpawnEntityAtNamedEntityOrigin", "Create an entity at the location of a named entity" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtLocationFromScript, "SpawnEntityAtLocation", "Create an entity at a specified location and orientaton, orientation is Euler angle in degrees (pitch, yaw, roll)" )
END_SCRIPTDESC()
LINK_ENTITY_TO_CLASS( env_entity_maker, CEnvEntityMaker );
@ -266,8 +278,50 @@ void CEnvEntityMaker::SpawnEntity( Vector vecAlternateOrigin, QAngle vecAlternat
}
}
#endif
pTemplate->CreationComplete( hNewEntities );
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityFromScript()
{
SpawnEntity();
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtEntityOriginFromScript( HSCRIPT hEntity )
{
CBaseEntity *pTargetEntity = ToEnt( hEntity );
if ( pTargetEntity )
{
SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtNamedEntityOriginFromScript( const char *pszName )
{
CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, pszName, this, NULL, NULL );
if( pTargetEntity )
{
SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtLocationFromScript( const Vector &vecAlternateOrigin, const Vector &vecAlternateAngles )
{
SpawnEntity( vecAlternateOrigin, *((QAngle *)&vecAlternateAngles) );
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not the template entities can fit if spawned.

View File

@ -44,6 +44,18 @@ BEGIN_DATADESC( CBaseFilter )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CBaseFilter, CBaseEntity, "All entities which could be used as filters." )
DEFINE_SCRIPTFUNC_NAMED( ScriptPassesFilter, "PassesFilter", "Check if the given caller and entity pass the filter." )
DEFINE_SCRIPTFUNC_NAMED( ScriptPassesDamageFilter, "PassesDamageFilter", "Check if the given caller and damage info pass the damage filter." )
DEFINE_SCRIPTFUNC_NAMED( ScriptPassesFinalDamageFilter, "PassesFinalDamageFilter", "Used by filter_damage_redirect to distinguish between standalone filter calls and actually damaging an entity. Returns true if there's no unique behavior." )
DEFINE_SCRIPTFUNC_NAMED( ScriptBloodAllowed, "BloodAllowed", "Check if the given caller and damage info allow for the production of blood." )
DEFINE_SCRIPTFUNC_NAMED( ScriptDamageMod, "DamageMod", "Mods the damage info with the given caller." )
END_SCRIPTDESC();
#endif
//-----------------------------------------------------------------------------
bool CBaseFilter::PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity )
@ -142,6 +154,14 @@ void CBaseFilter::InputSetField( inputdata_t& inputdata )
}
#endif
#ifdef MAPBASE_VSCRIPT
bool CBaseFilter::ScriptPassesFilter( HSCRIPT pCaller, HSCRIPT pEntity ) { return PassesFilter( ToEnt(pCaller), ToEnt(pEntity) ); }
bool CBaseFilter::ScriptPassesDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? PassesDamageFilter( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : NULL; }
bool CBaseFilter::ScriptPassesFinalDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? PassesFinalDamageFilter( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : NULL; }
bool CBaseFilter::ScriptBloodAllowed( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? BloodAllowed( ToEnt( pCaller ), *const_cast<const CTakeDamageInfo*>(HScriptToClass<CTakeDamageInfo>( pInfo )) ) : NULL; }
bool CBaseFilter::ScriptDamageMod( HSCRIPT pCaller, HSCRIPT pInfo ) { return (pInfo) ? DamageMod( ToEnt( pCaller ), *HScriptToClass<CTakeDamageInfo>( pInfo ) ) : NULL; }
#endif
// ###################################################################
// > FilterMultiple
@ -223,6 +243,13 @@ void CFilterMultiple::Activate( void )
Warning("filter_multi: Tried to add entity (%s) which is not a filter entity!\n", STRING( m_iFilterName[i] ) );
continue;
}
#ifdef MAPBASE
else if ( pFilter == this )
{
Warning("filter_multi: Tried to add itself!\n");
continue;
}
#endif
// Take this entity and increment out array pointer
m_hFilter[nNextFilter] = pFilter;
@ -2109,3 +2136,152 @@ BEGIN_DATADESC( CFilterDamageLogic )
END_DATADESC()
#endif
#ifdef MAPBASE_VSCRIPT
// ###################################################################
// > CFilterScript
// ###################################################################
class CFilterScript : public CBaseFilter
{
DECLARE_CLASS( CFilterScript, CBaseFilter );
DECLARE_DATADESC();
public:
bool PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity )
{
if (m_ScriptScope.IsInitialized())
{
g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
g_pScriptVM->SetValue( "activator", (pEntity) ? ScriptVariant_t( pEntity->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
ScriptVariant_t functionReturn;
if (!CallScriptFunction( "PassesFilter", &functionReturn ))
{
Warning("%s: No PassesFilter function\n", GetDebugName());
}
g_pScriptVM->ClearValue( "caller" );
g_pScriptVM->ClearValue( "activator" );
return functionReturn.m_bool;
}
Warning("%s: No script scope, cannot filter\n", GetDebugName());
return false;
}
bool PassesDamageFilterImpl( CBaseEntity *pCaller, const CTakeDamageInfo &info )
{
if (m_ScriptScope.IsInitialized())
{
HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast<CTakeDamageInfo*>(&info) );
g_pScriptVM->SetValue( "info", pInfo );
g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
ScriptVariant_t functionReturn;
if (!CallScriptFunction( "PassesDamageFilter", &functionReturn ))
{
// Fall back to main filter function
return PassesFilterImpl( pCaller, info.GetAttacker() );
}
g_pScriptVM->RemoveInstance( pInfo );
g_pScriptVM->ClearValue( "info" );
g_pScriptVM->ClearValue( "caller" );
return functionReturn.m_bool;
}
Warning("%s: No script scope, cannot filter\n", GetDebugName());
return false;
}
bool PassesFinalDamageFilter( CBaseEntity *pCaller, const CTakeDamageInfo &info )
{
if (m_ScriptScope.IsInitialized())
{
HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast<CTakeDamageInfo*>(&info) );
g_pScriptVM->SetValue( "info", pInfo );
g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
ScriptVariant_t functionReturn;
if (!CallScriptFunction( "PassesFinalDamageFilter", &functionReturn ))
{
return BaseClass::PassesFinalDamageFilter( pCaller, info );
}
g_pScriptVM->RemoveInstance( pInfo );
g_pScriptVM->ClearValue( "info" );
g_pScriptVM->ClearValue( "caller" );
return functionReturn.m_bool;
}
Warning("%s: No script scope, cannot filter\n", GetDebugName());
return false;
}
bool BloodAllowed( CBaseEntity *pCaller, const CTakeDamageInfo &info )
{
if (m_ScriptScope.IsInitialized())
{
HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast<CTakeDamageInfo*>(&info) );
g_pScriptVM->SetValue( "info", pInfo );
g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
ScriptVariant_t functionReturn;
if (!CallScriptFunction( "BloodAllowed", &functionReturn ))
{
return BaseClass::BloodAllowed( pCaller, info );
}
g_pScriptVM->RemoveInstance( pInfo );
g_pScriptVM->ClearValue( "info" );
g_pScriptVM->ClearValue( "caller" );
return functionReturn.m_bool;
}
Warning("%s: No script scope, cannot filter\n", GetDebugName());
return false;
}
bool DamageMod( CBaseEntity *pCaller, CTakeDamageInfo &info )
{
if (m_ScriptScope.IsInitialized())
{
HSCRIPT pInfo = g_pScriptVM->RegisterInstance( &info );
g_pScriptVM->SetValue( "info", pInfo );
g_pScriptVM->SetValue( "caller", (pCaller) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
ScriptVariant_t functionReturn;
if (!CallScriptFunction( "DamageMod", &functionReturn ))
{
return BaseClass::DamageMod( pCaller, info );
}
g_pScriptVM->RemoveInstance( pInfo );
g_pScriptVM->ClearValue( "info" );
g_pScriptVM->ClearValue( "caller" );
return functionReturn.m_bool;
}
Warning("%s: No script scope, cannot filter\n", GetDebugName());
return false;
}
};
LINK_ENTITY_TO_CLASS( filter_script, CFilterScript );
BEGIN_DATADESC( CFilterScript )
END_DATADESC()
#endif

View File

@ -38,6 +38,9 @@ class CBaseFilter : public CLogicalEntity
public:
DECLARE_DATADESC();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
bool PassesFilter( CBaseEntity *pCaller, CBaseEntity *pEntity );
#ifdef MAPBASE
@ -56,6 +59,14 @@ public:
bool PassesDamageFilter( const CTakeDamageInfo &info );
#endif
#ifdef MAPBASE_VSCRIPT
bool ScriptPassesFilter( HSCRIPT pCaller, HSCRIPT pEntity );
bool ScriptPassesDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo );
bool ScriptPassesFinalDamageFilter( HSCRIPT pCaller, HSCRIPT pInfo );
bool ScriptBloodAllowed( HSCRIPT pCaller, HSCRIPT pInfo );
bool ScriptDamageMod( HSCRIPT pCaller, HSCRIPT pInfo );
#endif
bool m_bNegated;
// Inputs

View File

@ -148,6 +148,39 @@ BEGIN_DATADESC_NO_BASE( CFourWheelVehiclePhysics )
DEFINE_FIELD( m_bLastSkid, FIELD_BOOLEAN ),
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CFourWheelVehiclePhysics, "Handler for four-wheel vehicle physics." )
DEFINE_SCRIPTFUNC( SetThrottle, "Sets the throttle." )
DEFINE_SCRIPTFUNC( SetMaxThrottle, "Sets the max throttle." )
DEFINE_SCRIPTFUNC( SetMaxReverseThrottle, "Sets the max reverse throttle." )
DEFINE_SCRIPTFUNC( SetSteering, "Sets the steering." )
DEFINE_SCRIPTFUNC( SetSteeringDegrees, "Sets the degrees of steering." )
DEFINE_SCRIPTFUNC( SetAction, "Sets the action." )
DEFINE_SCRIPTFUNC( SetHandbrake, "Sets the handbrake." )
DEFINE_SCRIPTFUNC( SetBoost, "Sets the boost." )
DEFINE_SCRIPTFUNC( SetHasBrakePedal, "Sets whether a handbrake pedal exists." )
DEFINE_SCRIPTFUNC( SetDisableEngine, "Sets whether the engine is disabled." )
DEFINE_SCRIPTFUNC( IsEngineDisabled, "Checks whether the engine is disabled." )
DEFINE_SCRIPTFUNC( EnableMotion, "Enables vehicle motion." )
DEFINE_SCRIPTFUNC( DisableMotion, "Disables vehicle motion." )
DEFINE_SCRIPTFUNC( GetSpeed, "Gets the speed." )
DEFINE_SCRIPTFUNC( GetMaxSpeed, "Gets the max speed." )
DEFINE_SCRIPTFUNC( GetRPM, "Gets the RPM." )
DEFINE_SCRIPTFUNC( GetThrottle, "Gets the throttle." )
DEFINE_SCRIPTFUNC( HasBoost, "Checks if the vehicle has the ability to boost." )
DEFINE_SCRIPTFUNC( BoostTimeLeft, "Gets how much time is left in any current boost." )
DEFINE_SCRIPTFUNC( IsBoosting, "Checks if the vehicle is boosting." )
DEFINE_SCRIPTFUNC( GetHLSpeed, "Gets HL speed." )
DEFINE_SCRIPTFUNC( GetSteering, "Gets the steeering." )
DEFINE_SCRIPTFUNC( GetSteeringDegrees, "Gets the degrees of steeering." )
END_SCRIPTDESC();
#endif
//-----------------------------------------------------------------------------
// Constructor

View File

@ -93,6 +93,9 @@
#include "world.h"
#endif
#include "vscript/ivscript.h"
#include "vscript_server.h"
#ifdef TF_DLL
#include "gc_clientsystem.h"
@ -185,6 +188,7 @@ IServerEngineTools *serverenginetools = NULL;
ISceneFileCache *scenefilecache = NULL;
IXboxSystem *xboxsystem = NULL; // Xbox 360 only
IMatchmaking *matchmaking = NULL; // Xbox 360 only
IScriptManager *scriptmanager = NULL;
#if defined( REPLAY_ENABLED )
IReplaySystem *g_pReplay = NULL;
IServerReplayContext *g_pReplayServerContext = NULL;
@ -627,6 +631,16 @@ bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory,
if ( IsX360() && (matchmaking = (IMatchmaking *)appSystemFactory( VENGINE_MATCHMAKING_VERSION, NULL )) == NULL )
return false;
if (!CommandLine()->CheckParm("-noscripting"))
{
scriptmanager = (IScriptManager*)appSystemFactory(VSCRIPT_INTERFACE_VERSION, NULL);
if (scriptmanager == nullptr)
{
scriptmanager = (IScriptManager*)Sys_GetFactoryThis()(VSCRIPT_INTERFACE_VERSION, NULL);
}
}
// If not running dedicated, grab the engine vgui interface
if ( !engine->IsDedicatedServer() )
{
@ -684,6 +698,7 @@ bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory,
g_pGameSaveRestoreBlockSet->AddBlockHandler( GetCommentarySaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->AddBlockHandler( GetEventQueueSaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->AddBlockHandler( GetAchievementSaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->AddBlockHandler( GetVScriptSaveRestoreBlockHandler() );
// The string system must init first + shutdown last
IGameSystem::Add( GameStringSystem() );
@ -762,6 +777,7 @@ void CServerGameDLL::DLLShutdown( void )
// Due to dependencies, these are not autogamesystems
ModelSoundsCacheShutdown();
g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetVScriptSaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetAchievementSaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetCommentarySaveRestoreBlockHandler() );
g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetEventQueueSaveRestoreBlockHandler() );

View File

@ -143,6 +143,28 @@ public:
return m_list.Count();
}
#ifdef MAPBASE_VSCRIPT
virtual void RegisterVScript()
{
g_pScriptVM->RegisterInstance( this, "Globals" );
}
int ScriptAddEntity( const char *pGlobalname, const char *pMapName, int state )
{
return AddEntity( pGlobalname, pMapName, (GLOBALESTATE)state );
}
void ScriptSetState( int globalIndex, int state )
{
SetState( globalIndex, (GLOBALESTATE)state );
}
int ScriptGetState( int globalIndex )
{
return (int)GetState( globalIndex );
}
#endif
void Reset( void );
int Save( ISave &save );
int Restore( IRestore &restore );
@ -323,3 +345,15 @@ CON_COMMAND(server_game_time, "Gives the game time in seconds (server's curtime)
ShowServerGameTime();
}
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CGlobalState, SCRIPT_SINGLETON "Global state system." )
DEFINE_SCRIPTFUNC( GetIndex, "Gets the index of the specified global name. Returns -1 if it does not exist." )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddEntity, "AddGlobal", "Adds a new global with a specific map name and state. Returns its index." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetState, "GetState", "Gets the state of the specified global." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetState, "SetState", "Sets the state of the specified global." )
DEFINE_SCRIPTFUNC( GetCounter, "Gets the counter of the specified global." )
DEFINE_SCRIPTFUNC( SetCounter, "Sets the counter of the specified global." )
DEFINE_SCRIPTFUNC( AddToCounter, "Adds to the counter of the specified global." )
END_SCRIPTDESC();
#endif

View File

@ -2457,6 +2457,16 @@ BEGIN_DATADESC( CAI_ActBusyGoal )
DEFINE_OUTPUT( m_OnNPCSeeEnemy, "OnNPCSeeEnemy" ),
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CAI_ActBusyGoal, CAI_GoalEntity, "A goal entity which makes NPCs act busy." )
DEFINE_SCRIPTFUNC_NAMED( ScriptForceBusy, "ForceBusy", "Force a NPC to act busy." )
DEFINE_SCRIPTFUNC_NAMED( ScriptForceBusyComplex, "ForceBusyComplex", "Force a NPC to act busy with additional parameters." )
DEFINE_SCRIPTFUNC_NAMED( ScriptStopBusy, "StopBusy", "Force a NPC to stop busying." )
END_SCRIPTDESC();
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -2824,6 +2834,46 @@ interval_t &CAI_ActBusyGoal::NextBusySearchInterval()
}
#endif
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_ActBusyGoal::ScriptForceBusy( HSCRIPT hNPC, HSCRIPT hHint, bool bTeleportOnly )
{
CAI_ActBusyBehavior *pBehavior = GetBusyBehaviorForNPC( ToEnt( hNPC ), "ForceBusy (vscript)" );
if ( !pBehavior )
return;
// Tell the NPC to immediately act busy
pBehavior->SetBusySearchRange( m_flBusySearchRange );
pBehavior->ForceActBusy( this, dynamic_cast<CAI_Hint*>(ToEnt( hHint )), NO_MAX_TIME, false, bTeleportOnly );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_ActBusyGoal::ScriptForceBusyComplex( HSCRIPT hNPC, HSCRIPT hHint, bool bTeleportOnly, bool bVisibleOnly, bool bUseNearestBusy, float flMaxTime, int activity, HSCRIPT pSeeEntity )
{
CAI_ActBusyBehavior *pBehavior = GetBusyBehaviorForNPC( ToEnt( hNPC ), "ForceBusyComplex (vscript)" );
if ( !pBehavior )
return;
// Tell the NPC to immediately act busy
pBehavior->SetBusySearchRange( m_flBusySearchRange );
pBehavior->ForceActBusy( this, dynamic_cast<CAI_Hint*>(ToEnt( hHint )), flMaxTime, bVisibleOnly, bTeleportOnly, bUseNearestBusy, ToEnt( pSeeEntity ), (Activity)activity );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_ActBusyGoal::ScriptStopBusy( HSCRIPT hNPC )
{
CAI_ActBusyBehavior *pBehavior = GetBusyBehaviorForNPC( ToEnt( hNPC ), "StopBusy (vscript)" );
if ( !pBehavior )
return;
// Just stop busying
pBehavior->StopBusying();
}
#endif
//==========================================================================================================
// ACT BUSY QUEUE
//==========================================================================================================

View File

@ -239,6 +239,12 @@ public:
interval_t &NextBusySearchInterval();
#endif
#ifdef MAPBASE_VSCRIPT
void ScriptForceBusy( HSCRIPT hNPC, HSCRIPT hHint, bool bTeleportOnly );
void ScriptForceBusyComplex( HSCRIPT hNPC, HSCRIPT hHint, bool bTeleportOnly, bool bVisibleOnly, bool bUseNearestBusy, float flMaxTime, int activity, HSCRIPT pSeeEntity );
void ScriptStopBusy( HSCRIPT hNPC );
#endif
protected:
CAI_ActBusyBehavior *GetBusyBehaviorForNPC( const char *pszActorName, CBaseEntity *pActivator, CBaseEntity *pCaller, const char *sInputName );
CAI_ActBusyBehavior *GetBusyBehaviorForNPC( CBaseEntity *pEntity, const char *sInputName );
@ -257,6 +263,9 @@ protected:
#endif
DECLARE_DATADESC();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
protected:
float m_flBusySearchRange;

View File

@ -593,6 +593,18 @@ BEGIN_DATADESC( CHL2_Player )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CHL2_Player, CBasePlayer, "The HL2 player entity." )
DEFINE_SCRIPTFUNC_NAMED( SuitPower_Drain, "RemoveAuxPower", "Removes from the player's available aux power." )
DEFINE_SCRIPTFUNC_NAMED( SuitPower_Charge, "AddAuxPower", "Adds to the player's available aux power." )
DEFINE_SCRIPTFUNC_NAMED( SuitPower_SetCharge, "SetAuxPower", "Sets the player's available aux power." )
DEFINE_SCRIPTFUNC_NAMED( SuitPower_GetCurrentPercentage, "GetAuxPower", "Gets the player's available aux power." )
DEFINE_SCRIPTFUNC( GetFlashlightBattery, "Gets the energy available in the player's flashlight. If the legacy (aux power-based) flashlight is enabled, this returns the aux power." )
END_SCRIPTDESC();
#endif
CHL2_Player::CHL2_Player()
{
m_nNumMissPositions = 0;
@ -4678,7 +4690,7 @@ void CLogicPlayerProxy::InputRequestPlayerFlashBattery( inputdata_t &inputdata )
// If it's the EP2 flashlight, it returns the flashlight battery. If it's the legacy flashlight, it returns the aux power.
// Note that this is on CHL2_Player, not CLogicPlayerProxy.
inline float CHL2_Player::GetFlashlightBattery()
float CHL2_Player::GetFlashlightBattery()
{
#ifdef HL2_EPISODIC
return Flashlight_UseLegacyVersion() ? SuitPower_GetCurrentPercentage() : m_HL2Local.m_flFlashBattery;

View File

@ -79,6 +79,9 @@ class CHL2_Player : public CBasePlayer
{
public:
DECLARE_CLASS( CHL2_Player, CBasePlayer );
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
CHL2_Player();
~CHL2_Player( void );

View File

@ -27,6 +27,126 @@
extern CServerGameDLL g_ServerGameDLL;
//-----------------------------------------------------------------------------
// Purpose: An entity that acts as a container for game scripts.
//-----------------------------------------------------------------------------
#define MAX_SCRIPT_GROUP 16
class CLogicScript : public CPointEntity
{
public:
DECLARE_CLASS( CLogicScript, CPointEntity );
DECLARE_DATADESC();
void RunVScripts()
{
/*
EntityGroup <- [];
function __AppendToScriptGroup( name )
{
if ( name.len() == 0 )
{
EntityGroup.append( null );
}
else
{
local ent = Entities.FindByName( null, name );
EntityGroup.append( ent );
if ( ent != null )
{
ent.ValidateScriptScope();
ent.GetScriptScope().EntityGroup <- EntityGroup;
}
}
}
*/
static const char szAddCode[] =
{
0x45,0x6e,0x74,0x69,0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x20,0x3c,0x2d,0x20,0x5b,0x5d,0x3b,0x0d,0x0a,
0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x20,0x5f,0x5f,0x41,0x70,0x70,0x65,0x6e,0x64,0x54,0x6f,0x53,
0x63,0x72,0x69,0x70,0x74,0x47,0x72,0x6f,0x75,0x70,0x28,0x20,0x6e,0x61,0x6d,0x65,0x20,0x29,0x20,0x0d,
0x0a,0x7b,0x0d,0x0a,0x09,0x69,0x66,0x20,0x28,0x20,0x6e,0x61,0x6d,0x65,0x2e,0x6c,0x65,0x6e,0x28,0x29,
0x20,0x3d,0x3d,0x20,0x30,0x20,0x29,0x20,0x0d,0x0a,0x09,0x7b,0x20,0x0d,0x0a,0x09,0x09,0x45,0x6e,0x74,
0x69,0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x2e,0x61,0x70,0x70,0x65,0x6e,0x64,0x28,0x20,0x6e,0x75,0x6c,
0x6c,0x20,0x29,0x3b,0x20,0x0d,0x0a,0x09,0x7d,0x20,0x0d,0x0a,0x09,0x65,0x6c,0x73,0x65,0x0d,0x0a,0x09,
0x7b,0x20,0x0d,0x0a,0x09,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x65,0x6e,0x74,0x20,0x3d,0x20,0x45,0x6e,
0x74,0x69,0x74,0x69,0x65,0x73,0x2e,0x46,0x69,0x6e,0x64,0x42,0x79,0x4e,0x61,0x6d,0x65,0x28,0x20,0x6e,
0x75,0x6c,0x6c,0x2c,0x20,0x6e,0x61,0x6d,0x65,0x20,0x29,0x3b,0x0d,0x0a,0x09,0x09,0x45,0x6e,0x74,0x69,
0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x2e,0x61,0x70,0x70,0x65,0x6e,0x64,0x28,0x20,0x65,0x6e,0x74,0x20,
0x29,0x3b,0x0d,0x0a,0x09,0x09,0x69,0x66,0x20,0x28,0x20,0x65,0x6e,0x74,0x20,0x21,0x3d,0x20,0x6e,0x75,
0x6c,0x6c,0x20,0x29,0x0d,0x0a,0x09,0x09,0x7b,0x0d,0x0a,0x09,0x09,0x09,0x65,0x6e,0x74,0x2e,0x56,0x61,
0x6c,0x69,0x64,0x61,0x74,0x65,0x53,0x63,0x72,0x69,0x70,0x74,0x53,0x63,0x6f,0x70,0x65,0x28,0x29,0x3b,
0x0d,0x0a,0x09,0x09,0x09,0x65,0x6e,0x74,0x2e,0x47,0x65,0x74,0x53,0x63,0x72,0x69,0x70,0x74,0x53,0x63,
0x6f,0x70,0x65,0x28,0x29,0x2e,0x45,0x6e,0x74,0x69,0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x20,0x3c,0x2d,
0x20,0x45,0x6e,0x74,0x69,0x74,0x79,0x47,0x72,0x6f,0x75,0x70,0x3b,0x0d,0x0a,0x09,0x09,0x7d,0x0d,0x0a,
0x09,0x7d,0x0d,0x0a,0x7d,0x0d,0x0a,0x00
};
int iLastMember;
for ( iLastMember = MAX_SCRIPT_GROUP - 1; iLastMember >= 0; iLastMember-- )
{
if ( m_iszGroupMembers[iLastMember] != NULL_STRING )
{
break;
}
}
if ( iLastMember >= 0 )
{
HSCRIPT hAddScript = g_pScriptVM->CompileScript( szAddCode );
if ( hAddScript )
{
ValidateScriptScope();
m_ScriptScope.Run( hAddScript );
HSCRIPT hAddFunc = m_ScriptScope.LookupFunction( "__AppendToScriptGroup" );
if ( hAddFunc )
{
for ( int i = 0; i <= iLastMember; i++ )
{
m_ScriptScope.Call( hAddFunc, NULL, STRING(m_iszGroupMembers[i]) );
}
g_pScriptVM->ReleaseFunction( hAddFunc );
m_ScriptScope.ClearValue( "__AppendToScriptGroup" );
}
g_pScriptVM->ReleaseScript( hAddScript );
}
}
BaseClass::RunVScripts();
}
string_t m_iszGroupMembers[MAX_SCRIPT_GROUP];
};
LINK_ENTITY_TO_CLASS( logic_script, CLogicScript );
BEGIN_DATADESC( CLogicScript )
// Silence, Classcheck!
// DEFINE_ARRAY( m_iszGroupMembers, FIELD_STRING, MAX_NUM_TEMPLATES ),
DEFINE_KEYFIELD( m_iszGroupMembers[0], FIELD_STRING, "Group00"),
DEFINE_KEYFIELD( m_iszGroupMembers[1], FIELD_STRING, "Group01"),
DEFINE_KEYFIELD( m_iszGroupMembers[2], FIELD_STRING, "Group02"),
DEFINE_KEYFIELD( m_iszGroupMembers[3], FIELD_STRING, "Group03"),
DEFINE_KEYFIELD( m_iszGroupMembers[4], FIELD_STRING, "Group04"),
DEFINE_KEYFIELD( m_iszGroupMembers[5], FIELD_STRING, "Group05"),
DEFINE_KEYFIELD( m_iszGroupMembers[6], FIELD_STRING, "Group06"),
DEFINE_KEYFIELD( m_iszGroupMembers[7], FIELD_STRING, "Group07"),
DEFINE_KEYFIELD( m_iszGroupMembers[8], FIELD_STRING, "Group08"),
DEFINE_KEYFIELD( m_iszGroupMembers[9], FIELD_STRING, "Group09"),
DEFINE_KEYFIELD( m_iszGroupMembers[10], FIELD_STRING, "Group10"),
DEFINE_KEYFIELD( m_iszGroupMembers[11], FIELD_STRING, "Group11"),
DEFINE_KEYFIELD( m_iszGroupMembers[12], FIELD_STRING, "Group12"),
DEFINE_KEYFIELD( m_iszGroupMembers[13], FIELD_STRING, "Group13"),
DEFINE_KEYFIELD( m_iszGroupMembers[14], FIELD_STRING, "Group14"),
DEFINE_KEYFIELD( m_iszGroupMembers[15], FIELD_STRING, "Group15"),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Compares a set of integer inputs to the one main input
@ -3679,7 +3799,8 @@ BEGIN_DATADESC( CLogicConsole )
END_DATADESC()
ConVar sv_allow_logic_convar("sv_allow_logic_convar", "1");
ConVar sv_allow_logic_convar( "sv_allow_logic_convar", "1", FCVAR_NOT_CONNECTED );
//-----------------------------------------------------------------------------
// Purpose: Gets console variables for the evil mapper.
//-----------------------------------------------------------------------------

View File

@ -91,8 +91,9 @@ void CV_InitMod()
void CVEnt_Precache(CMapbaseCVarModEntity *modent)
{
if (Q_strstr(STRING(modent->m_target), "sv_allow_logic_convar"))
return;
// Now protected by FCVAR_NOT_CONNECTED
//if (Q_strstr(STRING(modent->m_target), "sv_allow_logic_convar"))
// return;
#ifdef MAPBASE_MP
if (gpGlobals->maxClients > 1 && !modent->m_bUseServer)

View File

@ -16,6 +16,9 @@ class CLogicExternalData : public CLogicalEntity
{
DECLARE_CLASS( CLogicExternalData, CLogicalEntity );
DECLARE_DATADESC();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
public:
~CLogicExternalData();
@ -34,6 +37,16 @@ public:
void InputSave( inputdata_t &inputdata );
void InputReload( inputdata_t &inputdata );
#ifdef MAPBASE_VSCRIPT
HSCRIPT ScriptGetKeyValues( void );
HSCRIPT ScriptGetKeyValueBlock( void );
void ScriptSetKeyValues( HSCRIPT hKV );
void ScriptSetKeyValueBlock( HSCRIPT hKV );
void ScriptSetBlock( const char *szNewBlock, HSCRIPT hActivator = NULL, HSCRIPT hCaller = NULL );
#endif
char m_iszFile[MAX_PATH];
// Root file
@ -76,6 +89,21 @@ BEGIN_DATADESC( CLogicExternalData )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CLogicExternalData, CBaseEntity, "An entity which loads keyvalues from an external data file." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValues, "GetKeyValues", "Gets the external data expressed in CScriptKeyValues." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueBlock, "GetKeyValueBlock", "Gets the current external data block expressed in CScriptKeyValues." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValues, "SetKeyValues", "Sets the external data from a CScriptKeyValues object." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValueBlock, "SetKeyValues", "Sets the current external data block from a CScriptKeyValues object." )
DEFINE_SCRIPTFUNC( LoadFile, "Loads external data from the external file." )
DEFINE_SCRIPTFUNC( SaveFile, "Saves the external data to the external file." )
END_SCRIPTDESC();
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -243,3 +271,95 @@ void CLogicExternalData::InputReload( inputdata_t &inputdata )
{
LoadFile();
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CLogicExternalData::ScriptGetKeyValues( void )
{
if (m_bReloadBeforeEachAction)
LoadFile();
HSCRIPT hScript = NULL;
if (m_pRoot)
{
// Does this need to be destructed or freed? m_pScriptModelKeyValues apparently doesn't.
CScriptKeyValues *pKV = new CScriptKeyValues( m_pRoot );
hScript = g_pScriptVM->RegisterInstance( pKV );
}
return hScript;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CLogicExternalData::ScriptGetKeyValueBlock( void )
{
if (m_bReloadBeforeEachAction)
LoadFile();
HSCRIPT hScript = NULL;
if (m_pBlock)
{
// Does this need to be destructed or freed? m_pScriptModelKeyValues apparently doesn't.
CScriptKeyValues *pKV = new CScriptKeyValues( m_pBlock );
hScript = g_pScriptVM->RegisterInstance( pKV );
}
return hScript;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CLogicExternalData::ScriptSetKeyValues( HSCRIPT hKV )
{
if (m_pRoot)
{
m_pRoot->deleteThis();
m_pRoot = NULL;
}
CScriptKeyValues *pKV = HScriptToClass<CScriptKeyValues>( hKV );
if (pKV)
{
m_pRoot = pKV->m_pKeyValues;
}
}
void CLogicExternalData::ScriptSetKeyValueBlock( HSCRIPT hKV )
{
if (m_pBlock)
{
m_pBlock->deleteThis();
m_pBlock = NULL;
}
CScriptKeyValues *pKV = HScriptToClass<CScriptKeyValues>( hKV );
if (pKV)
{
m_pBlock = pKV->m_pKeyValues;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CLogicExternalData::ScriptSetBlock( const char *szNewBlock, HSCRIPT hActivator, HSCRIPT hCaller )
{
CBaseEntity *pActivator = ToEnt( hActivator );
CBaseEntity *pCaller = ToEnt( hCaller );
string_t iszNewTarget = AllocPooledString(szNewBlock);
if (STRING(iszNewTarget)[0] == '!')
{
if (FStrEq(STRING(iszNewTarget), "!self"))
iszNewTarget = GetEntityName();
else if (pActivator && FStrEq(STRING(iszNewTarget), "!activator"))
iszNewTarget = pActivator->GetEntityName();
else if (pCaller && FStrEq(STRING(iszNewTarget), "!caller"))
iszNewTarget = pCaller->GetEntityName();
}
m_target = iszNewTarget;
LoadFile();
}
#endif

View File

@ -18,6 +18,8 @@
#include "IEffects.h"
#include "props.h"
#include "point_template.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -114,6 +116,8 @@ END_DATADESC()
//-----------------------------------------------------------------------------
void CBaseNPCMaker::Spawn( void )
{
ScriptInstallPreSpawnHook();
SetSolid( SOLID_NONE );
m_nLiveChildren = 0;
Precache();
@ -830,6 +834,12 @@ void CTemplateNPCMaker::MakeNPC( void )
pent->SetAbsAngles( angles );
}
if ( !ScriptPreInstanceSpawn( &m_ScriptScope, pEntity, m_iszTemplateData ) )
{
UTIL_RemoveImmediate( pEntity );
return;
}
m_OnSpawnNPC.Set( pEntity, pEntity, this );
if ( m_spawnflags & SF_NPCMAKER_FADE )
@ -867,6 +877,8 @@ void CTemplateNPCMaker::MakeNPC( void )
SetUse( NULL );
}
}
ScriptPostSpawn( &m_ScriptScope, &pEntity, 1 );
}
//-----------------------------------------------------------------------------

View File

@ -478,6 +478,33 @@ BEGIN_DATADESC( CBasePlayer )
// DEFINE_UTLVECTOR( m_vecPlayerSimInfo ),
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptIsPlayerNoclipping, "IsNoclipping", "Returns true if the player is in noclip mode." )
DEFINE_SCRIPTFUNC_NAMED( VScriptGetExpresser, "GetExpresser", "Gets a handle for this player's expresser." )
DEFINE_SCRIPTFUNC( FragCount, "Gets the number of frags (kills) this player has in a multiplayer game." )
DEFINE_SCRIPTFUNC( DeathCount, "Gets the number of deaths this player has had in a multiplayer game." )
DEFINE_SCRIPTFUNC( IsConnected, "Returns true if this player is connected." )
DEFINE_SCRIPTFUNC( IsDisconnecting, "Returns true if this player is disconnecting." )
DEFINE_SCRIPTFUNC( IsSuitEquipped, "Returns true if this player had the HEV suit equipped." )
DEFINE_SCRIPTFUNC_NAMED( ArmorValue, "GetArmor", "Gets the player's armor." )
DEFINE_SCRIPTFUNC_NAMED( SetArmorValue, "SetArmor", "Sets the player's armor." )
DEFINE_SCRIPTFUNC( FlashlightIsOn, "Returns true if the flashlight is on." )
DEFINE_SCRIPTFUNC( FlashlightTurnOn, "Turns on the flashlight." )
DEFINE_SCRIPTFUNC( FlashlightTurnOff, "Turns off the flashlight." )
END_SCRIPTDESC();
#else
BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseAnimating, "The player entity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptIsPlayerNoclipping, "IsNoclipping", "Returns true if the player is in noclip mode." )
END_SCRIPTDESC();
#endif
int giPrecacheGrunt = 0;
edict_t *CBasePlayer::s_PlayerEdict = NULL;
@ -690,6 +717,11 @@ CBasePlayer::~CBasePlayer( )
//-----------------------------------------------------------------------------
void CBasePlayer::UpdateOnRemove( void )
{
if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM )
{
g_pScriptVM->SetValue( "player", SCRIPT_VARIANT_NULL );
}
VPhysicsDestroyObject();
// Remove him from his current team
@ -5110,6 +5142,11 @@ void CBasePlayer::Spawn( void )
UpdateLastKnownArea();
m_weaponFiredTimer.Invalidate();
if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM )
{
g_pScriptVM->SetValue( "player", GetScriptInstance() );
}
}
void CBasePlayer::Activate( void )
@ -5300,6 +5337,14 @@ void CBasePlayer::OnRestore( void )
m_nVehicleViewSavedFrame = 0;
m_nBodyPitchPoseParam = LookupPoseParameter( "body_pitch" );
// HACK: (03/25/09) Then the player goes across a transition it doesn't spawn and register
// it's instance. We're hacking around this for now, but this will go away when we get around to
// having entities cross transitions and keep their script state.
if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM && (gpGlobals->eLoadType == MapLoad_Transition) )
{
g_pScriptVM->SetValue( "player", GetScriptInstance() );
}
}
/* void CBasePlayer::SetTeamName( const char *pTeamName )
@ -6864,6 +6909,30 @@ void CBasePlayer::ShowCrosshair( bool bShow )
}
}
//-----------------------------------------------------------------------------
// Used by vscript to determine if the player is noclipping
//-----------------------------------------------------------------------------
bool CBasePlayer::ScriptIsPlayerNoclipping(void)
{
return (GetMoveType() == MOVETYPE_NOCLIP);
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBasePlayer::VScriptGetExpresser()
{
HSCRIPT hScript = NULL;
CAI_Expresser *pExpresser = GetExpresser();
if (pExpresser)
{
hScript = g_pScriptVM->RegisterInstance( pExpresser );
}
return hScript;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------

View File

@ -244,6 +244,8 @@ protected:
public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
// script description
DECLARE_ENT_SCRIPTDESC();
CBasePlayer();
~CBasePlayer();
@ -386,6 +388,12 @@ public:
void ShowViewModel( bool bShow );
void ShowCrosshair( bool bShow );
bool ScriptIsPlayerNoclipping(void);
#ifdef MAPBASE_VSCRIPT
HSCRIPT VScriptGetExpresser();
#endif
// View model prediction setup
void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov );

View File

@ -53,24 +53,6 @@ END_DATADESC()
LINK_ENTITY_TO_CLASS( point_devshot_camera, CPointDevShotCamera );
//-----------------------------------------------------------------------------
// Purpose: Convenience function so we don't have to make this check all over
//-----------------------------------------------------------------------------
static CBasePlayer * UTIL_GetLocalPlayerOrListenServerHost( void )
{
if ( gpGlobals->maxClients > 1 )
{
if ( engine->IsDedicatedServer() )
{
return NULL;
}
return UTIL_GetListenServerHost();
}
return UTIL_GetLocalPlayer();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------

View File

@ -133,6 +133,8 @@ void PrecachePointTemplates()
void CPointTemplate::Spawn( void )
{
Precache();
ScriptInstallPreSpawnHook();
ValidateScriptScope();
}
void CPointTemplate::Precache()
@ -345,7 +347,7 @@ bool CPointTemplate::CreateInstance( const Vector &vecOrigin, const QAngle &vecA
// Some templates have Entity I/O connecting the entities within the template.
// Unique versions of these templates need to be created whenever they're instanced.
if ( AllowNameFixup() && Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) )
if ( AllowNameFixup() && ( Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) || m_ScriptScope.IsInitialized() ) )
{
// This template requires instancing.
// Create a new mapdata block and ask the template system to fill it in with
@ -381,7 +383,15 @@ bool CPointTemplate::CreateInstance( const Vector &vecOrigin, const QAngle &vecA
pEntity->SetAbsOrigin( vecNewOrigin );
pEntity->SetAbsAngles( vecNewAngles );
pSpawnList[i].m_pEntity = pEntity;
if (ScriptPreInstanceSpawn(&m_ScriptScope, pEntity, Templates_FindByIndex(iTemplateIndex)))
{
pSpawnList[i].m_pEntity = pEntity;
}
else
{
pSpawnList[i].m_pEntity = NULL;
UTIL_RemoveImmediate(pEntity);
}
pSpawnList[i].m_nDepth = 0;
pSpawnList[i].m_pDeferredParent = NULL;
}
@ -426,7 +436,7 @@ bool CPointTemplate::CreateSpecificInstance( int iTemplate, const Vector &vecOri
// Some templates have Entity I/O connecting the entities within the template.
// Unique versions of these templates need to be created whenever they're instanced.
if ( AllowNameFixup() && Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) )
if ( AllowNameFixup() && ( Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) || m_ScriptScope.IsInitialized() ) )
{
// This template requires instancing.
// Create a new mapdata block and ask the template system to fill it in with
@ -474,6 +484,17 @@ bool CPointTemplate::CreateSpecificInstance( int iTemplate, const Vector &vecOri
}
#endif
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CPointTemplate::CreationComplete( const CUtlVector<CBaseEntity*> &entities )
{
if ( !entities.Count() )
return;
ScriptPostSpawn( &m_ScriptScope, (CBaseEntity **)entities.Base(), entities.Count() );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
@ -514,3 +535,72 @@ void CPointTemplate::InputForceSpawnRandomTemplate( inputdata_t &inputdata )
m_pOutputOutEntity.Set(pEntity, pEntity, this);
}
#endif
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void ScriptInstallPreSpawnHook()
{
#ifdef IS_WINDOWS_PC
if ( !g_pScriptVM->ValueExists( "__ExecutePreSpawn " ) )
{
//g_pScriptVM->Run( g_Script_spawn_helper );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: This function is called after a spawner creates its child entity
// but before the keyvalues are injected. This gives us an
// opportunity to change any keyvalues before the entity is
// configured and spawned. In this case, we see if there is a VScript
// that wants to change anything about this entity.
//-----------------------------------------------------------------------------
bool ScriptPreInstanceSpawn( CScriptScope *pScriptScope, CBaseEntity *pChild, string_t iszKeyValueData )
{
if ( !pScriptScope->IsInitialized() )
return true;
ScriptVariant_t result;
if ( pScriptScope->Call( "__ExecutePreSpawn", &result, ToHScript( pChild ) ) != SCRIPT_DONE )
return true;
if ( ( result.m_type == FIELD_BOOLEAN && !result.m_bool ) || ( result.m_type == FIELD_INTEGER && !result.m_int ) )
return false;
return true;
}
void ScriptPostSpawn( CScriptScope *pScriptScope, CBaseEntity **ppEntities, int nEntities )
{
if ( !pScriptScope->IsInitialized() )
return;
HSCRIPT hPostSpawnFunc = pScriptScope->LookupFunction( "PostSpawn" );
if ( !hPostSpawnFunc )
return;
ScriptVariant_t varEntityMakerResultTable;
if ( !g_pScriptVM->GetValue( *pScriptScope, "__EntityMakerResult", &varEntityMakerResultTable ) )
return;
if ( varEntityMakerResultTable.m_type != FIELD_HSCRIPT )
return;
HSCRIPT hEntityMakerResultTable = varEntityMakerResultTable.m_hScript;
char szEntName[256];
for ( int i = 0; i < nEntities; i++ )
{
V_strncpy( szEntName, ppEntities[i]->GetEntityNameAsCStr(), ARRAYSIZE(szEntName) );
char *pAmpersand = V_strrchr( szEntName, '&' );
if ( pAmpersand )
*pAmpersand = 0;
g_pScriptVM->SetValue( hEntityMakerResultTable, szEntName, ToHScript( ppEntities[i] ) );
}
pScriptScope->Call( hPostSpawnFunc, NULL, hEntityMakerResultTable );
pScriptScope->Call( "__FinishSpawn" );
g_pScriptVM->ReleaseValue( varEntityMakerResultTable );
g_pScriptVM->ReleaseFunction( hPostSpawnFunc );
}

View File

@ -20,6 +20,10 @@ struct template_t
DECLARE_SIMPLE_DATADESC();
};
void ScriptInstallPreSpawnHook();
bool ScriptPreInstanceSpawn( CScriptScope *pScriptScope, CBaseEntity *pChild, string_t iszKeyValueData );
void ScriptPostSpawn( CScriptScope *pScriptScope, CBaseEntity **ppEntities, int nEntities );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -52,6 +56,7 @@ public:
#ifdef MAPBASE
bool CreateSpecificInstance( int iTemplate, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity **pOutEntity );
#endif
void CreationComplete(const CUtlVector<CBaseEntity*>& entities);
// Inputs
void InputForceSpawn( inputdata_t &inputdata );

View File

@ -33,6 +33,8 @@
#include "SceneCache.h"
#include "scripted.h"
#include "env_debughistory.h"
#include "team.h"
#include "triggers.h"
#ifdef HL2_EPISODIC
#include "npc_alyx_episodic.h"
@ -323,6 +325,8 @@ public:
DECLARE_CLASS( CSceneEntity, CPointEntity );
DECLARE_SERVERCLASS();
// script description
DECLARE_ENT_SCRIPTDESC();
CSceneEntity( void );
~CSceneEntity( void );
@ -470,6 +474,8 @@ public:
void InputScriptPlayerDeath( inputdata_t &inputdata );
void AddBroadcastTeamTarget( int nTeamIndex );
void RemoveBroadcastTeamTarget( int nTeamIndex );
// Data
public:
string_t m_iszSceneFile;
@ -543,6 +549,9 @@ public:
virtual CBaseEntity *FindNamedEntity( const char *name, CBaseEntity *pActor = NULL, bool bBaseFlexOnly = false, bool bUseClear = false );
CBaseEntity *FindNamedTarget( string_t iszTarget, bool bBaseFlexOnly = false );
virtual CBaseEntity *FindNamedEntityClosest( const char *name, CBaseEntity *pActor = NULL, bool bBaseFlexOnly = false, bool bUseClear = false, const char *pszSecondary = NULL );
HSCRIPT ScriptFindNamedEntity( const char *name );
bool ScriptLoadSceneFromString( const char * pszFilename, const char *pszData );
private:
@ -764,6 +773,17 @@ BEGIN_DATADESC( CSceneEntity )
DEFINE_OUTPUT( m_OnTrigger16, "OnTrigger16"),
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( CSceneEntity, CBaseEntity, "Choreographed scene which controls animation and/or dialog on one or more actors." )
DEFINE_SCRIPTFUNC( EstimateLength, "Returns length of this scene in seconds." )
DEFINE_SCRIPTFUNC( IsPlayingBack, "If this scene is currently playing." )
DEFINE_SCRIPTFUNC( IsPaused, "If this scene is currently paused." )
DEFINE_SCRIPTFUNC( AddBroadcastTeamTarget, "Adds a team (by index) to the broadcast list" )
DEFINE_SCRIPTFUNC( RemoveBroadcastTeamTarget, "Removes a team (by index) from the broadcast list" )
DEFINE_SCRIPTFUNC_NAMED( ScriptFindNamedEntity, "FindNamedEntity", "given an entity reference, such as !target, get actual entity from scene object" )
DEFINE_SCRIPTFUNC_NAMED( ScriptLoadSceneFromString, "LoadSceneFromString", "given a dummy scene name and a vcd string, load the scene" )
END_SCRIPTDESC();
const ConVar *CSceneEntity::m_pcvSndMixahead = NULL;
//-----------------------------------------------------------------------------
@ -3066,7 +3086,7 @@ void CSceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEv
CBaseFlex *pActor = NULL;
CChoreoActor *actor = event->GetActor();
if ( actor )
if ( actor && (event->GetType() != CChoreoEvent::SCRIPT) && (event->GetType() != CChoreoEvent::CAMERA) )
{
pActor = FindNamedActor( actor );
if (pActor == NULL)
@ -3229,6 +3249,80 @@ void CSceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEv
}
}
break;
case CChoreoEvent::CAMERA:
{
// begin the camera shot
const char *pszShotType = event->GetParameters();
CBaseEntity *pActor1 = FindNamedEntity( event->GetParameters2( ), pActor );
CBaseEntity *pActor2 = FindNamedEntity( event->GetParameters3( ), pActor );
float duration = event->GetDuration();
// grab any camera we find in the map
// TODO: find camera that is nearest this scene entity?
CTriggerCamera *pCamera = (CTriggerCamera *)gEntList.FindEntityByClassname( NULL, "point_viewcontrol" );
if ( !pCamera )
{
Warning( "CSceneEntity %s unable to find a camera (point_viewcontrol) in this map!\n", STRING(GetEntityName()) );
}
else
{
pCamera->StartCameraShot( pszShotType, this, pActor1, pActor2, duration );
}
}
break;
case CChoreoEvent::SCRIPT:
{
// NOTE: this is only used by auto-generated vcds to embed script commands to map entities.
// vscript call - param1 is entity name, param2 is function name, param3 is function parameter string
// calls a vscript function defined on the scope of the named CBaseEntity object/actor.
// script call is of the format FunctionName(pActor, pThisSceneEntity, pszScriptParameters, duration)
const char *pszActorName = event->GetParameters();
const char *pszFunctionName = event->GetParameters2();
const char *pszScriptParameters = event->GetParameters3();
float duration = event->GetDuration();
// TODO: should be new method CBaseEntity::CallScriptFunctionParams()
CBaseEntity *pEntity = (CBaseEntity *)gEntList.FindEntityByName( NULL, pszActorName );
//START_VMPROFILE
if ( !pEntity )
{
Warning( "CSceneEntity::SCRIPT event - unable to find entity named '%s' in this map!\n", pszActorName );
}
else
{
if( !pEntity->ValidateScriptScope() )
{
DevMsg("\n***\nCChoreoEvent::SCRIPT - FAILED to create private ScriptScope. ABORTING script call\n***\n");
break;
}
HSCRIPT hFunc = pEntity->m_ScriptScope.LookupFunction( pszFunctionName );
if( hFunc )
{
pEntity->m_ScriptScope.Call( hFunc, NULL, ToHScript(this), pszScriptParameters, duration );
pEntity->m_ScriptScope.ReleaseFunction( hFunc );
//UPDATE_VMPROFILE
}
else
{
Warning("CSceneEntity::SCRIPT event - '%s' entity has no script function '%s' defined!\n", pszActorName,pszFunctionName);
}
}
}
break;
case CChoreoEvent::FIRETRIGGER:
{
if ( IsMultiplayer() )
@ -3437,6 +3531,19 @@ void CSceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEven
}
}
break;
case CChoreoEvent::CAMERA:
{
// call the end of camera or call a dispatch function
}
break;
case CChoreoEvent::SCRIPT:
{
// call the end of script or call a dispatch function
}
break;
case CChoreoEvent::SEQUENCE:
{
if ( pActor )
@ -4268,6 +4375,53 @@ CBaseEntity *CSceneEntity::FindNamedEntityClosest( const char *name, CBaseEntity
}
HSCRIPT CSceneEntity::ScriptFindNamedEntity(const char* name)
{
return ToHScript(FindNamedEntity(name, NULL, false, false));
}
//-----------------------------------------------------------------------------
// Purpose: vscript - create a scene directly from a buffer containing
// a vcd description, and load it into the scene entity.
//-----------------------------------------------------------------------------
bool CSceneEntity::ScriptLoadSceneFromString(const char* pszFilename, const char* pszData)
{
CChoreoScene* pScene = new CChoreoScene(NULL);
// CSceneTokenProcessor SceneTokenProcessor;
// SceneTokenProcessor.SetBuffer( pszData );
g_TokenProcessor.SetBuffer((char*)pszData);
if (!pScene->ParseFromBuffer(pszFilename, &g_TokenProcessor)) //&SceneTokenProcessor ) )
{
Warning("CSceneEntity::LoadSceneFromString: Unable to parse scene data '%s'\n", pszFilename);
delete pScene;
pScene = NULL;
}
else
{
pScene->SetPrintFunc(LocalScene_Printf);
pScene->SetEventCallbackInterface(this);
// precache all sounds for the newly constructed scene
PrecacheScene(pScene);
}
if (pScene != NULL)
{
// release prior scene if present
UnloadScene();
m_pScene = pScene;
return true;
}
else
{
return false;
}
}
//-----------------------------------------------------------------------------
// Purpose: Remove all "scene" expressions from all actors in this scene
//-----------------------------------------------------------------------------
@ -4691,6 +4845,44 @@ void CSceneEntity::SetRecipientFilter( IRecipientFilter *filter )
}
}
//-----------------------------------------------------------------------------
// Purpose: Adds a player (by index) to the recipient filter
//-----------------------------------------------------------------------------
void CSceneEntity::AddBroadcastTeamTarget(int nTeamIndex)
{
if (m_pRecipientFilter == NULL)
{
CRecipientFilter filter;
SetRecipientFilter(&filter);
}
CTeam* pTeam = GetGlobalTeam(nTeamIndex);
Assert(pTeam);
if (pTeam == NULL)
return;
m_pRecipientFilter->AddRecipientsByTeam(pTeam);
}
//-----------------------------------------------------------------------------
// Purpose: Removes a player (by index) from the recipient filter
//-----------------------------------------------------------------------------
void CSceneEntity::RemoveBroadcastTeamTarget(int nTeamIndex)
{
if (m_pRecipientFilter == NULL)
{
CRecipientFilter filter;
SetRecipientFilter(&filter);
}
CTeam* pTeam = GetGlobalTeam(nTeamIndex);
Assert(pTeam);
if (pTeam == NULL)
return;
m_pRecipientFilter->RemoveRecipientsByTeam(pTeam);
}
//-----------------------------------------------------------------------------
// Purpose:
@ -4986,6 +5178,26 @@ int GetSceneSpeechCount( char const *pszScene )
return 0;
}
HSCRIPT ScriptCreateSceneEntity( const char* pszScene )
{
if ( IsEntityCreationAllowedInScripts() == false )
{
Warning( "VScript error: A script attempted to create a scene entity mid-game. Entity creation from scripts is only allowed during map init.\n" );
return NULL;
}
g_pScriptVM->RegisterClass( GetScriptDescForClass( CSceneEntity ) );
CSceneEntity *pScene = (CSceneEntity *)CBaseEntity::CreateNoSpawn( "logic_choreographed_scene", vec3_origin, vec3_angle );
if ( pScene )
{
pScene->m_iszSceneFile = AllocPooledString( pszScene );
DispatchSpawn( pScene );
}
return ToHScript( pScene );
}
#ifdef MAPBASE
CON_COMMAND(mapbase_scene_precache, "Just work")
{

View File

@ -48,6 +48,7 @@ int GetSceneSpeechCount( char const *pszScene );
bool IsInInterruptableScenes( CBaseFlex *pActor );
void PrecacheInstancedScene( char const *pszScene );
HSCRIPT ScriptCreateSceneEntity( char const *pszScene );
char const *GetSceneFilename( CBaseEntity *ent );
void ReloadSceneFromDisk( CBaseEntity *ent );

View File

@ -648,6 +648,11 @@ $Project
$File "$SRCDIR\game\shared\voice_common.h"
$File "$SRCDIR\game\shared\voice_gamemgr.cpp"
$File "$SRCDIR\game\shared\voice_gamemgr.h"
$File "vscript_server.cpp"
$File "vscript_server.h"
$File "vscript_server.nut"
$File "$SRCDIR\game\shared\vscript_shared.cpp"
$File "$SRCDIR\game\shared\vscript_shared.h"
$File "waterbullet.cpp"
$File "waterbullet.h"
$File "WaterLODControl.cpp"

View File

@ -31,6 +31,9 @@ $Project
$File "$SRCDIR\game\shared\mapbase\MapEdit.h"
$File "$SRCDIR\game\shared\mapbase\matchers.cpp"
$File "$SRCDIR\game\shared\mapbase\matchers.h"
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_math.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_hl2.cpp" [$MAPBASE_VSCRIPT]
$File "mapbase\ai_grenade.cpp"
$File "mapbase\ai_grenade.h"
@ -81,4 +84,9 @@ $Project
}
}
}
$Folder "Link Libraries"
{
$Lib "vscript" [$MAPBASE_VSCRIPT]
}
}

View File

@ -2978,94 +2978,6 @@ void CAI_ChangeHintGroup::InputActivate( inputdata_t &inputdata )
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CTriggerCamera : public CBaseEntity
{
public:
DECLARE_CLASS( CTriggerCamera, CBaseEntity );
#ifdef MAPBASE
CTriggerCamera();
void UpdateOnRemove();
#endif
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
void Enable( void );
void Disable( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void FollowTarget( void );
#ifdef MAPBASE
void MoveThink( void );
#endif
void Move(void);
// Always transmit to clients so they know where to move the view to
virtual int UpdateTransmitState();
DECLARE_DATADESC();
// Input handlers
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
#ifdef MAPBASE
void InputSetFOV( inputdata_t &inputdata );
void InputSetFOVRate( inputdata_t &inputdata );
#endif
private:
EHANDLE m_hPlayer;
EHANDLE m_hTarget;
// used for moving the camera along a path (rail rides)
CBaseEntity *m_pPath;
string_t m_sPath;
float m_flWait;
float m_flReturnTime;
float m_flStopTime;
float m_moveDistance;
float m_targetSpeed;
float m_initialSpeed;
float m_acceleration;
float m_deceleration;
int m_state;
Vector m_vecMoveDir;
#ifdef MAPBASE
float m_fov;
float m_fovSpeed;
bool m_bDontSetPlayerView;
#endif
string_t m_iszTargetAttachment;
int m_iAttachmentIndex;
bool m_bSnapToGoal;
#if HL2_EPISODIC
bool m_bInterpolatePosition;
// these are interpolation vars used for interpolating the camera over time
Vector m_vStartPos, m_vEndPos;
float m_flInterpStartTime;
const static float kflPosInterpTime; // seconds
#endif
int m_nPlayerButtons;
int m_nOldTakeDamage;
private:
COutputEvent m_OnEndFollow;
#ifdef MAPBASE
COutputEvent m_OnStartFollow;
#endif
};
#if HL2_EPISODIC
const float CTriggerCamera::kflPosInterpTime = 2.0f;
#endif
@ -3127,6 +3039,12 @@ BEGIN_DATADESC( CTriggerCamera )
END_DATADESC()
// VScript: publish class and select members to script language
BEGIN_ENT_SCRIPTDESC( CTriggerCamera, CBaseEntity, "Server-side camera entity" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetFov, "GetFov", "get camera's current fov setting as integer" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetFov, "SetFov", "set camera's current fov in integer degrees and fov change rate as float" )
END_SCRIPTDESC();
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
@ -3641,6 +3559,59 @@ void CTriggerCamera::FollowTarget( )
Move();
}
void CTriggerCamera::StartCameraShot( const char *pszShotType, CBaseEntity *pSceneEntity, CBaseEntity *pActor1, CBaseEntity *pActor2, float duration )
{
// called from SceneEntity in response to a CChoreoEvent::CAMERA sent from a VCD.
// talk to vscript, start a camera move
HSCRIPT hStartCameraShot = NULL;
// switch to this camera
// Enable();
// get script module associated with this ent, lookup function in module
if( m_iszVScripts != NULL_STRING )
{
hStartCameraShot = m_ScriptScope.LookupFunction( "ScriptStartCameraShot" );
}
// call the script function to begin the camera move
if ( hStartCameraShot )
{
g_pScriptVM->Call( hStartCameraShot, m_ScriptScope, true, NULL, pszShotType, ToHScript(pSceneEntity), ToHScript(pActor1), ToHScript(pActor2), duration );
g_pScriptVM->ReleaseFunction( hStartCameraShot );
}
}
//-----------------------------------------------------------------------------
// Purpose: vscript callback to get the player's fov
//-----------------------------------------------------------------------------
int CTriggerCamera::ScriptGetFov(void)
{
if (m_hPlayer)
{
CBasePlayer* pBasePlayer = (CBasePlayer*)m_hPlayer.Get();
int iFOV = pBasePlayer->GetFOV();
return iFOV;
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: vscript callback to slam the player's fov
//-----------------------------------------------------------------------------
void CTriggerCamera::ScriptSetFov(int iFOV, float fovSpeed)
{
if (m_hPlayer)
{
m_fov = iFOV;
m_fovSpeed = fovSpeed;
CBasePlayer* pBasePlayer = (CBasePlayer*)m_hPlayer.Get();
pBasePlayer->SetFOV(this, iFOV, fovSpeed);
}
}
#ifdef MAPBASE
void CTriggerCamera::MoveThink()
{

View File

@ -244,4 +244,98 @@ public:
CUtlVector<EHANDLE> m_hurtEntities;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CTriggerCamera : public CBaseEntity
{
public:
DECLARE_CLASS( CTriggerCamera, CBaseEntity );
// script description
DECLARE_ENT_SCRIPTDESC();
#ifdef MAPBASE
CTriggerCamera();
void UpdateOnRemove();
#endif
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
void Enable( void );
void Disable( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void FollowTarget( void );
void StartCameraShot( const char *pszShotType, CBaseEntity *pSceneEntity, CBaseEntity *pActor1, CBaseEntity *pActor2, float duration );
int ScriptGetFov(void);
void ScriptSetFov(int iFOV, float rate);
#ifdef MAPBASE
void MoveThink( void );
#endif
void Move(void);
// Always transmit to clients so they know where to move the view to
virtual int UpdateTransmitState();
DECLARE_DATADESC();
// Input handlers
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
#ifdef MAPBASE
void InputSetFOV( inputdata_t &inputdata );
void InputSetFOVRate( inputdata_t &inputdata );
#endif
private:
EHANDLE m_hPlayer;
EHANDLE m_hTarget;
// used for moving the camera along a path (rail rides)
CBaseEntity *m_pPath;
string_t m_sPath;
float m_flWait;
float m_flReturnTime;
float m_flStopTime;
float m_moveDistance;
float m_targetSpeed;
float m_initialSpeed;
float m_acceleration;
float m_deceleration;
int m_state;
Vector m_vecMoveDir;
#ifdef MAPBASE
float m_fov;
float m_fovSpeed;
bool m_bDontSetPlayerView;
#endif
string_t m_iszTargetAttachment;
int m_iAttachmentIndex;
bool m_bSnapToGoal;
#if HL2_EPISODIC
bool m_bInterpolatePosition;
// these are interpolation vars used for interpolating the camera over time
Vector m_vStartPos, m_vEndPos;
float m_flInterpStartTime;
const static float kflPosInterpTime; // seconds
#endif
int m_nPlayerButtons;
int m_nOldTakeDamage;
private:
COutputEvent m_OnEndFollow;
#ifdef MAPBASE
COutputEvent m_OnStartFollow;
#endif
};
#endif // TRIGGERS_H

View File

@ -1959,7 +1959,7 @@ extern "C" void Sys_Error( char *error, ... )
// *mapData - pointer a block of entity map data
// Output : -1 if the entity was not successfully created; 0 on success
//-----------------------------------------------------------------------------
int DispatchSpawn( CBaseEntity *pEntity )
int DispatchSpawn( CBaseEntity *pEntity, bool bRunVScripts )
{
if ( pEntity )
{
@ -1974,6 +1974,12 @@ int DispatchSpawn( CBaseEntity *pEntity )
//pEntity->SetAbsMins( pEntity->GetOrigin() - Vector(1,1,1) );
//pEntity->SetAbsMaxs( pEntity->GetOrigin() + Vector(1,1,1) );
if (bRunVScripts)
{
pEntity->RunVScripts();
pEntity->RunPrecacheScripts();
}
#if defined(TRACK_ENTITY_MEMORY) && defined(USE_MEM_DEBUG)
const char *pszClassname = NULL;
int iClassname = ((CEntityFactoryDictionary*)EntityFactoryDictionary())->m_Factories.Find( pEntity->GetClassname() );
@ -2040,6 +2046,11 @@ int DispatchSpawn( CBaseEntity *pEntity )
}
gEntList.NotifySpawn( pEntity );
if( bRunVScripts )
{
pEntity->RunOnPostSpawnScripts();
}
}
return 0;

View File

@ -237,6 +237,24 @@ CBasePlayer* UTIL_GetLocalPlayer( void );
// get the local player on a listen server
CBasePlayer *UTIL_GetListenServerHost( void );
//-----------------------------------------------------------------------------
// Purpose: Convenience function so we don't have to make this check all over
//-----------------------------------------------------------------------------
static CBasePlayer * UTIL_GetLocalPlayerOrListenServerHost( void )
{
if ( gpGlobals->maxClients > 1 )
{
if ( engine->IsDedicatedServer() )
{
return NULL;
}
return UTIL_GetListenServerHost();
}
return UTIL_GetLocalPlayer();
}
CBasePlayer* UTIL_PlayerByUserId( int userID );
CBasePlayer* UTIL_PlayerByName( const char *name ); // not case sensitive

View File

@ -65,6 +65,22 @@ const char *variant_t::GetDebug()
return UTIL_VarArgs("%s (%s)", String(), fieldtype);
}
#ifdef MAPBASE_VSCRIPT
void variant_t::SetScriptVariant( ScriptVariant_t &var )
{
switch (FieldType())
{
case FIELD_INTEGER: var = Int(); break;
case FIELD_FLOAT: var = Float(); break;
case FIELD_STRING: var = String(); break;
case FIELD_POSITION_VECTOR:
case FIELD_VECTOR: var = reinterpret_cast<Vector*>(&flVal); break; // HACKHACK
case FIELD_BOOLEAN: var = Bool(); break;
case FIELD_EHANDLE: var = ToHScript( Entity() ); break;
}
}
#endif
// cmp1 = val1 float
// cmp2 = val2 float
#define VariantToFloat(val1, val2, lenallowed) \

View File

@ -17,6 +17,10 @@
class CBaseEntity;
#ifdef MAPBASE_VSCRIPT
struct ScriptVariant_t;
#endif
//
// A variant class for passing data in entity input/output connections.
@ -80,6 +84,10 @@ public:
const char *GetDebug();
#endif
#ifdef MAPBASE_VSCRIPT
void SetScriptVariant( ScriptVariant_t &var );
#endif
static typedescription_t m_SaveBool[];
static typedescription_t m_SaveInt[];
static typedescription_t m_SaveFloat[];

View File

@ -66,6 +66,15 @@ BEGIN_DATADESC( CPropVehicle )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CPropVehicle, CBaseAnimating, "The base class for four-wheel physics vehicles." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetVehicleType, "GetVehicleType", "Get a vehicle's type." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetPhysics, "GetPhysics", "Get a vehicle's physics." )
END_SCRIPTDESC();
#endif
LINK_ENTITY_TO_CLASS( prop_vehicle, CPropVehicle );
//-----------------------------------------------------------------------------
@ -226,6 +235,23 @@ void CPropVehicle::InputHandBrakeOff( inputdata_t &inputdata )
m_VehiclePhysics.ReleaseHandbrake();
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
HSCRIPT CPropVehicle::ScriptGetPhysics()
{
HSCRIPT hScript = NULL;
CFourWheelVehiclePhysics *pPhysics = GetPhysics();
if (pPhysics)
{
hScript = g_pScriptVM->RegisterInstance( pPhysics );
}
return hScript;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -379,6 +405,19 @@ BEGIN_DATADESC( CPropVehicleDriveable )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CPropVehicleDriveable, CPropVehicle, "The base class for driveable vehicles." )
DEFINE_SCRIPTFUNC( IsOverturned, "Check if the vehicle is overturned." )
DEFINE_SCRIPTFUNC( IsVehicleBodyInWater, "Check if the vehicle's body is submerged in water." )
DEFINE_SCRIPTFUNC( StartEngine, "Start the engine." )
DEFINE_SCRIPTFUNC( StopEngine, "Stop the engine." )
DEFINE_SCRIPTFUNC( IsEngineOn, "Check if the engine is on." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetDriver, "GetDriver", "Get a vehicle's driver, which could be either a player or a npc_vehicledriver." )
END_SCRIPTDESC();
#endif
LINK_ENTITY_TO_CLASS( prop_vehicle_driveable, CPropVehicleDriveable );

View File

@ -109,6 +109,12 @@ public:
void InputHandBrakeOff( inputdata_t &inputdata );
DECLARE_DATADESC();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
HSCRIPT ScriptGetPhysics();
int ScriptGetVehicleType() { return GetVehicleType(); }
#endif
#ifdef HL2_EPISODIC
void AddPhysicsChild( CBaseEntity *pChild );
@ -166,6 +172,9 @@ class CPropVehicleDriveable : public CPropVehicle, public IDrivableVehicle, publ
DECLARE_CLASS( CPropVehicleDriveable, CPropVehicle );
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
public:
CPropVehicleDriveable( void );
~CPropVehicleDriveable( void );
@ -238,6 +247,10 @@ public:
// If this is a vehicle, returns the vehicle interface
virtual IServerVehicle *GetServerVehicle() { return m_pServerVehicle; }
#ifdef MAPBASE_VSCRIPT
HSCRIPT ScriptGetDriver() { return ToHScript( GetDriver() ); }
#endif
protected:
virtual bool ShouldThink() { return ( GetDriver() != NULL ); }

View File

@ -0,0 +1,932 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "vscript_server.h"
#include "icommandline.h"
#include "tier1/utlbuffer.h"
#include "tier1/fmtstr.h"
#include "filesystem.h"
#include "eventqueue.h"
#include "characterset.h"
#include "sceneentity.h" // for exposing scene precache function
#include "isaverestore.h"
#include "gamerules.h"
#include "vscript_server.nut"
#ifdef MAPBASE_VSCRIPT
#include "world.h"
#endif
extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
// #define VMPROFILE 1
#ifdef VMPROFILE
#define VMPROF_START float debugStartTime = Plat_FloatTime();
#define VMPROF_SHOW( funcname, funcdesc ) DevMsg("***VSCRIPT PROFILE***: %s %s: %6.4f milliseconds\n", (##funcname), (##funcdesc), (Plat_FloatTime() - debugStartTime)*1000.0 );
#else // !VMPROFILE
#define VMPROF_START
#define VMPROF_SHOW
#endif // VMPROFILE
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CScriptEntityIterator
{
public:
HSCRIPT First() { return Next(NULL); }
HSCRIPT Next( HSCRIPT hStartEntity )
{
return ToHScript( gEntList.NextEnt( ToEnt( hStartEntity ) ) );
}
HSCRIPT CreateByClassname( const char *className )
{
return ToHScript( CreateEntityByName( className ) );
}
HSCRIPT FindByClassname( HSCRIPT hStartEntity, const char *szName )
{
return ToHScript( gEntList.FindEntityByClassname( ToEnt( hStartEntity ), szName ) );
}
HSCRIPT FindByName( HSCRIPT hStartEntity, const char *szName )
{
return ToHScript( gEntList.FindEntityByName( ToEnt( hStartEntity ), szName ) );
}
HSCRIPT FindInSphere( HSCRIPT hStartEntity, const Vector &vecCenter, float flRadius )
{
return ToHScript( gEntList.FindEntityInSphere( ToEnt( hStartEntity ), vecCenter, flRadius ) );
}
HSCRIPT FindByTarget( HSCRIPT hStartEntity, const char *szName )
{
return ToHScript( gEntList.FindEntityByTarget( ToEnt( hStartEntity ), szName ) );
}
HSCRIPT FindByModel( HSCRIPT hStartEntity, const char *szModelName )
{
return ToHScript( gEntList.FindEntityByModel( ToEnt( hStartEntity ), szModelName ) );
}
HSCRIPT FindByNameNearest( const char *szName, const Vector &vecSrc, float flRadius )
{
return ToHScript( gEntList.FindEntityByNameNearest( szName, vecSrc, flRadius ) );
}
HSCRIPT FindByNameWithin( HSCRIPT hStartEntity, const char *szName, const Vector &vecSrc, float flRadius )
{
return ToHScript( gEntList.FindEntityByNameWithin( ToEnt( hStartEntity ), szName, vecSrc, flRadius ) );
}
HSCRIPT FindByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius )
{
return ToHScript( gEntList.FindEntityByClassnameNearest( szName, vecSrc, flRadius ) );
}
HSCRIPT FindByClassnameWithin( HSCRIPT hStartEntity , const char *szName, const Vector &vecSrc, float flRadius )
{
return ToHScript( gEntList.FindEntityByClassnameWithin( ToEnt( hStartEntity ), szName, vecSrc, flRadius ) );
}
private:
} g_ScriptEntityIterator;
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptEntityIterator, "CEntities", SCRIPT_SINGLETON "The global list of entities" )
DEFINE_SCRIPTFUNC( First, "Begin an iteration over the list of entities" )
DEFINE_SCRIPTFUNC( Next, "Continue an iteration over the list of entities, providing reference to a previously found entity" )
DEFINE_SCRIPTFUNC( CreateByClassname, "Creates an entity by classname" )
DEFINE_SCRIPTFUNC( FindByClassname, "Find entities by class name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByName, "Find entities by name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindInSphere, "Find entities within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByTarget, "Find entities by targetname. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByModel, "Find entities by model name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByNameNearest, "Find entities by name nearest to a point." )
DEFINE_SCRIPTFUNC( FindByNameWithin, "Find entities by name within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
DEFINE_SCRIPTFUNC( FindByClassnameNearest, "Find entities by class name nearest to a point." )
DEFINE_SCRIPTFUNC( FindByClassnameWithin, "Find entities by class name within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" )
END_SCRIPTDESC();
// ----------------------------------------------------------------------------
// KeyValues access - CBaseEntity::ScriptGetKeyFromModel returns root KeyValues
// ----------------------------------------------------------------------------
BEGIN_SCRIPTDESC_ROOT( CScriptKeyValues, "Wrapper class over KeyValues instance" )
DEFINE_SCRIPT_CONSTRUCTOR()
DEFINE_SCRIPTFUNC_NAMED( ScriptFindKey, "FindKey", "Given a KeyValues object and a key name, find a KeyValues object associated with the key name" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetFirstSubKey, "GetFirstSubKey", "Given a KeyValues object, return the first sub key object" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetNextKey, "GetNextKey", "Given a KeyValues object, return the next key object in a sub key group" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueInt, "GetKeyInt", "Given a KeyValues object and a key name, return associated integer value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueFloat, "GetKeyFloat", "Given a KeyValues object and a key name, return associated float value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueBool, "GetKeyBool", "Given a KeyValues object and a key name, return associated bool value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueString, "GetKeyString", "Given a KeyValues object and a key name, return associated string value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptIsKeyValueEmpty, "IsKeyEmpty", "Given a KeyValues object and a key name, return true if key name has no value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptReleaseKeyValues, "ReleaseKeyValues", "Given a root KeyValues object, release its contents" );
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptGetName, "GetName", "Given a KeyValues object, return its name" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetInt, "GetInt", "Given a KeyValues object, return its own associated integer value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetFloat, "GetFloat", "Given a KeyValues object, return its own associated float value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetString, "GetString", "Given a KeyValues object, return its own associated string value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptGetBool, "GetBool", "Given a KeyValues object, return its own associated bool value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValueInt, "SetKeyInt", "Given a KeyValues object and a key name, set associated integer value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValueFloat, "SetKeyFloat", "Given a KeyValues object and a key name, set associated float value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValueBool, "SetKeyBool", "Given a KeyValues object and a key name, set associated bool value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValueString, "SetKeyString", "Given a KeyValues object and a key name, set associated string value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetName, "SetName", "Given a KeyValues object, set its name" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetInt, "SetInt", "Given a KeyValues object, set its own associated integer value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetFloat, "SetFloat", "Given a KeyValues object, set its own associated float value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetBool, "SetBool", "Given a KeyValues object, set its own associated bool value" );
DEFINE_SCRIPTFUNC_NAMED( ScriptSetString, "SetString", "Given a KeyValues object, set its own associated string value" );
#endif
END_SCRIPTDESC();
HSCRIPT CScriptKeyValues::ScriptFindKey( const char *pszName )
{
KeyValues *pKeyValues = m_pKeyValues->FindKey(pszName);
if ( pKeyValues == NULL )
return NULL;
CScriptKeyValues *pScriptKey = new CScriptKeyValues( pKeyValues );
// UNDONE: who calls ReleaseInstance on this??
HSCRIPT hScriptInstance = g_pScriptVM->RegisterInstance( pScriptKey );
return hScriptInstance;
}
HSCRIPT CScriptKeyValues::ScriptGetFirstSubKey( void )
{
KeyValues *pKeyValues = m_pKeyValues->GetFirstSubKey();
if ( pKeyValues == NULL )
return NULL;
CScriptKeyValues *pScriptKey = new CScriptKeyValues( pKeyValues );
// UNDONE: who calls ReleaseInstance on this??
HSCRIPT hScriptInstance = g_pScriptVM->RegisterInstance( pScriptKey );
return hScriptInstance;
}
HSCRIPT CScriptKeyValues::ScriptGetNextKey( void )
{
KeyValues *pKeyValues = m_pKeyValues->GetNextKey();
if ( pKeyValues == NULL )
return NULL;
CScriptKeyValues *pScriptKey = new CScriptKeyValues( pKeyValues );
// UNDONE: who calls ReleaseInstance on this??
HSCRIPT hScriptInstance = g_pScriptVM->RegisterInstance( pScriptKey );
return hScriptInstance;
}
int CScriptKeyValues::ScriptGetKeyValueInt( const char *pszName )
{
int i = m_pKeyValues->GetInt( pszName );
return i;
}
float CScriptKeyValues::ScriptGetKeyValueFloat( const char *pszName )
{
float f = m_pKeyValues->GetFloat( pszName );
return f;
}
const char *CScriptKeyValues::ScriptGetKeyValueString( const char *pszName )
{
const char *psz = m_pKeyValues->GetString( pszName );
return psz;
}
bool CScriptKeyValues::ScriptIsKeyValueEmpty( const char *pszName )
{
bool b = m_pKeyValues->IsEmpty( pszName );
return b;
}
bool CScriptKeyValues::ScriptGetKeyValueBool( const char *pszName )
{
bool b = m_pKeyValues->GetBool( pszName );
return b;
}
void CScriptKeyValues::ScriptReleaseKeyValues( )
{
m_pKeyValues->deleteThis();
m_pKeyValues = NULL;
}
#ifdef MAPBASE_VSCRIPT
const char *CScriptKeyValues::ScriptGetName()
{
const char *psz = m_pKeyValues->GetName();
return psz;
}
int CScriptKeyValues::ScriptGetInt()
{
int i = m_pKeyValues->GetInt();
return i;
}
float CScriptKeyValues::ScriptGetFloat()
{
float f = m_pKeyValues->GetFloat();
return f;
}
const char *CScriptKeyValues::ScriptGetString()
{
const char *psz = m_pKeyValues->GetString();
return psz;
}
bool CScriptKeyValues::ScriptGetBool()
{
bool b = m_pKeyValues->GetBool();
return b;
}
void CScriptKeyValues::ScriptSetKeyValueInt( const char *pszName, int iValue )
{
m_pKeyValues->SetInt( pszName, iValue );
}
void CScriptKeyValues::ScriptSetKeyValueFloat( const char *pszName, float flValue )
{
m_pKeyValues->SetFloat( pszName, flValue );
}
void CScriptKeyValues::ScriptSetKeyValueString( const char *pszName, const char *pszValue )
{
m_pKeyValues->SetString( pszName, pszValue );
}
void CScriptKeyValues::ScriptSetKeyValueBool( const char *pszName, bool bValue )
{
m_pKeyValues->SetBool( pszName, bValue );
}
void CScriptKeyValues::ScriptSetName( const char *pszValue )
{
m_pKeyValues->SetName( pszValue );
}
void CScriptKeyValues::ScriptSetInt( int iValue )
{
m_pKeyValues->SetInt( NULL, iValue );
}
void CScriptKeyValues::ScriptSetFloat( float flValue )
{
m_pKeyValues->SetFloat( NULL, flValue );
}
void CScriptKeyValues::ScriptSetString( const char *pszValue )
{
m_pKeyValues->SetString( NULL, pszValue );
}
void CScriptKeyValues::ScriptSetBool( bool bValue )
{
m_pKeyValues->SetBool( NULL, bValue );
}
#endif
// constructors
CScriptKeyValues::CScriptKeyValues( KeyValues *pKeyValues = NULL )
{
m_pKeyValues = pKeyValues;
}
// destructor
CScriptKeyValues::~CScriptKeyValues( )
{
if (m_pKeyValues)
{
m_pKeyValues->deleteThis();
}
m_pKeyValues = NULL;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static float Time()
{
return gpGlobals->curtime;
}
static float FrameTime()
{
return gpGlobals->frametime;
}
#ifdef MAPBASE_VSCRIPT
static int MaxPlayers()
{
return gpGlobals->maxClients;
}
static float IntervalPerTick()
{
return gpGlobals->interval_per_tick;
}
#endif
static void SendToConsole( const char *pszCommand )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayerOrListenServerHost();
if ( !pPlayer )
{
DevMsg ("Cannot execute \"%s\", no player\n", pszCommand );
return;
}
engine->ClientCommand( pPlayer->edict(), pszCommand );
}
static const char *GetMapName()
{
return STRING( gpGlobals->mapname );
}
static const char *DoUniqueString( const char *pszBase )
{
static char szBuf[512];
g_pScriptVM->GenerateUniqueKey( pszBase, szBuf, ARRAYSIZE(szBuf) );
return szBuf;
}
static void DoEntFire( const char *pszTarget, const char *pszAction, const char *pszValue, float delay, HSCRIPT hActivator, HSCRIPT hCaller )
{
const char *target = "", *action = "Use";
variant_t value;
target = STRING( AllocPooledString( pszTarget ) );
// 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"
if ( gpGlobals->maxClients > 1 && V_stricmp( target, "point_servercommand" ) == 0 )
{
return;
}
if ( *pszAction )
{
action = STRING( AllocPooledString( pszAction ) );
}
if ( *pszValue )
{
value.SetString( AllocPooledString( pszValue ) );
}
if ( delay < 0 )
{
delay = 0;
}
g_EventQueue.AddEvent( target, action, value, delay, ToEnt(hActivator), ToEnt(hCaller) );
}
bool DoIncludeScript( const char *pszScript, HSCRIPT hScope )
{
if ( !VScriptRunScript( pszScript, hScope, true ) )
{
g_pScriptVM->RaiseException( CFmtStr( "Failed to include script \"%s\"", ( pszScript ) ? pszScript : "unknown" ) );
return false;
}
return true;
}
HSCRIPT CreateProp( const char *pszEntityName, const Vector &vOrigin, const char *pszModelName, int iAnim )
{
CBaseAnimating *pBaseEntity = (CBaseAnimating *)CreateEntityByName( pszEntityName );
pBaseEntity->SetAbsOrigin( vOrigin );
pBaseEntity->SetModel( pszModelName );
pBaseEntity->SetPlaybackRate( 1.0f );
int iSequence = pBaseEntity->SelectWeightedSequence( (Activity)iAnim );
if ( iSequence != -1 )
{
pBaseEntity->SetSequence( iSequence );
}
return ToHScript( pBaseEntity );
}
//--------------------------------------------------------------------------------------------------
// Use an entity's script instance to add an entity IO event (used for firing events on unnamed entities from vscript)
//--------------------------------------------------------------------------------------------------
static void DoEntFireByInstanceHandle( HSCRIPT hTarget, const char *pszAction, const char *pszValue, float delay, HSCRIPT hActivator, HSCRIPT hCaller )
{
const char *action = "Use";
variant_t value;
if ( *pszAction )
{
action = STRING( AllocPooledString( pszAction ) );
}
if ( *pszValue )
{
value.SetString( AllocPooledString( pszValue ) );
}
if ( delay < 0 )
{
delay = 0;
}
CBaseEntity* pTarget = ToEnt(hTarget);
if ( !pTarget )
{
Warning( "VScript error: DoEntFire was passed an invalid entity instance.\n" );
return;
}
g_EventQueue.AddEvent( pTarget, action, value, delay, ToEnt(hActivator), ToEnt(hCaller) );
}
static float ScriptTraceLine( const Vector &vecStart, const Vector &vecEnd, HSCRIPT entIgnore )
{
// UTIL_TraceLine( vecAbsStart, vecAbsEnd, MASK_BLOCKLOS, pLooker, COLLISION_GROUP_NONE, ptr );
trace_t tr;
CBaseEntity *pLooker = ToEnt(entIgnore);
UTIL_TraceLine( vecStart, vecEnd, MASK_NPCWORLDSTATIC, pLooker, COLLISION_GROUP_NONE, &tr);
if (tr.fractionleftsolid && tr.startsolid)
{
return 1.0 - tr.fractionleftsolid;
}
else
{
return tr.fraction;
}
}
bool VScriptServerInit()
{
VMPROF_START
if( scriptmanager != NULL )
{
ScriptLanguage_t scriptLanguage = SL_DEFAULT;
char const *pszScriptLanguage;
#ifdef MAPBASE_VSCRIPT
if (GetWorldEntity()->GetScriptLanguage() != SL_NONE)
{
// Allow world entity to override script language
scriptLanguage = GetWorldEntity()->GetScriptLanguage();
}
else
#endif
if ( CommandLine()->CheckParm( "-scriptlang", &pszScriptLanguage ) )
{
if( !Q_stricmp(pszScriptLanguage, "gamemonkey") )
{
scriptLanguage = SL_GAMEMONKEY;
}
else if( !Q_stricmp(pszScriptLanguage, "squirrel") )
{
scriptLanguage = SL_SQUIRREL;
}
else if( !Q_stricmp(pszScriptLanguage, "python") )
{
scriptLanguage = SL_PYTHON;
}
#ifdef MAPBASE_VSCRIPT
else if( !Q_stricmp(pszScriptLanguage, "lua") )
{
scriptLanguage = SL_LUA;
}
#endif
else
{
DevWarning("-server_script does not recognize a language named '%s'. virtual machine did NOT start.\n", pszScriptLanguage );
scriptLanguage = SL_NONE;
}
}
if( scriptLanguage != SL_NONE )
{
if ( g_pScriptVM == NULL )
g_pScriptVM = scriptmanager->CreateVM( scriptLanguage );
if( g_pScriptVM )
{
Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() );
ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_ShowMessageAll, "ShowMessage", "Print a hud message on all clients" );
ScriptRegisterFunction( g_pScriptVM, SendToConsole, "Send a string to the console as a command" );
ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map.");
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptTraceLine, "TraceLine", "given 2 points & ent to ignore, return fraction along line that hits world or models" );
ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" );
ScriptRegisterFunction( g_pScriptVM, FrameTime, "Get the time spent on the server in the last frame" );
#ifdef MAPBASE_VSCRIPT
ScriptRegisterFunction( g_pScriptVM, MaxPlayers, "Get the maximum number of players allowed on this server" );
ScriptRegisterFunction( g_pScriptVM, IntervalPerTick, "Get the interval used between each tick" );
ScriptRegisterFunction( g_pScriptVM, DoEntFire, SCRIPT_ALIAS( "EntFire", "Generate an entity i/o event" ) );
ScriptRegisterFunction( g_pScriptVM, DoEntFireByInstanceHandle, SCRIPT_ALIAS( "EntFireByHandle", "Generate an entity i/o event. First parameter is an entity instance." ) );
#else
ScriptRegisterFunction( g_pScriptVM, DoEntFire, SCRIPT_ALIAS( "EntFire", "Generate and entity i/o event" ) );
ScriptRegisterFunctionNamed( g_pScriptVM, DoEntFireByInstanceHandle, "EntFireByHandle", "Generate and entity i/o event. First parameter is an entity instance." );
#endif
ScriptRegisterFunction( g_pScriptVM, DoUniqueString, SCRIPT_ALIAS( "UniqueString", "Generate a string guaranteed to be unique across the life of the script VM, with an optional root string. Useful for adding data to tables when not sure what keys are already in use in that table." ) );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCreateSceneEntity, "CreateSceneEntity", "Create a scene entity to play the specified scene." );
ScriptRegisterFunctionNamed( g_pScriptVM, NDebugOverlay::Box, "DebugDrawBox", "Draw a debug overlay box" );
ScriptRegisterFunctionNamed( g_pScriptVM, NDebugOverlay::Line, "DebugDrawLine", "Draw a debug overlay box" );
ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" );
ScriptRegisterFunction( g_pScriptVM, CreateProp, "Create a physics prop" );
if ( GameRules() )
{
GameRules()->RegisterScriptFunctions();
}
g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" );
#ifdef MAPBASE_VSCRIPT
IGameSystem::RegisterVScriptAllSystems();
RegisterSharedScriptFunctions();
#endif
if (scriptLanguage == SL_SQUIRREL)
{
g_pScriptVM->Run( g_Script_vscript_server );
}
VScriptRunScript( "mapspawn", false );
VMPROF_SHOW( pszScriptLanguage, "virtual machine startup" );
return true;
}
else
{
DevWarning("VM Did not start!\n");
}
}
}
else
{
Log( "\nVSCRIPT: Scripting is disabled.\n" );
}
g_pScriptVM = NULL;
return false;
}
void VScriptServerTerm()
{
if( g_pScriptVM != NULL )
{
if( g_pScriptVM )
{
scriptmanager->DestroyVM( g_pScriptVM );
g_pScriptVM = NULL;
}
}
}
bool VScriptServerReplaceClosures( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing )
{
if ( !g_pScriptVM )
{
return false;
}
HSCRIPT hReplaceClosuresFunc = g_pScriptVM->LookupFunction( "__ReplaceClosures" );
if ( !hReplaceClosuresFunc )
{
return false;
}
HSCRIPT hNewScript = VScriptCompileScript( pszScriptName, bWarnMissing );
if ( !hNewScript )
{
return false;
}
g_pScriptVM->Call( hReplaceClosuresFunc, NULL, true, NULL, hNewScript, hScope );
return true;
}
CON_COMMAND( script_reload_code, "Execute a vscript file, replacing existing functions with the functions in the run script" )
{
if ( !*args[1] )
{
Warning( "No script specified\n" );
return;
}
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
VScriptServerReplaceClosures( args[1], NULL, true );
}
CON_COMMAND( script_reload_entity_code, "Execute all of this entity's VScripts, replacing existing functions with the functions in the run scripts" )
{
extern CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent );
const char *pszTarget = "";
if ( *args[1] )
{
pszTarget = args[1];
}
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if ( !pPlayer )
return;
CBaseEntity *pEntity = NULL;
while ( (pEntity = GetNextCommandEntity( pPlayer, pszTarget, pEntity )) != NULL )
{
if ( pEntity->m_ScriptScope.IsInitialized() && pEntity->m_iszVScripts != NULL_STRING )
{
char szScriptsList[255];
Q_strcpy( szScriptsList, STRING(pEntity->m_iszVScripts) );
CUtlStringList szScripts;
V_SplitString( szScriptsList, " ", szScripts);
for( int i = 0 ; i < szScripts.Count() ; i++ )
{
VScriptServerReplaceClosures( szScripts[i], pEntity->m_ScriptScope, true );
}
}
}
}
CON_COMMAND( script_reload_think, "Execute an activation script, replacing existing functions with the functions in the run script" )
{
extern CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent );
const char *pszTarget = "";
if ( *args[1] )
{
pszTarget = args[1];
}
if ( !g_pScriptVM )
{
Warning( "Scripting disabled or no server running\n" );
return;
}
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if ( !pPlayer )
return;
CBaseEntity *pEntity = NULL;
while ( (pEntity = GetNextCommandEntity( pPlayer, pszTarget, pEntity )) != NULL )
{
if ( pEntity->m_ScriptScope.IsInitialized() && pEntity->m_iszScriptThinkFunction != NULL_STRING )
{
VScriptServerReplaceClosures( STRING(pEntity->m_iszScriptThinkFunction), pEntity->m_ScriptScope, true );
}
}
}
class CVScriptGameSystem : public CAutoGameSystemPerFrame
{
public:
// Inherited from IAutoServerSystem
virtual void LevelInitPreEntity( void )
{
m_bAllowEntityCreationInScripts = true;
VScriptServerInit();
}
virtual void LevelInitPostEntity( void )
{
m_bAllowEntityCreationInScripts = false;
}
virtual void LevelShutdownPostEntity( void )
{
VScriptServerTerm();
}
virtual void FrameUpdatePostEntityThink()
{
if ( g_pScriptVM )
g_pScriptVM->Frame( gpGlobals->frametime );
}
bool m_bAllowEntityCreationInScripts;
};
CVScriptGameSystem g_VScriptGameSystem;
#ifdef MAPBASE_VSCRIPT
ConVar script_allow_entity_creation_midgame( "script_allow_entity_creation_midgame", "1", FCVAR_NOT_CONNECTED, "Allows VScript files to create entities mid-game, as opposed to only creating entities on startup." );
#endif
bool IsEntityCreationAllowedInScripts( void )
{
#ifdef MAPBASE_VSCRIPT
if (script_allow_entity_creation_midgame.GetBool())
return true;
#endif
return g_VScriptGameSystem.m_bAllowEntityCreationInScripts;
}
static short VSCRIPT_SERVER_SAVE_RESTORE_VERSION = 2;
//-----------------------------------------------------------------------------
class CVScriptSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
{
public:
CVScriptSaveRestoreBlockHandler() :
m_InstanceMap( DefLessFunc(const char *) )
{
}
const char *GetBlockName()
{
return "VScriptServer";
}
//---------------------------------
void Save( ISave *pSave )
{
pSave->StartBlock();
int temp = g_pScriptVM != NULL;
pSave->WriteInt( &temp );
if ( g_pScriptVM )
{
temp = g_pScriptVM->GetLanguage();
pSave->WriteInt( &temp );
CUtlBuffer buffer;
g_pScriptVM->WriteState( &buffer );
temp = buffer.TellPut();
pSave->WriteInt( &temp );
if ( temp > 0 )
{
pSave->WriteData( (const char *)buffer.Base(), temp );
}
}
pSave->EndBlock();
}
//---------------------------------
void WriteSaveHeaders( ISave *pSave )
{
pSave->WriteShort( &VSCRIPT_SERVER_SAVE_RESTORE_VERSION );
}
//---------------------------------
void ReadRestoreHeaders( IRestore *pRestore )
{
// No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
short version;
pRestore->ReadShort( &version );
m_fDoLoad = ( version == VSCRIPT_SERVER_SAVE_RESTORE_VERSION );
}
//---------------------------------
void Restore( IRestore *pRestore, bool createPlayers )
{
if ( !m_fDoLoad && g_pScriptVM )
{
return;
}
CBaseEntity *pEnt = gEntList.FirstEnt();
while ( pEnt )
{
if ( pEnt->m_iszScriptId != NULL_STRING )
{
g_pScriptVM->RegisterClass( pEnt->GetScriptDesc() );
m_InstanceMap.Insert( STRING( pEnt->m_iszScriptId ), pEnt );
}
pEnt = gEntList.NextEnt( pEnt );
}
pRestore->StartBlock();
if ( pRestore->ReadInt() && pRestore->ReadInt() == g_pScriptVM->GetLanguage() )
{
int nBytes = pRestore->ReadInt();
if ( nBytes > 0 )
{
CUtlBuffer buffer;
buffer.EnsureCapacity( nBytes );
pRestore->ReadData( (char *)buffer.AccessForDirectRead( nBytes ), nBytes, 0 );
g_pScriptVM->ReadState( &buffer );
}
}
pRestore->EndBlock();
}
void PostRestore( void )
{
for ( int i = m_InstanceMap.FirstInorder(); i != m_InstanceMap.InvalidIndex(); i = m_InstanceMap.NextInorder( i ) )
{
CBaseEntity *pEnt = m_InstanceMap[i];
if ( pEnt->m_hScriptInstance )
{
ScriptVariant_t variant;
if ( g_pScriptVM->GetValue( STRING(pEnt->m_iszScriptId), &variant ) && variant.m_type == FIELD_HSCRIPT )
{
pEnt->m_ScriptScope.Init( variant.m_hScript, false );
pEnt->RunPrecacheScripts();
}
}
else
{
// Script system probably has no internal references
pEnt->m_iszScriptId = NULL_STRING;
}
}
m_InstanceMap.Purge();
}
CUtlMap<const char *, CBaseEntity *> m_InstanceMap;
private:
bool m_fDoLoad;
};
//-----------------------------------------------------------------------------
CVScriptSaveRestoreBlockHandler g_VScriptSaveRestoreBlockHandler;
//-------------------------------------
ISaveRestoreBlockHandler *GetVScriptSaveRestoreBlockHandler()
{
return &g_VScriptSaveRestoreBlockHandler;
}
//-----------------------------------------------------------------------------
bool CBaseEntityScriptInstanceHelper::ToString( void *p, char *pBuf, int bufSize )
{
CBaseEntity *pEntity = (CBaseEntity *)p;
if ( pEntity->GetEntityName() != NULL_STRING )
{
V_snprintf( pBuf, bufSize, "([%d] %s: %s)", pEntity->entindex(), STRING(pEntity->m_iClassname), STRING( pEntity->GetEntityName() ) );
}
else
{
V_snprintf( pBuf, bufSize, "([%d] %s)", pEntity->entindex(), STRING(pEntity->m_iClassname) );
}
return true;
}
void *CBaseEntityScriptInstanceHelper::BindOnRead( HSCRIPT hInstance, void *pOld, const char *pszId )
{
int iEntity = g_VScriptSaveRestoreBlockHandler.m_InstanceMap.Find( pszId );
if ( iEntity != g_VScriptSaveRestoreBlockHandler.m_InstanceMap.InvalidIndex() )
{
CBaseEntity *pEnt = g_VScriptSaveRestoreBlockHandler.m_InstanceMap[iEntity];
pEnt->m_hScriptInstance = hInstance;
return pEnt;
}
return NULL;
}
CBaseEntityScriptInstanceHelper g_BaseEntityScriptInstanceHelper;

View File

@ -0,0 +1,74 @@
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#ifndef VSCRIPT_SERVER_H
#define VSCRIPT_SERVER_H
#include "vscript/ivscript.h"
#include "tier1/KeyValues.h"
#include "vscript_shared.h"
#if defined( _WIN32 )
#pragma once
#endif
class ISaveRestoreBlockHandler;
bool VScriptServerReplaceClosures( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing = false );
ISaveRestoreBlockHandler *GetVScriptSaveRestoreBlockHandler();
class CBaseEntityScriptInstanceHelper : public IScriptInstanceHelper
{
bool ToString( void *p, char *pBuf, int bufSize );
void *BindOnRead( HSCRIPT hInstance, void *pOld, const char *pszId );
};
extern CBaseEntityScriptInstanceHelper g_BaseEntityScriptInstanceHelper;
// Only allow scripts to create entities during map initialization
bool IsEntityCreationAllowedInScripts( void );
// ----------------------------------------------------------------------------
// KeyValues access
// ----------------------------------------------------------------------------
class CScriptKeyValues
{
public:
CScriptKeyValues( KeyValues *pKeyValues );
~CScriptKeyValues( );
HSCRIPT ScriptFindKey( const char *pszName );
HSCRIPT ScriptGetFirstSubKey( void );
HSCRIPT ScriptGetNextKey( void );
int ScriptGetKeyValueInt( const char *pszName );
float ScriptGetKeyValueFloat( const char *pszName );
const char *ScriptGetKeyValueString( const char *pszName );
bool ScriptIsKeyValueEmpty( const char *pszName );
bool ScriptGetKeyValueBool( const char *pszName );
void ScriptReleaseKeyValues( );
#ifdef MAPBASE_VSCRIPT
const char *ScriptGetName();
int ScriptGetInt();
float ScriptGetFloat();
const char *ScriptGetString();
bool ScriptGetBool();
void ScriptSetKeyValueInt( const char *pszName, int iValue );
void ScriptSetKeyValueFloat( const char *pszName, float flValue );
void ScriptSetKeyValueString( const char *pszName, const char *pszValue );
void ScriptSetKeyValueBool( const char *pszName, bool bValue );
void ScriptSetName( const char *pszValue );
void ScriptSetInt( int iValue );
void ScriptSetFloat( float flValue );
void ScriptSetString( const char *pszValue );
void ScriptSetBool( bool bValue );
#endif
KeyValues *m_pKeyValues; // actual KeyValue entity
};
#endif // VSCRIPT_SERVER_H

View File

@ -0,0 +1,155 @@
static char g_Script_vscript_server[] = R"vscript(
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
function UniqueString( string = "" )
{
return DoUniqueString( string.tostring() );
}
function EntFire( target, action, value = null, delay = 0.0, activator = null, caller = null )
{
if ( !value )
{
value = "";
}
if ( "self" in this )
{
if ( !caller )
{
caller = self;
}
if ( !activator )
{
activator = self;
}
}
DoEntFire( target.tostring(), action.tostring(), value.tostring(), delay, activator, caller );
}
function EntFireByHandle( target, action, value = null, delay = 0.0, activator = null, caller = null )
{
if ( !value )
{
value = "";
}
if ( "self" in this )
{
if ( !caller )
{
caller = self;
}
if ( !activator )
{
activator = self;
}
}
DoEntFireByInstanceHandle( target, action.tostring(), value.tostring(), delay, activator, caller );
}
function __ReplaceClosures( script, scope )
{
if ( !scope )
{
scope = getroottable();
}
local tempParent = { getroottable = function() { return null; } };
local temp = { runscript = script };
temp.set_delegate(tempParent);
temp.runscript()
foreach( key,val in temp )
{
if ( typeof(val) == "function" && key != "runscript" )
{
printl( " Replacing " + key );
scope[key] <- val;
}
}
}
__OutputsPattern <- regexp("^On.*Output$");
function ConnectOutputs( table )
{
const nCharsToStrip = 6;
foreach( key, val in table )
{
if ( typeof( val ) == "function" && __OutputsPattern.match( key ) )
{
//printl(key.slice( 0, nCharsToStrip ) );
table.self.ConnectOutput( key.slice( 0, key.len() - nCharsToStrip ), key );
}
}
}
function IncludeScript( name, scope = null )
{
if ( scope == null )
{
scope = this;
}
return ::DoIncludeScript( name, scope );
}
//---------------------------------------------------------
// Text dump this scope's contents to the console.
//---------------------------------------------------------
function __DumpScope( depth, table )
{
local indent=function( count )
{
local i;
for( i = 0 ; i < count ; i++ )
{
print(" ");
}
}
foreach(key, value in table)
{
indent(depth);
print( key );
switch (type(value))
{
case "table":
print("(TABLE)\n");
indent(depth);
print("{\n");
__DumpScope( depth + 1, value);
indent(depth);
print("}");
break;
case "array":
print("(ARRAY)\n");
indent(depth);
print("[\n")
__DumpScope( depth + 1, value);
indent(depth);
print("]");
break;
case "string":
print(" = \"");
print(value);
print("\"");
break;
default:
print(" = ");
print(value);
break;
}
print("\n");
}
}
)vscript";

View File

@ -393,6 +393,9 @@ BEGIN_DATADESC( CWorld )
DEFINE_KEYFIELD( m_flMaxPropScreenSpaceWidth, FIELD_FLOAT, "maxpropscreenwidth" ),
DEFINE_KEYFIELD( m_flMinPropScreenSpaceWidth, FIELD_FLOAT, "minpropscreenwidth" ),
DEFINE_KEYFIELD( m_iszDetailSpriteMaterial, FIELD_STRING, "detailmaterial" ),
#ifdef MAPBASE_VSCRIPT
DEFINE_KEYFIELD( m_iScriptLanguage, FIELD_INTEGER, "vscriptlanguage" ),
#endif
DEFINE_KEYFIELD( m_bColdWorld, FIELD_BOOLEAN, "coldworld" ),
#ifdef MAPBASE
@ -417,6 +420,9 @@ IMPLEMENT_SERVERCLASS_ST(CWorld, DT_WORLD)
#ifdef MAPBASE
SendPropStringT (SENDINFO(m_iszChapterTitle) ),
#endif
#ifdef MAPBASE_VSCRIPT
SendPropInt (SENDINFO(m_iScriptLanguage), 2, SPROP_UNSIGNED ),
#endif
END_SEND_TABLE()
//
@ -476,6 +482,10 @@ CWorld::CWorld( )
SetSolid( SOLID_BSP );
SetMoveType( MOVETYPE_NONE );
#ifdef MAPBASE_VSCRIPT
m_iScriptLanguage = SL_NONE;
#endif
m_bColdWorld = false;
}

View File

@ -61,6 +61,10 @@ public:
void InputSetChapterTitle( inputdata_t &inputdata );
#endif
#ifdef MAPBASE_VSCRIPT
ScriptLanguage_t GetScriptLanguage() { return (ScriptLanguage_t)(m_iScriptLanguage.Get()); }
#endif
private:
DECLARE_DATADESC();
@ -84,6 +88,10 @@ private:
CNetworkVar( float, m_flMaxPropScreenSpaceWidth );
CNetworkVar( string_t, m_iszDetailSpriteMaterial );
#ifdef MAPBASE_VSCRIPT
CNetworkVar( int, m_iScriptLanguage );
#endif
// start flags
CNetworkVar( bool, m_bStartDark );
CNetworkVar( bool, m_bColdWorld );

View File

@ -1217,6 +1217,19 @@ void CBaseEntity::EmitSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle,
EmitSound( filter, entindex(), params, handle );
}
#if !defined ( CLIENT_DLL ) || defined( MAPBASE_VSCRIPT )
void CBaseEntity::ScriptEmitSound( const char *soundname )
{
EmitSound( soundname );
}
float CBaseEntity::ScriptSoundDuration( const char *soundname, const char *actormodel )
{
float duration = CBaseEntity::GetSoundDuration( soundname, actormodel );
return duration;
}
#endif // !CLIENT
//-----------------------------------------------------------------------------
// Purpose:
// Input : filter -
@ -1486,6 +1499,14 @@ HSOUNDSCRIPTHANDLE CBaseEntity::PrecacheScriptSound( const char *soundname )
#endif
}
#if !defined ( CLIENT_DLL ) || defined( MAPBASE_VSCRIPT )
// Same as server version of above, but signiture changed so it can be deduced by the macros
void CBaseEntity::VScriptPrecacheScriptSound(const char* soundname)
{
g_SoundEmitterSystem.PrecacheScriptSound(soundname);
}
#endif // !CLIENT_DLL
void CBaseEntity::PrefetchScriptSound( const char *soundname )
{
g_SoundEmitterSystem.PrefetchScriptSound( soundname );

View File

@ -1801,6 +1801,22 @@ void CBaseCombatWeapon::InputHideWeapon( inputdata_t &inputdata )
SetWeaponVisible( false );
}
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char *CBaseCombatWeapon::ScriptGetPrimaryAmmoType()
{
return GetPrimaryAmmoType() <= GetAmmoDef()->m_nAmmoIndex ? GetAmmoDef()->m_AmmoType[GetPrimaryAmmoType()].pName : NULL;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char *CBaseCombatWeapon::ScriptGetSecondaryAmmoType()
{
return GetSecondaryAmmoType() <= GetAmmoDef()->m_nAmmoIndex ? GetAmmoDef()->m_AmmoType[GetSecondaryAmmoType()].pName : NULL;
}
#endif
#endif
//-----------------------------------------------------------------------------
@ -2871,6 +2887,48 @@ END_PREDICTION_DATA()
// Special hack since we're aliasing the name C_BaseCombatWeapon with a macro on the client
IMPLEMENT_NETWORKCLASS_ALIASED( BaseCombatWeapon, DT_BaseCombatWeapon )
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( CBaseCombatWeapon, CBaseAnimating, "The base class for all equippable weapons." )
DEFINE_SCRIPTFUNC( Clip1, "Get the weapon's current primary ammo." )
DEFINE_SCRIPTFUNC( Clip2, "Get the weapon's current secondary ammo." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetClip1, "SetClip1", "Set the weapon's current primary ammo." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetClip2, "SetClip2", "Set the weapon's current secondary ammo." )
DEFINE_SCRIPTFUNC( GetMaxClip1, "Get the weapon's maximum primary ammo." )
DEFINE_SCRIPTFUNC( GetMaxClip2, "Get the weapon's maximum secondary ammo." )
DEFINE_SCRIPTFUNC( GetDefaultClip1, "Get the weapon's default primary ammo." )
DEFINE_SCRIPTFUNC( GetDefaultClip2, "Get the weapon's default secondary ammo." )
DEFINE_SCRIPTFUNC( HasAnyAmmo, "Check if the weapon currently has ammo or doesn't need ammo." )
DEFINE_SCRIPTFUNC( HasPrimaryAmmo, "Check if the weapon currently has ammo or doesn't need primary ammo." )
DEFINE_SCRIPTFUNC( HasSecondaryAmmo, "Check if the weapon currently has ammo or doesn't need secondary ammo." )
DEFINE_SCRIPTFUNC( UsesPrimaryAmmo, "Check if the weapon uses primary ammo." )
DEFINE_SCRIPTFUNC( UsesSecondaryAmmo, "Check if the weapon uses secondary ammo." )
DEFINE_SCRIPTFUNC( GiveDefaultAmmo, "Fill the weapon back up to default ammo." )
DEFINE_SCRIPTFUNC( UsesClipsForAmmo1, "Check if the weapon uses clips for primary ammo." )
DEFINE_SCRIPTFUNC( UsesClipsForAmmo2, "Check if the weapon uses clips for secondary ammo." )
#ifndef CLIENT_DLL
DEFINE_SCRIPTFUNC_NAMED( ScriptGetPrimaryAmmoType, "GetPrimaryAmmoType", "Get the weapon's primary ammo type." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSecondaryAmmoType, "GetSecondaryAmmoType", "Get the weapon's secondary ammo type." )
#endif
DEFINE_SCRIPTFUNC( GetSubType, "Get the weapon's subtype." )
DEFINE_SCRIPTFUNC( SetSubType, "Set the weapon's subtype." )
DEFINE_SCRIPTFUNC( GetFireRate, "Get the weapon's firing rate." )
DEFINE_SCRIPTFUNC( GetWorldModel, "Get the weapon's world model." )
DEFINE_SCRIPTFUNC( GetViewModel, "Get the weapon's view model." )
DEFINE_SCRIPTFUNC( GetWeight, "Get the weapon's weight." )
DEFINE_SCRIPTFUNC( CanBePickedUpByNPCs, "Check if the weapon can be picked up by NPCs." )
END_SCRIPTDESC();
#endif
#if !defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose: Save Data for Base Weapon object

View File

@ -196,6 +196,9 @@ public:
DECLARE_CLASS( CBaseCombatWeapon, BASECOMBATWEAPON_DERIVED_FROM );
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
CBaseCombatWeapon();
virtual ~CBaseCombatWeapon();
@ -446,6 +449,12 @@ public:
virtual void Activate( void );
virtual bool ShouldUseLargeViewModelVROverride() { return false; }
#ifdef MAPBASE_VSCRIPT
void ScriptSetClip1( int ammo ) { m_iClip1 = ammo; }
void ScriptSetClip2( int ammo ) { m_iClip2 = ammo; }
#endif
public:
// Server Only Methods
#if !defined( CLIENT_DLL )
@ -510,6 +519,11 @@ public:
virtual CDmgAccumulator *GetDmgAccumulator( void ) { return NULL; }
#ifdef MAPBASE_VSCRIPT
const char* ScriptGetPrimaryAmmoType();
const char* ScriptGetSecondaryAmmoType();
#endif
// Client only methods
#else

View File

@ -1599,6 +1599,27 @@ typedef CTraceFilterSimpleList CBulletsTraceFilter;
void CBaseEntity::FireBullets( const FireBulletsInfo_t &info )
{
#if defined(MAPBASE_VSCRIPT) && defined(GAME_DLL)
if (m_ScriptScope.IsInitialized())
{
CFireBulletsInfoAccessor pInfo( const_cast<FireBulletsInfo_t*>(&info) );
HSCRIPT hInfo = g_pScriptVM->RegisterInstance( &pInfo );
g_pScriptVM->SetValue( "info", hInfo );
ScriptVariant_t functionReturn;
if ( CallScriptFunction( "FireBullets", &functionReturn ) )
{
if (!functionReturn.m_bool)
return;
}
g_pScriptVM->RemoveInstance( hInfo );
g_pScriptVM->ClearValue( "info" );
}
#endif
static int tracerCount;
trace_t tr;
CAmmoDef* pAmmoDef = GetAmmoDef();

View File

@ -68,6 +68,9 @@ enum InvalidatePhysicsBits_t
#endif
#include "vscript/ivscript.h"
#include "vscript_shared.h"
#if !defined( NO_ENTITY_PREDICTION )
// CBaseEntity inlines
inline bool CBaseEntity::IsPlayerSimulated( void ) const
@ -247,6 +250,17 @@ inline bool CBaseEntity::IsEffectActive( int nEffects ) const
return (m_fEffects & nEffects) != 0;
}
inline HSCRIPT ToHScript(CBaseEntity* pEnt)
{
return (pEnt) ? pEnt->GetScriptInstance() : NULL;
}
template <> ScriptClassDesc_t* GetScriptDesc<CBaseEntity>(CBaseEntity*);
inline CBaseEntity* ToEnt(HSCRIPT hScript)
{
return (hScript) ? (CBaseEntity*)g_pScriptVM->GetInstanceValue(hScript, GetScriptDescForClass(CBaseEntity)) : NULL;
}
// Shared EntityMessage between game and client .dlls
#define BASEENTITY_MSG_REMOVE_DECALS 1

View File

@ -2064,6 +2064,8 @@ static EventNameMap_t g_NameMap[] =
{ CChoreoEvent::STOPPOINT, "stoppoint" },
{ CChoreoEvent::PERMIT_RESPONSES, "permitresponses" },
{ CChoreoEvent::GENERIC, "generic" },
{ CChoreoEvent::CAMERA, "camera" },
{ CChoreoEvent::SCRIPT, "script" },
};
//-----------------------------------------------------------------------------

View File

@ -307,6 +307,12 @@ public:
// A string passed to the game code for interpretation
GENERIC,
// Camera control
CAMERA,
// Script function call
SCRIPT,
// THIS MUST BE LAST!!!
NUM_TYPES,
} EVENTTYPE;

View File

@ -173,6 +173,8 @@ public:
virtual bool InRoundRestart( void ) { return false; }
virtual void RegisterScriptFunctions( void ){ };
//Allow thirdperson camera.
virtual bool AllowThirdPersonCamera( void ) { return false; }

View File

@ -79,6 +79,10 @@ public:
virtual void LevelInitPreEntity();
#endif
#ifdef MAPBASE_VSCRIPT
virtual void RegisterScriptFunctions( void );
#endif
private:
// Rules change for the mega physgun
CNetworkVar( bool, m_bMegaPhysgun );

View File

@ -344,6 +344,15 @@ void IGameSystem::PreClientUpdateAllSystems()
#endif
#ifdef MAPBASE_VSCRIPT
void IGameSystem::RegisterVScriptAllSystems()
{
InvokeMethod( &IGameSystem::RegisterVScript );
}
#endif
//-----------------------------------------------------------------------------
// Invokes a method on all installed game systems in proper order

View File

@ -98,6 +98,13 @@ public:
static CBasePlayer *RunCommandPlayer();
static CUserCmd *RunCommandUserCmd();
#endif
#ifdef MAPBASE_VSCRIPT
// This should be abstract, but there's a lot of systems which derive from
// this interface that would need to have this declared
virtual void RegisterVScript() { ; }
static void RegisterVScriptAllSystems();
#endif
};
class IGameSystemPerFrame : public IGameSystem

View File

@ -244,7 +244,7 @@ public:
pKV->deleteThis();
}
void AddManifestFile( const char *file, bool bDontStore = false )
void AddManifestFile( const char *file )
{
KeyValues *pKV = new KeyValues(file);
if ( !pKV->LoadFromFile( filesystem, file ) )
@ -364,6 +364,24 @@ public:
}
}
}
#ifdef MAPBASE_VSCRIPT
void ScriptAddManifestFile( const char *szScript ) { AddManifestFile( szScript ); }
void LoadSoundscriptFile( const char *szScript ) { LoadFromValue(szScript, MANIFEST_SOUNDSCRIPTS, false); }
#ifndef CLIENT_DLL
void LoadTalkerFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_TALKER, false ); }
void LoadActbusyFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_ACTBUSY, false ); }
#endif
const char *GetModName() { return g_iszGameName; }
bool IsCoreMapbase() { return g_bMapbaseCore; }
virtual void RegisterVScript()
{
g_pScriptVM->RegisterInstance( this, "Mapbase" );
}
#endif
};
CMapbaseSystem g_MapbaseSystem;
@ -374,6 +392,19 @@ BEGIN_DATADESC_NO_BASE( CMapbaseSystem )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CMapbaseSystem, SCRIPT_SINGLETON "All-purpose Mapbase system primarily used for map-specific files." )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddManifestFile, "AddManifestFile", "Loads a manifest file." )
DEFINE_SCRIPTFUNC( LoadSoundscriptFile, "Loads a custom soundscript file." )
#ifndef CLIENT_DLL
DEFINE_SCRIPTFUNC( LoadTalkerFile, "Loads a custom talker file." )
DEFINE_SCRIPTFUNC( LoadActbusyFile, "Loads a custom actbusy file." )
#endif
DEFINE_SCRIPTFUNC( GetModName, "Gets the name of the mod. This is the name which shows up on Steam, RPC, etc." )
DEFINE_SCRIPTFUNC( IsCoreMapbase, "Indicates whether this is one of the original Mapbase mods or just a separate mod using its code." )
END_SCRIPTDESC();
#endif
#ifdef GAME_DLL
static CUtlVector<MODTITLECOMMENT> g_MapbaseChapterMaps;
static CUtlVector<MODCHAPTER> g_MapbaseChapterList;
@ -437,7 +468,7 @@ ThreeState_t Flashlight_GetLegacyVersionKey()
static void CC_Mapbase_LoadManifestFile( const CCommand& args )
{
g_MapbaseSystem.AddManifestFile(args[1], args[2]);
g_MapbaseSystem.AddManifestFile(args[1]);
}
static ConCommand mapbase_loadmanifestfile("mapbase_loadmanifestfile", CC_Mapbase_LoadManifestFile, "Loads a Mapbase manifest file. If you don't want this to be saved and found when reloaded, type a '1' after the file path." );

View File

@ -0,0 +1,68 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: VScript functions for Half-Life 2.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hl2_gamerules.h"
#ifndef CLIENT_DLL
#include "eventqueue.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifndef CLIENT_DLL
extern CBaseEntity *CreatePlayerLoadSave( Vector vOrigin, float flDuration, float flHoldTime, float flLoadTime );
HSCRIPT ScriptGameOver( const char *pszMessage, float flDelay, float flFadeTime, float flLoadTime, int r, int g, int b )
{
CBaseEntity *pPlayer = AI_GetSinglePlayer();
if (pPlayer)
{
UTIL_ShowMessage( pszMessage, ToBasePlayer( pPlayer ) );
ToBasePlayer( pPlayer )->NotifySinglePlayerGameEnding();
}
else
{
// TODO: How should MP handle this?
return NULL;
}
CBaseEntity *pReload = CreatePlayerLoadSave( vec3_origin, flFadeTime, flLoadTime + 1.0f, flLoadTime );
if (pReload)
{
pReload->SetRenderColor( r, g, b, 255 );
g_EventQueue.AddEvent( pReload, "Reload", flDelay, pReload, pReload );
}
return ToHScript( pReload );
}
bool ScriptMegaPhyscannonActive()
{
return HL2GameRules()->MegaPhyscannonActive();
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Returns how much damage the given ammo type should do to the victim
// when fired by the attacker.
// Input : pAttacker - Dude what shot the gun.
// pVictim - Dude what done got shot.
// nAmmoType - What been shot out.
// Output : How much hurt to put on dude what done got shot (pVictim).
//-----------------------------------------------------------------------------
void CHalfLife2::RegisterScriptFunctions( void )
{
BaseClass::RegisterScriptFunctions();
#ifndef CLIENT_DLL
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGameOver, "GameOver", "Ends the game and reloads the last save." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMegaPhyscannonActive, "MegaPhyscannonActive", "Checks if supercharged gravity gun mode is enabled." );
#endif
}

View File

@ -0,0 +1,308 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared VScript math functions.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//=============================================================================
//
// matrix3x4_t
//
//=============================================================================
//
// Exposes matrix3x4_t to VScript
//
class CScriptMatrix3x4
{
public:
CScriptMatrix3x4()
{
matrix = new matrix3x4_t();
m_bFree = true;
}
~CScriptMatrix3x4()
{
if (m_bFree == true)
delete matrix;
}
CScriptMatrix3x4( matrix3x4_t &inmatrix ) { matrix = &inmatrix; }
matrix3x4_t *GetMatrix() { return matrix; }
void SetMatrix( matrix3x4_t &inmatrix ) { matrix = &inmatrix; }
void Init( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin )
{
matrix->Init( xAxis, yAxis, zAxis, vecOrigin );
}
private:
matrix3x4_t *matrix;
bool m_bFree = false;
};
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptMatrix3x4, "matrix3x4_t", "A 3x4 matrix transform." )
DEFINE_SCRIPT_CONSTRUCTOR()
DEFINE_SCRIPTFUNC( Init, "Creates a matrix where the X axis = forward, the Y axis = left, and the Z axis = up." )
END_SCRIPTDESC();
inline matrix3x4_t *ToMatrix3x4( HSCRIPT hMat ) { return HScriptToClass<CScriptMatrix3x4>( hMat )->GetMatrix(); }
HSCRIPT ScriptCreateMatrixInstance( matrix3x4_t &matrix )
{
CScriptMatrix3x4 *smatrix = new CScriptMatrix3x4( matrix );
return g_pScriptVM->RegisterInstance( smatrix );
}
void ScriptFreeMatrixInstance( HSCRIPT hMat )
{
CScriptMatrix3x4 *smatrix = HScriptToClass<CScriptMatrix3x4>( hMat );
if (smatrix)
{
g_pScriptVM->RemoveInstance( hMat );
delete smatrix;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void ScriptConcatTransforms( HSCRIPT hMat1, HSCRIPT hMat2, HSCRIPT hOut )
{
if (!hMat1 || !hMat2 || !hOut)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
matrix3x4_t *pMat2 = ToMatrix3x4( hMat2 );
matrix3x4_t *pOut = ToMatrix3x4( hOut );
ConcatTransforms( *pMat1, *pMat2, *pOut );
}
void ScriptMatrixCopy( HSCRIPT hMat1, HSCRIPT hOut )
{
if (!hMat1 || !hOut)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
matrix3x4_t *pOut = ToMatrix3x4( hOut );
MatrixCopy( *pMat1, *pOut );
}
void ScriptMatrixInvert( HSCRIPT hMat1, HSCRIPT hOut )
{
if (!hMat1 || !hOut)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
matrix3x4_t *pOut = ToMatrix3x4( hOut );
MatrixInvert( *pMat1, *pOut );
}
void ScriptMatricesAreEqual( HSCRIPT hMat1, HSCRIPT hMat2 )
{
if (!hMat1 || !hMat2)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
matrix3x4_t *pMat2 = ToMatrix3x4( hMat2 );
MatricesAreEqual( *pMat1, *pMat2 );
}
const Vector& ScriptMatrixGetColumn( HSCRIPT hMat1, int column )
{
static Vector outvec;
outvec.Zero();
if (!hMat1)
return outvec;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
MatrixGetColumn( *pMat1, column, outvec );
return outvec;
}
void ScriptMatrixSetColumn( const Vector& vecset, int column, HSCRIPT hMat1 )
{
if (!hMat1)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
static Vector outvec;
MatrixSetColumn( vecset, column, *pMat1 );
}
void ScriptMatrixAngles( HSCRIPT hMat1, const QAngle& angset, const Vector& vecset )
{
if (!hMat1)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
MatrixAngles( *pMat1, *const_cast<QAngle*>(&angset), *const_cast<Vector*>(&vecset) );
}
void ScriptAngleMatrix( const QAngle& angset, const Vector& vecset, HSCRIPT hMat1 )
{
if (!hMat1)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
AngleMatrix( angset, vecset, *pMat1 );
}
void ScriptAngleIMatrix( const QAngle& angset, const Vector& vecset, HSCRIPT hMat1 )
{
if (!hMat1)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
AngleIMatrix( angset, vecset, *pMat1 );
}
void ScriptSetIdentityMatrix( HSCRIPT hMat1 )
{
if (!hMat1)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
SetIdentityMatrix( *pMat1 );
}
void ScriptSetScaleMatrix( float x, float y, float z, HSCRIPT hMat1 )
{
if (!hMat1)
return;
matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 );
SetScaleMatrix( x, y, z, *pMat1 );
}
//=============================================================================
//
// Misc. Vector/QAngle functions
//
//=============================================================================
const Vector& ScriptAngleVectors( const QAngle &angles )
{
static Vector forward;
AngleVectors( angles, &forward );
return forward;
}
const QAngle& ScriptVectorAngles( const Vector &forward )
{
static QAngle angles;
VectorAngles( forward, angles );
return angles;
}
const Vector& ScriptCalcClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point )
{
static Vector outvec;
CalcClosestPointOnAABB( mins, maxs, point, outvec );
return outvec;
}
const Vector& ScriptCalcClosestPointOnLine( const Vector &point, const Vector &vLineA, const Vector &vLineB )
{
static Vector outvec;
CalcClosestPointOnLine( point, vLineA, vLineB, outvec );
return outvec;
}
float ScriptCalcDistanceToLine( const Vector &point, const Vector &vLineA, const Vector &vLineB )
{
return CalcDistanceToLine( point, vLineA, vLineB );
}
const Vector& ScriptCalcClosestPointOnLineSegment( const Vector &point, const Vector &vLineA, const Vector &vLineB )
{
static Vector outvec;
CalcClosestPointOnLineSegment( point, vLineA, vLineB, outvec );
return outvec;
}
float ScriptCalcDistanceToLineSegment( const Vector &point, const Vector &vLineA, const Vector &vLineB )
{
return CalcDistanceToLineSegment( point, vLineA, vLineB );
}
#ifndef CLIENT_DLL
const Vector& ScriptPredictedPosition( HSCRIPT hTarget, float flTimeDelta )
{
static Vector predicted;
UTIL_PredictedPosition( ToEnt(hTarget), flTimeDelta, &predicted );
return predicted;
}
#endif
void RegisterMathScriptFunctions()
{
ScriptRegisterFunction( g_pScriptVM, RandomFloat, "Generate a random floating point number within a range, inclusive." );
ScriptRegisterFunction( g_pScriptVM, RandomInt, "Generate a random integer within a range, inclusive." );
ScriptRegisterFunction( g_pScriptVM, Approach, "Returns a value which approaches the target value from the input value with the specified speed." );
ScriptRegisterFunction( g_pScriptVM, ApproachAngle, "Returns an angle which approaches the target angle from the input angle with the specified speed." );
ScriptRegisterFunction( g_pScriptVM, AngleDiff, "Returns the degrees difference between two yaw angles." );
ScriptRegisterFunction( g_pScriptVM, AngleDistance, "Returns the distance between two angles." );
ScriptRegisterFunction( g_pScriptVM, AngleNormalize, "Clamps an angle to be in between -360 and 360." );
ScriptRegisterFunction( g_pScriptVM, AngleNormalizePositive, "Clamps an angle to be in between 0 and 360." );
ScriptRegisterFunction( g_pScriptVM, AnglesAreEqual, "Checks if two angles are equal based on a given tolerance value." );
//
// matrix3x4_t
//
g_pScriptVM->RegisterClass( GetScriptDescForClass( CScriptMatrix3x4 ) );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptFreeMatrixInstance, "FreeMatrixInstance", "Frees an allocated matrix instance." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptConcatTransforms, "ConcatTransforms", "Concatenates two transformation matrices into another matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMatrixCopy, "MatrixCopy", "Copies a matrix to another matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMatrixInvert, "MatrixInvert", "Inverts a matrix and copies the result to another matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMatricesAreEqual, "MatricesAreEqual", "Checks if two matrices are equal." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMatrixGetColumn, "MatrixGetColumn", "Gets the column of a matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMatrixSetColumn, "MatrixSetColumn", "Sets the column of a matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMatrixAngles, "MatrixAngles", "Gets the angles and position of a matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptAngleMatrix, "AngleMatrix", "Sets the angles and position of a matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptAngleIMatrix, "AngleIMatrix", "Sets the inverted angles and position of a matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptSetIdentityMatrix, "SetIdentityMatrix", "Turns a matrix into an identity matrix." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptSetScaleMatrix, "SetScaleMatrix", "Scales a matrix." );
//
// Misc. Vector/QAngle functions
//
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptAngleVectors, "AngleVectors", "Turns an angle into a direction vector." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptVectorAngles, "VectorAngles", "Turns a direction vector into an angle." );
ScriptRegisterFunction( g_pScriptVM, CalcSqrDistanceToAABB, "Returns the squared distance to a bounding box." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalcClosestPointOnAABB, "CalcClosestPointOnAABB", "Returns the closest point on a bounding box." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalcDistanceToLine, "CalcDistanceToLine", "Returns the distance to a line." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalcClosestPointOnLine, "CalcClosestPointOnLine", "Returns the closest point on a line." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalcDistanceToLineSegment, "CalcDistanceToLineSegment", "Returns the distance to a line segment." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalcClosestPointOnLineSegment, "CalcClosestPointOnLineSegment", "Returns the closest point on a line segment." );
#ifndef CLIENT_DLL
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPredictedPosition, "PredictedPosition", "Predicts what an entity's position will be in a given amount of time." );
#endif
}

View File

@ -0,0 +1,857 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Due to this being a custom integration of VScript based on the Alien Swarm SDK, we don't have access to
// some of the code normally available in games like L4D2 or Valve's original VScript DLL.
// Instead, that code is recreated here, shared between server and client.
//
// It also contains other functions unique to Mapbase.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "matchers.h"
#include "takedamageinfo.h"
#ifndef CLIENT_DLL
#include "globalstate.h"
#include "vscript_server.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CScriptNetPropManager
{
public:
#ifdef CLIENT_DLL
RecvProp *RecurseTable( RecvTable *pTable, const char *pszPropName )
#else
SendProp *RecurseTable( SendTable *pTable, const char *pszPropName )
#endif
{
#ifdef CLIENT_DLL
RecvProp *pProp = NULL;
#else
SendProp *pProp = NULL;
#endif
for (int i = 0; i < pTable->GetNumProps(); i++)
{
pProp = pTable->GetProp( i );
if (pProp->GetType() == DPT_DataTable)
{
pProp = RecurseTable(pProp->GetDataTable(), pszPropName);
if (pProp)
return pProp;
}
else
{
if (FStrEq( pProp->GetName(), pszPropName ))
return pProp;
}
}
return NULL;
}
#ifdef CLIENT_DLL
RecvProp *RecurseNetworkClass( ClientClass *pClass, const char *pszPropName )
#else
SendProp *RecurseNetworkClass( ServerClass *pClass, const char *pszPropName )
#endif
{
#ifdef CLIENT_DLL
RecvProp *pProp = RecurseTable( pClass->m_pRecvTable, pszPropName );
#else
SendProp *pProp = RecurseTable( pClass->m_pTable, pszPropName );
#endif
if (pProp)
return pProp;
if (pClass->m_pNext)
return RecurseNetworkClass( pClass->m_pNext, pszPropName );
else
return NULL;
}
#ifdef CLIENT_DLL
RecvProp *GetPropByName( CBaseEntity *pEnt, const char *pszPropName )
{
if (pEnt)
{
return RecurseNetworkClass( pEnt->GetClientClass(), pszPropName );
}
return NULL;
}
#else
SendProp *GetPropByName( CBaseEntity *pEnt, const char *pszPropName )
{
if (pEnt)
{
return RecurseNetworkClass( pEnt->GetServerClass(), pszPropName );
}
return NULL;
}
#endif
int GetPropArraySize( HSCRIPT hEnt, const char *pszPropName )
{
CBaseEntity *pEnt = ToEnt( hEnt );
auto *pProp = GetPropByName( pEnt, pszPropName );
if (pProp)
{
// TODO: Is this what this function wants?
return pProp->GetNumElements();
}
return -1;
}
#define GetPropFunc( name, varType, propType, defaultval ) \
varType name( HSCRIPT hEnt, const char *pszPropName ) \
{ \
CBaseEntity *pEnt = ToEnt( hEnt ); \
auto *pProp = GetPropByName( pEnt, pszPropName ); \
if (pProp && pProp->GetType() == propType) \
{ \
return *(varType*)((char *)pEnt + pProp->GetOffset()); \
} \
return defaultval; \
} \
#define GetPropFuncArray( name, varType, propType, defaultval ) \
varType name( HSCRIPT hEnt, const char *pszPropName, int iArrayElement ) \
{ \
CBaseEntity *pEnt = ToEnt( hEnt ); \
auto *pProp = GetPropByName( pEnt, pszPropName ); \
if (pProp && pProp->GetType() == propType) \
{ \
return ((varType*)((char *)pEnt + pProp->GetOffset()))[iArrayElement]; \
} \
return defaultval; \
} \
GetPropFunc( GetPropFloat, float, DPT_Float, -1 );
GetPropFuncArray( GetPropFloatArray, float, DPT_Float, -1 );
GetPropFunc( GetPropInt, int, DPT_Int, -1 );
GetPropFuncArray( GetPropIntArray, int, DPT_Int, -1 );
GetPropFunc( GetPropVector, Vector, DPT_Vector, vec3_invalid );
GetPropFuncArray( GetPropVectorArray, Vector, DPT_Vector, vec3_invalid );
HSCRIPT GetPropEntity( HSCRIPT hEnt, const char *pszPropName )
{
CBaseEntity *pEnt = ToEnt( hEnt );
auto *pProp = GetPropByName( pEnt, pszPropName );
if (pProp && pProp->GetType() == DPT_Int)
{
return ToHScript( *(CHandle<CBaseEntity>*)((char *)pEnt + pProp->GetOffset()) );
}
return NULL;
}
HSCRIPT GetPropEntityArray( HSCRIPT hEnt, const char *pszPropName, int iArrayElement )
{
CBaseEntity *pEnt = ToEnt( hEnt );
auto *pProp = GetPropByName( pEnt, pszPropName );
if (pProp && pProp->GetType() == DPT_Int)
{
return ToHScript( ((CHandle<CBaseEntity>*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] );
}
return NULL;
}
const char *GetPropString( HSCRIPT hEnt, const char *pszPropName )
{
CBaseEntity *pEnt = ToEnt( hEnt );
auto *pProp = GetPropByName( pEnt, pszPropName );
if (pProp && pProp->GetType() == DPT_Int)
{
return (const char*)((char *)pEnt + pProp->GetOffset());
}
return NULL;
}
const char *GetPropStringArray( HSCRIPT hEnt, const char *pszPropName, int iArrayElement )
{
CBaseEntity *pEnt = ToEnt( hEnt );
auto *pProp = GetPropByName( pEnt, pszPropName );
if (pProp && pProp->GetType() == DPT_Int)
{
return ((const char**)((char *)pEnt + pProp->GetOffset()))[iArrayElement];
}
return NULL;
}
const char *GetPropType( HSCRIPT hEnt, const char *pszPropName )
{
CBaseEntity *pEnt = ToEnt( hEnt );
auto *pProp = GetPropByName( pEnt, pszPropName );
if (pProp)
{
switch (pProp->GetType())
{
case DPT_Int: return "integer";
case DPT_Float: return "float";
case DPT_Vector: return "vector";
case DPT_VectorXY: return "vector2d";
case DPT_String: return "string";
case DPT_Array: return "array";
case DPT_DataTable: return "datatable";
}
}
return NULL;
}
bool HasProp( HSCRIPT hEnt, const char *pszPropName )
{
CBaseEntity *pEnt = ToEnt( hEnt );
return GetPropByName( pEnt, pszPropName ) != NULL;
}
#define SetPropFunc( name, varType, propType ) \
void name( HSCRIPT hEnt, const char *pszPropName, varType value ) \
{ \
CBaseEntity *pEnt = ToEnt( hEnt ); \
auto *pProp = GetPropByName( pEnt, pszPropName ); \
if (pProp && pProp->GetType() == propType) \
{ \
*(varType*)((char *)pEnt + pProp->GetOffset()) = value; \
} \
} \
#define SetPropFuncArray( name, varType, propType ) \
void name( HSCRIPT hEnt, const char *pszPropName, varType value, int iArrayElement ) \
{ \
CBaseEntity *pEnt = ToEnt( hEnt ); \
auto *pProp = GetPropByName( pEnt, pszPropName ); \
if (pProp && pProp->GetType() == propType) \
{ \
((varType*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] = value; \
} \
} \
SetPropFunc( SetPropFloat, float, DPT_Float );
SetPropFuncArray( SetPropFloatArray, float, DPT_Float );
SetPropFunc( SetPropInt, int, DPT_Int );
SetPropFuncArray( SetPropIntArray, int, DPT_Int );
SetPropFunc( SetPropVector, Vector, DPT_Vector );
SetPropFuncArray( SetPropVectorArray, Vector, DPT_Vector );
SetPropFunc( SetPropString, const char*, DPT_String );
SetPropFuncArray( SetPropStringArray, const char*, DPT_String );
void SetPropEntity( HSCRIPT hEnt, const char *pszPropName, HSCRIPT value )
{
CBaseEntity *pEnt = ToEnt( hEnt );
auto *pProp = GetPropByName( pEnt, pszPropName );
if (pProp && pProp->GetType() == DPT_Int)
{
*((CHandle<CBaseEntity>*)((char *)pEnt + pProp->GetOffset())) = ToEnt(value);
}
}
HSCRIPT SetPropEntityArray( HSCRIPT hEnt, const char *pszPropName, HSCRIPT value, int iArrayElement )
{
CBaseEntity *pEnt = ToEnt( hEnt );
auto *pProp = GetPropByName( pEnt, pszPropName );
if (pProp && pProp->GetType() == DPT_Int)
{
((CHandle<CBaseEntity>*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] = ToEnt(value);
}
return NULL;
}
private:
} g_ScriptNetPropManager;
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptNetPropManager, "CNetPropManager", SCRIPT_SINGLETON "Allows reading and updating the network properties of an entity." )
DEFINE_SCRIPTFUNC( GetPropArraySize, "Returns the size of an netprop array, or -1." )
DEFINE_SCRIPTFUNC( GetPropEntity, "Reads an EHANDLE valued netprop (21 bit integer). Returns the script handle of the entity." )
DEFINE_SCRIPTFUNC( GetPropEntityArray, "Reads an EHANDLE valued netprop (21 bit integer) from an array. Returns the script handle of the entity." )
DEFINE_SCRIPTFUNC( GetPropFloat, "Reads a float valued netprop." )
DEFINE_SCRIPTFUNC( GetPropFloatArray, "Reads a float valued netprop from an array." )
DEFINE_SCRIPTFUNC( GetPropInt, "Reads an integer valued netprop." )
DEFINE_SCRIPTFUNC( GetPropIntArray, "Reads an integer valued netprop from an array." )
DEFINE_SCRIPTFUNC( GetPropString, "Reads a string valued netprop." )
DEFINE_SCRIPTFUNC( GetPropStringArray, "Reads a string valued netprop from an array." )
DEFINE_SCRIPTFUNC( GetPropVector, "Reads a 3D vector valued netprop." )
DEFINE_SCRIPTFUNC( GetPropVectorArray, "Reads a 3D vector valued netprop from an array." )
DEFINE_SCRIPTFUNC( GetPropType, "Returns the name of the netprop type as a string." )
DEFINE_SCRIPTFUNC( HasProp, "Checks if a netprop exists." )
DEFINE_SCRIPTFUNC( SetPropEntity, "Sets an EHANDLE valued netprop (21 bit integer) to reference the specified entity." )
DEFINE_SCRIPTFUNC( SetPropEntityArray, "Sets an EHANDLE valued netprop (21 bit integer) from an array to reference the specified entity." )
DEFINE_SCRIPTFUNC( SetPropFloat, "Sets a netprop to the specified float." )
DEFINE_SCRIPTFUNC( SetPropFloatArray, "Sets a netprop from an array to the specified float." )
DEFINE_SCRIPTFUNC( SetPropInt, "Sets a netprop to the specified integer." )
DEFINE_SCRIPTFUNC( SetPropIntArray, "Sets a netprop from an array to the specified integer." )
DEFINE_SCRIPTFUNC( SetPropString, "Sets a netprop to the specified string." )
DEFINE_SCRIPTFUNC( SetPropStringArray, "Sets a netprop from an array to the specified string." )
DEFINE_SCRIPTFUNC( SetPropVector, "Sets a netprop to the specified vector." )
DEFINE_SCRIPTFUNC( SetPropVectorArray, "Sets a netprop from an array to the specified vector." )
END_SCRIPTDESC();
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CScriptConvarLookup
{
public:
#ifndef CLIENT_DLL
const char *GetClientConvarValue( const char *pszConVar, int entindex )
{
return engine->GetClientConVarValue( entindex, pszConVar );
}
#endif
const char *GetStr( const char *pszConVar )
{
ConVarRef cvar( pszConVar );
return cvar.GetString();
}
float GetFloat( const char *pszConVar )
{
ConVarRef cvar( pszConVar );
return cvar.GetFloat();
}
void SetValue( const char *pszConVar, const char *pszValue )
{
ConVarRef cvar( pszConVar );
if (!cvar.IsValid())
return;
// FCVAR_NOT_CONNECTED can be used to protect specific convars from nefarious interference
if (cvar.IsFlagSet(FCVAR_NOT_CONNECTED))
return;
cvar.SetValue( pszValue );
}
private:
} g_ScriptConvarLookup;
BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptConvarLookup, "CConvars", SCRIPT_SINGLETON "Provides an interface for getting and setting convars." )
#ifndef CLIENT_DLL
DEFINE_SCRIPTFUNC( GetClientConvarValue, "Returns the convar value for the entindex as a string. Only works with client convars with the FCVAR_USERINFO flag." )
#endif
DEFINE_SCRIPTFUNC( GetStr, "Returns the convar as a string. May return null if no such convar." )
DEFINE_SCRIPTFUNC( GetFloat, "Returns the convar as a float. May return null if no such convar." )
DEFINE_SCRIPTFUNC( SetValue, "Sets the value of the convar. Supported types are bool, int, float, string." )
END_SCRIPTDESC();
#ifndef CLIENT_DLL
void AddThinkToEnt( HSCRIPT entity, const char *pszFuncName )
{
CBaseEntity *pEntity = ToEnt( entity );
if (!pEntity)
return;
if (pszFuncName == NULL || pszFuncName[0] == '\0')
pEntity->m_iszScriptThinkFunction = NULL_STRING;
else
pEntity->m_iszScriptThinkFunction = AllocPooledString(pszFuncName);
pEntity->SetContextThink( &CBaseEntity::ScriptThink, gpGlobals->curtime, "ScriptThink" );
}
HSCRIPT EntIndexToHScript( int index )
{
return ToHScript( UTIL_EntityByIndex( index ) );
}
void ParseScriptTableKeyValues( CBaseEntity *pEntity, HSCRIPT hKV )
{
int nIterator = -1;
ScriptVariant_t varKey, varValue;
while ((nIterator = g_pScriptVM->GetKeyValue( hKV, nIterator, &varKey, &varValue )) != -1)
{
switch (varValue.m_type)
{
case FIELD_CSTRING: pEntity->KeyValue( varKey.m_pszString, varValue.m_pszString ); break;
case FIELD_FLOAT: pEntity->KeyValue( varKey.m_pszString, varValue.m_float ); break;
case FIELD_VECTOR: pEntity->KeyValue( varKey.m_pszString, *varValue.m_pVector ); break;
}
g_pScriptVM->ReleaseValue( varKey );
g_pScriptVM->ReleaseValue( varValue );
}
}
void PrecacheEntityFromTable( const char *pszClassname, HSCRIPT hKV )
{
if ( IsEntityCreationAllowedInScripts() == false )
{
Warning( "VScript error: A script attempted to create an entity mid-game. Due to the server's settings, entity creation from scripts is only allowed during map init.\n" );
return;
}
// This is similar to UTIL_PrecacheOther(), but we can't check if we can only precache it once.
// Probably for the best anyway, as similar classes can still have different precachable properties.
CBaseEntity *pEntity = CreateEntityByName( pszClassname );
if (!pEntity)
{
Assert( !"PrecacheEntityFromTable: only works for CBaseEntities" );
return;
}
ParseScriptTableKeyValues( pEntity, hKV );
pEntity->Precache();
UTIL_RemoveImmediate( pEntity );
}
HSCRIPT SpawnEntityFromTable( const char *pszClassname, HSCRIPT hKV )
{
if ( IsEntityCreationAllowedInScripts() == false )
{
Warning( "VScript error: A script attempted to create an entity mid-game. Due to the server's settings, entity creation from scripts is only allowed during map init.\n" );
return NULL;
}
CBaseEntity *pEntity = CreateEntityByName( pszClassname );
if ( !pEntity )
{
Assert( !"SpawnEntityFromTable: only works for CBaseEntities" );
return NULL;
}
gEntList.NotifyCreateEntity( pEntity );
ParseScriptTableKeyValues( pEntity, hKV );
DispatchSpawn( pEntity );
pEntity->Activate();
return ToHScript( pEntity );
}
#endif
//-----------------------------------------------------------------------------
// Mapbase-specific functions start here
//-----------------------------------------------------------------------------
static void ScriptColorPrint( int r, int g, int b, const char *pszMsg )
{
const Color clr(r, g, b, 255);
ConColorMsg( clr, "%s", pszMsg );
}
static void ScriptColorPrintL( int r, int g, int b, const char *pszMsg )
{
const Color clr(r, g, b, 255);
ConColorMsg( clr, "%s\n", pszMsg );
}
#ifndef CLIENT_DLL
HSCRIPT SpawnEntityFromKeyValues( const char *pszClassname, HSCRIPT hKV )
{
if ( IsEntityCreationAllowedInScripts() == false )
{
Warning( "VScript error: A script attempted to create an entity mid-game. Due to the server's settings, entity creation from scripts is only allowed during map init.\n" );
return NULL;
}
CBaseEntity *pEntity = CreateEntityByName( pszClassname );
if ( !pEntity )
{
Assert( !"SpawnEntityFromKeyValues: only works for CBaseEntities" );
return NULL;
}
gEntList.NotifyCreateEntity( pEntity );
CScriptKeyValues *pScriptKV = hKV ? HScriptToClass<CScriptKeyValues>( hKV ) : NULL;
if (pScriptKV)
{
KeyValues *pKV = pScriptKV->m_pKeyValues;
for (pKV = pKV->GetFirstSubKey(); pKV != NULL; pKV = pKV->GetNextKey())
{
pEntity->KeyValue( pKV->GetName(), pKV->GetString() );
}
}
DispatchSpawn( pEntity );
pEntity->Activate();
return ToHScript( pEntity );
}
void ScriptDispatchSpawn( HSCRIPT hEntity )
{
CBaseEntity *pEntity = ToEnt( hEntity );
if (pEntity)
{
DispatchSpawn( pEntity );
}
}
#endif
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static HSCRIPT CreateDamageInfo( HSCRIPT hInflictor, HSCRIPT hAttacker, const Vector &vecForce, const Vector &vecDamagePos, float flDamage, int iDamageType )
{
// The script is responsible for deleting this via DestroyDamageInfo().
CTakeDamageInfo *damageInfo = new CTakeDamageInfo(ToEnt(hInflictor), ToEnt(hAttacker), flDamage, iDamageType);
HSCRIPT hScript = g_pScriptVM->RegisterInstance( damageInfo );
damageInfo->SetDamagePosition( vecDamagePos );
damageInfo->SetDamageForce( vecForce );
return hScript;
}
static void DestroyDamageInfo( HSCRIPT hDamageInfo )
{
if (hDamageInfo)
{
CTakeDamageInfo *pInfo = (CTakeDamageInfo*)g_pScriptVM->GetInstanceValue( hDamageInfo, GetScriptDescForClass( CTakeDamageInfo ) );
if (pInfo)
{
g_pScriptVM->RemoveInstance( hDamageInfo );
delete pInfo;
}
}
}
void ScriptCalculateExplosiveDamageForce( HSCRIPT info, const Vector &vecDir, const Vector &vecForceOrigin, float flScale ) { CalculateExplosiveDamageForce( HScriptToClass<CTakeDamageInfo>(info), vecDir, vecForceOrigin, flScale ); }
void ScriptCalculateBulletDamageForce( HSCRIPT info, int iBulletType, const Vector &vecBulletDir, const Vector &vecForceOrigin, float flScale ) { CalculateBulletDamageForce( HScriptToClass<CTakeDamageInfo>(info), iBulletType, vecBulletDir, vecForceOrigin, flScale ); }
void ScriptCalculateMeleeDamageForce( HSCRIPT info, const Vector &vecMeleeDir, const Vector &vecForceOrigin, float flScale ) { CalculateMeleeDamageForce( HScriptToClass<CTakeDamageInfo>( info ), vecMeleeDir, vecForceOrigin, flScale ); }
void ScriptGuessDamageForce( HSCRIPT info, const Vector &vecForceDir, const Vector &vecForceOrigin, float flScale ) { GuessDamageForce( HScriptToClass<CTakeDamageInfo>( info ), vecForceDir, vecForceOrigin, flScale ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CTraceInfoAccessor
{
public:
// CGrameTrace stuff
bool DidHitWorld() const { return m_tr.DidHitWorld(); }
bool DidHitNonWorldEntity() const { return m_tr.DidHitNonWorldEntity(); }
int GetEntityIndex() const { return m_tr.GetEntityIndex(); }
bool DidHit() const { return m_tr.DidHit(); }
float FractionLeftSolid() const { return m_tr.fractionleftsolid; }
int HitGroup() const { return m_tr.hitgroup; }
int PhysicsBone() const { return m_tr.physicsbone; }
HSCRIPT Entity() const { return ToHScript(m_tr.m_pEnt); }
int HitBox() const { return m_tr.hitbox; }
// CBaseTrace stuff
bool IsDispSurface() { return m_tr.IsDispSurface(); }
bool IsDispSurfaceWalkable() { return m_tr.IsDispSurfaceWalkable(); }
bool IsDispSurfaceBuildable() { return m_tr.IsDispSurfaceBuildable(); }
bool IsDispSurfaceProp1() { return m_tr.IsDispSurfaceProp1(); }
bool IsDispSurfaceProp2() { return m_tr.IsDispSurfaceProp2(); }
Vector StartPos() const { return m_tr.startpos; }
Vector EndPos() const { return m_tr.endpos; }
float Fraction() const { return m_tr.fraction; }
int Contents() const { return m_tr.contents; }
int DispFlags() const { return m_tr.dispFlags; }
bool AllSolid() const { return m_tr.allsolid; }
bool StartSolid() const { return m_tr.startsolid; }
trace_t &GetTrace() { return m_tr; }
void Destroy() { delete this; }
private:
trace_t m_tr;
};
BEGIN_SCRIPTDESC_ROOT_NAMED( CTraceInfoAccessor, "CGameTrace", "Handle for accessing trace_t info." )
DEFINE_SCRIPTFUNC( DidHitWorld, "Returns whether the trace hit the world entity or not." )
DEFINE_SCRIPTFUNC( DidHitNonWorldEntity, "Returns whether the trace hit something other than the world entity." )
DEFINE_SCRIPTFUNC( GetEntityIndex, "Returns the index of whatever entity this trace hit." )
DEFINE_SCRIPTFUNC( DidHit, "Returns whether the trace hit anything." )
DEFINE_SCRIPTFUNC( FractionLeftSolid, "If this trace started within a solid, this is the point in the trace's fraction at which it left that solid." )
DEFINE_SCRIPTFUNC( HitGroup, "Returns the specific hit group this trace hit if it hit an entity." )
DEFINE_SCRIPTFUNC( PhysicsBone, "Returns the physics bone this trace hit if it hit an entity." )
DEFINE_SCRIPTFUNC( Entity, "Returns the entity this trace has hit." )
DEFINE_SCRIPTFUNC( HitBox, "Returns the hitbox of the entity this trace has hit. If it hit the world entity, this returns the static prop index." )
DEFINE_SCRIPTFUNC( IsDispSurface, "Returns whether this trace hit a displacement." )
DEFINE_SCRIPTFUNC( IsDispSurfaceWalkable, "Returns whether DISPSURF_FLAG_WALKABLE is ticked on the displacement this trace hit." )
DEFINE_SCRIPTFUNC( IsDispSurfaceBuildable, "Returns whether DISPSURF_FLAG_BUILDABLE is ticked on the displacement this trace hit." )
DEFINE_SCRIPTFUNC( IsDispSurfaceProp1, "Returns whether DISPSURF_FLAG_SURFPROP1 is ticked on the displacement this trace hit." )
DEFINE_SCRIPTFUNC( IsDispSurfaceProp2, "Returns whether DISPSURF_FLAG_SURFPROP2 is ticked on the displacement this trace hit." )
DEFINE_SCRIPTFUNC( StartPos, "Gets the trace's start position." )
DEFINE_SCRIPTFUNC( EndPos, "Gets the trace's end position." )
DEFINE_SCRIPTFUNC( Fraction, "Gets the fraction of the trace completed. For example, if the trace stopped exactly halfway to the end position, this would be 0.5." )
DEFINE_SCRIPTFUNC( Contents, "Gets the contents of the surface the trace has hit." )
DEFINE_SCRIPTFUNC( DispFlags, "Gets the displacement flags of the surface the trace has hit." )
DEFINE_SCRIPTFUNC( AllSolid, "Returns whether the trace is completely within a solid." )
DEFINE_SCRIPTFUNC( StartSolid, "Returns whether the trace started within a solid." )
DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." )
END_SCRIPTDESC();
static HSCRIPT ScriptTraceLineComplex( const Vector &vecStart, const Vector &vecEnd, HSCRIPT entIgnore, int iMask, int iCollisionGroup )
{
// The script is responsible for deleting this via Destroy().
CTraceInfoAccessor *traceInfo = new CTraceInfoAccessor();
HSCRIPT hScript = g_pScriptVM->RegisterInstance( traceInfo );
CBaseEntity *pLooker = ToEnt(entIgnore);
UTIL_TraceLine( vecStart, vecEnd, iMask, pLooker, iCollisionGroup, &traceInfo->GetTrace());
return hScript;
}
static HSCRIPT ScriptTraceHullComplex( const Vector &vecStart, const Vector &vecEnd, const Vector &hullMin, const Vector &hullMax,
HSCRIPT entIgnore, int iMask, int iCollisionGroup )
{
// The script is responsible for deleting this via Destroy().
CTraceInfoAccessor *traceInfo = new CTraceInfoAccessor();
HSCRIPT hScript = g_pScriptVM->RegisterInstance( traceInfo );
CBaseEntity *pLooker = ToEnt(entIgnore);
UTIL_TraceHull( vecStart, vecEnd, hullMin, hullMax, iMask, pLooker, iCollisionGroup, &traceInfo->GetTrace());
return hScript;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
BEGIN_SCRIPTDESC_ROOT_NAMED( CFireBulletsInfoAccessor, "FireBulletsInfo_t", "Handle for accessing FireBulletsInfo_t info." )
DEFINE_SCRIPTFUNC( GetShots, "Gets the number of shots which should be fired." )
DEFINE_SCRIPTFUNC( SetShots, "Sets the number of shots which should be fired." )
DEFINE_SCRIPTFUNC( GetSource, "Gets the source of the bullets." )
DEFINE_SCRIPTFUNC( SetSource, "Sets the source of the bullets." )
DEFINE_SCRIPTFUNC( GetDirShooting, "Gets the direction of the bullets." )
DEFINE_SCRIPTFUNC( SetDirShooting, "Sets the direction of the bullets." )
DEFINE_SCRIPTFUNC( GetSpread, "Gets the spread of the bullets." )
DEFINE_SCRIPTFUNC( SetSpread, "Sets the spread of the bullets." )
DEFINE_SCRIPTFUNC( GetDistance, "Gets the distance the bullets should travel." )
DEFINE_SCRIPTFUNC( SetDistance, "Sets the distance the bullets should travel." )
DEFINE_SCRIPTFUNC( GetAmmoType, "Gets the ammo type the bullets should use." )
DEFINE_SCRIPTFUNC( SetAmmoType, "Sets the ammo type the bullets should use." )
DEFINE_SCRIPTFUNC( GetTracerFreq, "Gets the tracer frequency." )
DEFINE_SCRIPTFUNC( SetTracerFreq, "Sets the tracer frequency." )
DEFINE_SCRIPTFUNC( GetDamage, "Gets the damage the bullets should deal. 0 = use ammo type" )
DEFINE_SCRIPTFUNC( SetDamage, "Sets the damage the bullets should deal. 0 = use ammo type" )
DEFINE_SCRIPTFUNC( GetPlayerDamage, "Gets the damage the bullets should deal when hitting the player. 0 = use regular damage" )
DEFINE_SCRIPTFUNC( SetPlayerDamage, "Sets the damage the bullets should deal when hitting the player. 0 = use regular damage" )
DEFINE_SCRIPTFUNC( GetFlags, "Gets the flags the bullets should use." )
DEFINE_SCRIPTFUNC( SetFlags, "Sets the flags the bullets should use." )
DEFINE_SCRIPTFUNC( GetDamageForceScale, "Gets the scale of the damage force applied by the bullets." )
DEFINE_SCRIPTFUNC( SetDamageForceScale, "Sets the scale of the damage force applied by the bullets." )
DEFINE_SCRIPTFUNC( GetAttacker, "Gets the entity considered to be the one who fired the bullets." )
DEFINE_SCRIPTFUNC( SetAttacker, "Sets the entity considered to be the one who fired the bullets." )
DEFINE_SCRIPTFUNC( GetAdditionalIgnoreEnt, "Gets the optional entity which the bullets should ignore." )
DEFINE_SCRIPTFUNC( SetAdditionalIgnoreEnt, "Sets the optional entity which the bullets should ignore." )
DEFINE_SCRIPTFUNC( GetPrimaryAttack, "Gets whether the bullets came from a primary attack." )
DEFINE_SCRIPTFUNC( SetPrimaryAttack, "Sets whether the bullets came from a primary attack." )
//DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." )
END_SCRIPTDESC();
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
HSCRIPT CFireBulletsInfoAccessor::GetAttacker()
{
return ToHScript( m_info->m_pAttacker );
}
void CFireBulletsInfoAccessor::SetAttacker( HSCRIPT value )
{
m_info->m_pAttacker = ToEnt( value );
}
HSCRIPT CFireBulletsInfoAccessor::GetAdditionalIgnoreEnt()
{
return ToHScript( m_info->m_pAdditionalIgnoreEnt );
}
void CFireBulletsInfoAccessor::SetAdditionalIgnoreEnt( HSCRIPT value )
{
m_info->m_pAdditionalIgnoreEnt = ToEnt( value );
}
static HSCRIPT CreateFireBulletsInfo( int cShots, const Vector &vecSrc, const Vector &vecDirShooting,
const Vector &vecSpread, float iDamage, HSCRIPT pAttacker )
{
// The script is responsible for deleting this via DestroyFireBulletsInfo().
FireBulletsInfo_t *info = new FireBulletsInfo_t();
CFireBulletsInfoAccessor *bulletsInfo = new CFireBulletsInfoAccessor( info );
HSCRIPT hScript = g_pScriptVM->RegisterInstance( bulletsInfo );
bulletsInfo->SetShots( cShots );
bulletsInfo->SetSource( vecSrc );
bulletsInfo->SetDirShooting( vecDirShooting );
bulletsInfo->SetSpread( vecSpread );
bulletsInfo->SetDamage( iDamage );
bulletsInfo->SetAttacker( pAttacker );
return hScript;
}
static void DestroyFireBulletsInfo( HSCRIPT hBulletsInfo )
{
if (hBulletsInfo)
{
CFireBulletsInfoAccessor *pInfo = (CFireBulletsInfoAccessor*)g_pScriptVM->GetInstanceValue( hBulletsInfo, GetScriptDescForClass( CFireBulletsInfoAccessor ) );
if (pInfo)
{
g_pScriptVM->RemoveInstance( hBulletsInfo );
pInfo->Destroy();
}
}
}
// For the function in baseentity.cpp
FireBulletsInfo_t *GetFireBulletsInfoFromInfo( HSCRIPT hBulletsInfo )
{
if (hBulletsInfo)
{
CFireBulletsInfoAccessor *pInfo = (CFireBulletsInfoAccessor*)g_pScriptVM->GetInstanceValue( hBulletsInfo, GetScriptDescForClass( CFireBulletsInfoAccessor ) );
if (pInfo)
{
return pInfo->GetInfo();
}
}
return NULL;
}
//=============================================================================
//=============================================================================
static void ScriptEntitiesInBox( HSCRIPT hTable, int listMax, const Vector &hullMin, const Vector &hullMax, int iMask )
{
CBaseEntity *list[1024];
int count = UTIL_EntitiesInBox( list, listMax, hullMin, hullMax, iMask );
for ( int i = 0; i < count; i++ )
{
g_pScriptVM->SetValue( hTable, STRING(list[i]->GetEntityName()), ToHScript( list[i] ) );
}
}
static void ScriptEntitiesAtPoint( HSCRIPT hTable, int listMax, const Vector &point, int iMask )
{
CBaseEntity *list[1024];
int count = UTIL_EntitiesAtPoint( list, listMax, point, iMask );
for ( int i = 0; i < count; i++ )
{
g_pScriptVM->SetValue( hTable, STRING(list[i]->GetEntityName()), ToHScript( list[i] ) );
}
}
static void ScriptEntitiesInSphere( HSCRIPT hTable, int listMax, const Vector &center, float radius, int iMask )
{
CBaseEntity *list[1024];
int count = UTIL_EntitiesInSphere( list, listMax, center, radius, iMask );
for ( int i = 0; i < count; i++ )
{
g_pScriptVM->SetValue( hTable, STRING(list[i]->GetEntityName()), ToHScript( list[i] ) );
}
}
//=============================================================================
//=============================================================================
bool ScriptMatcherMatch( const char *pszQuery, const char *szValue ) { return Matcher_Match( pszQuery, szValue ); }
//=============================================================================
//=============================================================================
extern void RegisterMathScriptFunctions();
void RegisterSharedScriptFunctions()
{
//
// Due to this being a custom integration of VScript based on the Alien Swarm SDK, we don't have access to
// some of the code normally available in games like L4D2 or Valve's original VScript DLL.
// Instead, that code is recreated here, shared between server and client.
//
#ifndef CLIENT_DLL
ScriptRegisterFunctionNamed( g_pScriptVM, NDebugOverlay::BoxDirection, "DebugDrawBoxDirection", "Draw a debug forward box" );
ScriptRegisterFunctionNamed( g_pScriptVM, NDebugOverlay::Text, "DebugDrawText", "Draw a debug overlay text" );
ScriptRegisterFunction( g_pScriptVM, AddThinkToEnt, "This will put a think function onto an entity, or pass null to remove it. This is NOT chained, so be careful." );
ScriptRegisterFunction( g_pScriptVM, EntIndexToHScript, "Returns the script handle for the given entity index." );
ScriptRegisterFunction( g_pScriptVM, PrecacheEntityFromTable, "Precache an entity from KeyValues in a table." );
ScriptRegisterFunction( g_pScriptVM, SpawnEntityFromTable, "Native function for entity spawning." );
#endif
g_pScriptVM->RegisterInstance( &g_ScriptConvarLookup, "Convars" );
g_pScriptVM->RegisterInstance( &g_ScriptNetPropManager, "NetProps" );
// Functions unique to Mapbase
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptColorPrint, "printc", "Version of print() which takes a color before the message." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptColorPrintL, "printcl", "Version of printl() which takes a color before the message." );
#ifndef CLIENT_DLL
ScriptRegisterFunction( g_pScriptVM, SpawnEntityFromKeyValues, "Spawns an entity with the keyvalues in a CScriptKeyValues handle." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptDispatchSpawn, "DispatchSpawn", "Spawns an unspawned entity." );
#endif
ScriptRegisterFunction( g_pScriptVM, CreateDamageInfo, "Creates damage info." );
ScriptRegisterFunction( g_pScriptVM, DestroyDamageInfo, "Destroys damage info." );
ScriptRegisterFunction( g_pScriptVM, ImpulseScale, "Returns an impulse scale required to push an object." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateExplosiveDamageForce, "CalculateExplosiveDamageForce", "Fill out a damage info handle with a damage force for an explosive." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateBulletDamageForce, "CalculateBulletDamageForce", "Fill out a damage info handle with a damage force for a bullet impact." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCalculateMeleeDamageForce, "CalculateMeleeDamageForce", "Fill out a damage info handle with a damage force for a melee impact." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGuessDamageForce, "GuessDamageForce", "Try and guess the physics force to use." );
ScriptRegisterFunction( g_pScriptVM, CreateFireBulletsInfo, "Creates FireBullets info." );
ScriptRegisterFunction( g_pScriptVM, DestroyFireBulletsInfo, "Destroys FireBullets info." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptTraceLineComplex, "TraceLineComplex", "Complex version of TraceLine which takes 2 points, an ent to ignore, a trace mask, and a collision group. Returns a handle which can access all trace info." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptTraceHullComplex, "TraceHullComplex", "Takes 2 points, min/max hull bounds, an ent to ignore, a trace mask, and a collision group to trace to a point using a hull. Returns a handle which can access all trace info." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptEntitiesInBox, "EntitiesInBox", "Gets all entities which are within a worldspace box." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptEntitiesAtPoint, "EntitiesAtPoint", "Gets all entities which are intersecting a point in space." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptEntitiesInSphere, "EntitiesInSphere", "Gets all entities which are within a sphere." );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMatcherMatch, "Matcher_Match", "Compares a string to a query using Mapbase's matcher system, supporting wildcards, RS matchers, etc." );
ScriptRegisterFunction( g_pScriptVM, Matcher_NamesMatch, "Compares a string to a query using Mapbase's matcher system using wildcards only." );
ScriptRegisterFunction( g_pScriptVM, AppearsToBeANumber, "Checks if the given string appears to be a number." );
RegisterMathScriptFunctions();
#ifdef CLIENT_DLL
VScriptRunScript( "vscript_client", true );
#else
VScriptRunScript( "vscript_server", true );
#endif
}

View File

@ -36,6 +36,7 @@ public:
m_pEvent( 0 ),
m_pScene( 0 ),
m_pActor( 0 ),
m_hSceneEntity(0),
m_bStarted( false ),
m_iLayer( -1 ),
m_iPriority( 0 ),
@ -63,6 +64,8 @@ public:
// Current actor
CChoreoActor *m_pActor;
CHandle< CSceneEntity > m_hSceneEntity;
// Set after the first time the event has been configured ( allows
// bumping markov index only at start of event playback, not every frame )
bool m_bStarted;

View File

@ -31,6 +31,60 @@ BEGIN_SIMPLE_DATADESC( CTakeDamageInfo )
DEFINE_FIELD( m_iDamagedOtherPlayers, FIELD_INTEGER),
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CTakeDamageInfo, "Damage information handler." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetInflictor, "GetInflictor", "Gets the inflictor." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetInflictor, "SetInflictor", "Sets the inflictor." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetWeapon, "GetWeapon", "Gets the weapon." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetWeapon, "SetWeapon", "Sets the weapon." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttacker, "GetAttacker", "Gets the attacker." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAttacker, "SetAttacker", "Sets the attacker." )
DEFINE_SCRIPTFUNC( GetDamage, "Gets the damage." )
DEFINE_SCRIPTFUNC( SetDamage, "Sets the damage." )
DEFINE_SCRIPTFUNC( GetMaxDamage, "Gets the max damage." )
DEFINE_SCRIPTFUNC( SetMaxDamage, "Sets the max damage." )
DEFINE_SCRIPTFUNC( ScaleDamage, "Scales the damage." )
DEFINE_SCRIPTFUNC( AddDamage, "Adds to the damage." )
DEFINE_SCRIPTFUNC( SubtractDamage, "Removes from the damage." )
DEFINE_SCRIPTFUNC( GetDamageBonus, "Gets the damage bonus." )
DEFINE_SCRIPTFUNC( SetDamageBonus, "Sets the damage bonus." )
DEFINE_SCRIPTFUNC( GetBaseDamage, "Gets the base damage." )
DEFINE_SCRIPTFUNC( BaseDamageIsValid, "Checks if the base damage is valid." )
DEFINE_SCRIPTFUNC( GetDamageForce, "Gets the damage force." )
DEFINE_SCRIPTFUNC( SetDamageForce, "Sets the damage force." )
DEFINE_SCRIPTFUNC( ScaleDamageForce, "Scales the damage force." )
DEFINE_SCRIPTFUNC( GetDamagePosition, "Gets the damage position." )
DEFINE_SCRIPTFUNC( SetDamagePosition, "Sets the damage position." )
DEFINE_SCRIPTFUNC( GetReportedPosition, "Gets the reported damage position." )
DEFINE_SCRIPTFUNC( SetReportedPosition, "Sets the reported damage position." )
DEFINE_SCRIPTFUNC( GetDamageType, "Gets the damage type." )
DEFINE_SCRIPTFUNC( SetDamageType, "Sets the damage type." )
DEFINE_SCRIPTFUNC( AddDamageType, "Adds to the damage type." )
DEFINE_SCRIPTFUNC( GetDamageCustom, "Gets the damage custom." )
DEFINE_SCRIPTFUNC( SetDamageCustom, "Sets the damage custom." )
DEFINE_SCRIPTFUNC( GetDamageStats, "Gets the damage stats." )
DEFINE_SCRIPTFUNC( SetDamageStats, "Sets the damage stats." )
DEFINE_SCRIPTFUNC( IsForceFriendlyFire, "Gets force friendly fire." )
DEFINE_SCRIPTFUNC( SetForceFriendlyFire, "Sets force friendly fire." )
DEFINE_SCRIPTFUNC( GetAmmoType, "Gets the ammo type." )
DEFINE_SCRIPTFUNC( SetAmmoType, "Sets the ammo type." )
DEFINE_SCRIPTFUNC( GetAmmoName, "Gets the ammo type name." )
DEFINE_SCRIPTFUNC( GetPlayerPenetrationCount, "Gets the player penetration count." )
DEFINE_SCRIPTFUNC( SetPlayerPenetrationCount, "Sets the player penetration count." )
DEFINE_SCRIPTFUNC( GetDamagedOtherPlayers, "Gets whether other players have been damaged." )
DEFINE_SCRIPTFUNC( SetDamagedOtherPlayers, "Sets whether other players have been damaged." )
END_SCRIPTDESC();
#endif
void CTakeDamageInfo::Init( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, const Vector &reportedPosition, float flDamage, int bitsDamageType, int iCustomDamage )
{
m_hInflictor = pInflictor;
@ -166,6 +220,50 @@ const char *CTakeDamageInfo::GetAmmoName() const
return pszAmmoType;
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CTakeDamageInfo::ScriptGetInflictor() const
{
return ToHScript( GetInflictor() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTakeDamageInfo::ScriptSetInflictor( HSCRIPT pInflictor )
{
SetInflictor( ToEnt( pInflictor ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CTakeDamageInfo::ScriptGetWeapon() const
{
return ToHScript( GetWeapon() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTakeDamageInfo::ScriptSetWeapon( HSCRIPT pWeapon )
{
SetWeapon( ToEnt( pWeapon ) );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CTakeDamageInfo::ScriptGetAttacker() const
{
return ToHScript( GetAttacker() );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTakeDamageInfo::ScriptSetAttacker( HSCRIPT pAttacker )
{
SetAttacker( ToEnt( pAttacker ) );
}
#endif
// -------------------------------------------------------------------------------------------------- //
// MultiDamage
// Collects multiple small damages into a single damage

View File

@ -14,6 +14,10 @@
#include "networkvar.h" // todo: change this when DECLARE_CLASS is moved into a better location.
#ifdef MAPBASE_VSCRIPT
#include "vscript/ivscript.h"
#endif
// Used to initialize m_flBaseDamage to something that we know pretty much for sure
// hasn't been modified by a user.
#define BASEDAMAGE_NOT_SPECIFIED FLT_MAX
@ -102,6 +106,15 @@ public:
// For designer debug output.
static void DebugGetDamageTypeString(unsigned int DamageType, char *outbuf, int outbuflength );
#ifdef MAPBASE_VSCRIPT
HSCRIPT ScriptGetInflictor() const;
void ScriptSetInflictor( HSCRIPT pInflictor );
HSCRIPT ScriptGetWeapon() const;
void ScriptSetWeapon( HSCRIPT pWeapon );
HSCRIPT ScriptGetAttacker() const;
void ScriptSetAttacker( HSCRIPT pAttacker );
#endif
//private:
void CopyDamageToBaseDamage();

Some files were not shown because too many files have changed in this diff Show More