diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index b4f9e404b2..c1ad395005 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -426,11 +426,16 @@ BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_AnimTimeMustBeFirst ) 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_NAMED( GetAbsOrigin, "GetOrigin", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" ) +#ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC_NAMED( ScriptGetRight, "GetRightVector", "Get the right vector of the entity" ) + DEFINE_SCRIPTFUNC_NAMED( GetTeamNumber, "GetTeam", "Gets this entity's team" ) +#else + DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" ) DEFINE_SCRIPTFUNC( GetTeamNumber, "Gets this entity's team" ) +#endif + DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" ) #ifdef MAPBASE_VSCRIPT DEFINE_SCRIPTFUNC( GetHealth, "" ) diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index a37140d467..478949a264 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -1132,7 +1132,11 @@ class C_BaseEntity : public IClientEntity 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; } +#ifdef MAPBASE_VSCRIPT + const Vector& ScriptGetRight(void) { static Vector vecRight; GetVectors(NULL, &vecRight, NULL); return vecRight; } +#else + const Vector& ScriptGetLeft(void) { static Vector vecRight; GetVectors(NULL, &vecRight, NULL); return vecRight; } +#endif const Vector& ScriptGetUp(void) { static Vector vecUp; GetVectors(NULL, NULL, &vecUp); return vecUp; } #ifdef MAPBASE_VSCRIPT diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index a8b70b8dc1..175068950b 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2136,6 +2136,9 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity ) DEFINE_FUNCTION( SUB_CallUseToggle ), DEFINE_THINKFUNC( ShadowCastDistThink ), DEFINE_THINKFUNC( ScriptThink ), +#ifdef MAPBASE_VSCRIPT + DEFINE_THINKFUNC( ScriptThinkH ), +#endif #ifdef MAPBASE DEFINE_FUNCTION( SUB_RemoveWhenNotVisible ), @@ -2173,6 +2176,10 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC( GetClassname, "" ) DEFINE_SCRIPTFUNC_NAMED( GetEntityNameAsCStr, "GetName", "" ) +#ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC( GetDebugName, "If name exists returns name, otherwise returns classname" ) + DEFINE_SCRIPTFUNC_NAMED( SetNameAsCStr, "SetName", "" ) +#endif DEFINE_SCRIPTFUNC( GetPreTemplateName, "Get the entity name stripped of template unique decoration" ) DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" ) @@ -2185,11 +2192,15 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC( GetLocalAngles, "GetLocalAngles" ) DEFINE_SCRIPTFUNC( SetLocalAngles, "SetLocalAngles" ) #endif - DEFINE_SCRIPTFUNC_NAMED( ScriptSetOrigin, "SetOrigin", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetForward, "SetForwardVector", "Set the orientation of the entity to have this forward vector" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" ) +#ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC_NAMED( ScriptGetRight, "GetRightVector", "Get the right vector of the entity" ) +#else + DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" ) +#endif DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" ) #ifdef MAPBASE_VSCRIPT @@ -2199,16 +2210,17 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptEntityToWorldTransform, "EntityToWorldTransform", "Get the entity's transform" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetPhysicsObject, "GetPhysicsObject", "Get the entity's physics object if it has one" ) + + DEFINE_SCRIPTFUNC( ApplyAbsVelocityImpulse, "" ) + DEFINE_SCRIPTFUNC( ApplyLocalAngularVelocityImpulse, "" ) #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 @@ -2225,7 +2237,10 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptSetOwner, "SetOwner", "" ) DEFINE_SCRIPTFUNC_NAMED( GetTeamNumber, "GetTeam", "" ) DEFINE_SCRIPTFUNC_NAMED( ChangeTeam, "SetTeam", "" ) - + +#ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC_NAMED( ScriptSetParent, "SetParent", "" ) +#endif DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveParent, "GetMoveParent", "If in hierarchy, retrieves the entity's parent" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetRootMoveParent, "GetRootMoveParent", "If in hierarchy, walks up the hierarchy to find the root parent" ) DEFINE_SCRIPTFUNC_NAMED( ScriptFirstMoveChild, "FirstMoveChild", "" ) @@ -2259,16 +2274,17 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptAddOutput, "AddOutput", "Add an output" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValue, "GetKeyValue", "Get a keyvalue" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetColorVector", "Get the render color as a vector" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetColorR", "Get the render color's R value" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetColorG", "Get the render color's G value" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorB, "GetColorB", "Get the render color's B value" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetAlpha, "GetAlpha", "Get the render color's alpha value" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorVector, "SetColorVector", "Set the render color as a vector" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorR, "SetColorR", "Set the render color's R value" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorG, "SetColorG", "Set the render color's G value" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetColorB", "Set the render color's B value" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetAlpha", "Set the render color's alpha value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetRenderColorVector", "Get the render color as a vector" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetRenderColorR", "Get the render color's R value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetRenderColorG", "Get the render color's G value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorB, "GetRenderColorB", "Get the render color's B value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAlpha, "GetRenderAlpha", "Get the render color's alpha value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorVector, "SetRenderColorVector", "Set the render color as a vector" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColor, "SetRenderColor", "Set the render color" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorR, "SetRenderColorR", "Set the render color's R value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorG, "SetRenderColorG", "Set the render color's G value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetRenderColorB", "Set the render color's B value" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetRenderAlpha", "Set the render color's alpha value" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetRenderMode, "GetRenderMode", "Get render mode" ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetRenderMode, "SetRenderMode", "Set render mode" ) @@ -2296,6 +2312,13 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC( GetCollisionGroup, "Get the collision group" ) DEFINE_SCRIPTFUNC( SetCollisionGroup, "Set the collision group" ) + DEFINE_SCRIPTFUNC( GetGravity, "" ) + DEFINE_SCRIPTFUNC( SetGravity, "" ) + DEFINE_SCRIPTFUNC( GetFriction, "" ) + DEFINE_SCRIPTFUNC( SetFriction, "" ) + DEFINE_SCRIPTFUNC( GetMass, "" ) + DEFINE_SCRIPTFUNC( SetMass, "" ) + DEFINE_SCRIPTFUNC( GetSolidFlags, "Get solid flags" ) DEFINE_SCRIPTFUNC( AddSolidFlags, "Add solid flags" ) DEFINE_SCRIPTFUNC( RemoveSolidFlags, "Remove solid flags" ) @@ -2305,14 +2328,26 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" 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." ) DEFINE_SCRIPTFUNC( IsWorld, "Returns true if this entity is the world." ) + + // DEFINE_SCRIPTFUNC( IsMarkedForDeletion, "Returns true if the entity is valid and marked for deletion." ) #endif DEFINE_SCRIPTFUNC( ValidateScriptScope, "Ensure that an entity's script scope has been created" ) DEFINE_SCRIPTFUNC( GetScriptScope, "Retrieve the script-side data associated with an entity" ) +#ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC( GetOrCreatePrivateScriptScope, "Create and retrieve the script-side data associated with an entity" ) +#endif DEFINE_SCRIPTFUNC( GetScriptId, "Retrieve the unique identifier used to refer to the entity within the scripting system" ) DEFINE_SCRIPTFUNC_NAMED( GetScriptOwnerEntity, "GetOwner", "Gets this entity's owner" ) DEFINE_SCRIPTFUNC_NAMED( SetScriptOwnerEntity, "SetOwner", "Sets this entity's owner" ) DEFINE_SCRIPTFUNC( entindex, "" ) + +#ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC_NAMED( ScriptSetThinkFunction, "SetThinkFunction", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptStopThinkFunction, "StopThinkFunction", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetThink, "SetThink", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptStopThink, "StopThink", "" ) +#endif END_SCRIPTDESC(); @@ -2418,6 +2453,13 @@ void CBaseEntity::UpdateOnRemove( void ) if ( m_hScriptInstance ) { +#ifdef MAPBASE_VSCRIPT + HSCRIPT hFunc = LookupScriptFunction("UpdateOnRemove"); + if ( hFunc ) + { + CallScriptFunctionHandle( hFunc, NULL ); + } +#endif g_pScriptVM->RemoveInstance( m_hScriptInstance ); m_hScriptInstance = NULL; } @@ -8341,8 +8383,8 @@ void CBaseEntity::ScriptThink(void) // 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"); + + SetNextThink( gpGlobals->curtime + flThinkFrequency, "ScriptThink" ); } else { @@ -8350,14 +8392,110 @@ void CBaseEntity::ScriptThink(void) } } +#ifdef MAPBASE_VSCRIPT +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptSetThinkFunction(const char *szFunc, float time) +{ + // Empty string stops thinking + if (!szFunc || szFunc[0] == '\0') + { + ScriptStopThinkFunction(); + } + else + { + m_iszScriptThinkFunction = AllocPooledString(szFunc); + SetContextThink( &CBaseEntity::ScriptThink, gpGlobals->curtime + time, "ScriptThink" ); + } +} + +void CBaseEntity::ScriptStopThinkFunction() +{ + m_iszScriptThinkFunction = NULL_STRING; + SetContextThink( NULL, TICK_NEVER_THINK, "ScriptThink" ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptThinkH() +{ + if (m_hfnThink) + { + ScriptVariant_t varThinkRetVal; + if (g_pScriptVM->ExecuteFunction(m_hfnThink, NULL, 0, &varThinkRetVal, NULL, true) == SCRIPT_ERROR) + { + DevWarning("%s FAILED to call script think function (invalid closure)!\n", GetDebugName()); + ScriptStopThink(); + return; + } + + float flThinkFrequency = 0.f; + if (!varThinkRetVal.AssignTo(&flThinkFrequency)) + { + // no return value stops thinking + ScriptStopThink(); + return; + } + + SetNextThink(gpGlobals->curtime + flThinkFrequency, "ScriptThinkH"); + } + else + { + DevWarning("%s FAILED to call script think function (invalid closure)!\n", GetDebugName()); + } +} + +void CBaseEntity::ScriptSetThink(HSCRIPT hFunc, float time) +{ + if (hFunc) + { + if (m_hfnThink) + { + // release old func + ScriptStopThink(); + } + + // no type check here, print error on call instead + m_hfnThink = hFunc; + + SetContextThink( &CBaseEntity::ScriptThinkH, gpGlobals->curtime + time, "ScriptThinkH" ); + } + else + { + ScriptStopThink(); + } +} + +void CBaseEntity::ScriptStopThink() +{ + if (m_hfnThink) + { + g_pScriptVM->ReleaseScript(m_hfnThink); + m_hfnThink = NULL; + } + SetContextThink( NULL, TICK_NEVER_THINK, "ScriptThinkH" ); +} +#endif // MAPBASE_VSCRIPT //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- const char* CBaseEntity::GetScriptId() { +#ifdef MAPBASE_VSCRIPT + return STRING(m_iszScriptId); +#else return STRING(m_iszScriptThinkFunction); +#endif } +//----------------------------------------------------------------------------- +// Recreate the old behaviour of GetScriptId under a new function +//----------------------------------------------------------------------------- +// const char* CBaseEntity::GetScriptThinkFunction() +// { +// return STRING(m_iszScriptThinkFunction); +// } + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- HSCRIPT CBaseEntity::GetScriptScope() @@ -8365,6 +8503,51 @@ HSCRIPT CBaseEntity::GetScriptScope() return m_ScriptScope; } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +#ifdef MAPBASE_VSCRIPT +HSCRIPT CBaseEntity::GetOrCreatePrivateScriptScope() +{ + ValidateScriptScope(); + return m_ScriptScope; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptSetParent(HSCRIPT hParent, const char *szAttachment) +{ + CBaseEntity *pParent = ToEnt(hParent); + if ( !pParent ) + { + SetParent(NULL); + return; + } + + // if an attachment is specified, the parent needs to be CBaseAnimating + if ( szAttachment && szAttachment[0] != '\0' ) + { + CBaseAnimating *pAnimating = pParent->GetBaseAnimating(); + if ( !pAnimating ) + { + Warning("ERROR: Tried to set parent for entity %s (%s), but its parent has no model.\n", GetClassname(), GetDebugName()); + return; + } + + int iAttachment = pAnimating->LookupAttachment(szAttachment); + if ( iAttachment <= 0 ) + { + Warning("ERROR: Tried to set parent for entity %s (%s), but it has no attachment named %s.\n", GetClassname(), GetDebugName(), szAttachment); + return; + } + + SetParent(pParent, iAttachment); + SetMoveType(MOVETYPE_NONE); + return; + } + + SetParent(pParent); +} +#endif //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- HSCRIPT CBaseEntity::ScriptGetMoveParent(void) @@ -9762,6 +9945,11 @@ void CBaseEntity::ScriptSetColorVector( const Vector& vecColor ) SetRenderColor( vecColor.x, vecColor.y, vecColor.z ); } +void CBaseEntity::ScriptSetColor( int r, int g, int b ) +{ + SetRenderColor( r, g, b ); +} + //----------------------------------------------------------------------------- // Vscript: Gets the entity matrix transform //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index fe03c1ff99..740dc76297 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -591,6 +591,9 @@ class CBaseEntity : public IServerEntity CBaseEntity *NextMovePeer( void ); void SetName( string_t newTarget ); +#ifdef MAPBASE_VSCRIPT + void SetNameAsCStr( const char *newTarget ); +#endif void SetParent( string_t newParent, CBaseEntity *pActivator, int iAttachment = -1 ); // Set the movement parent. Your local origin and angles will become relative to this parent. @@ -1363,6 +1366,10 @@ class CBaseEntity : public IServerEntity void SetGravity( float gravity ); float GetFriction( void ) const; void SetFriction( float flFriction ); +#ifdef MAPBASE_VSCRIPT + void SetMass(float mass); + float GetMass(); +#endif virtual bool FVisible ( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); virtual bool FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); @@ -1958,8 +1965,21 @@ class CBaseEntity : public IServerEntity void ConnectOutputToScript(const char* pszOutput, const char* pszScriptFunc); void DisconnectOutputFromScript(const char* pszOutput, const char* pszScriptFunc); void ScriptThink(); +#ifdef MAPBASE_VSCRIPT + void ScriptSetThinkFunction(const char *szFunc, float time); + void ScriptStopThinkFunction(); + void ScriptSetThink(HSCRIPT hFunc, float time); + void ScriptStopThink(); + void ScriptThinkH(); +private: + HSCRIPT m_hfnThink; +public: +#endif const char* GetScriptId(); HSCRIPT GetScriptScope(); +#ifdef MAPBASE_VSCRIPT + HSCRIPT GetOrCreatePrivateScriptScope(); +#endif void RunPrecacheScripts(void); void RunOnPostSpawnScripts(void); @@ -1989,7 +2009,11 @@ class CBaseEntity : public IServerEntity 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; } +#ifdef MAPBASE_VSCRIPT + const Vector& ScriptGetRight(void) { static Vector vecRight; GetVectors(NULL, &vecRight, NULL); return vecRight; } +#else + const Vector& ScriptGetLeft(void) { static Vector vecRight; GetVectors(NULL, &vecRight, NULL); return vecRight; } +#endif const Vector& ScriptGetUp(void) { static Vector vecUp; GetVectors(NULL, NULL, &vecUp); return vecUp; } #ifdef MAPBASE_VSCRIPT @@ -1999,6 +2023,8 @@ class CBaseEntity : public IServerEntity HSCRIPT ScriptEntityToWorldTransform( void ); HSCRIPT ScriptGetPhysicsObject( void ); + + void ScriptSetParent(HSCRIPT hParent, const char *szAttachment); #endif const char* ScriptGetModelName(void) const; @@ -2037,6 +2063,7 @@ class CBaseEntity : public IServerEntity int ScriptGetColorB() { return m_clrRender.GetB(); } int ScriptGetAlpha() { return m_clrRender.GetA(); } void ScriptSetColorVector( const Vector& vecColor ); + void ScriptSetColor( int r, int g, int b ); void ScriptSetColorR( int iVal ) { SetRenderColorR( iVal ); } void ScriptSetColorG( int iVal ) { SetRenderColorG( iVal ); } void ScriptSetColorB( int iVal ) { SetRenderColorB( iVal ); } @@ -2203,6 +2230,12 @@ inline void CBaseEntity::SetName( string_t newName ) m_iName = newName; } +#ifdef MAPBASE_VSCRIPT +inline void CBaseEntity::SetNameAsCStr( const char *newName ) +{ + m_iName = AllocPooledString(newName); +} +#endif inline bool CBaseEntity::NameMatches( const char *pszNameOrWildcard ) { @@ -2380,6 +2413,37 @@ inline const QAngle& CBaseEntity::GetAbsAngles( void ) const return m_angAbsRotation; } +#ifdef MAPBASE_VSCRIPT +inline float CBaseEntity::GetMass() +{ + IPhysicsObject *vPhys = VPhysicsGetObject(); + if (vPhys) + { + return vPhys->GetMass(); + } + else + { + Warning("Tried to call GetMass() on %s but it has no physics.\n", GetDebugName()); + return -1; + } +} + +inline void CBaseEntity::SetMass(float mass) +{ + mass = MAX(0, mass); + Assert(mass > 0); + + IPhysicsObject *vPhys = VPhysicsGetObject(); + if (vPhys) + { + vPhys->SetMass(mass); + } + else + { + Warning("Tried to call SetMass() on %s but it has no physics.\n", GetDebugName()); + } +} +#endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index f193ddca73..91b529799f 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -490,7 +490,7 @@ BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) DEFINE_SCRIPTFUNC_NAMED( VScriptGetExpresser, "GetExpresser", "Gets a handle for this player's expresser." ) DEFINE_SCRIPTFUNC( GetPlayerName, "Gets the player's name." ) - DEFINE_SCRIPTFUNC_NAMED( GetUserID, "GetPlayerUserId", "Gets the player's user ID." ) + DEFINE_SCRIPTFUNC( GetUserID, "Gets the player's user ID." ) DEFINE_SCRIPTFUNC( GetNetworkIDString, "Gets the player's network (i.e. Steam) ID." ) DEFINE_SCRIPTFUNC( FragCount, "Gets the number of frags (kills) this player has in a multiplayer game." ) @@ -518,6 +518,10 @@ BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) DEFINE_SCRIPTFUNC( GetButtonDisabled, "Gets the player's currently unusable buttons." ) DEFINE_SCRIPTFUNC( GetButtonForced, "Gets the player's currently forced buttons." ) + DEFINE_SCRIPTFUNC( GetFOV, "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetFOVOwner, "GetFOVOwner", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetFOV, "SetFOV", "" ) + END_SCRIPTDESC(); #else BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseAnimating, "The player entity." ) @@ -9169,6 +9173,18 @@ void CBasePlayer::SetDefaultFOV( int FOV ) m_iDefaultFOV = ( FOV == 0 ) ? g_pGameRules->DefaultFOV() : FOV; } +#ifdef MAPBASE_VSCRIPT +void CBasePlayer::ScriptSetFOV(int iFOV, float flRate) +{ + m_iFOVStart = GetFOV(); + + m_flFOVTime = gpGlobals->curtime; + m_iFOV = iFOV; + + m_Local.m_flFOVRate = flRate; +} +#endif + //----------------------------------------------------------------------------- // Purpose: // static func // Input : set - diff --git a/sp/src/game/server/player.h b/sp/src/game/server/player.h index 885bdf05f3..568402522e 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -771,6 +771,10 @@ class CBasePlayer : public CBaseCombatCharacter int GetDefaultFOV( void ) const; // Default FOV if not specified otherwise int GetFOVForNetworking( void ); // Get the current FOV used for network computations bool SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate = 0.0f, int iZoomStart = 0 ); // Alters the base FOV of the player (must have a valid requester) +#ifdef MAPBASE_VSCRIPT + void ScriptSetFOV(int iFOV, float flSpeed); // Overrides player FOV, ignores zoom owner + HSCRIPT ScriptGetFOVOwner() { return ToHScript(m_hZoomOwner); } +#endif void SetDefaultFOV( int FOV ); // Sets the base FOV if nothing else is affecting it by zooming CBaseEntity *GetFOVOwner( void ) { return m_hZoomOwner; } float GetFOVDistanceAdjustFactor(); // shared between client and server diff --git a/sp/src/game/server/vscript_server.cpp b/sp/src/game/server/vscript_server.cpp index 4a76ec9082..4928374e70 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -17,6 +17,7 @@ #include "gamerules.h" #include "vscript_server.nut" #ifdef MAPBASE_VSCRIPT +#include "particle_parse.h" #include "world.h" #endif @@ -43,6 +44,12 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * ); class CScriptEntityIterator { public: +#ifdef MAPBASE_VSCRIPT + HSCRIPT GetLocalPlayer() + { + return ToHScript( UTIL_GetLocalPlayerOrListenServerHost() ); + } +#endif HSCRIPT First() { return Next(NULL); } HSCRIPT Next( HSCRIPT hStartEntity ) @@ -104,6 +111,9 @@ class CScriptEntityIterator } g_ScriptEntityIterator; BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptEntityIterator, "CEntities", SCRIPT_SINGLETON "The global list of entities" ) +#ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC( GetLocalPlayer, "Get local player or listen server host" ) +#endif 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" ) @@ -323,7 +333,422 @@ CScriptKeyValues::~CScriptKeyValues( ) m_pKeyValues = NULL; } +#ifdef MAPBASE_VSCRIPT +#define RETURN_IF_CANNOT_DRAW_OVERLAY\ + if (engine->IsPaused())\ + {\ + DevWarning("debugoverlay: cannot draw while the game paused!\n");\ + return;\ + } +class CDebugOverlayScriptHelper +{ +public: + + void Box(const Vector &origin, const Vector &mins, const Vector &maxs, int r, int g, int b, int a, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddBoxOverlay(origin, mins, maxs, vec3_angle, r, g, b, a, flDuration); + } + } + void BoxDirection(const Vector &origin, const Vector &mins, const Vector &maxs, const Vector &forward, int r, int g, int b, int a, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + QAngle f_angles = vec3_angle; + f_angles.y = UTIL_VecToYaw(forward); + + if (debugoverlay) + { + debugoverlay->AddBoxOverlay(origin, mins, maxs, f_angles, r, g, b, a, flDuration); + } + } + void BoxAngles(const Vector &origin, const Vector &mins, const Vector &maxs, const QAngle &angles, int r, int g, int b, int a, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddBoxOverlay(origin, mins, maxs, angles, r, g, b, a, flDuration); + } + } + void SweptBox(const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, const QAngle & angles, int r, int g, int b, int a, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddSweptBoxOverlay(start, end, mins, maxs, angles, r, g, b, a, flDuration); + } + } + void EntityBounds(HSCRIPT pEntity, int r, int g, int b, int a, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + const CCollisionProperty *pCollide = ToEnt(pEntity)->CollisionProp(); + if (debugoverlay) + { + debugoverlay->AddBoxOverlay(pCollide->GetCollisionOrigin(), pCollide->OBBMins(), pCollide->OBBMaxs(), pCollide->GetCollisionAngles(), r, g, b, a, flDuration); + } + } + void Line(const Vector &origin, const Vector &target, int r, int g, int b, bool noDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddLineOverlay(origin, target, r, g, b, noDepthTest, flDuration); + } + } + void Triangle(const Vector &p1, const Vector &p2, const Vector &p3, int r, int g, int b, int a, bool noDepthTest, float duration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddTriangleOverlay(p1, p2, p3, r, g, b, a, noDepthTest, duration); + } + } + void EntityText(int entityID, int text_offset, const char *text, float flDuration, int r, int g, int b, int a) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddEntityTextOverlay(entityID, text_offset, flDuration, + (int)clamp(r * 255.f, 0.f, 255.f), (int)clamp(g * 255.f, 0.f, 255.f), (int)clamp(b * 255.f, 0.f, 255.f), + (int)clamp(a * 255.f, 0.f, 255.f), text); + } + } + void EntityTextAtPosition(const Vector &origin, int text_offset, const char *text, float flDuration, int r, int g, int b, int a) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddTextOverlayRGB(origin, text_offset, flDuration, r, g, b, a, "%s", text); + } + } + void Grid(const Vector &vPosition) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddGridOverlay(vPosition); + } + } + void Text(const Vector &origin, const char *text, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + if (debugoverlay) + { + debugoverlay->AddTextOverlay(origin, flDuration, "%s", text); + } + } + void ScreenText(float fXpos, float fYpos, const char *text, int r, int g, int b, int a, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + if (debugoverlay) + { + debugoverlay->AddScreenTextOverlay(fXpos, fYpos, flDuration, r, g, b, a, text); + } + } + void Cross3D(const Vector &position, float size, int r, int g, int b, bool noDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Line( position + Vector(size,0,0), position - Vector(size,0,0), r, g, b, noDepthTest, flDuration ); + Line( position + Vector(0,size,0), position - Vector(0,size,0), r, g, b, noDepthTest, flDuration ); + Line( position + Vector(0,0,size), position - Vector(0,0,size), r, g, b, noDepthTest, flDuration ); + } + void Cross3DOriented(const Vector &position, const QAngle &angles, float size, int r, int g, int b, bool noDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector forward, right, up; + AngleVectors( angles, &forward, &right, &up ); + + forward *= size; + right *= size; + up *= size; + + Line( position + right, position - right, r, g, b, noDepthTest, flDuration ); + Line( position + forward, position - forward, r, g, b, noDepthTest, flDuration ); + Line( position + up, position - up, r, g, b, noDepthTest, flDuration ); + } + void DrawTickMarkedLine(const Vector &startPos, const Vector &endPos, float tickDist, int tickTextDist, int r, int g, int b, bool noDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector lineDir = (endPos - startPos); + float lineDist = VectorNormalize(lineDir); + int numTicks = lineDist / tickDist; + + Vector upVec = Vector(0,0,4); + Vector sideDir; + Vector tickPos = startPos; + int tickTextCnt = 0; + + CrossProduct(lineDir, upVec, sideDir); + + Line(startPos, endPos, r, g, b, noDepthTest, flDuration); + + for (int i = 0; i 0 ) + { + Triangle( p5, p4, p3, r, g, b, a, noDepthTest, flDuration ); + Triangle( p1, p7, p6, r, g, b, a, noDepthTest, flDuration ); + Triangle( p6, p2, p1, r, g, b, a, noDepthTest, flDuration ); + + Triangle( p3, p4, p5, r, g, b, a, noDepthTest, flDuration ); + Triangle( p6, p7, p1, r, g, b, a, noDepthTest, flDuration ); + Triangle( p1, p2, p6, r, g, b, a, noDepthTest, flDuration ); + } + } + void YawArrow(const Vector &startPos, float yaw, float length, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector forward = UTIL_YawToVector( yaw ); + HorzArrow( startPos, startPos + forward * length, width, r, g, b, a, noDepthTest, flDuration ); + } + void VertArrow(const Vector &startPos, const Vector &endPos, float width, int r, int g, int b, int a, bool noDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector lineDir = (endPos - startPos); + VectorNormalize( lineDir ); + Vector upVec; + Vector sideDir; + float radius = width / 2.0; + + VectorVectors( lineDir, sideDir, upVec ); + + Vector p1 = startPos - upVec * radius; + Vector p2 = endPos - lineDir * width - upVec * radius; + Vector p3 = endPos - lineDir * width - upVec * width; + Vector p4 = endPos; + Vector p5 = endPos - lineDir * width + upVec * width; + Vector p6 = endPos - lineDir * width + upVec * radius; + Vector p7 = startPos + upVec * radius; + + Line(p1, p2, r,g,b,noDepthTest,flDuration); + Line(p2, p3, r,g,b,noDepthTest,flDuration); + Line(p3, p4, r,g,b,noDepthTest,flDuration); + Line(p4, p5, r,g,b,noDepthTest,flDuration); + Line(p5, p6, r,g,b,noDepthTest,flDuration); + Line(p6, p7, r,g,b,noDepthTest,flDuration); + + if ( a > 0 ) + { + Triangle( p5, p4, p3, r, g, b, a, noDepthTest, flDuration ); + Triangle( p1, p7, p6, r, g, b, a, noDepthTest, flDuration ); + Triangle( p6, p2, p1, r, g, b, a, noDepthTest, flDuration ); + + Triangle( p3, p4, p5, r, g, b, a, noDepthTest, flDuration ); + Triangle( p6, p7, p1, r, g, b, a, noDepthTest, flDuration ); + Triangle( p1, p2, p6, r, g, b, a, noDepthTest, flDuration ); + } + } + void Axis(const Vector &position, const QAngle &angles, float size, bool noDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector xvec, yvec, zvec; + AngleVectors( angles, &xvec, &yvec, &zvec ); + + xvec = position + (size * xvec); + yvec = position - (size * yvec); + zvec = position + (size * zvec); + + Line( position, xvec, 255, 0, 0, noDepthTest, flDuration ); + Line( position, yvec, 0, 255, 0, noDepthTest, flDuration ); + Line( position, zvec, 0, 0, 255, noDepthTest, flDuration ); + } + void Sphere(const Vector ¢er, float radius, int r, int g, int b, bool noDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + Vector edge, lastEdge; + + float axisSize = radius; + Line( center + Vector( 0, 0, -axisSize ), center + Vector( 0, 0, axisSize ), r, g, b, noDepthTest, flDuration ); + Line( center + Vector( 0, -axisSize, 0 ), center + Vector( 0, axisSize, 0 ), r, g, b, noDepthTest, flDuration ); + Line( center + Vector( -axisSize, 0, 0 ), center + Vector( axisSize, 0, 0 ), r, g, b, noDepthTest, flDuration ); + + lastEdge = Vector( radius + center.x, center.y, center.z ); + float angle; + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = radius * cosf( angle / 180.0f * M_PI ) + center.x; + edge.y = center.y; + edge.z = radius * sinf( angle / 180.0f * M_PI ) + center.z; + + Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); + + lastEdge = edge; + } + + lastEdge = Vector( center.x, radius + center.y, center.z ); + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = center.x; + edge.y = radius * cosf( angle / 180.0f * M_PI ) + center.y; + edge.z = radius * sinf( angle / 180.0f * M_PI ) + center.z; + + Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); + + lastEdge = edge; + } + + lastEdge = Vector( center.x, radius + center.y, center.z ); + for( angle=0.0f; angle <= 360.0f; angle += 22.5f ) + { + edge.x = radius * cosf( angle / 180.0f * M_PI ) + center.x; + edge.y = radius * sinf( angle / 180.0f * M_PI ) + center.y; + edge.z = center.z; + + Line( edge, lastEdge, r, g, b, noDepthTest, flDuration ); + + lastEdge = edge; + } + } + void CircleOriented(const Vector &position, const QAngle &angles, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + matrix3x4_t xform; + AngleMatrix(angles, position, xform); + Vector xAxis, yAxis; + MatrixGetColumn(xform, 2, xAxis); + MatrixGetColumn(xform, 1, yAxis); + Circle(position, xAxis, yAxis, radius, r, g, b, a, bNoDepthTest, flDuration); + } + void Circle(const Vector &position, const Vector &xAxis, const Vector &yAxis, float radius, int r, int g, int b, int a, bool bNoDepthTest, float flDuration) + { + RETURN_IF_CANNOT_DRAW_OVERLAY + + const unsigned int nSegments = 16; + const float flRadStep = (M_PI*2.0f) / (float) nSegments; + + Vector vecLastPosition; + Vector vecStart = position + xAxis * radius; + Vector vecPosition = vecStart; + + for ( int i = 1; i <= nSegments; i++ ) + { + vecLastPosition = vecPosition; + + float flSin, flCos; + SinCos( flRadStep*i, &flSin, &flCos ); + vecPosition = position + (xAxis * flCos * radius) + (yAxis * flSin * radius); + + Line( vecLastPosition, vecPosition, r, g, b, bNoDepthTest, flDuration ); + + if ( a && i > 1 ) + { + debugoverlay->AddTriangleOverlay( vecStart, vecLastPosition, vecPosition, r, g, b, a, bNoDepthTest, flDuration ); + } + } + } + void ClearAllOverlays() + { + // Clear all entities of their debug overlays + for (CBaseEntity *pEntity = gEntList.FirstEnt(); pEntity; pEntity = gEntList.NextEnt(pEntity)) + { + pEntity->m_debugOverlays = 0; + } + + if (debugoverlay) + { + debugoverlay->ClearAllOverlays(); + } + } + +private: +} g_ScriptDebugOverlay; + +BEGIN_SCRIPTDESC_ROOT(CDebugOverlayScriptHelper, SCRIPT_SINGLETON "CDebugOverlayScriptHelper") + DEFINE_SCRIPTFUNC( Box, "" ) + DEFINE_SCRIPTFUNC( BoxDirection, "" ) + DEFINE_SCRIPTFUNC( BoxAngles, "" ) + DEFINE_SCRIPTFUNC( SweptBox, "" ) + DEFINE_SCRIPTFUNC( EntityBounds, "" ) + DEFINE_SCRIPTFUNC( Line, "" ) + DEFINE_SCRIPTFUNC( Triangle, "" ) + DEFINE_SCRIPTFUNC( EntityText, "" ) + DEFINE_SCRIPTFUNC( EntityTextAtPosition, "" ) + DEFINE_SCRIPTFUNC( Grid, "" ) + DEFINE_SCRIPTFUNC( Text, "" ) + DEFINE_SCRIPTFUNC( ScreenText, "" ) + DEFINE_SCRIPTFUNC( Cross3D, "" ) + DEFINE_SCRIPTFUNC( Cross3DOriented, "" ) + DEFINE_SCRIPTFUNC( DrawTickMarkedLine, "" ) + DEFINE_SCRIPTFUNC( HorzArrow, "" ) + DEFINE_SCRIPTFUNC( YawArrow, "" ) + DEFINE_SCRIPTFUNC( VertArrow, "" ) + DEFINE_SCRIPTFUNC( Axis, "" ) + DEFINE_SCRIPTFUNC( Sphere, "" ) + DEFINE_SCRIPTFUNC( CircleOriented, "" ) + DEFINE_SCRIPTFUNC( Circle, "" ) + DEFINE_SCRIPTFUNC( ClearAllOverlays, "" ) +END_SCRIPTDESC(); +#endif // MAPBASE_VSCRIPT //----------------------------------------------------------------------------- @@ -484,6 +909,16 @@ static float ScriptTraceLine( const Vector &vecStart, const Vector &vecEnd, HSCR } } +#ifdef MAPBASE_VSCRIPT +//----------------------------------------------------------------------------- +// Simple particle effect dispatch +//----------------------------------------------------------------------------- +static void ScriptDispatchParticleEffect(const char *pszParticleName, const Vector &vecOrigin, const QAngle &vecAngles) +{ + DispatchParticleEffect(pszParticleName, vecOrigin, vecAngles); +} +#endif + bool VScriptServerInit() { VMPROF_START @@ -544,6 +979,7 @@ bool VScriptServerInit() #else Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); #endif + 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" ); @@ -557,17 +993,22 @@ bool VScriptServerInit() 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." ) ); + // ScriptRegisterFunction( g_pScriptVM, IsValidEntity, "Returns true if the entity is valid." ); #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." ); +#ifndef MAPBASE_VSCRIPT ScriptRegisterFunctionNamed( g_pScriptVM, NDebugOverlay::Box, "DebugDrawBox", "Draw a debug overlay box" ); ScriptRegisterFunctionNamed( g_pScriptVM, NDebugOverlay::Line, "DebugDrawLine", "Draw a debug overlay box" ); +#endif ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" ); ScriptRegisterFunction( g_pScriptVM, CreateProp, "Create a physics prop" ); - +#ifdef MAPBASE_VSCRIPT + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptDispatchParticleEffect, "DispatchParticleEffect", "Dispatches a one-off particle system" ); +#endif if ( GameRules() ) { @@ -575,6 +1016,9 @@ bool VScriptServerInit() } g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" ); +#ifdef MAPBASE_VSCRIPT + g_pScriptVM->RegisterInstance( &g_ScriptDebugOverlay, "debugoverlay" ); +#endif #ifdef MAPBASE_VSCRIPT g_pScriptVM->RegisterAllClasses(); diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index 886d0ea1c5..6e225f3645 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -118,6 +118,15 @@ void RegisterSharedScriptConstants() // usually doing nothing sounds like a bad idea. ScriptRegisterFunction( g_pScriptVM, RegisterActivityConstants, "Registers all activity IDs as usable constants." ); + + // + // Math/world + // + ScriptRegisterConstantNamed( g_pScriptVM, ((float)(180.f / M_PI_F)), "RAD2DEG", "" ); + ScriptRegisterConstantNamed( g_pScriptVM, ((float)(M_PI_F / 180.f)), "DEG2RAD", "" ); + ScriptRegisterConstant( g_pScriptVM, MAX_COORD_FLOAT, "" ); + ScriptRegisterConstant( g_pScriptVM, MAX_TRACE_LENGTH, "" ); + // // Damage Types // diff --git a/sp/src/game/shared/mapbase/vscript_funcs_math.cpp b/sp/src/game/shared/mapbase/vscript_funcs_math.cpp index 3c74b06d6e..e6162f2e18 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_math.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_math.cpp @@ -389,7 +389,6 @@ 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." ); diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index c611c4e770..4625ec684d 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -391,12 +391,7 @@ void AddThinkToEnt( HSCRIPT entity, const char *pszFuncName ) 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" ); + pEntity->ScriptSetThinkFunction(pszFuncName, 0.f); } HSCRIPT EntIndexToHScript( int index ) @@ -985,7 +980,14 @@ bool ScriptMatcherMatch( const char *pszQuery, const char *szValue ) { return Ma //============================================================================= //============================================================================= -bool IsServerScript() +#ifndef CLIENT_DLL +bool IsDedicatedServer() +{ + return engine->IsDedicatedServer(); +} +#endif + +bool ScriptIsServer() { #ifdef GAME_DLL return true; @@ -994,7 +996,7 @@ bool IsServerScript() #endif } -bool IsClientScript() +bool ScriptIsClient() { #ifdef CLIENT_DLL return true; @@ -1003,6 +1005,12 @@ bool IsClientScript() #endif } +// Notification printing on the right edge of the screen +void NPrint(int pos, const char* fmt) +{ + engine->Con_NPrintf(pos, fmt); +} + //============================================================================= //============================================================================= @@ -1017,9 +1025,6 @@ void RegisterSharedScriptFunctions() // #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, EmitSoundOn, "Play named sound on an entity." ); ScriptRegisterFunction( g_pScriptVM, EmitSoundOnClient, "Play named sound only on the client for the specified player." ); @@ -1041,6 +1046,7 @@ void RegisterSharedScriptFunctions() //----------------------------------------------------------------------------- + ScriptRegisterFunction( g_pScriptVM, NPrint, "" ); 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." ); @@ -1092,9 +1098,11 @@ void RegisterSharedScriptFunctions() 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." ); - // For shared server/clientside scripts - ScriptRegisterFunction( g_pScriptVM, IsServerScript, "Returns true if the script is being run on the server." ); - ScriptRegisterFunction( g_pScriptVM, IsClientScript, "Returns true if the script is being run on the client." ); +#ifndef CLIENT_DLL + ScriptRegisterFunction( g_pScriptVM, IsDedicatedServer, "Is this a dedicated server?" ); +#endif + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptIsServer, "IsServer", "Returns true if the script is being run on the server." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptIsClient, "IsClient", "Returns true if the script is being run on the client." ); RegisterMathScriptFunctions(); diff --git a/sp/src/vscript/squirrel/include/sqstdtime.h b/sp/src/vscript/squirrel/include/sqstdtime.h new file mode 100644 index 0000000000..fbf1bee725 --- /dev/null +++ b/sp/src/vscript/squirrel/include/sqstdtime.h @@ -0,0 +1,88 @@ +//----------------------------------------------------------------------- +// see copyright notice in squirrel.h +// +// Purpose : Squirrel time library cropped out from +// the system library as a safe include. +// +//----------------------------------------------------------------------- + +#include "squirrel.h" +#include "time.h" + +static SQInteger _system_clock(HSQUIRRELVM v) +{ + sq_pushfloat(v, ((SQFloat)clock()) / (SQFloat)CLOCKS_PER_SEC); + return 1; +} + +static SQInteger _system_time(HSQUIRRELVM v) +{ + SQInteger t = (SQInteger)time(NULL); + sq_pushinteger(v, t); + return 1; +} + +static void _set_integer_slot(HSQUIRRELVM v, const SQChar *name, SQInteger val) +{ + sq_pushstring(v, name, -1); + sq_pushinteger(v, val); + sq_rawset(v, -3); +} + +static SQInteger _system_date(HSQUIRRELVM v) +{ + time_t t; + SQInteger it; + SQInteger format = 'l'; + if (sq_gettop(v) > 1) { + sq_getinteger(v, 2, &it); + t = it; + if (sq_gettop(v) > 2) { + sq_getinteger(v, 3, (SQInteger*)&format); + } + } + else { + time(&t); + } + tm *date; + if (format == 'u') + date = gmtime(&t); + else + date = localtime(&t); + if (!date) + return sq_throwerror(v, _SC("crt api failure")); + sq_newtable(v); + _set_integer_slot(v, _SC("sec"), date->tm_sec); + _set_integer_slot(v, _SC("min"), date->tm_min); + _set_integer_slot(v, _SC("hour"), date->tm_hour); + _set_integer_slot(v, _SC("day"), date->tm_mday); + _set_integer_slot(v, _SC("month"), date->tm_mon); + _set_integer_slot(v, _SC("year"), date->tm_year + 1900); + _set_integer_slot(v, _SC("wday"), date->tm_wday); + _set_integer_slot(v, _SC("yday"), date->tm_yday); + return 1; +} + +#define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_system_##name,nparams,pmask} +static const SQRegFunction timelib_funcs[] = { + _DECL_FUNC(clock, 0, NULL), + _DECL_FUNC(time, 1, NULL), + _DECL_FUNC(date, -1, _SC(".nn")), + { NULL, (SQFUNCTION)0, 0, NULL } +}; +#undef _DECL_FUNC + +SQInteger sqstd_register_timelib(HSQUIRRELVM v) +{ + SQInteger i = 0; + while (timelib_funcs[i].name != 0) + { + sq_pushstring(v, timelib_funcs[i].name, -1); + sq_newclosure(v, timelib_funcs[i].f, 0); + sq_setparamscheck(v, timelib_funcs[i].nparamscheck, timelib_funcs[i].typemask); + sq_setnativeclosurename(v, -1, timelib_funcs[i].name); + sq_newslot(v, -3, SQFalse); + i++; + } + return 1; +} diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 8b98ff7eb2..1c523c596f 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -17,6 +17,7 @@ #include "sqstdaux.h" //#include "sqstdblob.h" //#include "sqstdsystem.h" +#include "sqstdtime.h" //#include "sqstdio.h" #include "sqstdmath.h" #include "sqstdstring.h" @@ -263,7 +264,7 @@ namespace SQVector if (key[0] < 'x' || key['0'] > 'z' || key[1] != '\0') { - return sqstd_throwerrorf(vm, "Unexpected key %s", key); + return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key); } Vector* v = nullptr; @@ -289,7 +290,7 @@ namespace SQVector if (key[0] < 'x' || key['0'] > 'z' || key[1] != '\0') { - return sqstd_throwerrorf(vm, "Unexpected key %s", key); + return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key); } Vector* v = nullptr; @@ -1024,7 +1025,7 @@ SQInteger function_stub(HSQUIRRELVM vm) { HSQOBJECT val; if (SQ_FAILED(sq_getstackobj(vm, i + 2, &val))) - return sq_throwerror(vm, "Expected string"); + return sq_throwerror(vm, "Expected handle"); if (sq_isnull(val)) { @@ -1054,7 +1055,7 @@ SQInteger function_stub(HSQUIRRELVM vm) if (!self) { - return sq_throwerror(vm, "Can't be used on a null instance"); + return sq_throwerror(vm, "Accessed null instance"); } instance = ((ClassInstanceData*)self)->instance; @@ -1112,7 +1113,6 @@ SQInteger constructor_stub(HSQUIRRELVM vm) return sqstd_throwerrorf(vm, "Unable to construct instances of %s", pClassDesc->m_pszScriptName); } - SquirrelVM* pSquirrelVM = (SquirrelVM*)sq_getforeignptr(vm); assert(pSquirrelVM); @@ -1191,7 +1191,7 @@ SQInteger get_stub(HSQUIRRELVM vm) } else { - return sqstd_throwerrorf(vm, "Unexpected key %s", key); + return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key); } return 1; @@ -1223,7 +1223,7 @@ SQInteger set_stub(HSQUIRRELVM vm) else { sq_pop(vm, 1); - return sqstd_throwerrorf(vm, "Unexpected key %s", key); + return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key); } return 0; @@ -1251,7 +1251,7 @@ SQInteger add_stub(HSQUIRRELVM vm) } sq_pop(vm, 1); - return sqstd_throwerrorf(vm, "Unexpected _add"); + return sqstd_throwerrorf(vm, "invalid arith op +"); } SQInteger sub_stub(HSQUIRRELVM vm) @@ -1276,7 +1276,7 @@ SQInteger sub_stub(HSQUIRRELVM vm) } sq_pop(vm, 1); - return sqstd_throwerrorf(vm, "Unexpected _sub"); + return sqstd_throwerrorf(vm, "invalid arith op -"); } SQInteger mul_stub(HSQUIRRELVM vm) @@ -1301,7 +1301,7 @@ SQInteger mul_stub(HSQUIRRELVM vm) } sq_pop(vm, 1); - return sqstd_throwerrorf(vm, "Unexpected _mul"); + return sqstd_throwerrorf(vm, "invalid arith op *"); } SQInteger div_stub(HSQUIRRELVM vm) @@ -1326,7 +1326,7 @@ SQInteger div_stub(HSQUIRRELVM vm) } sq_pop(vm, 1); - return sqstd_throwerrorf(vm, "Unexpected _div"); + return sqstd_throwerrorf(vm, "invalid arith op /"); } SQInteger IsValid_stub(HSQUIRRELVM vm) @@ -1374,12 +1374,11 @@ void printfunc(HSQUIRRELVM SQ_UNUSED_ARG(v), const SQChar* format, ...) void errorfunc(HSQUIRRELVM SQ_UNUSED_ARG(v), const SQChar* format, ...) { - // NOTE: This is only separate from printfunc to make it easier to add breakpoints va_list args; va_start(args, format); char buffer[256]; vsprintf(buffer, format, args); - Msg("%s", buffer); + Warning("%s", buffer); va_end(args); } @@ -1558,6 +1557,9 @@ bool SquirrelVM::Init() //sqstd_register_iolib(vm_); //sqstd_register_systemlib(vm_); + // There is no vulnerability in getting time. + sqstd_register_timelib(vm_); + sqstd_seterrorhandlers(vm_); @@ -1570,9 +1572,9 @@ bool SquirrelVM::Init() constructor(pattern) { base.constructor(pattern); - pattern_ = pattern; + this.pattern_ = pattern; } - pattern_=""; + pattern_ = ""; } )script") == SCRIPT_ERROR) { @@ -1593,14 +1595,66 @@ bool SquirrelVM::Init() if (Run( R"script( + Msg <- print; + Warning <- error; + + // LocalTime from Source 2 + // function LocalTime() + // { + // local date = ::date(); + // return { + // Hours = date.hour, + // Minutes = date.min, + // Seconds = date.sec + // } + // } + + function clamp(val,min,max) + { + if ( max < min ) + return max; + else if( val < min ) + return min; + else if( val > max ) + return max; + else + return val; + } + + function max(a,b) + { + return a > b ? a : b; + } + + function min(a,b) + { + return a < b ? a : b; + } + + function RemapVal(val, A, B, C, D) + { + if ( A == B ) + return val >= B ? D : C; + return C + (D - C) * (val - A) / (B - A); + } + + function RemapValClamped(val, A, B, C, D) + { + if ( A == B ) + return val >= B ? D : C; + local cVal = (val - A) / (B - A); + cVal = ::clamp( cVal, 0.0, 1.0 ); + return C + (D - C) * cVal; + } + function printl( text ) { - return print(text + "\n"); + return ::print(text + "\n"); } class CSimpleCallChainer { - function constructor(prefixString, scopeForThis, exactMatch) + constructor(prefixString, scopeForThis, exactMatch) { prefix = prefixString; scope = scopeForThis; @@ -1610,7 +1664,7 @@ bool SquirrelVM::Init() function PostScriptExecute() { - local func = null; + local func; try { func = scope[prefix]; } catch(e) { @@ -1628,9 +1682,10 @@ bool SquirrelVM::Init() func.pcall(scope); } } + prefix = null; - scope= null; - chain = []; + scope = null; + chain = null; } DocumentedFuncs <- {} @@ -1698,7 +1753,7 @@ bool SquirrelVM::Init() { // Is an aliased function print("Signature: function " + name + "("); - foreach(k,v in this[name].getinfos()["parameters"]) + foreach(k,v in this[name].getinfos().parameters) { if (k == 0 && v == "this") continue; if (k > 1) print(", "); @@ -1732,7 +1787,7 @@ bool SquirrelVM::Init() { // Is an aliased function print("Signature: function " + name + "("); - foreach(k,v in this[name].getinfos()["parameters"]) + foreach(k,v in this[name].getinfos().parameters) { if (k == 0 && v == "this") continue; if (k > 1) print(", ");