diff --git a/README b/README index 1022c6ed..12ecc545 100644 --- a/README +++ b/README @@ -40,8 +40,8 @@ or complicated code changes accessible and easy to use for level designers and o If you believe any content in Mapbase originates from any leak or unauthorized source (from Valve or otherwise), please contact Blixibon immediately. Mapbase is intended to be usable by everyone, including licensed Source projects and Steam mods. *** -The Alien Swarm SDK was used to backport features and code from newer branches of Source into a Source 2013/Half-Life 2 environment. -Mapbase also implements some of Tony Sergi's code changes from the Source 2007 SDK codebase. Both SDKs are publicly distributed by Valve and are available on Steam. +-- The Alien Swarm SDK was used to backport features and code from newer branches of Source into a Source 2013/Half-Life 2 environment. +-- Mapbase also implements some of Tony Sergi's code changes from the Source 2007 SDK codebase. Both SDKs are publicly distributed by Valve and are available on Steam. Some of the features backported from the Alien Swarm SDK (e.g. game instructor, particle rain) require assets from later versions of Source in order to work properly. The required assets have been backported from Alien Swarm and Left 4 Dead for the release build. They are not available in the code repository. @@ -100,11 +100,13 @@ Direct contributions: - Combine lock hardware on door01_left.mdl created by Kralich (This is asset-based and not reflected in the code) - npc_vehicledriver fixes provided by CrAzY - npc_combine cover behavior patches provided by iohnnyboy +- logic_playmovie icon created by URAKOLOUY5 (This is asset-based and not reflected in the code) == Contributions from samisalreadytaken: =-- https://github.com/mapbase-source/source-sdk-2013/pull/47 (VScript utility/consistency changes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/59 (New VScript functions and singletons based on API documentation in later Source/Source 2 games) =-- https://github.com/mapbase-source/source-sdk-2013/pull/80 (More VScript changes, including support for extremely flexible client/server messaging) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/105 (VScript fixes and optimizations, Vector class extensions, custom convars/commands) //--------------------------------------------------------------------------------------------------------------------------------------------------- @@ -117,6 +119,7 @@ Other sources: -- https://github.com/ValveSoftware/source-sdk-2013/pull/401 (func_rot_button "Starts locked" flag fix) -- https://github.com/ValveSoftware/source-sdk-2013/pull/391 (VBSP func_detail smoothing group fix) -- https://github.com/ValveSoftware/source-sdk-2013/pull/362 (npc_manhack npc_maker fix; Adjusted for formatting and save/restore in Mapbase) +-- https://github.com/Petercov/Source-PlusPlus/commit/ecdf50c48cd31dec4dbdb7fea2d0780e7f0dd8ec (used as a guide for porting the Alien Swarm SDK response system) - https://github.com/momentum-mod/game/blob/1d066180b3bf74830c51e6914d46c40b0bea1fc2/mp/src/game/server/player.cpp#L6543 (spec_goto fix) - Poison zombie barnacle crash fix implemented based on a snippet from HL2: Plus posted by Agent Agrimar on Discord (Mapbase makes the barnacle recognize it as poison just like poison headcrabs) - https://gamebanana.com/skins/172192 (Airboat handling fix; This is asset-based and not reflected in the code) diff --git a/sp/src/devtools/makefile_base_posix.mak b/sp/src/devtools/makefile_base_posix.mak index 559ee2be..21147f21 100644 --- a/sp/src/devtools/makefile_base_posix.mak +++ b/sp/src/devtools/makefile_base_posix.mak @@ -6,10 +6,11 @@ MAKEFILE_LINK:=$(THISFILE).link -include $(MAKEFILE_LINK) -$(MAKEFILE_LINK): $(shell which $(CC)) $(THISFILE) - if [ "$(shell printf "$(shell $(CC) -dumpversion)\n8" | sort -Vr | head -1)" = 8 ]; then \ - $(COMPILE.cpp) -o gcc9+support.o gcc9+support.c ;\ +# depend on CXX so the correct makefile can be selected when the system is updated +$(MAKEFILE_LINK): $(shell which $(CXX)) $(THISFILE) $(SRCROOT)/devtools/gcc9+support.cpp + @ if [ "$(shell printf "$(shell $(CXX) -dumpversion)\n8" | sort -Vr | head -1)" = 8 ]; then \ ln -sf $(MAKEFILE_BASE).default $@ ;\ else \ + $(COMPILE.cpp) -o $(SRCROOT)/devtools/gcc9+support.o $(SRCROOT)/devtools/gcc9+support.cpp &&\ ln -sf $(MAKEFILE_BASE).gcc8 $@ ;\ fi diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index f9b6486c..640459e5 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -293,6 +293,7 @@ BEGIN_ENT_SCRIPTDESC( C_ClientRagdoll, C_BaseAnimating, "Client-side ragdolls" ) END_SCRIPTDESC(); ScriptHook_t C_BaseAnimating::g_Hook_OnClientRagdoll; +ScriptHook_t C_BaseAnimating::g_Hook_FireEvent; #endif BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" ) @@ -346,6 +347,13 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si BEGIN_SCRIPTHOOK( C_BaseAnimating::g_Hook_OnClientRagdoll, "OnClientRagdoll", FIELD_VOID, "Called when this entity turns into a client-side ragdoll." ) DEFINE_SCRIPTHOOK_PARAM( "ragdoll", FIELD_HSCRIPT ) END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( C_BaseAnimating::g_Hook_FireEvent, "FireEvent", FIELD_BOOLEAN, "Called when handling animation events. Return false to cancel base handling." ) + DEFINE_SCRIPTHOOK_PARAM( "origin", FIELD_VECTOR ) + DEFINE_SCRIPTHOOK_PARAM( "angles", FIELD_VECTOR ) + DEFINE_SCRIPTHOOK_PARAM( "event", FIELD_INTEGER ) + DEFINE_SCRIPTHOOK_PARAM( "options", FIELD_CSTRING ) + END_SCRIPTHOOK() #endif END_SCRIPTDESC(); @@ -3651,7 +3659,11 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) flEventCycle, gpGlobals->curtime ); } - + +#ifdef MAPBASE_VSCRIPT + if (ScriptHookFireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ) == false) + continue; +#endif FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ); } @@ -3684,6 +3696,11 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) gpGlobals->curtime ); } +#ifdef MAPBASE_VSCRIPT + if (ScriptHookFireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ) == false) + continue; +#endif + FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ); } } @@ -3691,6 +3708,26 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) m_flPrevEventCycle = flEventCycle; } +#ifdef MAPBASE_VSCRIPT +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_BaseAnimating::ScriptHookFireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ) +{ + if (m_ScriptScope.IsInitialized() && g_Hook_FireEvent.CanRunInScope(m_ScriptScope)) + { + // origin, angles, event, options + ScriptVariant_t args[] = { origin, angles, event, options }; + ScriptVariant_t returnValue = true; + g_Hook_FireEvent.Call( m_ScriptScope, &returnValue, args ); + + return returnValue.m_bool; + } + + return true; +} +#endif + //----------------------------------------------------------------------------- // Purpose: Parses a muzzle effect event and sends it out for drawing // Input : *options - event parameters in text format diff --git a/sp/src/game/client/c_baseanimating.h b/sp/src/game/client/c_baseanimating.h index 6f48ac1a..50b3659b 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -164,6 +164,10 @@ public: virtual void FireObsoleteEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); virtual const char* ModifyEventParticles( const char* token ) { return token; } +#ifdef MAPBASE_VSCRIPT + bool ScriptHookFireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); +#endif + #if defined ( SDK_DLL ) || defined ( HL2MP ) virtual void ResetEventsParity() { m_nPrevResetEventsParity = -1; } // used to force animation events to function on players so the muzzleflashes and other events occur // so new functions don't have to be made to parse the models like CSS does in ProcessMuzzleFlashEvent @@ -477,6 +481,7 @@ public: HSCRIPT ScriptBecomeRagdollOnClient(); static ScriptHook_t g_Hook_OnClientRagdoll; + static ScriptHook_t g_Hook_FireEvent; float ScriptGetPoseParameter(const char* szName); #endif diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index d45ed98c..a3b40378 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -451,6 +451,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelName, "GetModelName", "Returns the name of the model" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptStopSound, "StopSound", "Stops a sound from this entity." ) 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." ) @@ -472,6 +473,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities DEFINE_SCRIPTFUNC_NAMED( GetAbsAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector" ) DEFINE_SCRIPTFUNC_NAMED( SetAbsAngles, "SetAngles", "Set entity pitch, yaw, roll" ) + DEFINE_SCRIPTFUNC( 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" ) @@ -541,7 +543,13 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities 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( SetModel, "Set client-only entity model" ) + //DEFINE_SCRIPTFUNC_NAMED( ScriptInitializeAsClientEntity, "InitializeAsClientEntity", "" ) + DEFINE_SCRIPTFUNC_NAMED( Remove, "Destroy", "Remove clientside entity" ) DEFINE_SCRIPTFUNC_NAMED( GetEntityIndex, "entindex", "" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptSetContextThink, "SetContextThink", "Set a think function on this entity." ) + #endif END_SCRIPTDESC(); @@ -1334,6 +1342,15 @@ void C_BaseEntity::Term() { g_pScriptVM->RemoveInstance( m_hScriptInstance ); m_hScriptInstance = NULL; + +#ifdef MAPBASE_VSCRIPT + FOR_EACH_VEC( m_ScriptThinkFuncs, i ) + { + HSCRIPT h = m_ScriptThinkFuncs[i]->m_hfnThink; + if ( h ) g_pScriptVM->ReleaseScript( h ); + } + m_ScriptThinkFuncs.PurgeAndDeleteElements(); +#endif } } diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index c8890ccb..f2170be4 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -161,6 +161,16 @@ struct thinkfunc_t int m_nLastThinkTick; }; +#ifdef MAPBASE_VSCRIPT +struct scriptthinkfunc_t +{ + int m_nNextThinkTick; + HSCRIPT m_hfnThink; + unsigned short m_iContextHash; + bool m_bNoParam; +}; +#endif + #define CREATE_PREDICTED_ENTITY( className ) \ C_BaseEntity::CreatePredictedEntityByName( className, __FILE__, __LINE__ ); @@ -390,7 +400,7 @@ public: #ifdef MAPBASE_VSCRIPT // "I don't know why but wrapping entindex() works, while calling it directly crashes." - inline int C_BaseEntity::GetEntityIndex() const { return entindex(); } + inline int GetEntityIndex() const { return entindex(); } #endif // This works for client-only entities and returns the GetEntryIndex() of the entity's handle, @@ -1173,6 +1183,7 @@ public: #ifdef MAPBASE_VSCRIPT const char* ScriptGetModelName( void ) const { return STRING(GetModelName()); } + void ScriptStopSound(const char* soundname); void ScriptEmitSound(const char* soundname); float ScriptSoundDuration(const char* soundname, const char* actormodel); @@ -1519,6 +1530,15 @@ protected: CUtlVector< thinkfunc_t > m_aThinkFunctions; int m_iCurrentThinkContext; +#ifdef MAPBASE_VSCRIPT +public: + void ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, float time ); + void ScriptContextThink(); +private: + CUtlVector< scriptthinkfunc_t* > m_ScriptThinkFuncs; +public: +#endif + // Object eye position Vector m_vecViewOffset; diff --git a/sp/src/game/client/c_baselesson.cpp b/sp/src/game/client/c_baselesson.cpp index 8a2d9617..ec01575b 100644 --- a/sp/src/game/client/c_baselesson.cpp +++ b/sp/src/game/client/c_baselesson.cpp @@ -15,7 +15,7 @@ #include "ammodef.h" #include "vprof.h" #include "view.h" -#include "vstdlib/ikeyvaluessystem.h" +#include "vstdlib/IKeyValuesSystem.h" #ifdef MAPBASE #include "usermessages.h" #endif @@ -666,7 +666,8 @@ void CIconLesson::UpdateInactive() CUtlBuffer msg_data; msg_data.PutChar( 1 ); msg_data.PutString( m_szHudHint.String() ); - usermessages->DispatchUserMessage( usermessages->LookupUserMessage( "KeyHintText" ), bf_read( msg_data.Base(), msg_data.TellPut() ) ); + bf_read msg( msg_data.Base(), msg_data.TellPut() ); + usermessages->DispatchUserMessage( usermessages->LookupUserMessage( "KeyHintText" ), msg ); } #endif @@ -1039,40 +1040,40 @@ Vector CIconLesson::GetIconTargetPosition( C_BaseEntity *pIconTarget ) #define LESSON_VARIABLE_INIT_SYMBOL( _varEnum, _varName, _varType ) g_n##_varEnum##Symbol = KeyValuesSystem()->GetSymbolForString( #_varEnum ); -#define LESSON_SCRIPT_STRING_ADD_TO_MAP( _varEnum, _varName, _varType ) g_NameToTypeMap.Insert( #_varEnum, LESSON_VARIABLE_##_varEnum## ); +#define LESSON_SCRIPT_STRING_ADD_TO_MAP( _varEnum, _varName, _varType ) g_NameToTypeMap.Insert( #_varEnum, LESSON_VARIABLE_##_varEnum ); // Create enum value -#define LESSON_VARIABLE_ENUM( _varEnum, _varName, _varType ) LESSON_VARIABLE_##_varEnum##, +#define LESSON_VARIABLE_ENUM( _varEnum, _varName, _varType ) LESSON_VARIABLE_##_varEnum, // Init info call -#define LESSON_VARIABLE_INIT_INFO_CALL( _varEnum, _varName, _varType ) g_pLessonVariableInfo[ LESSON_VARIABLE_##_varEnum## ].Init_##_varEnum##(); +#define LESSON_VARIABLE_INIT_INFO_CALL( _varEnum, _varName, _varType ) g_pLessonVariableInfo[ LESSON_VARIABLE_##_varEnum ].Init_##_varEnum(); // Init info #define LESSON_VARIABLE_INIT_INFO( _varEnum, _varName, _varType ) \ - void Init_##_varEnum##() \ + void Init_##_varEnum() \ { \ - iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::_varName ); \ varType = LessonParamTypeFromString( #_varType ); \ } #define LESSON_VARIABLE_INIT_INFO_BOOL( _varEnum, _varName, _varType ) \ - void Init_##_varEnum##() \ + void Init_##_varEnum() \ { \ - iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::_varName ); \ varType = FIELD_BOOLEAN; \ } #define LESSON_VARIABLE_INIT_INFO_EHANDLE( _varEnum, _varName, _varType ) \ - void Init_##_varEnum##() \ + void Init_##_varEnum() \ { \ - iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::_varName ); \ varType = FIELD_EHANDLE; \ } #define LESSON_VARIABLE_INIT_INFO_STRING( _varEnum, _varName, _varType ) \ - void Init_##_varEnum##() \ + void Init_##_varEnum() \ { \ - iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::_varName ); \ varType = FIELD_STRING; \ } @@ -1094,15 +1095,15 @@ Vector CIconLesson::GetIconTargetPosition( C_BaseEntity *pIconTarget ) // Process the element action on this variable #define PROCESS_LESSON_ACTION( _varEnum, _varName, _varType ) \ - case LESSON_VARIABLE_##_varEnum##:\ + case LESSON_VARIABLE_##_varEnum:\ return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, _varName, &pLessonElement->szParam, eventParam_float ); #define PROCESS_LESSON_ACTION_EHANDLE( _varEnum, _varName, _varType ) \ - case LESSON_VARIABLE_##_varEnum##:\ + case LESSON_VARIABLE_##_varEnum:\ return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, _varName, &pLessonElement->szParam, eventParam_float, eventParam_BaseEntity, eventParam_string ); #define PROCESS_LESSON_ACTION_STRING( _varEnum, _varName, _varType ) \ - case LESSON_VARIABLE_##_varEnum##:\ + case LESSON_VARIABLE_##_varEnum:\ return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, &_varName, &pLessonElement->szParam, eventParam_string ); // Init the variable from the script (or a convar) @@ -2957,7 +2958,7 @@ bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const ch { if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) { - ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName ); ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); @@ -2969,7 +2970,7 @@ bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const ch if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) { - ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName ); ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f ", pVar->HealthFraction() ); ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); diff --git a/sp/src/game/client/c_baselesson.h b/sp/src/game/client/c_baselesson.h index 2cad41ca..b413d282 100644 --- a/sp/src/game/client/c_baselesson.h +++ b/sp/src/game/client/c_baselesson.h @@ -426,7 +426,7 @@ private: LessonEvent_t * AddUpdateEvent( void ); private: - static CUtlDict< int, int > CScriptedIconLesson::LessonActionMap; + static CUtlDict< int, int > LessonActionMap; EHANDLE m_hLocalPlayer; float m_fOutput; diff --git a/sp/src/game/client/c_gameinstructor.h b/sp/src/game/client/c_gameinstructor.h index 00c97c66..14ae908c 100644 --- a/sp/src/game/client/c_gameinstructor.h +++ b/sp/src/game/client/c_gameinstructor.h @@ -9,7 +9,7 @@ #include "GameEventListener.h" -#include "vgui_controls/phandle.h" +#include "vgui_controls/PHandle.h" class CBaseLesson; diff --git a/sp/src/game/client/c_movie_display.cpp b/sp/src/game/client/c_movie_display.cpp new file mode 100644 index 00000000..2285b97e --- /dev/null +++ b/sp/src/game/client/c_movie_display.cpp @@ -0,0 +1,26 @@ +//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// +//=====================================================================================// +#include "cbase.h" +#include "c_movie_display.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT( C_MovieDisplay, DT_MovieDisplay, CMovieDisplay ) + RecvPropBool( RECVINFO( m_bEnabled ) ), + RecvPropBool( RECVINFO( m_bLooping ) ), + RecvPropString( RECVINFO( m_szMovieFilename ) ), + RecvPropString( RECVINFO( m_szGroupName ) ), +END_RECV_TABLE() + +C_MovieDisplay::C_MovieDisplay() +{ +} + +C_MovieDisplay::~C_MovieDisplay() +{ +} diff --git a/sp/src/game/client/c_movie_display.h b/sp/src/game/client/c_movie_display.h new file mode 100644 index 00000000..d133e82e --- /dev/null +++ b/sp/src/game/client/c_movie_display.h @@ -0,0 +1,34 @@ +//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef C_MOVIE_DISPLAY_H +#define C_MOVIE_DISPLAY_H + +#include "cbase.h" + +class C_MovieDisplay : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_MovieDisplay, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_MovieDisplay(); + ~C_MovieDisplay(); + + bool IsEnabled( void ) const { return m_bEnabled; } + bool IsLooping( void ) const { return m_bLooping; } + + const char *GetMovieFilename( void ) const { return m_szMovieFilename; } + const char *GetGroupName( void ) const { return m_szGroupName; } + +private: + bool m_bEnabled; + bool m_bLooping; + char m_szMovieFilename[128]; + char m_szGroupName[128]; +}; + +#endif //C_MOVIE_DISPLAY_H \ No newline at end of file diff --git a/sp/src/game/client/c_rope.cpp b/sp/src/game/client/c_rope.cpp index 450faf78..636b7c6e 100644 --- a/sp/src/game/client/c_rope.cpp +++ b/sp/src/game/client/c_rope.cpp @@ -73,6 +73,27 @@ IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_RopeKeyframe, DT_RopeKeyframe, CRopeKeyframe RecvPropInt( RECVINFO( m_iParentAttachment ) ), END_RECV_TABLE() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( C_RopeKeyframe, C_BaseEntity, "The clientside class of move_rope and keyframe_rope" ) + DEFINE_SCRIPTFUNC( GetNodePosition, "Gets the position of the specified node index" ) + DEFINE_SCRIPTFUNC( GetNumNodes, "Gets the number of nodes available" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetStartEntity, "GetStartEntity", "Gets the rope's start entity" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetEndEntity, "GetEndEntity", "Gets the rope's end entity" ) + + DEFINE_SCRIPTFUNC( SetupHangDistance, "Sets the rope's hang distance" ) + DEFINE_SCRIPTFUNC( SetSlack, "Sets the rope's slack value (extra length)" ) + DEFINE_SCRIPTFUNC( GetRopeFlags, "Gets the rope's flags" ) + DEFINE_SCRIPTFUNC( SetRopeFlags, "Sets the rope's flags" ) + + DEFINE_SCRIPTFUNC( SetColorMod, "Sets the rope's color mod value" ) + + DEFINE_SCRIPTFUNC( ShakeRope, "Shakes the rope with the specified center, radius, and magnitude" ) + + DEFINE_SCRIPTFUNC( AnyPointsMoved, "Returns true if any points have moved recently" ) +END_SCRIPTDESC(); +#endif + #define ROPE_IMPULSE_SCALE 20 #define ROPE_IMPULSE_DECAY 0.95 @@ -2022,6 +2043,25 @@ bool C_RopeKeyframe::GetAttachment( int number, Vector &origin, QAngle &angles ) return false; } +#ifdef MAPBASE +const Vector &C_RopeKeyframe::GetNodePosition( int index ) +{ + int nNodes = m_RopePhysics.NumNodes(); + if ( index >= nNodes || nNodes < 2 ) + { + Warning( "C_RopeKeyframe::GetNodePosition(): Invalid node index %i (number of nodes is %i)\n", index, nNodes ); + return vec3_origin; + } + + return m_RopePhysics.GetNode( index )->m_vPredicted; +} + +int C_RopeKeyframe::GetNumNodes() +{ + return m_RopePhysics.NumNodes(); +} +#endif + bool C_RopeKeyframe::AnyPointsMoved() { #ifdef MAPBASE diff --git a/sp/src/game/client/c_rope.h b/sp/src/game/client/c_rope.h index 3d821081..204b412b 100644 --- a/sp/src/game/client/c_rope.h +++ b/sp/src/game/client/c_rope.h @@ -33,6 +33,9 @@ public: DECLARE_CLASS( C_RopeKeyframe, C_BaseEntity ); DECLARE_CLIENTCLASS(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif private: @@ -142,6 +145,11 @@ public: virtual bool GetAttachment( int number, Vector &origin ); virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); +#ifdef MAPBASE + const Vector &GetNodePosition( int index ); + int GetNumNodes(); +#endif + private: void FinishInit( const char *pMaterialName ); @@ -166,6 +174,11 @@ private: void ReceiveMessage( int classID, bf_read &msg ); bool CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttachment, Vector &vPos, QAngle *pAngles ); +#ifdef MAPBASE_VSCRIPT + HSCRIPT ScriptGetStartEntity() { return ToHScript( GetStartEntity() ); } + HSCRIPT ScriptGetEndEntity() { return ToHScript( GetEndEntity() ); } +#endif + private: // Track which links touched something last frame. Used to prevent wind from gusting on them. diff --git a/sp/src/game/client/c_world.h b/sp/src/game/client/c_world.h index 2174f32b..12366490 100644 --- a/sp/src/game/client/c_world.h +++ b/sp/src/game/client/c_world.h @@ -49,6 +49,8 @@ public: #endif #ifdef MAPBASE_VSCRIPT + void ClientThink() { ScriptContextThink(); } + // -2 = Use server language ScriptLanguage_t GetScriptLanguage() { return (ScriptLanguage_t)(m_iScriptLanguageClient != -2 ? m_iScriptLanguageClient : m_iScriptLanguageServer); } #endif diff --git a/sp/src/game/client/cdll_client_int.cpp b/sp/src/game/client/cdll_client_int.cpp index 6fd1c711..ea23d800 100644 --- a/sp/src/game/client/cdll_client_int.cpp +++ b/sp/src/game/client/cdll_client_int.cpp @@ -274,6 +274,8 @@ void ProcessCacheUsedMaterials() } } +void VGui_ClearVideoPanels(); + // String tables INetworkStringTable *g_pStringTableParticleEffectNames = NULL; INetworkStringTable *g_StringTableEffectDispatch = NULL; @@ -1217,6 +1219,8 @@ void CHLClient::Shutdown( void ) g_pSixenseInput = NULL; #endif + VGui_ClearVideoPanels(); + C_BaseAnimating::ShutdownBoneSetupThreadPool(); ClientWorldFactoryShutdown(); diff --git a/sp/src/game/client/client_mapbase.vpc b/sp/src/game/client/client_mapbase.vpc index a6d7fe29..2c5b606a 100644 --- a/sp/src/game/client/client_mapbase.vpc +++ b/sp/src/game/client/client_mapbase.vpc @@ -32,6 +32,9 @@ $Project $File "c_postprocesscontroller.cpp" $File "c_postprocesscontroller.h" $File "c_env_dof_controller.cpp" + $File "c_movie_display.cpp" + $File "c_movie_display.h" + $File "vgui_movie_display.cpp" $Folder "Mapbase" { @@ -58,6 +61,7 @@ $Project $File "mapbase\c_func_fake_worldportal.cpp" $File "mapbase\c_func_fake_worldportal.h" $File "mapbase\c_point_glow.cpp" + $File "mapbase\c_vgui_text_display.cpp" } $Folder "HL2 DLL" diff --git a/sp/src/game/client/episodic/c_prop_scalable.cpp b/sp/src/game/client/episodic/c_prop_scalable.cpp index d3902db3..b3134460 100644 --- a/sp/src/game/client/episodic/c_prop_scalable.cpp +++ b/sp/src/game/client/episodic/c_prop_scalable.cpp @@ -5,6 +5,10 @@ //============================================================================= #include "cbase.h" +#ifdef MAPBASE +#include "proxyentity.h" +#include "materialsystem/imaterialvar.h" +#endif class C_PropScalable : public C_BaseAnimating { @@ -194,3 +198,56 @@ void C_PropScalable::GetRenderBounds( Vector &theMins, Vector &theMaxs ) Assert( theMins.IsValid() && theMaxs.IsValid() ); } + +#ifdef MAPBASE +ConVar r_coreball_update_sphere_center( "r_coreball_update_sphere_center", "1", FCVAR_NONE, "Allows prop_coreball to update its center to the entity's origin" ); + +class CCoreBallUpdateMaterialProxy : public CEntityMaterialProxy +{ +public: + CCoreBallUpdateMaterialProxy() + { + m_pMaterial = NULL; + m_pSphereCenter = NULL; + } + virtual ~CCoreBallUpdateMaterialProxy() + { + } + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) + { + m_pMaterial = pMaterial; + bool found; + m_pSphereCenter = m_pMaterial->FindVar( "$spherecenter", &found ); + if( !found ) + { + m_pSphereCenter = NULL; + return false; + } + return true; + } + virtual void OnBind( C_BaseEntity *pC_BaseEntity ) + { + if (r_coreball_update_sphere_center.GetBool()) + { + const Vector &origin = pC_BaseEntity->GetAbsOrigin(); + m_pSphereCenter->SetVecValue( origin.x, origin.y, origin.z ); + } + else + { + // Just continuously bind the old hacked value (TODO: Optimize so it's not just assigning the same value constantly?) + m_pSphereCenter->SetVecValue( 2688.0, 12139.0, 5170.0 ); + } + } + + virtual IMaterial *GetMaterial() + { + return m_pMaterial; + } + +protected: + IMaterial *m_pMaterial; + IMaterialVar *m_pSphereCenter; +}; + +EXPOSE_INTERFACE( CCoreBallUpdateMaterialProxy, IMaterialProxy, "CoreBallUpdate" IMATERIAL_PROXY_INTERFACE_VERSION ); +#endif diff --git a/sp/src/game/client/hud_locator_target.cpp b/sp/src/game/client/hud_locator_target.cpp index 8f0d4c0c..8479b07e 100644 --- a/sp/src/game/client/hud_locator_target.cpp +++ b/sp/src/game/client/hud_locator_target.cpp @@ -10,7 +10,7 @@ #include "iclientmode.h" #include #include -#include +#include #include #include #include diff --git a/sp/src/game/client/hud_locator_target.h b/sp/src/game/client/hud_locator_target.h index 06799325..69939dbb 100644 --- a/sp/src/game/client/hud_locator_target.h +++ b/sp/src/game/client/hud_locator_target.h @@ -34,7 +34,7 @@ #define LOCATOR_ICON_FX_FADE_OUT 0x00000800 // Set when deactivated so it can smoothly vanish #define LOCATOR_ICON_FX_FADE_IN 0x00001000 // Set when activated so it can smoothly appear -#include "tier1/UtlSymbol.h" +#include "tier1/utlsymbol.h" // See comments in UtlSymbol on why this is useful DECLARE_PRIVATE_SYMBOLTYPE( CGameInstructorSymbol ); diff --git a/sp/src/game/client/mapbase/c_vgui_text_display.cpp b/sp/src/game/client/mapbase/c_vgui_text_display.cpp new file mode 100644 index 00000000..c3847ac0 --- /dev/null +++ b/sp/src/game/client/mapbase/c_vgui_text_display.cpp @@ -0,0 +1,259 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: Displays easy, flexible VGui text. Mapbase equivalent of point_worldtext. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "panelmetaclassmgr.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include +#include +#include +#include "ienginevgui.h" +#include "c_vguiscreen.h" +#include "vgui_bitmapbutton.h" +#include "vgui_bitmappanel.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// vgui_text_display +//----------------------------------------------------------------------------- +class C_VGuiTextDisplay : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_VGuiTextDisplay, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_VGuiTextDisplay(); + ~C_VGuiTextDisplay(); + + virtual void PostDataUpdate( DataUpdateType_t updateType ); + + bool IsEnabled( void ) const { return m_bEnabled; } + + const char *GetDisplayText( void ) const { return m_szDisplayText; } + const char *GetFontName( void ) const { return m_szFont; } + int GetResolution( void ) const { return m_iResolution; } + vgui::Label::Alignment GetContentAlignment() const { return m_iContentAlignment; } + + bool NeedsTextUpdate() { return m_bTextNeedsUpdate; } + void UpdatedText() { m_bTextNeedsUpdate = false; } + +private: + bool m_bEnabled; + char m_szDisplayText[256]; + vgui::Label::Alignment m_iContentAlignment; + char m_szFont[64]; + int m_iResolution; + + bool m_bTextNeedsUpdate; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_VGuiTextDisplay, DT_VGuiTextDisplay, CVGuiTextDisplay ) + RecvPropBool( RECVINFO( m_bEnabled ) ), + RecvPropString( RECVINFO( m_szDisplayText ) ), + RecvPropInt( RECVINFO( m_iContentAlignment ) ), + RecvPropString( RECVINFO( m_szFont ) ), + RecvPropInt( RECVINFO( m_iResolution ) ), +END_RECV_TABLE() + +C_VGuiTextDisplay::C_VGuiTextDisplay() +{ +} + +C_VGuiTextDisplay::~C_VGuiTextDisplay() +{ +} + +void C_VGuiTextDisplay::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + // For now, always update + m_bTextNeedsUpdate = true; +} + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class C_TextDisplayPanel : public CVGuiScreenPanel +{ + DECLARE_CLASS( C_TextDisplayPanel, CVGuiScreenPanel ); + +public: + C_TextDisplayPanel( vgui::Panel *parent, const char *panelName ); + ~C_TextDisplayPanel( void ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + + void UpdateText(); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick( void ); + virtual void Paint( void ); + +private: + + CHandle m_hVGUIScreen; + CHandle m_hScreenEntity; + + // VGUI specifics + Label *m_pDisplayTextLabel; +}; + +DECLARE_VGUI_SCREEN_FACTORY( C_TextDisplayPanel, "text_display_panel" ); + +CUtlVector g_TextDisplays; + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +C_TextDisplayPanel::C_TextDisplayPanel( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, "C_TextDisplayPanel"/*, vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/WorldTextPanel.res", "WorldTextPanel" )*/ ) +{ + // Add ourselves to the global list of movie displays + g_TextDisplays.AddToTail( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Clean up the movie +//----------------------------------------------------------------------------- +C_TextDisplayPanel::~C_TextDisplayPanel( void ) +{ + // Remove ourselves from the global list of movie displays + g_TextDisplays.FindAndRemove( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Setup our scheme +//----------------------------------------------------------------------------- +void C_TextDisplayPanel::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + /* + m_pDisplayTextLabel->SetFgColor( Color( 255, 255, 255, 255 ) ); + m_pDisplayTextLabel->SetText( "" ); + m_pDisplayTextLabel->SetVisible( false ); + */ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TextDisplayPanel::UpdateText() +{ + color32 clr = m_hScreenEntity->GetRenderColor(); + + m_pDisplayTextLabel->SetFgColor( Color( clr.r, clr.g, clr.b, clr.a ) ); + m_pDisplayTextLabel->SetText( m_hScreenEntity->GetDisplayText() ); + + //SetSize( m_hScreenEntity->GetTextSize(), m_hScreenEntity->GetTextSize() ); + SetSize( m_hScreenEntity->GetResolution(), m_hScreenEntity->GetResolution() ); + m_pDisplayTextLabel->SetSize( m_hScreenEntity->GetResolution(), m_hScreenEntity->GetResolution() ); + //m_pDisplayTextLabel->SetSize( m_hScreenEntity->GetTextSize(), m_hScreenEntity->GetTextSize() ); + + Label::Alignment iAlignment = m_hScreenEntity->GetContentAlignment(); + m_pDisplayTextLabel->SetContentAlignment( iAlignment ); + + bool bWrap = true; + bool bCenterWrap = false; + switch (iAlignment) + { + // Center wrap if centered + case Label::Alignment::a_north: + case Label::Alignment::a_center: + case Label::Alignment::a_south: + bCenterWrap = true; + break; + + // HACKHACK: Don't wrap if using an east alignment + case Label::Alignment::a_northeast: + case Label::Alignment::a_east: + case Label::Alignment::a_southeast: + bWrap = false; + break; + } + + m_pDisplayTextLabel->SetWrap( bWrap ); + m_pDisplayTextLabel->SetCenterWrap( bCenterWrap ); + + //Msg( "Resolution is %i\n", m_hScreenEntity->GetResolution() ); + + const char *pszFontName = m_hScreenEntity->GetFontName(); + if (pszFontName && pszFontName[0] != '\0') + { + HFont font = scheme()->GetIScheme( GetScheme() )->GetFont( pszFontName ); + m_pDisplayTextLabel->SetFont( font ); + } + + m_pDisplayTextLabel->SetVisible( true ); +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool C_TextDisplayPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + if ( !BaseClass::Init( pKeyValues, pInitData ) ) + return false; + + // Make sure we get ticked... + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + m_pDisplayTextLabel = dynamic_cast(FindChildByName( "TextDisplay" )); + + // Save this for simplicity later on + m_hVGUIScreen = dynamic_cast( GetEntity() ); + if ( m_hVGUIScreen != NULL ) + { + // Also get the associated entity + m_hScreenEntity = dynamic_cast(m_hVGUIScreen->GetOwnerEntity()); + UpdateText(); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Update the display string +//----------------------------------------------------------------------------- +void C_TextDisplayPanel::OnTick() +{ + if (m_hScreenEntity->NeedsTextUpdate()) + { + UpdateText(); + m_hScreenEntity->UpdatedText(); + } + + BaseClass::OnTick(); +} + +ConVar r_vguitext_bg( "r_vguitext_bg", "0" ); + +//----------------------------------------------------------------------------- +// Purpose: Update and draw the frame +//----------------------------------------------------------------------------- +void C_TextDisplayPanel::Paint( void ) +{ + // Black out the background (we could omit drawing under the video surface, but this is straight-forward) + if ( r_vguitext_bg.GetBool() ) + { + surface()->DrawSetColor( 0, 0, 0, 255 ); + surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() ); + + //surface()->DrawSetColor( 64, 64, 64, 255 ); + //surface()->DrawFilledRect( 0, 0, m_pDisplayTextLabel->GetWide(), m_pDisplayTextLabel->GetTall() ); + } + + // Parent's turn + BaseClass::Paint(); +} diff --git a/sp/src/game/client/panelmetaclassmgr.cpp b/sp/src/game/client/panelmetaclassmgr.cpp index 2b36cc44..6f0b50d0 100644 --- a/sp/src/game/client/panelmetaclassmgr.cpp +++ b/sp/src/game/client/panelmetaclassmgr.cpp @@ -234,14 +234,6 @@ CPanelMetaClassMgrImp::CPanelMetaClassMgrImp() : m_PanelTypeDict( true, 0, 32 ) CPanelMetaClassMgrImp::~CPanelMetaClassMgrImp() { -#ifdef MAPBASE // VDC Memory Leak Fixes - while (m_MetaClassKeyValues.Count()>0) - { - if (m_MetaClassKeyValues[0]) - m_MetaClassKeyValues[0]->deleteThis(); - m_MetaClassKeyValues.RemoveAt(0); - } -#endif } diff --git a/sp/src/game/client/vgui_movie_display.cpp b/sp/src/game/client/vgui_movie_display.cpp new file mode 100644 index 00000000..135ad7f9 --- /dev/null +++ b/sp/src/game/client/vgui_movie_display.cpp @@ -0,0 +1,437 @@ +//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include "cbase.h" +#include "c_vguiscreen.h" +#include "vgui_controls/Label.h" +#include "vgui_bitmappanel.h" +#include +#include "c_slideshow_display.h" +#include "ienginevgui.h" +#include "fmtstr.h" +#include "vgui_controls/ImagePanel.h" +#include +#include "video/ivideoservices.h" +#include "engine/IEngineSound.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "c_movie_display.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + +using namespace vgui; + +struct VideoPlaybackInfo_t +{ + VideoPlaybackInfo_t( void ) : + m_pMaterial ( NULL ), + m_nSourceHeight(0), m_nSourceWidth(0), + m_flU(0.0f),m_flV(0.0f) {} + + IMaterial *m_pMaterial; + int m_nSourceHeight, m_nSourceWidth; // Source movie's dimensions + float m_flU, m_flV; // U,V ranges for video on its sheet +}; + +//----------------------------------------------------------------------------- +// Control screen +//----------------------------------------------------------------------------- +class CMovieDisplayScreen : public CVGuiScreenPanel +{ + DECLARE_CLASS( CMovieDisplayScreen, CVGuiScreenPanel ); + +public: + CMovieDisplayScreen( vgui::Panel *parent, const char *panelName ); + ~CMovieDisplayScreen( void ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + + virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ); + virtual void OnTick( void ); + virtual void Paint( void ); + +private: + bool IsActive( void ); + + void SetupMovie( void ); + void UpdateMovie( void ); + bool BeginPlayback( const char *pFilename ); + void CalculatePlaybackDimensions( int nSrcWidth, int nSrcHeight ); + + inline void GetPanelPos( int &xpos, int &ypos ) + { + xpos = ( (float) ( GetWide() - m_nPlaybackWidth ) / 2 ); + ypos = ( (float) ( GetTall() - m_nPlaybackHeight ) / 2 ); + } + +private: + + // BINK playback info + IVideoMaterial *m_VideoMaterial; + VideoPlaybackInfo_t m_playbackInfo; + CHandle m_hVGUIScreen; + CHandle m_hScreenEntity; + + int m_nTextureId; + int m_nPlaybackHeight; // Playback dimensions (proper ration adjustments) + int m_nPlaybackWidth; + bool m_bBlackBackground; + bool m_bSlaved; + bool m_bInitialized; + + bool m_bLastActiveState; // HACK: I'd rather get a real callback... + + // VGUI specifics + Label *m_pDisplayTextLabel; + + Color m_cDefault; + Color m_cInvisible; + + bool bIsAlreadyVisible; +}; + +DECLARE_VGUI_SCREEN_FACTORY( CMovieDisplayScreen, "movie_display_screen" ); + +CUtlVector g_MovieDisplays; + +//----------------------------------------------------------------------------- +// Constructor: +//----------------------------------------------------------------------------- +CMovieDisplayScreen::CMovieDisplayScreen( vgui::Panel *parent, const char *panelName ) +: BaseClass( parent, "CMovieDisplayScreen", vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/MovieDisplayScreen.res", "MovieDisplayScreen" ) ) +{ + m_pDisplayTextLabel = new vgui::Label( this, "NumberDisplay", "testing!"); + + m_VideoMaterial = NULL; + m_nTextureId = -1; + m_bBlackBackground = true; + m_bSlaved = false; + m_bInitialized = false; + + // Add ourselves to the global list of movie displays + g_MovieDisplays.AddToTail( this ); + + m_bLastActiveState = IsActive(); +} + +//----------------------------------------------------------------------------- +// Purpose: Clean up the movie +//----------------------------------------------------------------------------- +CMovieDisplayScreen::~CMovieDisplayScreen( void ) +{ + if ( g_pVideo != NULL && m_VideoMaterial != NULL ) + { + g_pVideo->DestroyVideoMaterial( m_VideoMaterial ); + m_VideoMaterial = NULL; + } + + // Clean up our texture reference + g_pMatSystemSurface->DestroyTextureID( m_nTextureId ); + + // Remove ourselves from the global list of movie displays + g_MovieDisplays.FindAndRemove( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Setup our scheme +//----------------------------------------------------------------------------- +void CMovieDisplayScreen::ApplySchemeSettings( IScheme *pScheme ) +{ + assert( pScheme ); + + m_cDefault = Color( 255, 255, 255, 255 ); + m_cInvisible = Color( 0, 0, 0, 0 ); + + m_pDisplayTextLabel->SetFgColor( m_cDefault ); + m_pDisplayTextLabel->SetText( "" ); + m_pDisplayTextLabel->SetVisible( false ); +} + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +bool CMovieDisplayScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + // Make sure we get ticked... + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + if ( !BaseClass::Init( pKeyValues, pInitData ) ) + return false; + + // Save this for simplicity later on + m_hVGUIScreen = dynamic_cast( GetEntity() ); + if ( m_hVGUIScreen != NULL ) + { + // Also get the associated entity + m_hScreenEntity = dynamic_cast(m_hVGUIScreen->GetOwnerEntity()); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Helper function to check our active state +//----------------------------------------------------------------------------- +bool CMovieDisplayScreen::IsActive( void ) +{ + bool bScreenActive = false; + if ( m_hVGUIScreen != NULL ) + { + bScreenActive = m_hVGUIScreen->IsActive(); + } + + return bScreenActive; +} + +//----------------------------------------------------------------------------- +// Purpose: Either become the master of a group of screens, or become a slave to another +//----------------------------------------------------------------------------- +void CMovieDisplayScreen::SetupMovie( void ) +{ + // Only bother if we haven't been setup yet + if ( m_bInitialized ) + return; + + const char *szGroupName = m_hScreenEntity->GetGroupName(); + + CMovieDisplayScreen *pMasterScreen = NULL; + for ( int i = 0; i < g_MovieDisplays.Count(); i++ ) + { + // Must be valid and not us + if ( g_MovieDisplays[i] == NULL || g_MovieDisplays[i] == this ) + continue; + + // Must have an associated movie entity + if ( g_MovieDisplays[i]->m_hScreenEntity == NULL ) + continue; + + // Must have a group name to care + if ( szGroupName[0] == NULL ) + continue; + + // Group names must match! + // FIXME: Use an ID instead? + const char *szTestGroupName = g_MovieDisplays[i]->m_hScreenEntity->GetGroupName(); + if ( Q_strnicmp( szTestGroupName, szGroupName, 128 ) ) + continue; + + // See if we've found a master display + if ( g_MovieDisplays[i]->m_bInitialized && g_MovieDisplays[i]->m_bSlaved == false ) + { + m_bSlaved = true; + + // Share the info from the master + m_playbackInfo = g_MovieDisplays[i]->m_playbackInfo; + + // We need to calculate our own playback dimensions as we may be a different size than our parent + CalculatePlaybackDimensions( m_playbackInfo.m_nSourceWidth, m_playbackInfo.m_nSourceHeight ); + + // Bind our texture + m_nTextureId = surface()->CreateNewTextureID( true ); + g_pMatSystemSurface->DrawSetTextureMaterial( m_nTextureId, m_playbackInfo.m_pMaterial ); + + // Hold this as the master screen + pMasterScreen = g_MovieDisplays[i]; + break; + } + } + + // We need to try again, we have no screen entity! + if ( m_hScreenEntity == NULL ) + return; + + // No master found, become one + if ( pMasterScreen == NULL ) + { + const char *szFilename = m_hScreenEntity->GetMovieFilename(); + BeginPlayback( szFilename ); + m_bSlaved = false; + } + + // Done + m_bInitialized = true; +} + +//----------------------------------------------------------------------------- +// Purpose: Deal with the details of the video playback +//----------------------------------------------------------------------------- +void CMovieDisplayScreen::UpdateMovie( void ) +{ + // Only the master in a group updates the bink file + if ( m_bSlaved ) + return; + + if ( m_VideoMaterial == NULL ) + return; + + // Get the current activity state of the screen + bool bScreenActive = IsActive(); + + // Pause if the game has paused + if ( engine->IsPaused() || engine->Con_IsVisible() ) + { + bScreenActive = false; + } + + // See if we've changed our activity state + if ( bScreenActive != m_bLastActiveState ) + { + m_VideoMaterial->SetPaused( !bScreenActive ); + } + + // Updated + m_bLastActiveState = bScreenActive; + + // Update the frame if we're currently enabled + if ( bScreenActive ) + { + // Update our frame + if ( m_VideoMaterial->Update() == false ) + { + // Issue a close command + // OnVideoOver(); + // StopPlayback(); + } + } +} + +//----------------------------------------------------------------------------- +// Update the display string +//----------------------------------------------------------------------------- +void CMovieDisplayScreen::OnTick() +{ + BaseClass::OnTick(); + + // Create our playback or slave to another screen already playing + SetupMovie(); + + // Now update the movie + UpdateMovie(); +} + +//----------------------------------------------------------------------------- +// Purpose: Adjust the playback dimensions to properly account for our screen dimensions +//----------------------------------------------------------------------------- +void CMovieDisplayScreen::CalculatePlaybackDimensions( int nSrcWidth, int nSrcHeight ) +{ + float flFrameRatio = ( (float) GetWide() / (float) GetTall() ); + float flVideoRatio = ( (float) nSrcWidth / (float) nSrcHeight ); + + if ( flVideoRatio > flFrameRatio ) + { + m_nPlaybackWidth = GetWide(); + m_nPlaybackHeight = ( GetWide() / flVideoRatio ); + } + else if ( flVideoRatio < flFrameRatio ) + { + m_nPlaybackWidth = ( GetTall() * flVideoRatio ); + m_nPlaybackHeight = GetTall(); + } + else + { + m_nPlaybackWidth = GetWide(); + m_nPlaybackHeight = GetTall(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Begins playback of a movie +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CMovieDisplayScreen::BeginPlayback( const char *pFilename ) +{ + // need working video services + if ( g_pVideo == NULL ) + return false; + + // Create a new video material + if ( m_VideoMaterial != NULL ) + { + g_pVideo->DestroyVideoMaterial( m_VideoMaterial ); + m_VideoMaterial = NULL; + } + + // Create a globally unique name for this material + char szMaterialName[256]; + + // Append our group name if we have one + const char *szGroupName = m_hScreenEntity->GetGroupName(); + if ( szGroupName[0] != NULL ) + { + Q_snprintf( szMaterialName, sizeof(szMaterialName), "%s_%s", pFilename, szGroupName ); + } + else + { + Q_strncpy( szMaterialName, pFilename, sizeof(szMaterialName) ); + } + + const char *pszMaterialName = CFmtStrN<128>( "VideoMaterial_%s", m_hScreenEntity->GetEntityName() ); + m_VideoMaterial = g_pVideo->CreateVideoMaterial( pszMaterialName, pFilename, "GAME", + VideoPlaybackFlags::DEFAULT_MATERIAL_OPTIONS, + VideoSystem::DETERMINE_FROM_FILE_EXTENSION/*, m_bAllowAlternateMedia*/ ); + + if ( m_VideoMaterial == NULL ) + return false; + + m_VideoMaterial->SetMuted( true ); // FIXME: Allow? + + if ( m_hScreenEntity->IsLooping() ) + { + m_VideoMaterial->SetLooping( true ); + } + + if ( m_VideoMaterial->HasAudio() ) + { + // We want to be the sole audio source + enginesound->NotifyBeginMoviePlayback(); + } + + // Get our basic info from the movie + m_VideoMaterial->GetVideoImageSize( &m_playbackInfo.m_nSourceWidth, &m_playbackInfo.m_nSourceHeight ); + m_VideoMaterial->GetVideoTexCoordRange( &m_playbackInfo.m_flU, &m_playbackInfo.m_flV ); + m_playbackInfo.m_pMaterial = m_VideoMaterial->GetMaterial(); + + // Get our playback dimensions + CalculatePlaybackDimensions( m_playbackInfo.m_nSourceWidth, m_playbackInfo.m_nSourceHeight ); + + // Bind our texture + m_nTextureId = surface()->CreateNewTextureID( true ); + g_pMatSystemSurface->DrawSetTextureMaterial( m_nTextureId, m_playbackInfo.m_pMaterial ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Update and draw the frame +//----------------------------------------------------------------------------- +void CMovieDisplayScreen::Paint( void ) +{ + // Masters must keep the video updated + if ( m_bSlaved == false && m_VideoMaterial == NULL ) + { + BaseClass::Paint(); + return; + } + + // Sit in the "center" + int xpos, ypos; + GetPanelPos( xpos, ypos ); + + // Black out the background (we could omit drawing under the video surface, but this is straight-forward) + if ( m_bBlackBackground ) + { + surface()->DrawSetColor( 0, 0, 0, 255 ); + surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() ); + } + + // Draw it + surface()->DrawSetTexture( m_nTextureId ); + surface()->DrawSetColor( 255, 255, 255, 255 ); + surface()->DrawTexturedSubRect( xpos, ypos, xpos+m_nPlaybackWidth, ypos+m_nPlaybackHeight, 0.0f, 0.0f, m_playbackInfo.m_flU, m_playbackInfo.m_flV ); + + // Parent's turn + BaseClass::Paint(); +} diff --git a/sp/src/game/client/vgui_video.cpp b/sp/src/game/client/vgui_video.cpp index 6df78893..17e28aa2 100644 --- a/sp/src/game/client/vgui_video.cpp +++ b/sp/src/game/client/vgui_video.cpp @@ -16,20 +16,59 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +using namespace vgui; + +static CUtlVector< VideoPanel * > g_vecVideoPanels; + +// Thiis is a hack due to the fact that the user can type quit with the video panel up, but it's parented to the GameUI dll root panel, which is already gone so +// we would crash in the destructor +void VGui_ClearVideoPanels() +{ + for ( int i = g_vecVideoPanels.Count() - 1; i >= 0; --i ) + { + if ( g_vecVideoPanels[ i ] ) + { + delete g_vecVideoPanels[ i ]; + } + } + g_vecVideoPanels.RemoveAll(); +} + +struct VideoPanelParms_t +{ + VideoPanelParms_t( bool _interrupt = true, bool _loop = false, bool _mute = false ) + { + bAllowInterrupt = _interrupt; + bLoop = _loop; + bMute = _mute; + } + + bool bAllowInterrupt; + bool bLoop; + bool bMute; + + //float flFadeIn; + //float flFadeOut; +}; VideoPanel::VideoPanel( unsigned int nXPos, unsigned int nYPos, unsigned int nHeight, unsigned int nWidth, bool allowAlternateMedia ) : BaseClass( NULL, "VideoPanel" ), m_VideoMaterial( NULL ), m_nPlaybackWidth( 0 ), m_nPlaybackHeight( 0 ), - m_bAllowAlternateMedia( allowAlternateMedia ) + m_nShutdownCount( 0 ), + m_bLooping( false ), + m_bStopAllSounds( true ), + m_bAllowInterruption( true ), + m_bAllowAlternateMedia( allowAlternateMedia ), + m_bStarted( false ) { - #ifdef MAPBASE vgui::VPANEL pParent = enginevgui->GetPanel( PANEL_ROOT ); #else vgui::VPANEL pParent = enginevgui->GetPanel( PANEL_GAMEUIDLL ); #endif + SetParent( pParent ); SetVisible( false ); @@ -53,6 +92,11 @@ VideoPanel::VideoPanel( unsigned int nXPos, unsigned int nYPos, unsigned int nHe SetScheme(vgui::scheme()->LoadSchemeFromFile( "resource/VideoPanelScheme.res", "VideoPanelScheme")); LoadControlSettings("resource/UI/VideoPanel.res"); + + // Let us update + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + g_vecVideoPanels.AddToTail( this ); } //----------------------------------------------------------------------------- @@ -60,6 +104,8 @@ VideoPanel::VideoPanel( unsigned int nXPos, unsigned int nYPos, unsigned int nHe //----------------------------------------------------------------------------- VideoPanel::~VideoPanel( void ) { + g_vecVideoPanels.FindAndRemove( this ); + SetParent( (vgui::Panel *) NULL ); // Shut down this video, destroy the video material @@ -70,13 +116,39 @@ VideoPanel::~VideoPanel( void ) } } +//----------------------------------------------------------------------------- +// Purpose: Keeps a tab on when the movie is ending and allows a frame to pass to prevent threading issues +//----------------------------------------------------------------------------- +void VideoPanel::OnTick( void ) +{ + if ( m_nShutdownCount > 0 ) + { + m_nShutdownCount++; + + if ( m_nShutdownCount > 10 ) + { + OnClose(); + m_nShutdownCount = 0; + } + } + + BaseClass::OnTick(); +} + +void VideoPanel::OnVideoOver() +{ + StopPlayback(); +} + //----------------------------------------------------------------------------- // Purpose: Begins playback of a movie // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool VideoPanel::BeginPlayback( const char *pFilename ) { - // Who the heck hacked this in? + if ( !pFilename || pFilename[ 0 ] == '\0' ) + return false; + #ifdef _X360 XVIDEO_MODE videoMode; XGetVideoMode( &videoMode ); @@ -106,9 +178,25 @@ bool VideoPanel::BeginPlayback( const char *pFilename ) if ( m_VideoMaterial == NULL ) return false; + if ( m_bLooping ) + { + m_VideoMaterial->SetLooping( true ); + } + +#ifdef MAPBASE + if ( m_bMuted ) + { + m_VideoMaterial->SetMuted( true ); + } +#endif + + m_bStarted = true; + // We want to be the sole audio source - // FIXME: This may not always be true! - enginesound->NotifyBeginMoviePlayback(); + if ( m_bStopAllSounds ) + { + enginesound->NotifyBeginMoviePlayback(); + } int nWidth, nHeight; m_VideoMaterial->GetVideoImageSize( &nWidth, &nHeight ); @@ -168,9 +256,10 @@ void VideoPanel::DoModal( void ) //----------------------------------------------------------------------------- void VideoPanel::OnKeyCodeTyped( vgui::KeyCode code ) { - if ( code == KEY_ESCAPE ) + bool bInterruptKeyPressed = ( code == KEY_ESCAPE ); + if ( m_bAllowInterruption && bInterruptKeyPressed ) { - OnClose(); + StopPlayback(); } else { @@ -181,34 +270,54 @@ void VideoPanel::OnKeyCodeTyped( vgui::KeyCode code ) //----------------------------------------------------------------------------- // Purpose: Handle keys that should cause us to close //----------------------------------------------------------------------------- -void VideoPanel::OnKeyCodePressed( vgui::KeyCode code ) +void VideoPanel::OnKeyCodePressed( vgui::KeyCode keycode ) { + vgui::KeyCode code = GetBaseButtonCode( keycode ); + + // All these keys will interrupt playback + bool bInterruptKeyPressed = ( code == KEY_ESCAPE || + code == KEY_BACKQUOTE || + code == KEY_SPACE || + code == KEY_ENTER || + code == KEY_XBUTTON_A || + code == KEY_XBUTTON_B || + code == KEY_XBUTTON_X || + code == KEY_XBUTTON_Y || + code == KEY_XBUTTON_START || + code == KEY_XBUTTON_BACK ); + // These keys cause the panel to shutdown - if ( code == KEY_ESCAPE || - code == KEY_BACKQUOTE || - code == KEY_SPACE || - code == KEY_ENTER || - code == KEY_XBUTTON_A || - code == KEY_XBUTTON_B || - code == KEY_XBUTTON_X || - code == KEY_XBUTTON_Y || - code == KEY_XBUTTON_START || - code == KEY_XBUTTON_BACK ) + if ( m_bAllowInterruption && bInterruptKeyPressed ) { - OnClose(); + StopPlayback(); } else { - BaseClass::OnKeyCodePressed( code ); + BaseClass::OnKeyCodePressed( keycode ); } } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VideoPanel::StopPlayback( void ) +{ + SetVisible( false ); + + // Start the deferred shutdown process + m_nShutdownCount = 1; +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void VideoPanel::OnClose( void ) { - enginesound->NotifyEndMoviePlayback(); + if ( m_bStopAllSounds ) + { + enginesound->NotifyEndMoviePlayback(); + } + BaseClass::OnClose(); if ( vgui::input()->GetAppModalSurface() == GetVPanel() ) @@ -224,7 +333,6 @@ void VideoPanel::OnClose( void ) engine->ClientCmd( m_szExitCommand ); } - SetVisible( false ); MarkForDeletion(); } @@ -247,26 +355,52 @@ void VideoPanel::Paint( void ) if ( m_VideoMaterial == NULL ) return; + float alpha = ((float)GetFgColor()[3]/255.0f); +#ifdef MAPBASE + if (m_flFadeIn != 0.0f || m_flFadeOut != 0.0f) + { + // GetCurrentVideoTime() and GetVideoDuration() are borked + float flFrameCount = m_VideoMaterial->GetFrameCount(); + float flEnd = flFrameCount / m_VideoMaterial->GetVideoFrameRate().GetFPS(); + float flTime = ((float)(m_VideoMaterial->GetCurrentFrame()) / flFrameCount) * flEnd; + float flFadeOutDelta = (flEnd - m_flFadeOut); + + if (flTime <= m_flFadeIn) + { + alpha = (flTime / m_flFadeIn); + } + else if (flTime >= flFadeOutDelta) + { + alpha = (1.0f - ((flTime - flFadeOutDelta) / m_flFadeOut)); + } + } +#endif + if ( m_VideoMaterial->Update() == false ) { // Issue a close command OnVideoOver(); - OnClose(); + //OnClose(); } // Sit in the "center" int xpos, ypos; GetPanelPos( xpos, ypos ); + LocalToScreen( xpos, ypos ); // Black out the background (we could omit drawing under the video surface, but this is straight-forward) if ( m_bBlackBackground ) { - vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); + vgui::surface()->DrawSetColor( 0, 0, 0, alpha * 255.0f ); vgui::surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() ); } // Draw the polys to draw this out CMatRenderContextPtr pRenderContext( materials ); + +#ifdef MAPBASE + pRenderContext->ClearColor4ub( 255, 255, 255, alpha * 255.0f ); +#endif pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->PushMatrix(); @@ -306,8 +440,6 @@ void VideoPanel::Paint( void ) flTopY = FLerp( 1, -1, 0, vh ,flTopY ); flBottomY = FLerp( 1, -1, 0, vh, flBottomY ); - float alpha = ((float)GetFgColor()[3]/255.0f); - for ( int corner=0; corner<4; corner++ ) { bool bLeft = (corner==0) || (corner==3); @@ -340,16 +472,37 @@ void VideoPanel::Paint( void ) bool VideoPanel_Create( unsigned int nXPos, unsigned int nYPos, unsigned int nWidth, unsigned int nHeight, const char *pVideoFilename, - const char *pExitCommand /*= NULL*/) + const char *pExitCommand /*= NULL*/, + const VideoPanelParms_t &parms ) { // Create the base video panel - VideoPanel *pVideoPanel = new VideoPanel( nXPos, nYPos, nHeight, nWidth, false ); + VideoPanel *pVideoPanel = new VideoPanel( nXPos, nYPos, nHeight, nWidth ); if ( pVideoPanel == NULL ) return false; + // Toggle if we want the panel to allow interruption + pVideoPanel->SetAllowInterrupt( parms.bAllowInterrupt ); + // Set the command we'll call (if any) when the video is interrupted or completes pVideoPanel->SetExitCommand( pExitCommand ); +#ifdef MAPBASE + // Toggle if we want the panel to loop (inspired by Portal 2) + pVideoPanel->SetLooping( parms.bLoop ); + + // Toggle if we want the panel to be muted + pVideoPanel->SetMuted( parms.bMute ); + + // TODO: Unique "Stop All Sounds" parameter + if (parms.bMute) + { + pVideoPanel->SetStopAllSounds( false ); + } + + // Fade parameters (unfinished) + //pVideoPanel->SetFade( parms.flFadeIn, parms.flFadeOut ); +#endif + // Start it going if ( pVideoPanel->BeginPlayback( pVideoFilename ) == false ) { @@ -364,8 +517,29 @@ bool VideoPanel_Create( unsigned int nXPos, unsigned int nYPos, } //----------------------------------------------------------------------------- -// Purpose: Used to launch a video playback (Debug) - -// user must include file extension +// Purpose: Create a video panel with the supplied commands +//----------------------------------------------------------------------------- +void CreateVideoPanel( const char *lpszFilename, const char *lpszExitCommand, int nWidth, int nHeight, VideoPanelParms_t &parms ) +{ + char strFullpath[MAX_PATH]; + Q_strncpy( strFullpath, "media/", MAX_PATH ); // Assume we must play out of the media directory + char strFilename[MAX_PATH]; + Q_StripExtension( lpszFilename, strFilename, MAX_PATH ); + Q_strncat( strFullpath, lpszFilename, MAX_PATH ); + + // Use the full screen size if they haven't specified an override + unsigned int nScreenWidth = ( nWidth != 0 ) ? nWidth : ScreenWidth(); + unsigned int nScreenHeight = ( nHeight != 0 ) ? nHeight : ScreenHeight(); + + // Create the panel and go! + if ( VideoPanel_Create( 0, 0, nScreenWidth, nScreenHeight, strFullpath, lpszExitCommand, parms ) == false ) + { + Warning( "Unable to play video: %s\n", strFullpath ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Used to launch a video playback //----------------------------------------------------------------------------- CON_COMMAND( playvideo, "Plays a video: [width height]" ) @@ -375,30 +549,32 @@ CON_COMMAND( playvideo, "Plays a video: [width height]" ) unsigned int nScreenWidth = Q_atoi( args[2] ); unsigned int nScreenHeight = Q_atoi( args[3] ); - - char strFullpath[MAX_PATH]; - Q_strncpy( strFullpath, "media/", MAX_PATH ); // Assume we must play out of the media directory - char strFilename[MAX_PATH]; - Q_StripExtension( args[1], strFilename, MAX_PATH ); - Q_strncat( strFullpath, args[1], MAX_PATH ); - - if ( nScreenWidth == 0 ) - { - nScreenWidth = ScreenWidth(); - } - - if ( nScreenHeight == 0 ) - { - nScreenHeight = ScreenHeight(); - } - // Create the panel and go! - if ( VideoPanel_Create( 0, 0, nScreenWidth, nScreenHeight, strFullpath ) == false ) - { - Warning( "Unable to play video: %s\n", strFullpath ); - } + // New struct; functionally identical + VideoPanelParms_t parms; + + CreateVideoPanel( args[1], NULL, nScreenWidth, nScreenHeight, parms ); } +//----------------------------------------------------------------------------- +// Purpose: Used to launch a video playback +//----------------------------------------------------------------------------- + +CON_COMMAND( playvideo_nointerrupt, "Plays a video without ability to skip: [width height]" ) +{ + if ( args.ArgC() < 2 ) + return; + + unsigned int nScreenWidth = Q_atoi( args[2] ); + unsigned int nScreenHeight = Q_atoi( args[3] ); + + // New struct; functionally identical + VideoPanelParms_t parms( false ); + + CreateVideoPanel( args[1], NULL, nScreenWidth, nScreenHeight, parms ); +} + + //----------------------------------------------------------------------------- // Purpose: Used to launch a video playback and fire a command on completion //----------------------------------------------------------------------------- @@ -408,21 +584,78 @@ CON_COMMAND( playvideo_exitcommand, "Plays a video and fires and exit command wh if ( args.ArgC() < 2 ) return; - unsigned int nScreenWidth = ScreenWidth(); - unsigned int nScreenHeight = ScreenHeight(); - - char strFullpath[MAX_PATH]; - Q_strncpy( strFullpath, "media/", MAX_PATH ); // Assume we must play out of the media directory - char strFilename[MAX_PATH]; - Q_StripExtension( args[1], strFilename, MAX_PATH ); - Q_strncat( strFullpath, args[1], MAX_PATH ); - + // Pull out the exit command we want to use char *pExitCommand = Q_strstr( args.GetCommandString(), args[2] ); - // Create the panel and go! - if ( VideoPanel_Create( 0, 0, nScreenWidth, nScreenHeight, strFullpath, pExitCommand ) == false ) + // New struct; functionally identical + VideoPanelParms_t parms; + + CreateVideoPanel( args[1], pExitCommand, 0, 0, parms ); +} + +//----------------------------------------------------------------------------- +// Purpose: Used to launch a video playback and fire a command on completion +//----------------------------------------------------------------------------- + +CON_COMMAND( playvideo_exitcommand_nointerrupt, "Plays a video (without interruption) and fires and exit command when it is stopped or finishes: " ) +{ + if ( args.ArgC() < 2 ) + return; + + // Pull out the exit command we want to use + char *pExitCommand = Q_strstr( args.GetCommandString(), args[2] ); + + // New struct; functionally identical + VideoPanelParms_t parms( false ); + + CreateVideoPanel( args[1], pExitCommand, 0, 0, parms ); +} + +//----------------------------------------------------------------------------- +// Purpose: Cause all playback to stop +//----------------------------------------------------------------------------- + +CON_COMMAND( stopvideos, "Stops all videos playing to the screen" ) +{ + FOR_EACH_VEC( g_vecVideoPanels, itr ) { - Warning( "Unable to play video: %s\n", strFullpath ); - engine->ClientCmd( pExitCommand ); + g_vecVideoPanels[itr]->StopPlayback(); } } + +//----------------------------------------------------------------------------- +// Purpose: Used to launch a video playback and fire a command on completion +//----------------------------------------------------------------------------- + +CON_COMMAND( playvideo_complex, "Plays a video with various parameters to simplify logic_playmovie: " ) +{ + if ( args.ArgC() < 2 ) + return; + + // Pull out the exit command we want to use + char *pExitCommand = Q_strstr( args.GetCommandString(), args[2] ); + + // Parameters + VideoPanelParms_t parms; + + if (args.ArgC() >= 3) + parms.bAllowInterrupt = atoi( args[3] ) != 0; + if (args.ArgC() >= 4) + parms.bLoop = atoi( args[4] ) != 0; + if (args.ArgC() >= 5) + parms.bMute = atoi( args[5] ) != 0; + + //if (args.ArgC() >= 5) + // parms.flFadeIn = atof( args[5] ); + //if (args.ArgC() >= 6) + // parms.flFadeOut = atof( args[6] ); + + // Stop a softlock + if (parms.bAllowInterrupt == false && parms.bLoop) + { + Warning( "WARNING: Tried to play video set to be uninterruptible and looping. This would cause a softlock because the video loops forever and there's no way to stop it.\n" ); + return; + } + + CreateVideoPanel( args[1], pExitCommand, 0, 0, parms ); +} diff --git a/sp/src/game/client/vgui_video.h b/sp/src/game/client/vgui_video.h index 61a980b1..b413d832 100644 --- a/sp/src/game/client/vgui_video.h +++ b/sp/src/game/client/vgui_video.h @@ -45,14 +45,22 @@ public: } bool BeginPlayback( const char *pFilename ); + void StopPlayback( void ); void SetBlackBackground( bool bBlack ){ m_bBlackBackground = bBlack; } + void SetAllowInterrupt( bool bAllowInterrupt ) { m_bAllowInterruption = bAllowInterrupt; } + void SetStopAllSounds( bool bStopAllSounds ) { m_bStopAllSounds = bStopAllSounds; } +#ifdef MAPBASE + void SetLooping( bool bLooping ) { m_bLooping = bLooping; } + void SetMuted( bool bMuted ) { m_bMuted = bMuted; } + void SetFade( float flStartFade, float flEndFade ) { m_flFadeIn = flStartFade; m_flFadeOut = flEndFade; } +#endif protected: - virtual void OnTick( void ) { BaseClass::OnTick(); } + virtual void OnTick( void ); virtual void OnCommand( const char *pcCommand ) { BaseClass::OnCommand( pcCommand ); } - virtual void OnVideoOver(){} + virtual void OnVideoOver(); protected: IVideoMaterial *m_VideoMaterial; @@ -65,8 +73,19 @@ protected: float m_flU; // U,V ranges for video on its sheet float m_flV; + bool m_bLooping; +#ifdef MAPBASE + float m_flFadeIn; + float m_flFadeOut; + bool m_bMuted; +#endif + bool m_bStopAllSounds; + bool m_bAllowInterruption; bool m_bBlackBackground; bool m_bAllowAlternateMedia; + int m_nShutdownCount; + + bool m_bStarted; }; diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 58b5431c..dccaf2a5 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -165,6 +165,8 @@ public: void SetVarFloat( int i, float value ); void SetVarVector( int i, const Vector &value ); + const char *GetVarName( int i ); + private: IMaterialVar *m_MaterialVars[SCRIPT_MAT_PROXY_MAX_VARS]; @@ -194,12 +196,19 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptMaterialProxy, "CScriptMaterialProxy", "Mate 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" ) + + DEFINE_SCRIPTFUNC( GetVarName, "Gets a material var's name" ) END_SCRIPTDESC(); CScriptMaterialProxy::CScriptMaterialProxy() { m_hScriptInstance = NULL; m_hFuncOnBind = NULL; + + for (int i = 0; i < SCRIPT_MAT_PROXY_MAX_VARS; i++) + { + m_MaterialVars[i] = NULL; + } } CScriptMaterialProxy::~CScriptMaterialProxy() @@ -316,18 +325,20 @@ void CScriptMaterialProxy::TermScript() void CScriptMaterialProxy::OnBind( void *pRenderable ) { - if( !pRenderable ) - return; - if (m_hFuncOnBind != NULL) { - IClientRenderable *pRend = ( IClientRenderable* )pRenderable; - C_BaseEntity *pEnt = pRend->GetIClientUnknown()->GetBaseEntity(); - if ( pEnt ) + C_BaseEntity *pEnt = NULL; + if (pRenderable) { - g_pScriptVM->SetValue( m_ScriptScope, "entity", pEnt->GetScriptInstance() ); + IClientRenderable *pRend = (IClientRenderable*)pRenderable; + pEnt = pRend->GetIClientUnknown()->GetBaseEntity(); + if ( pEnt ) + { + g_pScriptVM->SetValue( m_ScriptScope, "entity", pEnt->GetScriptInstance() ); + } } - else + + if (!pEnt) { // 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 ); @@ -414,6 +425,14 @@ void CScriptMaterialProxy::SetVarVector( int i, const Vector &value ) return m_MaterialVars[i]->SetVecValue( value.Base(), 3 ); } +const char *CScriptMaterialProxy::GetVarName( int i ) +{ + if (!ValidateIndex( i ) || !m_MaterialVars[i]) + return NULL; + + return m_MaterialVars[i]->GetName(); +} + EXPOSE_INTERFACE( CScriptMaterialProxy, IMaterialProxy, "VScriptProxy" IMATERIAL_PROXY_INTERFACE_VERSION ); bool CMaterialProxyScriptInstanceHelper::ToString( void *p, char *pBuf, int bufSize ) @@ -461,6 +480,11 @@ bool DoIncludeScript( const char *pszScript, HSCRIPT hScope ) } #ifdef MAPBASE_VSCRIPT +static float FrameTime() +{ + return gpGlobals->frametime; +} + static bool Con_IsVisible() { return engine->Con_IsVisible(); @@ -585,6 +609,7 @@ bool VScriptClientInit() 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." ) ); ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" ); #ifdef MAPBASE_VSCRIPT + ScriptRegisterFunction( g_pScriptVM, FrameTime, "Get the time spent on the client in the last frame" ); ScriptRegisterFunction( g_pScriptVM, Con_IsVisible, "Returns true if the console is visible" ); ScriptRegisterFunction( g_pScriptVM, ScreenWidth, "Width of the screen in pixels" ); ScriptRegisterFunction( g_pScriptVM, ScreenHeight, "Height of the screen in pixels" ); diff --git a/sp/src/game/client/vscript_client.nut b/sp/src/game/client/vscript_client.nut index 5fce6ff5..505395da 100644 --- a/sp/src/game/client/vscript_client.nut +++ b/sp/src/game/client/vscript_client.nut @@ -5,18 +5,26 @@ static char g_Script_vscript_client[] = R"vscript( // //============================================================================= +local DoUniqueString = DoUniqueString +local DoDispatchParticleEffect = DoDispatchParticleEffect + function UniqueString( string = "" ) { - return DoUniqueString( string.tostring() ); + return DoUniqueString( "" + string ); } function IncludeScript( name, scope = null ) { - if ( scope == null ) + if ( !scope ) { scope = this; } return ::DoIncludeScript( name, scope ); } +function DispatchParticleEffect( particleName, origin, angles, entity = null ) +{ + DoDispatchParticleEffect( particleName, origin, angles, entity ); +} + )vscript"; \ No newline at end of file diff --git a/sp/src/game/server/BaseAnimatingOverlay.cpp b/sp/src/game/server/BaseAnimatingOverlay.cpp index 36534bc0..c1d7b883 100644 --- a/sp/src/game/server/BaseAnimatingOverlay.cpp +++ b/sp/src/game/server/BaseAnimatingOverlay.cpp @@ -427,6 +427,11 @@ void CAnimationLayer::DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAni event.eventtime = pOwner->m_flAnimTime + (flCycle - m_flCycle) / flCycleRate + pOwner->GetAnimTimeInterval(); } +#ifdef MAPBASE_VSCRIPT + if (eventHandler->m_ScriptScope.IsInitialized() && eventHandler->ScriptHookHandleAnimEvent( &event ) == false) + continue; +#endif + // Msg( "dispatch %d (%d : %.2f)\n", index - 1, event.event, event.eventtime ); eventHandler->HandleAnimEvent( &event ); } diff --git a/sp/src/game/server/EnvMessage.cpp b/sp/src/game/server/EnvMessage.cpp index 3f47c2ea..6de81783 100644 --- a/sp/src/game/server/EnvMessage.cpp +++ b/sp/src/game/server/EnvMessage.cpp @@ -212,6 +212,10 @@ static ConCommand creditsdone("creditsdone", CreditsDone_f ); extern ConVar sv_unlockedchapters; +#ifdef MAPBASE +extern int Mapbase_GetChapterCount(); +#endif + void CCredits::OnRestore() { BaseClass::OnRestore(); @@ -226,6 +230,10 @@ void CCredits::OnRestore() void CCredits::RollOutroCredits() { +#ifdef MAPBASE + // Don't set this if we're using Mapbase chapters or if sv_unlockedchapters is already greater than 15 + if (Mapbase_GetChapterCount() <= 0 && sv_unlockedchapters.GetInt() < 15) +#endif sv_unlockedchapters.SetValue( "15" ); CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index ad174778..e62f7f66 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -97,6 +97,7 @@ #ifdef MAPBASE #include "mapbase/matchers.h" +#include "items.h" #endif #include "env_debughistory.h" @@ -303,10 +304,11 @@ CSimpleSimTimer CAI_BaseNPC::m_AnyUpdateEnemyPosTimer; #ifdef MAPBASE_VSCRIPT // TODO: Better placement? -ScriptHook_t g_Hook_QueryHearSound; -ScriptHook_t g_Hook_QuerySeeEntity; -ScriptHook_t g_Hook_TranslateActivity; -ScriptHook_t g_Hook_TranslateSchedule; +ScriptHook_t CAI_BaseNPC::g_Hook_QueryHearSound; +ScriptHook_t CAI_BaseNPC::g_Hook_QuerySeeEntity; +ScriptHook_t CAI_BaseNPC::g_Hook_TranslateActivity; +ScriptHook_t CAI_BaseNPC::g_Hook_TranslateSchedule; +ScriptHook_t CAI_BaseNPC::g_Hook_GetActualShootPosition; #endif // @@ -10687,6 +10689,19 @@ void CAI_BaseNPC::CollectShotStats( const Vector &vecShootOrigin, const Vector & //----------------------------------------------------------------------------- Vector CAI_BaseNPC::GetActualShootPosition( const Vector &shootOrigin ) { +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_GetActualShootPosition.CanRunInScope(m_ScriptScope)) + { + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { shootOrigin, ToHScript( GetEnemy() ) }; + if (g_Hook_GetActualShootPosition.Call( m_ScriptScope, &functionReturn, args )) + { + if (functionReturn.m_type == FIELD_VECTOR && functionReturn.m_pVector->LengthSqr() != 0.0f) + return *functionReturn.m_pVector; + } + } +#endif + // Project the target's location into the future. Vector vecEnemyLKP = GetEnemyLKP(); Vector vecEnemyOffset = GetEnemy()->BodyTarget( shootOrigin ) - GetEnemy()->GetAbsOrigin(); @@ -11495,17 +11510,9 @@ void CAI_BaseNPC::PickupItem( CBaseEntity *pItem ) m_OnItemPickup.Set( pItem, pItem, this ); Assert( pItem != NULL ); - if( FClassnameIs( pItem, "item_healthkit" ) ) + if( FClassnameIs( pItem, "item_health*" ) ) // item_healthkit, item_healthvial, item_healthkit_custom, etc. { - if ( TakeHealth( sk_healthkit.GetFloat(), DMG_GENERIC ) ) - { - RemoveAllDecals(); - UTIL_Remove( pItem ); - } - } - else if( FClassnameIs( pItem, "item_healthvial" ) ) - { - if ( TakeHealth( sk_healthvial.GetFloat(), DMG_GENERIC ) ) + if ( TakeHealth( static_cast(pItem)->GetItemAmount(), DMG_GENERIC ) ) { RemoveAllDecals(); UTIL_Remove( pItem ); @@ -12075,20 +12082,24 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC // // Hooks // - BEGIN_SCRIPTHOOK( g_Hook_QueryHearSound, "QueryHearSound", FIELD_BOOLEAN, "Called when the NPC is deciding whether to hear a CSound or not." ) + BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_QueryHearSound, "QueryHearSound", FIELD_BOOLEAN, "Called when the NPC is deciding whether to hear a CSound or not." ) DEFINE_SCRIPTHOOK_PARAM( "sound", FIELD_HSCRIPT ) END_SCRIPTHOOK() - BEGIN_SCRIPTHOOK( g_Hook_QuerySeeEntity, "QuerySeeEntity", FIELD_BOOLEAN, "Called when the NPC is deciding whether to see an entity or not." ) + BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_QuerySeeEntity, "QuerySeeEntity", FIELD_BOOLEAN, "Called when the NPC is deciding whether to see an entity or not." ) DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) END_SCRIPTHOOK() - BEGIN_SCRIPTHOOK( g_Hook_TranslateActivity, "NPC_TranslateActivity", FIELD_VARIANT, "Called when the NPC is translating their current activity. The activity is provided in both string and ID form. Should return either an activity string or an activity ID. Return -1 to not translate." ) + BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_TranslateActivity, "NPC_TranslateActivity", FIELD_VARIANT, "Called when the NPC is translating their current activity. The activity is provided in both string and ID form. Should return either an activity string or an activity ID. Return -1 to not translate." ) DEFINE_SCRIPTHOOK_PARAM( "activity", FIELD_CSTRING ) DEFINE_SCRIPTHOOK_PARAM( "activity_id", FIELD_INTEGER ) END_SCRIPTHOOK() - BEGIN_SCRIPTHOOK( g_Hook_TranslateSchedule, "NPC_TranslateSchedule", FIELD_VARIANT, "Called when the NPC is translating their current schedule. The schedule is provided in both string and ID form. Should return either a schedule string or a schedule ID. Return -1 to not translate." ) + BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_TranslateSchedule, "NPC_TranslateSchedule", FIELD_VARIANT, "Called when the NPC is translating their current schedule. The schedule is provided in both string and ID form. Should return either a schedule string or a schedule ID. Return -1 to not translate." ) DEFINE_SCRIPTHOOK_PARAM( "schedule", FIELD_CSTRING ) DEFINE_SCRIPTHOOK_PARAM( "schedule_id", FIELD_INTEGER ) END_SCRIPTHOOK() + BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_GetActualShootPosition, "GetActualShootPosition", FIELD_VOID, "Called when the NPC is getting their actual shoot position, using the default shoot position as the parameter. (NOTE: NPCs which override this themselves might not always use this hook!)" ) + DEFINE_SCRIPTHOOK_PARAM( "shootOrigin", FIELD_VECTOR ) + DEFINE_SCRIPTHOOK_PARAM( "target", FIELD_HSCRIPT ) + END_SCRIPTHOOK() END_SCRIPTDESC(); #endif diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index 284a315a..e032e990 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -100,11 +100,6 @@ extern bool AIStrongOpt( void ); #ifdef MAPBASE // Defines Mapbase's extended NPC response system usage. #define EXPANDED_RESPONSE_SYSTEM_USAGE - -// Use the model keyvalue if it is defined -#define DefaultOrCustomModel(defaultModel) GetModelName() != NULL_STRING ? STRING(GetModelName()) : defaultModel -#else -#define DefaultOrCustomModel() defaultModel #endif #ifdef EXPANDED_RESPONSE_SYSTEM_USAGE @@ -1244,6 +1239,8 @@ public: int ScriptGetActivityID() { return GetActivity(); } void ScriptSetActivity( const char *szActivity ) { SetActivity( (Activity)GetActivityID( szActivity ) ); } void ScriptSetActivityID( int iActivity ) { SetActivity((Activity)iActivity); } + int ScriptTranslateActivity( const char *szActivity ) { return TranslateActivity( (Activity)GetActivityID( szActivity ) ); } + int ScriptTranslateActivityID( int iActivity ) { return TranslateActivity( (Activity)iActivity ); } const char* VScriptGetSchedule(); int VScriptGetScheduleID(); @@ -2311,6 +2308,15 @@ public: CUtlVector m_ScheduleHistory; #endif//AI_MONITOR_FOR_OSCILLATION +#ifdef MAPBASE_VSCRIPT + static ScriptHook_t g_Hook_QueryHearSound; + static ScriptHook_t g_Hook_QuerySeeEntity; + static ScriptHook_t g_Hook_TranslateActivity; + static ScriptHook_t g_Hook_TranslateSchedule; + static ScriptHook_t g_Hook_GetActualShootPosition; + static ScriptHook_t g_Hook_OverrideMove; +#endif + private: // Break into pieces! diff --git a/sp/src/game/server/ai_speech.cpp b/sp/src/game/server/ai_speech.cpp index 60190744..dafad41e 100644 --- a/sp/src/game/server/ai_speech.cpp +++ b/sp/src/game/server/ai_speech.cpp @@ -1210,7 +1210,7 @@ void CAI_Expresser::SpeechMsg( CBaseEntity *pFlex, const char *pszFormat, ... ) } else { - CGMsg( 1, CON_GROUP_CHOREO "%s", string ); + CGMsg( 1, CON_GROUP_CHOREO, "%s", string ); } UTIL_LogPrintf( string ); } diff --git a/sp/src/game/server/baseanimating.cpp b/sp/src/game/server/baseanimating.cpp index f16744f1..788edc27 100644 --- a/sp/src/game/server/baseanimating.cpp +++ b/sp/src/game/server/baseanimating.cpp @@ -284,6 +284,7 @@ END_SEND_TABLE() #ifdef MAPBASE_VSCRIPT ScriptHook_t CBaseAnimating::g_Hook_OnServerRagdoll; +ScriptHook_t CBaseAnimating::g_Hook_HandleAnimEvent; #endif BEGIN_ENT_SCRIPTDESC( CBaseAnimating, CBaseEntity, "Animating models" ) @@ -342,6 +343,10 @@ BEGIN_ENT_SCRIPTDESC( CBaseAnimating, CBaseEntity, "Animating models" ) DEFINE_SCRIPTHOOK_PARAM( "ragdoll", FIELD_HSCRIPT ) DEFINE_SCRIPTHOOK_PARAM( "submodel", FIELD_BOOLEAN ) END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( CBaseAnimating::g_Hook_HandleAnimEvent, "HandleAnimEvent", FIELD_BOOLEAN, "Called when handling animation events. Return false to cancel base handling." ) + DEFINE_SCRIPTHOOK_PARAM( "event", FIELD_HSCRIPT ) + END_SCRIPTHOOK() #endif END_SCRIPTDESC(); @@ -1243,6 +1248,11 @@ void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler ) event.eventtime = m_flAnimTime + (flCycle - GetCycle()) / flCycleRate + GetAnimTimeInterval(); } +#ifdef MAPBASE_VSCRIPT + if (eventHandler->ScriptHookHandleAnimEvent( &event ) == false) + continue; +#endif + /* if (m_debugOverlays & OVERLAY_NPC_SELECTED_BIT) { @@ -1273,6 +1283,29 @@ void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler ) } } +#ifdef MAPBASE_VSCRIPT +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CBaseAnimating::ScriptHookHandleAnimEvent( animevent_t *pEvent ) +{ + if (m_ScriptScope.IsInitialized() && g_Hook_HandleAnimEvent.CanRunInScope(m_ScriptScope)) + { + HSCRIPT hEvent = g_pScriptVM->RegisterInstance( pEvent ); + + // event + ScriptVariant_t args[] = { hEvent }; + ScriptVariant_t returnValue = true; + g_Hook_HandleAnimEvent.Call( m_ScriptScope, &returnValue, args ); + + g_pScriptVM->RemoveInstance( hEvent ); + return returnValue.m_bool; + } + + return true; +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/baseanimating.h b/sp/src/game/server/baseanimating.h index 8513d886..8f0e0aa8 100644 --- a/sp/src/game/server/baseanimating.h +++ b/sp/src/game/server/baseanimating.h @@ -144,6 +144,9 @@ public: bool HasAnimEvent( int nSequence, int nEvent ); virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler ); // Handle events that have happend since last time called up until X seconds into the future virtual void HandleAnimEvent( animevent_t *pEvent ); +#ifdef MAPBASE_VSCRIPT + bool ScriptHookHandleAnimEvent( animevent_t *pEvent ); +#endif int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); inline int LookupPoseParameter( const char *szName ) { return LookupPoseParameter(GetModelPtr(), szName); } @@ -211,6 +214,7 @@ public: void SetSkin( int iSkin ) { m_nSkin = iSkin; } static ScriptHook_t g_Hook_OnServerRagdoll; + static ScriptHook_t g_Hook_HandleAnimEvent; #endif // These return the attachment in the space of the entity diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 5302ee6a..b6871817 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2225,6 +2225,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC( SetModel, "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelName, "GetModelName", "Returns the name of the model" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptStopSound, "StopSound", "Stops a sound from this entity." ) 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.") @@ -2269,6 +2270,9 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC( ApplyAbsVelocityImpulse, "" ) DEFINE_SCRIPTFUNC( ApplyLocalAngularVelocityImpulse, "" ) + + DEFINE_SCRIPTFUNC( BodyTarget, "" ) + DEFINE_SCRIPTFUNC( HeadTarget, "" ) #endif DEFINE_SCRIPTFUNC_NAMED( GetAbsVelocity, "GetVelocity", "" ) @@ -2285,11 +2289,11 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" 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( 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( Remove, "Destroy", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetOwner, "SetOwner", "" ) DEFINE_SCRIPTFUNC_NAMED( GetTeamNumber, "GetTeam", "" ) DEFINE_SCRIPTFUNC_NAMED( ChangeTeam, "SetTeam", "" ) @@ -2590,10 +2594,10 @@ void CBaseEntity::UpdateOnRemove( void ) #ifdef MAPBASE_VSCRIPT FOR_EACH_VEC( m_ScriptThinkFuncs, i ) { - HSCRIPT h = m_ScriptThinkFuncs[i].m_hfnThink; + HSCRIPT h = m_ScriptThinkFuncs[i]->m_hfnThink; if ( h ) g_pScriptVM->ReleaseScript( h ); } - m_ScriptThinkFuncs.Purge(); + m_ScriptThinkFuncs.PurgeAndDeleteElements(); #endif // MAPBASE_VSCRIPT } } @@ -8675,173 +8679,6 @@ void CBaseEntity::ScriptStopThinkFunction() m_iszScriptThinkFunction = NULL_STRING; SetContextThink( NULL, TICK_NEVER_THINK, "ScriptThink" ); } - - -static inline void ScriptStopContextThink( scriptthinkfunc_t *context ) -{ - g_pScriptVM->ReleaseScript( context->m_hfnThink ); - context->m_hfnThink = NULL; - context->m_nNextThinkTick = TICK_NEVER_THINK; -} - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CBaseEntity::ScriptContextThink() -{ - float flNextThink = FLT_MAX; - int nScheduledTick = 0; - - for ( int i = m_ScriptThinkFuncs.Count(); i--; ) - { - scriptthinkfunc_t *cur = &m_ScriptThinkFuncs[i]; - - if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) - continue; - - if ( cur->m_nNextThinkTick > gpGlobals->tickcount ) - { - // There is more to execute, don't stop thinking if the rest are done. - - // also find the shortest schedule - if ( !nScheduledTick || nScheduledTick > cur->m_nNextThinkTick ) - { - nScheduledTick = cur->m_nNextThinkTick; - } - continue; - } - - ScriptVariant_t varReturn; - - if ( cur->m_bNoParam ) - { - if ( g_pScriptVM->Call( cur->m_hfnThink, NULL, true, &varReturn ) == SCRIPT_ERROR ) - { - ScriptStopContextThink(cur); - m_ScriptThinkFuncs.Remove(i); - continue; - } - } - else - { - if ( g_pScriptVM->Call( cur->m_hfnThink, NULL, true, &varReturn, m_hScriptInstance ) == SCRIPT_ERROR ) - { - ScriptStopContextThink(cur); - m_ScriptThinkFuncs.Remove(i); - continue; - } - } - - float flReturn; - if ( !varReturn.AssignTo( &flReturn ) ) - { - ScriptStopContextThink(cur); - m_ScriptThinkFuncs.Remove(i); - continue; - } - - if ( flReturn < 0.0f ) - { - ScriptStopContextThink(cur); - m_ScriptThinkFuncs.Remove(i); - continue; - } - - // find the shortest delay - if ( flReturn < flNextThink ) - { - flNextThink = flReturn; - } - - cur->m_nNextThinkTick = TIME_TO_TICKS( gpGlobals->curtime + flReturn ); - } - - if ( flNextThink < FLT_MAX ) - { - SetNextThink( gpGlobals->curtime + flNextThink, "ScriptContextThink" ); - } - else if ( nScheduledTick ) - { - SetNextThink( TICKS_TO_TIME( nScheduledTick ), "ScriptContextThink" ); - } - else - { - SetNextThink( TICK_NEVER_THINK, "ScriptContextThink" ); - } -} - -// see ScriptSetThink -static bool s_bScriptContextThinkNoParam = false; - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, float flTime ) -{ - scriptthinkfunc_t th; - V_memset( &th, 0x0, sizeof(scriptthinkfunc_t) ); - unsigned short hash = ( szContext && *szContext ) ? HashString( szContext ) : 0; - bool bFound = false; - - FOR_EACH_VEC( m_ScriptThinkFuncs, i ) - { - scriptthinkfunc_t f = m_ScriptThinkFuncs[i]; - if ( hash == f.m_iContextHash ) - { - th = f; - m_ScriptThinkFuncs.Remove(i); // reorder - bFound = true; - break; - } - } - - if ( hFunc ) - { - float nextthink = gpGlobals->curtime + flTime; - - th.m_bNoParam = s_bScriptContextThinkNoParam; - th.m_hfnThink = hFunc; - th.m_iContextHash = hash; - th.m_nNextThinkTick = TIME_TO_TICKS( nextthink ); - - m_ScriptThinkFuncs.AddToHead( th ); - - int nexttick = GetNextThinkTick( RegisterThinkContext( "ScriptContextThink" ) ); - - // sooner than next think - if ( nexttick <= 0 || nexttick > th.m_nNextThinkTick ) - { - SetContextThink( &CBaseEntity::ScriptContextThink, nextthink, "ScriptContextThink" ); - } - } - // null func input, think exists - else if ( bFound ) - { - ScriptStopContextThink( &th ); - } -} - -//----------------------------------------------------------------------------- -// m_bNoParam and s_bScriptContextThinkNoParam exist only to keep backwards compatibility -// and are an alternative to this script closure: -// -// function CBaseEntity::SetThink( func, time ) -// { -// SetContextThink( "", function(_){ return func() }, time ) -// } -//----------------------------------------------------------------------------- -void CBaseEntity::ScriptSetThink( HSCRIPT hFunc, float time ) -{ - s_bScriptContextThinkNoParam = true; - ScriptSetContextThink( NULL, hFunc, time ); - s_bScriptContextThinkNoParam = false; -} - -void CBaseEntity::ScriptStopThink() -{ - ScriptSetContextThink( NULL, NULL, 0.0f ); -} - #endif // MAPBASE_VSCRIPT //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 358f2037..a25bc031 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -352,9 +352,9 @@ struct thinkfunc_t #ifdef MAPBASE_VSCRIPT struct scriptthinkfunc_t { + int m_nNextThinkTick; HSCRIPT m_hfnThink; unsigned short m_iContextHash; - int m_nNextThinkTick; bool m_bNoParam; }; #endif @@ -2025,7 +2025,7 @@ public: void ScriptStopThink(); void ScriptContextThink(); private: - CUtlVector< scriptthinkfunc_t > m_ScriptThinkFuncs; + CUtlVector< scriptthinkfunc_t* > m_ScriptThinkFuncs; public: #endif const char* GetScriptId(); @@ -2056,8 +2056,10 @@ public: 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 +#ifndef MAPBASE_VSCRIPT void ScriptSetSize(const Vector& mins, const Vector& maxs) { UTIL_SetSize(this, mins, maxs); } void ScriptUtilRemove(void) { UTIL_Remove(this); } +#endif 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); } @@ -2083,6 +2085,7 @@ public: const char* ScriptGetModelName(void) const; HSCRIPT ScriptGetModelKeyValues(void); + void ScriptStopSound(const char* soundname); void ScriptEmitSound(const char* soundname); float ScriptSoundDuration(const char* soundname, const char* actormodel); diff --git a/sp/src/game/server/bmodels.cpp b/sp/src/game/server/bmodels.cpp index 2a74df6c..e8291f8f 100644 --- a/sp/src/game/server/bmodels.cpp +++ b/sp/src/game/server/bmodels.cpp @@ -450,6 +450,11 @@ protected: bool m_bSolidBsp; // Brush is SOLID_BSP +#ifdef MAPBASE + int m_iMinPitch = 30; // FANPITCHMIN + int m_iMaxPitch = 100; // FANPITCHMAX +#endif + public: Vector m_vecClientOrigin; QAngle m_vecClientAngles; @@ -472,6 +477,10 @@ BEGIN_DATADESC( CFuncRotating ) DEFINE_FIELD( m_angStart, FIELD_VECTOR ), DEFINE_FIELD( m_bStopAtStartPos, FIELD_BOOLEAN ), DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_iMinPitch, FIELD_INTEGER, "minpitch" ), + DEFINE_KEYFIELD( m_iMaxPitch, FIELD_INTEGER, "maxpitch" ), +#endif // Function Pointers DEFINE_FUNCTION( SpinUpMove ), @@ -823,8 +832,14 @@ void CFuncRotating::HurtTouch ( CBaseEntity *pOther ) } +#ifdef MAPBASE +// In Mapbase, use the keyvalues instead +#define FANPITCHMIN m_iMinPitch +#define FANPITCHMAX m_iMaxPitch +#else #define FANPITCHMIN 30 #define FANPITCHMAX 100 +#endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/cbase.cpp b/sp/src/game/server/cbase.cpp index 81050538..d98ea9cd 100644 --- a/sp/src/game/server/cbase.cpp +++ b/sp/src/game/server/cbase.cpp @@ -850,7 +850,7 @@ void CEventQueue::Dump( void ) // Purpose: adds the action into the correct spot in the priority queue, targeting entity via string name //----------------------------------------------------------------------------- #ifdef MAPBASE_VSCRIPT -intptr_t +int #else void #endif @@ -874,6 +874,7 @@ CEventQueue::AddEvent( const char *target, const char *targetInput, variant_t Va AddEvent( newEvent ); #ifdef MAPBASE_VSCRIPT + Assert( sizeof(EventQueuePrioritizedEvent_t*) == sizeof(int) ); return reinterpret_cast(newEvent); // POINTER_TO_INT #endif } @@ -882,7 +883,7 @@ CEventQueue::AddEvent( const char *target, const char *targetInput, variant_t Va // Purpose: adds the action into the correct spot in the priority queue, targeting entity via pointer //----------------------------------------------------------------------------- #ifdef MAPBASE_VSCRIPT -intptr_t +int #else void #endif @@ -906,6 +907,7 @@ CEventQueue::AddEvent( CBaseEntity *target, const char *targetInput, variant_t V AddEvent( newEvent ); #ifdef MAPBASE_VSCRIPT + Assert( sizeof(EventQueuePrioritizedEvent_t*) == sizeof(int) ); return reinterpret_cast(newEvent); // POINTER_TO_INT #endif } @@ -1293,7 +1295,7 @@ void CEventQueue::CancelEventsByInput( CBaseEntity *pTarget, const char *szInput } } -bool CEventQueue::RemoveEvent( intptr_t event ) +bool CEventQueue::RemoveEvent( int event ) { EventQueuePrioritizedEvent_t *pe = reinterpret_cast(event); // INT_TO_POINTER @@ -1310,7 +1312,7 @@ bool CEventQueue::RemoveEvent( intptr_t event ) return false; } -float CEventQueue::GetTimeLeft( intptr_t event ) +float CEventQueue::GetTimeLeft( int event ) { EventQueuePrioritizedEvent_t *pe = reinterpret_cast(event); // INT_TO_POINTER diff --git a/sp/src/game/server/cbase.h b/sp/src/game/server/cbase.h index 290e3b25..2b00af39 100644 --- a/sp/src/game/server/cbase.h +++ b/sp/src/game/server/cbase.h @@ -104,6 +104,13 @@ extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseE #define MAX_OLD_ENEMIES 4 // how many old enemies to remember +#ifdef MAPBASE +// Use the model keyvalue if it is defined +#define DefaultOrCustomModel(defaultModel) GetModelName() != NULL_STRING ? STRING(GetModelName()) : defaultModel +#else +#define DefaultOrCustomModel() defaultModel +#endif + // used by suit voice to indicate damage sustained and repaired type to player enum diff --git a/sp/src/game/server/envmicrophone.cpp b/sp/src/game/server/envmicrophone.cpp index ee78f87f..29a59ead 100644 --- a/sp/src/game/server/envmicrophone.cpp +++ b/sp/src/game/server/envmicrophone.cpp @@ -48,6 +48,7 @@ BEGIN_DATADESC( CEnvMicrophone ) DEFINE_KEYFIELD(m_iszLandmarkName, FIELD_STRING, "landmark"), DEFINE_FIELD(m_hLandmark, FIELD_EHANDLE), DEFINE_KEYFIELD(m_flPitchScale, FIELD_FLOAT, "PitchScale"), + DEFINE_KEYFIELD(m_flVolumeScale, FIELD_FLOAT, "VolumeScale"), DEFINE_KEYFIELD(m_nChannel, FIELD_INTEGER, "channel"), #endif // DEFINE_FIELD(m_bAvoidFeedback, FIELD_BOOLEAN), // DONT SAVE @@ -61,6 +62,7 @@ BEGIN_DATADESC( CEnvMicrophone ) #ifdef MAPBASE DEFINE_INPUTFUNC(FIELD_INTEGER, "SetDSPPreset", InputSetDSPPreset), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPitchScale", InputSetPitchScale ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetVolumeScale", InputSetVolumeScale ), DEFINE_INPUTFUNC( FIELD_INTEGER, "SetChannel", InputSetChannel ), #endif @@ -272,6 +274,15 @@ void CEnvMicrophone::InputSetPitchScale( inputdata_t &inputdata ) m_flPitchScale = inputdata.value.Float(); } +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CEnvMicrophone::InputSetVolumeScale( inputdata_t &inputdata ) +{ + m_flVolumeScale = inputdata.value.Float(); +} + //----------------------------------------------------------------------------- // Purpose: // Input : &inputdata - @@ -545,11 +556,13 @@ MicrophoneResult_t CEnvMicrophone::SoundPlayed( int entindex, const char *soundn EmitSound_t ep; #ifdef MAPBASE ep.m_nChannel = m_nChannel; + if (m_flVolumeScale != 1.0f) + ep.m_flVolume = (flVolume * m_flVolumeScale); #else ep.m_nChannel = CHAN_STATIC; + ep.m_flVolume = flVolume; #endif ep.m_pSoundName = soundname; - ep.m_flVolume = flVolume; ep.m_SoundLevel = soundlevel; ep.m_nFlags = iFlags; #ifdef MAPBASE diff --git a/sp/src/game/server/envmicrophone.h b/sp/src/game/server/envmicrophone.h index cf8e729e..11527d58 100644 --- a/sp/src/game/server/envmicrophone.h +++ b/sp/src/game/server/envmicrophone.h @@ -57,6 +57,7 @@ public: #ifdef MAPBASE void InputSetDSPPreset( inputdata_t &inputdata ); void InputSetPitchScale( inputdata_t &inputdata ); + void InputSetVolumeScale( inputdata_t &inputdata ); void InputSetChannel( inputdata_t &inputdata ); #endif @@ -88,6 +89,7 @@ private: string_t m_iszLandmarkName; EHANDLE m_hLandmark; float m_flPitchScale = 1.0f; + float m_flVolumeScale = 1.0f; int m_nChannel = CHAN_STATIC; #endif diff --git a/sp/src/game/server/eventqueue.h b/sp/src/game/server/eventqueue.h index 61b0d252..d5cc2d5f 100644 --- a/sp/src/game/server/eventqueue.h +++ b/sp/src/game/server/eventqueue.h @@ -41,8 +41,8 @@ class CEventQueue public: // pushes an event into the queue, targeting a string name (m_iName), or directly by a pointer #ifdef MAPBASE_VSCRIPT - intptr_t AddEvent( const char *target, const char *action, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); - intptr_t AddEvent( CBaseEntity *target, const char *action, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); + int AddEvent( const char *target, const char *action, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); + int AddEvent( CBaseEntity *target, const char *action, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); #else void AddEvent( const char *target, const char *action, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); void AddEvent( CBaseEntity *target, const char *action, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID = 0 ); @@ -73,8 +73,8 @@ public: #ifdef MAPBASE_VSCRIPT void CancelEventsByInput( CBaseEntity *pTarget, const char *szInput ); - bool RemoveEvent( intptr_t event ); - float GetTimeLeft( intptr_t event ); + bool RemoveEvent( int event ); + float GetTimeLeft( int event ); #endif // MAPBASE_VSCRIPT private: diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index f249c3e6..fe523806 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -278,6 +278,7 @@ public: CUtlDict m_QueuedKV; int m_MaxArmor = 100; + int m_SuitZoomFOV = 25; #endif bool PassesDamageFilter( const CTakeDamageInfo &info ); @@ -1760,7 +1761,11 @@ void CHL2_Player::ToggleZoom(void) //----------------------------------------------------------------------------- void CHL2_Player::StartZooming( void ) { +#ifdef MAPBASE + int iFOV = GetPlayerProxy() ? GetPlayerProxy()->m_SuitZoomFOV : 25; +#else int iFOV = 25; +#endif if ( SetFOV( this, iFOV, 0.4f ) ) { m_HL2Local.m_bZooming = true; @@ -4615,6 +4620,7 @@ BEGIN_DATADESC( CLogicPlayerProxy ) DEFINE_INPUTFUNC( FIELD_STRING, "SetPlayerModel", InputSetPlayerModel ), DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetPlayerDrawExternally", InputSetPlayerDrawExternally ), DEFINE_INPUT( m_MaxArmor, FIELD_INTEGER, "SetMaxInputArmor" ), + DEFINE_INPUT( m_SuitZoomFOV, FIELD_INTEGER, "SetSuitZoomFOV" ), #endif DEFINE_FIELD( m_hPlayer, FIELD_EHANDLE ), END_DATADESC() diff --git a/sp/src/game/server/hl2/hl2_player.h b/sp/src/game/server/hl2/hl2_player.h index 84ae23b9..0ffc68f5 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -303,7 +303,7 @@ public: virtual bool IsHoldingEntity( CBaseEntity *pEnt ); virtual void ForceDropOfCarriedPhysObjects( CBaseEntity *pOnlyIfHoldindThis ); virtual float GetHeldObjectMass( IPhysicsObject *pHeldObject ); - virtual CBaseEntity *CHL2_Player::GetHeldObject( void ); + virtual CBaseEntity *GetHeldObject( void ); virtual bool IsFollowingPhysics( void ) { return (m_afPhysicsFlags & PFLAG_ONBARNACLE) > 0; } void InputForceDropPhysObjects( inputdata_t &data ); diff --git a/sp/src/game/server/hl2/item_battery.cpp b/sp/src/game/server/hl2/item_battery.cpp index 7e299fc5..d5c8b416 100644 --- a/sp/src/game/server/hl2/item_battery.cpp +++ b/sp/src/game/server/hl2/item_battery.cpp @@ -23,12 +23,12 @@ public: void Spawn( void ) { Precache( ); - SetModel( "models/items/battery.mdl" ); + SetModel( DefaultOrCustomModel( "models/items/battery.mdl" ) ); BaseClass::Spawn( ); } void Precache( void ) { - PrecacheModel ("models/items/battery.mdl"); + PrecacheModel( DefaultOrCustomModel( "models/items/battery.mdl" ) ); PrecacheScriptSound( "ItemBattery.Touch" ); @@ -36,10 +36,30 @@ public: bool MyTouch( CBasePlayer *pPlayer ) { CHL2_Player *pHL2Player = dynamic_cast( pPlayer ); +#ifdef MAPBASE + return ( pHL2Player && pHL2Player->ApplyBattery( m_flPowerMultiplier ) ); +#else return ( pHL2Player && pHL2Player->ApplyBattery() ); +#endif } + +#ifdef MAPBASE + void InputSetPowerMultiplier( inputdata_t &inputdata ) { m_flPowerMultiplier = inputdata.value.Float(); } + float m_flPowerMultiplier = 1.0f; + + DECLARE_DATADESC(); +#endif }; LINK_ENTITY_TO_CLASS(item_battery, CItemBattery); PRECACHE_REGISTER(item_battery); +#ifdef MAPBASE +BEGIN_DATADESC( CItemBattery ) + + DEFINE_KEYFIELD( m_flPowerMultiplier, FIELD_FLOAT, "PowerMultiplier" ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPowerMultiplier", InputSetPowerMultiplier ), + +END_DATADESC() +#endif + diff --git a/sp/src/game/server/hl2/item_healthkit.cpp b/sp/src/game/server/hl2/item_healthkit.cpp index 628f873e..54f961c7 100644 --- a/sp/src/game/server/hl2/item_healthkit.cpp +++ b/sp/src/game/server/hl2/item_healthkit.cpp @@ -30,11 +30,29 @@ public: void Spawn( void ); void Precache( void ); bool MyTouch( CBasePlayer *pPlayer ); + +#ifdef MAPBASE + float GetItemAmount() { return sk_healthkit.GetFloat() * m_flHealthMultiplier; } + + void InputSetHealthMultiplier( inputdata_t &inputdata ) { m_flHealthMultiplier = inputdata.value.Float(); } + float m_flHealthMultiplier = 1.0f; + + DECLARE_DATADESC(); +#endif }; LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit ); PRECACHE_REGISTER(item_healthkit); +#ifdef MAPBASE +BEGIN_DATADESC( CHealthKit ) + + DEFINE_KEYFIELD( m_flHealthMultiplier, FIELD_FLOAT, "HealthMultiplier" ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetHealthMultiplier", InputSetHealthMultiplier ), + +END_DATADESC() +#endif + //----------------------------------------------------------------------------- // Purpose: @@ -66,7 +84,11 @@ void CHealthKit::Precache( void ) //----------------------------------------------------------------------------- bool CHealthKit::MyTouch( CBasePlayer *pPlayer ) { +#ifdef MAPBASE + if ( pPlayer->TakeHealth( GetItemAmount(), DMG_GENERIC ) ) +#else if ( pPlayer->TakeHealth( sk_healthkit.GetFloat(), DMG_GENERIC ) ) +#endif { CSingleUserRecipientFilter user( pPlayer ); user.MakeReliable(); @@ -119,7 +141,11 @@ public: bool MyTouch( CBasePlayer *pPlayer ) { +#ifdef MAPBASE + if ( pPlayer->TakeHealth( GetItemAmount(), DMG_GENERIC ) ) +#else if ( pPlayer->TakeHealth( sk_healthvial.GetFloat(), DMG_GENERIC ) ) +#endif { CSingleUserRecipientFilter user( pPlayer ); user.MakeReliable(); @@ -145,11 +171,132 @@ public: return false; } + +#ifdef MAPBASE + float GetItemAmount() { return sk_healthvial.GetFloat() * m_flHealthMultiplier; } + + void InputSetHealthMultiplier( inputdata_t &inputdata ) { m_flHealthMultiplier = inputdata.value.Float(); } + float m_flHealthMultiplier = 1.0f; + + DECLARE_DATADESC(); +#endif }; LINK_ENTITY_TO_CLASS( item_healthvial, CHealthVial ); PRECACHE_REGISTER( item_healthvial ); +#ifdef MAPBASE +BEGIN_DATADESC( CHealthVial ) + + DEFINE_KEYFIELD( m_flHealthMultiplier, FIELD_FLOAT, "HealthMultiplier" ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetHealthMultiplier", InputSetHealthMultiplier ), + +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Small health kit. Heals the player when picked up. +//----------------------------------------------------------------------------- +class CHealthKitCustom : public CItem +{ +public: + DECLARE_CLASS( CHealthKitCustom, CItem ); + CHealthKitCustom(); + + void Spawn( void ); + void Precache( void ); + bool MyTouch( CBasePlayer *pPlayer ); + + float GetItemAmount() { return m_flHealthAmount; } + + void InputSetHealthAmount( inputdata_t &inputdata ) { m_flHealthAmount = inputdata.value.Float(); } + + float m_flHealthAmount; + string_t m_iszTouchSound; + + DECLARE_DATADESC(); +}; + +LINK_ENTITY_TO_CLASS( item_healthkit_custom, CHealthKitCustom ); +//PRECACHE_REGISTER(item_healthkit_custom); + +#ifdef MAPBASE +BEGIN_DATADESC( CHealthKitCustom ) + + DEFINE_KEYFIELD( m_flHealthAmount, FIELD_FLOAT, "HealthAmount" ), + DEFINE_KEYFIELD( m_iszTouchSound, FIELD_STRING, "TouchSound" ), + + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetHealthAmount", InputSetHealthAmount ), + +END_DATADESC() +#endif + + +CHealthKitCustom::CHealthKitCustom() +{ + SetModelName( AllocPooledString( "models/items/healthkit.mdl" ) ); + m_flHealthAmount = sk_healthkit.GetFloat(); + m_iszTouchSound = AllocPooledString( "HealthKit.Touch" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthKitCustom::Spawn( void ) +{ + Precache(); + SetModel( STRING( GetModelName() ) ); + + BaseClass::Spawn(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthKitCustom::Precache( void ) +{ + PrecacheModel( STRING( GetModelName() ) ); + + PrecacheScriptSound( STRING( m_iszTouchSound ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pPlayer - +// Output : +//----------------------------------------------------------------------------- +bool CHealthKitCustom::MyTouch( CBasePlayer *pPlayer ) +{ + if ( pPlayer->TakeHealth( GetItemAmount(), DMG_GENERIC ) ) + { + CSingleUserRecipientFilter user( pPlayer ); + user.MakeReliable(); + + UserMessageBegin( user, "ItemPickup" ); + WRITE_STRING( GetClassname() ); + MessageEnd(); + + CPASAttenuationFilter filter( pPlayer, STRING( m_iszTouchSound ) ); + EmitSound( filter, pPlayer->entindex(), STRING( m_iszTouchSound ) ); + + if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES ) + { + Respawn(); + } + else + { + UTIL_Remove(this); + } + + return true; + } + + return false; +} +#endif + //----------------------------------------------------------------------------- // Wall mounted health kit. Heals the player when used. //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/proto_sniper.cpp b/sp/src/game/server/hl2/proto_sniper.cpp index 5427850a..61460130 100644 --- a/sp/src/game/server/hl2/proto_sniper.cpp +++ b/sp/src/game/server/hl2/proto_sniper.cpp @@ -334,6 +334,10 @@ private: bool IsPlayerAllySniper(); +#ifdef MAPBASE + const Vector &GetPaintCursor() { return m_vecPaintCursor; } +#endif + private: /// This is the variable from which m_flPaintTime gets set. @@ -403,6 +407,9 @@ private: DEFINE_CUSTOM_AI; DECLARE_DATADESC(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif }; @@ -500,6 +507,26 @@ BEGIN_DATADESC( CProtoSniper ) END_DATADESC() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( CProtoSniper, CAI_BaseNPC, "Combine sniper NPC." ) + + DEFINE_SCRIPTFUNC( GetBulletSpeed, "" ) + DEFINE_SCRIPTFUNC( GetBulletOrigin, "" ) + DEFINE_SCRIPTFUNC( ScopeGlint, "" ) + + DEFINE_SCRIPTFUNC( GetPositionParameter, "" ) + DEFINE_SCRIPTFUNC( IsSweepingRandomly, "" ) + DEFINE_SCRIPTFUNC( FindFrustratedShot, "" ) + + DEFINE_SCRIPTFUNC( IsLaserOn, "" ) + DEFINE_SCRIPTFUNC( LaserOn, "" ) + DEFINE_SCRIPTFUNC( LaserOff, "" ) + + DEFINE_SCRIPTFUNC( GetPaintCursor, "Get the point the sniper is currently aiming at." ) + +END_SCRIPTDESC() +#endif + //========================================================= @@ -2588,6 +2615,19 @@ Vector CProtoSniper::DesiredBodyTarget( CBaseEntity *pTarget ) // By default, aim for the center Vector vecTarget = pTarget->WorldSpaceCenter(); +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_GetActualShootPosition.CanRunInScope(m_ScriptScope)) + { + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { GetBulletOrigin(), ToHScript( pTarget ) }; + if (g_Hook_GetActualShootPosition.Call( m_ScriptScope, &functionReturn, args )) + { + if (functionReturn.m_type == FIELD_VECTOR && functionReturn.m_pVector->LengthSqr() != 0.0f) + return *functionReturn.m_pVector; + } + } +#endif + float flTimeSinceLastMiss = gpGlobals->curtime - m_flTimeLastShotMissed; if( pTarget->GetFlags() & FL_CLIENT ) diff --git a/sp/src/game/server/items.h b/sp/src/game/server/items.h index 2089fa1f..53f440e8 100644 --- a/sp/src/game/server/items.h +++ b/sp/src/game/server/items.h @@ -90,9 +90,12 @@ public: #ifdef MAPBASE // This is in CBaseEntity, but I can't find a use for it anywhere. - // Must not have been fully implemented. Please remove this if it turns out to be something important. + // It may have been originally intended for TF2 or some other game-specific item class. Please remove this if it turns out to be something important. virtual bool IsCombatItem() { return true; } + // Used to access item_healthkit values, etc. from outside of the class + virtual float GetItemAmount() { return 1.0f; } + void InputEnablePlayerPickup( inputdata_t &inputdata ); void InputDisablePlayerPickup( inputdata_t &inputdata ); void InputEnableNPCPickup( inputdata_t &inputdata ); diff --git a/sp/src/game/server/logic_playmovie.cpp b/sp/src/game/server/logic_playmovie.cpp new file mode 100644 index 00000000..4e62f738 --- /dev/null +++ b/sp/src/game/server/logic_playmovie.cpp @@ -0,0 +1,136 @@ +//===== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======// +// +// Purpose: Plays a movie and reports on finish +// +//===========================================================================// + +#include "cbase.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CLogicPlayMovie : public CLogicalEntity +{ +public: + DECLARE_CLASS( CLogicPlayMovie, CLogicalEntity ); + DECLARE_DATADESC(); + + CLogicPlayMovie( void ) { } + ~CLogicPlayMovie( void ) { } + + virtual void Precache( void ); + virtual void Spawn( void ); + +private: + + void InputPlayMovie( inputdata_t &data ); +#ifdef MAPBASE + void InputStopMovie( inputdata_t &data ); +#endif + void InputMovieFinished( inputdata_t &data ); + + string_t m_strMovieFilename; + bool m_bAllowUserSkip; +#ifdef MAPBASE + bool m_bLooping; + bool m_bMuted; + + bool m_bPlayingVideo; +#endif + + COutputEvent m_OnPlaybackFinished; +}; + +LINK_ENTITY_TO_CLASS( logic_playmovie, CLogicPlayMovie ); + +BEGIN_DATADESC( CLogicPlayMovie ) + + DEFINE_KEYFIELD( m_strMovieFilename, FIELD_STRING, "MovieFilename" ), + DEFINE_KEYFIELD( m_bAllowUserSkip, FIELD_BOOLEAN, "allowskip" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_bLooping, FIELD_BOOLEAN, "loopvideo" ), + DEFINE_KEYFIELD( m_bMuted, FIELD_BOOLEAN, "mute" ), + + DEFINE_FIELD( m_bPlayingVideo, FIELD_BOOLEAN ), +#endif + + DEFINE_INPUTFUNC( FIELD_VOID, "PlayMovie", InputPlayMovie ), +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_VOID, "StopMovie", InputStopMovie ), +#endif + DEFINE_INPUTFUNC( FIELD_VOID, "__MovieFinished", InputMovieFinished ), + + DEFINE_OUTPUT( m_OnPlaybackFinished, "OnPlaybackFinished" ), + +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CLogicPlayMovie::Precache( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CLogicPlayMovie::Spawn( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CLogicPlayMovie::InputPlayMovie( inputdata_t &data ) +{ + // Build the hacked string + + char szClientCmd[256]; + Q_snprintf( szClientCmd, sizeof(szClientCmd), + "playvideo_complex %s \"ent_fire %s __MovieFinished\" %d %d %d\n", + STRING(m_strMovieFilename), + GetEntityNameAsCStr(), + m_bAllowUserSkip, +#ifdef MAPBASE + m_bLooping, + m_bMuted +#else + 0, + 0 +#endif + ); + + // Send it on + engine->ServerCommand( szClientCmd ); + +#ifdef MAPBASE + m_bPlayingVideo = true; +#endif +} + +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CLogicPlayMovie::InputStopMovie( inputdata_t &data ) +{ + if (m_bPlayingVideo) + { + // Send it on + engine->ServerCommand( "stopvideos\n" ); + } +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CLogicPlayMovie::InputMovieFinished( inputdata_t &data ) +{ + // Simply fire our output + m_OnPlaybackFinished.FireOutput( this, this ); + +#ifdef MAPBASE + m_bPlayingVideo = false; +#endif +} diff --git a/sp/src/game/server/mapbase/logic_externaldata.cpp b/sp/src/game/server/mapbase/logic_externaldata.cpp index b28189f7..c13117f5 100644 --- a/sp/src/game/server/mapbase/logic_externaldata.cpp +++ b/sp/src/game/server/mapbase/logic_externaldata.cpp @@ -199,7 +199,7 @@ void CLogicExternalData::InputWriteKeyValue( inputdata_t &inputdata ) // Separate key from value char *delimiter = Q_strstr(szValue, " "); - if (delimiter && (delimiter + 1) != '\0') + if (delimiter && delimiter[1] != '\0') { Q_strncpy(key, szValue, MIN((delimiter - szValue) + 1, sizeof(key))); Q_strncpy(value, delimiter + 1, sizeof(value)); diff --git a/sp/src/game/server/mapbase/vgui_text_display.cpp b/sp/src/game/server/mapbase/vgui_text_display.cpp new file mode 100644 index 00000000..84e0ac63 --- /dev/null +++ b/sp/src/game/server/mapbase/vgui_text_display.cpp @@ -0,0 +1,437 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: Displays easy, flexible VGui text. Mapbase equivalent of point_worldtext. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "vguiscreen.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define SF_TESTDISPLAY_START_DISABLED (1 << 0) + +//----------------------------------------------------------------------------- +// vgui_text_display +//----------------------------------------------------------------------------- +class CVGuiTextDisplay : public CBaseEntity +{ +public: + + DECLARE_CLASS( CVGuiTextDisplay, CBaseEntity ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + CVGuiTextDisplay(); + virtual ~CVGuiTextDisplay(); + + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + virtual int UpdateTransmitState(); + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual void OnRestore( void ); + + void ScreenVisible( bool bVisible ); + + void Disable( void ); + void Enable( void ); + + void InputDisable( inputdata_t &inputdata ); + void InputEnable( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + + void InputSetMessage( inputdata_t &inputdata ); + void InputSetTextAlignment( inputdata_t &inputdata ); + void InputSetFont( inputdata_t &inputdata ); + void InputSetResolution( inputdata_t &inputdata ); + void InputSetTextSize( inputdata_t &inputdata ); + +private: + + // Control panel + void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ); + void GetControlPanelClassName( int nPanelIndex, const char *&pPanelName ); + void SpawnControlPanels( void ); + void RestoreControlPanels( void ); + +private: + CNetworkVar( bool, m_bEnabled ); + + CNetworkString( m_szDisplayText, 256 ); + CNetworkVar( int, m_iContentAlignment ); + CNetworkString( m_szFont, 64 ); + CNetworkVar( int, m_iResolution ); + float m_flTextSize; + + //CNetworkColor32( m_DisplayColor ); // Use render color + + bool m_bDoFullTransmit; + + CHandle m_hScreen; +}; + +LINK_ENTITY_TO_CLASS( vgui_text_display, CVGuiTextDisplay ); + +//----------------------------------------------------------------------------- +// Save/load +//----------------------------------------------------------------------------- +BEGIN_DATADESC( CVGuiTextDisplay ) + + DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ), + + DEFINE_AUTO_ARRAY_KEYFIELD( m_szDisplayText, FIELD_CHARACTER, "message" ), + DEFINE_KEYFIELD( m_iContentAlignment, FIELD_INTEGER, "alignment" ), + DEFINE_AUTO_ARRAY_KEYFIELD( m_szFont, FIELD_CHARACTER, "font" ), + DEFINE_KEYFIELD( m_iResolution, FIELD_INTEGER, "resolution" ), + DEFINE_KEYFIELD( m_flTextSize, FIELD_FLOAT, "textsize" ), + + DEFINE_FIELD( m_bDoFullTransmit, FIELD_BOOLEAN ), + + DEFINE_FIELD( m_hScreen, FIELD_EHANDLE ), + + DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), + DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), + DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ), + + DEFINE_INPUTFUNC( FIELD_STRING, "SetMessage", InputSetMessage ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetTextAlignment", InputSetTextAlignment ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetFont", InputSetFont ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetResolution", InputSetResolution ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPanelSize", InputSetTextSize ), + +END_DATADESC() + +IMPLEMENT_SERVERCLASS_ST( CVGuiTextDisplay, DT_VGuiTextDisplay ) + SendPropBool( SENDINFO( m_bEnabled ) ), + SendPropString( SENDINFO( m_szDisplayText ) ), + SendPropInt( SENDINFO( m_iContentAlignment ) ), + SendPropString( SENDINFO( m_szFont ) ), + SendPropInt( SENDINFO( m_iResolution ) ), +END_SEND_TABLE() + +CVGuiTextDisplay::CVGuiTextDisplay() +{ + m_flTextSize = 100.0f; + m_iResolution = 200; + m_iContentAlignment = 7; // a_south +} + +CVGuiTextDisplay::~CVGuiTextDisplay() +{ + DestroyVGuiScreen( m_hScreen.Get() ); +} + +//----------------------------------------------------------------------------- +// Read in Hammer data +//----------------------------------------------------------------------------- +bool CVGuiTextDisplay::KeyValue( const char *szKeyName, const char *szValue ) +{ + // NOTE: Have to do these separate because they set two values instead of one + if( FStrEq( szKeyName, "angles" ) ) + { + Assert( GetMoveParent() == NULL ); + QAngle angles; + UTIL_StringToVector( angles.Base(), szValue ); + + // Because the vgui screen basis is strange (z is front, y is up, x is right) + // we need to rotate the typical basis before applying it + VMatrix mat, rotation, tmp; + MatrixFromAngles( angles, mat ); + MatrixBuildRotationAboutAxis( rotation, Vector( 0, 1, 0 ), 90 ); + MatrixMultiply( mat, rotation, tmp ); + MatrixBuildRotateZ( rotation, 90 ); + MatrixMultiply( tmp, rotation, mat ); + MatrixToAngles( mat, angles ); + SetAbsAngles( angles ); + } + else if( FStrEq( szKeyName, "message" ) ) + { + Q_strcpy( m_szDisplayText.GetForModify(), szValue ); + } + else if( FStrEq( szKeyName, "font" ) ) + { + Q_strcpy( m_szFont.GetForModify(), szValue ); + } + else if( FStrEq( szKeyName, "color" ) ) + { + // Use render color + return BaseClass::KeyValue( "rendercolor", szValue ); + } + else + return BaseClass::KeyValue( szKeyName, szValue ); + + return true; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +int CVGuiTextDisplay::UpdateTransmitState() +{ + if ( m_bDoFullTransmit ) + { + m_bDoFullTransmit = false; + return SetTransmitState( FL_EDICT_ALWAYS ); + } + + return SetTransmitState( FL_EDICT_FULLCHECK ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ) +{ + // Are we already marked for transmission? + if ( pInfo->m_pTransmitEdict->Get( entindex() ) ) + return; + + BaseClass::SetTransmit( pInfo, bAlways ); + + // Force our screen to be sent too. + m_hScreen->SetTransmit( pInfo, bAlways ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::Spawn( void ) +{ + Precache(); + + BaseClass::Spawn(); + + m_bEnabled = !HasSpawnFlags( SF_TESTDISPLAY_START_DISABLED ); + + SpawnControlPanels(); + + ScreenVisible( m_bEnabled ); + + m_bDoFullTransmit = true; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::Precache( void ) +{ + BaseClass::Precache(); + + PrecacheVGuiScreen( "text_display_panel" ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::OnRestore( void ) +{ + BaseClass::OnRestore(); + + RestoreControlPanels(); + + ScreenVisible( m_bEnabled ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::ScreenVisible( bool bVisible ) +{ + // Set its active state + m_hScreen->SetActive( bVisible ); + + if ( bVisible ) + { + m_hScreen->RemoveEffects( EF_NODRAW ); + } + else + { + m_hScreen->AddEffects( EF_NODRAW ); + } +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::Disable( void ) +{ + if ( !m_bEnabled ) + return; + + m_bEnabled = false; + + ScreenVisible( false ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::Enable( void ) +{ + if ( m_bEnabled ) + return; + + m_bEnabled = true; + + ScreenVisible( true ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::InputDisable( inputdata_t &inputdata ) +{ + Disable(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::InputEnable( inputdata_t &inputdata ) +{ + Enable(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::InputToggle( inputdata_t &inputdata ) +{ + m_bEnabled ? Disable() : Enable(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::InputSetMessage( inputdata_t &inputdata ) +{ + Q_strcpy( m_szDisplayText.GetForModify(), inputdata.value.String() ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::InputSetTextAlignment( inputdata_t &inputdata ) +{ + m_iContentAlignment = inputdata.value.Int(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::InputSetFont( inputdata_t &inputdata ) +{ + Q_strcpy( m_szFont.GetForModify(), inputdata.value.String() ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::InputSetResolution( inputdata_t &inputdata ) +{ + m_iResolution = inputdata.value.Int(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::InputSetTextSize( inputdata_t &inputdata ) +{ + m_flTextSize = inputdata.value.Float(); + + if (m_hScreen) + { + m_hScreen->SetActualSize( m_flTextSize, m_flTextSize ); + m_hScreen->SetLocalOrigin( m_hScreen->CollisionProp()->OBBCenter() * -1.0f ); + } +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ) +{ + pPanelName = "text_display_panel"; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::GetControlPanelClassName( int nPanelIndex, const char *&pPanelName ) +{ + pPanelName = "vgui_screen"; +} + +//----------------------------------------------------------------------------- +// This is called by the base object when it's time to spawn the control panels +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::SpawnControlPanels() +{ + int nPanel; + for ( nPanel = 0; true; ++nPanel ) + { + const char *pScreenName; + GetControlPanelInfo( nPanel, pScreenName ); + if (!pScreenName) + continue; + + const char *pScreenClassname; + GetControlPanelClassName( nPanel, pScreenClassname ); + if ( !pScreenClassname ) + continue; + + float flWidth = m_flTextSize; + float flHeight = m_flTextSize; + + CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, this, this, 0 ); + pScreen->ChangeTeam( GetTeamNumber() ); + pScreen->SetActualSize( flWidth, flHeight ); + pScreen->SetLocalOrigin( pScreen->CollisionProp()->OBBCenter() * -1.0f ); + pScreen->SetActive( true ); + pScreen->MakeVisibleOnlyToTeammates( false ); + pScreen->SetTransparency( true ); + m_hScreen = pScreen; + + return; + } +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CVGuiTextDisplay::RestoreControlPanels( void ) +{ + int nPanel; + for ( nPanel = 0; true; ++nPanel ) + { + const char *pScreenName; + GetControlPanelInfo( nPanel, pScreenName ); + if (!pScreenName) + continue; + + const char *pScreenClassname; + GetControlPanelClassName( nPanel, pScreenClassname ); + if ( !pScreenClassname ) + continue; + + CVGuiScreen *pScreen = (CVGuiScreen *)gEntList.FindEntityByClassname( NULL, pScreenClassname ); + + while ( ( pScreen && pScreen->GetOwnerEntity() != this ) || Q_strcmp( pScreen->GetPanelName(), pScreenName ) != 0 ) + { + pScreen = (CVGuiScreen *)gEntList.FindEntityByClassname( pScreen, pScreenClassname ); + } + + if ( pScreen ) + { + m_hScreen = pScreen; + m_hScreen->SetActive( true ); + } + + return; + } +} diff --git a/sp/src/game/server/movie_display.cpp b/sp/src/game/server/movie_display.cpp new file mode 100644 index 00000000..5c31fb23 --- /dev/null +++ b/sp/src/game/server/movie_display.cpp @@ -0,0 +1,372 @@ +//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============// +// +// Purpose: Allows movies to be played as a VGUI screen in the world +// +//=====================================================================================// + +#include "cbase.h" +#include "EnvMessage.h" +#include "fmtstr.h" +#include "vguiscreen.h" +#include "filesystem.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + +class CMovieDisplay : public CBaseEntity +{ +public: + + DECLARE_CLASS( CMovieDisplay, CBaseEntity ); + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + virtual ~CMovieDisplay(); + + virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + virtual int UpdateTransmitState(); + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + + virtual void Spawn( void ); + virtual void Precache( void ); + virtual void OnRestore( void ); + + void ScreenVisible( bool bVisible ); + + void Disable( void ); + void Enable( void ); + + void InputDisable( inputdata_t &inputdata ); + void InputEnable( inputdata_t &inputdata ); + + void InputSetDisplayText( inputdata_t &inputdata ); + +private: + + // Control panel + void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ); + void GetControlPanelClassName( int nPanelIndex, const char *&pPanelName ); + void SpawnControlPanels( void ); + void RestoreControlPanels( void ); + +private: + CNetworkVar( bool, m_bEnabled ); + CNetworkVar( bool, m_bLooping ); + + CNetworkString( m_szDisplayText, 128 ); + + // Filename of the movie to play + CNetworkString( m_szMovieFilename, 128 ); + string_t m_strMovieFilename; + + // "Group" name. Screens of the same group name will play the same movie at the same time + // Effectively this lets multiple screens tune to the same "channel" in the world + CNetworkString( m_szGroupName, 128 ); + string_t m_strGroupName; + + int m_iScreenWidth; + int m_iScreenHeight; + + bool m_bDoFullTransmit; + + CHandle m_hScreen; +}; + +LINK_ENTITY_TO_CLASS( vgui_movie_display, CMovieDisplay ); + +//----------------------------------------------------------------------------- +// Save/load +//----------------------------------------------------------------------------- +BEGIN_DATADESC( CMovieDisplay ) + + DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ), + + DEFINE_AUTO_ARRAY_KEYFIELD( m_szDisplayText, FIELD_CHARACTER, "displaytext" ), + + DEFINE_AUTO_ARRAY( m_szMovieFilename, FIELD_CHARACTER ), + DEFINE_KEYFIELD( m_strMovieFilename, FIELD_STRING, "moviefilename" ), + + DEFINE_AUTO_ARRAY( m_szGroupName, FIELD_CHARACTER ), + DEFINE_KEYFIELD( m_strGroupName, FIELD_STRING, "groupname" ), + + DEFINE_KEYFIELD( m_iScreenWidth, FIELD_INTEGER, "width" ), + DEFINE_KEYFIELD( m_iScreenHeight, FIELD_INTEGER, "height" ), + DEFINE_KEYFIELD( m_bLooping, FIELD_BOOLEAN, "looping" ), + + DEFINE_FIELD( m_bDoFullTransmit, FIELD_BOOLEAN ), + + DEFINE_FIELD( m_hScreen, FIELD_EHANDLE ), + + DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), + DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), + + DEFINE_INPUTFUNC( FIELD_STRING, "SetDisplayText", InputSetDisplayText ), + +END_DATADESC() + +IMPLEMENT_SERVERCLASS_ST( CMovieDisplay, DT_MovieDisplay ) + SendPropBool( SENDINFO( m_bEnabled ) ), + SendPropBool( SENDINFO( m_bLooping ) ), + SendPropString( SENDINFO( m_szMovieFilename ) ), + SendPropString( SENDINFO( m_szGroupName ) ), +END_SEND_TABLE() + +CMovieDisplay::~CMovieDisplay() +{ + DestroyVGuiScreen( m_hScreen.Get() ); +} + +//----------------------------------------------------------------------------- +// Read in Hammer data +//----------------------------------------------------------------------------- +bool CMovieDisplay::KeyValue( const char *szKeyName, const char *szValue ) +{ + // NOTE: Have to do these separate because they set two values instead of one + if( FStrEq( szKeyName, "angles" ) ) + { + Assert( GetMoveParent() == NULL ); + QAngle angles; + UTIL_StringToVector( angles.Base(), szValue ); + + // Because the vgui screen basis is strange (z is front, y is up, x is right) + // we need to rotate the typical basis before applying it + VMatrix mat, rotation, tmp; + MatrixFromAngles( angles, mat ); + MatrixBuildRotationAboutAxis( rotation, Vector( 0, 1, 0 ), 90 ); + MatrixMultiply( mat, rotation, tmp ); + MatrixBuildRotateZ( rotation, 90 ); + MatrixMultiply( tmp, rotation, mat ); + MatrixToAngles( mat, angles ); + SetAbsAngles( angles ); + + return true; + } + + return BaseClass::KeyValue( szKeyName, szValue ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +int CMovieDisplay::UpdateTransmitState() +{ + if ( m_bDoFullTransmit ) + { + m_bDoFullTransmit = false; + return SetTransmitState( FL_EDICT_ALWAYS ); + } + + return SetTransmitState( FL_EDICT_FULLCHECK ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ) +{ + // Are we already marked for transmission? + if ( pInfo->m_pTransmitEdict->Get( entindex() ) ) + return; + + BaseClass::SetTransmit( pInfo, bAlways ); + + // Force our screen to be sent too. + m_hScreen->SetTransmit( pInfo, bAlways ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::Spawn( void ) +{ + // Move the strings into a networkable form + Q_strcpy( m_szMovieFilename.GetForModify(), m_strMovieFilename.ToCStr() ); + Q_strcpy( m_szGroupName.GetForModify(), m_strGroupName.ToCStr() ); + + Precache(); + + BaseClass::Spawn(); + + m_bEnabled = false; + + SpawnControlPanels(); + + ScreenVisible( m_bEnabled ); + + m_bDoFullTransmit = true; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::Precache( void ) +{ + BaseClass::Precache(); + + PrecacheVGuiScreen( "video_display_screen" ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::OnRestore( void ) +{ + BaseClass::OnRestore(); + + RestoreControlPanels(); + + ScreenVisible( m_bEnabled ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::ScreenVisible( bool bVisible ) +{ + // Set its active state + m_hScreen->SetActive( bVisible ); + + if ( bVisible ) + { + m_hScreen->RemoveEffects( EF_NODRAW ); + } + else + { + m_hScreen->AddEffects( EF_NODRAW ); + } +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::Disable( void ) +{ + if ( !m_bEnabled ) + return; + + m_bEnabled = false; + + ScreenVisible( false ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::Enable( void ) +{ + if ( m_bEnabled ) + return; + + m_bEnabled = true; + + ScreenVisible( true ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::InputDisable( inputdata_t &inputdata ) +{ + Disable(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::InputEnable( inputdata_t &inputdata ) +{ + Enable(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::InputSetDisplayText( inputdata_t &inputdata ) +{ + Q_strcpy( m_szDisplayText.GetForModify(), inputdata.value.String() ); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ) +{ + pPanelName = "movie_display_screen"; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::GetControlPanelClassName( int nPanelIndex, const char *&pPanelName ) +{ + pPanelName = "vgui_screen"; +} + +//----------------------------------------------------------------------------- +// This is called by the base object when it's time to spawn the control panels +//----------------------------------------------------------------------------- +void CMovieDisplay::SpawnControlPanels() +{ + int nPanel; + for ( nPanel = 0; true; ++nPanel ) + { + const char *pScreenName; + GetControlPanelInfo( nPanel, pScreenName ); + if (!pScreenName) + continue; + + const char *pScreenClassname; + GetControlPanelClassName( nPanel, pScreenClassname ); + if ( !pScreenClassname ) + continue; + + float flWidth = m_iScreenWidth; + float flHeight = m_iScreenHeight; + + CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, this, this, 0 ); + pScreen->ChangeTeam( GetTeamNumber() ); + pScreen->SetActualSize( flWidth, flHeight ); + pScreen->SetActive( true ); + pScreen->MakeVisibleOnlyToTeammates( false ); + pScreen->SetTransparency( true ); + m_hScreen = pScreen; + + return; + } +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CMovieDisplay::RestoreControlPanels( void ) +{ + int nPanel; + for ( nPanel = 0; true; ++nPanel ) + { + const char *pScreenName; + GetControlPanelInfo( nPanel, pScreenName ); + if (!pScreenName) + continue; + + const char *pScreenClassname; + GetControlPanelClassName( nPanel, pScreenClassname ); + if ( !pScreenClassname ) + continue; + + CVGuiScreen *pScreen = (CVGuiScreen *)gEntList.FindEntityByClassname( NULL, pScreenClassname ); + + while ( ( pScreen && pScreen->GetOwnerEntity() != this ) || Q_strcmp( pScreen->GetPanelName(), pScreenName ) != 0 ) + { + pScreen = (CVGuiScreen *)gEntList.FindEntityByClassname( pScreen, pScreenClassname ); + } + + if ( pScreen ) + { + m_hScreen = pScreen; + m_hScreen->SetActive( true ); + } + + return; + } +} diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 2c57cc36..0f26c252 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -526,8 +526,8 @@ BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) DEFINE_SCRIPTFUNC( GetButtonForced, "Gets the player's currently forced buttons." ) DEFINE_SCRIPTFUNC( GetFOV, "" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetFOVOwner, "GetFOVOwner", "" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetFOV, "SetFOV", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetFOVOwner, "GetFOVOwner", "Gets current view owner." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetFOV, "SetFOV", "Sets player FOV regardless of view owner." ) DEFINE_SCRIPTFUNC( ViewPunch, "Punches the player's view with the specified vector." ) DEFINE_SCRIPTFUNC( SetMuzzleFlashTime, "Sets the player's muzzle flash time for AI." ) @@ -5251,6 +5251,11 @@ void CBasePlayer::Spawn( void ) m_vecSmoothedVelocity = vec3_origin; InitVCollision( GetAbsOrigin(), GetAbsVelocity() ); + if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM ) + { + g_pScriptVM->SetValue( "player", GetScriptInstance() ); + } + #if !defined( TF_DLL ) IGameEvent *event = gameeventmanager->CreateEvent( "player_spawn" ); @@ -5275,11 +5280,6 @@ void CBasePlayer::Spawn( void ) UpdateLastKnownArea(); m_weaponFiredTimer.Invalidate(); - - if ( !g_pGameRules->IsMultiplayer() && g_pScriptVM ) - { - g_pScriptVM->SetValue( "player", GetScriptInstance() ); - } } void CBasePlayer::Activate( void ) diff --git a/sp/src/game/server/point_spotlight.cpp b/sp/src/game/server/point_spotlight.cpp index 5a854557..d5901714 100644 --- a/sp/src/game/server/point_spotlight.cpp +++ b/sp/src/game/server/point_spotlight.cpp @@ -75,6 +75,12 @@ private: float m_flHDRColorScale; int m_nMinDXLevel; +#ifdef MAPBASE + float m_flHaloScale; + string_t m_iszHaloMaterial; + string_t m_iszSpotlightMaterial; +#endif + public: COutputEvent m_OnOn, m_OnOff; ///< output fires when turned on, off }; @@ -98,6 +104,11 @@ BEGIN_DATADESC( CPointSpotlight ) DEFINE_KEYFIELD( m_flSpotlightGoalWidth,FIELD_FLOAT, "SpotlightWidth"), DEFINE_KEYFIELD( m_flHDRColorScale, FIELD_FLOAT, "HDRColorScale" ), DEFINE_KEYFIELD( m_nMinDXLevel, FIELD_INTEGER, "mindxlevel" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_flHaloScale, FIELD_FLOAT, "HaloScale" ), + DEFINE_KEYFIELD( m_iszHaloMaterial, FIELD_STRING, "HaloMaterial" ), + DEFINE_KEYFIELD( m_iszSpotlightMaterial, FIELD_STRING, "SpotlightMaterial" ), +#endif // Inputs DEFINE_INPUTFUNC( FIELD_VOID, "LightOn", InputLightOn ), @@ -127,6 +138,9 @@ CPointSpotlight::CPointSpotlight() #endif m_flHDRColorScale = 1.0f; m_nMinDXLevel = 0; +#ifdef MAPBASE + m_flHaloScale = 60.0f; +#endif } #ifdef MAPBASE @@ -148,8 +162,23 @@ void CPointSpotlight::Precache(void) BaseClass::Precache(); // Sprites. +#ifdef MAPBASE + if (m_iszHaloMaterial == NULL_STRING) + { + m_iszHaloMaterial = AllocPooledString( "sprites/light_glow03.vmt" ); + } + + if (m_iszSpotlightMaterial == NULL_STRING) + { + m_iszSpotlightMaterial = AllocPooledString( "sprites/glow_test02.vmt" ); + } + + m_nHaloSprite = PrecacheModel( STRING( m_iszHaloMaterial ) ); + PrecacheModel( STRING( m_iszSpotlightMaterial ) ); +#else m_nHaloSprite = PrecacheModel("sprites/light_glow03.vmt"); PrecacheModel( "sprites/glow_test02.vmt" ); +#endif } @@ -367,13 +396,21 @@ void CPointSpotlight::SpotlightCreate(void) } //m_hSpotlight = CBeam::BeamCreate( "sprites/spotlight.vmt", m_flSpotlightGoalWidth ); +#ifdef MAPBASE + m_hSpotlight = CBeam::BeamCreate( STRING(m_iszSpotlightMaterial), m_flSpotlightGoalWidth ); +#else m_hSpotlight = CBeam::BeamCreate( "sprites/glow_test02.vmt", m_flSpotlightGoalWidth ); +#endif // Set the temporary spawnflag on the beam so it doesn't save (we'll recreate it on restore) m_hSpotlight->SetHDRColorScale( m_flHDRColorScale ); m_hSpotlight->AddSpawnFlags( SF_BEAM_TEMPORARY ); m_hSpotlight->SetColor( m_clrRender->r, m_clrRender->g, m_clrRender->b ); m_hSpotlight->SetHaloTexture(m_nHaloSprite); +#ifdef MAPBASE + m_hSpotlight->SetHaloScale(m_flHaloScale); +#else m_hSpotlight->SetHaloScale(60); +#endif m_hSpotlight->SetEndWidth(m_flSpotlightGoalWidth); m_hSpotlight->SetBeamFlags( (FBEAM_SHADEOUT|FBEAM_NOTILE) ); m_hSpotlight->SetBrightness( 64 ); diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index 1ff2b18e..fc332249 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -3508,7 +3508,10 @@ void CSceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEv if ( IsMultiplayer() ) break; - DispatchStartPermitResponses( scene, pActor, event ); + if ( pActor ) + { + DispatchStartPermitResponses( scene, pActor, event ); + } } break; default: @@ -3666,7 +3669,10 @@ void CSceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEven if ( IsMultiplayer() ) break; - DispatchEndPermitResponses( scene, pActor, event ); + if ( pActor ) + { + DispatchEndPermitResponses( scene, pActor, event ); + } } break; default: diff --git a/sp/src/game/server/server_mapbase.vpc b/sp/src/game/server/server_mapbase.vpc index b4672f19..9c943105 100644 --- a/sp/src/game/server/server_mapbase.vpc +++ b/sp/src/game/server/server_mapbase.vpc @@ -28,6 +28,8 @@ $Project $File "postprocesscontroller.h" $File "env_dof_controller.cpp" $File "env_dof_controller.h" + $File "logic_playmovie.cpp" + $File "movie_display.cpp" $File "ai_expresserfollowup.cpp" [$NEW_RESPONSE_SYSTEM] $File "ai_speechqueue.cpp" [$NEW_RESPONSE_SYSTEM] $File "ai_speechqueue.h" [$NEW_RESPONSE_SYSTEM] @@ -78,6 +80,7 @@ $Project $File "mapbase\SystemConvarMod.cpp" $File "mapbase\SystemConvarMod.h" $File "mapbase\variant_tools.h" + $File "mapbase\vgui_text_display.cpp" $File "mapbase\logic_eventlistener.cpp" $File "mapbase\logic_register_activator.cpp" diff --git a/sp/src/game/server/vscript_server.cpp b/sp/src/game/server/vscript_server.cpp index ebab60e6..6927b0f1 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -110,6 +110,11 @@ public: { return ToHScript( gEntList.FindEntityByClassnameWithin( ToEnt( hStartEntity ), szName, vecMins, vecMaxs ) ); } + + HSCRIPT FindByClassNearestFacing( const Vector &origin, const Vector &facing, float threshold, const char *classname ) + { + return ToHScript( gEntList.FindEntityClassNearestFacing( origin, facing, threshold, const_cast(classname) ) ); + } #endif private: } g_ScriptEntityIterator; @@ -132,6 +137,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptEntityIterator, "CEntities", SCRIPT_SINGLETO 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" ) #ifdef MAPBASE_VSCRIPT DEFINE_SCRIPTFUNC( FindByClassnameWithinBox, "Find entities by class name within an AABB. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" ) + DEFINE_SCRIPTFUNC( FindByClassNearestFacing, "Find the nearest entity along the facing direction from the given origin within the angular threshold with the given classname." ) #endif END_SCRIPTDESC(); @@ -265,11 +271,6 @@ static int MaxPlayers() return gpGlobals->maxClients; } -static float IntervalPerTick() -{ - return gpGlobals->interval_per_tick; -} - static int GetLoadType() { return gpGlobals->eLoadType; @@ -328,7 +329,11 @@ static void DoEntFire( const char *pszTarget, const char *pszAction, const char // ent_fire point_servercommand command "rcon_password mynewpassword" if ( gpGlobals->maxClients > 1 && V_stricmp( target, "point_servercommand" ) == 0 ) { +#ifdef MAPBASE_VSCRIPT return 0; +#else + return; +#endif } if ( *pszAction ) @@ -447,12 +452,6 @@ static float GetEntityIOEventTimeLeft( int event ) { return g_EventQueue.GetTimeLeft(event); } - -// vscript_server.nut adds this to the base CConvars class -static const char *ScriptGetClientConvarValue( const char *pszConVar, int entindex ) -{ - return engine->GetClientConVarValue( entindex, pszConVar ); -} #endif // MAPBASE_VSCRIPT bool VScriptServerInit() @@ -537,7 +536,6 @@ bool VScriptServerInit() #ifdef MAPBASE_VSCRIPT ScriptRegisterFunction( g_pScriptVM, SendToConsoleServer, "Send a string to the server console as a command" ); 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, GetLoadType, "Get the way the current game was loaded (corresponds to the MapLoad enum)" ); 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." ) ); @@ -545,7 +543,6 @@ bool VScriptServerInit() ScriptRegisterFunction( g_pScriptVM, CancelEntityIOEvent, "Remove entity I/O event." ); ScriptRegisterFunction( g_pScriptVM, GetEntityIOEventTimeLeft, "Get time left on entity I/O event." ); - ScriptRegisterFunction( g_pScriptVM, ScriptGetClientConvarValue, SCRIPT_HIDE ); #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." ); diff --git a/sp/src/game/server/vscript_server.nut b/sp/src/game/server/vscript_server.nut index deecea7b..deeacf5d 100644 --- a/sp/src/game/server/vscript_server.nut +++ b/sp/src/game/server/vscript_server.nut @@ -5,15 +5,14 @@ static char g_Script_vscript_server[] = R"vscript( // //============================================================================= -local DoEntFire = ::DoEntFire -local DoEntFireByInstanceHandle = ::DoEntFireByInstanceHandle -local DoDispatchParticleEffect = ::DoDispatchParticleEffect -local DoUniqueString = ::DoUniqueString -local ScriptGetClientConvarValue = ::ScriptGetClientConvarValue +local DoEntFire = DoEntFire +local DoEntFireByInstanceHandle = DoEntFireByInstanceHandle +local DoDispatchParticleEffect = DoDispatchParticleEffect +local DoUniqueString = DoUniqueString function UniqueString( string = "" ) { - return DoUniqueString( string.tostring() ); + return DoUniqueString( "" + string ); } function EntFire( target, action, value = null, delay = 0.0, activator = null, caller = null ) @@ -36,7 +35,7 @@ function EntFire( target, action, value = null, delay = 0.0, activator = null, c } } - return DoEntFire( target.tostring(), action.tostring(), value.tostring(), delay, activator, caller ); + return DoEntFire( "" + target, "" + action, "" + value, delay, activator, caller ); } function EntFireByHandle( target, action, value = null, delay = 0.0, activator = null, caller = null ) @@ -59,7 +58,7 @@ function EntFireByHandle( target, action, value = null, delay = 0.0, activator = } } - return DoEntFireByInstanceHandle( target, action.tostring(), value.tostring(), delay, activator, caller ); + return DoEntFireByInstanceHandle( target, "" + action, "" + value, delay, activator, caller ); } function DispatchParticleEffect( particleName, origin, angles, entity = null ) @@ -67,12 +66,6 @@ function DispatchParticleEffect( particleName, origin, angles, entity = null ) DoDispatchParticleEffect( particleName, origin, angles, entity ); } -// CConvars is declared within the library -function CConvars::GetClientConvarValue(cvar,idx) -{ - return ScriptGetClientConvarValue(cvar,idx); -} - __Documentation.RegisterHelp( "CConvars::GetClientConvarValue", "CConvars::GetClientConvarValue(string, int)", "Returns the convar value for the entindex as a string. Only works with client convars with the FCVAR_USERINFO flag." ); function __ReplaceClosures( script, scope ) diff --git a/sp/src/game/shared/SoundEmitterSystem.cpp b/sp/src/game/shared/SoundEmitterSystem.cpp index 390b5ca4..e1072b78 100644 --- a/sp/src/game/shared/SoundEmitterSystem.cpp +++ b/sp/src/game/shared/SoundEmitterSystem.cpp @@ -1226,6 +1226,11 @@ void CBaseEntity::ScriptEmitSound( const char *soundname ) EmitSound( soundname ); } +void CBaseEntity::ScriptStopSound( const char *soundname ) +{ + StopSound( soundname ); +} + float CBaseEntity::ScriptSoundDuration( const char *soundname, const char *actormodel ) { float duration = CBaseEntity::GetSoundDuration( soundname, actormodel ); diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index f07f3775..cae3f5d9 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2712,4 +2712,296 @@ HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void ) else return NULL; } + +static inline void ScriptStopContextThink( scriptthinkfunc_t *context ) +{ + Assert( context->m_hfnThink ); + + g_pScriptVM->ReleaseScript( context->m_hfnThink ); + context->m_hfnThink = NULL; + //context->m_nNextThinkTick = TICK_NEVER_THINK; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptContextThink() +{ + float flNextThink = FLT_MAX; + int nScheduledTick = 0; + + for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ++i ) + { + scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i]; + + if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) + { + continue; + } + + if ( cur->m_nNextThinkTick > gpGlobals->tickcount ) + { + // There is more to execute, don't stop thinking if the rest are done. + + // Find the shortest schedule + if ( !nScheduledTick || nScheduledTick > cur->m_nNextThinkTick ) + { + nScheduledTick = cur->m_nNextThinkTick; + } + continue; + } + +#ifdef _DEBUG + // going to run the script func + cur->m_nNextThinkTick = 0; +#endif + + ScriptVariant_t varReturn; + + if ( !cur->m_bNoParam ) + { + ScriptVariant_t arg = m_hScriptInstance; + if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, &arg, 1, &varReturn, NULL, true ) == SCRIPT_ERROR ) + { + cur->m_nNextThinkTick = TICK_NEVER_THINK; + continue; + } + } + else + { + if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, NULL, 0, &varReturn, NULL, true ) == SCRIPT_ERROR ) + { + cur->m_nNextThinkTick = TICK_NEVER_THINK; + continue; + } + } + + if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) + { + // stopped from script while thinking + continue; + } + + float flReturn; + if ( !varReturn.AssignTo( &flReturn ) ) + { + cur->m_nNextThinkTick = TICK_NEVER_THINK; + continue; + } + + if ( flReturn < 0.0f ) + { + cur->m_nNextThinkTick = TICK_NEVER_THINK; + continue; + } + + if ( flReturn < flNextThink ) + { + flNextThink = flReturn; + } + + cur->m_nNextThinkTick = TIME_TO_TICKS( gpGlobals->curtime + flReturn ); + } + + // deferred safe removal + for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ) + { + if ( m_ScriptThinkFuncs[i]->m_nNextThinkTick == TICK_NEVER_THINK ) + { + ScriptStopContextThink( m_ScriptThinkFuncs[i] ); + delete m_ScriptThinkFuncs[i]; + m_ScriptThinkFuncs.Remove(i); + } + else ++i; + } + + bool bNewNext = flNextThink < FLT_MAX; + +#ifdef _DEBUG +#ifdef GAME_DLL + int nNextThinkTick = GetNextThinkTick("ScriptContextThink"); // -1 +#else + int nNextThinkTick = GetNextThinkTick(); // 0 +#endif + if ( ( nNextThinkTick <= 0 ) || ( nNextThinkTick >= nScheduledTick ) || ( nNextThinkTick == gpGlobals->tickcount ) ) + { +#endif + if ( nScheduledTick ) + { + float flScheduledTime = TICKS_TO_TIME( nScheduledTick ); + + if ( bNewNext ) + { + flNextThink = min( gpGlobals->curtime + flNextThink, flScheduledTime ); + } + else + { + flNextThink = flScheduledTime; + } + } + else + { + if ( bNewNext ) + { + flNextThink = gpGlobals->curtime + flNextThink; + } + else + { +#ifdef GAME_DLL + flNextThink = TICK_NEVER_THINK; +#else + flNextThink = CLIENT_THINK_NEVER; +#endif + } + } +#ifdef _DEBUG + } + else + { + // Next think was set (from script) to a sooner tick while thinking? + Assert(0); + + if ( nScheduledTick ) + { + int nNextSchedule = min( nScheduledTick, nNextThinkTick ); + float flNextSchedule = TICKS_TO_TIME( nNextSchedule ); + + if ( bNewNext ) + { + flNextThink = min( gpGlobals->curtime + flNextThink, flNextSchedule ); + } + else + { + flNextThink = flNextSchedule; + } + } + else + { + float nextthink = TICKS_TO_TIME( nNextThinkTick ); + + if ( bNewNext ) + { + flNextThink = min( gpGlobals->curtime + flNextThink, nextthink ); + } + else + { + flNextThink = nextthink; + } + } + } +#endif + +#ifdef GAME_DLL + SetNextThink( flNextThink, "ScriptContextThink" ); +#else + SetNextClientThink( flNextThink ); +#endif +} + +// see ScriptSetThink +static bool s_bScriptContextThinkNoParam = false; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, float flTime ) +{ +#ifdef CLIENT_DLL + // Context thinking is not yet supported on client, entities can only have 1 think function. + // C_World does not have one by default, so it is safe to set its. + if ( !IsWorld() ) + { + g_pScriptVM->RaiseException("SetContextThink is only supported on C_World"); + return; + } +#endif + + scriptthinkfunc_t *pf = NULL; + unsigned short hash = ( szContext && *szContext ) ? HashString( szContext ) : 0; + + FOR_EACH_VEC( m_ScriptThinkFuncs, i ) + { + scriptthinkfunc_t *f = m_ScriptThinkFuncs[i]; + if ( hash == f->m_iContextHash ) + { + pf = f; + break; + } + } + + if ( hFunc ) + { + // add new + if ( !pf ) + { + pf = new scriptthinkfunc_t; + + m_ScriptThinkFuncs.SetGrowSize(1); + m_ScriptThinkFuncs.AddToTail( pf ); + + pf->m_bNoParam = s_bScriptContextThinkNoParam; + pf->m_iContextHash = hash; + } + // update existing + else + { +#ifdef _DEBUG + if ( pf->m_nNextThinkTick == 0 ) + { + Warning("Script think ('%s') was changed while it was thinking!\n", szContext); + } +#endif + g_pScriptVM->ReleaseScript( pf->m_hfnThink ); + } + + float nextthink = gpGlobals->curtime + flTime; + + pf->m_hfnThink = hFunc; + pf->m_nNextThinkTick = TIME_TO_TICKS( nextthink ); + +#ifdef GAME_DLL + int nexttick = GetNextThinkTick( RegisterThinkContext( "ScriptContextThink" ) ); +#else + int nexttick = GetNextThinkTick(); +#endif + + // sooner than next think + if ( nexttick <= 0 || nexttick > pf->m_nNextThinkTick ) + { +#ifdef GAME_DLL + SetContextThink( &CBaseEntity::ScriptContextThink, nextthink, "ScriptContextThink" ); +#else + SetNextClientThink( nextthink ); +#endif + } + } + // null func input, think exists + else if ( pf ) + { + pf->m_nNextThinkTick = TICK_NEVER_THINK; + } +} + +//----------------------------------------------------------------------------- +// m_bNoParam and s_bScriptContextThinkNoParam exist only to keep backwards compatibility +// and are an alternative to this script closure: +// +// function CBaseEntity::SetThink( func, time ) +// { +// SetContextThink( "", function(_){ return func() }, time ) +// } +//----------------------------------------------------------------------------- +#ifndef CLIENT_DLL +void CBaseEntity::ScriptSetThink( HSCRIPT hFunc, float time ) +{ + s_bScriptContextThinkNoParam = true; + ScriptSetContextThink( NULL, hFunc, time ); + s_bScriptContextThinkNoParam = false; +} + +void CBaseEntity::ScriptStopThink() +{ + ScriptSetContextThink( NULL, NULL, 0.0f ); +} +#endif #endif diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 9e8562f9..5aff896f 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -71,7 +71,7 @@ ConVar mapbase_load_actbusy("mapbase_load_actbusy", "1", FCVAR_ARCHIVE, "Should #ifdef GAME_DLL // This cvar should change with each Mapbase update -ConVar mapbase_version( "mapbase_version", "6.2", FCVAR_NONE, "The version of Mapbase currently being used in this mod." ); +ConVar mapbase_version( "mapbase_version", "6.3", FCVAR_NONE, "The version of Mapbase currently being used in this mod." ); extern void MapbaseGameLog_Init(); @@ -178,7 +178,7 @@ public: #ifdef GAME_DLL if (g_bMapContainsCustomTalker && mapbase_flush_talker.GetBool()) { - CGMsg( 1, "Mapbase Misc.", "Mapbase: Reloading response system to flush custom talker\n" ); + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Mapbase: Reloading response system to flush custom talker\n" ); ReloadResponseSystem(); g_bMapContainsCustomTalker = false; } @@ -188,7 +188,7 @@ public: virtual void LevelInitPreEntity() { #ifdef GAME_DLL - CGMsg( 0, "Mapbase Misc.", "Mapbase system loaded\n" ); + CGMsg( 0, CON_GROUP_MAPBASE_MISC, "Mapbase system loaded\n" ); #endif // Checks gameinfo.txt for Mapbase-specific options @@ -212,8 +212,11 @@ public: RefreshMapName(); - // Shared Mapbase localization file + // Shared Mapbase scripts to avoid overwriting mod files g_pVGuiLocalize->AddFile( "resource/mapbase_%language%.txt" ); +#ifdef CLIENT_DLL + PanelMetaClassMgr()->LoadMetaClassDefinitionFile( "scripts/vgui_screens_mapbase.txt" ); +#endif } virtual void OnRestore() @@ -352,11 +355,11 @@ public: return; } - CGMsg( 1, "Mapbase Misc.", "===== Mapbase Manifest: Loading manifest file %s =====\n", file ); + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "===== Mapbase Manifest: Loading manifest file %s =====\n", file ); AddManifestFile(pKV, false); - CGMsg( 1, "Mapbase Misc.", "==============================================================================\n" ); + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "==============================================================================\n" ); pKV->deleteThis(); } @@ -553,6 +556,11 @@ CUtlVector *Mapbase_GetChapterList() return &g_MapbaseChapterList; } +int Mapbase_GetChapterCount() +{ + return g_MapbaseChapterList.Count(); +} + ThreeState_t Flashlight_GetLegacyVersionKey() { KeyValues *gameinfo = new KeyValues( "GameInfo" ); @@ -591,7 +599,7 @@ public: const char *scriptfile = STRING(m_target); if ( filesystem->FileExists( scriptfile, "MOD" ) ) { - CGMsg(0, "Mapbase Misc.", "Mapbase: Adding manifest file \"%s\"\n", scriptfile); + CGMsg(0, CON_GROUP_MAPBASE_MISC, "Mapbase: Adding manifest file \"%s\"\n", scriptfile); g_MapbaseSystem.AddManifestFile(scriptfile); } else diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index b03ee0e8..5d4675c5 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -8,6 +8,7 @@ #include "cbase.h" #include "activitylist.h" #include "in_buttons.h" +#include "rope_shared.h" #ifdef CLIENT_DLL #include "c_ai_basenpc.h" #else @@ -66,7 +67,7 @@ BEGIN_SCRIPTENUM( RenderMode, "Render modes used by Get/SetRenderMode" ) DEFINE_ENUMCONST_NAMED( kRenderTransAdd, "Additive", "" ) DEFINE_ENUMCONST_NAMED( kRenderEnvironmental, "Environmental", "" ) DEFINE_ENUMCONST_NAMED( kRenderTransAddFrameBlend, "AdditiveFractionalFrame", "" ) - DEFINE_ENUMCONST_NAMED( kRenderTransAlphaAdd, "Alpha Add", "" ) + DEFINE_ENUMCONST_NAMED( kRenderTransAlphaAdd, "AlphaAdd", "" ) DEFINE_ENUMCONST_NAMED( kRenderWorldGlow, "WorldSpaceGlow", "" ) DEFINE_ENUMCONST_NAMED( kRenderNone, "None", "" ) @@ -310,6 +311,22 @@ void RegisterSharedScriptConstants() ScriptRegisterConstant( g_pScriptVM, MOVETYPE_OBSERVER, "Move type used in GetMoveType(), etc." ); ScriptRegisterConstant( g_pScriptVM, MOVETYPE_CUSTOM, "Move type used in GetMoveType(), etc." ); + // + // Ropes + // + ScriptRegisterConstant( g_pScriptVM, ROPE_RESIZE, "Try to keep the rope dangling the same amount even as the rope length changes. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_BARBED, "Hack option to draw like a barbed wire. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_COLLIDE, "Collide with the world. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_SIMULATE, "Is the rope valid? (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_BREAKABLE, "Can the endpoints detach? (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_USE_WIND, "Wind simulation on this rope. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_INITIAL_HANG, "By default, ropes will simulate for a bit internally when they are created so they sag, but dynamically created ropes for things like harpoons don't want this. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_PLAYER_WPN_ATTACH, "If this flag is set, then the second attachment must be a player. The rope will attach to \"buff_attach\" on the player's active weapon. This is a flag because it requires special code on the client to find the weapon. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_NO_GRAVITY, "Disable gravity on this rope. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_NUMFLAGS, "The number of rope flags recognized by the game." ); + + ScriptRegisterConstantNamed( g_pScriptVM, Vector( ROPE_GRAVITY ), "ROPE_GRAVITY", "Default rope gravity vector." ); + #ifdef GAME_DLL // // Sound Types, Contexts, and Channels @@ -483,7 +500,8 @@ void RegisterSharedScriptConstants() //ScriptRegisterConstant( g_pScriptVM, AISS_AUTO_PVS_AFTER_PVS, "" ); ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAGS_NONE, "No sleep flags. (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS, "Indicates a NPC will sleep upon exiting PVS. (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); - ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS_AFTER_PVS, "Indicates a NPC will sleep upon exiting PVS after entering PVS for the first time(?????) (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); + // note: the one "?" is escaped to prevent evaluation of a trigraph + ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS_AFTER_PVS, "Indicates a NPC will sleep upon exiting PVS after entering PVS for the first time(????\?) (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_PLAYING, "SCRIPT_PLAYING", "Playing the action animation." ); ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_WAIT, "SCRIPT_WAIT", "Waiting on everyone in the script to be ready. Plays the pre idle animation if there is one." ); diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index ae927a81..9fb186c2 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -22,10 +22,14 @@ #include "globalstate.h" #include "vscript_server.h" #include "soundent.h" -#endif // !CLIENT_DLL +#include "rope.h" +#else +#include "c_rope.h" +#endif // CLIENT_DLL #include "con_nprint.h" #include "particle_parse.h" +#include "npcevent.h" #include "vscript_funcs_shared.h" #include "vscript_singletons.h" @@ -164,18 +168,18 @@ HSCRIPT SpawnEntityFromTable( const char *pszClassname, HSCRIPT hKV ) HSCRIPT EntIndexToHScript( int index ) { #ifdef GAME_DLL - edict_t *e = INDEXENT(index); - if ( e && !e->IsFree() ) - { - return ToHScript( GetContainingEntity( e ) ); - } + edict_t *e = INDEXENT(index); + if ( e && !e->IsFree() ) + { + return ToHScript( GetContainingEntity( e ) ); + } #else // CLIENT_DLL - if ( index < NUM_ENT_ENTRIES ) - { - return ToHScript( CBaseEntity::Instance( index ) ); - } + if ( index < NUM_ENT_ENTRIES ) + { + return ToHScript( CBaseEntity::Instance( index ) ); + } #endif - return NULL; + return NULL; } //----------------------------------------------------------------------------- @@ -501,6 +505,61 @@ FireBulletsInfo_t *GetFireBulletsInfoFromInfo( HSCRIPT hBulletsInfo ) return HScriptToClass( hBulletsInfo ); } +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +CAnimEventTInstanceHelper g_AnimEventTInstanceHelper; + +BEGIN_SCRIPTDESC_ROOT( animevent_t, "Handle for accessing animevent_t info." ) + DEFINE_SCRIPT_INSTANCE_HELPER( &g_AnimEventTInstanceHelper ) +END_SCRIPTDESC(); + +bool CAnimEventTInstanceHelper::Get( void *p, const char *pszKey, ScriptVariant_t &variant ) +{ + animevent_t *ani = ((animevent_t *)p); + if (FStrEq( pszKey, "event" )) + variant = ani->event; + else if (FStrEq( pszKey, "options" )) + variant = ani->options; + else if (FStrEq( pszKey, "cycle" )) + variant = ani->cycle; + else if (FStrEq( pszKey, "eventtime" )) + variant = ani->eventtime; + else if (FStrEq( pszKey, "type" )) + variant = ani->type; + else if (FStrEq( pszKey, "source" )) + variant = ToHScript(ani->pSource); + else + return false; + + return true; +} + +bool CAnimEventTInstanceHelper::Set( void *p, const char *pszKey, ScriptVariant_t &variant ) +{ + animevent_t *ani = ((animevent_t *)p); + if (FStrEq( pszKey, "event" )) + ani->event = variant; + else if (FStrEq( pszKey, "options" )) + ani->options = variant; + else if (FStrEq( pszKey, "cycle" )) + ani->cycle = variant; + else if (FStrEq( pszKey, "eventtime" )) + ani->eventtime = variant; + else if (FStrEq( pszKey, "type" )) + ani->type = variant; + else if (FStrEq( pszKey, "source" )) + { + CBaseEntity *pEnt = ToEnt( variant.m_hScript ); + if (pEnt) + ani->pSource = pEnt->GetBaseAnimating(); + } + else + return false; + + return true; +} + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- @@ -682,6 +741,19 @@ static void ScriptDecalTrace( HSCRIPT hTrace, const char *decalName ) UTIL_DecalTrace( &traceInfo->GetTrace(), decalName ); } +static HSCRIPT ScriptCreateRope( HSCRIPT hStart, HSCRIPT hEnd, int iStartAttachment, int iEndAttachment, float ropeWidth, const char *pMaterialName, int numSegments, int ropeFlags ) +{ +#ifdef CLIENT_DLL + C_RopeKeyframe *pRope = C_RopeKeyframe::Create( ToEnt( hStart ), ToEnt( hEnd ), iStartAttachment, iEndAttachment, ropeWidth, pMaterialName, numSegments, ropeFlags ); +#else + CRopeKeyframe *pRope = CRopeKeyframe::Create( ToEnt( hStart ), ToEnt( hEnd ), iStartAttachment, iEndAttachment, ropeWidth, pMaterialName, numSegments ); + if (pRope) + pRope->m_RopeFlags |= ropeFlags; // HACKHACK +#endif + + return ToHScript( pRope ); +} + //----------------------------------------------------------------------------- // Simple particle effect dispatch //----------------------------------------------------------------------------- @@ -740,20 +812,29 @@ void NPrint( int pos, const char* fmt ) void NXPrint( int pos, int r, int g, int b, bool fixed, float ftime, const char* fmt ) { - static con_nprint_t *info = new con_nprint_t; + con_nprint_t info; - info->index = pos; - info->time_to_live = ftime; - info->color[0] = r / 255.f; - info->color[1] = g / 255.f; - info->color[2] = b / 255.f; - info->fixed_width_font = fixed; + info.index = pos; + info.time_to_live = ftime; + info.color[0] = r / 255.f; + info.color[1] = g / 255.f; + info.color[2] = b / 255.f; + info.fixed_width_font = fixed; - engine->Con_NXPrintf(info, fmt); - - // delete info; + engine->Con_NXPrintf( &info, fmt ); } +static float IntervalPerTick() +{ + return gpGlobals->interval_per_tick; +} + +static int GetFrameCount() +{ + return gpGlobals->framecount; +} + + //============================================================================= //============================================================================= @@ -837,6 +918,8 @@ void RegisterSharedScriptFunctions() ScriptRegisterFunctionNamed( g_pScriptVM, ScriptDecalTrace, "DecalTrace", "Creates a dynamic decal based on the given trace info. The trace information can be generated by TraceLineComplex() and the decal name must be from decals_subrect.txt." ); ScriptRegisterFunctionNamed( g_pScriptVM, ScriptDispatchParticleEffect, "DoDispatchParticleEffect", SCRIPT_ALIAS( "DispatchParticleEffect", "Dispatches a one-off particle system" ) ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCreateRope, "CreateRope", "Creates a single rope between two entities. Can optionally follow specific attachments." ); + 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." ); @@ -850,6 +933,9 @@ void RegisterSharedScriptFunctions() #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." ); + ScriptRegisterFunction( g_pScriptVM, IntervalPerTick, "Simulation tick interval" ); + ScriptRegisterFunction( g_pScriptVM, GetFrameCount, "Absolute frame counter" ); + //ScriptRegisterFunction( g_pScriptVM, GetTickCount, "Simulation ticks" ); RegisterScriptSingletons(); } diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.h b/sp/src/game/shared/mapbase/vscript_funcs_shared.h index ad3192bf..0a38e5a1 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.h +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.h @@ -121,4 +121,13 @@ private: HSCRIPT m_planeAccessor; }; +//----------------------------------------------------------------------------- +// Exposes animevent_t to VScript +//----------------------------------------------------------------------------- +class CAnimEventTInstanceHelper : public IScriptInstanceHelper +{ + bool Get( void *p, const char *pszKey, ScriptVariant_t &variant ); + bool Set( void *p, const char *pszKey, ScriptVariant_t &variant ); +}; + #endif diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index e001513e..47e26bb0 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -23,6 +23,15 @@ #include "igameevents.h" #include "engine/ivdebugoverlay.h" +#ifdef CLIENT_DLL +#include "IEffects.h" +#include "fx.h" +#include "itempents.h" +#include "c_te_legacytempents.h" +#include "iefx.h" +#include "dlight.h" +#endif + #include "vscript_singletons.h" // memdbgon must be the last include file in a .cpp file!!! @@ -355,20 +364,25 @@ END_SCRIPTDESC(); // Game Event Listener // Based on Source 2 API //============================================================================= + +// Define to use the older code that loads all events manually independent from the game event manager. +// Otherwise access event descriptors directly from engine. +//#define USE_OLD_EVENT_DESCRIPTORS 1 + class CScriptGameEventListener : public IGameEventListener2, public CAutoGameSystem { public: - CScriptGameEventListener() : m_bActive(false) {} + CScriptGameEventListener() : m_bActive(false) /*, m_nEventTick(0)*/ {} ~CScriptGameEventListener() { StopListeningForEvent(); } - intptr_t ListenToGameEvent( const char* szEvent, HSCRIPT hFunc, const char* szContext ); + int ListenToGameEvent( const char* szEvent, HSCRIPT hFunc, const char* szContext ); void StopListeningForEvent(); public: - static bool StopListeningToGameEvent( intptr_t listener ); + static bool StopListeningToGameEvent( int listener ); static void StopListeningToAllGameEvents( const char* szContext ); public: @@ -376,89 +390,78 @@ public: void LevelShutdownPreEntity(); private: - bool m_bActive; - unsigned int m_iContextHash; + //int m_index; HSCRIPT m_hCallback; + unsigned int m_iContextHash; + bool m_bActive; + //int m_nEventTick; static StringHashFunctor Hash; static inline unsigned int HashContext( const char* c ) { return (c && *c) ? Hash(c) : 0; } + inline int GetIndex() + { + Assert( sizeof(CScriptGameEventListener*) == sizeof(int) ); + return reinterpret_cast(this); + } + public: - static void DumpEventListeners(); -#ifndef CLIENT_DLL + enum // event data types, dependant on engine definitions + { + TYPE_LOCAL = 0, + TYPE_STRING = 1, + TYPE_FLOAT = 2, + TYPE_LONG = 3, + TYPE_SHORT = 4, + TYPE_BYTE = 5, + TYPE_BOOL = 6 + }; + static void WriteEventData( IGameEvent *event, HSCRIPT hTable ); + +#ifdef USE_OLD_EVENT_DESCRIPTORS static void LoadAllEvents(); static void LoadEventsFromFile( const char *filename, const char *pathID = NULL ); - static void WriteEventData( IGameEvent *event, HSCRIPT hTable ); -#endif // !CLIENT_DLL + static CUtlMap< unsigned int, KeyValues* > s_GameEvents; + static CUtlVector< KeyValues* > s_LoadedFiles; +#endif public: -#ifndef CLIENT_DLL - static CUtlMap< unsigned int, KeyValues* > s_GameEvents; + //static int g_nIndexCounter; + static CUtlVectorAutoPurge< CScriptGameEventListener* > s_Listeners; +#if _DEBUG + static void DumpEventListeners(); #endif - static CUtlVectorAutoPurge< CScriptGameEventListener* > s_GameEventListeners; - static CUtlVector< KeyValues* > s_LoadedFiles; + }; -#ifndef CLIENT_DLL -CUtlMap< unsigned int, KeyValues* > CScriptGameEventListener::s_GameEvents( DefLessFunc(unsigned int) ); -#endif -CUtlVectorAutoPurge< CScriptGameEventListener* > CScriptGameEventListener::s_GameEventListeners; -CUtlVector< KeyValues* > CScriptGameEventListener::s_LoadedFiles; +CUtlVectorAutoPurge< CScriptGameEventListener* > CScriptGameEventListener::s_Listeners; StringHashFunctor CScriptGameEventListener::Hash; +#ifdef USE_OLD_EVENT_DESCRIPTORS +CUtlMap< unsigned int, KeyValues* > CScriptGameEventListener::s_GameEvents( DefLessFunc(unsigned int) ); +CUtlVector< KeyValues* > CScriptGameEventListener::s_LoadedFiles; +#endif + + #if _DEBUG #ifdef CLIENT_DLL CON_COMMAND_F( cl_dump_script_game_event_listeners, "Dump all game event listeners created from script.", FCVAR_CHEAT ) { CScriptGameEventListener::DumpEventListeners(); } -#else // GAME_DLL +#else CON_COMMAND_F( dump_script_game_event_listeners, "Dump all game event listeners created from script.", FCVAR_CHEAT ) { CScriptGameEventListener::DumpEventListeners(); } -#endif // CLIENT_DLL +#endif #endif -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CScriptGameEventListener::DumpEventListeners() -{ - CGMsg( 0, CON_GROUP_VSCRIPT, "--- Script game event listener dump start\n" ); - FOR_EACH_VEC( s_GameEventListeners, i ) - { - CGMsg( 0, CON_GROUP_VSCRIPT, " %d (0x%p) %d : %d\n", i,s_GameEventListeners[i], - s_GameEventListeners[i], - s_GameEventListeners[i]->m_iContextHash ); - } - CGMsg( 0, CON_GROUP_VSCRIPT, "--- Script game event listener dump end\n" ); -} - -void CScriptGameEventListener::FireGameEvent( IGameEvent *event ) -{ - ScriptVariant_t hTable; - g_pScriptVM->CreateTable( hTable ); - // TODO: pass event data on client -#ifdef GAME_DLL - WriteEventData( event, hTable ); -#endif - g_pScriptVM->SetValue( hTable, "game_event_listener", reinterpret_cast(this) ); // POINTER_TO_INT - // g_pScriptVM->SetValue( hTable, "game_event_name", event->GetName() ); - g_pScriptVM->ExecuteFunction( m_hCallback, &hTable, 1, NULL, NULL, true ); - g_pScriptVM->ReleaseScript( hTable ); -} - -void CScriptGameEventListener::LevelShutdownPreEntity() -{ - s_GameEventListeners.FindAndFastRemove(this); - delete this; -} +#ifdef USE_OLD_EVENT_DESCRIPTORS //----------------------------------------------------------------------------- // Executed in LevelInitPreEntity //----------------------------------------------------------------------------- -#ifndef CLIENT_DLL void CScriptGameEventListener::LoadAllEvents() { // Listed in the same order they are loaded in GameEventManager @@ -506,8 +509,8 @@ void CScriptGameEventListener::LoadEventsFromFile( const char *filename, const c return; } - // Set the key value types to what they are from their string description values to read the correct data type in WriteEventData. - // There might be a better way of doing this, but this is okay since it's only done on file load. + int count = 0; + for ( KeyValues *key = pKV->GetFirstSubKey(); key; key = key->GetNextKey() ) { for ( KeyValues *sub = key->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) @@ -515,13 +518,29 @@ void CScriptGameEventListener::LoadEventsFromFile( const char *filename, const c if ( sub->GetDataType() == KeyValues::TYPE_STRING ) { const char *szVal = sub->GetString(); - if ( !V_stricmp( szVal, "byte" ) || !V_stricmp( szVal, "short" ) || !V_stricmp( szVal, "long" ) || !V_stricmp( szVal, "bool" ) ) + if ( !V_stricmp( szVal, "string" ) ) { - sub->SetInt( NULL, 0 ); + sub->SetInt( NULL, TYPE_STRING ); + } + else if ( !V_stricmp( szVal, "bool" ) ) + { + sub->SetInt( NULL, TYPE_BOOL ); + } + else if ( !V_stricmp( szVal, "byte" ) ) + { + sub->SetInt( NULL, TYPE_BYTE ); + } + else if ( !V_stricmp( szVal, "short" ) ) + { + sub->SetInt( NULL, TYPE_SHORT ); + } + else if ( !V_stricmp( szVal, "long" ) ) + { + sub->SetInt( NULL, TYPE_LONG ); } else if ( !V_stricmp( szVal, "float" ) ) { - sub->SetFloat( NULL, 0.0f ); + sub->SetInt( NULL, TYPE_FLOAT ); } } // none : value is not networked @@ -537,42 +556,125 @@ void CScriptGameEventListener::LoadEventsFromFile( const char *filename, const c // Replace key so modevents can overwrite gameevents. // It does not check for hash collisions, however. s_GameEvents.InsertOrReplace( Hash( key->GetName() ), key ); + ++count; } // Store files (allocated KV) s_LoadedFiles.AddToTail( pKV ); - CGMsg( 2, CON_GROUP_VSCRIPT, "CScriptGameEventListener::LoadEventsFromFile: Loaded [%s]%s\n", pathID, filename ); + CGMsg( 2, CON_GROUP_VSCRIPT, "CScriptGameEventListener::LoadEventsFromFile: Loaded [%s]%s (%i)\n", pathID, filename, count ); } +#endif + +#if _DEBUG +void CScriptGameEventListener::DumpEventListeners() +{ + CGMsg( 0, CON_GROUP_VSCRIPT, "--- Script game event listener dump start\n" ); + CGMsg( 0, CON_GROUP_VSCRIPT, "# ADDRESS ID CONTEXT\n" ); + FOR_EACH_VEC( s_Listeners, i ) + { + CGMsg( 0, CON_GROUP_VSCRIPT, " %d (0x%p) %d : %u\n", i, + (void*)s_Listeners[i], + s_Listeners[i]->GetIndex(), + s_Listeners[i]->m_iContextHash ); + } + CGMsg( 0, CON_GROUP_VSCRIPT, "--- Script game event listener dump end\n" ); +} +#endif + +void CScriptGameEventListener::LevelShutdownPreEntity() +{ + s_Listeners.FindAndFastRemove(this); + delete this; +} + +void CScriptGameEventListener::FireGameEvent( IGameEvent *event ) +{ + //m_nEventTick = gpGlobals->tickcount; + ScriptVariant_t hTable; + g_pScriptVM->CreateTable( hTable ); + WriteEventData( event, hTable ); + g_pScriptVM->SetValue( hTable, "game_event_listener", GetIndex() ); + // g_pScriptVM->SetValue( hTable, "game_event_name", event->GetName() ); + g_pScriptVM->ExecuteFunction( m_hCallback, &hTable, 1, NULL, NULL, true ); + g_pScriptVM->ReleaseScript( hTable ); +} + +struct CGameEventDescriptor +{ + byte _0[36]; + KeyValues *m_pEventKeys; + //byte _1[22]; +}; + +class CGameEvent__// : public IGameEvent +{ +public: + virtual ~CGameEvent__(); // [0] + CGameEventDescriptor *m_pDescriptor; // 0x04 + //KeyValues *m_pEventData; // 0x08 +}; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CScriptGameEventListener::WriteEventData( IGameEvent *event, HSCRIPT hTable ) { +#ifdef USE_OLD_EVENT_DESCRIPTORS int i = s_GameEvents.Find( Hash( event->GetName() ) ); - if ( i != s_GameEvents.InvalidIndex() ) + if ( i == s_GameEvents.InvalidIndex() ) + return; + KeyValues *pKV = s_GameEvents[i]; +#endif + +#if defined(_DEBUG) && !defined(USE_OLD_EVENT_DESCRIPTORS) + try { - KeyValues *pKV = s_GameEvents[i]; - for ( KeyValues *sub = pKV->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) +#endif + +#if !defined(USE_OLD_EVENT_DESCRIPTORS) + KeyValues *pKV = reinterpret_cast< CGameEvent__* >(event)->m_pDescriptor->m_pEventKeys; +#endif + + for ( KeyValues *sub = pKV->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) + { + const char *szKey = sub->GetName(); + switch ( sub->GetInt() ) { - const char *szKey = sub->GetName(); - switch ( sub->GetDataType() ) - { - case KeyValues::TYPE_STRING: g_pScriptVM->SetValue( hTable, szKey, event->GetString( szKey ) ); break; - case KeyValues::TYPE_INT: g_pScriptVM->SetValue( hTable, szKey, event->GetInt ( szKey ) ); break; - case KeyValues::TYPE_FLOAT: g_pScriptVM->SetValue( hTable, szKey, event->GetFloat ( szKey ) ); break; - // default: DevWarning( 2, "CScriptGameEventListener::WriteEventData: unknown data type '%d' on key '%s' in event '%s'\n", sub->GetDataType(), szKey, szEvent ); - } + case TYPE_LOCAL: + case TYPE_STRING: g_pScriptVM->SetValue( hTable, szKey, event->GetString( szKey ) ); break; + case TYPE_FLOAT: g_pScriptVM->SetValue( hTable, szKey, event->GetFloat ( szKey ) ); break; + case TYPE_BOOL: g_pScriptVM->SetValue( hTable, szKey, event->GetBool ( szKey ) ); break; + default: g_pScriptVM->SetValue( hTable, szKey, event->GetInt ( szKey ) ); } } + +#if defined(_DEBUG) && !defined(USE_OLD_EVENT_DESCRIPTORS) + // Access a bunch of KeyValues functions to validate it is the correct address. + // This may not always throw an exception when it is incorrect, but eventually it will. + } + catch (...) + { + // CGameEvent or CGameEventDescriptor offsets did not match! + // This should mean these were modified in engine.dll. + // + // Implement this utility yourself by adding a function to get event descriptor keys + // either on CGameEventManager or on CGameEvent interfaces. + // On CGameEventManager downcast IGameEvent input to CGameEvent, then return event->descriptor->keys + // On CGameEvent return (member) descriptor->keys + // + // Finally assign it to pKV above. + + Warning("CScriptGameEventListener::WriteEventData internal error\n"); + Assert(0); + } +#endif } -#endif // !CLIENT_DLL //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -intptr_t CScriptGameEventListener::ListenToGameEvent( const char* szEvent, HSCRIPT hFunc, const char* szContext ) +int CScriptGameEventListener::ListenToGameEvent( const char* szEvent, HSCRIPT hFunc, const char* szContext ) { bool bValid; @@ -590,14 +692,14 @@ intptr_t CScriptGameEventListener::ListenToGameEvent( const char* szEvent, HSCRI m_hCallback = hFunc; m_bActive = true; - s_GameEventListeners.AddToTail( this ); + s_Listeners.AddToTail( this ); - return reinterpret_cast( this ); // POINTER_TO_INT + return GetIndex(); } else { delete this; - return 0x0; + return 0; } } @@ -610,29 +712,31 @@ void CScriptGameEventListener::StopListeningForEvent() return; if ( g_pScriptVM ) - { g_pScriptVM->ReleaseScript( m_hCallback ); - } - else - { - // AssertMsg( !m_hCallback, "LEAK (0x%p)\n", (void*)m_hCallback ); - } m_hCallback = NULL; m_bActive = false; if ( gameeventmanager ) gameeventmanager->RemoveListener( this ); + + // Event listeners are iterated forwards in the game event manager, + // removing while iterating will cause it to skip one listener. + // This could be prevented by writing a custom game event manager. + //if ( m_nEventTick == gpGlobals->tickcount ) + //{ + // Warning("CScriptGameEventListener stopped in the same frame it was fired. This will break other event listeners!\n"); + //} } //----------------------------------------------------------------------------- // Stop the specified event listener. //----------------------------------------------------------------------------- -bool CScriptGameEventListener::StopListeningToGameEvent( intptr_t listener ) +bool CScriptGameEventListener::StopListeningToGameEvent( int listener ) { CScriptGameEventListener *p = reinterpret_cast(listener); // INT_TO_POINTER - bool bRemoved = s_GameEventListeners.FindAndFastRemove(p); + bool bRemoved = s_Listeners.FindAndFastRemove(p); if ( bRemoved ) { delete p; @@ -649,12 +753,12 @@ void CScriptGameEventListener::StopListeningToAllGameEvents( const char* szConte unsigned int hash = HashContext( szContext ); // Iterate from the end so they can be safely removed as they are deleted - for ( int i = s_GameEventListeners.Count(); i--; ) + for ( int i = s_Listeners.Count(); i--; ) { - CScriptGameEventListener *pCur = s_GameEventListeners[i]; + CScriptGameEventListener *pCur = s_Listeners[i]; if ( pCur->m_iContextHash == hash ) { - s_GameEventListeners.Remove(i); // keep list order + s_Listeners.Remove(i); // keep list order delete pCur; } } @@ -805,11 +909,13 @@ StringHashFunctor CScriptSaveRestoreUtil::Hash; void CScriptSaveRestoreUtil::SaveTable( const char *szId, HSCRIPT hTable ) { KeyValues *pKV; - int idx = m_Lookup.Find( Hash(szId) ); + unsigned int hash = Hash(szId); + + int idx = m_Lookup.Find( hash ); if ( idx == m_Lookup.InvalidIndex() ) { pKV = new KeyValues("ScriptSavedTable"); - m_Lookup.Insert( Hash(szId), pKV ); + m_Lookup.Insert( hash, pKV ); } else { @@ -879,7 +985,7 @@ void CScriptSaveRestoreUtil::ClearSavedTable( const char *szId ) // Read/Write to File // Based on L4D2/Source 2 API //============================================================================= -#define SCRIPT_MAX_FILE_READ_SIZE (16 * 1024) // 16KB +#define SCRIPT_MAX_FILE_READ_SIZE (64 * 1024 * 1024) // 64MB #define SCRIPT_MAX_FILE_WRITE_SIZE (64 * 1024 * 1024) // 64MB #define SCRIPT_RW_PATH_ID "MOD" #define SCRIPT_RW_FULL_PATH_FMT "vscript_io/%s" @@ -906,11 +1012,11 @@ public: } private: - static const char *m_pszReturnReadFile; + static char *m_pszReturnReadFile; } g_ScriptReadWrite; -const char *CScriptReadWriteFile::m_pszReturnReadFile = NULL; +char *CScriptReadWriteFile::m_pszReturnReadFile = NULL; //----------------------------------------------------------------------------- // @@ -968,19 +1074,32 @@ const char *CScriptReadWriteFile::FileRead( const char *szFile ) return NULL; } - CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); - if ( !g_pFullFileSystem->ReadFile( pszFullName, SCRIPT_RW_PATH_ID, buf, SCRIPT_MAX_FILE_READ_SIZE ) ) + FileHandle_t file = g_pFullFileSystem->Open( pszFullName, "rb", SCRIPT_RW_PATH_ID ); + if ( !file ) { return NULL; } - // first time calling, allocate - if ( !m_pszReturnReadFile ) - m_pszReturnReadFile = new char[SCRIPT_MAX_FILE_READ_SIZE]; + // Close the previous buffer + if (m_pszReturnReadFile) + g_pFullFileSystem->FreeOptimalReadBuffer( m_pszReturnReadFile ); - V_strncpy( const_cast(m_pszReturnReadFile), (const char*)buf.Base(), buf.Size() ); - buf.Purge(); - return m_pszReturnReadFile; + unsigned bufSize = g_pFullFileSystem->GetOptimalReadSize( file, size + 2 ); + m_pszReturnReadFile = (char*)g_pFullFileSystem->AllocOptimalReadBuffer( file, bufSize ); + + bool bRetOK = ( g_pFullFileSystem->ReadEx( m_pszReturnReadFile, bufSize, size, file ) != 0 ); + g_pFullFileSystem->Close( file ); // close file after reading + + if ( bRetOK ) + { + m_pszReturnReadFile[size] = 0; // null terminate file as EOF + //buffer[size+1] = 0; // double NULL terminating in case this is a unicode file + return m_pszReturnReadFile; + } + else + { + return NULL; + } } //----------------------------------------------------------------------------- @@ -1095,8 +1214,10 @@ HSCRIPT CScriptReadWriteFile::KeyValuesRead( const char *szFile ) #ifdef GAME_DLL #define m_MsgIn_() m_MsgIn-> +#define DLL_LOC_STR "[Server]" #else #define m_MsgIn_() m_MsgIn. +#define DLL_LOC_STR "[Client]" #endif @@ -1120,7 +1241,7 @@ void CNetMsgScriptHelper::Reset() } //----------------------------------------------------------------------------- -// Create the storage for the reciever callback functions. +// Create the storage for the receiver callback functions. // Functions are handled in the VM, the storage table is here. //----------------------------------------------------------------------------- void CNetMsgScriptHelper::InitPostVM() @@ -1156,7 +1277,7 @@ bool CNetMsgScriptHelper::Init() // IGameSystem //----------------------------------------------------------------------------- void CNetMsgScriptHelper::__MsgFunc_ScriptMsg( bf_read &msg ) { - g_ScriptNetMsg->RecieveMessage( msg ); + g_ScriptNetMsg->ReceiveMessage( msg ); } #endif // CLIENT_DLL @@ -1165,11 +1286,11 @@ void CNetMsgScriptHelper::__MsgFunc_ScriptMsg( bf_read &msg ) // //----------------------------------------------------------------------------- #ifdef GAME_DLL -void CNetMsgScriptHelper::RecieveMessage( bf_read *msg, CBaseEntity *pPlayer ) +void CNetMsgScriptHelper::ReceiveMessage( bf_read *msg, CBaseEntity *pPlayer ) { m_MsgIn = msg; #else -void CNetMsgScriptHelper::RecieveMessage( bf_read &msg ) +void CNetMsgScriptHelper::ReceiveMessage( bf_read &msg ) { m_MsgIn.StartReading( msg.m_pData, msg.m_nDataBytes ); #endif @@ -1179,7 +1300,7 @@ void CNetMsgScriptHelper::RecieveMessage( bf_read &msg ) // Don't do anything if there's no VM here. This can happen if a message from the server goes to a VM-less client, or vice versa. if ( !g_pScriptVM ) { - CGWarning( 0, CON_GROUP_VSCRIPT, "CNetMsgScriptHelper: No VM on receiving side\n" ); + CGWarning( 0, CON_GROUP_VSCRIPT, DLL_LOC_STR " CNetMsgScriptHelper: No VM on receiving side\n" ); return; } @@ -1192,13 +1313,13 @@ void CNetMsgScriptHelper::RecieveMessage( bf_read &msg ) if ( g_pScriptVM->ExecuteFunction( hfn, NULL, 0, NULL, NULL, true ) == SCRIPT_ERROR ) #endif { - DevWarning( 3, "NetMsg: invalid callback for '%d'\n", hash ); + DevWarning( 2, DLL_LOC_STR " NetMsg: invalid callback [%d]\n", hash ); } g_pScriptVM->ReleaseValue( hfn ); } else { - DevWarning( 3, "NetMsg hook not found for '%d'\n", hash ); + DevWarning( 2, DLL_LOC_STR " NetMsg hook not found [%d]\n", hash ); } } @@ -1230,6 +1351,8 @@ void CNetMsgScriptHelper::Send( HSCRIPT player, bool bReliable ) m_filter.MakeReliable(); } + Assert( usermessages->LookupUserMessage( "ScriptMsg" ) != -1 ); + DoSendUserMsg( &m_filter, usermessages->LookupUserMessage( "ScriptMsg" ) ); } #else // CLIENT_DLL @@ -1247,7 +1370,7 @@ void CNetMsgScriptHelper::Send() //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -void CNetMsgScriptHelper::Recieve( const char *msg, HSCRIPT func ) +void CNetMsgScriptHelper::Receive( const char *msg, HSCRIPT func ) { if ( func ) g_pScriptVM->SetValue( m_Hooks, int( HashStringCaseless(msg) ), func ); @@ -1428,9 +1551,7 @@ void CNetMsgScriptHelper::WriteBool( bool bValue ) void CNetMsgScriptHelper::WriteEntity( HSCRIPT hEnt ) { CBaseEntity *p = ToEnt(hEnt); - int i; - if (p) i = p->entindex(); - else i = -1; + int i = p ? p->entindex() : -1; m_MsgOut.WriteSBitLong( i, MAX_EDICT_BITS ); } @@ -1583,6 +1704,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "N DEFINE_SCRIPTFUNC( SendUserMessage, "Send a usermessage from the server to the client" ) DEFINE_SCRIPTFUNC( SendEntityMessage, "Send a message from a server side entity to its client side counterpart" ) DEFINE_SCRIPTFUNC( AddRecipient, "" ) + //DEFINE_SCRIPTFUNC( RemoveRecipient, "" ) DEFINE_SCRIPTFUNC( AddRecipientsByPVS, "" ) DEFINE_SCRIPTFUNC( AddRecipientsByPAS, "" ) DEFINE_SCRIPTFUNC( AddAllPlayers, "" ) @@ -1592,28 +1714,29 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "N DEFINE_SCRIPTFUNC( Reset, "Reset the current network message buffer" ) DEFINE_SCRIPTFUNC( Start, "Start writing new custom network message" ) - DEFINE_SCRIPTFUNC( Recieve, "Set custom network message callback" ) + DEFINE_SCRIPTFUNC( Receive, "Set custom network message callback" ) + DEFINE_SCRIPTFUNC_NAMED( Receive, "Recieve", SCRIPT_HIDE ) // This was a typo until v6.3 #ifdef GAME_DLL DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the server to the client (max 252 bytes)" ) #else DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the client to the server (max 2045 bytes)" ) #endif - DEFINE_SCRIPTFUNC( WriteInt, "" ) - DEFINE_SCRIPTFUNC( WriteUInt, "" ) + DEFINE_SCRIPTFUNC( WriteInt, "variable bit signed int" ) + DEFINE_SCRIPTFUNC( WriteUInt, "variable bit unsigned int" ) DEFINE_SCRIPTFUNC( WriteByte, "8 bit unsigned char" ) DEFINE_SCRIPTFUNC( WriteChar, "8 bit char" ) DEFINE_SCRIPTFUNC( WriteShort, "16 bit short" ) DEFINE_SCRIPTFUNC( WriteWord, "16 bit unsigned short" ) DEFINE_SCRIPTFUNC( WriteLong, "32 bit long" ) - DEFINE_SCRIPTFUNC( WriteFloat, "" ) + DEFINE_SCRIPTFUNC( WriteFloat, "32 bit float" ) DEFINE_SCRIPTFUNC( WriteNormal, "12 bit" ) DEFINE_SCRIPTFUNC( WriteAngle, "8 bit unsigned char" ) DEFINE_SCRIPTFUNC( WriteCoord, "" ) DEFINE_SCRIPTFUNC( WriteVec3Coord, "" ) DEFINE_SCRIPTFUNC( WriteVec3Normal, "27 bit" ) DEFINE_SCRIPTFUNC( WriteAngles, "" ) - DEFINE_SCRIPTFUNC( WriteString, "max 512 bytes at once" ) + DEFINE_SCRIPTFUNC( WriteString, "" ) DEFINE_SCRIPTFUNC( WriteBool, "1 bit" ) DEFINE_SCRIPTFUNC( WriteEntity, "11 bit (entindex)" ) DEFINE_SCRIPTFUNC( WriteEHandle, "32 bit long" ) @@ -1632,7 +1755,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "N DEFINE_SCRIPTFUNC( ReadVec3Coord, "" ) DEFINE_SCRIPTFUNC( ReadVec3Normal, "" ) DEFINE_SCRIPTFUNC( ReadAngles, "" ) - DEFINE_SCRIPTFUNC( ReadString, "" ) + DEFINE_SCRIPTFUNC( ReadString, "max 512 bytes at once" ) DEFINE_SCRIPTFUNC( ReadBool, "" ) DEFINE_SCRIPTFUNC( ReadEntity, "" ) DEFINE_SCRIPTFUNC( ReadEHandle, "" ) @@ -1645,10 +1768,7 @@ END_SCRIPTDESC(); #define RETURN_IF_CANNOT_DRAW_OVERLAY\ if (engine->IsPaused())\ - {\ - CGWarning( 1, CON_GROUP_VSCRIPT, "debugoverlay: cannot draw while the game is paused!\n");\ - return;\ - } + return; class CDebugOverlayScriptHelper { public: @@ -2054,6 +2174,651 @@ END_SCRIPTDESC(); +//============================================================================= +// ConVars +//============================================================================= +class CScriptConCommand : public ICommandCallback, public ICommandCompletionCallback +{ +public: + ~CScriptConCommand() + { + Unregister(); + delete m_cmd; + } + + CScriptConCommand( const char *name, HSCRIPT fn, const char *helpString, int flags ) + { + m_cmd = new ConCommand( name, this, helpString, flags, 0 ); + m_hCallback = fn; + m_hCompletionCallback = NULL; + m_nCmdNameLen = V_strlen(name) + 1; + + Assert( m_nCmdNameLen - 1 <= 128 ); + } + + void CommandCallback( const CCommand &command ) + { + int count = command.ArgC(); + ScriptVariant_t *vArgv = (ScriptVariant_t*)stackalloc( sizeof(ScriptVariant_t) * count ); + for ( int i = 0; i < count; ++i ) + { + vArgv[i] = command[i]; + } + if ( g_pScriptVM->ExecuteFunction( m_hCallback, vArgv, count, NULL, NULL, true ) == SCRIPT_ERROR ) + { + DevWarning( 1, "CScriptConCommand: invalid callback for '%s'\n", command[0] ); + } + } + + int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands ) + { + Assert( g_pScriptVM ); + Assert( m_hCompletionCallback ); + + ScriptVariant_t hArray; + g_pScriptVM->CreateArray( hArray ); + + // split command name from partial, pass both separately to the script function + char *cmdname = (char*)stackalloc( m_nCmdNameLen ); + V_memcpy( cmdname, partial, m_nCmdNameLen - 1 ); + cmdname[ m_nCmdNameLen - 1 ] = 0; + + char argPartial[256]; + V_StrRight( partial, V_strlen(partial) - m_nCmdNameLen, argPartial, sizeof(argPartial) ); + + ScriptVariant_t args[3] = { cmdname, argPartial, hArray }; + if ( g_pScriptVM->ExecuteFunction( m_hCompletionCallback, args, 3, NULL, NULL, true ) == SCRIPT_ERROR ) + { + DevWarning( 1, "CScriptConCommand: invalid command completion callback for '%s'\n", cmdname ); + g_pScriptVM->ReleaseScript( hArray ); + return 0; + } + + int count = 0; + ScriptVariant_t val; + int it = -1; + while ( ( it = g_pScriptVM->GetKeyValue( hArray, it, NULL, &val ) ) != -1 ) + { + if ( val.m_type == FIELD_CSTRING ) + { + CUtlString s = val.m_pszString; + //s.SetLength( COMMAND_COMPLETION_ITEM_LENGTH - 1 ); + commands.AddToTail( s ); + ++count; + } + g_pScriptVM->ReleaseValue(val); + + if ( count == COMMAND_COMPLETION_MAXITEMS ) + break; + } + g_pScriptVM->ReleaseScript( hArray ); + return count; + } + + void SetCompletionCallback( HSCRIPT fn ) + { + if ( m_hCompletionCallback ) + g_pScriptVM->ReleaseScript( m_hCompletionCallback ); + + if (fn) + { + if ( !m_cmd->IsRegistered() ) + return; + + m_cmd->m_pCommandCompletionCallback = this; + m_cmd->m_bHasCompletionCallback = true; + m_hCompletionCallback = fn; + } + else + { + m_cmd->m_pCommandCompletionCallback = NULL; + m_cmd->m_bHasCompletionCallback = false; + m_hCompletionCallback = NULL; + } + } + + void SetCallback( HSCRIPT fn ) + { + if (fn) + { + if ( !m_cmd->IsRegistered() ) + Register(); + + if ( m_hCallback ) + g_pScriptVM->ReleaseScript( m_hCallback ); + m_hCallback = fn; + } + else + { + Unregister(); + } + } + + inline void Unregister() + { + if ( g_pCVar && m_cmd->IsRegistered() ) + g_pCVar->UnregisterConCommand( m_cmd ); + + if ( g_pScriptVM ) + { + if ( m_hCallback ) + { + g_pScriptVM->ReleaseScript( m_hCallback ); + m_hCallback = NULL; + } + + SetCompletionCallback( NULL ); + } + } + + inline void Register() + { + if ( g_pCVar ) + g_pCVar->RegisterConCommand( m_cmd ); + } + + HSCRIPT m_hCallback; + HSCRIPT m_hCompletionCallback; + int m_nCmdNameLen; + ConCommand *m_cmd; +}; + +class CScriptConVar +{ +public: + ~CScriptConVar() + { + Unregister(); + delete m_cvar; + } + + CScriptConVar( const char *pName, const char *pDefaultValue, const char *pHelpString, int flags/*, float fMin, float fMax*/ ) + { + m_cvar = new ConVar( pName, pDefaultValue, flags, pHelpString ); + } + + inline void Unregister() + { + if ( g_pCVar && m_cvar->IsRegistered() ) + g_pCVar->UnregisterConCommand( m_cvar ); + } + + ConVar *m_cvar; +}; + +class CScriptConvarAccessor : public CAutoGameSystem +{ +public: + static CUtlMap< unsigned int, bool > g_ConVarsBlocked; + static CUtlMap< unsigned int, bool > g_ConCommandsOverridable; + static CUtlMap< unsigned int, CScriptConCommand* > g_ScriptConCommands; + static CUtlMap< unsigned int, CScriptConVar* > g_ScriptConVars; + static inline unsigned int Hash( const char*sz ){ return HashStringCaseless(sz); } + +public: + inline void AddOverridable( const char *name ) + { + g_ConCommandsOverridable.InsertOrReplace( Hash(name), true ); + } + + inline bool IsOverridable( unsigned int hash ) + { + int idx = g_ConCommandsOverridable.Find( hash ); + if ( idx == g_ConCommandsOverridable.InvalidIndex() ) + return false; + return g_ConCommandsOverridable[idx]; + } + + inline void AddBlockedConVar( const char *name ) + { + g_ConVarsBlocked.InsertOrReplace( Hash(name), true ); + } + + inline bool IsBlockedConvar( const char *name ) + { + int idx = g_ConVarsBlocked.Find( Hash(name) ); + if ( idx == g_ConVarsBlocked.InvalidIndex() ) + return false; + return g_ConVarsBlocked[idx]; + } + +public: + void RegisterCommand( const char *name, HSCRIPT fn, const char *helpString, int flags ); + void SetCompletionCallback( const char *name, HSCRIPT fn ); + void UnregisterCommand( const char *name ); + void RegisterConvar( const char *name, const char *pDefaultValue, const char *helpString, int flags ); + + HSCRIPT GetCommandClient() + { +#ifdef GAME_DLL + return ToHScript( UTIL_GetCommandClient() ); +#else + return ToHScript( C_BasePlayer::GetLocalPlayer() ); +#endif + } +#ifdef GAME_DLL + const char *GetClientConvarValue( int index, const char* cvar ) + { + return engine->GetClientConVarValue( index, cvar ); + } +#endif +public: + bool Init(); + + void LevelShutdownPostEntity() + { + g_ScriptConCommands.PurgeAndDeleteElements(); + g_ScriptConVars.PurgeAndDeleteElements(); + } + +public: + float GetFloat( const char *pszConVar ) + { + ConVarRef cvar( pszConVar ); + if ( cvar.IsFlagSet( FCVAR_SERVER_CANNOT_QUERY ) ) + return NULL; + return cvar.GetFloat(); + } + + int GetInt( const char *pszConVar ) + { + ConVarRef cvar( pszConVar ); + if ( cvar.IsFlagSet( FCVAR_SERVER_CANNOT_QUERY ) ) + return NULL; + return cvar.GetInt(); + } + + bool GetBool( const char *pszConVar ) + { + ConVarRef cvar( pszConVar ); + if ( cvar.IsFlagSet( FCVAR_SERVER_CANNOT_QUERY ) ) + return NULL; + return cvar.GetBool(); + } + + const char *GetStr( const char *pszConVar ) + { + ConVarRef cvar( pszConVar ); + if ( cvar.IsFlagSet( FCVAR_SERVER_CANNOT_QUERY ) ) + return NULL; + return cvar.GetString(); + } + + const char *GetDefaultValue( const char *pszConVar ) + { + ConVarRef cvar( pszConVar ); + return cvar.GetDefault(); + } + + bool IsFlagSet( const char *pszConVar, int nFlags ) + { + ConVarRef cvar( pszConVar ); + return cvar.IsFlagSet( nFlags ); + } + + void SetFloat( const char *pszConVar, float value ) + { + SetValue( pszConVar, value ); + } + + void SetInt( const char *pszConVar, int value ) + { + SetValue( pszConVar, value ); + } + + void SetBool( const char *pszConVar, bool value ) + { + SetValue( pszConVar, value ); + } + + void SetStr( const char *pszConVar, const char *value ) + { + SetValue( pszConVar, value ); + } + + template + void SetValue( const char *pszConVar, T value ) + { + ConVarRef cvar( pszConVar ); + if ( !cvar.IsValid() ) + return; + + if ( cvar.IsFlagSet( FCVAR_NOT_CONNECTED | FCVAR_SERVER_CANNOT_QUERY ) ) + return; + + if ( IsBlockedConvar( pszConVar ) ) + return; + + cvar.SetValue( value ); + } + +} g_ScriptConvarAccessor; + + +CUtlMap< unsigned int, bool > CScriptConvarAccessor::g_ConVarsBlocked( DefLessFunc(unsigned int) ); +CUtlMap< unsigned int, bool > CScriptConvarAccessor::g_ConCommandsOverridable( DefLessFunc(unsigned int) ); +CUtlMap< unsigned int, CScriptConCommand* > CScriptConvarAccessor::g_ScriptConCommands( DefLessFunc(unsigned int) ); +CUtlMap< unsigned int, CScriptConVar* > CScriptConvarAccessor::g_ScriptConVars( DefLessFunc(unsigned int) ); + +void CScriptConvarAccessor::RegisterCommand( const char *name, HSCRIPT fn, const char *helpString, int flags ) +{ + unsigned int hash = Hash(name); + int idx = g_ScriptConCommands.Find(hash); + if ( idx == g_ScriptConCommands.InvalidIndex() ) + { + if ( g_pCVar->FindVar(name) || ( g_pCVar->FindCommand(name) && !IsOverridable(hash) ) ) + { + DevWarning( 1, "CScriptConvarAccessor::RegisterCommand unable to register blocked ConCommand: %s\n", name ); + return; + } + + if ( !fn ) + return; + + CScriptConCommand *p = new CScriptConCommand( name, fn, helpString, flags ); + g_ScriptConCommands.Insert( hash, p ); + } + else + { + CScriptConCommand *pCmd = g_ScriptConCommands[idx]; + pCmd->SetCallback( fn ); + pCmd->m_cmd->AddFlags( flags ); + //CGMsg( 1, CON_GROUP_VSCRIPT, "CScriptConvarAccessor::RegisterCommand replacing command already registered: %s\n", name ); + } +} + +void CScriptConvarAccessor::SetCompletionCallback( const char *name, HSCRIPT fn ) +{ + unsigned int hash = Hash(name); + int idx = g_ScriptConCommands.Find(hash); + if ( idx != g_ScriptConCommands.InvalidIndex() ) + { + g_ScriptConCommands[idx]->SetCompletionCallback( fn ); + } +} + +void CScriptConvarAccessor::UnregisterCommand( const char *name ) +{ + unsigned int hash = Hash(name); + int idx = g_ScriptConCommands.Find(hash); + if ( idx != g_ScriptConCommands.InvalidIndex() ) + { + g_ScriptConCommands[idx]->Unregister(); + } +} + +void CScriptConvarAccessor::RegisterConvar( const char *name, const char *pDefaultValue, const char *helpString, int flags ) +{ + Assert( g_pCVar ); + unsigned int hash = Hash(name); + int idx = g_ScriptConVars.Find(hash); + if ( idx == g_ScriptConVars.InvalidIndex() ) + { + if ( g_pCVar->FindVar(name) || g_pCVar->FindCommand(name) ) + { + DevWarning( 1, "CScriptConvarAccessor::RegisterConvar unable to register blocked ConCommand: %s\n", name ); + return; + } + + CScriptConVar *p = new CScriptConVar( name, pDefaultValue, helpString, flags ); + g_ScriptConVars.Insert( hash, p ); + } + else + { + g_ScriptConVars[idx]->m_cvar->AddFlags( flags ); + //CGMsg( 1, CON_GROUP_VSCRIPT, "CScriptConvarAccessor::RegisterConvar convar %s already registered\n", name ); + } +} + +bool CScriptConvarAccessor::Init() +{ + static bool bExecOnce = false; + if ( bExecOnce ) + return true; + bExecOnce = true; + + AddOverridable( "+attack" ); + AddOverridable( "+attack2" ); + AddOverridable( "+attack3" ); + AddOverridable( "+forward" ); + AddOverridable( "+back" ); + AddOverridable( "+moveleft" ); + AddOverridable( "+moveright" ); + AddOverridable( "+use" ); + AddOverridable( "+jump" ); + AddOverridable( "+zoom" ); + AddOverridable( "+reload" ); + AddOverridable( "+speed" ); + AddOverridable( "+walk" ); + AddOverridable( "+duck" ); + AddOverridable( "+strafe" ); + AddOverridable( "+alt1" ); + AddOverridable( "+alt2" ); + AddOverridable( "+grenade1" ); + AddOverridable( "+grenade2" ); + AddOverridable( "+showscores" ); + + AddOverridable( "-attack" ); + AddOverridable( "-attack2" ); + AddOverridable( "-attack3" ); + AddOverridable( "-forward" ); + AddOverridable( "-back" ); + AddOverridable( "-moveleft" ); + AddOverridable( "-moveright" ); + AddOverridable( "-use" ); + AddOverridable( "-jump" ); + AddOverridable( "-zoom" ); + AddOverridable( "-reload" ); + AddOverridable( "-speed" ); + AddOverridable( "-walk" ); + AddOverridable( "-duck" ); + AddOverridable( "-strafe" ); + AddOverridable( "-alt1" ); + AddOverridable( "-alt2" ); + AddOverridable( "-grenade1" ); + AddOverridable( "-grenade2" ); + AddOverridable( "-showscores" ); + + AddOverridable( "toggle_duck" ); + AddOverridable( "lastinv" ); + AddOverridable( "invnext" ); + AddOverridable( "invprev" ); + AddOverridable( "phys_swap" ); + AddOverridable( "slot1" ); + AddOverridable( "slot2" ); + AddOverridable( "slot3" ); + AddOverridable( "slot4" ); + AddOverridable( "slot5" ); + AddOverridable( "slot6" ); + AddOverridable( "slot7" ); + + AddOverridable( "save" ); + AddOverridable( "load" ); + + + AddBlockedConVar( "con_enable" ); + AddBlockedConVar( "cl_allowdownload" ); + AddBlockedConVar( "cl_allowupload" ); + AddBlockedConVar( "cl_downloadfilter" ); + + return true; +} + +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptConvarAccessor, "CConvars", SCRIPT_SINGLETON "Provides an interface to convars." ) + DEFINE_SCRIPTFUNC( RegisterConvar, "register a new console variable." ) + DEFINE_SCRIPTFUNC( RegisterCommand, "register a console command." ) + DEFINE_SCRIPTFUNC( SetCompletionCallback, "callback is called with 3 parameters (cmdname, partial, commands), user strings must be appended to 'commands' array" ) + DEFINE_SCRIPTFUNC( UnregisterCommand, "unregister a console command." ) + DEFINE_SCRIPTFUNC( GetCommandClient, "returns the player who issued this console command." ) +#ifdef GAME_DLL + DEFINE_SCRIPTFUNC( GetClientConvarValue, "Get a convar keyvalue for a specified client" ) +#endif + DEFINE_SCRIPTFUNC( GetFloat, "Returns the convar as a float. May return null if no such convar." ) + DEFINE_SCRIPTFUNC( GetInt, "Returns the convar as an int. May return null if no such convar." ) + DEFINE_SCRIPTFUNC( GetBool, "Returns the convar as a bool. May return null if no such convar." ) + DEFINE_SCRIPTFUNC( GetStr, "Returns the convar as a string. May return null if no such convar." ) + DEFINE_SCRIPTFUNC( GetDefaultValue, "Returns the convar's default value as a string. May return null if no such convar." ) + DEFINE_SCRIPTFUNC( IsFlagSet, "Returns the convar's flags. May return null if no such convar." ) + DEFINE_SCRIPTFUNC( SetFloat, "Sets the value of the convar as a float." ) + DEFINE_SCRIPTFUNC( SetInt, "Sets the value of the convar as an int." ) + DEFINE_SCRIPTFUNC( SetBool, "Sets the value of the convar as a bool." ) + DEFINE_SCRIPTFUNC( SetStr, "Sets the value of the convar as a string." ) +END_SCRIPTDESC(); + + +//============================================================================= +// Effects +// (Unique to mapbase) +// +// At the moment only clientside until a filtering method on server is finalised. +// +// TEs most of the time call IEffects (g_pEffects) or ITempEnts (tempents) on client, +// but they also record for tools recording mode. +// +// On client no TE is suppressed. +// TE flags are found at tempent.h +// +// TODO: +//============================================================================= +#ifdef CLIENT_DLL + +class CEffectsScriptHelper +{ +private: + C_RecipientFilter filter; + +public: + void DynamicLight( int index, const Vector& origin, int r, int g, int b, int exponent, + float radius, float die, float decay, int style = 0, int flags = 0 ) + { + //te->DynamicLight( filter, delay, &origin, r, g, b, exponent, radius, die, decay ); + dlight_t *dl = effects->CL_AllocDlight( index ); + dl->origin = origin; + dl->color.r = r; + dl->color.g = g; + dl->color.b = b; + dl->color.exponent = exponent; + dl->radius = radius; + dl->die = gpGlobals->curtime + die; + dl->decay = decay; + dl->style = style; + dl->flags = flags; + } + + void Explosion( const Vector& pos, float scale, int radius, int magnitude, int flags ) + { + filter.AddAllPlayers(); + // framerate, modelindex, normal and materialtype are unused + // radius for ragdolls + extern short g_sModelIndexFireball; + te->Explosion( filter, 0.0f, &pos, g_sModelIndexFireball, scale, 15, flags, radius, magnitude, &vec3_origin ); + } + +// void FXExplosion( const Vector& pos, const Vector& normal, int materialType = 'C' ) +// { +// // just the particles +// // materialtype only for debris. can be 'C','W' or anything else. +// FX_Explosion( const_cast(pos), const_cast(normal), materialType ); +// } + +// void ConcussiveExplosion( const Vector& pos, const Vector& normal ) +// { +// FX_ConcussiveExplosion( const_cast(pos), const_cast(normal) ); +// } + +// void MicroExplosion( const Vector& pos, const Vector& normal ) +// { +// FX_MicroExplosion( const_cast(pos), const_cast(normal) ); +// } + +// void MuzzleFlash( int type, HSCRIPT hEntity, int attachment, bool firstPerson ) +// { +// C_BaseEntity *p = ToEnt(hEntity); +// ClientEntityHandle_t ent = p ? (ClientEntityList().EntIndexToHandle)( p->entindex() ) : NULL;; +// tempents->MuzzleFlash( type, ent, attachment, firstPerson ); +// } + + void Sparks( const Vector& pos, int nMagnitude, int nTrailLength, const Vector& pDir ) + { + //te->Sparks( filter, delay, &pos, nMagnitude, nTrailLength, &pDir ); + //g_pEffects->Sparks( pos, nMagnitude, nTrailLength, &pDir ); + FX_ElectricSpark( pos, nMagnitude, nTrailLength, &pDir ); + } + + void MetalSparks( const Vector& pos, const Vector& dir ) + { + //g_pEffects->MetalSparks( pos, dir ); + FX_MetalSpark( pos, dir, dir ); + } + +// void Smoke( const Vector& pos, float scale, int framerate) +// { +// extern short g_sModelIndexSmoke; +// //te->Smoke( filter, 0.0, &pos, g_sModelIndexSmoke, scale * 10.0f, framerate ); +// g_pEffects->Smoke( pos, g_sModelIndexSmoke, scale, framerate ); +// } + + void Dust( const Vector &pos, const Vector &dir, float size, float speed ) + { + //te->Dust( filter, delay, pos, dir, size, speed ); + //g_pEffects->Dust( pos, dir, size, speed ); + FX_Dust( pos, dir, size, speed ); + } + + void Bubbles( const Vector &mins, const Vector &maxs, float height, int modelindex, int count, float speed ) + { + //int bubbles = modelinfo->GetModelIndex( "sprites/bubble.vmt" ); + //te->Bubbles( filter, delay, &mins, &maxs, height, modelindex, count, speed ); + tempents->Bubbles( mins, maxs, height, modelindex, count, speed ); + } + +// void Fizz( const Vector& mins, const Vector& maxs, int modelIndex, int density, int current/*, int flags*/ ) +// { +// //te->Fizz( filter, delay, ent, modelindex, density, current ); +// //tempents->FizzEffect( ToEnt(ent), modelindex, density, current ); +// } + + void Sprite( const Vector &pos, const Vector &dir, float scale, int modelIndex, int rendermode, + int renderfx, int brightness, float life, int flags ) + { + //te->Sprite( filter, delay, &pos, modelindex, size, brightness ); + float a = (1.0 / 255.0) * brightness; + tempents->TempSprite( pos, dir, scale, modelIndex, rendermode, renderfx, a, life, flags ); + } + +// void PhysicsProp( float delay, int modelindex, int skin, const Vector& pos, const QAngle &angles, +// const Vector& vel, int flags, int effects ) +// { +// //te->PhysicsProp( filter, delay, modelindex, skin, pos, angles, vel, flags, effects ); +// tempents->PhysicsProp( modelindex, skin, pos, angles, vel, flags, effects ); +// } + + void ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAccel, int modelindex, + int lifetime, HSCRIPT pOwner, const char *pszImpactEffect = NULL, const char *pszParticleEffect = NULL ) + { + //te->ClientProjectile( filter, delay, &vecOrigin, &vecVelocity, modelindex, lifetime, ToEnt(pOwner) ); + if ( pszImpactEffect && !(*pszImpactEffect) ) + pszImpactEffect = NULL; + if ( pszParticleEffect && !(*pszParticleEffect) ) + pszParticleEffect = NULL; + tempents->ClientProjectile( vecOrigin, vecVelocity, vecAccel, modelindex, lifetime, ToEnt(pOwner), pszImpactEffect, pszParticleEffect ); + } + +} g_ScriptEffectsHelper; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CEffectsScriptHelper, "CEffects", SCRIPT_SINGLETON "" ) + DEFINE_SCRIPTFUNC( DynamicLight, "" ) + DEFINE_SCRIPTFUNC( Explosion, "" ) + DEFINE_SCRIPTFUNC( Sparks, "" ) + DEFINE_SCRIPTFUNC( MetalSparks, "" ) + DEFINE_SCRIPTFUNC( Dust, "" ) + DEFINE_SCRIPTFUNC( Bubbles, "" ) + DEFINE_SCRIPTFUNC( Sprite, "" ) + DEFINE_SCRIPTFUNC( ClientProjectile, "" ) +END_SCRIPTDESC(); +#endif + + void RegisterScriptSingletons() { ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::SaveTable, "SaveTable", "Store a table with primitive values that will persist across level transitions and save loads." ); @@ -2076,6 +2841,10 @@ void RegisterScriptSingletons() g_pScriptVM->RegisterInstance( &g_ScriptLocalize, "Localize" ); g_pScriptVM->RegisterInstance( g_ScriptNetMsg, "NetMsg" ); g_pScriptVM->RegisterInstance( &g_ScriptDebugOverlay, "debugoverlay" ); + g_pScriptVM->RegisterInstance( &g_ScriptConvarAccessor, "Convars" ); +#ifdef CLIENT_DLL + g_pScriptVM->RegisterInstance( &g_ScriptEffectsHelper, "effects" ); +#endif // Singletons not unique to VScript (not declared or defined here) g_pScriptVM->RegisterInstance( GameRules(), "GameRules" ); @@ -2084,9 +2853,9 @@ void RegisterScriptSingletons() g_pScriptVM->RegisterInstance( &g_AI_SquadManager, "Squads" ); #endif -#ifndef CLIENT_DLL +#ifdef USE_OLD_EVENT_DESCRIPTORS CScriptGameEventListener::LoadAllEvents(); -#endif // !CLIENT_DLL +#endif g_ScriptNetMsg->InitPostVM(); } diff --git a/sp/src/game/shared/mapbase/vscript_singletons.h b/sp/src/game/shared/mapbase/vscript_singletons.h index a3b94f9b..a18d4a38 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.h +++ b/sp/src/game/shared/mapbase/vscript_singletons.h @@ -5,8 +5,8 @@ // $NoKeywords: $ //============================================================================= -#ifndef VSCRIPT_SINGLETONS -#define VSCRIPT_SINGLETONS +#ifndef VSCRIPT_SINGLETONS_H +#define VSCRIPT_SINGLETONS_H #ifdef _WIN32 #pragma once #endif @@ -29,21 +29,24 @@ class CNetMsgScriptHelper : public CAutoGameSystem class CNetMsgScriptHelper #endif { +#ifdef CLIENT_DLL +public: + bool m_bWriteReady; // dt ready to send +#endif + private: #ifdef GAME_DLL - CRecipientFilter m_filter; bf_read *m_MsgIn; + CRecipientFilter m_filter; #else bf_read m_MsgIn; #endif + HSCRIPT m_Hooks; bf_write m_MsgOut; byte m_MsgData[ PAD_NUMBER( SCRIPT_NETMSG_DATA_SIZE, 4 ) ]; - HSCRIPT m_Hooks; public: #ifdef CLIENT_DLL - bool m_bWriteReady; // dt ready to send - CNetMsgScriptHelper() : m_Hooks(NULL), m_bWriteReady(false) {} #else CNetMsgScriptHelper() : m_Hooks(NULL) {} @@ -58,9 +61,9 @@ public: void InitPostVM(); #ifdef GAME_DLL - void RecieveMessage( bf_read *msg, CBaseEntity *pPlayer ); + void ReceiveMessage( bf_read *msg, CBaseEntity *pPlayer ); #else - void RecieveMessage( bf_read &msg ); + void ReceiveMessage( bf_read &msg ); #endif void WriteToBuffer( bf_write *bf ); @@ -72,7 +75,7 @@ public: #else void Send(); #endif - void Recieve( const char *msg, HSCRIPT func ); + void Receive( const char *msg, HSCRIPT func ); #ifdef GAME_DLL inline void DoSendUserMsg( CRecipientFilter *filter, int type ); @@ -100,14 +103,14 @@ public: void WriteShort( int iValue ); // 16 bit short void WriteWord( int iValue ); // 16 bit unsigned short void WriteLong( int iValue ); // 32 bit long - void WriteFloat( float flValue ); - void WriteNormal( float flValue ); // 12 bit + void WriteFloat( float flValue ); // 32 bit float + void WriteNormal( float flValue ); // 12 bit (1 + NORMAL_FRACTIONAL_BITS) void WriteAngle( float flValue ); // 8 bit unsigned char void WriteCoord( float flValue ); void WriteVec3Coord( const Vector& rgflValue ); void WriteVec3Normal( const Vector& rgflValue ); // 27 bit ( 3 + 2 * (1 + NORMAL_FRACTIONAL_BITS) ) void WriteAngles( const QAngle& rgflValue ); - void WriteString( const char *sz ); // max 512 bytes at once + void WriteString( const char *sz ); void WriteBool( bool bValue ); // 1 bit void WriteEntity( HSCRIPT hEnt ); // 11 bit (entindex) void WriteEHandle( HSCRIPT hEnt ); // 32 bit long diff --git a/sp/src/game/shared/mapbase/weapon_custom_scripted.h b/sp/src/game/shared/mapbase/weapon_custom_scripted.h index 90630a65..f1493ce0 100644 --- a/sp/src/game/shared/mapbase/weapon_custom_scripted.h +++ b/sp/src/game/shared/mapbase/weapon_custom_scripted.h @@ -5,8 +5,8 @@ // $NoKeywords: $ //============================================================================= -#ifndef VSCRIPT_FUNCS_MATH -#define VSCRIPT_FUNCS_MATH +#ifndef WEAPON_CUSTOM_SCRIPTED_H +#define WEAPON_CUSTOM_SCRIPTED_H #ifdef _WIN32 #pragma once #endif diff --git a/sp/src/game/shared/usercmd.cpp b/sp/src/game/shared/usercmd.cpp index 032b366c..1607eba3 100644 --- a/sp/src/game/shared/usercmd.cpp +++ b/sp/src/game/shared/usercmd.cpp @@ -335,7 +335,7 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ) #if defined( MAPBASE_VSCRIPT ) && defined( GAME_DLL ) if ( buf->ReadOneBit() ) { - g_ScriptNetMsg->RecieveMessage( buf, pPlayer ); + g_ScriptNetMsg->ReceiveMessage( buf, pPlayer ); } #endif diff --git a/sp/src/game/shared/vscript_shared.cpp b/sp/src/game/shared/vscript_shared.cpp index c460a48a..86e220b4 100644 --- a/sp/src/game/shared/vscript_shared.cpp +++ b/sp/src/game/shared/vscript_shared.cpp @@ -440,13 +440,17 @@ ISaveRestoreBlockHandler *GetVScriptSaveRestoreBlockHandler() bool CBaseEntityScriptInstanceHelper::ToString( void *p, char *pBuf, int bufSize ) { CBaseEntity *pEntity = (CBaseEntity *)p; +#ifdef CLIENT_DLL + if ( pEntity->GetEntityName() && pEntity->GetEntityName()[0] ) +#else if ( pEntity->GetEntityName() != NULL_STRING ) +#endif { - V_snprintf( pBuf, bufSize, "([%d] %s: %s)", pEntity->entindex(), STRING(pEntity->m_iClassname), STRING( pEntity->GetEntityName() ) ); + V_snprintf( pBuf, bufSize, "([%d] %s: %s)", pEntity->entindex(), pEntity->GetClassname(), STRING( pEntity->GetEntityName() ) ); } else { - V_snprintf( pBuf, bufSize, "([%d] %s)", pEntity->entindex(), STRING(pEntity->m_iClassname) ); + V_snprintf( pBuf, bufSize, "([%d] %s)", pEntity->entindex(), pEntity->GetClassname() ); } return true; } diff --git a/sp/src/materialsystem/stdshaders/SDK_core_ps2x.fxc b/sp/src/materialsystem/stdshaders/SDK_core_ps2x.fxc new file mode 100644 index 00000000..3db01c24 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/SDK_core_ps2x.fxc @@ -0,0 +1,222 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +// STATIC: "CONVERT_TO_SRGB" "0..1" [ps20b][= g_pHardwareConfig->NeedsShaderSRGBConversion()] [PC] +// STATIC: "CONVERT_TO_SRGB" "0..0" [= 0] [XBOX] +// STATIC: "CUBEMAP" "0..1" +// STATIC: "FLOWMAP" "0..1" +// STATIC: "CORECOLORTEXTURE" "0..1" +// STATIC: "REFRACT" "0..1" +// DYNAMIC: "PIXELFOGTYPE" "0..1" + +// SKIP: ( $REFRACT || $CORECOLORTEXTURE ) && $CUBEMAP + +#include "common_ps_fxc.h" + +sampler RefractSampler : register( s2 ); +sampler NormalSampler : register( s3 ); +#if CUBEMAP +sampler EnvmapSampler : register( s4 ); +#endif +#if FLOWMAP +sampler FlowmapSampler : register( s6 ); +#endif + +#if CORECOLORTEXTURE +sampler CoreColorSampler : register( s7 ); +#endif + +const HALF3 g_EnvmapTint : register( c0 ); +const HALF3 g_RefractTint : register( c1 ); +const HALF3 g_EnvmapContrast : register( c2 ); +const HALF3 g_EnvmapSaturation : register( c3 ); +const HALF2 g_RefractScale : register( c5 ); +#if FLOWMAP +const float g_Time : register( c6 ); +const float2 g_FlowScrollRate : register( c7 ); +const float g_CoreColorTexCoordOffset : register( c9 ); +#endif + +const float3 g_EyePos : register( c8 ); +const float4 g_FogParams : register( c11 ); + + +const float3 g_SphereCenter : register( c12 ); +const float3 g_SphereRadius : register( c15 ); + +float LengthThroughSphere( float3 vecRayOrigin, float3 vecRayDelta, + float3 vecSphereCenter, float flRadius, out float alpha ) +{ + // Solve using the ray equation + the sphere equation + // P = o + dt + // (x - xc)^2 + (y - yc)^2 + (z - zc)^2 = r^2 + // (ox + dx * t - xc)^2 + (oy + dy * t - yc)^2 + (oz + dz * t - zc)^2 = r^2 + // (ox - xc)^2 + 2 * (ox-xc) * dx * t + dx^2 * t^2 + + // (oy - yc)^2 + 2 * (oy-yc) * dy * t + dy^2 * t^2 + + // (oz - zc)^2 + 2 * (oz-zc) * dz * t + dz^2 * t^2 = r^2 + // (dx^2 + dy^2 + dz^2) * t^2 + 2 * ((ox-xc)dx + (oy-yc)dy + (oz-zc)dz) t + + // (ox-xc)^2 + (oy-yc)^2 + (oz-zc)^2 - r^2 = 0 + // or, t = (-b +/- sqrt( b^2 - 4ac)) / 2a + // a = DotProduct( vecRayDelta, vecRayDelta ); + // b = 2 * DotProduct( vecRayOrigin - vecCenter, vecRayDelta ) + // c = DotProduct(vecRayOrigin - vecCenter, vecRayOrigin - vecCenter) - flRadius * flRadius; + + float3 vecSphereToRay; + vecSphereToRay = vecRayOrigin - vecSphereCenter; + + float a = dot( vecRayDelta, vecRayDelta ); + + // This would occur in the case of a zero-length ray + // if ( a == 0.0f ) + // { + // *pT1 = *pT2 = 0.0f; + // return vecSphereToRay.LengthSqr() <= flRadius * flRadius; + // } + + float b = 2 * dot( vecSphereToRay, vecRayDelta ); + float c = dot( vecSphereToRay, vecSphereToRay ) - flRadius * flRadius; + float flDiscrim = b * b - 4 * a * c; + // if ( flDiscrim < 0.0f ) + // return 0.0f; + + float hack = flDiscrim; + flDiscrim = sqrt( flDiscrim ); + float oo2a = 0.5f / a; + + + //if( hack < 0.0f ) + //{ + // alpha = 0.0f; + // return 0.0f; + //} + //else + //{ + // alpha = 1.0f; + // return abs( flDiscrim ) * 2 * oo2a; + //} + + //replacing the if's above because if's in hlsl are bad..... + float fHackGreaterThanZero = step( 0.0f, hack ); + alpha = fHackGreaterThanZero; + return (fHackGreaterThanZero * (abs( flDiscrim ) * 2 * oo2a)); + + + // *pT1 = ( - b - flDiscrim ) * oo2a; + // *pT2 = ( - b + flDiscrim ) * oo2a; + // return true; +} + + +struct PS_INPUT +{ + float2 vBumpTexCoord : TEXCOORD0; // dudvMapAndNormalMapTexCoord + HALF3 vWorldVertToEyeVector : TEXCOORD1; + HALF3x3 tangentSpaceTranspose : TEXCOORD2; + float3 vRefractXYW : TEXCOORD5; + float3 projNormal : TEXCOORD6; + float4 worldPos_projPosZ : TEXCOORD7; +}; + +float4 main( PS_INPUT i ) : COLOR +{ + HALF3 result = 0.0f; + + HALF blend = 1.0f; + +#if FLOWMAP + // Mapbase tries to un-hack some of this code + //float3 g_SphereCenter = { 2688.0f, 12139.0f, 5170.0f }; + //float g_SphereDiameter = 430.0f; + //float g_SphereRadius = g_SphereDiameter * 0.5f; + + float g_SphereDiameter = g_SphereRadius * 2.0f; + + float3 tmp = i.worldPos_projPosZ.xyz - g_SphereCenter; + float hackRadius = 1.05f * sqrt( dot( tmp, tmp ) ); + + float sphereAlpha; + float lengthThroughSphere = LengthThroughSphere( g_EyePos, normalize( i.worldPos_projPosZ.xyz - g_EyePos ), + g_SphereCenter, /*g_SphereRadius*/ hackRadius, sphereAlpha ); + + float normalizedLengthThroughSphere = lengthThroughSphere / g_SphereDiameter; + + + float3 hackWorldSpaceNormal = normalize( i.worldPos_projPosZ.xyz - g_SphereCenter ); + float3 realFuckingNormal = abs( hackWorldSpaceNormal ); + hackWorldSpaceNormal = 0.5f * ( hackWorldSpaceNormal + 1.0f ); + + // hackWorldSpaceNormal = abs( hackWorldSpaceNormal ); + + // return float4( hackWorldSpaceNormal.x, 0.0f, 0.0f, 1.0f ); + + i.vBumpTexCoord.xy = 0.0f; + i.vBumpTexCoord.xy = realFuckingNormal.z * tex2D( FlowmapSampler, hackWorldSpaceNormal.xy ); + i.vBumpTexCoord.xy += realFuckingNormal.y * tex2D( FlowmapSampler, hackWorldSpaceNormal.xz ); + i.vBumpTexCoord.xy += realFuckingNormal.x * tex2D( FlowmapSampler, hackWorldSpaceNormal.yz ); + i.vBumpTexCoord.xy += g_Time * g_FlowScrollRate; + // return float4( i.vBumpTexCoord.xy, 0.0f, 0.0f ); +#endif + + // Load normal and expand range + HALF4 vNormalSample = tex2D( NormalSampler, i.vBumpTexCoord ); + // return vNormalSample; + HALF3 tangentSpaceNormal = vNormalSample * 2.0 - 1.0; + + HALF3 refractTintColor = g_RefractTint; + + // Perform division by W only once + float ooW = 1.0f / i.vRefractXYW.z; + + // Compute coordinates for sampling refraction + float2 vRefractTexCoordNoWarp = i.vRefractXYW.xy * ooW; + float2 vRefractTexCoord = tangentSpaceNormal.xy; + HALF scale = vNormalSample.a * g_RefractScale.x; +#if FLOWMAP + scale *= normalizedLengthThroughSphere; +#endif + vRefractTexCoord *= scale; +#if FLOWMAP + float2 hackOffset = vRefractTexCoord; +#endif + vRefractTexCoord += vRefractTexCoordNoWarp; + + float3 colorWarp = tex2D( RefractSampler, vRefractTexCoord.xy ); + float3 colorNoWarp = tex2D( RefractSampler, vRefractTexCoordNoWarp.xy ); + + colorWarp *= refractTintColor; +#if REFRACT + result = lerp( colorNoWarp, colorWarp, blend ); + // return float4( 1.0f, 0.0f, 0.0f, 1.0f ); +#endif + +#if CUBEMAP + HALF specularFactor = vNormalSample.a; + + HALF3 worldSpaceNormal = mul( i.tangentSpaceTranspose, tangentSpaceNormal ); + + HALF3 reflectVect = CalcReflectionVectorUnnormalized( worldSpaceNormal, i.vWorldVertToEyeVector ); + HALF3 specularLighting = texCUBE( EnvmapSampler, reflectVect ); + specularLighting *= specularFactor; + specularLighting *= g_EnvmapTint; + HALF3 specularLightingSquared = specularLighting * specularLighting; + specularLighting = lerp( specularLighting, specularLightingSquared, g_EnvmapContrast ); + HALF3 greyScale = dot( specularLighting, HALF3( 0.299f, 0.587f, 0.114f ) ); + specularLighting = lerp( greyScale, specularLighting, g_EnvmapSaturation ); + result += specularLighting; +#endif + +#if CORECOLORTEXTURE && FLOWMAP + float4 coreColorTexel = tex2D( CoreColorSampler, hackOffset + float2( normalizedLengthThroughSphere, g_CoreColorTexCoordOffset ) ); + HALF4 rgba = HALF4( lerp( result, coreColorTexel, coreColorTexel.a /*normalizedLengthThroughSphere*/ ), sphereAlpha ); +#else + HALF4 rgba = HALF4( result, vNormalSample.a ); +#endif + + + float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos.z, i.worldPos_projPosZ.z, i.worldPos_projPosZ.w ); + return FinalOutput( rgba, fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE ); +} + diff --git a/sp/src/materialsystem/stdshaders/SDK_core_vs20.fxc b/sp/src/materialsystem/stdshaders/SDK_core_vs20.fxc new file mode 100644 index 00000000..9b7c9652 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/SDK_core_vs20.fxc @@ -0,0 +1,103 @@ +// STATIC: "MODEL" "0..1" + +// DYNAMIC: "COMPRESSED_VERTS" "0..1" +// DYNAMIC: "SKINNING" "0..1" + +#include "common_vs_fxc.h" + +static const bool g_bSkinning = SKINNING ? true : false; +static const bool g_bModel = MODEL ? true : false; + +const float4 cBumpTexCoordTransform[2] : register( SHADER_SPECIFIC_CONST_1 ); + +struct VS_INPUT +{ + float4 vPos : POSITION; + float4 vBoneWeights : BLENDWEIGHT; + float4 vBoneIndices : BLENDINDICES; + float4 vNormal : NORMAL; + float4 vBaseTexCoord : TEXCOORD0; +#if !MODEL + float3 vTangentS : TANGENT; + float3 vTangentT : BINORMAL0; +#else + float4 vUserData : TANGENT; +#endif +}; + +struct VS_OUTPUT +{ + float4 vProjPos_POSITION : POSITION; + float vFog : FOG; + float2 vBumpTexCoord : TEXCOORD0; + float3 vTangentEyeVect : TEXCOORD1; + float3x3 tangentSpaceTranspose : TEXCOORD2; + float3 vRefractXYW : TEXCOORD5; + float4 projNormal_screenCoordW : TEXCOORD6; + float4 worldPos_projPosZ : TEXCOORD7; + float4 fogFactorW : COLOR1; +}; + +VS_OUTPUT main( const VS_INPUT v ) +{ + VS_OUTPUT o = ( VS_OUTPUT )0; + + float3 worldNormal, worldPos, worldTangentS, worldTangentT; + + float3 vObjNormal; +#if MODEL + float4 vObjTangent; + DecompressVertex_NormalTangent( v.vNormal, v.vUserData, vObjNormal, vObjTangent ); + + SkinPositionNormalAndTangentSpace( + g_bSkinning, + v.vPos, vObjNormal, vObjTangent, + v.vBoneWeights, v.vBoneIndices, + worldPos, worldNormal, worldTangentS, worldTangentT ); +#else + DecompressVertex_Normal( v.vNormal, vObjNormal ); + + worldPos = mul( v.vPos, cModel[0] ); + worldTangentS = mul( v.vTangentS, ( const float3x3 )cModel[0] ); + worldTangentT = mul( v.vTangentT, ( const float3x3 )cModel[0] ); + worldNormal = mul( vObjNormal, ( float3x3 )cModel[0] ); +#endif + + + // Projected position + float4 vProjPos = mul( float4( worldPos, 1 ), cViewProj ); + o.vProjPos_POSITION = vProjPos; + o.projNormal_screenCoordW.xyz = mul( worldNormal, cViewProj ); + + o.worldPos_projPosZ = float4( worldPos.xyz, vProjPos.z ); + + // Map projected position to the refraction texture + float2 vRefractPos; + vRefractPos.x = vProjPos.x; + vRefractPos.y = -vProjPos.y; // invert Y + vRefractPos = (vRefractPos + vProjPos.w) * 0.5f; + + // Refraction transform + o.vRefractXYW = float3(vRefractPos.x, vRefractPos.y, vProjPos.w); + + // Compute fog based on the position + float3 vWorldPos = mul( v.vPos, cModel[0] ); + o.fogFactorW = o.vFog = CalcFog( vWorldPos, vProjPos, FOGTYPE_RANGE ); + + // Eye vector + float3 vWorldEyeVect = cEyePos - vWorldPos; + // Transform to the tangent space + o.vTangentEyeVect.x = dot( vWorldEyeVect, worldTangentS ); + o.vTangentEyeVect.y = dot( vWorldEyeVect, worldTangentT ); + o.vTangentEyeVect.z = dot( vWorldEyeVect, worldNormal ); + + // Tranform bump coordinates + o.vBumpTexCoord.x = dot( v.vBaseTexCoord, cBumpTexCoordTransform[0] ); + o.vBumpTexCoord.y = dot( v.vBaseTexCoord, cBumpTexCoordTransform[1] ); + + o.tangentSpaceTranspose[0] = worldTangentS; + o.tangentSpaceTranspose[1] = worldTangentT; + o.tangentSpaceTranspose[2] = worldNormal; + + return o; +} diff --git a/sp/src/materialsystem/stdshaders/core_dx9.cpp b/sp/src/materialsystem/stdshaders/core_dx9.cpp new file mode 100644 index 00000000..ceff0563 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/core_dx9.cpp @@ -0,0 +1,307 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "BaseVSShader.h" +#include "SDK_core_vs20.inc" +#include "SDK_core_ps20.inc" +#include "SDK_core_ps20b.inc" + +#define MAXBLUR 1 + +DEFINE_FALLBACK_SHADER( SDK_Core, SDK_Core_DX90 ) + +BEGIN_VS_SHADER( SDK_Core_DX90, + "Help for Core" ) + + BEGIN_SHADER_PARAMS + SHADER_PARAM_OVERRIDE( COLOR, SHADER_PARAM_TYPE_COLOR, "{255 255 255}", "unused", SHADER_PARAM_NOT_EDITABLE ) + SHADER_PARAM_OVERRIDE( ALPHA, SHADER_PARAM_TYPE_FLOAT, "1.0", "unused", SHADER_PARAM_NOT_EDITABLE ) + SHADER_PARAM( REFRACTAMOUNT, SHADER_PARAM_TYPE_FLOAT, "2", "" ) + SHADER_PARAM( REFRACTTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "refraction tint" ) + SHADER_PARAM( NORMALMAP, SHADER_PARAM_TYPE_TEXTURE, "models/shadertest/shader1_normal", "normal map" ) + SHADER_PARAM( BUMPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "frame number for $bumpmap" ) + SHADER_PARAM( BUMPTRANSFORM, SHADER_PARAM_TYPE_MATRIX, "center .5 .5 scale 1 1 rotate 0 translate 0 0", "$bumpmap texcoord transform" ) + SHADER_PARAM( TIME, SHADER_PARAM_TYPE_FLOAT, "0.0f", "" ) + SHADER_PARAM( ENVMAP, SHADER_PARAM_TYPE_TEXTURE, "shadertest/shadertest_env", "envmap" ) + SHADER_PARAM( ENVMAPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "envmap frame number" ) + SHADER_PARAM( ENVMAPTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "envmap tint" ) + SHADER_PARAM( ENVMAPCONTRAST, SHADER_PARAM_TYPE_FLOAT, "0.0", "contrast 0 == normal 1 == color*color" ) + SHADER_PARAM( ENVMAPSATURATION, SHADER_PARAM_TYPE_FLOAT, "1.0", "saturation 0 == greyscale 1 == normal" ) + SHADER_PARAM( FLOWMAP, SHADER_PARAM_TYPE_TEXTURE, "", "flowmap" ) + SHADER_PARAM( FLOWMAPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "frame number for $flowmap" ) + SHADER_PARAM( FLOWMAPSCROLLRATE, SHADER_PARAM_TYPE_VEC2, "[0 0", "2D rate to scroll $flowmap" ) + SHADER_PARAM( CORECOLORTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "" ); + SHADER_PARAM( CORECOLORTEXTUREFRAME, SHADER_PARAM_TYPE_INTEGER, "", "" ); + SHADER_PARAM( FLOWMAPTEXCOORDOFFSET, SHADER_PARAM_TYPE_FLOAT, "0.0", "" ); +#ifdef MAPBASE + SHADER_PARAM( SPHERECENTER, SHADER_PARAM_TYPE_VEC3, "2688.0, 12139.0, 5170.0", "The sphere's worldspace center (was previously hardcoded)" ); + SHADER_PARAM( SPHERERADIUS, SHADER_PARAM_TYPE_FLOAT, "215.0", "The sphere's worldspace radius (was previously hardcoded)" ); +#endif + END_SHADER_PARAMS + SHADER_INIT_PARAMS() + { + SET_FLAGS2( MATERIAL_VAR2_NEEDS_TANGENT_SPACES ); + SET_FLAGS( MATERIAL_VAR_TRANSLUCENT ); + if( !params[ENVMAPTINT]->IsDefined() ) + { + params[ENVMAPTINT]->SetVecValue( 1.0f, 1.0f, 1.0f ); + } + if( !params[ENVMAPCONTRAST]->IsDefined() ) + { + params[ENVMAPCONTRAST]->SetFloatValue( 0.0f ); + } + if( !params[ENVMAPSATURATION]->IsDefined() ) + { + params[ENVMAPSATURATION]->SetFloatValue( 1.0f ); + } + if( !params[ENVMAPFRAME]->IsDefined() ) + { + params[ENVMAPFRAME]->SetIntValue( 0 ); + } + if( !params[BASETEXTURE]->IsDefined() ) + { + SET_FLAGS2( MATERIAL_VAR2_NEEDS_POWER_OF_TWO_FRAME_BUFFER_TEXTURE ); + } + } + + SHADER_FALLBACK + { + if( g_pHardwareConfig->GetDXSupportLevel() < 90 ) + return "Core_dx90"; + + return 0; + } + + SHADER_INIT + { + if (params[BASETEXTURE]->IsDefined() ) + { + LoadTexture( BASETEXTURE ); + } + if (params[NORMALMAP]->IsDefined() ) + { + LoadBumpMap( NORMALMAP ); + } + if ( params[ENVMAP]->IsDefined() ) + { + LoadCubeMap( ENVMAP ); + } + if ( params[FLOWMAP]->IsDefined() ) + { + LoadTexture( FLOWMAP ); + } + if ( params[CORECOLORTEXTURE]->IsDefined() ) + { + LoadTexture( CORECOLORTEXTURE ); + } + } + + inline void DrawPass( IMaterialVar **params, IShaderShadow* pShaderShadow, + IShaderDynamicAPI* pShaderAPI, int nPass, VertexCompressionType_t vertexCompression ) + { + bool bIsModel = IS_FLAG_SET( MATERIAL_VAR_MODEL ); + bool bHasEnvmap = params[ENVMAP]->IsTexture(); + bool bHasFlowmap = params[FLOWMAP]->IsTexture(); + bool bHasCoreColorTexture = params[CORECOLORTEXTURE]->IsTexture(); + + SHADOW_STATE + { + SetInitialShadowState( ); + + if( nPass == 0 ) + { + // Alpha test: FIXME: shouldn't this be handled in Shader_t::SetInitialShadowState + pShaderShadow->EnableAlphaTest( IS_FLAG_SET(MATERIAL_VAR_ALPHATEST) ); + } + else + { + pShaderShadow->DepthFunc( SHADER_DEPTHFUNC_EQUAL ); + EnableAlphaBlending( SHADER_BLEND_ONE, SHADER_BLEND_ONE ); + } + + // If envmap is not specified, the alpha channel is the translucency + // (If envmap *is* specified, alpha channel is the reflection amount) + if ( params[NORMALMAP]->IsTexture() && !bHasEnvmap ) + { + SetDefaultBlendingShadowState( NORMALMAP, false ); + } + + // source render target that contains the image that we are warping. + pShaderShadow->EnableTexture( SHADER_SAMPLER2, true ); + if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) + { + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER2, true ); + } + + // normal map + pShaderShadow->EnableTexture( SHADER_SAMPLER3, true ); + if( bHasEnvmap ) + { + // envmap + pShaderShadow->EnableTexture( SHADER_SAMPLER4, true ); + if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) + { + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER4, true ); + } + } + + if( bHasFlowmap ) + { + pShaderShadow->EnableTexture( SHADER_SAMPLER6, true ); + } + + if( bHasCoreColorTexture ) + { + pShaderShadow->EnableTexture( SHADER_SAMPLER7, true ); + } + + if( g_pHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) + { + pShaderShadow->EnableSRGBWrite( true ); + } + + unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL; + int userDataSize = 0; + int nTexCoordCount = 1; + if( bIsModel ) + { + userDataSize = 4; + } + else + { + flags |= VERTEX_TANGENT_S | VERTEX_TANGENT_T; + } + + // This shader supports compressed vertices, so OR in that flag: + flags |= VERTEX_FORMAT_COMPRESSED; + + pShaderShadow->VertexShaderVertexFormat( flags, nTexCoordCount, NULL, userDataSize ); + + DECLARE_STATIC_VERTEX_SHADER( sdk_core_vs20 ); + SET_STATIC_VERTEX_SHADER_COMBO( MODEL, bIsModel ); + SET_STATIC_VERTEX_SHADER( sdk_core_vs20 ); + + if ( g_pHardwareConfig->SupportsPixelShaders_2_b() ) + { + DECLARE_STATIC_PIXEL_SHADER( sdk_core_ps20b ); + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap && ( nPass == 1 ) ); + SET_STATIC_PIXEL_SHADER_COMBO( FLOWMAP, bHasFlowmap ); + SET_STATIC_PIXEL_SHADER_COMBO( CORECOLORTEXTURE, bHasCoreColorTexture && ( nPass == 0 ) ); + SET_STATIC_PIXEL_SHADER_COMBO( REFRACT, nPass == 0 ); + SET_STATIC_PIXEL_SHADER( sdk_core_ps20b ); + } + else + { + DECLARE_STATIC_PIXEL_SHADER( sdk_core_ps20 ); + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap && ( nPass == 1 ) ); + SET_STATIC_PIXEL_SHADER_COMBO( FLOWMAP, bHasFlowmap ); + SET_STATIC_PIXEL_SHADER_COMBO( CORECOLORTEXTURE, bHasCoreColorTexture && ( nPass == 0 ) ); + SET_STATIC_PIXEL_SHADER_COMBO( REFRACT, nPass == 0 ); + SET_STATIC_PIXEL_SHADER( sdk_core_ps20 ); + } + + DefaultFog(); + } + DYNAMIC_STATE + { + pShaderAPI->SetDefaultState(); + + if ( params[BASETEXTURE]->IsTexture() ) + { + BindTexture( SHADER_SAMPLER2, BASETEXTURE, FRAME ); + } + else + { + pShaderAPI->BindStandardTexture( SHADER_SAMPLER2, TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0 ); + } + + BindTexture( SHADER_SAMPLER3, NORMALMAP, BUMPFRAME ); + + if( bHasEnvmap ) + { + BindTexture( SHADER_SAMPLER4, ENVMAP, ENVMAPFRAME ); + } + + if( bHasFlowmap ) + { + BindTexture( SHADER_SAMPLER6, FLOWMAP, FLOWMAPFRAME ); + } + + if( bHasCoreColorTexture ) + { + BindTexture( SHADER_SAMPLER7, CORECOLORTEXTURE, CORECOLORTEXTUREFRAME ); + } + + DECLARE_DYNAMIC_VERTEX_SHADER( sdk_core_vs20 ); + SET_DYNAMIC_VERTEX_SHADER_COMBO( SKINNING, pShaderAPI->GetCurrentNumBones() > 0 ); + SET_DYNAMIC_VERTEX_SHADER_COMBO( COMPRESSED_VERTS, (int)vertexCompression ); + SET_DYNAMIC_VERTEX_SHADER( sdk_core_vs20 ); + + if ( g_pHardwareConfig->SupportsPixelShaders_2_b() ) + { + DECLARE_DYNAMIC_PIXEL_SHADER( sdk_core_ps20b ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); + SET_DYNAMIC_PIXEL_SHADER( sdk_core_ps20b ); + } + else + { + DECLARE_DYNAMIC_PIXEL_SHADER( sdk_core_ps20 ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); + SET_DYNAMIC_PIXEL_SHADER( sdk_core_ps20 ); + } + + SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_1, BUMPTRANSFORM ); + + if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ) + { + SetPixelShaderConstant( 0, ENVMAPTINT ); + SetPixelShaderConstant( 1, REFRACTTINT ); + } + else + { + SetPixelShaderConstantGammaToLinear( 0, ENVMAPTINT ); + SetPixelShaderConstantGammaToLinear( 1, REFRACTTINT ); + } + SetPixelShaderConstant( 2, ENVMAPCONTRAST ); + SetPixelShaderConstant( 3, ENVMAPSATURATION ); + float c5[4] = { params[REFRACTAMOUNT]->GetFloatValue(), + params[REFRACTAMOUNT]->GetFloatValue(), 0.0f, 0.0f }; + pShaderAPI->SetPixelShaderConstant( 5, c5, 1 ); + + float eyePos[4]; + s_pShaderAPI->GetWorldSpaceCameraPosition( eyePos ); + s_pShaderAPI->SetPixelShaderConstant( 8, eyePos, 1 ); + pShaderAPI->SetPixelShaderFogParams( 11 ); + + + + if( bHasFlowmap ) + { + float curTime = pShaderAPI->CurrentTime(); + float timeVec[4] = { curTime, curTime, curTime, curTime }; + pShaderAPI->SetPixelShaderConstant( 6, timeVec, 1 ); + + SetPixelShaderConstant( 7, FLOWMAPSCROLLRATE ); + + SetPixelShaderConstant( 9, FLOWMAPTEXCOORDOFFSET ); + } + +#ifdef MAPBASE + SetPixelShaderConstant( 12, SPHERECENTER ); + SetPixelShaderConstant( 15, SPHERERADIUS ); +#endif + } + Draw(); + } + + SHADER_DRAW + { + DrawPass( params, pShaderShadow, pShaderAPI, 0, vertexCompression ); + DrawPass( params, pShaderShadow, pShaderAPI, 1, vertexCompression ); + } +END_SHADER + diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20.inc new file mode 100644 index 00000000..d6701fc7 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20.inc @@ -0,0 +1,162 @@ +#include "shaderlib/cshader.h" +class sdk_core_ps20_Static_Index +{ +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nFLOWMAP; +#ifdef _DEBUG + bool m_bFLOWMAP; +#endif +public: + void SetFLOWMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLOWMAP = i; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } + void SetFLOWMAP( bool i ) + { + m_nFLOWMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } +private: + int m_nCORECOLORTEXTURE; +#ifdef _DEBUG + bool m_bCORECOLORTEXTURE; +#endif +public: + void SetCORECOLORTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCORECOLORTEXTURE = i; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } + void SetCORECOLORTEXTURE( bool i ) + { + m_nCORECOLORTEXTURE = i ? 1 : 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } +private: + int m_nREFRACT; +#ifdef _DEBUG + bool m_bREFRACT; +#endif +public: + void SetREFRACT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nREFRACT = i; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } + void SetREFRACT( bool i ) + { + m_nREFRACT = i ? 1 : 0; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } +public: + sdk_core_ps20_Static_Index( ) + { +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bFLOWMAP = false; +#endif // _DEBUG + m_nFLOWMAP = 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = false; +#endif // _DEBUG + m_nCORECOLORTEXTURE = 0; +#ifdef _DEBUG + m_bREFRACT = false; +#endif // _DEBUG + m_nREFRACT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCUBEMAP && m_bFLOWMAP && m_bCORECOLORTEXTURE && m_bREFRACT; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 2 * m_nCUBEMAP ) + ( 4 * m_nFLOWMAP ) + ( 8 * m_nCORECOLORTEXTURE ) + ( 16 * m_nREFRACT ) + 0; + } +}; +#define shaderStaticTest_sdk_core_ps20 psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_FLOWMAP + psh_forgot_to_set_static_CORECOLORTEXTURE + psh_forgot_to_set_static_REFRACT + 0 +class sdk_core_ps20_Dynamic_Index +{ +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +public: + sdk_core_ps20_Dynamic_Index() + { +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bPIXELFOGTYPE; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nPIXELFOGTYPE ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_ps20 psh_forgot_to_set_dynamic_PIXELFOGTYPE + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20b.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20b.inc new file mode 100644 index 00000000..9b9a843d --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20b.inc @@ -0,0 +1,187 @@ +#include "shaderlib/cshader.h" +class sdk_core_ps20b_Static_Index +{ +private: + int m_nCONVERT_TO_SRGB; +#ifdef _DEBUG + bool m_bCONVERT_TO_SRGB; +#endif +public: + void SetCONVERT_TO_SRGB( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCONVERT_TO_SRGB = i; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } + void SetCONVERT_TO_SRGB( bool i ) + { + m_nCONVERT_TO_SRGB = i ? 1 : 0; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nFLOWMAP; +#ifdef _DEBUG + bool m_bFLOWMAP; +#endif +public: + void SetFLOWMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLOWMAP = i; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } + void SetFLOWMAP( bool i ) + { + m_nFLOWMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } +private: + int m_nCORECOLORTEXTURE; +#ifdef _DEBUG + bool m_bCORECOLORTEXTURE; +#endif +public: + void SetCORECOLORTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCORECOLORTEXTURE = i; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } + void SetCORECOLORTEXTURE( bool i ) + { + m_nCORECOLORTEXTURE = i ? 1 : 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } +private: + int m_nREFRACT; +#ifdef _DEBUG + bool m_bREFRACT; +#endif +public: + void SetREFRACT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nREFRACT = i; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } + void SetREFRACT( bool i ) + { + m_nREFRACT = i ? 1 : 0; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } +public: + sdk_core_ps20b_Static_Index( ) + { +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif // _DEBUG + m_nCONVERT_TO_SRGB = g_pHardwareConfig->NeedsShaderSRGBConversion(); +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bFLOWMAP = false; +#endif // _DEBUG + m_nFLOWMAP = 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = false; +#endif // _DEBUG + m_nCORECOLORTEXTURE = 0; +#ifdef _DEBUG + m_bREFRACT = false; +#endif // _DEBUG + m_nREFRACT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCONVERT_TO_SRGB && m_bCUBEMAP && m_bFLOWMAP && m_bCORECOLORTEXTURE && m_bREFRACT; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 2 * m_nCONVERT_TO_SRGB ) + ( 4 * m_nCUBEMAP ) + ( 8 * m_nFLOWMAP ) + ( 16 * m_nCORECOLORTEXTURE ) + ( 32 * m_nREFRACT ) + 0; + } +}; +#define shaderStaticTest_sdk_core_ps20b psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_FLOWMAP + psh_forgot_to_set_static_CORECOLORTEXTURE + psh_forgot_to_set_static_REFRACT + 0 +class sdk_core_ps20b_Dynamic_Index +{ +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +public: + sdk_core_ps20b_Dynamic_Index() + { +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bPIXELFOGTYPE; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nPIXELFOGTYPE ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_ps20b psh_forgot_to_set_dynamic_PIXELFOGTYPE + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_vs20.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_vs20.inc new file mode 100644 index 00000000..ef6a680c --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_vs20.inc @@ -0,0 +1,112 @@ +#include "shaderlib/cshader.h" +class sdk_core_vs20_Static_Index +{ +private: + int m_nMODEL; +#ifdef _DEBUG + bool m_bMODEL; +#endif +public: + void SetMODEL( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nMODEL = i; +#ifdef _DEBUG + m_bMODEL = true; +#endif + } + void SetMODEL( bool i ) + { + m_nMODEL = i ? 1 : 0; +#ifdef _DEBUG + m_bMODEL = true; +#endif + } +public: + sdk_core_vs20_Static_Index( ) + { +#ifdef _DEBUG + m_bMODEL = false; +#endif // _DEBUG + m_nMODEL = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bMODEL; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 4 * m_nMODEL ) + 0; + } +}; +#define shaderStaticTest_sdk_core_vs20 vsh_forgot_to_set_static_MODEL + 0 +class sdk_core_vs20_Dynamic_Index +{ +private: + int m_nCOMPRESSED_VERTS; +#ifdef _DEBUG + bool m_bCOMPRESSED_VERTS; +#endif +public: + void SetCOMPRESSED_VERTS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCOMPRESSED_VERTS = i; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } + void SetCOMPRESSED_VERTS( bool i ) + { + m_nCOMPRESSED_VERTS = i ? 1 : 0; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } +private: + int m_nSKINNING; +#ifdef _DEBUG + bool m_bSKINNING; +#endif +public: + void SetSKINNING( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSKINNING = i; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } + void SetSKINNING( bool i ) + { + m_nSKINNING = i ? 1 : 0; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } +public: + sdk_core_vs20_Dynamic_Index() + { +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = false; +#endif // _DEBUG + m_nCOMPRESSED_VERTS = 0; +#ifdef _DEBUG + m_bSKINNING = false; +#endif // _DEBUG + m_nSKINNING = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bCOMPRESSED_VERTS && m_bSKINNING; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nCOMPRESSED_VERTS ) + ( 2 * m_nSKINNING ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_vs20 vsh_forgot_to_set_dynamic_COMPRESSED_VERTS + vsh_forgot_to_set_dynamic_SKINNING + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20.inc new file mode 100644 index 00000000..d6701fc7 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20.inc @@ -0,0 +1,162 @@ +#include "shaderlib/cshader.h" +class sdk_core_ps20_Static_Index +{ +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nFLOWMAP; +#ifdef _DEBUG + bool m_bFLOWMAP; +#endif +public: + void SetFLOWMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLOWMAP = i; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } + void SetFLOWMAP( bool i ) + { + m_nFLOWMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } +private: + int m_nCORECOLORTEXTURE; +#ifdef _DEBUG + bool m_bCORECOLORTEXTURE; +#endif +public: + void SetCORECOLORTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCORECOLORTEXTURE = i; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } + void SetCORECOLORTEXTURE( bool i ) + { + m_nCORECOLORTEXTURE = i ? 1 : 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } +private: + int m_nREFRACT; +#ifdef _DEBUG + bool m_bREFRACT; +#endif +public: + void SetREFRACT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nREFRACT = i; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } + void SetREFRACT( bool i ) + { + m_nREFRACT = i ? 1 : 0; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } +public: + sdk_core_ps20_Static_Index( ) + { +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bFLOWMAP = false; +#endif // _DEBUG + m_nFLOWMAP = 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = false; +#endif // _DEBUG + m_nCORECOLORTEXTURE = 0; +#ifdef _DEBUG + m_bREFRACT = false; +#endif // _DEBUG + m_nREFRACT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCUBEMAP && m_bFLOWMAP && m_bCORECOLORTEXTURE && m_bREFRACT; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 2 * m_nCUBEMAP ) + ( 4 * m_nFLOWMAP ) + ( 8 * m_nCORECOLORTEXTURE ) + ( 16 * m_nREFRACT ) + 0; + } +}; +#define shaderStaticTest_sdk_core_ps20 psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_FLOWMAP + psh_forgot_to_set_static_CORECOLORTEXTURE + psh_forgot_to_set_static_REFRACT + 0 +class sdk_core_ps20_Dynamic_Index +{ +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +public: + sdk_core_ps20_Dynamic_Index() + { +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bPIXELFOGTYPE; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nPIXELFOGTYPE ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_ps20 psh_forgot_to_set_dynamic_PIXELFOGTYPE + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20b.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20b.inc new file mode 100644 index 00000000..9b9a843d --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20b.inc @@ -0,0 +1,187 @@ +#include "shaderlib/cshader.h" +class sdk_core_ps20b_Static_Index +{ +private: + int m_nCONVERT_TO_SRGB; +#ifdef _DEBUG + bool m_bCONVERT_TO_SRGB; +#endif +public: + void SetCONVERT_TO_SRGB( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCONVERT_TO_SRGB = i; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } + void SetCONVERT_TO_SRGB( bool i ) + { + m_nCONVERT_TO_SRGB = i ? 1 : 0; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nFLOWMAP; +#ifdef _DEBUG + bool m_bFLOWMAP; +#endif +public: + void SetFLOWMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLOWMAP = i; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } + void SetFLOWMAP( bool i ) + { + m_nFLOWMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } +private: + int m_nCORECOLORTEXTURE; +#ifdef _DEBUG + bool m_bCORECOLORTEXTURE; +#endif +public: + void SetCORECOLORTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCORECOLORTEXTURE = i; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } + void SetCORECOLORTEXTURE( bool i ) + { + m_nCORECOLORTEXTURE = i ? 1 : 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } +private: + int m_nREFRACT; +#ifdef _DEBUG + bool m_bREFRACT; +#endif +public: + void SetREFRACT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nREFRACT = i; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } + void SetREFRACT( bool i ) + { + m_nREFRACT = i ? 1 : 0; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } +public: + sdk_core_ps20b_Static_Index( ) + { +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif // _DEBUG + m_nCONVERT_TO_SRGB = g_pHardwareConfig->NeedsShaderSRGBConversion(); +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bFLOWMAP = false; +#endif // _DEBUG + m_nFLOWMAP = 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = false; +#endif // _DEBUG + m_nCORECOLORTEXTURE = 0; +#ifdef _DEBUG + m_bREFRACT = false; +#endif // _DEBUG + m_nREFRACT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCONVERT_TO_SRGB && m_bCUBEMAP && m_bFLOWMAP && m_bCORECOLORTEXTURE && m_bREFRACT; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 2 * m_nCONVERT_TO_SRGB ) + ( 4 * m_nCUBEMAP ) + ( 8 * m_nFLOWMAP ) + ( 16 * m_nCORECOLORTEXTURE ) + ( 32 * m_nREFRACT ) + 0; + } +}; +#define shaderStaticTest_sdk_core_ps20b psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_FLOWMAP + psh_forgot_to_set_static_CORECOLORTEXTURE + psh_forgot_to_set_static_REFRACT + 0 +class sdk_core_ps20b_Dynamic_Index +{ +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +public: + sdk_core_ps20b_Dynamic_Index() + { +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bPIXELFOGTYPE; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nPIXELFOGTYPE ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_ps20b psh_forgot_to_set_dynamic_PIXELFOGTYPE + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_vs20.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_vs20.inc new file mode 100644 index 00000000..ef6a680c --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_vs20.inc @@ -0,0 +1,112 @@ +#include "shaderlib/cshader.h" +class sdk_core_vs20_Static_Index +{ +private: + int m_nMODEL; +#ifdef _DEBUG + bool m_bMODEL; +#endif +public: + void SetMODEL( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nMODEL = i; +#ifdef _DEBUG + m_bMODEL = true; +#endif + } + void SetMODEL( bool i ) + { + m_nMODEL = i ? 1 : 0; +#ifdef _DEBUG + m_bMODEL = true; +#endif + } +public: + sdk_core_vs20_Static_Index( ) + { +#ifdef _DEBUG + m_bMODEL = false; +#endif // _DEBUG + m_nMODEL = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bMODEL; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 4 * m_nMODEL ) + 0; + } +}; +#define shaderStaticTest_sdk_core_vs20 vsh_forgot_to_set_static_MODEL + 0 +class sdk_core_vs20_Dynamic_Index +{ +private: + int m_nCOMPRESSED_VERTS; +#ifdef _DEBUG + bool m_bCOMPRESSED_VERTS; +#endif +public: + void SetCOMPRESSED_VERTS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCOMPRESSED_VERTS = i; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } + void SetCOMPRESSED_VERTS( bool i ) + { + m_nCOMPRESSED_VERTS = i ? 1 : 0; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } +private: + int m_nSKINNING; +#ifdef _DEBUG + bool m_bSKINNING; +#endif +public: + void SetSKINNING( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSKINNING = i; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } + void SetSKINNING( bool i ) + { + m_nSKINNING = i ? 1 : 0; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } +public: + sdk_core_vs20_Dynamic_Index() + { +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = false; +#endif // _DEBUG + m_nCOMPRESSED_VERTS = 0; +#ifdef _DEBUG + m_bSKINNING = false; +#endif // _DEBUG + m_nSKINNING = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bCOMPRESSED_VERTS && m_bSKINNING; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nCOMPRESSED_VERTS ) + ( 2 * m_nSKINNING ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_vs20 vsh_forgot_to_set_dynamic_COMPRESSED_VERTS + vsh_forgot_to_set_dynamic_SKINNING + 0 diff --git a/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc b/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc index 40d64143..d6a8480d 100644 --- a/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc +++ b/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc @@ -64,6 +64,8 @@ $Project $File "engine_post_dx9.cpp" $File "depthoffield_dx9.cpp" + + $File "core_dx9.cpp" } //$Shaders "mapbase_dx9_20b.txt" diff --git a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp index b2a8ddcc..6f64a15d 100644 --- a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp +++ b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp @@ -1566,9 +1566,10 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar** // Doing it here in the shader itself allows us to retain other properties, like FANCY_BLENDING. else { - // m_SemiStaticCmdsOut wasn't being sent correctly, so we have to assign this to the API directly - float editorBlend = bEditorBlend ? 1.0f : 0.0f; - pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 21, &editorBlend, 1 ); + // TODO: This is inefficient use of a constant; Something should be done about this in the future + static const float editorBlend[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + static const float regularBlend[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 21, (bEditorBlend ? editorBlend : regularBlend), 1 ); /* if (bEditorBlend) { diff --git a/sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp b/sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp index 99ac7914..d24ac04b 100644 --- a/sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp +++ b/sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp @@ -7,9 +7,9 @@ #include "BaseVSShader.h" #include "cpp_shader_constant_register_map.h" -#include "sdk_windowimposter_vs20.inc" -#include "sdk_windowimposter_ps20.inc" -#include "sdk_windowimposter_ps20b.inc" +#include "SDK_windowimposter_vs20.inc" +#include "SDK_windowimposter_ps20.inc" +#include "SDK_windowimposter_ps20b.inc" diff --git a/sp/src/public/tier1/convar.h b/sp/src/public/tier1/convar.h index 2c364727..37268cc4 100644 --- a/sp/src/public/tier1/convar.h +++ b/sp/src/public/tier1/convar.h @@ -21,7 +21,7 @@ #include "tier1/utlvector.h" #include "tier1/utlstring.h" #include "icvar.h" -#include "color.h" +#include "Color.h" #ifdef _WIN32 #define FORCEINLINE_CVAR FORCEINLINE @@ -301,6 +301,10 @@ private: ICommandCallback *m_pCommandCallback; }; +#ifdef MAPBASE_VSCRIPT + // Allow late modification of the completion callback. +public: +#endif union { FnCommandCompletionCallback m_fnCompletionCallback; @@ -308,6 +312,9 @@ private: }; bool m_bHasCompletionCallback : 1; +#ifdef MAPBASE_VSCRIPT +private: +#endif bool m_bUsingNewCommandCallback : 1; bool m_bUsingCommandCallbackInterface : 1; }; diff --git a/sp/src/public/tier1/mapbase_con_groups.h b/sp/src/public/tier1/mapbase_con_groups.h index c0e35626..cdd955c9 100644 --- a/sp/src/public/tier1/mapbase_con_groups.h +++ b/sp/src/public/tier1/mapbase_con_groups.h @@ -17,21 +17,23 @@ //static const Color CON_COLOR_DEV_VERBOSE( 192, 128, 192, 255 ); // General -#define CON_GROUP_MAPBASE_MISC "Mapbase Misc." -#define CON_GROUP_PHYSICS "Physics" +#define CON_GROUP_MAPBASE_MISC 0 // "Mapbase Misc." +#define CON_GROUP_PHYSICS 1 // "Physics" // Server -#define CON_GROUP_IO_SYSTEM "I/O System" -#define CON_GROUP_NPC_AI "NPC AI" -#define CON_GROUP_NPC_SCRIPTS "NPC Scripts" -#define CON_GROUP_CHOREO "Choreo" +#define CON_GROUP_IO_SYSTEM 2 // "Entity I/O" +#define CON_GROUP_NPC_AI 3 // "NPC AI" +#define CON_GROUP_NPC_SCRIPTS 4 // "NPC Scripts" +#define CON_GROUP_CHOREO 5 // "Choreo" // VScript -#define CON_GROUP_VSCRIPT "VScript" -#define CON_GROUP_VSCRIPT_PRINT "VScript Print" +#define CON_GROUP_VSCRIPT 6 // "VScript" +#define CON_GROUP_VSCRIPT_PRINT 7 // "VScript Print" + +#define CON_GROUP_MAX 8 // must always be at the end // Mapbase console group message. -void CGMsg( int level, const char *pszGroup, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +void CGMsg( int level, int nGroup, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 ); #define CGWarning CGMsg diff --git a/sp/src/public/vgui/MouseCode.h b/sp/src/public/vgui/MouseCode.h index 7ba16214..9b13fc81 100644 --- a/sp/src/public/vgui/MouseCode.h +++ b/sp/src/public/vgui/MouseCode.h @@ -18,6 +18,15 @@ namespace vgui { typedef ButtonCode_t MouseCode; + +static inline int MouseButtonBit(MouseCode code) +{ + if (code < MOUSE_FIRST || code > MOUSE_LAST) { + Assert(false); + return 0; + } + return 1 << (code - MOUSE_FIRST); +} } #endif // MOUSECODE_H diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index a1c1e856..b2750f5c 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -95,6 +95,9 @@ #ifndef IVSCRIPT_H #define IVSCRIPT_H +#include +#include + #include "platform.h" #include "datamap.h" #include "appframework/IAppSystem.h" @@ -163,20 +166,6 @@ public: // //----------------------------------------------------------------------------- -#ifdef MAPBASE_VSCRIPT -template T *HScriptToClass( HSCRIPT hObj ) -{ - return (hObj) ? (T*)g_pScriptVM->GetInstanceValue( hObj, GetScriptDesc( (T*)NULL ) ) : NULL; -} -#else -DECLARE_POINTER_HANDLE( HSCRIPT ); -#define INVALID_HSCRIPT ((HSCRIPT)-1) -#endif - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- - enum ExtendedFieldType { FIELD_TYPEUNKNOWN = FIELD_TYPECOUNT, @@ -645,8 +634,21 @@ struct ScriptEnumDesc_t // //----------------------------------------------------------------------------- +// forwards T (and T&) if T is neither enum or an unsigned integer +// the overload for int below captures enums and unsigned integers and "bends" them to int +template +static inline typename std::enable_if::type>::value && !std::is_unsigned::type>::value, T&&>::type ToConstantVariant(T &&value) +{ + return std::forward(value); +} + +static inline int ToConstantVariant(int value) +{ + return value; +} + #define ScriptRegisterConstant( pVM, constant, description ) ScriptRegisterConstantNamed( pVM, constant, #constant, description ) -#define ScriptRegisterConstantNamed( pVM, constant, scriptName, description ) do { static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = constant; pVM->RegisterConstant( &binding ); } while (0) +#define ScriptRegisterConstantNamed( pVM, constant, scriptName, description ) do { static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = ToConstantVariant(constant); pVM->RegisterConstant( &binding ); } while (0) // Could probably use a better name. // This is used for registering variants (particularly vectors) not tied to existing variables. @@ -749,9 +751,6 @@ struct ScriptEnumDesc_t #define DEFINE_SCRIPTHOOK_PARAM( paramName, type ) pHook->AddParameter( paramName, type ); -// Define actual parameters instead of global variables -#define DEFINE_SCRIPTHOOK_REALPARAM( paramName, type ) - #define END_SCRIPTHOOK() \ pDesc->m_Hooks.AddToTail(pHook); \ } @@ -944,7 +943,7 @@ public: #endif #ifdef MAPBASE_VSCRIPT - // virtual void CreateArray(ScriptVariant_t &arr, int size = 0) = 0; + virtual void CreateArray(ScriptVariant_t &arr, int size = 0) = 0; virtual bool ArrayAppend(HSCRIPT hArray, const ScriptVariant_t &val) = 0; #endif @@ -1093,6 +1092,20 @@ public: #endif }; +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +#ifdef MAPBASE_VSCRIPT +template T *HScriptToClass( HSCRIPT hObj ) +{ + extern IScriptVM *g_pScriptVM; + return (hObj) ? (T*)g_pScriptVM->GetInstanceValue( hObj, GetScriptDesc( (T*)NULL ) ) : NULL; +} +#else +DECLARE_POINTER_HANDLE( HSCRIPT ); +#define INVALID_HSCRIPT ((HSCRIPT)-1) +#endif //----------------------------------------------------------------------------- // Script scope helper class diff --git a/sp/src/public/vscript/vscript_templates.h b/sp/src/public/vscript/vscript_templates.h index e23a9fe9..2d7058a3 100644 --- a/sp/src/public/vscript/vscript_templates.h +++ b/sp/src/public/vscript/vscript_templates.h @@ -137,29 +137,25 @@ inline void *ScriptConvertFuncPtrToVoid( FUNCPTR_TYPE pFunc ) #elif defined( GNUC ) else if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + sizeof( int ) ) ) { - AssertMsg( 0, "Note: This path has not been verified yet. See comments below in #else case." ); - struct GnuMFP { union { void *funcadr; // If vtable_index_2 is even, then this is the function pointer. - int vtable_index_2; // If vtable_index_2 is odd, then this = vindex*2+1. + int vtable_index_2; // If vtable_index_2 is odd, then (vtable_index_2 - 1) * 2 is the index into the vtable. }; - int delta; + int delta; // Offset from this-ptr to vtable }; - + GnuMFP *p = (GnuMFP*)&pFunc; - if ( p->vtable_index_2 & 1 ) - { - char **delta = (char**)p->delta; - char *pCur = *delta + (p->vtable_index_2+1)/2; - return (void*)( pCur + 4 ); - } - else + if ( p->delta == 0 ) { + // No need to check whether this is a direct function pointer or not, + // this gets converted back to a "proper" member-function pointer in + // ScriptConvertFuncPtrFromVoid() to get invoked return p->funcadr; } + AssertMsg( 0, "Function pointer must be from primary vtable" ); } #else #error "Need to implement code to crack non-offset member function pointer case" @@ -257,8 +253,30 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p ) convert.mfp.m_delta = 0; return convert.pFunc; } -#elif defined( POSIX ) - AssertMsg( 0, "Note: This path has not been implemented yet." ); +#elif defined( GNUC ) + if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + sizeof( int ) ) ) + { + struct GnuMFP + { + union + { + void *funcadr; // If vtable_index_2 is even, then this is the function pointer. + int vtable_index_2; // If vtable_index_2 is odd, then (vtable_index_2 - 1) * 2 is the index into the vtable. + }; + int delta; // Offset from this-ptr to vtable + }; + + union FuncPtrConvertGnu + { + GnuMFP mfp; + FUNCPTR_TYPE pFunc; + }; + + FuncPtrConvertGnu convert; + convert.mfp.funcadr = p; + convert.mfp.delta = 0; + return convert.pFunc; + } #else #error "Need to implement code to crack non-offset member function pointer case" #endif diff --git a/sp/src/tier1/mapbase_con_groups.cpp b/sp/src/tier1/mapbase_con_groups.cpp index 533d5791..08ca8fc7 100644 --- a/sp/src/tier1/mapbase_con_groups.cpp +++ b/sp/src/tier1/mapbase_con_groups.cpp @@ -65,46 +65,35 @@ DEFINE_CON_GROUP_CVAR( vscript_print, "80 186 255", "Messages from VScript's 'pr //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -#define DEFINE_CON_GROUP(name, codename) { name, &con_group_##codename##_color } +#define DEFINE_CON_GROUP(id, name, codename) { name, &con_group_##codename##_color } -ConGroup_t g_ConGroups[] = { +ConGroup_t g_ConGroups[CON_GROUP_MAX] = { // General - DEFINE_CON_GROUP( CON_GROUP_MAPBASE_MISC, mapbase_misc ), - DEFINE_CON_GROUP( CON_GROUP_PHYSICS, physics ), + DEFINE_CON_GROUP( CON_GROUP_MAPBASE_MISC, "Mapbase misc.", mapbase_misc ), + DEFINE_CON_GROUP( CON_GROUP_PHYSICS, "Physics", physics ), // Server - DEFINE_CON_GROUP( CON_GROUP_IO_SYSTEM, inputoutput ), - DEFINE_CON_GROUP( CON_GROUP_NPC_AI, npc_ai ), - DEFINE_CON_GROUP( CON_GROUP_NPC_SCRIPTS, npc_scripts ), - DEFINE_CON_GROUP( CON_GROUP_CHOREO, choreo ), + DEFINE_CON_GROUP( CON_GROUP_IO_SYSTEM, "Entity IO", inputoutput ), + DEFINE_CON_GROUP( CON_GROUP_NPC_AI, "NPC AI", npc_ai ), + DEFINE_CON_GROUP( CON_GROUP_NPC_SCRIPTS, "NPC scripts", npc_scripts ), + DEFINE_CON_GROUP( CON_GROUP_CHOREO, "Choreo", choreo ), // VScript - DEFINE_CON_GROUP( CON_GROUP_VSCRIPT, vscript ), - DEFINE_CON_GROUP( CON_GROUP_VSCRIPT_PRINT, vscript_print ), + DEFINE_CON_GROUP( CON_GROUP_VSCRIPT, "VScript", vscript ), + DEFINE_CON_GROUP( CON_GROUP_VSCRIPT_PRINT, "VScript print", vscript_print ), }; void CV_ColorChanged( IConVar *pConVar, const char *pOldString, float flOldValue ) { - for (int i = 0; i < ARRAYSIZE( g_ConGroups ); i++) + for (int i = 0; i < CON_GROUP_MAX; i++) { // Reset the alpha to indicate it needs to be refreshed g_ConGroups[i]._clr[3] = 0; } } -ConGroup_t *FindConGroup( const char *pszGroup ) -{ - for (int i = 0; i < ARRAYSIZE( g_ConGroups ); i++) - { - if (V_strcmp(pszGroup, g_ConGroups[i].pszName) == 0) - return &g_ConGroups[i]; - } - - return NULL; -} - //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -113,7 +102,7 @@ ConVar con_group_include_name( "con_group_include_name", "0", FCVAR_NONE, "Inclu CON_COMMAND( con_group_list, "Prints a list of all console groups." ) { Msg( "============================================================\n" ); - for (int i = 0; i < ARRAYSIZE( g_ConGroups ); i++) + for (int i = 0; i < CON_GROUP_MAX; i++) { Msg( " # " ); ConColorMsg( g_ConGroups[i].GetColor(), "%s", g_ConGroups[i].pszName ); @@ -146,7 +135,7 @@ CON_COMMAND( con_group_toggle, "Toggles a console group." ) } */ -void CGMsg( int level, const char *pszGroup, const tchar* pMsg, ... ) +void CGMsg( int level, int nGroup, const tchar* pMsg, ... ) { // Return early if we're not at this level if (!IsSpewActive("developer", level)) @@ -158,22 +147,21 @@ void CGMsg( int level, const char *pszGroup, const tchar* pMsg, ... ) Q_vsnprintf( string, sizeof(string), pMsg, argptr ); va_end( argptr ); - ConGroup_t *pGroup = FindConGroup( pszGroup ); - if (pGroup) + Assert( nGroup >= 0 ); + Assert( nGroup < CON_GROUP_MAX ); + + ConGroup_t *pGroup = &g_ConGroups[nGroup]; + + /*if (pGroup->bDisabled) { - /*if (pGroup->bDisabled) - { - // Do nothing - } - else*/ if (con_group_include_name.GetBool()) - { - ConColorMsg( level, pGroup->GetColor(), "[%s] %s", pGroup->pszName, string ); - } - else - { - ConColorMsg( level, pGroup->GetColor(), string ); - } + // Do nothing + } + else*/ if (con_group_include_name.GetBool()) + { + ConColorMsg(level, pGroup->GetColor(), "[%s] %s", pGroup->pszName, string); } else - DevMsg( level, string ); + { + ConColorMsg(level, pGroup->GetColor(), "%s", string); + } } diff --git a/sp/src/utils/vbsp/vscript_funcs_vmfs.cpp b/sp/src/utils/vbsp/vscript_funcs_vmfs.cpp index 3894ddf3..8ef38c81 100644 --- a/sp/src/utils/vbsp/vscript_funcs_vmfs.cpp +++ b/sp/src/utils/vbsp/vscript_funcs_vmfs.cpp @@ -83,6 +83,7 @@ static HSCRIPT VMFKV_LoadFromFile( const char *szFile ) KeyValues *pKV = new KeyValues( szFile ); if ( !pKV->LoadFromFile( g_pFullFileSystem, pszFullName, NULL ) ) { + pKV->deleteThis(); return NULL; } diff --git a/sp/src/utils/vbsp/vscript_vbsp.cpp b/sp/src/utils/vbsp/vscript_vbsp.cpp index 91fa41f6..c8295e02 100644 --- a/sp/src/utils/vbsp/vscript_vbsp.cpp +++ b/sp/src/utils/vbsp/vscript_vbsp.cpp @@ -11,6 +11,7 @@ #include "vbsp.h" #include "map.h" #include "fgdlib/fgdlib.h" +#include "convar.h" #include "vscript_vbsp.h" #include "vscript_vbsp.nut" @@ -183,6 +184,28 @@ BEGIN_SCRIPTDESC_ROOT( CMapFile, "Map file" ) END_SCRIPTDESC(); + +static float cvar_getf( const char* sz ) +{ + ConVarRef cvar(sz); + if ( cvar.IsFlagSet( FCVAR_SERVER_CANNOT_QUERY ) ) + return NULL; + return cvar.GetFloat(); +} + +static bool cvar_setf( const char* sz, float val ) +{ + ConVarRef cvar(sz); + if ( !cvar.IsValid() ) + return false; + + if ( cvar.IsFlagSet( FCVAR_SERVER_CANNOT_QUERY ) ) + return false; + + cvar.SetValue(val); + return true; +} + static const char *GetSource() { return source; @@ -244,6 +267,9 @@ bool VScriptVBSPInit() { Log( "VSCRIPT VBSP: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); + ScriptRegisterFunction( g_pScriptVM, cvar_getf, "Gets the value of the given cvar, as a float." ); + ScriptRegisterFunction( g_pScriptVM, cvar_setf, "Sets the value of the given cvar, as a float." ); + ScriptRegisterFunction( g_pScriptVM, GetSource, "Gets the base directory of the first map loaded." ); ScriptRegisterFunction( g_pScriptVM, GetMapBase, "Gets the base name of the first map loaded." ); ScriptRegisterFunction( g_pScriptVM, GetMainMap, "Gets the first map loaded." ); diff --git a/sp/src/vgui2/vgui_controls/Button.cpp b/sp/src/vgui2/vgui_controls/Button.cpp index cceb8043..406c3e13 100644 --- a/sp/src/vgui2/vgui_controls/Button.cpp +++ b/sp/src/vgui2/vgui_controls/Button.cpp @@ -695,12 +695,12 @@ void Button::SetMouseClickEnabled(MouseCode code,bool state) if(state) { //set bit to 1 - _mouseClickMask|=1<<((int)(code+1)); + _mouseClickMask|=MouseButtonBit(code); } else { //set bit to 0 - _mouseClickMask&=~(1<<((int)(code+1))); + _mouseClickMask&=~MouseButtonBit(code); } } @@ -709,7 +709,7 @@ void Button::SetMouseClickEnabled(MouseCode code,bool state) //----------------------------------------------------------------------------- bool Button::IsMouseClickEnabled(MouseCode code) { - if(_mouseClickMask&(1<<((int)(code+1)))) + if(_mouseClickMask&MouseButtonBit(code)) { return true; } diff --git a/sp/src/vscript/vscript_bindings_base.cpp b/sp/src/vscript/vscript_bindings_base.cpp index 56da8435..9511efa4 100644 --- a/sp/src/vscript/vscript_bindings_base.cpp +++ b/sp/src/vscript/vscript_bindings_base.cpp @@ -50,100 +50,6 @@ static void ScriptColorPrintL( int r, int g, int b, const char *pszMsg ) ConColorMsg( clr, "%s\n", pszMsg ); } -//============================================================================= -// -// Convar Lookup -// -//============================================================================= -class CScriptConvarLookup -{ -public: - - float GetFloat( const char *pszConVar ) - { - ConVarRef cvar( pszConVar ); - return cvar.GetFloat(); - } - - int GetInt( const char *pszConVar ) - { - ConVarRef cvar( pszConVar ); - return cvar.GetInt(); - } - - bool GetBool( const char *pszConVar ) - { - ConVarRef cvar( pszConVar ); - return cvar.GetBool(); - } - - const char *GetStr( const char *pszConVar ) - { - ConVarRef cvar( pszConVar ); - return cvar.GetString(); - } - - const char *GetDefaultValue( const char *pszConVar ) - { - ConVarRef cvar( pszConVar ); - return cvar.GetDefault(); - } - - bool IsFlagSet( const char *pszConVar, int nFlags ) - { - ConVarRef cvar( pszConVar ); - return cvar.IsFlagSet( nFlags ); - } - - void SetFloat( const char *pszConVar, float value ) - { - SetValue( pszConVar, value ); - } - - void SetInt( const char *pszConVar, int value ) - { - SetValue( pszConVar, value ); - } - - void SetBool( const char *pszConVar, bool value ) - { - SetValue( pszConVar, value ); - } - - void SetStr( const char *pszConVar, const char *value ) - { - SetValue( pszConVar, value ); - } - - template - void SetValue( const char *pszConVar, T value ) - { - 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( value ); - } - -private: -} g_ScriptConvarLookup; - -BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptConvarLookup, "CConvars", SCRIPT_SINGLETON "Provides an interface for getting and setting convars." ) - DEFINE_SCRIPTFUNC( GetFloat, "Returns the convar as a float. May return null if no such convar." ) - DEFINE_SCRIPTFUNC( GetInt, "Returns the convar as an int. May return null if no such convar." ) - DEFINE_SCRIPTFUNC( GetBool, "Returns the convar as a bool. May return null if no such convar." ) - DEFINE_SCRIPTFUNC( GetStr, "Returns the convar as a string. May return null if no such convar." ) - DEFINE_SCRIPTFUNC( GetDefaultValue, "Returns the convar's default value as a string. May return null if no such convar." ) - DEFINE_SCRIPTFUNC( IsFlagSet, "Returns the convar's flags. May return null if no such convar." ) - DEFINE_SCRIPTFUNC( SetFloat, "Sets the value of the convar as a float." ) - DEFINE_SCRIPTFUNC( SetInt, "Sets the value of the convar as an int." ) - DEFINE_SCRIPTFUNC( SetBool, "Sets the value of the convar as a bool." ) - DEFINE_SCRIPTFUNC( SetStr, "Sets the value of the convar as a string." ) -END_SCRIPTDESC(); //============================================================================= // @@ -203,6 +109,7 @@ BEGIN_SCRIPTDESC_ROOT( CScriptKeyValues, "Wrapper class over KeyValues instance" DEFINE_SCRIPTFUNC_NAMED( ScriptReleaseKeyValues, "ReleaseKeyValues", "Given a root KeyValues object, release its contents" ); DEFINE_SCRIPTFUNC( TableToSubKeys, "Converts a script table to KeyValues." ); + DEFINE_SCRIPTFUNC( SubKeysToTable, "Converts to script table." ); DEFINE_SCRIPTFUNC_NAMED( ScriptFindOrCreateKey, "FindOrCreateKey", "Given a KeyValues object and a key name, find or create a KeyValues object associated with the key name" ); @@ -319,6 +226,19 @@ void CScriptKeyValues::TableToSubKeys( HSCRIPT hTable ) } } +void CScriptKeyValues::SubKeysToTable( HSCRIPT hTable ) +{ + FOR_EACH_SUBKEY( m_pKeyValues, key ) + { + switch ( key->GetDataType() ) + { + case KeyValues::TYPE_STRING: g_pScriptVM->SetValue( hTable, key->GetName(), key->GetString() ); break; + case KeyValues::TYPE_INT: g_pScriptVM->SetValue( hTable, key->GetName(), key->GetInt() ); break; + case KeyValues::TYPE_FLOAT: g_pScriptVM->SetValue( hTable, key->GetName(), key->GetFloat() ); break; + } + } +} + HSCRIPT CScriptKeyValues::ScriptFindOrCreateKey( const char *pszName ) { KeyValues *pKeyValues = m_pKeyValues->FindKey(pszName, true); @@ -529,7 +449,6 @@ void RegisterBaseBindings( IScriptVM *pVM ) //----------------------------------------------------------------------------- - pVM->RegisterInstance( &g_ScriptConvarLookup, "Convars" ); pVM->RegisterInstance( &g_ScriptGlobalSys, "GlobalSys" ); //----------------------------------------------------------------------------- diff --git a/sp/src/vscript/vscript_bindings_base.h b/sp/src/vscript/vscript_bindings_base.h index a2d9fb9a..2629aada 100644 --- a/sp/src/vscript/vscript_bindings_base.h +++ b/sp/src/vscript/vscript_bindings_base.h @@ -35,6 +35,7 @@ public: // Functions below are new with Mapbase void TableToSubKeys( HSCRIPT hTable ); + void SubKeysToTable( HSCRIPT hTable ); HSCRIPT ScriptFindOrCreateKey( const char *pszName ); diff --git a/sp/src/vscript/vscript_bindings_math.cpp b/sp/src/vscript/vscript_bindings_math.cpp index cb6c594d..2f189265 100644 --- a/sp/src/vscript/vscript_bindings_math.cpp +++ b/sp/src/vscript/vscript_bindings_math.cpp @@ -181,7 +181,7 @@ END_SCRIPTDESC(); bool CScriptQuaternionInstanceHelper::ToString( void *p, char *pBuf, int bufSize ) { Quaternion *pQuat = ((Quaternion *)p); - V_snprintf( pBuf, bufSize, "(quaternion: (%f, %f, %f, %f))", pQuat->x, pQuat->y, pQuat->z, pQuat->w ); + V_snprintf( pBuf, bufSize, "(Quaternion %p [%f %f %f %f])", (void*)pQuat, pQuat->x, pQuat->y, pQuat->z, pQuat->w ); return true; } @@ -390,6 +390,11 @@ float ScriptCalcDistanceToLineSegment( const Vector &point, const Vector &vLineA return CalcDistanceToLineSegment( point, vLineA, vLineB ); } +inline float ScriptExponentialDecay( float decayTo, float decayTime, float dt ) +{ + return ExponentialDecay( decayTo, decayTime, dt ); +} + void RegisterMathBaseBindings( IScriptVM *pVM ) { ScriptRegisterConstantNamed( pVM, ((float)(180.f / M_PI_F)), "RAD2DEG", "" ); @@ -453,4 +458,12 @@ void RegisterMathBaseBindings( IScriptVM *pVM ) ScriptRegisterFunctionNamed( pVM, ScriptCalcClosestPointOnLine, "CalcClosestPointOnLine", "Returns the closest point on a line." ); ScriptRegisterFunctionNamed( pVM, ScriptCalcDistanceToLineSegment, "CalcDistanceToLineSegment", "Returns the distance to a line segment." ); ScriptRegisterFunctionNamed( pVM, ScriptCalcClosestPointOnLineSegment, "CalcClosestPointOnLineSegment", "Returns the closest point on a line segment." ); + + ScriptRegisterFunction( pVM, SimpleSplineRemapVal, "remaps a value in [startInterval, startInterval+rangeInterval] from linear to spline using SimpleSpline" ); + ScriptRegisterFunction( pVM, SimpleSplineRemapValClamped, "remaps a value in [startInterval, startInterval+rangeInterval] from linear to spline using SimpleSpline" ); + ScriptRegisterFunction( pVM, Bias, "The curve is biased towards 0 or 1 based on biasAmt, which is between 0 and 1." ); + ScriptRegisterFunction( pVM, Gain, "Gain is similar to Bias, but biasAmt biases towards or away from 0.5." ); + ScriptRegisterFunction( pVM, SmoothCurve, "SmoothCurve maps a 0-1 value into another 0-1 value based on a cosine wave" ); + ScriptRegisterFunction( pVM, SmoothCurve_Tweak, "SmoothCurve peaks at flPeakPos, flPeakSharpness controls the sharpness of the peak" ); + ScriptRegisterFunctionNamed( pVM, ScriptExponentialDecay, "ExponentialDecay", "decayTo is factor the value should decay to in decayTime" ); } diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 2c80041b..afb466f6 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -214,7 +214,7 @@ public: virtual bool ClearValue(HSCRIPT hScope, const char* pszKey) override; virtual bool ClearValue( HSCRIPT hScope, ScriptVariant_t pKey ) override; - // virtual void CreateArray(ScriptVariant_t &arr, int size = 0) override; + virtual void CreateArray(ScriptVariant_t &arr, int size = 0) override; virtual bool ArrayAppend(HSCRIPT hArray, const ScriptVariant_t &val) override; //---------------------------------------------------------------------------- @@ -241,7 +241,7 @@ public: HSQOBJECT regexpClass_; }; -SQUserPointer TYPETAG_VECTOR = "VectorTypeTag"; +static char TYPETAG_VECTOR[] = "VectorTypeTag"; namespace SQVector { @@ -270,7 +270,7 @@ namespace SQVector return 0; } - SQInteger Get(HSQUIRRELVM vm) + SQInteger _get(HSQUIRRELVM vm) { const char* key = nullptr; sq_getstring(vm, 2, &key); @@ -296,7 +296,7 @@ namespace SQVector return 1; } - SQInteger Set(HSQUIRRELVM vm) + SQInteger _set(HSQUIRRELVM vm) { const char* key = nullptr; sq_getstring(vm, 2, &key); @@ -328,7 +328,7 @@ namespace SQVector return 0; } - SQInteger Add(HSQUIRRELVM vm) + SQInteger _add(HSQUIRRELVM vm) { Vector* v1 = nullptr; Vector* v2 = nullptr; @@ -350,7 +350,7 @@ namespace SQVector return 1; } - SQInteger Sub(HSQUIRRELVM vm) + SQInteger _sub(HSQUIRRELVM vm) { Vector* v1 = nullptr; Vector* v2 = nullptr; @@ -372,23 +372,20 @@ namespace SQVector return 1; } - SQInteger Multiply(HSQUIRRELVM vm) + SQInteger _multiply(HSQUIRRELVM vm) { Vector* v1 = nullptr; if (sq_gettop(vm) != 2 || SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR))) { - return sq_throwerror(vm, "Expected (Vector, float) or (Vector, Vector)"); + return sq_throwerror(vm, "Expected (Vector, Vector|float)"); } - SQObjectType paramType = sq_gettype(vm, 2); - float s = 0.0; Vector* v2 = nullptr; - if ((paramType & SQOBJECT_NUMERIC) && - SQ_SUCCEEDED(sq_getfloat(vm, 2, &s))) + if ( SQ_SUCCEEDED(sq_getfloat(vm, 2, &s)) ) { sq_getclass(vm, 1); sq_createinstance(vm, -1); @@ -399,8 +396,7 @@ namespace SQVector return 1; } - else if (paramType == OT_INSTANCE && - SQ_SUCCEEDED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v2, TYPETAG_VECTOR))) + else if ( SQ_SUCCEEDED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v2, TYPETAG_VECTOR)) ) { sq_getclass(vm, 1); sq_createinstance(vm, -1); @@ -413,27 +409,24 @@ namespace SQVector } else { - return sq_throwerror(vm, "Expected (Vector, float) or (Vector, Vector)"); + return sq_throwerror(vm, "Expected (Vector, Vector|float)"); } } - SQInteger Divide(HSQUIRRELVM vm) + SQInteger _divide(HSQUIRRELVM vm) { Vector* v1 = nullptr; if (sq_gettop(vm) != 2 || SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR))) { - return sq_throwerror(vm, "Expected (Vector, float) or (Vector, Vector)"); + return sq_throwerror(vm, "Expected (Vector, Vector|float)"); } - SQObjectType paramType = sq_gettype(vm, 2); - float s = 0.0; Vector* v2 = nullptr; - if ((paramType & SQOBJECT_NUMERIC) && - SQ_SUCCEEDED(sq_getfloat(vm, 2, &s))) + if ( SQ_SUCCEEDED(sq_getfloat(vm, 2, &s)) ) { sq_getclass(vm, 1); sq_createinstance(vm, -1); @@ -444,8 +437,7 @@ namespace SQVector return 1; } - else if (paramType == OT_INSTANCE && - SQ_SUCCEEDED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v2, TYPETAG_VECTOR))) + else if ( SQ_SUCCEEDED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v2, TYPETAG_VECTOR)) ) { sq_getclass(vm, 1); sq_createinstance(vm, -1); @@ -458,10 +450,226 @@ namespace SQVector } else { - return sq_throwerror(vm, "Expected (Vector, float) or (Vector, Vector)"); + return sq_throwerror(vm, "Expected (Vector, Vector|float)"); } } + SQInteger _unm(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + + if (sq_gettop(vm) != 1 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR))) + { + return sq_throwerror(vm, "Expected (Vector)"); + } + + sq_getclass(vm, 1); + sq_createinstance(vm, -1); + SQUserPointer p; + sq_getinstanceup(vm, -1, &p, 0); + new(p) Vector(-v1->x, -v1->y, -v1->z); + sq_remove(vm, -2); + + return 1; + } + + // multi purpose - copy from input vector, or init with 3 float input + SQInteger Set(HSQUIRRELVM vm) + { + SQInteger top = sq_gettop(vm); + Vector* v1 = nullptr; + + if ( top < 2 || SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) ) + { + return sq_throwerror(vm, "Expected (Vector, Vector)"); + } + + Vector* v2 = nullptr; + + if ( SQ_SUCCEEDED(sq_getinstanceup(vm, 2, (SQUserPointer*)&v2, TYPETAG_VECTOR)) ) + { + if ( top != 2 ) + return sq_throwerror(vm, "Expected (Vector, Vector)"); + + VectorCopy( *v2, *v1 ); + sq_remove( vm, -1 ); + + return 1; + } + + float x, y, z; + + if ( top == 4 && + SQ_SUCCEEDED(sq_getfloat(vm, 2, &x)) && + SQ_SUCCEEDED(sq_getfloat(vm, 3, &y)) && + SQ_SUCCEEDED(sq_getfloat(vm, 4, &z)) ) + { + v1->Init( x, y, z ); + sq_pop( vm, 3 ); + + return 1; + } + + return sq_throwerror(vm, "Expected (Vector, Vector)"); + } + + SQInteger Add(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + Vector* v2 = nullptr; + + if (sq_gettop(vm) != 2 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) || + SQ_FAILED(sq_getinstanceup(vm, 2, (SQUserPointer*)&v2, TYPETAG_VECTOR))) + { + return sq_throwerror(vm, "Expected (Vector, Vector)"); + } + + VectorAdd( *v1, *v2, *v1 ); + sq_remove( vm, -1 ); + + return 1; + } + + SQInteger Subtract(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + Vector* v2 = nullptr; + + if (sq_gettop(vm) != 2 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) || + SQ_FAILED(sq_getinstanceup(vm, 2, (SQUserPointer*)&v2, TYPETAG_VECTOR))) + { + return sq_throwerror(vm, "Expected (Vector, Vector)"); + } + + VectorSubtract( *v1, *v2, *v1 ); + sq_remove( vm, -1 ); + + return 1; + } + + SQInteger Multiply(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + + if (sq_gettop(vm) != 2 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR))) + { + return sq_throwerror(vm, "Expected (Vector, Vector|float)"); + } + + Vector* v2 = nullptr; + + if ( SQ_SUCCEEDED(sq_getinstanceup( vm, 2, (SQUserPointer*)&v2, TYPETAG_VECTOR )) ) + { + VectorMultiply( *v1, *v2, *v1 ); + sq_remove( vm, -1 ); + + return 1; + } + + float flInput; + + if ( SQ_SUCCEEDED(sq_getfloat( vm, 2, &flInput )) ) + { + VectorMultiply( *v1, flInput, *v1 ); + sq_remove( vm, -1 ); + + return 1; + } + + return sq_throwerror(vm, "Expected (Vector, Vector|float)"); + } + + SQInteger Divide(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + + if (sq_gettop(vm) != 2 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR))) + { + return sq_throwerror(vm, "Expected (Vector, Vector|float)"); + } + + Vector* v2 = nullptr; + + if ( SQ_SUCCEEDED(sq_getinstanceup( vm, 2, (SQUserPointer*)&v2, TYPETAG_VECTOR )) ) + { + VectorDivide( *v1, *v2, *v1 ); + sq_remove( vm, -1 ); + + return 1; + } + + float flInput; + + if ( SQ_SUCCEEDED(sq_getfloat( vm, 2, &flInput )) ) + { + VectorDivide( *v1, flInput, *v1 ); + sq_remove( vm, -1 ); + + return 1; + } + + return sq_throwerror(vm, "Expected (Vector, Vector|float)"); + } + + SQInteger DistTo(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + Vector* v2 = nullptr; + + if (sq_gettop(vm) != 2 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) || + SQ_FAILED(sq_getinstanceup(vm, 2, (SQUserPointer*)&v2, TYPETAG_VECTOR))) + { + return sq_throwerror(vm, "Expected (Vector, Vector)"); + } + + sq_pushfloat( vm, v1->DistTo(*v2) ); + + return 1; + } + + SQInteger DistToSqr(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + Vector* v2 = nullptr; + + if (sq_gettop(vm) != 2 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) || + SQ_FAILED(sq_getinstanceup(vm, 2, (SQUserPointer*)&v2, TYPETAG_VECTOR))) + { + return sq_throwerror(vm, "Expected (Vector, Vector)"); + } + + sq_pushfloat( vm, v1->DistToSqr(*v2) ); + + return 1; + } + + SQInteger IsEqualTo(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + Vector* v2 = nullptr; + + if (sq_gettop(vm) < 2 || // bother checking > 3? + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) || + SQ_FAILED(sq_getinstanceup(vm, 2, (SQUserPointer*)&v2, TYPETAG_VECTOR)) ) + { + return sq_throwerror(vm, "Expected (Vector, Vector, float)"); + } + + float tolerance = 0.0f; + sq_getfloat( vm, 3, &tolerance ); + + sq_pushbool( vm, VectorsAreEqual( *v1, *v2, tolerance ) ); + + return 1; + } + SQInteger Length(HSQUIRRELVM vm) { Vector* v1 = nullptr; @@ -557,30 +765,23 @@ namespace SQVector SQInteger Scale(HSQUIRRELVM vm) { Vector* v1 = nullptr; + float s = 0.0f; if (sq_gettop(vm) != 2 || - SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR))) + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) || + SQ_SUCCEEDED(sq_getfloat(vm, 2, &s))) { return sq_throwerror(vm, "Expected (Vector, float)"); } - float s = 0.0; + sq_getclass(vm, 1); + sq_createinstance(vm, -1); + SQUserPointer p; + sq_getinstanceup(vm, -1, &p, 0); + new(p) Vector((*v1) * s); + sq_remove(vm, -2); - if (SQ_SUCCEEDED(sq_getfloat(vm, 2, &s))) - { - sq_getclass(vm, 1); - sq_createinstance(vm, -1); - SQUserPointer p; - sq_getinstanceup(vm, -1, &p, 0); - new(p) Vector((*v1) * s); - sq_remove(vm, -2); - - return 1; - } - else - { - return sq_throwerror(vm, "Expected (Vector, float)"); - } + return 1; } SQInteger Dot(HSQUIRRELVM vm) @@ -613,6 +814,42 @@ namespace SQVector return 1; } + SQInteger FromKVString(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + const char* szInput; + + if (sq_gettop(vm) != 2 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) || + SQ_FAILED(sq_getstring(vm, 2, &szInput)) ) + { + return sq_throwerror(vm, "Expected (Vector, string)"); + } + + float x = 0.0f, y = 0.0f, z = 0.0f; + + if ( sscanf( szInput, "%f %f %f", &x, &y, &z ) < 3 ) // UTIL_StringToVector + { + // Don't throw, return null while invalidating the input vector. + // This allows the user to easily check for input errors without halting. + //return sq_throwerror(vm, "invalid KV string"); + + sq_pushnull(vm); + *v1 = vec3_invalid; + + return 1; + } + + v1->x = x; + v1->y = y; + v1->z = z; + + // return input vector + sq_remove( vm, -1 ); + + return 1; + } + SQInteger Cross(HSQUIRRELVM vm) { Vector* v1 = nullptr; @@ -635,6 +872,25 @@ namespace SQVector return 1; } + SQInteger WithinAABox(HSQUIRRELVM vm) + { + Vector* v1 = nullptr; + Vector* mins = nullptr; + Vector* maxs = nullptr; + + if (sq_gettop(vm) != 3 || + SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&v1, TYPETAG_VECTOR)) || + SQ_FAILED(sq_getinstanceup(vm, 2, (SQUserPointer*)&mins, TYPETAG_VECTOR)) || + SQ_FAILED(sq_getinstanceup(vm, 3, (SQUserPointer*)&maxs, TYPETAG_VECTOR))) + { + return sq_throwerror(vm, "Expected (Vector, Vector, Vector)"); + } + + sq_pushbool( vm, v1->WithinAABox( *mins, *maxs ) ); + + return 1; + } + SQInteger ToString(HSQUIRRELVM vm) { Vector* v1 = nullptr; @@ -645,7 +901,7 @@ namespace SQVector return sq_throwerror(vm, "Expected (Vector)"); } - sqstd_pushstringf(vm, "(vector: (%f, %f, %f))", v1->x, v1->y, v1->z); + sqstd_pushstringf(vm, "(Vector %p [%f %f %f])", (void*)v1, v1->x, v1->y, v1->z); return 1; } @@ -701,22 +957,33 @@ namespace SQVector static const SQRegFunction funcs[] = { {_SC("constructor"), Construct,0,nullptr}, - {_SC("_get"), Get, 2, _SC(".s")}, - {_SC("_set"), Set, 3, _SC(".sn")}, - {_SC("_add"), Add, 2, _SC("..")}, - {_SC("_sub"), Sub, 2, _SC("..")}, - {_SC("_mul"), Multiply, 2, _SC("..")}, - {_SC("_div"), Divide, 2, _SC("..")}, + {_SC("_get"), _get, 2, _SC(".s")}, + {_SC("_set"), _set, 3, _SC(".sn")}, + {_SC("_add"), _add, 2, _SC("..")}, + {_SC("_sub"), _sub, 2, _SC("..")}, + {_SC("_mul"), _multiply, 2, _SC("..")}, + {_SC("_div"), _divide, 2, _SC("..")}, + {_SC("_unm"), _unm, 1, _SC(".")}, + {_SC("Set"), Set, -2, _SC("..nn")}, + {_SC("Add"), Add, 2, _SC("..")}, + {_SC("Subtract"), Subtract, 2, _SC("..")}, + {_SC("Multiply"), Multiply, 2, _SC("..")}, + {_SC("Divide"), Divide, 2, _SC("..")}, + {_SC("DistTo"), DistTo, 2, _SC("..")}, + {_SC("DistToSqr"), DistToSqr, 2, _SC("..")}, + {_SC("IsEqualTo"), IsEqualTo, -2, _SC("..n")}, {_SC("Length"), Length, 1, _SC(".")}, {_SC("LengthSqr"), LengthSqr, 1, _SC(".")}, {_SC("Length2D"), Length2D, 1, _SC(".")}, {_SC("Length2DSqr"), Length2DSqr, 1, _SC(".")}, {_SC("Normalized"), Normalized, 1, _SC(".")}, {_SC("Norm"), Norm, 1, _SC(".")}, - {_SC("Scale"), Scale, 2, _SC("..")}, + {_SC("Scale"), Scale, 2, _SC(".n")}, // identical to _multiply {_SC("Dot"), Dot, 2, _SC("..")}, {_SC("Cross"), Cross, 2, _SC("..")}, + {_SC("WithinAABox"), WithinAABox, 3, _SC("...")}, {_SC("ToKVString"), ToKVString, 1, _SC(".")}, + {_SC("FromKVString"), FromKVString, 2, _SC(".s")}, {_SC("_tostring"), ToString, 1, _SC(".")}, {_SC("_typeof"), TypeOf, 1, _SC(".")}, {_SC("_nexti"), Nexti, 2, _SC("..")}, @@ -827,7 +1094,7 @@ void PushVariant(HSQUIRRELVM vm, const ScriptVariant_t& value) sq_createinstance(vm, -1); SQUserPointer p; sq_getinstanceup(vm, -1, &p, 0); - new(p) Vector(value); + new(p) Vector(static_cast(value)); sq_remove(vm, -2); break; } @@ -2698,7 +2965,7 @@ bool SquirrelVM::ClearValue(HSCRIPT hScope, ScriptVariant_t pKey) return true; } -/* + void SquirrelVM::CreateArray(ScriptVariant_t &arr, int size) { SquirrelSafeCheck safeCheck(vm_); @@ -2713,16 +2980,14 @@ void SquirrelVM::CreateArray(ScriptVariant_t &arr, int size) arr = (HSCRIPT)obj; } -*/ + bool SquirrelVM::ArrayAppend(HSCRIPT hArray, const ScriptVariant_t &val) { SquirrelSafeCheck safeCheck(vm_); - HSQOBJECT arr = *(HSQOBJECT*)hArray; - if ( !sq_isarray(arr) ) - return false; + HSQOBJECT *arr = (HSQOBJECT*)hArray; - sq_pushobject(vm_, arr); + sq_pushobject(vm_, *arr); PushVariant(vm_, val); bool ret = sq_arrayappend(vm_, -2) == SQ_OK; sq_pop(vm_, 1); diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index cb929807..f12d385b 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -65,6 +65,22 @@ function AngleDistance( next, cur ) return delta } +function FLerp( f1, f2, i1, i2, x ) +{ + return f1+(f2-f1)*(x-i1)/(i2-i1); +} + +function Lerp( f, A, B ) +{ + return A + ( B - A ) * f +} + +function SimpleSpline( f ) +{ + local ff = f * f; + return 3.0 * ff - 2.0 * ff * f; +} + function printl( text ) { return ::print(text + "\n");