diff --git a/.github/workflows/mapbase_build-base.yml b/.github/workflows/mapbase_build-base.yml index fac52365..45602a72 100644 --- a/.github/workflows/mapbase_build-base.yml +++ b/.github/workflows/mapbase_build-base.yml @@ -54,7 +54,7 @@ jobs: - uses: actions/checkout@v4 - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1.1 + uses: compnerd/gha-setup-vsdevenv@v6 - name: Enable VS2022 working-directory: '${{inputs.branch}}/src/vpc_scripts' @@ -77,107 +77,40 @@ jobs: # -------------------------------------------------------------------- - # "I'm invoking msbuild for each project individually, which looks a bit odd considering there is a solution file which should be able to invoke the builds in their proper order automatically, but passing the solution to msbuild doesn't seem to work." - # https://github.com/mapbase-source/source-sdk-2013/pull/162 - - - name: Build mathlib + - name: Build #if: steps.filter.outputs.game == 'true' working-directory: '${{inputs.branch}}/src' shell: cmd run: | - msbuild -m -p:Configuration=${{inputs.configuration}} mathlib\mathlib.vcxproj - - - name: Build Base Libraries - if: inputs.project-group == 'all' || inputs.project-group == 'game' || inputs.project-group == 'maptools' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} raytrace\raytrace.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} tier1\tier1.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} vgui2\vgui_controls\vgui_controls.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} vscript\vscript.vcxproj - - - name: Build Map Tools - if: inputs.project-group == 'all' || inputs.project-group == 'maptools' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} fgdlib\fgdlib.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vbsp\vbsp.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vvis\vvis_dll.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vvis_launcher\vvis_launcher.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vrad\vrad_dll.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} utils\vrad_launcher\vrad_launcher.vcxproj - - - name: Build Shaders - if: inputs.project-group == 'shaders' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_${{inputs.game}}.vcxproj - - - name: Build Game - if: inputs.project-group == 'game' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_${{inputs.game}}.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_${{inputs.game}}.vcxproj - - # TODO: Hook to game naming? - - name: Build everything - if: inputs.project-group == 'all' - working-directory: '${{inputs.branch}}/src' - shell: cmd - run: | - msbuild -m -p:Configuration=${{inputs.configuration}} responserules\runtime\responserules.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_episodic.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} materialsystem\stdshaders\game_shader_dx9_hl2.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_episodic.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\client\client_hl2.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_episodic.vcxproj - msbuild -m -p:Configuration=${{inputs.configuration}} game\server\server_hl2.vcxproj + devenv ${{inputs.solution-name}}.sln /upgrade + msbuild -m -t:Rebuild -p:Configuration=${{inputs.configuration}};Platform=x86 ${{inputs.solution-name}}.sln # -------------------------------------------------------------------- - - name: Publish Windows game DLLs - if: inputs.project-group == 'game' - uses: actions/upload-artifact@v3 + - name: Publish game binaries + if: inputs.project-group == 'game' || inputs.project-group == 'shaders' + uses: actions/upload-artifact@v4 with: - name: 'Windows Game DLLs (server & client.dll) [${{ inputs.configuration }}]' + name: '${{inputs.project-group}}_${{inputs.game}}_win32_${{ inputs.configuration }}' path: | - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/client.dll - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/server.dll + ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/*.dll if-no-files-found: error - - name: Publish Windows shader DLL - if: inputs.project-group == 'shaders' - uses: actions/upload-artifact@v3 - with: - name: 'Windows Shader DLL (game_shader_dx9.dll) [${{ inputs.configuration }}]' - path: | - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/game_shader_dx9.dll - if-no-files-found: error - - - name: Publish Windows map tools + - name: Publish map tools if: inputs.project-group == 'maptools' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: 'Windows Map Tools [${{ inputs.configuration }}]' + name: '${{inputs.project-group}}_win32_${{ inputs.configuration }}' path: | - ${{inputs.branch}}/game/bin/vbsp.exe - ${{inputs.branch}}/game/bin/vvis.exe - ${{inputs.branch}}/game/bin/vvis_dll.dll - ${{inputs.branch}}/game/bin/vrad.exe - ${{inputs.branch}}/game/bin/vrad_dll.dll + ${{inputs.branch}}/game/bin/*.exe + ${{inputs.branch}}/game/bin/*.dll if-no-files-found: error - - name: Publish everything (Windows) + - name: Publish everything if: inputs.project-group == 'all' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: 'Everything (Windows) [${{ inputs.configuration }}]' + name: 'everything_win32_${{ inputs.configuration }}' path: | ${{inputs.branch}}/game/bin ${{inputs.branch}}/game/mod_*/bin @@ -224,30 +157,21 @@ jobs: # -------------------------------------------------------------------- - - name: Publish Linux game SOs - if: inputs.project-group == 'game' - uses: actions/upload-artifact@v3 + - name: Publish game binaries + if: inputs.project-group == 'game' || inputs.project-group == 'shaders' + uses: actions/upload-artifact@v4 with: - name: 'Linux Game SOs (server & client.so) [${{ inputs.configuration }}]' + name: '${{inputs.project-group}}_${{inputs.game}}_linux32_${{ inputs.configuration }}' path: | - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/client.so - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/server.so + ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/*.so + !${{inputs.branch}}/game/mod_${{inputs.game}}/bin/*_srv.so if-no-files-found: error - - name: Publish Linux shader SO - if: inputs.project-group == 'shaders' - uses: actions/upload-artifact@v3 - with: - name: 'Linux Shader SO (game_shader_dx9.so) [${{ inputs.configuration }}]' - path: | - ${{inputs.branch}}/game/mod_${{inputs.game}}/bin/game_shader_dx9.so - if-no-files-found: error - - #- name: Publish Linux map tools + #- name: Publish map tools # if: inputs.project-group == 'maptools' - # uses: actions/upload-artifact@v3 + # uses: actions/upload-artifact@v4 # with: - # name: 'Linux Map Tools [${{ inputs.configuration }}]' + # name: '${{inputs.project-group}}_linux32_${{ inputs.configuration }}' # path: | # ${{inputs.branch}}/game/bin/vbsp # ${{inputs.branch}}/game/bin/vvis @@ -258,11 +182,11 @@ jobs: # For now, don't publish the .dbg files even though we publish .pdb files on Windows # (they're too big) - - name: Publish everything (Linux) + - name: Publish everything if: inputs.project-group == 'all' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: 'Everything (Linux) [${{ inputs.configuration }}]' + name: 'everything_linux32_${{ inputs.configuration }}' path: | ${{inputs.branch}}/game/bin/*.so !${{inputs.branch}}/game/bin/*_srv.so diff --git a/README b/README index d9d11024..b2fcc972 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ //========================================================================================================================= - Mapbase v7.2 - Source 2013 + Mapbase v7.3 - Source 2013 https://github.com/mapbase-source/source-sdk-2013 https://www.moddb.com/mods/mapbase @@ -117,7 +117,18 @@ Direct contributions: - https://github.com/mapbase-source/source-sdk-2013/pull/237 (Commander goal trace fix by Agrimar) - https://github.com/mapbase-source/source-sdk-2013/pull/245 (ViewPunch random fix by Mr0maks) - https://github.com/mapbase-source/source-sdk-2013/pull/248 (soundlevel_t conversation warning fix by Mechami) +- https://github.com/mapbase-source/source-sdk-2013/pull/266 ("OnPhysGunPull" output in CPhysicsProp by rlenhub) +- https://github.com/mapbase-source/source-sdk-2013/pull/292 (env_headcrabcanister random spawn type by arbabf) +- https://github.com/mapbase-source/source-sdk-2013/pull/294 (SDK_LightmappedGeneric editor blend swap fix by azzyr) +- https://github.com/mapbase-source/source-sdk-2013/pull/308 (BlurFilterY fix by Wikot235) +- https://github.com/mapbase-source/source-sdk-2013/pull/312 (Zombie improvements by Wikot235) +- https://github.com/mapbase-source/source-sdk-2013/pull/315 (env_flare crash fix by Wikot235) +- https://github.com/mapbase-source/source-sdk-2013/pull/324 (server-only info/func_null by SirYodaJedi) +- https://github.com/mapbase-source/source-sdk-2013/pull/333 (Cvar to transition levels while in MOVETYPE_NOCLIP by Wikot235) +- https://github.com/mapbase-source/source-sdk-2013/pull/342 (NaN particle cull radius fix by celisej567) - https://github.com/mapbase-source/mapbase-game-src/pull/1 (Advanced video options duplicate field name fix by arbabf; This is asset-based and not reflected in the code) +- https://github.com/mapbase-source/mapbase-game-src/pull/2 (gameinfo.txt typo fix by CarePackage17; This is asset-based and not reflected in the code) +- https://github.com/mapbase-source/mapbase-game-src/pull/3 (HudMessage cutoff fix by arbabf; This is asset-based and not reflected in the code) - Demo autorecord code provided by Klems - cc_emit crash fix provided by 1upD - Custom HL2 ammo crate models created by Rykah (Textures created by Blixibon; This is asset-based and, aside from the SLAM crate, not reflected in the code) @@ -144,8 +155,10 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/206 (Fix CScriptNetMsgHelper::WriteEntity()) =-- https://github.com/mapbase-source/source-sdk-2013/pull/213 (VScript HUD visibility control, optimizations for 3D skybox angles/fake worldportals) =-- https://github.com/mapbase-source/source-sdk-2013/pull/229 (VScript VGUI HUD viewport parenting, game_text and vgui_text_display VScript font fallback) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/260 (CScriptNetPropManager rewrite) =-- https://github.com/mapbase-source/source-sdk-2013/pull/261 (Misc VScript additions) =-- https://github.com/mapbase-source/source-sdk-2013/pull/279 (weapon_custom_scripted fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/332 (Fix OOB access) == Contributions from z33ky: =-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) @@ -159,6 +172,7 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/159 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/162 (VS2019 exception specification fix) =-- https://github.com/mapbase-source/source-sdk-2013/pull/170 (HL2 non-Episodic build fix) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/322 (Small Mapbase fixes) == Contributions from Petercov: =-- https://github.com/mapbase-source/source-sdk-2013/pull/182 (NPCs load dynamic interactions from all animation MDLs) @@ -168,6 +182,7 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/183 (Enhanced custom weapons support) =-- https://github.com/mapbase-source/source-sdk-2013/pull/230 (Caption fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/231 (Sentence source bug fix) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/264 (Outputs for vgui_screen) //------------------------------------------------------------------------------------------------------------------------- diff --git a/mp/src/game/client/particlemgr.cpp b/mp/src/game/client/particlemgr.cpp index 0eb09a43..615b7cc4 100644 --- a/mp/src/game/client/particlemgr.cpp +++ b/mp/src/game/client/particlemgr.cpp @@ -146,6 +146,8 @@ CParticleEffectBinding::CParticleEffectBinding() m_LastMin = m_Min; m_LastMax = m_Max; + m_flParticleCullRadius = 0.0f; + SetParticleCullRadius( 0.0f ); m_nActiveParticles = 0; diff --git a/mp/src/game/server/subs.cpp b/mp/src/game/server/subs.cpp index b2bf003f..e7ad7354 100644 --- a/mp/src/game/server/subs.cpp +++ b/mp/src/game/server/subs.cpp @@ -22,10 +22,10 @@ void CPointEntity::Spawn( void ) } -class CNullEntity : public CBaseEntity +class CNullEntity : public CServerOnlyEntity { public: - DECLARE_CLASS( CNullEntity, CBaseEntity ); + DECLARE_CLASS( CNullEntity, CServerOnlyEntity ); void Spawn( void ); }; diff --git a/sp/src/game/client/c_basecombatcharacter.cpp b/sp/src/game/client/c_basecombatcharacter.cpp index 0afe4cbf..85dbb9d5 100644 --- a/sp/src/game/client/c_basecombatcharacter.cpp +++ b/sp/src/game/client/c_basecombatcharacter.cpp @@ -34,6 +34,10 @@ C_BaseCombatCharacter::C_BaseCombatCharacter() m_pGlowEffect = NULL; m_bGlowEnabled = false; m_bOldGlowEnabled = false; + m_GlowColor.Init( 0.76f, 0.76f, 0.76f ); + m_OldGlowColor = m_GlowColor; + m_GlowAlpha = 1.0f; + m_OldGlowAlpha = 1.0f; #endif // GLOWS_ENABLE } @@ -66,6 +70,8 @@ void C_BaseCombatCharacter::OnPreDataChanged( DataUpdateType_t updateType ) #ifdef GLOWS_ENABLE m_bOldGlowEnabled = m_bGlowEnabled; + m_OldGlowColor = m_GlowColor; + m_OldGlowAlpha = m_GlowAlpha; #endif // GLOWS_ENABLE } @@ -77,7 +83,7 @@ void C_BaseCombatCharacter::OnDataChanged( DataUpdateType_t updateType ) BaseClass::OnDataChanged( updateType ); #ifdef GLOWS_ENABLE - if ( m_bOldGlowEnabled != m_bGlowEnabled ) + if ( m_bOldGlowEnabled != m_bGlowEnabled || m_OldGlowColor != m_GlowColor || m_OldGlowAlpha != m_GlowAlpha ) { UpdateGlowEffect(); } @@ -106,11 +112,13 @@ void C_BaseCombatCharacter::DoMuzzleFlash() //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void C_BaseCombatCharacter::GetGlowEffectColor( float *r, float *g, float *b ) +void C_BaseCombatCharacter::GetGlowEffectColor( float *r, float *g, float *b, float *a ) { - *r = 0.76f; - *g = 0.76f; - *b = 0.76f; + *r = m_GlowColor.x; + *g = m_GlowColor.y; + *b = m_GlowColor.z; + if (a) + *a = m_GlowAlpha; } //----------------------------------------------------------------------------- @@ -127,10 +135,10 @@ void C_BaseCombatCharacter::UpdateGlowEffect( void ) // create a new effect if ( m_bGlowEnabled ) { - float r, g, b; - GetGlowEffectColor( &r, &g, &b ); + float r, g, b, a; + GetGlowEffectColor( &r, &g, &b, &a ); - m_pGlowEffect = new CGlowObject( this, Vector( r, g, b ), 1.0, true ); + m_pGlowEffect = new CGlowObject( this, Vector( r, g, b ), a, true ); } } @@ -161,6 +169,8 @@ BEGIN_RECV_TABLE(C_BaseCombatCharacter, DT_BaseCombatCharacter) RecvPropArray3( RECVINFO_ARRAY(m_hMyWeapons), RecvPropEHandle( RECVINFO( m_hMyWeapons[0] ) ) ), #ifdef GLOWS_ENABLE RecvPropBool( RECVINFO( m_bGlowEnabled ) ), + RecvPropVector( RECVINFO( m_GlowColor ) ), + RecvPropFloat( RECVINFO( m_GlowAlpha ) ), #endif // GLOWS_ENABLE #ifdef INVASION_CLIENT_DLL diff --git a/sp/src/game/client/c_basecombatcharacter.h b/sp/src/game/client/c_basecombatcharacter.h index f580fe46..4941b136 100644 --- a/sp/src/game/client/c_basecombatcharacter.h +++ b/sp/src/game/client/c_basecombatcharacter.h @@ -99,7 +99,7 @@ public: #ifdef GLOWS_ENABLE CGlowObject *GetGlowObject( void ){ return m_pGlowEffect; } - virtual void GetGlowEffectColor( float *r, float *g, float *b ); + virtual void GetGlowEffectColor( float *r, float *g, float *b, float *a = NULL ); #endif // GLOWS_ENABLE #ifdef MAPBASE_VSCRIPT @@ -133,6 +133,10 @@ private: bool m_bGlowEnabled; bool m_bOldGlowEnabled; CGlowObject *m_pGlowEffect; + Vector m_GlowColor; + Vector m_OldGlowColor; + float m_GlowAlpha; + int m_OldGlowAlpha; #endif // GLOWS_ENABLE private: diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index 1d3de004..4a72bdb7 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -485,6 +485,8 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities DEFINE_SCRIPTFUNC_NAMED( ScriptEntityToWorldTransform, "EntityToWorldTransform", "Get the entity's transform" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetPhysicsObject, "GetPhysicsObject", "Get the entity's physics object if it has one" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPhysicsInitNormal, "PhysicsInitNormal", "Initializes the entity's physics object with the specified solid type, solid flags, and whether to start asleep" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPhysicsDestroyObject, "PhysicsDestroyObject", "Destroys the entity's physics object" ) DEFINE_SCRIPTFUNC( GetWaterLevel, "Get current level of water submergence" ) diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index 422a59d4..aa383c73 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -1206,6 +1206,8 @@ public: HSCRIPT ScriptEntityToWorldTransform( void ); HSCRIPT ScriptGetPhysicsObject( void ); + void ScriptPhysicsInitNormal( int nSolidType, int nSolidFlags, bool createAsleep ); + void ScriptPhysicsDestroyObject() { VPhysicsDestroyObject(); } void ScriptSetParent( HSCRIPT hParent, const char *szAttachment ); HSCRIPT ScriptGetMoveParent( void ); diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index 6e068341..73d593c5 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -1133,6 +1133,9 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2 | IN_VALIDVGUIINPUT); +#ifdef MAPBASE + pCmd->buttons |= IN_VGUIMODE; +#endif // MAPBASE return; } #else @@ -1142,6 +1145,10 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); +#ifdef MAPBASE + pCmd->buttons &= ~(IN_USE | IN_ATTACK3); + pCmd->buttons |= IN_VGUIMODE; +#endif // MAPBASE return; } #endif @@ -1206,6 +1213,10 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); +#ifdef MAPBASE + pCmd->buttons &= ~(IN_USE | IN_ATTACK3); + pCmd->buttons |= IN_VGUIMODE; +#endif // MAPBASE } } diff --git a/sp/src/game/client/c_env_screenoverlay.cpp b/sp/src/game/client/c_env_screenoverlay.cpp index a3125882..e6d7e553 100644 --- a/sp/src/game/client/c_env_screenoverlay.cpp +++ b/sp/src/game/client/c_env_screenoverlay.cpp @@ -219,6 +219,11 @@ enum SCREENEFFECT_EP2_ADVISOR_STUN, SCREENEFFECT_EP1_INTRO, SCREENEFFECT_EP2_GROGGY, + +#ifdef MAPBASE + SCREENEFFECT_MAPBASE_CHROMATIC_BLUR = 100, // Overlays 3 different frames of red, green, and blue tints respectively with different offsets + SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION, // Similar to above, except it stretches frames in addition to offsetting them +#endif }; // ============================================================================ @@ -303,6 +308,21 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys ); g_pScreenSpaceEffects->EnableScreenSpaceEffect( "ep2_groggy" ); } +#ifdef MAPBASE + else if ( m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_BLUR || m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION ) + { + if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + return; + + // Set our keys + pKeys->SetFloat( "duration", m_flDuration ); + pKeys->SetInt( "fadeout", 0 ); + pKeys->SetInt( "stretch", m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION ); + + g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "mapbase_chromatic_aberration", pKeys ); + g_pScreenSpaceEffects->EnableScreenSpaceEffect( "mapbase_chromatic_aberration" ); + } +#endif pKeys->deleteThis(); } @@ -349,6 +369,25 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys ); } +#ifdef MAPBASE + else if ( m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_BLUR || m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION ) + { + if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + return; + + // Create a keyvalue block to set these params + KeyValues *pKeys = new KeyValues( "keys" ); + if ( pKeys == NULL ) + return; + + // Set our keys + pKeys->SetFloat( "duration", m_flDuration ); + pKeys->SetInt( "fadeout", 1 ); + pKeys->SetInt( "stretch", m_nType == SCREENEFFECT_MAPBASE_CHROMATIC_ABERRATION ); + + g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "mapbase_chromatic_aberration", pKeys ); + } +#endif break; } diff --git a/sp/src/game/client/c_impact_effects.cpp b/sp/src/game/client/c_impact_effects.cpp index 5b350c18..64a51bf3 100644 --- a/sp/src/game/client/c_impact_effects.cpp +++ b/sp/src/game/client/c_impact_effects.cpp @@ -95,18 +95,23 @@ extern PMaterialHandle g_Material_Spark; //----------------------------------------------------------------------------- void GetColorForSurface( trace_t *trace, Vector *color ) { - Vector baseColor, diffuseColor; - Vector end = trace->startpos + ( ( Vector )trace->endpos - ( Vector )trace->startpos ) * 1.1f; - + Vector baseColor = vec3_invalid, diffuseColor; + const char *kind; + if ( trace->DidHitWorld() ) { if ( trace->hitbox == 0 ) { + kind = "World"; + Vector end = trace->startpos + ( trace->endpos - trace->startpos ) * 1.1f; // If we hit the world, then ask the world for the fleck color - engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor ); + if ( !engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor ) ) { + baseColor = vec3_invalid; // Make sure this wasn't modified + } } else { + kind = "Static Prop"; // In this case we hit a static prop. staticpropmgr->GetStaticPropMaterialColorAndLighting( trace, trace->hitbox - 1, diffuseColor, baseColor ); } @@ -117,20 +122,24 @@ void GetColorForSurface( trace_t *trace, Vector *color ) C_BaseEntity *pEnt = trace->m_pEnt; if ( !pEnt ) { - Msg("Couldn't find surface in GetColorForSurface()\n"); - color->x = 255; - color->y = 255; - color->z = 255; - return; + kind = "Null-Entity"; + } else { + kind = "Entity"; + ICollideable *pCollide = pEnt->GetCollideable(); + int modelIndex = pCollide->GetCollisionModelIndex(); + model_t* pModel = const_cast(modelinfo->GetModel( modelIndex )); + + // Ask the model info about what we need to know + modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(), + pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor ); } + } - ICollideable *pCollide = pEnt->GetCollideable(); - int modelIndex = pCollide->GetCollisionModelIndex(); - model_t* pModel = const_cast(modelinfo->GetModel( modelIndex )); - - // Ask the model info about what we need to know - modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(), - pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor ); + if ( baseColor == vec3_invalid ) + { + Warning( "Couldn't find surface color of %s\n", kind ); + baseColor = Vector( .5f, .5f, .5f ); + diffuseColor = engine->GetLightForPoint( trace->endpos, true ); } //Get final light value diff --git a/sp/src/game/client/c_vguiscreen.cpp b/sp/src/game/client/c_vguiscreen.cpp index adf8830c..7695afd8 100644 --- a/sp/src/game/client/c_vguiscreen.cpp +++ b/sp/src/game/client/c_vguiscreen.cpp @@ -38,10 +38,14 @@ extern vgui::IInputInternal *g_InputInternal; #define VGUI_SCREEN_MODE_RADIUS 80 //Precache the materials -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectVGuiScreen ) -CLIENTEFFECT_MATERIAL( "engine/writez" ) +CLIENTEFFECT_REGISTER_BEGIN(PrecacheEffectVGuiScreen) +CLIENTEFFECT_MATERIAL("engine/writez") CLIENTEFFECT_REGISTER_END() +#ifdef MAPBASE +C_EntityClassList g_VGUIScreenList; +template <> C_VGuiScreen* C_EntityClassList::m_pClassList = NULL; +#endif // MAPBASE // ----------------------------------------------------------------------------- // // This is a cache of preloaded keyvalues. @@ -102,11 +106,19 @@ C_VGuiScreen::C_VGuiScreen() m_WriteZMaterial.Init( "engine/writez", TEXTURE_GROUP_VGUI ); m_OverlayMaterial.Init( m_WriteZMaterial ); + +#ifdef MAPBASE + g_VGUIScreenList.Insert(this); +#endif // MAPBASE } C_VGuiScreen::~C_VGuiScreen() { DestroyVguiScreen(); + +#ifdef MAPBASE + g_VGUIScreenList.Remove(this); +#endif // MAPBASE } //----------------------------------------------------------------------------- @@ -416,34 +428,69 @@ void C_VGuiScreen::ClientThink( void ) int px = (int)(u * m_nPixelWidth + 0.5f); int py = (int)(v * m_nPixelHeight + 0.5f); +#ifndef MAPBASE // Generate mouse input commands if ((px != m_nOldPx) || (py != m_nOldPy)) { - g_InputInternal->InternalCursorMoved( px, py ); + g_InputInternal->InternalCursorMoved(px, py); + m_nOldPx = px; m_nOldPy = py; } if (m_nButtonPressed & IN_ATTACK) { - g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_PRESSED ); + g_InputInternal->SetMouseCodeState(MOUSE_LEFT, vgui::BUTTON_PRESSED); g_InputInternal->InternalMousePressed(MOUSE_LEFT); } if (m_nButtonPressed & IN_ATTACK2) { - g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_PRESSED ); - g_InputInternal->InternalMousePressed( MOUSE_RIGHT ); + g_InputInternal->SetMouseCodeState(MOUSE_RIGHT, vgui::BUTTON_PRESSED); + g_InputInternal->InternalMousePressed(MOUSE_RIGHT); } - if ( (m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus + if ((m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus { - g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_RELEASED ); - g_InputInternal->InternalMouseReleased( MOUSE_LEFT ); + g_InputInternal->SetMouseCodeState(MOUSE_LEFT, vgui::BUTTON_RELEASED); + g_InputInternal->InternalMouseReleased(MOUSE_LEFT); } if (m_nButtonReleased & IN_ATTACK2) { - g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_RELEASED ); - g_InputInternal->InternalMouseReleased( MOUSE_RIGHT ); + g_InputInternal->SetMouseCodeState(MOUSE_RIGHT, vgui::BUTTON_RELEASED); + g_InputInternal->InternalMouseReleased(MOUSE_RIGHT); } +#else + vgui::VPANEL focus = g_InputInternal->GetMouseOver(); + // Generate mouse input commands + if ((px != m_nOldPx) || (py != m_nOldPy)) + { + g_InputInternal->UpdateCursorPosInternal(px, py); + + m_nOldPx = px; + m_nOldPy = py; + + focus = pPanel->IsWithinTraverse(px, py, true); + g_InputInternal->SetMouseFocus(focus); + vgui::ivgui()->PostMessage(focus, new KeyValues("CursorMoved", "xpos", px, "ypos", py), NULL); + } + + for (int i = 0; i < 2; i++) + { + const int nBit = i ? IN_ATTACK2 : (IN_ATTACK | IN_USE); + const vgui::MouseCode nButton = i ? MOUSE_RIGHT : MOUSE_LEFT; + + if ((m_nButtonReleased & nBit) || ((m_nButtonState & nBit) && m_bLoseThinkNextFrame)) // for a button release on loosing focus + { + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL); + } + else if (m_nButtonPressed & nBit) + { + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_PRESSED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MousePressed", "code", nButton), NULL); + } + } +#endif // !MAPBASE + if ( m_bLoseThinkNextFrame == true ) { @@ -627,6 +674,7 @@ bool C_VGuiScreen::IsInputOnlyToOwner( void ) return (m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) != 0; } +#ifndef MAPBASE //----------------------------------------------------------------------------- // // Enumator class for finding vgui screens close to the local player @@ -634,29 +682,29 @@ bool C_VGuiScreen::IsInputOnlyToOwner( void ) //----------------------------------------------------------------------------- class CVGuiScreenEnumerator : public IPartitionEnumerator { - DECLARE_CLASS_GAMEROOT( CVGuiScreenEnumerator, IPartitionEnumerator ); + DECLARE_CLASS_GAMEROOT(CVGuiScreenEnumerator, IPartitionEnumerator); public: - virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + virtual IterationRetval_t EnumElement(IHandleEntity* pHandleEntity); int GetScreenCount(); - C_VGuiScreen *GetVGuiScreen( int index ); + C_VGuiScreen* GetVGuiScreen(int index); private: CUtlVector< CHandle< C_VGuiScreen > > m_VguiScreens; }; -IterationRetval_t CVGuiScreenEnumerator::EnumElement( IHandleEntity *pHandleEntity ) +IterationRetval_t CVGuiScreenEnumerator::EnumElement(IHandleEntity* pHandleEntity) { - C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); - if ( pEnt == NULL ) + C_BaseEntity* pEnt = ClientEntityList().GetBaseEntityFromHandle(pHandleEntity->GetRefEHandle()); + if (pEnt == NULL) return ITERATION_CONTINUE; // FIXME.. pretty expensive... - C_VGuiScreen *pScreen = dynamic_cast(pEnt); - if ( pScreen ) + C_VGuiScreen* pScreen = dynamic_cast(pEnt); + if (pScreen) { - int i = m_VguiScreens.AddToTail( ); - m_VguiScreens[i].Set( pScreen ); + int i = m_VguiScreens.AddToTail(); + m_VguiScreens[i].Set(pScreen); } return ITERATION_CONTINUE; @@ -667,10 +715,12 @@ int CVGuiScreenEnumerator::GetScreenCount() return m_VguiScreens.Count(); } -C_VGuiScreen *CVGuiScreenEnumerator::GetVGuiScreen( int index ) +C_VGuiScreen* CVGuiScreenEnumerator::GetVGuiScreen(int index) { return m_VguiScreens[index].Get(); -} +} +#endif // !MAPBASE + //----------------------------------------------------------------------------- @@ -704,18 +754,29 @@ C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &vi Ray_t lookRay; lookRay.Init( viewPosition, lookEnd ); +#ifndef MAPBASE // Look for vgui screens that are close to the player CVGuiScreenEnumerator localScreens; - partition->EnumerateElementsInSphere( PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens ); + partition->EnumerateElementsInSphere(PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens); +#endif // !MAPBASE Vector vecOut, vecViewDelta; float flBestDist = 2.0f; C_VGuiScreen *pBestScreen = NULL; +#ifndef MAPBASE for (int i = localScreens.GetScreenCount(); --i >= 0; ) +#else + for (C_VGuiScreen* pScreen = g_VGUIScreenList.m_pClassList; pScreen != NULL; pScreen = pScreen->m_pNext) +#endif // !MAPBASE { - C_VGuiScreen *pScreen = localScreens.GetVGuiScreen(i); - +#ifndef MAPBASE + C_VGuiScreen* pScreen = localScreens.GetVGuiScreen(i); +#else + // Skip if out of PVS + if (pScreen->IsDormant()) + continue; +#endif if ( pScreen->IsAttachedToViewModel() ) continue; @@ -865,11 +926,21 @@ vgui::Panel *CVGuiScreenPanel::CreateControlByName(const char *controlName) //----------------------------------------------------------------------------- // Purpose: Called when the user presses a button //----------------------------------------------------------------------------- -void CVGuiScreenPanel::OnCommand( const char *command) +void CVGuiScreenPanel::OnCommand(const char* command) { - if ( Q_stricmp( command, "vguicancel" ) ) + if (Q_stricmp(command, "vguicancel")) { - engine->ClientCmd( const_cast( command ) ); +#ifdef MAPBASE + if (m_hEntity && m_hEntity->IsServerEntity()) + { + KeyValues* pCommand = new KeyValues("EntityCommand"); + pCommand->SetInt("entindex", m_hEntity->index); + pCommand->SetString("command_data", command); + engine->ServerCmdKeyValues(pCommand); + } + else +#endif + engine->ClientCmd(const_cast(command)); } BaseClass::OnCommand(command); diff --git a/sp/src/game/client/c_vguiscreen.h b/sp/src/game/client/c_vguiscreen.h index 71780093..331fbc78 100644 --- a/sp/src/game/client/c_vguiscreen.h +++ b/sp/src/game/client/c_vguiscreen.h @@ -66,6 +66,10 @@ class C_VGuiScreen : public C_BaseEntity public: DECLARE_CLIENTCLASS(); +#ifdef MAPBASE + C_VGuiScreen* m_pNext; +#endif // MAPBASE + C_VGuiScreen(); ~C_VGuiScreen(); diff --git a/sp/src/game/client/episodic/episodic_screenspaceeffects.cpp b/sp/src/game/client/episodic/episodic_screenspaceeffects.cpp index a2b59bbc..fd8cafb2 100644 --- a/sp/src/game/client/episodic/episodic_screenspaceeffects.cpp +++ b/sp/src/game/client/episodic/episodic_screenspaceeffects.cpp @@ -462,3 +462,225 @@ void CEP2StunEffect::Render( int x, int y, int w, int h ) pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PopMatrix(); } + +// ================================================================================================================ +// +// Chromatic Aberration +// +// ================================================================================================================ + +#ifdef MAPBASE +ConVar r_chromatic_aberration_offset( "r_chromatic_aberration_offset", "8.0" ); +ConVar r_chromatic_aberration_intensity( "r_chromatic_aberration_intensity", "0.2" ); +ConVar r_chromatic_aberration_noise( "r_chromatic_aberration_noise", "4.0" ); + +ConVar r_chromatic_aberration_frame1_clr( "r_chromatic_aberration_frame1_clr", "1.0 0.0 0.0 1.0" ); +ConVar r_chromatic_aberration_frame1_offset_x( "r_chromatic_aberration_frame1_offset_x", "1.0" ); +ConVar r_chromatic_aberration_frame1_offset_y( "r_chromatic_aberration_frame1_offset_y", "4.0" ); + +ConVar r_chromatic_aberration_frame2_clr( "r_chromatic_aberration_frame2_clr", "0.0 1.0 0.0 1.0" ); +ConVar r_chromatic_aberration_frame2_offset_x( "r_chromatic_aberration_frame2_offset_x", "-5.0" ); +ConVar r_chromatic_aberration_frame2_offset_y( "r_chromatic_aberration_frame2_offset_y", "-1.0" ); + +ConVar r_chromatic_aberration_frame3_clr( "r_chromatic_aberration_frame3_clr", "0.0 0.0 1.0 1.0" ); +ConVar r_chromatic_aberration_frame3_offset_x( "r_chromatic_aberration_frame3_offset_x", "3.0" ); +ConVar r_chromatic_aberration_frame3_offset_y( "r_chromatic_aberration_frame3_offset_y", "-3.0" ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CChromaticAberrationEffect::Init( void ) +{ + m_flDuration = 0.0f; + m_flFinishTime = 0.0f; + m_bUpdateView = true; + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", STUN_TEXTURE ); + m_EffectMaterial.Init( "__stuneffect", TEXTURE_GROUP_CLIENT_EFFECTS, pVMTKeyValues ); + m_StunTexture.Init( STUN_TEXTURE, TEXTURE_GROUP_CLIENT_EFFECTS ); +} + +void CChromaticAberrationEffect::Shutdown( void ) +{ + m_EffectMaterial.Shutdown(); + m_StunTexture.Shutdown(); +} + +//------------------------------------------------------------------------------ +// Purpose: Pick up changes in our parameters +//------------------------------------------------------------------------------ +void CChromaticAberrationEffect::SetParameters( KeyValues *params ) +{ + if( params->FindKey( "duration" ) ) + { + m_flDuration = params->GetFloat( "duration" ); + m_flFinishTime = gpGlobals->curtime + m_flDuration; + m_bUpdateView = true; + } + + if( params->FindKey( "fadeout" ) ) + { + m_bFadeOut = ( params->GetInt( "fadeout" ) == 1 ); + } + + if( params->FindKey( "stretch" ) ) + { + m_bStretch = ( params->GetInt( "stretch" ) == 1 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Render the effect +//----------------------------------------------------------------------------- +void CChromaticAberrationEffect::RenderColorFrame( CMatRenderContextPtr &pRenderContext, float flEffectPerc, int nColorMode, int x, int y, int w, int h ) +{ + // Change color + float flColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + + float viewOffsX = flEffectPerc; + if (m_bStretch) + viewOffsX *= r_chromatic_aberration_offset.GetFloat() * 2; + else + viewOffsX *= r_chromatic_aberration_offset.GetFloat(); + + float viewOffsY = viewOffsX; + + { + char szColor[16] = { 0 }; + float flNoise = sin( gpGlobals->curtime * r_chromatic_aberration_noise.GetFloat() ) * flEffectPerc; + + switch (nColorMode) + { + // Red + case 0: + Q_strncpy( szColor, r_chromatic_aberration_frame1_clr.GetString(), sizeof( szColor ) ); + + viewOffsX *= r_chromatic_aberration_frame1_offset_x.GetFloat(); + viewOffsY *= r_chromatic_aberration_frame1_offset_y.GetFloat(); + + viewOffsX += flNoise; + viewOffsY += flNoise; + break; + + // Green + case 1: + Q_strncpy( szColor, r_chromatic_aberration_frame2_clr.GetString(), sizeof( szColor ) ); + + viewOffsX *= r_chromatic_aberration_frame2_offset_x.GetFloat(); + viewOffsY *= r_chromatic_aberration_frame2_offset_y.GetFloat(); + + viewOffsX += flNoise; + viewOffsY += flNoise; + break; + + // Blue + case 2: + Q_strncpy( szColor, r_chromatic_aberration_frame3_clr.GetString(), sizeof( szColor ) ); + + viewOffsX *= r_chromatic_aberration_frame3_offset_x.GetFloat(); + viewOffsY *= r_chromatic_aberration_frame3_offset_y.GetFloat(); + + viewOffsX += flNoise; + viewOffsY += flNoise; + break; + } + + char *c = strtok( szColor, " " ); + for (int i = 0; i < 4 && c != NULL; i++, c = strtok( NULL, " " )) + { + flColor[i] = atof( c ); + } + } + + if (flColor[3] == 0.0f || g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80) + return; + + m_EffectMaterial->ColorModulate( flColor[0], flColor[1], flColor[2] ); + + // Set alpha blend value + float flOverlayAlpha = clamp( r_chromatic_aberration_intensity.GetFloat() * flEffectPerc * flColor[3], 0.0f, 1.0f); + m_EffectMaterial->AlphaModulate( flOverlayAlpha ); + + // Draw full screen alpha-blended quad + if (m_bStretch) + { + float vX = x - (viewOffsX * 0.5f); + float vY = y - (viewOffsY * 0.5f); + + pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, vX, vY, w + viewOffsX, h + viewOffsY, + 0, 0, (m_StunTexture->GetActualWidth()-1), (m_StunTexture->GetActualHeight()-1), + m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() ); + } + else + { + float vX = x + viewOffsX; + float vY = y + viewOffsY; + + pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, 0, 0, w, h, + vX, vY, (m_StunTexture->GetActualWidth()-1)+vX, (m_StunTexture->GetActualHeight()-1)+vY, + m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Render the effect +//----------------------------------------------------------------------------- +void CChromaticAberrationEffect::Render( int x, int y, int w, int h ) +{ + // Make sure we're ready to play this effect + if ( !IsEnabled() ) + return; + + if ( m_bFadeOut && m_flFinishTime < gpGlobals->curtime ) + { + g_pScreenSpaceEffects->DisableScreenSpaceEffect( "mapbase_chromatic_aberration" ); + return; + } + + CMatRenderContextPtr pRenderContext( materials ); + + // Set ourselves to the proper rendermode + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + // Draw the texture if we're using it + if ( m_bUpdateView ) + { + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + m_bUpdateView = false; + } + + float flEffectPerc = SmoothCurve( clamp( ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration, 0.0f, 1.0f ) ); + if (!m_bFadeOut) + flEffectPerc = 1.0f - flEffectPerc; + + RenderColorFrame( pRenderContext, flEffectPerc, 0, x, y, w, h ); + RenderColorFrame( pRenderContext, flEffectPerc, 1, x, y, w, h ); + RenderColorFrame( pRenderContext, flEffectPerc, 2, x, y, w, h ); + + // Save off this pass + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = w; + srcRect.height = h; + pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL ); + + // Restore our state + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); +} +#endif diff --git a/sp/src/game/client/episodic/episodic_screenspaceeffects.h b/sp/src/game/client/episodic/episodic_screenspaceeffects.h index ff5bc716..661aa403 100644 --- a/sp/src/game/client/episodic/episodic_screenspaceeffects.h +++ b/sp/src/game/client/episodic/episodic_screenspaceeffects.h @@ -116,4 +116,38 @@ private: ADD_SCREENSPACE_EFFECT( CEP2StunEffect, ep2_groggy ); +#ifdef MAPBASE +class CChromaticAberrationEffect : public IScreenSpaceEffect +{ +public: + CChromaticAberrationEffect( void ) : + m_flDuration( 0.0f ), + m_flFinishTime( 0.0f ), + m_bUpdateView( true ), + m_bEnabled( false ), + m_bFadeOut( false ) {} + + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void SetParameters( KeyValues *params ); + virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; }; + virtual bool IsEnabled( ) { return m_bEnabled; } + + virtual void RenderColorFrame( CMatRenderContextPtr &pRenderContext, float flEffectPerc, int nColorMode, int x, int y, int w, int h ); + virtual void Render( int x, int y, int w, int h ); + +private: + CTextureReference m_StunTexture; + CMaterialReference m_EffectMaterial; + float m_flDuration; + float m_flFinishTime; + bool m_bUpdateView; + bool m_bStretch; + bool m_bFadeOut; + bool m_bEnabled; +}; + +ADD_SCREENSPACE_EFFECT( CChromaticAberrationEffect, mapbase_chromatic_aberration ); +#endif + #endif // EPISODIC_SCREENSPACEEFFECTS_H diff --git a/sp/src/game/client/hl2/hud_credits.cpp b/sp/src/game/client/hl2/hud_credits.cpp index fb4354f5..bf0e58fd 100644 --- a/sp/src/game/client/hl2/hud_credits.cpp +++ b/sp/src/game/client/hl2/hud_credits.cpp @@ -35,8 +35,7 @@ struct creditname_t #ifdef MAPBASE // New credits stuff - - Color cColorOverride; + CCopyableUtlVector cColorOverride; // Images int iImageID = -1; @@ -408,8 +407,8 @@ void CHudCredits::DrawOutroCreditsName( void ) Color cColor = m_TextColor; #ifdef MAPBASE - if (pCredit->cColorOverride.a() > 0) - cColor = pCredit->cColorOverride; + if (pCredit->cColorOverride.Count() > 0) + cColor.SetRawColor( pCredit->cColorOverride[0] ); // Some lines should stick around and fade out if ( i >= m_CreditsList.Count()-m_iEndLines ) @@ -473,6 +472,12 @@ void CHudCredits::DrawOutroCreditsName( void ) { FOR_EACH_VEC( outStrings, i ) { + if (i < pCredit->cColorOverride.Count()) + { + // Change color to this particular column's color + cColor.SetRawColor( pCredit->cColorOverride[i] ); + } + int iImageID = GetOrAllocateImageID( outStrings[i] ); // Center the image if needed @@ -492,6 +497,12 @@ void CHudCredits::DrawOutroCreditsName( void ) { FOR_EACH_VEC( outStrings, i ) { + if (i < pCredit->cColorOverride.Count()) + { + // Change color to this particular column's color + cColor.SetRawColor( pCredit->cColorOverride[i] ); + } + DrawOutroCreditFont( outStrings[i], pCredit->flYPos, m_hTFont, cColor, iWidth*(i + 1), iDivisor ); } } @@ -768,8 +779,8 @@ void CHudCredits::DrawIntroCreditsName( void ) surface()->DrawSetTextFont( m_hTFont ); #ifdef MAPBASE Color cColor = m_cColor; - if (pCredit->cColorOverride.a() > 0) - cColor = pCredit->cColorOverride; + if (pCredit->cColorOverride.Count() > 0) + cColor.SetRawColor( pCredit->cColorOverride[0] ); surface()->DrawSetTextColor( cColor[0], cColor[1], cColor[2], FadeBlend( m_flFadeInTime, m_flFadeOutTime, m_flFadeHoldTime + pCredit->flTimeAdd, localTime ) * cColor[3] ); #else @@ -941,9 +952,25 @@ void CHudCredits::PrepareOutroCredits( void ) // Get color case 2: - int tmp[4]; - UTIL_StringToIntArray( tmp, 4, outStrings[i] ); - pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + char *pToken = strtok( outStrings[i], "," ); + if (pToken) + { + // Multiple colors for multiple columns + while (pToken != NULL) + { + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, pToken ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); + + pToken = strtok( NULL, "," ); + } + } + else + { + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, outStrings[i] ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); + } break; } } @@ -999,9 +1026,25 @@ void CHudCredits::PrepareOutroCredits( void ) { // Get color case 1: - int tmp[4]; - UTIL_StringToIntArray( tmp, 4, outStrings[i] ); - pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + char *pToken = strtok( outStrings[i], "," ); + if (pToken) + { + // Multiple colors for multiple columns + while (pToken != NULL) + { + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, pToken ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); + + pToken = strtok( NULL, "," ); + } + } + else + { + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, outStrings[i] ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); + } break; } } @@ -1024,8 +1067,12 @@ void CHudCredits::PrepareOutroCredits( void ) #ifdef MAPBASE // Check if the last line has a color override. If it does, use that as the alpha for the fadeout - if (m_CreditsList.Tail().cColorOverride.a() != 0) - m_Alpha = m_CreditsList.Tail().cColorOverride.a(); + if (m_CreditsList.Tail().cColorOverride.Count() > 0) + { + Color clr; + clr.SetRawColor( m_CreditsList.Tail().cColorOverride[0] ); + m_Alpha = clr.a(); + } #endif SetActive( true ); @@ -1057,9 +1104,10 @@ void CHudCredits::PrepareIntroCredits( void ) { // Get color case 1: + // TODO: Columns? int tmp[4]; UTIL_StringToIntArray( tmp, 4, outStrings[i] ); - pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + pCredit->cColorOverride.AddToTail( Color( tmp[0], tmp[1], tmp[2], tmp[3] ).GetRawColor() ); break; } } diff --git a/sp/src/game/client/mapbase/mapbase_autocubemap.cpp b/sp/src/game/client/mapbase/mapbase_autocubemap.cpp index 03602ef2..79f2497d 100644 --- a/sp/src/game/client/mapbase/mapbase_autocubemap.cpp +++ b/sp/src/game/client/mapbase/mapbase_autocubemap.cpp @@ -125,6 +125,12 @@ public: //Msg("No maps to cubemap with!\n"); //return; + if (C_BasePlayer::GetLocalPlayer() == NULL) + { + Msg( "Must be in a level (or have a loaded map list) to begin autocubemap\n" ); + return; + } + // Just do this map m_AutoCubemapMaps.AddToTail( strdup( g_MapName ) ); } diff --git a/sp/src/game/client/particlemgr.cpp b/sp/src/game/client/particlemgr.cpp index d62c6e73..b37a2000 100644 --- a/sp/src/game/client/particlemgr.cpp +++ b/sp/src/game/client/particlemgr.cpp @@ -146,6 +146,8 @@ CParticleEffectBinding::CParticleEffectBinding() m_LastMin = m_Min; m_LastMax = m_Max; + m_flParticleCullRadius = 0.0f; + SetParticleCullRadius( 0.0f ); m_nActiveParticles = 0; diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 7bece925..2312d6ca 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -272,6 +272,8 @@ void CScriptMaterialProxy::Release( void ) m_hScriptInstance = NULL; } + g_ScriptPersistableList.FindAndRemove( this ); + delete this; } diff --git a/sp/src/game/server/BasePropDoor.h b/sp/src/game/server/BasePropDoor.h index 7e8400d2..ea14d20d 100644 --- a/sp/src/game/server/BasePropDoor.h +++ b/sp/src/game/server/BasePropDoor.h @@ -38,6 +38,9 @@ public: DECLARE_CLASS( CBasePropDoor, CDynamicProp ); DECLARE_SERVERCLASS(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif CBasePropDoor( void ); @@ -79,6 +82,28 @@ public: virtual bool PassesDoorFilter(CBaseEntity *pEntity) { return true; } virtual bool KeyValue( const char *szKeyName, const char *szValue ); + + float GetSpeed() const { return m_flSpeed; } +#endif + +#ifdef MAPBASE_VSCRIPT + bool ScriptIsDoorOpen() { return IsDoorOpen(); } + bool ScriptIsDoorAjar() { return IsDoorAjar(); } + bool ScriptIsDoorOpening() { return IsDoorOpening(); } + bool ScriptIsDoorClosed() { return IsDoorClosed(); } + bool ScriptIsDoorClosing() { return IsDoorClosing(); } + bool ScriptIsDoorLocked() { return IsDoorLocked(); } + bool ScriptIsDoorBlocked() const { return IsDoorBlocked(); } + HSCRIPT ScriptGetActivator() { return ToHScript( m_hActivator.Get() ); } + + HSCRIPT ScriptGetDoorList( int i ) { return m_hDoorList.IsValidIndex(i) ? ToHScript( m_hDoorList[i] ) : NULL; } + int GetDoorListCount() { return m_hDoorList.Count(); } + + const char *ScriptGetFullyOpenSound() { return STRING( m_SoundOpen ); } + const char *ScriptGetFullyClosedSound() { return STRING( m_SoundClose ); } + const char *ScriptGetMovingSound() { return STRING( m_SoundMoving ); } + const char *ScriptGetLockedSound() { return STRING( m_ls.sLockedSound ); } + const char *ScriptGetUnlockedSound() { return STRING( m_ls.sUnlockedSound ); } #endif protected: @@ -178,6 +203,12 @@ private: #ifdef MAPBASE void InputAllowPlayerUse(inputdata_t &inputdata); void InputDisallowPlayerUse(inputdata_t &inputdata); + + void InputSetFullyOpenSound(inputdata_t &inputdata); + void InputSetFullyClosedSound(inputdata_t &inputdata); + void InputSetMovingSound(inputdata_t &inputdata); + void InputSetLockedSound(inputdata_t &inputdata); + void InputSetUnlockedSound(inputdata_t &inputdata); #endif void SetDoorBlocker( CBaseEntity *pBlocker ); diff --git a/sp/src/game/server/SkyCamera.cpp b/sp/src/game/server/SkyCamera.cpp index be9716d4..f5bb2825 100644 --- a/sp/src/game/server/SkyCamera.cpp +++ b/sp/src/game/server/SkyCamera.cpp @@ -211,6 +211,11 @@ void CSkyCamera::Activate( ) } } #endif + +#ifdef MAPBASE + if (HasSpawnFlags( SF_SKY_MASTER )) + g_hActiveSkybox = this; +#endif } #ifdef MAPBASE @@ -368,9 +373,11 @@ void CSkyCamera::InputActivateSkybox( inputdata_t &inputdata ) // Deactivate that skybox pActiveSky->SetThink( NULL ); pActiveSky->SetNextThink( TICK_NEVER_THINK ); + pActiveSky->RemoveSpawnFlags( SF_SKY_MASTER ); } g_hActiveSkybox = this; + AddSpawnFlags( SF_SKY_MASTER ); if (HasSpawnFlags( SF_SKY_START_UPDATING )) InputStartUpdating( inputdata ); @@ -384,6 +391,7 @@ void CSkyCamera::InputDeactivateSkybox( inputdata_t &inputdata ) if (GetCurrentSkyCamera() == this) { g_hActiveSkybox = NULL; + RemoveSpawnFlags( SF_SKY_MASTER ); // ClientData doesn't catch this immediately CBasePlayer *pPlayer = NULL; diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 002f3f36..f087f8a4 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -6110,7 +6110,11 @@ bool CAI_BaseNPC::UpdateEnemyMemory( CBaseEntity *pEnemy, const Vector &position // If the was eluding me and allow the NPC to play a sound if (GetEnemies()->HasEludedMe(pEnemy)) { +#ifdef MAPBASE + FoundEnemySound( pEnemy ); +#else FoundEnemySound(); +#endif } float reactionDelay = ( !pInformer || pInformer == this ) ? GetReactionDelay( pEnemy ) : 0.0; bool result = GetEnemies()->UpdateMemory(GetNavigator()->GetNetwork(), pEnemy, position, reactionDelay, firstHand); @@ -8045,10 +8049,13 @@ int CAI_BaseNPC::UnholsterWeapon( void ) if (i == -1) { // Set i to the first weapon you can find - for (i = 0; i < WeaponCount(); i++) + for (i = 0;;) { if (GetWeapon(i)) break; + + if (++i >= WeaponCount()) + return -1; } } #else @@ -11731,7 +11738,11 @@ bool CAI_BaseNPC::ChooseEnemy( void ) if ( fEnemyEluded ) { SetCondition( COND_LOST_ENEMY ); +#ifdef MAPBASE + LostEnemySound( pInitialEnemy ); +#else LostEnemySound(); +#endif } if ( fEnemyWasPlayer ) @@ -14895,22 +14906,39 @@ void CAI_BaseNPC::ParseScriptedNPCInteractions(void) else if (!Q_strncmp(szName, "their_", 6)) { const char *szTheirName = szName + 6; - sInteraction.bHasSeparateSequenceNames = true; if (!Q_strncmp(szTheirName, "entry_sequence", 14)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString(szValue); + } else if (!Q_strncmp(szTheirName, "entry_activity", 14)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_ENTRY].iActivity = GetOrRegisterActivity(szValue); + } else if (!Q_strncmp(szTheirName, "sequence", 8)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString(szValue); + } else if (!Q_strncmp(szTheirName, "activity", 8)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_SEQUENCE].iActivity = GetOrRegisterActivity(szValue); + } else if (!Q_strncmp(szTheirName, "exit_sequence", 13)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_EXIT].iszSequence = AllocPooledString(szValue); + } else if (!Q_strncmp(szTheirName, "exit_activity", 13)) + { + sInteraction.bHasSeparateSequenceNames = true; sInteraction.sTheirPhases[SNPCINT_EXIT].iActivity = GetOrRegisterActivity(szValue); + } // Add anything else to our miscellaneous criteria else @@ -15890,12 +15918,11 @@ bool CAI_BaseNPC::InteractionIsAllowed( CAI_BaseNPC *pOtherNPC, ScriptedNPCInter if (pOtherNPC->Classify() == CLASS_PLAYER_ALLY_VITAL) return false; - // This convar allows all NPCs to perform Mapbase interactions for both testing and player fun. - if (ai_dynint_always_enabled.GetBool() && m_iDynamicInteractionsAllowed != TRS_FALSE) - return true; + if (m_iDynamicInteractionsAllowed == TRS_FALSE) + return false; - // m_iDynamicInteractionsAllowed == TRS_FALSE case is already handled in CanRunAScriptedNPCInteraction(). - if (pInteraction->iFlags & SCNPC_FLAG_MAPBASE_ADDITION && m_iDynamicInteractionsAllowed == TRS_NONE) + // To maintain existing behavior, Mapbase additions require either explicit TRS_YES or ai_dynint_always_enabled. + if (pInteraction->iFlags & SCNPC_FLAG_MAPBASE_ADDITION && m_iDynamicInteractionsAllowed == TRS_NONE && !ai_dynint_always_enabled.GetBool()) return false; // Test misc. criteria here since some of it may not have been valid on initial calculation, but could be now diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index dbc229e2..7db67d33 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1401,6 +1401,11 @@ public: virtual void FearSound( void ) { return; }; virtual void LostEnemySound( void ) { return; }; virtual void FoundEnemySound( void ) { return; }; +#ifdef MAPBASE + // New versions of the above functions which pass the enemy in question as a parameter. Chains to the original by default + virtual void LostEnemySound( CBaseEntity *pEnemy ) { LostEnemySound(); }; + virtual void FoundEnemySound( CBaseEntity *pEnemy ) { FoundEnemySound(); }; +#endif virtual void BarnacleDeathSound( void ) { CTakeDamageInfo info; PainSound( info ); } virtual void SpeakSentence( int sentenceType ) { return; }; diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index 5f57b51d..56e20e03 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -3506,6 +3506,12 @@ void CAI_BaseNPC::RunTask( const Task_t *pTask ) // as this should only run with the NPC "receiving" the interaction ScriptedNPCInteraction_t *pInteraction = m_hForcedInteractionPartner->GetRunningDynamicInteraction(); + if ( !(pInteraction->iFlags & SCNPC_FLAG_TEST_OTHER_ANGLES) ) + { + TaskComplete(); + return; + } + // Get our target's origin Vector vecTarget = m_hForcedInteractionPartner->GetAbsOrigin(); diff --git a/sp/src/game/server/ai_playerally.cpp b/sp/src/game/server/ai_playerally.cpp index af969868..ea7c986f 100644 --- a/sp/src/game/server/ai_playerally.cpp +++ b/sp/src/game/server/ai_playerally.cpp @@ -14,6 +14,7 @@ #include "gameinterface.h" #ifdef MAPBASE #include "mapbase/matchers.h" +#include "ai_memory.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -133,6 +134,8 @@ ConceptInfo_t g_ConceptInfos[] = { TLK_TAKING_FIRE, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, { TLK_NEW_ENEMY, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, { TLK_COMBAT_IDLE, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, + { TLK_LOSTENEMY, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, + { TLK_REFINDENEMY, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, }, #endif }; @@ -1426,6 +1429,28 @@ void CAI_PlayerAlly::PainSound( const CTakeDamageInfo &info ) SpeakIfAllowed( TLK_WOUND ); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +void CAI_PlayerAlly::LostEnemySound( CBaseEntity *pEnemy ) +{ + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + modifiers.AppendCriteria( "lastseenenemy", gpGlobals->curtime - GetEnemies()->LastTimeSeen( pEnemy ) ); + + SpeakIfAllowed( TLK_LOSTENEMY, modifiers ); +} + +//----------------------------------------------------------------------------- +void CAI_PlayerAlly::FoundEnemySound( CBaseEntity *pEnemy ) +{ + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + SpeakIfAllowed( TLK_REFINDENEMY, modifiers ); +} +#endif + //----------------------------------------------------------------------------- // Purpose: Implemented to look at talk target //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/ai_playerally.h b/sp/src/game/server/ai_playerally.h index 47ddf916..8c34333a 100644 --- a/sp/src/game/server/ai_playerally.h +++ b/sp/src/game/server/ai_playerally.h @@ -137,6 +137,8 @@ #define TLK_TAKING_FIRE "TLK_TAKING_FIRE" // Someone fired at me (regardless of whether I was hit) #define TLK_NEW_ENEMY "TLK_NEW_ENEMY" // A new enemy appeared while combat was already in progress #define TLK_COMBAT_IDLE "TLK_COMBAT_IDLE" // Similar to TLK_ATTACKING, but specifically for when *not* currently attacking (e.g. when in cover or reloading) +#define TLK_LOSTENEMY "TLK_LOSTENEMY" // Current enemy has eluded squad +#define TLK_REFINDENEMY "TLK_REFINDENEMY" // Found a previously eluded enemy #endif //----------------------------------------------------------------------------- @@ -339,6 +341,11 @@ public: virtual void PainSound( const CTakeDamageInfo &info ); +#ifdef MAPBASE + virtual void LostEnemySound( CBaseEntity *pEnemy ); + virtual void FoundEnemySound( CBaseEntity *pEnemy ); +#endif + //--------------------------------- // Speech & Acting //--------------------------------- diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index a1033586..b7a2692d 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -193,6 +193,15 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatCharacter, CBaseFlex, "The base class shared by DEFINE_SCRIPTFUNC( EyeDirection2D, "Get the eyes' 2D direction." ) DEFINE_SCRIPTFUNC( EyeDirection3D, "Get the eyes' 3D direction." ) + DEFINE_SCRIPTFUNC( LastHitGroup, "Get the last hitgroup." ) + +#ifdef GLOWS_ENABLE + DEFINE_SCRIPTFUNC( AddGlowEffect, "" ) + DEFINE_SCRIPTFUNC( RemoveGlowEffect, "" ) + DEFINE_SCRIPTFUNC( IsGlowEffectActive, "" ) + DEFINE_SCRIPTFUNC( SetGlowColor, "" ) +#endif + // // Hooks // @@ -291,6 +300,8 @@ END_SEND_TABLE(); IMPLEMENT_SERVERCLASS_ST(CBaseCombatCharacter, DT_BaseCombatCharacter) #ifdef GLOWS_ENABLE SendPropBool( SENDINFO( m_bGlowEnabled ) ), + SendPropVector( SENDINFO( m_GlowColor ), 8, 0, 0, 1 ), + SendPropFloat( SENDINFO( m_GlowAlpha ) ), #endif // GLOWS_ENABLE // Data that only gets sent to the local player. SendPropDataTable( "bcc_localdata", 0, &REFERENCE_SEND_TABLE(DT_BCCLocalPlayerExclusive), SendProxy_SendBaseCombatCharacterLocalDataTable ), @@ -876,6 +887,8 @@ CBaseCombatCharacter::CBaseCombatCharacter( void ) #ifdef GLOWS_ENABLE m_bGlowEnabled.Set( false ); + m_GlowColor.GetForModify().Init( 0.76f, 0.76f, 0.76f ); + m_GlowAlpha.Set(1.0f); #endif // GLOWS_ENABLE } @@ -1608,6 +1621,15 @@ void CBaseCombatCharacter::FixupBurningServerRagdoll( CBaseEntity *pRagdoll ) } } +inline bool CBaseCombatCharacter::ShouldFadeServerRagdolls() const +{ +#ifdef MAPBASE + return IsNPC() ? HasSpawnFlags( SF_NPC_FADE_CORPSE ) : true; +#else + return true; +#endif +} + bool CBaseCombatCharacter::BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags ) { Assert( CanBecomeRagdoll() ); @@ -1616,7 +1638,7 @@ bool CBaseCombatCharacter::BecomeRagdollBoogie( CBaseEntity *pKiller, const Vect info.SetDamageForce( forceVector ); - CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); pRagdoll->SetCollisionBounds( CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs() ); @@ -1639,7 +1661,7 @@ CBaseEntity *CBaseCombatCharacter::BecomeRagdollBoogie( CBaseEntity *pKiller, co info.SetDamageForce( forceVector ); - CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); pRagdoll->SetCollisionBounds( CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs() ); @@ -1688,7 +1710,7 @@ bool CBaseCombatCharacter::BecomeRagdoll( const CTakeDamageInfo &info, const Vec #endif // in single player create ragdolls on the server when the player hits someone // with their vehicle - for more dramatic death/collisions - CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, info2, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, info2, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); FixupBurningServerRagdoll( pRagdoll ); RemoveDeferred(); return true; @@ -1702,7 +1724,7 @@ bool CBaseCombatCharacter::BecomeRagdoll( const CTakeDamageInfo &info, const Vec // Burning corpses are server-side in episodic, if we're in darkness mode if ( IsOnFire() && HL2GameRules()->IsAlyxInDarknessMode() ) { - CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_DEBRIS ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_DEBRIS, ShouldFadeServerRagdolls() ); FixupBurningServerRagdoll( pRagdoll ); RemoveDeferred(); return true; @@ -1723,7 +1745,7 @@ bool CBaseCombatCharacter::BecomeRagdoll( const CTakeDamageInfo &info, const Vec return false; //FIXME: This is fairly leafy to be here, but time is short! - CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CBaseEntity *pRagdoll = CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); FixupBurningServerRagdoll( pRagdoll ); PhysSetEntityGameFlags( pRagdoll, FVPHYSICS_NO_SELF_COLLISIONS ); RemoveDeferred(); @@ -1733,7 +1755,7 @@ bool CBaseCombatCharacter::BecomeRagdoll( const CTakeDamageInfo &info, const Vec if( hl2_episodic.GetBool() && Classify() == CLASS_PLAYER_ALLY_VITAL ) { - CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + CreateServerRagdoll( this, m_nForceBone, newinfo, COLLISION_GROUP_INTERACTIVE_DEBRIS, ShouldFadeServerRagdolls() ); RemoveDeferred(); return true; } @@ -4087,6 +4109,12 @@ bool CBaseCombatCharacter::IsGlowEffectActive( void ) { return m_bGlowEnabled; } + +void CBaseCombatCharacter::SetGlowColor( float red, float green, float blue, float alpha ) +{ + m_GlowColor.GetForModify().Init( red, green, blue ); + m_GlowAlpha.Set( alpha ); +} #endif // GLOWS_ENABLE //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index cdae243d..f7aa3d8e 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -350,6 +350,8 @@ public: // A version of BecomeRagdollBoogie() that allows the color to change and returns the entity itself instead. // In order to avoid breaking anything, it doesn't change the original function. virtual CBaseEntity *BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags, const Vector *vecColor ); + + bool ShouldFadeServerRagdolls() const; #endif CBaseEntity *FindHealthItem( const Vector &vecPosition, const Vector &range ); @@ -530,6 +532,7 @@ public: void AddGlowEffect( void ); void RemoveGlowEffect( void ); bool IsGlowEffectActive( void ); + void SetGlowColor( float red, float green, float blue, float alpha ); #endif // GLOWS_ENABLE #ifdef INVASION_DLL @@ -574,6 +577,8 @@ public: #ifdef GLOWS_ENABLE protected: CNetworkVar( bool, m_bGlowEnabled ); + CNetworkVector( m_GlowColor ); + CNetworkVar( float, m_GlowAlpha ); #endif // GLOWS_ENABLE private: diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 9df5cc09..d62e9536 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2312,6 +2312,8 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptEntityToWorldTransform, "EntityToWorldTransform", "Get the entity's transform" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetPhysicsObject, "GetPhysicsObject", "Get the entity's physics object if it has one" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPhysicsInitNormal, "PhysicsInitNormal", "Initializes the entity's physics object with the specified solid type, solid flags, and whether to start asleep" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptPhysicsDestroyObject, "PhysicsDestroyObject", "Destroys the entity's physics object" ) DEFINE_SCRIPTFUNC( ApplyAbsVelocityImpulse, "" ) DEFINE_SCRIPTFUNC( ApplyLocalAngularVelocityImpulse, "" ) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index acbffdb2..e5899231 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -606,6 +606,9 @@ public: void ValidateEntityConnections(); void FireNamedOutput( const char *pszOutput, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller, float flDelay = 0.0f ); +#ifdef MAPBASE + virtual +#endif CBaseEntityOutput *FindNamedOutput( const char *pszOutput ); #ifdef MAPBASE_VSCRIPT void ScriptFireOutput( const char *pszOutput, HSCRIPT hActivator, HSCRIPT hCaller, const char *szValue, float flDelay ); @@ -864,6 +867,13 @@ public: void SetAIWalkable( bool bBlocksLOS ); bool IsAIWalkable( void ); + +#ifdef MAPBASE + // Handle a potentially complex command from a client. + // Returns true if the command was handled successfully. + virtual bool HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) { return false; } +#endif // MAPBASE + private: int SaveDataDescBlock( ISave &save, datamap_t *dmap ); int RestoreDataDescBlock( IRestore &restore, datamap_t *dmap ); @@ -2097,6 +2107,8 @@ public: HSCRIPT ScriptEntityToWorldTransform( void ); HSCRIPT ScriptGetPhysicsObject( void ); + void ScriptPhysicsInitNormal( int nSolidType, int nSolidFlags, bool createAsleep ); + void ScriptPhysicsDestroyObject() { VPhysicsDestroyObject(); } void ScriptSetParent(HSCRIPT hParent, const char *szAttachment); #endif diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index e95ba310..ca2f6c7a 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -996,6 +996,9 @@ public: bool PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity ) { + if (!pEntity) + return false; + if (FStrEq(STRING(m_strFilterSkin), "-1") /*m_strFilterSkin == NULL_STRING|| FStrEq(STRING(m_strFilterSkin), "")*/) return Matcher_NamesMatch(STRING(m_iFilterModel), STRING(pEntity->GetModelName())); else if (pEntity->GetBaseAnimating()) @@ -1011,6 +1014,17 @@ public: inputdata.value.Convert(FIELD_STRING); m_iFilterModel = inputdata.value.StringID(); } + + bool KeyValue( const char *szKeyName, const char *szValue ) + { + if (FStrEq( szKeyName, "filtername" )) + { + m_iFilterModel = AllocPooledString( szValue ); + return true; + } + else + return BaseClass::KeyValue( szKeyName, szValue ); + } }; LINK_ENTITY_TO_CLASS( filter_activator_model, CFilterModel ); @@ -1019,7 +1033,6 @@ BEGIN_DATADESC( CFilterModel ) // Keyfields DEFINE_KEYFIELD( m_iFilterModel, FIELD_STRING, "filtermodel" ), - DEFINE_KEYFIELD( m_iFilterModel, FIELD_STRING, "filtername" ), DEFINE_KEYFIELD( m_strFilterSkin, FIELD_STRING, "skin" ), END_DATADESC() diff --git a/sp/src/game/server/hl2/env_headcrabcanister.cpp b/sp/src/game/server/hl2/env_headcrabcanister.cpp index e94fe3f1..4cf7fffb 100644 --- a/sp/src/game/server/hl2/env_headcrabcanister.cpp +++ b/sp/src/game/server/hl2/env_headcrabcanister.cpp @@ -33,6 +33,9 @@ ConVar sk_env_headcrabcanister_shake_radius( "sk_env_headcrabcanister_shake_radi ConVar sk_env_headcrabcanister_shake_radius_vehicle( "sk_env_headcrabcanister_shake_radius_vehicle", "2500" ); #define ENV_HEADCRABCANISTER_TRAIL_TIME 3.0f +#ifdef MAPBASE +#define RANDOM_CRAB_TYPE -1 +#endif //----------------------------------------------------------------------------- // Spawn flags @@ -258,7 +261,22 @@ void CEnvHeadcrabCanister::Precache( void ) PrecacheScriptSound( "HeadcrabCanister.SkyboxExplosion" ); PrecacheScriptSound( "HeadcrabCanister.Open" ); +#ifdef MAPBASE + if ( m_nHeadcrabType != RANDOM_CRAB_TYPE ) + { + UTIL_PrecacheOther( s_pHeadcrabClass[m_nHeadcrabType] ); + } + else + { + // precache all the headcrabs if we're spawning random species + for ( int i = 0; i < ARRAYSIZE( s_pHeadcrabClass ); i++ ) + { + UTIL_PrecacheOther( s_pHeadcrabClass[i] ); + } + } +#else UTIL_PrecacheOther( s_pHeadcrabClass[m_nHeadcrabType] ); +#endif } @@ -733,7 +751,17 @@ void CEnvHeadcrabCanister::HeadcrabCanisterSpawnHeadcrabThink() int nHeadCrabAttachment = LookupAttachment( "headcrab" ); if ( GetAttachment( nHeadCrabAttachment, vecSpawnPosition, vecSpawnAngles ) ) { +#ifdef MAPBASE + int iHeadcrabType = m_nHeadcrabType; + if ( m_nHeadcrabType == RANDOM_CRAB_TYPE ) + { + iHeadcrabType = RandomInt( 0, ARRAYSIZE( s_pHeadcrabClass ) - 1 ); + } + + CBaseEntity *pEnt = CreateEntityByName( s_pHeadcrabClass[iHeadcrabType] ); +#else CBaseEntity *pEnt = CreateEntityByName( s_pHeadcrabClass[m_nHeadcrabType] ); +#endif CBaseHeadcrab *pHeadCrab = assert_cast(pEnt); // Necessary to get it to eject properly (don't allow the NPC diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index cefdeeb4..b99f05b2 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -3617,6 +3617,20 @@ void CHL2_Player::UpdateWeaponPosture( void ) { m_LowerWeaponTimer.Set( .3 ); VPROF( "CHL2_Player::UpdateWeaponPosture-CheckLower" ); + +#ifdef MAPBASE + if (m_nButtons & IN_VGUIMODE) + { + //We're over a friendly, drop our weapon + if (Weapon_Lower() == false) + { + //FIXME: We couldn't lower our weapon! + } + + return; + } +#endif // MAPBASE + Vector vecAim = BaseClass::GetAutoaimVector( AUTOAIM_SCALE_DIRECT_ONLY ); const float CHECK_FRIENDLY_RANGE = 50 * 12; diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index f751d09a..f8609f49 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -211,6 +211,9 @@ BEGIN_DATADESC( CNPC_BaseZombie ) DEFINE_FIELD( m_fIsTorso, FIELD_BOOLEAN ), #ifdef MAPBASE DEFINE_KEYFIELD( m_fIsHeadless, FIELD_BOOLEAN, "Headless" ), + DEFINE_KEYFIELD( m_flMeleeReach, FIELD_FLOAT, "MeleeReach" ), + DEFINE_KEYFIELD( m_flMaxDistToSwat, FIELD_FLOAT, "MaxDistToSwat" ), + DEFINE_KEYFIELD( m_iMaxObjMassToSwat, FIELD_INTEGER, "MaxObjMassToSwat" ), #else DEFINE_FIELD( m_fIsHeadless, FIELD_BOOLEAN ), #endif @@ -256,6 +259,12 @@ CNPC_BaseZombie::CNPC_BaseZombie() // moan loop. m_iMoanSound = g_numZombies; +#ifdef MAPBASE + m_flMeleeReach = ZOMBIE_MELEE_REACH; + m_flMaxDistToSwat = ZOMBIE_PLAYER_MAX_SWAT_DIST; + m_iMaxObjMassToSwat = ZOMBIE_MAX_PHYSOBJ_MASS; +#endif + g_numZombies++; } @@ -295,7 +304,11 @@ bool CNPC_BaseZombie::FindNearestPhysicsObject( int iMaxMass ) float dist = VectorNormalize(vecDirToEnemy); vecDirToEnemy.z = 0; - if( dist > ZOMBIE_PLAYER_MAX_SWAT_DIST ) +#ifndef MAPBASE + if (dist > ZOMBIE_PLAYER_MAX_SWAT_DIST) +#else + if (dist > m_flMaxDistToSwat) +#endif { // Player is too far away. Don't bother // trying to swat anything at them until @@ -786,7 +799,7 @@ bool CNPC_BaseZombie::ShouldBecomeTorso( const CTakeDamageInfo &info, float flDa HeadcrabRelease_t CNPC_BaseZombie::ShouldReleaseHeadcrab( const CTakeDamageInfo &info, float flDamageThreshold ) { #ifdef MAPBASE - if ( m_iHealth <= 0 && !m_fIsHeadless ) + if ( m_iHealth <= 0 && !m_fIsHeadless && !HasSpawnFlags(SF_ZOMBIE_NO_HEADCRAB_SPAWN)) #else if ( m_iHealth <= 0 ) #endif @@ -2154,7 +2167,11 @@ void CNPC_BaseZombie::GatherConditions( void ) // between him and the object he's heading for already. if( gpGlobals->curtime >= m_flNextSwatScan && (m_hPhysicsEnt == NULL) ) { +#ifdef MAPBASE + FindNearestPhysicsObject(m_iMaxObjMassToSwat); +#else FindNearestPhysicsObject( ZOMBIE_MAX_PHYSOBJ_MASS ); +#endif m_flNextSwatScan = gpGlobals->curtime + 2.0; } } diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index fb17f037..cfc11566 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -44,7 +44,8 @@ extern int AE_ZOMBIE_POUND; #define ZOMBIE_BLOOD_BITE 3 #ifdef MAPBASE -#define SF_ZOMBIE_NO_TORSO ( 1 << 15 ) + #define SF_ZOMBIE_NO_TORSO ( 1 << 15 ) + #define SF_ZOMBIE_NO_HEADCRAB_SPAWN ( 1 << 16 ) #endif @@ -141,7 +142,14 @@ public: } int MeleeAttack1Conditions ( float flDot, float flDist ); - virtual float GetClawAttackRange() const { return ZOMBIE_MELEE_REACH; } + virtual float GetClawAttackRange() const + { +#ifdef MAPBASE + return m_flMeleeReach; +#else + return ZOMBIE_MELEE_REACH; +#endif + } // No range attacks int RangeAttack1Conditions ( float flDot, float flDist ) { return( 0 ); } @@ -257,6 +265,12 @@ protected: float m_flNextFlinch; +#ifdef MAPBASE + float m_flMeleeReach; + float m_flMaxDistToSwat; + int m_iMaxObjMassToSwat; +#endif + bool m_bHeadShot; // Used to determine the survival of our crab beyond our death. // diff --git a/sp/src/game/server/hl2/npc_antlion.cpp b/sp/src/game/server/hl2/npc_antlion.cpp index 2d59c9a0..bda685ea 100644 --- a/sp/src/game/server/hl2/npc_antlion.cpp +++ b/sp/src/game/server/hl2/npc_antlion.cpp @@ -378,13 +378,14 @@ void CNPC_Antlion::Spawn( void ) sInteraction01.vecRelativeOrigin = Vector(224, 0, 0); sInteraction01.angRelativeAngles = QAngle(0, 180, 0); - //sInteraction01.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; + sInteraction01.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; sInteraction01.iFlags |= SCNPC_FLAG_TEST_END_POSITION; sInteraction01.vecRelativeEndPos = Vector(312, -10, 0); sInteraction01.iTriggerMethod = SNPCINT_AUTOMATIC_IN_COMBAT; sInteraction01.flDelay = 15.0f; sInteraction01.iFlags |= SCNPC_FLAG_MAPBASE_ADDITION; sInteraction01.flDistSqr = (8 * 8); + sInteraction01.flMaxAngleDiff = 180.0f; // Initiate from any angle ScriptedNPCInteraction_t sInteraction02; @@ -393,11 +394,12 @@ void CNPC_Antlion::Spawn( void ) sInteraction02.vecRelativeOrigin = Vector(64, 0, 0); sInteraction02.angRelativeAngles = QAngle(0, 180, 0); - //sInteraction01.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; + sInteraction02.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; sInteraction02.iTriggerMethod = SNPCINT_AUTOMATIC_IN_COMBAT; sInteraction02.flDelay = 7.5f; sInteraction02.iFlags |= SCNPC_FLAG_MAPBASE_ADDITION; sInteraction02.flDistSqr = (8 * 8); + sInteraction02.flMaxAngleDiff = 180.0f; // Initiate from any angle AddScriptedNPCInteraction(&sInteraction01); diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index c2cac902..93116b4d 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -3145,13 +3145,22 @@ void CNPC_Combine::PainSound ( void ) // Input : // Output : //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CNPC_Combine::LostEnemySound( CBaseEntity *pEnemy ) +#else void CNPC_Combine::LostEnemySound( void) +#endif { if ( gpGlobals->curtime <= m_flNextLostSoundTime ) return; #ifdef COMBINE_SOLDIER_USES_RESPONSE_SYSTEM - if (SpeakIfAllowed( TLK_CMB_LOSTENEMY, UTIL_VarArgs("lastseenenemy:%d", GetEnemyLastTimeSeen()) )) + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + modifiers.AppendCriteria( "lastseenenemy", gpGlobals->curtime - GetEnemies()->LastTimeSeen( pEnemy ) ); + + if (SpeakIfAllowed( TLK_CMB_LOSTENEMY, modifiers )) { m_flNextLostSoundTime = gpGlobals->curtime + random->RandomFloat(5.0,15.0); } @@ -3179,10 +3188,17 @@ void CNPC_Combine::LostEnemySound( void) // Input : // Output : //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CNPC_Combine::FoundEnemySound( CBaseEntity *pEnemy ) +#else void CNPC_Combine::FoundEnemySound( void) +#endif { #ifdef COMBINE_SOLDIER_USES_RESPONSE_SYSTEM - SpeakIfAllowed( TLK_CMB_REFINDENEMY, SENTENCE_PRIORITY_HIGH ); + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + SpeakIfAllowed( TLK_CMB_REFINDENEMY, modifiers, SENTENCE_PRIORITY_HIGH ); #else m_Sentences.Speak( "COMBINE_REFIND_ENEMY", SENTENCE_PRIORITY_HIGH ); #endif diff --git a/sp/src/game/server/hl2/npc_combine.h b/sp/src/game/server/hl2/npc_combine.h index c9af8010..d6a500b9 100644 --- a/sp/src/game/server/hl2/npc_combine.h +++ b/sp/src/game/server/hl2/npc_combine.h @@ -181,8 +181,13 @@ public: #endif void IdleSound( void ); void AlertSound( void ); +#ifdef MAPBASE + void LostEnemySound( CBaseEntity *pEnemy ); + void FoundEnemySound( CBaseEntity *pEnemy ); +#else void LostEnemySound( void ); void FoundEnemySound( void ); +#endif void AnnounceAssault( void ); void AnnounceEnemyType( CBaseEntity *pEnemy ); void AnnounceEnemyKill( CBaseEntity *pEnemy ); diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index ed013fa3..f515ab92 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -534,10 +534,12 @@ void CNPC_MetroPolice::OnScheduleChange() { BaseClass::OnScheduleChange(); +#ifndef MAPBASE // Moved to Event_KilledOther() if ( GetEnemy() && HasCondition( COND_ENEMY_DEAD ) ) { AnnounceEnemyKill( GetEnemy() ); } +#endif } @@ -2938,7 +2940,11 @@ void CNPC_MetroPolice::DeathSound( const CTakeDamageInfo &info ) // Input : // Output : //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CNPC_MetroPolice::LostEnemySound( CBaseEntity *pEnemy ) +#else void CNPC_MetroPolice::LostEnemySound( void) +#endif { // Don't announce enemies when the player isn't a criminal if ( !PlayerIsCriminal() ) @@ -2948,7 +2954,12 @@ void CNPC_MetroPolice::LostEnemySound( void) return; #ifdef METROPOLICE_USES_RESPONSE_SYSTEM - if (SpeakIfAllowed(TLK_COP_LOSTENEMY)) + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + modifiers.AppendCriteria( "lastseenenemy", gpGlobals->curtime - GetEnemies()->LastTimeSeen( pEnemy ) ); + + if (SpeakIfAllowed(TLK_COP_LOSTENEMY, modifiers )) { m_flNextLostSoundTime = gpGlobals->curtime + random->RandomFloat(5.0,15.0); } @@ -2977,14 +2988,21 @@ void CNPC_MetroPolice::LostEnemySound( void) // Input : // Output : //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CNPC_MetroPolice::FoundEnemySound( CBaseEntity *pEnemy ) +#else void CNPC_MetroPolice::FoundEnemySound( void) +#endif { // Don't announce enemies when I'm in arrest behavior if ( HasSpawnFlags( SF_METROPOLICE_ARREST_ENEMY ) ) return; #ifdef METROPOLICE_USES_RESPONSE_SYSTEM - SpeakIfAllowed( TLK_COP_REFINDENEMY, SENTENCE_PRIORITY_HIGH ); + AI_CriteriaSet modifiers; + ModifyOrAppendEnemyCriteria( modifiers, pEnemy ); + + SpeakIfAllowed( TLK_COP_REFINDENEMY, modifiers, SENTENCE_PRIORITY_HIGH ); #else m_Sentences.Speak( "METROPOLICE_REFIND_ENEMY", SENTENCE_PRIORITY_HIGH ); #endif @@ -3706,6 +3724,21 @@ void CNPC_MetroPolice::Event_Killed( const CTakeDamageInfo &info ) BaseClass::Event_Killed( info ); } +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CNPC_MetroPolice::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) +{ + BaseClass::Event_KilledOther( pVictim, info ); + +#ifdef MAPBASE // Moved from OnScheduleChange() + if ( pVictim && (pVictim->IsPlayer() || pVictim->IsNPC()) ) + { + AnnounceEnemyKill( pVictim ); + } +#endif +} + //----------------------------------------------------------------------------- // Try to enter a slot where we shoot a pistol //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/npc_metropolice.h b/sp/src/game/server/hl2/npc_metropolice.h index 742de7e3..690bf2ae 100644 --- a/sp/src/game/server/hl2/npc_metropolice.h +++ b/sp/src/game/server/hl2/npc_metropolice.h @@ -79,6 +79,8 @@ public: virtual void Event_Killed( const CTakeDamageInfo &info ); + virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); + virtual void OnScheduleChange(); float GetIdealAccel( void ) const; @@ -170,8 +172,13 @@ private: void SpeakAssaultSentence( int nSentenceType ); void SpeakStandoffSentence( int nSentenceType ); +#ifdef MAPBASE + virtual void LostEnemySound( CBaseEntity *pEnemy ); + virtual void FoundEnemySound( CBaseEntity *pEnemy ); +#else virtual void LostEnemySound( void ); virtual void FoundEnemySound( void ); +#endif virtual void AlertSound( void ); virtual void PainSound( const CTakeDamageInfo &info ); virtual void DeathSound( const CTakeDamageInfo &info ); diff --git a/sp/src/game/server/hl2/npc_turret_floor.cpp b/sp/src/game/server/hl2/npc_turret_floor.cpp index 8698e742..f365dfd7 100644 --- a/sp/src/game/server/hl2/npc_turret_floor.cpp +++ b/sp/src/game/server/hl2/npc_turret_floor.cpp @@ -152,6 +152,9 @@ BEGIN_DATADESC( CNPC_FloorTurret ) DEFINE_OUTPUT( m_OnTipped, "OnTipped" ), DEFINE_OUTPUT( m_OnPhysGunPickup, "OnPhysGunPickup" ), DEFINE_OUTPUT( m_OnPhysGunDrop, "OnPhysGunDrop" ), +#ifdef MAPBASE + DEFINE_OUTPUT( m_OnStartTipped, "OnStartTipped" ), +#endif DEFINE_BASENPCINTERACTABLE_DATADESC(), @@ -1526,6 +1529,10 @@ bool CNPC_FloorTurret::PreThink( turretState_e state ) SetEyeState( TURRET_EYE_DEAD ); } +#ifdef MAPBASE + m_OnStartTipped.FireOutput( this, this ); +#endif + //Stop being targetted SetState( NPC_STATE_DEAD ); m_lifeState = LIFE_DEAD; diff --git a/sp/src/game/server/hl2/npc_turret_floor.h b/sp/src/game/server/hl2/npc_turret_floor.h index 8600e13a..af006a01 100644 --- a/sp/src/game/server/hl2/npc_turret_floor.h +++ b/sp/src/game/server/hl2/npc_turret_floor.h @@ -265,6 +265,9 @@ protected: COutputEvent m_OnTipped; COutputEvent m_OnPhysGunPickup; COutputEvent m_OnPhysGunDrop; +#ifdef MAPBASE + COutputEvent m_OnStartTipped; +#endif bool m_bHackedByAlyx; HSOUNDSCRIPTHANDLE m_ShotSounds; diff --git a/sp/src/game/server/hl2/prop_combine_ball.cpp b/sp/src/game/server/hl2/prop_combine_ball.cpp index 7a6f287b..1606e5b1 100644 --- a/sp/src/game/server/hl2/prop_combine_ball.cpp +++ b/sp/src/game/server/hl2/prop_combine_ball.cpp @@ -1080,6 +1080,113 @@ void CPropCombineBall::OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t R StopAnimating(); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPropCombineBall::SpawnerDestroyed( CBaseEntity *pActivator, bool *bSeekEnemy ) +{ + SetState( STATE_THROWN ); + WhizSoundThink(); + + m_bHeld = false; + m_bLaunched = true; + + // Stop with the dissolving + SetContextThink( NULL, gpGlobals->curtime, s_pHoldDissolveContext ); + + // We're ready to start colliding again. + SetCollisionGroup( HL2COLLISION_GROUP_COMBINE_BALL ); + + if ( m_pGlowTrail ) + { + m_pGlowTrail->TurnOn(); + m_pGlowTrail->SetRenderColor( 255, 255, 255, 255 ); + } + + // Set our desired speed to be launched at + SetSpeed( 1500.0f ); + + SetOwnerEntity( pActivator ); + SetWeaponLaunched( false ); + + if (!VPhysicsGetObject()) + return; + + if (pActivator->IsPlayer()) + { + PhysClearGameFlags( VPhysicsGetObject(), FVPHYSICS_NO_NPC_IMPACT_DMG ); + PhysSetGameFlags( VPhysicsGetObject(), FVPHYSICS_DMG_DISSOLVE | FVPHYSICS_HEAVY_OBJECT ); + } + else + { + // Don't do impact damage. Just touch them and do your dissolve damage and move on. + PhysSetGameFlags( VPhysicsGetObject(), FVPHYSICS_NO_NPC_IMPACT_DMG ); + } + + //if (pActivator->IsPlayer()) + //{ + // SetPlayerLaunched( ToBasePlayer( pActivator ) ); + //} + + Vector vecVelocity; + + if (bSeekEnemy) + { + CBaseEntity *pBestTarget = NULL; + CBaseEntity *list[256]; + + float distance; + float flBestDist = MAX_COORD_FLOAT; + int nCount = UTIL_EntitiesInSphere( list, 256, GetAbsOrigin(), sk_combine_ball_search_radius.GetFloat(), FL_NPC | FL_CLIENT ); + + for ( int i = 0; i < nCount; i++ ) + { + if ( !IsAttractiveTarget( list[i] ) ) + continue; + + distance = (list[i]->WorldSpaceCenter() - GetAbsOrigin()).LengthSqr(); + if ( distance < flBestDist ) + { + pBestTarget = list[i]; + flBestDist = distance; + } + } + + if ( pBestTarget ) + { + VectorSubtract( pBestTarget->WorldSpaceCenter(), GetAbsOrigin(), vecVelocity ); + VectorNormalize( vecVelocity ); + } + + *bSeekEnemy = (pBestTarget != NULL); + } + + if (bSeekEnemy == NULL || *bSeekEnemy == false) + { + // Choose a random direction based on current velocity + VPhysicsGetObject()->GetVelocity( &vecVelocity, NULL ); + VectorNormalize( vecVelocity ); + + QAngle shotAng; + VectorAngles( vecVelocity, shotAng ); + + // Offset by some small cone + shotAng[PITCH] += random->RandomInt( -75, 75 ); + shotAng[YAW] += random->RandomInt( -75, 75 ); + + AngleVectors( shotAng, &vecVelocity, NULL, NULL ); + } + + vecVelocity *= GetSpeed(); + + VPhysicsGetObject()->SetVelocity( &vecVelocity, &vec3_origin ); + + SetBallAsLaunched(); + StopAnimating(); +} +#endif + //------------------------------------------------------------------------------ // Stop looping sounds //------------------------------------------------------------------------------ @@ -1849,6 +1956,9 @@ BEGIN_DATADESC( CFuncCombineBallSpawner ) DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_VOID, "Destroy", InputDestroy ), +#endif DEFINE_OUTPUT( m_OnBallGrabbed, "OnBallGrabbed" ), DEFINE_OUTPUT( m_OnBallReinserted, "OnBallReinserted" ), @@ -2001,6 +2111,35 @@ void CFuncCombineBallSpawner::InputDisable( inputdata_t &inputdata ) SetThink( NULL ); } +#ifdef MAPBASE +void CFuncCombineBallSpawner::InputDestroy( inputdata_t &inputdata ) +{ + if ( !m_bEnabled ) + { + UTIL_Remove( this ); + return; + } + + // One ball always seeks the nearest enemy + bool bSoughtEnemy = false; + + CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "prop_combine_ball" ); + while (pEnt) + { + CPropCombineBall *pBall = static_cast(pEnt); + if (pBall && pBall->GetSpawner() == this) + { + BallGrabbed( pBall ); + pBall->SpawnerDestroyed( inputdata.pActivator, bSoughtEnemy ? NULL : &bSoughtEnemy ); + } + + pEnt = gEntList.FindEntityByClassname( pEnt, "prop_combine_ball" ); + } + + UTIL_Remove( this ); +} +#endif + //----------------------------------------------------------------------------- // Choose a random point inside the cylinder diff --git a/sp/src/game/server/hl2/prop_combine_ball.h b/sp/src/game/server/hl2/prop_combine_ball.h index d750d6ad..d798fde1 100644 --- a/sp/src/game/server/hl2/prop_combine_ball.h +++ b/sp/src/game/server/hl2/prop_combine_ball.h @@ -98,6 +98,9 @@ public: void SetSpawner( CFuncCombineBallSpawner *pSpawner ) { m_hSpawner = pSpawner; } void NotifySpawnerOfRemoval( void ); +#ifdef MAPBASE + void SpawnerDestroyed( CBaseEntity *pActivator, bool *bSeekEnemy ); +#endif float LastCaptureTime() const; @@ -243,6 +246,9 @@ private: // Input void InputEnable( inputdata_t &inputdata ); void InputDisable( inputdata_t &inputdata ); +#ifdef MAPBASE + void InputDestroy( inputdata_t &inputdata ); +#endif // Fire ball grabbed output void GrabBallTouch( CBaseEntity *pOther ); diff --git a/sp/src/game/server/hl2/weapon_flaregun.cpp b/sp/src/game/server/hl2/weapon_flaregun.cpp index 110f5c66..f2b74c46 100644 --- a/sp/src/game/server/hl2/weapon_flaregun.cpp +++ b/sp/src/game/server/hl2/weapon_flaregun.cpp @@ -568,10 +568,13 @@ void CFlare::Start( float lifeTime ) //----------------------------------------------------------------------------- void CFlare::Die( float fadeTime ) { - m_flTimeBurnOut = gpGlobals->curtime + fadeTime; + if (m_bInActiveList) + { + m_flTimeBurnOut = gpGlobals->curtime + fadeTime; - SetThink( &CFlare::FlareThink ); - SetNextThink( gpGlobals->curtime + 0.1f ); + SetThink(&CFlare::FlareThink); + SetNextThink(gpGlobals->curtime + 0.1f); + } } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 66991e45..2947e291 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -490,6 +490,9 @@ public: float GetLoadWeight( void ) const { return m_flLoadWeight; } void SetAngleAlignment( float alignAngleCosine ) { m_angleAlignment = alignAngleCosine; } void SetIgnorePitch( bool bIgnore ) { m_bIgnoreRelativePitch = bIgnore; } +#ifdef MAPBASE + void SetDontUseListMass( bool bDontUse ) { m_bDontUseListMass = bDontUse; } +#endif QAngle TransformAnglesToPlayerSpace( const QAngle &anglesIn, CBasePlayer *pPlayer ); QAngle TransformAnglesFromPlayerSpace( const QAngle &anglesIn, CBasePlayer *pPlayer ); @@ -531,6 +534,12 @@ private: // NVNT player controlling this grab controller CBasePlayer* m_pControllingPlayer; +#ifdef MAPBASE + // Prevents using the added mass of every part of the object + // (not saved due to only being used upon attach) + bool m_bDontUseListMass; +#endif + friend class CWeaponPhysCannon; }; @@ -581,6 +590,9 @@ CGrabController::CGrabController( void ) m_flDistanceOffset = 0; // NVNT constructing m_pControllingPlayer to NULL m_pControllingPlayer = NULL; +#ifdef MAPBASE + m_bDontUseListMass = false; +#endif } CGrabController::~CGrabController( void ) @@ -783,12 +795,18 @@ void CGrabController::AttachEntity( CBasePlayer *pPlayer, CBaseEntity *pEntity, { float mass = pList[i]->GetMass(); pList[i]->GetDamping( NULL, &m_savedRotDamping[i] ); - m_flLoadWeight += mass; m_savedMass[i] = mass; - // reduce the mass to prevent the player from adding crazy amounts of energy to the system - pList[i]->SetMass( REDUCED_CARRY_MASS / flFactor ); - pList[i]->SetDamping( NULL, &damping ); +#ifdef MAPBASE + if (!m_bDontUseListMass || pList[i] == pPhys) +#endif + { + m_flLoadWeight += mass; + + // reduce the mass to prevent the player from adding crazy amounts of energy to the system + pList[i]->SetMass( REDUCED_CARRY_MASS / flFactor ); + pList[i]->SetDamping( NULL, &damping ); + } } // NVNT setting m_pControllingPlayer to the player attached @@ -1077,7 +1095,24 @@ void CPlayerPickupController::Init( CBasePlayer *pPlayer, CBaseEntity *pObject ) Pickup_OnPhysGunPickup( pObject, m_pPlayer, PICKED_UP_BY_PLAYER ); +#ifdef MAPBASE + bool bUseGrabPos = false; + Vector vecGrabPos; + if ( dynamic_cast( pObject ) ) + { + m_grabController.SetDontUseListMass( true ); + + // Approximate where we're grabbing from + vecGrabPos = pPlayer->EyePosition() + (pPlayer->EyeDirection3D() * 16.0f); + bUseGrabPos = true; + } + else + m_grabController.SetDontUseListMass( false ); + + m_grabController.AttachEntity( pPlayer, pObject, pPhysics, false, vecGrabPos, bUseGrabPos ); +#else m_grabController.AttachEntity( pPlayer, pObject, pPhysics, false, vec3_origin, false ); +#endif // NVNT apply a downward force to simulate the mass of the held object. #if defined( WIN32 ) && !defined( _X360 ) HapticSetConstantForce(m_pPlayer,clamp(m_grabController.GetLoadWeight()*0.1,1,6)*Vector(0,-1,0)); @@ -2723,6 +2758,11 @@ CWeaponPhysCannon::FindObjectResult_t CWeaponPhysCannon::FindObject( void ) pullDir *= (mass + 0.5) * (1/50.0f); } + CPhysicsProp* pProp = dynamic_cast(pObj); + if (pProp) { + pProp->OnPhysGunPull( pOwner ); + } + // Nudge it towards us pObj->ApplyForceCenter( pullDir ); return OBJECT_NOT_FOUND; diff --git a/sp/src/game/server/mapbase/custom_weapon_factory.h b/sp/src/game/server/mapbase/custom_weapon_factory.h index 3abb17ed..bf46880b 100644 --- a/sp/src/game/server/mapbase/custom_weapon_factory.h +++ b/sp/src/game/server/mapbase/custom_weapon_factory.h @@ -107,7 +107,7 @@ public: virtual void ReleaseData(const void* pData) const { - delete pData; + delete (Data*)pData; } }; diff --git a/sp/src/game/server/physics_prop_ragdoll.cpp b/sp/src/game/server/physics_prop_ragdoll.cpp index cc788fc6..e208e620 100644 --- a/sp/src/game/server/physics_prop_ragdoll.cpp +++ b/sp/src/game/server/physics_prop_ragdoll.cpp @@ -30,6 +30,8 @@ #ifdef MAPBASE ConVar ragdoll_autointeractions("ragdoll_autointeractions", "1", FCVAR_NONE, "Controls whether we should rely on hardcoded keyvalues or automatic flesh checks for ragdoll physgun interactions."); #define IsBody() VPhysicsIsFlesh() + +ConVar ragdoll_always_allow_use( "ragdoll_always_allow_use", "0", FCVAR_NONE, "Allows all ragdolls to be used and, if they aren't explicitly set to prevent pickup, picked up." ); #endif //----------------------------------------------------------------------------- @@ -58,6 +60,8 @@ const float ATTACHED_DAMPING_SCALE = 50.0f; #define SF_RAGDOLLPROP_STARTASLEEP 0x10000 #ifdef MAPBASE #define SF_RAGDOLLPROP_FIXED_CONSTRAINTS 0x20000 +#define SF_RAGDOLLPROP_ALLOW_USE 0x40000 +#define SF_RAGDOLLPROP_PREVENT_PICKUP 0x80000 #endif //----------------------------------------------------------------------------- @@ -104,6 +108,8 @@ BEGIN_DATADESC(CRagdollProp) #ifdef MAPBASE DEFINE_INPUTFUNC( FIELD_VOID, "Wake", InputWake ), DEFINE_INPUTFUNC( FIELD_VOID, "Sleep", InputSleep ), + DEFINE_INPUTFUNC( FIELD_VOID, "AddToLRU", InputAddToLRU ), + DEFINE_INPUTFUNC( FIELD_VOID, "RemoveFromLRU", InputRemoveFromLRU ), #endif DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputTurnOn ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputTurnOff ), @@ -125,6 +131,10 @@ BEGIN_DATADESC(CRagdollProp) DEFINE_FIELD( m_strSourceClassName, FIELD_STRING ), DEFINE_FIELD( m_bHasBeenPhysgunned, FIELD_BOOLEAN ), +#ifdef MAPBASE + DEFINE_OUTPUT( m_OnPlayerUse, "OnPlayerUse" ), +#endif + // think functions DEFINE_THINKFUNC( SetDebrisThink ), DEFINE_THINKFUNC( ClearFlagsThink ), @@ -334,9 +344,39 @@ void CRagdollProp::Precache( void ) int CRagdollProp::ObjectCaps() { - return BaseClass::ObjectCaps() | FCAP_WCEDIT_POSITION; + int caps = FCAP_WCEDIT_POSITION; + +#ifdef MAPBASE + if (HasSpawnFlags( SF_RAGDOLLPROP_ALLOW_USE ) || ragdoll_always_allow_use.GetBool()) + caps |= FCAP_IMPULSE_USE; +#endif + + return BaseClass::ObjectCaps() | caps; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pActivator - +// *pCaller - +// useType - +// value - +//----------------------------------------------------------------------------- +void CRagdollProp::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + CBasePlayer *pPlayer = ToBasePlayer( pActivator ); + if (pPlayer) + { + m_OnPlayerUse.FireOutput( pActivator, this ); + + if (!HasSpawnFlags( SF_RAGDOLLPROP_PREVENT_PICKUP )) + { + pPlayer->PickupObject( this, false ); + } + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -405,7 +445,7 @@ void CRagdollProp::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t r m_bHasBeenPhysgunned = true; #ifdef MAPBASE - if( (ragdoll_autointeractions.GetBool() == true && IsBody()) || HasPhysgunInteraction( "onpickup", "boogie" ) ) + if( ((ragdoll_autointeractions.GetBool() == true && IsBody()) || HasPhysgunInteraction( "onpickup", "boogie" )) && reason != PICKED_UP_BY_PLAYER ) #else if( HasPhysgunInteraction( "onpickup", "boogie" ) ) #endif @@ -447,7 +487,7 @@ void CRagdollProp::OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reaso m_flLastPhysicsInfluenceTime = gpGlobals->curtime; #ifdef MAPBASE - if( (ragdoll_autointeractions.GetBool() == true && IsBody()) || HasPhysgunInteraction( "onpickup", "boogie" ) ) + if( ((ragdoll_autointeractions.GetBool() == true && IsBody()) || HasPhysgunInteraction( "onpickup", "boogie" )) && (Reason != DROPPED_BY_PLAYER && Reason != THROWN_BY_PLAYER) ) #else if( HasPhysgunInteraction( "onpickup", "boogie" ) ) #endif @@ -1844,6 +1884,24 @@ void CRagdollProp::InputSleep( inputdata_t &inputdata ) } } } + +//----------------------------------------------------------------------------- +// Purpose: Adds ragdoll to LRU. +//----------------------------------------------------------------------------- +void CRagdollProp::InputAddToLRU( inputdata_t &inputdata ) +{ + AddSpawnFlags( SF_RAGDOLLPROP_USE_LRU_RETIREMENT ); + s_RagdollLRU.MoveToTopOfLRU( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Removes ragdoll from LRU. +//----------------------------------------------------------------------------- +void CRagdollProp::InputRemoveFromLRU( inputdata_t &inputdata ) +{ + RemoveSpawnFlags( SF_RAGDOLLPROP_USE_LRU_RETIREMENT ); + s_RagdollLRU.RemoveFromLRU( this ); +} #endif void CRagdollProp::InputTurnOn( inputdata_t &inputdata ) diff --git a/sp/src/game/server/physics_prop_ragdoll.h b/sp/src/game/server/physics_prop_ragdoll.h index 46e527c3..82a3d77a 100644 --- a/sp/src/game/server/physics_prop_ragdoll.h +++ b/sp/src/game/server/physics_prop_ragdoll.h @@ -42,6 +42,10 @@ public: int ObjectCaps(); +#ifdef MAPBASE + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +#endif + DECLARE_SERVERCLASS(); // Don't treat as a live target virtual bool IsAlive( void ) { return false; } @@ -113,6 +117,8 @@ public: #ifdef MAPBASE void InputWake( inputdata_t &inputdata ); void InputSleep( inputdata_t &inputdata ); + void InputAddToLRU( inputdata_t &inputdata ); + void InputRemoveFromLRU( inputdata_t &inputdata ); #endif void InputTurnOn( inputdata_t &inputdata ); void InputTurnOff( inputdata_t &inputdata ); @@ -158,6 +164,10 @@ private: string_t m_strSourceClassName; bool m_bHasBeenPhysgunned; +#ifdef MAPBASE + COutputEvent m_OnPlayerUse; +#endif + // If not 1, then allow underlying sequence to blend in with simulated bone positions CNetworkVar( float, m_flBlendWeight ); CNetworkVar( int, m_nOverlaySequence ); diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 28c767c5..6fd1c504 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -498,6 +498,7 @@ END_DATADESC() #ifdef MAPBASE_VSCRIPT // TODO: Better placement? ScriptHook_t g_Hook_PlayerRunCommand; +ScriptHook_t g_Hook_FindUseEntity; BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) @@ -552,6 +553,9 @@ BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetEyeUp, "GetEyeUp", "Gets the player's up eye vector." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetViewModel, "GetViewModel", "Returns the viewmodel of the specified index." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetUseEntity, "GetUseEntity", "Gets the player's current use entity." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetHeldObject, "GetHeldObject", "Gets the player's currently held object IF it is being held by a gravity gun. To check for the player's held +USE object, use the standalone GetPlayerHeldEntity function." ) // // Hooks @@ -559,6 +563,11 @@ BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) BEGIN_SCRIPTHOOK( g_Hook_PlayerRunCommand, "PlayerRunCommand", FIELD_VOID, "Called when running a player command on the server." ) DEFINE_SCRIPTHOOK_PARAM( "command", FIELD_HSCRIPT ) END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( g_Hook_FindUseEntity, "FindUseEntity", FIELD_HSCRIPT, "Called when finding an entity to use. The 'entity' parameter is for the entity found by the default function. If 'is_radius' is true, then this entity was found by searching in a radius around the cursor, rather than being directly used. Return a different entity to use something else." ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + DEFINE_SCRIPTHOOK_PARAM( "is_radius", FIELD_BOOLEAN ) + END_SCRIPTHOOK() END_SCRIPTDESC(); #else diff --git a/sp/src/game/server/player.h b/sp/src/game/server/player.h index 72a1e38e..c3ef666a 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -414,6 +414,9 @@ public: const Vector& ScriptGetEyeUp() { static Vector vecUp; EyeVectors( NULL, NULL, &vecUp ); return vecUp; } HSCRIPT ScriptGetViewModel( int viewmodelindex ); + + HSCRIPT ScriptGetUseEntity() { return ToHScript( GetUseEntity() ); } + HSCRIPT ScriptGetHeldObject() { return ToHScript( GetHeldObject() ); } #endif // View model prediction setup diff --git a/sp/src/game/server/point_spotlight.cpp b/sp/src/game/server/point_spotlight.cpp index d5901714..71aad0b1 100644 --- a/sp/src/game/server/point_spotlight.cpp +++ b/sp/src/game/server/point_spotlight.cpp @@ -62,6 +62,7 @@ private: private: bool m_bSpotlightOn; bool m_bEfficientSpotlight; + bool m_bIgnoreSolid; Vector m_vSpotlightTargetPos; Vector m_vSpotlightCurrentPos; Vector m_vSpotlightDir; @@ -100,6 +101,7 @@ BEGIN_DATADESC( CPointSpotlight ) DEFINE_FIELD( m_vSpotlightDir, FIELD_VECTOR ), DEFINE_FIELD( m_nHaloSprite, FIELD_INTEGER ), + DEFINE_KEYFIELD( m_bIgnoreSolid, FIELD_BOOLEAN, "IgnoreSolid" ), DEFINE_KEYFIELD( m_flSpotlightMaxLength,FIELD_FLOAT, "SpotlightLength"), DEFINE_KEYFIELD( m_flSpotlightGoalWidth,FIELD_FLOAT, "SpotlightWidth"), DEFINE_KEYFIELD( m_flHDRColorScale, FIELD_FLOAT, "HDRColorScale" ), @@ -138,6 +140,7 @@ CPointSpotlight::CPointSpotlight() #endif m_flHDRColorScale = 1.0f; m_nMinDXLevel = 0; + m_bIgnoreSolid = false; #ifdef MAPBASE m_flHaloScale = 60.0f; #endif @@ -380,12 +383,21 @@ void CPointSpotlight::SpotlightCreate(void) AngleVectors( GetAbsAngles(), &m_vSpotlightDir ); - trace_t tr; - UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); + Vector vTargetPos; + if ( m_bIgnoreSolid ) + { + vTargetPos = GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength; + } + else + { + trace_t tr; + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); + vTargetPos = tr.endpos; + } m_hSpotlightTarget = (CSpotlightEnd*)CreateEntityByName( "spotlight_end" ); m_hSpotlightTarget->Spawn(); - m_hSpotlightTarget->SetAbsOrigin( tr.endpos ); + m_hSpotlightTarget->SetAbsOrigin( vTargetPos ); m_hSpotlightTarget->SetOwnerEntity( this ); m_hSpotlightTarget->m_clrRender = m_clrRender; m_hSpotlightTarget->m_Radius = m_flSpotlightMaxLength; @@ -437,9 +449,17 @@ Vector CPointSpotlight::SpotlightCurrentPos(void) AngleVectors( GetAbsAngles(), &m_vSpotlightDir ); // Get beam end point. Only collide with solid objects, not npcs - trace_t tr; - UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + (m_vSpotlightDir * 2 * m_flSpotlightMaxLength), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); - return tr.endpos; + Vector vEndPos = GetAbsOrigin() + ( m_vSpotlightDir * 2 * m_flSpotlightMaxLength ); + if ( m_bIgnoreSolid ) + { + return vEndPos; + } + else + { + trace_t tr; + UTIL_TraceLine( GetAbsOrigin(), vEndPos, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); + return tr.endpos; + } } //------------------------------------------------------------------------------ diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 5ad4c11a..037a0226 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -1338,6 +1338,12 @@ int CBreakableProp::OnTakeDamage( const CTakeDamageInfo &inputInfo ) //----------------------------------------------------------------------------- void CBreakableProp::Event_Killed( const CTakeDamageInfo &info ) { +#ifdef MAPBASE_VSCRIPT + // False = Cheat death + if (ScriptDeathHook( const_cast(&info) ) == false) + return; +#endif + IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( pPhysics && !pPhysics->IsMoveable() ) { @@ -3021,6 +3027,7 @@ BEGIN_DATADESC( CPhysicsProp ) DEFINE_OUTPUT( m_MotionEnabled, "OnMotionEnabled" ), DEFINE_OUTPUT( m_OnPhysGunPickup, "OnPhysGunPickup" ), DEFINE_OUTPUT( m_OnPhysGunOnlyPickup, "OnPhysGunOnlyPickup" ), + DEFINE_OUTPUT( m_OnPhysGunPull, "OnPhysGunPull" ), DEFINE_OUTPUT( m_OnPhysGunPunt, "OnPhysGunPunt" ), DEFINE_OUTPUT( m_OnPhysGunDrop, "OnPhysGunDrop" ), DEFINE_OUTPUT( m_OnPlayerUse, "OnPlayerUse" ), @@ -3391,6 +3398,13 @@ void CPhysicsProp::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t r CheckRemoveRagdolls(); } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPhysicsProp::OnPhysGunPull( CBasePlayer* pPhysGunUser ) { + m_OnPhysGunPull.FireOutput(pPhysGunUser, this); +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -4198,6 +4212,12 @@ BEGIN_DATADESC(CBasePropDoor) #ifdef MAPBASE DEFINE_INPUTFUNC(FIELD_VOID, "AllowPlayerUse", InputAllowPlayerUse), DEFINE_INPUTFUNC(FIELD_VOID, "DisallowPlayerUse", InputDisallowPlayerUse), + + DEFINE_INPUTFUNC( FIELD_STRING, "SetFullyOpenSound", InputSetFullyOpenSound ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetFullyClosedSound", InputSetFullyClosedSound ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetMovingSound", InputSetMovingSound ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetLockedSound", InputSetLockedSound ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetUnlockedSound", InputSetUnlockedSound ), #endif DEFINE_OUTPUT(m_OnBlockedOpening, "OnBlockedOpening"), @@ -4220,6 +4240,34 @@ END_DATADESC() IMPLEMENT_SERVERCLASS_ST(CBasePropDoor, DT_BasePropDoor) END_SEND_TABLE() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( CBasePropDoor, CBaseAnimating, "The base class used by prop doors, such as prop_door_rotating." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorOpen, "IsDoorOpen", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorAjar, "IsDoorAjar", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorOpening, "IsDoorOpening", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorClosed, "IsDoorClosed", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorClosing, "IsDoorClosing", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorLocked, "IsDoorLocked", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsDoorBlocked, "IsDoorBlocked", "" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetActivator, "GetActivator", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetDoorList, "GetDoorList", "Get connected door entity by index." ) + DEFINE_SCRIPTFUNC( GetDoorListCount, "Get number of connected doors." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetFullyOpenSound, "GetFullyOpenSound", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetFullyClosedSound, "GetFullyClosedSound", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetMovingSound, "GetMovingSound", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetLockedSound, "GetLockedSound", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetUnlockedSound, "GetUnlockedSound", "" ) + + DEFINE_SCRIPTFUNC( DoorCanClose, "Return true if the door has room to close. Boolean is for whether or not this is an automatic close and not manually triggered by someone." ) + DEFINE_SCRIPTFUNC( DoorCanOpen, "Return true if there are other doors connected to this one." ) + DEFINE_SCRIPTFUNC( HasSlaves, "" ) + +END_SCRIPTDESC(); +#endif + CBasePropDoor::CBasePropDoor( void ) { m_hMaster = NULL; @@ -4693,6 +4741,54 @@ void CBasePropDoor::InputOpenAwayFrom(inputdata_t &inputdata) } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetFullyOpenSound( inputdata_t &inputdata ) +{ + m_SoundOpen = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_SoundOpen ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetFullyClosedSound( inputdata_t &inputdata ) +{ + m_SoundClose = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_SoundClose ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetMovingSound( inputdata_t &inputdata ) +{ + m_SoundMoving = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_SoundMoving ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetLockedSound( inputdata_t &inputdata ) +{ + m_ls.sLockedSound = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_ls.sLockedSound ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePropDoor::InputSetUnlockedSound( inputdata_t &inputdata ) +{ + m_ls.sUnlockedSound = inputdata.value.StringID(); + PrecacheScriptSound( STRING( m_ls.sUnlockedSound ) ); +} +#endif + + //----------------------------------------------------------------------------- // Purpose: // diff --git a/sp/src/game/server/props.h b/sp/src/game/server/props.h index ebd87c4d..5c57824d 100644 --- a/sp/src/game/server/props.h +++ b/sp/src/game/server/props.h @@ -413,6 +413,7 @@ public: void EnableMotion( void ); bool CanBePickedUpByPhyscannon( void ); void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); + void OnPhysGunPull( CBasePlayer *pPhysGunUser ); void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason ); bool GetPropDataAngles( const char *pKeyName, QAngle &vecAngles ); @@ -446,6 +447,7 @@ private: COutputEvent m_OnPhysGunPickup; COutputEvent m_OnPhysGunPunt; COutputEvent m_OnPhysGunOnlyPickup; + COutputEvent m_OnPhysGunPull; COutputEvent m_OnPhysGunDrop; COutputEvent m_OnPlayerUse; COutputEvent m_OnPlayerPickup; diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index ab70e197..06f8f8fd 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -5298,6 +5298,23 @@ float GetSceneDuration( char const *pszScene ) { msecs = cachedData.msecs; } +#ifdef MAPBASE + else + { + // Raw scene file support + void *pBuffer = NULL; + if (filesystem->ReadFileEx( pszScene, "MOD", &pBuffer, true )) + { + g_TokenProcessor.SetBuffer((char*)pBuffer); + CChoreoScene *pScene = ChoreoLoadScene( pszScene, NULL, &g_TokenProcessor, LocalScene_Printf ); + g_TokenProcessor.SetBuffer(NULL); + + float flDuration = pScene->GetDuration(); + delete pScene; + return flDuration; + } + } +#endif return (float)msecs * 0.001f; } diff --git a/sp/src/game/server/scripted.cpp b/sp/src/game/server/scripted.cpp index f02a1dcd..1cc14d77 100644 --- a/sp/src/game/server/scripted.cpp +++ b/sp/src/game/server/scripted.cpp @@ -113,6 +113,9 @@ BEGIN_DATADESC( CAI_ScriptedSequence ) DEFINE_INPUTFUNC( FIELD_VOID, "MoveToPosition", InputMoveToPosition ), DEFINE_INPUTFUNC( FIELD_VOID, "BeginSequence", InputBeginSequence ), DEFINE_INPUTFUNC( FIELD_VOID, "CancelSequence", InputCancelSequence ), +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_VOID, "StopActionLoop", InputStopActionLoop ), +#endif DEFINE_KEYFIELD( m_iPlayerDeathBehavior, FIELD_INTEGER, "onplayerdeath" ), DEFINE_INPUTFUNC( FIELD_VOID, "ScriptPlayerDeath", InputScriptPlayerDeath ), @@ -382,6 +385,14 @@ void CAI_ScriptedSequence::InputSetTarget( inputdata_t &inputdata ) m_iszEntity = AllocPooledString(inputdata.value.String()); m_hTargetEnt = NULL; } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAI_ScriptedSequence::InputStopActionLoop( inputdata_t &inputdata ) +{ + StopActionLoop( false ); +} #endif diff --git a/sp/src/game/server/scripted.h b/sp/src/game/server/scripted.h index 7b1d8254..82aae6b3 100644 --- a/sp/src/game/server/scripted.h +++ b/sp/src/game/server/scripted.h @@ -112,6 +112,7 @@ public: void InputCancelSequence( inputdata_t &inputdata ); void InputMoveToPosition( inputdata_t &inputdata ); #ifdef MAPBASE + void InputStopActionLoop( inputdata_t &inputdata ); void InputSetTarget( inputdata_t &inputdata ); #endif diff --git a/sp/src/game/server/sound.cpp b/sp/src/game/server/sound.cpp index cb7df905..167644ab 100644 --- a/sp/src/game/server/sound.cpp +++ b/sp/src/game/server/sound.cpp @@ -938,7 +938,7 @@ void CAmbientGeneric::SendSound( SoundFlags_t flags) { #ifdef MAPBASE int iFlags = flags != SND_STOP ? ((int)flags | m_iSoundFlags) : flags; - char *szSoundFile = (char *)STRING( m_iszSound ); + const char *szSoundFile = STRING( m_iszSound ); CBaseEntity* pSoundSource = m_hSoundSource; if ( pSoundSource ) { diff --git a/sp/src/game/server/subs.cpp b/sp/src/game/server/subs.cpp index 0a37e4c1..53ba8f06 100644 --- a/sp/src/game/server/subs.cpp +++ b/sp/src/game/server/subs.cpp @@ -22,10 +22,10 @@ void CPointEntity::Spawn( void ) } -class CNullEntity : public CBaseEntity +class CNullEntity : public CServerOnlyEntity { public: - DECLARE_CLASS( CNullEntity, CBaseEntity ); + DECLARE_CLASS( CNullEntity, CServerOnlyEntity ); void Spawn( void ); }; diff --git a/sp/src/game/server/triggers.cpp b/sp/src/game/server/triggers.cpp index 2361f8fa..21b7b256 100644 --- a/sp/src/game/server/triggers.cpp +++ b/sp/src/game/server/triggers.cpp @@ -47,6 +47,7 @@ #define DEBUG_TRANSITIONS_VERBOSE 2 ConVar g_debug_transitions( "g_debug_transitions", "0", FCVAR_NONE, "Set to 1 and restart the map to be warned if the map has no trigger_transition volumes. Set to 2 to see a dump of all entities & associated results during a transition." ); +ConVar noclip_changelevel("noclip_changelevel", "0", FCVAR_CHEAT); // Global list of triggers that care about weapon fire // Doesn't need saving, the triggers re-add themselves on restore. @@ -1848,7 +1849,8 @@ void CChangeLevel::TouchChangeLevel( CBaseEntity *pOther ) return; } - if ( !pPlayer->IsInAVehicle() && pPlayer->GetMoveType() == MOVETYPE_NOCLIP ) + + if ( !pPlayer->IsInAVehicle() && pPlayer->GetMoveType() == MOVETYPE_NOCLIP && !noclip_changelevel.GetBool()) { DevMsg("In level transition: %s %s\n", st_szNextMap, st_szNextSpot ); return; diff --git a/sp/src/game/server/vguiscreen.cpp b/sp/src/game/server/vguiscreen.cpp index e049da22..e46afbf5 100644 --- a/sp/src/game/server/vguiscreen.cpp +++ b/sp/src/game/server/vguiscreen.cpp @@ -35,21 +35,21 @@ PRECACHE_REGISTER( vgui_screen ); //----------------------------------------------------------------------------- // Save/load //----------------------------------------------------------------------------- -BEGIN_DATADESC( CVGuiScreen ) +BEGIN_DATADESC(CVGuiScreen) - DEFINE_CUSTOM_FIELD( m_nPanelName, &g_VguiScreenStringOps ), - DEFINE_FIELD( m_nAttachmentIndex, FIELD_INTEGER ), +DEFINE_CUSTOM_FIELD(m_nPanelName, &g_VguiScreenStringOps), +DEFINE_FIELD(m_nAttachmentIndex, FIELD_INTEGER), // DEFINE_FIELD( m_nOverlayMaterial, FIELD_INTEGER ), - DEFINE_FIELD( m_fScreenFlags, FIELD_INTEGER ), - DEFINE_KEYFIELD( m_flWidth, FIELD_FLOAT, "width" ), - DEFINE_KEYFIELD( m_flHeight, FIELD_FLOAT, "height" ), - DEFINE_KEYFIELD( m_strOverlayMaterial, FIELD_STRING, "overlaymaterial" ), - DEFINE_FIELD( m_hPlayerOwner, FIELD_EHANDLE ), +DEFINE_FIELD(m_fScreenFlags, FIELD_INTEGER), +DEFINE_KEYFIELD(m_flWidth, FIELD_FLOAT, "width"), +DEFINE_KEYFIELD(m_flHeight, FIELD_FLOAT, "height"), +DEFINE_KEYFIELD(m_strOverlayMaterial, FIELD_STRING, "overlaymaterial"), +DEFINE_FIELD(m_hPlayerOwner, FIELD_EHANDLE), - DEFINE_INPUTFUNC( FIELD_VOID, "SetActive", InputSetActive ), - DEFINE_INPUTFUNC( FIELD_VOID, "SetInactive", InputSetInactive ), +DEFINE_INPUTFUNC(FIELD_VOID, "SetActive", InputSetActive), +DEFINE_INPUTFUNC(FIELD_VOID, "SetInactive", InputSetInactive), -END_DATADESC() +END_DATADESC(); //----------------------------------------------------------------------------- @@ -75,6 +75,24 @@ bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue ) *s = '\0'; } +#ifdef MAPBASE + // Named command outputs + if (szKeyName[0] == '~' && szKeyName[1]) + { + const char* pszOutputName = szKeyName + 1; + int i = m_PanelOutputs.Find(pszOutputName); + if (!m_PanelOutputs.IsValidIndex(i)) + { + auto pMem = new COutputEvent; + V_memset(pMem, 0, sizeof(COutputEvent)); + i = m_PanelOutputs.Insert(pszOutputName, pMem); + } + + m_PanelOutputs[i]->ParseEventAction(szValue); + return true; + } +#endif // MAPBASE + if ( FStrEq( szKeyName, "panelname" )) { SetPanelName( szValue ); @@ -158,6 +176,106 @@ void CVGuiScreen::OnRestore() BaseClass::OnRestore(); } +#ifdef MAPBASE +CVGuiScreen::~CVGuiScreen() +{ + m_PanelOutputs.PurgeAndDeleteElements(); +} + +int CVGuiScreen::Save(ISave& save) +{ +#if MAPBASE_VER_INT < 8000 + // HACKHACK: Until v8.0, mark this screen as using the new save system to prevent existing saves with vgui_screen from crashing + AddContext( "uses_new_save", "1" ); +#endif + + int status = BaseClass::Save(save); + if (!status) + return 0; + + const int iCount = m_PanelOutputs.Count(); + save.WriteInt(&iCount); + for (int i = 0; i < iCount; i++) + { + CBaseEntityOutput* output = m_PanelOutputs[i]; + const int nElems = output->NumberOfElements(); + save.WriteString(m_PanelOutputs.GetElementName(i)); + save.WriteInt(&nElems); + if (!output->Save(save)) + return 0; + } + + return status; +} + +int CVGuiScreen::Restore(IRestore& restore) +{ + int status = BaseClass::Restore(restore); + if (!status) + return 0; + +#if MAPBASE_VER_INT < 8000 + // HACKHACK: Until v8.0, mark this screen as using the new save system to prevent existing saves with vgui_screen from crashing + if (!HasContext( "uses_new_save", "1" )) + return status; +#endif + + const int iCount = restore.ReadInt(); + m_PanelOutputs.EnsureCapacity(iCount); + for (int i = 0; i < iCount; i++) + { + char cName[MAX_KEY]; + restore.ReadString(cName, MAX_KEY, 0); + const int iIndex = m_PanelOutputs.Insert(cName, new COutputEvent); + const int nElems = restore.ReadInt(); + if (!m_PanelOutputs[iIndex]->Restore(restore, nElems)) + return 0; + } + + return status; +} + +// Handle a command from the client-side vgui panel. +bool CVGuiScreen::HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) +{ +#if defined(HL2MP) // Enable this in multiplayer. + // Restrict to commands from our owning player. + if ((m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) && pClient != m_hPlayerOwner.Get()) + return false; +#endif + + // Give the owning entity a chance to handle the command. + if (GetOwnerEntity() && GetOwnerEntity()->HandleEntityCommand(pClient, pKeyValues)) + return true; + + // See if we have an output for this command. + const int i = m_PanelOutputs.Find(pKeyValues->GetString()); + if (m_PanelOutputs.IsValidIndex(i)) + { + variant_t Val; + Val.Set(FIELD_VOID, NULL); + m_PanelOutputs[i]->FireOutput(Val, pClient, this); + return true; + } + + return false; +} + +CBaseEntityOutput* CVGuiScreen::FindNamedOutput(const char* pszOutput) +{ + if (pszOutput && pszOutput[0] == '~' && pszOutput[1]) + { + const int i = m_PanelOutputs.Find(pszOutput + 1); + if (m_PanelOutputs.IsValidIndex(i)) + return m_PanelOutputs[i]; + + return NULL; + } + + return BaseClass::FindNamedOutput(pszOutput); +} +#endif // MAPBASE + void CVGuiScreen::SetAttachmentIndex( int nIndex ) { m_nAttachmentIndex = nIndex; diff --git a/sp/src/game/server/vguiscreen.h b/sp/src/game/server/vguiscreen.h index cf720916..557cacd7 100644 --- a/sp/src/game/server/vguiscreen.h +++ b/sp/src/game/server/vguiscreen.h @@ -32,6 +32,15 @@ public: virtual void Activate(); virtual void OnRestore(); +#ifdef MAPBASE + ~CVGuiScreen(); + virtual int Save(ISave& save); + virtual int Restore(IRestore& restore); + + virtual bool HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues); + virtual CBaseEntityOutput* FindNamedOutput(const char* pszOutput); +#endif // MAPBASE + const char *GetPanelName() const; // Sets the screen size + resolution @@ -75,6 +84,10 @@ private: CNetworkVar( int, m_fScreenFlags ); CNetworkVar( EHANDLE, m_hPlayerOwner ); +#ifdef MAPBASE + CUtlDict m_PanelOutputs; +#endif // MAPBASE + friend CVGuiScreen *CreateVGuiScreen( const char *pScreenClassname, const char *pScreenType, CBaseEntity *pAttachedTo, CBaseEntity *pOwner, int nAttachmentIndex ); }; diff --git a/sp/src/game/shared/SoundEmitterSystem.cpp b/sp/src/game/shared/SoundEmitterSystem.cpp index 6b10c6fe..131639bd 100644 --- a/sp/src/game/shared/SoundEmitterSystem.cpp +++ b/sp/src/game/shared/SoundEmitterSystem.cpp @@ -1001,7 +1001,11 @@ public: if ( duration ) { - *duration = enginesound->GetSoundDuration( pSample ); + if ( Q_stristr( pSample, ".mp3" ) ) { + *duration = 0; + } else { + *duration = enginesound->GetSoundDuration( pSample ); + } } TraceEmitSound( "EmitAmbientSound: Raw wave emitted '%s' (ent %i)\n", diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index b2cd6bdc..5f957612 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2811,6 +2811,14 @@ HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void ) return NULL; } +//----------------------------------------------------------------------------- +// Vscript: Gets the entity's physics object if it has one +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptPhysicsInitNormal( int nSolidType, int nSolidFlags, bool createAsleep ) +{ + VPhysicsInitNormal( (SolidType_t)nSolidType, nSolidFlags, createAsleep ); +} + #ifdef GAME_DLL #define SCRIPT_NEVER_THINK TICK_NEVER_THINK diff --git a/sp/src/game/shared/baseplayer_shared.cpp b/sp/src/game/shared/baseplayer_shared.cpp index 5ad7d453..9296bfcf 100644 --- a/sp/src/game/shared/baseplayer_shared.cpp +++ b/sp/src/game/shared/baseplayer_shared.cpp @@ -1069,6 +1069,10 @@ float IntervalDistance( float x, float x0, float x1 ) return 0; } +#if !defined(CLIENT_DLL) && defined(MAPBASE_VSCRIPT) +extern ScriptHook_t g_Hook_FindUseEntity; +#endif + CBaseEntity *CBasePlayer::FindUseEntity() { Vector forward, up; @@ -1160,7 +1164,24 @@ CBaseEntity *CBasePlayer::FindUseEntity() // if this is directly under the cursor just return it now if ( i == 0 ) + { +#if !defined(CLIENT_DLL) && defined(MAPBASE_VSCRIPT) + if (m_ScriptScope.IsInitialized() && g_Hook_FindUseEntity.CanRunInScope( m_ScriptScope )) + { + // entity, is_radius + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ToHScript( pNearest ), false }; + if (g_Hook_FindUseEntity.Call( m_ScriptScope, &functionReturn, args )) + { + pObject = ToEnt( functionReturn.m_hScript ); + pNearest = pObject; + } + } + + if (pObject) +#endif return pObject; + } } } } @@ -1245,6 +1266,19 @@ CBaseEntity *CBasePlayer::FindUseEntity() { pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward ); } + +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_FindUseEntity.CanRunInScope(m_ScriptScope)) + { + // entity, is_radius + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ToHScript( pNearest ), true }; + if (g_Hook_FindUseEntity.Call( m_ScriptScope, &functionReturn, args )) + { + pNearest = ToEnt( functionReturn.m_hScript ); + } + } +#endif if ( sv_debug_player_use.GetBool() ) { diff --git a/sp/src/game/shared/gamerules.cpp b/sp/src/game/shared/gamerules.cpp index cb199617..face9d54 100644 --- a/sp/src/game/shared/gamerules.cpp +++ b/sp/src/game/shared/gamerules.cpp @@ -963,3 +963,28 @@ CTacticalMissionManager *CGameRules::TacticalMissionManagerFactory( void ) } #endif + +#ifdef MAPBASE +void CGameRules::ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues) +{ +#ifndef CLIENT_DLL + static int s_nEntityCommandSymbol = KeyValues::CallGetSymbolForString("EntityCommand"); + static int s_nEntIndexSymbol = KeyValues::CallGetSymbolForString("entindex"); + static int s_nCommandDataSymbol = KeyValues::CallGetSymbolForString("command_data"); + + CBasePlayer* pPlayer = (CBasePlayer*)GetContainingEntity(pEntity); + if (!pPlayer) + return; + + if (pKeyValues->GetNameSymbol() == s_nEntityCommandSymbol) + { + CBaseEntity* pEntity = CBaseEntity::Instance(pKeyValues->GetInt(s_nEntIndexSymbol)); + KeyValues* pkvCommand = pKeyValues->FindKey(s_nCommandDataSymbol); + if (pEntity && pkvCommand) + { + pEntity->HandleEntityCommand(pPlayer, pkvCommand); + } + } +#endif // GAME_DLL +} +#endif // MAPBASE diff --git a/sp/src/game/shared/gamerules.h b/sp/src/game/shared/gamerules.h index 9ae672b6..a60f2771 100644 --- a/sp/src/game/shared/gamerules.h +++ b/sp/src/game/shared/gamerules.h @@ -178,7 +178,12 @@ public: //Allow thirdperson camera. virtual bool AllowThirdPersonCamera( void ) { return false; } - virtual void ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues ) {} +#ifdef MAPBASE + virtual void ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues); +#else + virtual void ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues) {} +#endif // MAPBASE + // IsConnectedUserInfoChangeAllowed allows the clients to change // cvars with the FCVAR_NOT_CONNECTED rule if it returns true diff --git a/sp/src/game/shared/in_buttons.h b/sp/src/game/shared/in_buttons.h index 870961f8..74e2ca5f 100644 --- a/sp/src/game/shared/in_buttons.h +++ b/sp/src/game/shared/in_buttons.h @@ -43,6 +43,10 @@ #define IN_GRENADE2 (1 << 24) // grenade 2 #define IN_ATTACK3 (1 << 25) +#ifdef MAPBASE +#define IN_VGUIMODE (1 << 26) +#endif // MAPBASE + #ifdef VGUI_SCREEN_FIX #define IN_VALIDVGUIINPUT (1 << 23) //bitflag for vgui fix #endif diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index 2ced7086..bb47bcb1 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -290,6 +290,17 @@ void RegisterSharedScriptConstants() ScriptRegisterConstant( g_pScriptVM, EF_ITEM_BLINK, "Effect flag used in GetEffects(), etc." ); ScriptRegisterConstant( g_pScriptVM, EF_PARENT_ANIMATES, "Effect flag used in GetEffects(), etc." ); + // + // Solid Types + // + ScriptRegisterConstant( g_pScriptVM, SOLID_NONE, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_BSP, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_BBOX, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_OBB, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_OBB_YAW, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_CUSTOM, "Solid type used by VPhysics" ); + ScriptRegisterConstant( g_pScriptVM, SOLID_VPHYSICS, "Solid type used by VPhysics" ); + // // Solid Flags // diff --git a/sp/src/game/shared/mapbase/vscript_funcs_hl2.cpp b/sp/src/game/shared/mapbase/vscript_funcs_hl2.cpp index 189f8883..529d0291 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_hl2.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_hl2.cpp @@ -10,6 +10,8 @@ #include "hl2_gamerules.h" #ifndef CLIENT_DLL #include "eventqueue.h" +#include "weapon_physcannon.h" +#include "player_pickup.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -47,6 +49,48 @@ bool ScriptMegaPhyscannonActive() { return HL2GameRules()->MegaPhyscannonActive(); } + +void ScriptPickup_ForcePlayerToDropThisObject( HSCRIPT hTarget ) +{ + Pickup_ForcePlayerToDropThisObject( ToEnt( hTarget ) ); +} + +float ScriptPlayerPickupGetHeldObjectMass( HSCRIPT hPickupControllerEntity, HSCRIPT hHeldObject ) +{ + IPhysicsObject *pPhysObj = HScriptToClass( hHeldObject ); + if (!pPhysObj) + { + CBaseEntity *pEnt = ToEnt( hHeldObject ); + if (pEnt) + pPhysObj = pEnt->VPhysicsGetObject(); + } + + if (!pPhysObj) + { + Warning( "PlayerPickupGetHeldObjectMass: Invalid physics object\n" ); + return 0.0f; + } + + return PlayerPickupGetHeldObjectMass( ToEnt( hPickupControllerEntity ), pPhysObj ); +} + +HSCRIPT ScriptGetPlayerHeldEntity( HSCRIPT hPlayer ) +{ + CBasePlayer *pPlayer = ToBasePlayer( ToEnt( hPlayer ) ); + if (!pPlayer) + return NULL; + + return ToHScript( GetPlayerHeldEntity( pPlayer ) ); +} + +HSCRIPT ScriptPhysCannonGetHeldEntity( HSCRIPT hWeapon ) +{ + CBaseEntity *pEnt = ToEnt( hWeapon ); + if (!pEnt) + return NULL; + + return ToHScript( PhysCannonGetHeldEntity( pEnt->MyCombatWeaponPointer() ) ); +} #endif //----------------------------------------------------------------------------- @@ -59,5 +103,10 @@ void CHalfLife2::RegisterScriptFunctions( void ) #ifndef CLIENT_DLL ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGameOver, "GameOver", "Ends the game and reloads the last save." ); ScriptRegisterFunctionNamed( g_pScriptVM, ScriptMegaPhyscannonActive, "MegaPhyscannonActive", "Checks if supercharged gravity gun mode is enabled." ); + + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPickup_ForcePlayerToDropThisObject, "Pickup_ForcePlayerToDropThisObject", "If the specified entity is being carried, instantly drops it." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPlayerPickupGetHeldObjectMass, "PlayerPickupGetHeldObjectMass", "Gets the mass of the specified player_pickup controller, with the second parameter the held object's physics object." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptGetPlayerHeldEntity, "GetPlayerHeldEntity", "Gets the specified player's currently held entity." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPhysCannonGetHeldEntity, "PhysCannonGetHeldEntity", "Gets the specified gravity gun's currently held entity." ); #endif } diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index 4c6d4817..227103df 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -771,6 +771,26 @@ static void AddPhysVelocity( HSCRIPT hPhys, const Vector& vecVelocity, const Vec pPhys->AddVelocity( &vecVelocity, &vecAngVelocity ); } +static void ScriptPhysEnableEntityCollisions( HSCRIPT hPhys1, HSCRIPT hPhys2 ) +{ + IPhysicsObject *pPhys1 = HScriptToClass( hPhys1 ); + IPhysicsObject *pPhys2 = HScriptToClass( hPhys2 ); + if (!pPhys1 || !pPhys2) + return; + + PhysEnableEntityCollisions( pPhys1, pPhys2 ); +} + +static void ScriptPhysDisableEntityCollisions( HSCRIPT hPhys1, HSCRIPT hPhys2 ) +{ + IPhysicsObject *pPhys1 = HScriptToClass( hPhys1 ); + IPhysicsObject *pPhys2 = HScriptToClass( hPhys2 ); + if (!pPhys1 || !pPhys2) + return; + + PhysDisableEntityCollisions( pPhys1, pPhys2 ); +} + //============================================================================= //============================================================================= @@ -1045,6 +1065,8 @@ void RegisterSharedScriptFunctions() ScriptRegisterFunction( g_pScriptVM, GetPhysAngVelocity, "Gets physics angular velocity for the given VPhysics object" ); ScriptRegisterFunction( g_pScriptVM, SetPhysVelocity, "Sets physics velocity for the given VPhysics object" ); ScriptRegisterFunction( g_pScriptVM, AddPhysVelocity, "Adds physics velocity for the given VPhysics object" ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPhysEnableEntityCollisions, "PhysEnableEntityCollisions", "Enables collisions between two VPhysics objects"); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPhysDisableEntityCollisions, "PhysDisableEntityCollisions", "Disables collisions between two VPhysics objects"); // // Precaching diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 86b1248f..d9950998 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -14,7 +14,13 @@ #include "ammodef.h" #include "tier1/utlcommon.h" +#include "soundenvelope.h" +#include "saverestore_utlvector.h" +#include "stdstring.h" + #ifndef CLIENT_DLL +#include "ai_speech.h" +#include "ai_memory.h" #include "ai_squad.h" #endif // !CLIENT_DLL @@ -44,285 +50,2492 @@ extern IScriptManager *scriptmanager; + +#ifdef GAME_DLL + extern void SendProxy_StringT_To_String(const SendProp*, const void*, const void*, DVariant*, int, int); + extern void SendProxy_UtlVectorLength(const SendProp*, const void*, const void*, DVariant*, int, int); + class CSendProxyRecipients; + extern void* SendProxy_LengthTable(const SendProp*, const void*, const void* pData, CSendProxyRecipients*, int); + #define DataTableProxy_EHandle SendProxy_EHandleToInt + #define DataTableProxy_String SendProxy_StringToString + #define DataTableProxy_TableLength SendProxy_LengthTable + #define DataTableProxy_UtlVectorLength SendProxy_UtlVectorLength +#else + extern void RecvProxy_UtlVectorLength(const CRecvProxyData*, void*, void*); + extern void DataTableRecvProxy_LengthProxy(const RecvProp*, void**, void*, int); + #define DataTableProxy_EHandle RecvProxy_IntToEHandle + #define DataTableProxy_String RecvProxy_StringToString + #define DataTableProxy_TableLength DataTableRecvProxy_LengthProxy + #define DataTableProxy_UtlVectorLength RecvProxy_UtlVectorLength +#endif +extern ISaveRestoreOps* GetPhysObjSaveRestoreOps( PhysInterfaceId_t ); +extern ISaveRestoreOps* ActivityDataOps(); +extern ISaveRestoreOps* GetSoundSaveRestoreOps(); +extern ISaveRestoreOps* GetStdStringDataOps(); +#ifdef GAME_DLL + #define UTLVECTOR_DATAOPS( fieldType, dataType )\ + CUtlVectorDataopsInstantiator< fieldType >::GetDataOps( (CUtlVector< dataType >*)0 ) + #define IS_EHANDLE_UTLVECTOR( td )\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBaseEntity > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBaseFlex > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBaseAnimating > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBaseCombatWeapon > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CBasePlayer > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CAI_BaseNPC > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CSceneEntity > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CSceneListManager > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CRagdollBoogie > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CFish > ) ||\ + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_EHANDLE, CHandle< CVGuiScreen > ) + + class CSceneListManager; + class CRagdollBoogie; + class CFish; + #ifdef _DEBUG + class CStringTableSaveRestoreOps; + extern CStringTableSaveRestoreOps g_VguiScreenStringOps; + extern INetworkStringTable *g_pStringTableVguiScreen; + extern ISaveRestoreOps *thinkcontextFuncs; + class CAI_EnemiesListSaveRestoreOps; + extern CAI_EnemiesListSaveRestoreOps g_AI_MemoryListSaveRestoreOps; + class CConceptHistoriesDataOps; + extern CConceptHistoriesDataOps g_ConceptHistoriesSaveDataOps; + #endif +#endif + //============================================================================= // Net Prop Manager // Based on L4D2 API //============================================================================= class CScriptNetPropManager { -public: +private: +#if GAME_DLL + typedef SendProp NetProp; + typedef SendTable NetTable; + typedef ServerClass NetworkClass; -#ifdef CLIENT_DLL - RecvProp *RecurseTable( RecvTable *pTable, const char *pszPropName ) + NetworkClass *GetNetworkClass( CBaseEntity* p ) { return p->GetServerClass(); } + NetTable *GetNetTable( NetworkClass* p ) { return p->m_pTable; } + + void NetworkStateChanged( CBaseEntity* p, int o ) { p->NetworkProp()->NetworkStateChanged( o ); } #else - SendProp *RecurseTable( SendTable *pTable, const char *pszPropName ) + typedef RecvProp NetProp; + typedef RecvTable NetTable; + typedef ClientClass NetworkClass; + + NetworkClass *GetNetworkClass( CBaseEntity* p ) { return p->GetClientClass(); } + NetTable *GetNetTable( NetworkClass* p ) { return p->m_pRecvTable; } + + void NetworkStateChanged( CBaseEntity*, int ) {} #endif + + int GetClassID( CBaseEntity *p ) { -#ifdef CLIENT_DLL - RecvProp *pProp = NULL; + return GetNetworkClass( p )->m_ClassID; + } + + int GetIntPropSize( NetProp *pProp ) + { + Assert( pProp->GetType() == DPT_Int ); + +#ifdef GAME_DLL + extern void SendProxy_UInt8ToInt32( const SendProp*, const void*, const void*, DVariant*, int, int ); + extern void SendProxy_UInt16ToInt32( const SendProp*, const void*, const void*, DVariant*, int, int ); + extern void SendProxy_UInt32ToInt32( const SendProp*, const void*, const void*, DVariant*, int, int ); + + SendVarProxyFn proxy = pProp->GetProxyFn(); + + if ( proxy == SendProxy_Int8ToInt32 || proxy == SendProxy_UInt8ToInt32 ) + return 8; + if ( proxy == SendProxy_Int16ToInt32 || proxy == SendProxy_UInt16ToInt32 ) + return 16; + if ( proxy == SendProxy_Int32ToInt32 || proxy == SendProxy_UInt32ToInt32 ) + return 32; + + return pProp->m_nBits; #else - SendProp *pProp = NULL; + RecvVarProxyFn proxy = pProp->GetProxyFn(); + + if ( proxy == RecvProxy_Int32ToInt8 ) + return 8; + if ( proxy == RecvProxy_Int32ToInt16 ) + return 16; + if ( proxy == RecvProxy_Int32ToInt32 ) + return 32; + + return 0; #endif - for (int i = 0; i < pTable->GetNumProps(); i++) + } + + bool IsEHandle( NetProp *pProp ) + { + return ( pProp->GetProxyFn() == DataTableProxy_EHandle ); + } + + bool IsUtlVector( NetProp *pProp ) + { +#ifdef GAME_DLL + SendVarProxyFn proxy = pProp->GetProxyFn(); +#else + RecvVarProxyFn proxy = pProp->GetProxyFn(); +#endif + + return ( proxy == DataTableProxy_UtlVectorLength ); + } + +private: + enum types + { + _INT1 = ( 1 << 0 ), + _INT8 = ( 1 << 1 ), + _INT16 = ( 1 << 2 ), + _INT32 = ( 1 << 3 ), + _FLOAT = ( 1 << 4 ), + _VEC3 = ( 1 << 5 ), + _VEC2 = ( 1 << 6 ), + _EHANDLE = ( 1 << 7 ), + _CLASSPTR = ( 1 << 8 ), + _EDICT = ( 1 << 9 ), + _CSTRING = ( 1 << 10 ), + _STRING_T = ( 1 << 11 ), + _ARRAY = ( 1 << 12 ), + _DATATABLE = ( 1 << 13 ), + + _PHYS = ( 1 << 14 ), + _STDSTRING = _CSTRING | _STRING_T, + + _DAR_EHANDLE = _EHANDLE | _ARRAY, + _DAR_CLASSPTR = _CLASSPTR | _ARRAY, + _DAR_INT = _INT32 | _ARRAY, + _DAR_FLOAT = _FLOAT | _ARRAY, + + //_MAX = ( 1 << 15 ) + }; + + // UNDONE: Special case for GetPropType() to be able to return the table/array itself + #define INDEX_GET_TYPE 0 + + #define MASK_INT_SIZE( _size ) ( ( 1 << (_size - 1) ) | ( (1 << (_size - 1)) - 1 ) ) + #define MASK_NEAREST_BYTE( _bits ) ( ( (1 << ALIGN_TO_NEAREST_BYTE(_bits)) - 1 ) & ~((1 << _bits) - 1) ) + #define ALIGN_TO_NEAREST_BYTE( _bits ) ( (_bits + 7) & ~7 ) + #define VARINFO_ARRAYSIZE_BITS 12 + + struct varinfo_t + { + int offset : 32; // actually a short + + union { - pProp = pTable->GetProp( i ); - if (pProp->GetType() == DPT_DataTable) + int mask : 32; + int stringsize : 32; + }; + + enum types datatype : 16; + + // element size in bytes + unsigned int elemsize : 8; + unsigned int arraysize : VARINFO_ARRAYSIZE_BITS; + + // Following are only used in integer netprops to handle unsigned and size casting + bool isUnsigned : 1; + bool isNotNetworked : 1; + + int GetOffset( int index ) + { + return offset + index * elemsize; + } + }; + + // Wrapper to be able to set case sensitive comparator in node insertion + class vardict_t : public CUtlDict< varinfo_t > + { + public: + vardict_t() : CUtlDict< varinfo_t >( k_eDictCompareTypeCaseSensitive ) {} + }; + + // NOTE: This is lazy and inefficient. + // Simply map highest level class id to unique caches. + CUtlVector< int > m_EntMap; + CUtlVector< vardict_t > m_VarDicts; + + varinfo_t* CacheNew( CBaseEntity *pEnt, const char *szProp ) + { + int idx = m_EntMap.Find( GetClassID( pEnt ) ); + if ( idx == m_EntMap.InvalidIndex() ) + { + // Vector indices are kept in parallel as a workaround for encapsulating maps + idx = m_EntMap.AddToTail( GetClassID( pEnt ) ); + m_VarDicts.AddToTail(); + } + + vardict_t &dict = m_VarDicts.Element( idx ); + + idx = dict.Find( szProp ); + if ( idx == dict.InvalidIndex() ) + idx = dict.Insert( szProp ); + + varinfo_t *pInfo = &dict.Element( idx ); + V_memset( pInfo, 0, sizeof( varinfo_t ) ); + return pInfo; + } + + varinfo_t* CacheFetch( CBaseEntity *pEnt, const char *szProp ) + { + int idx = m_EntMap.Find( GetClassID( pEnt ) ); + if ( idx == m_EntMap.InvalidIndex() ) + return NULL; + + vardict_t &dict = m_VarDicts.Element( idx ); + idx = dict.Find( szProp ); + if ( idx == dict.InvalidIndex() ) + return NULL; + + varinfo_t *pInfo = &dict.Element( idx ); + return pInfo; + } + +public: + ~CScriptNetPropManager() + { + PurgeCache(); + } + + void PurgeCache() + { + m_EntMap.Purge(); + m_VarDicts.Purge(); + } + +private: + typedescription_t *FindField( char *pBase, datamap_t *map, const char *szName, int *offset ) + { + if ( map->baseMap ) + { + typedescription_t* p = FindField( pBase, map->baseMap, szName, offset ); + if ( p ) + return p; + } + + typedescription_t *pFields = map->dataDesc; + int numFields = map->dataNumFields; + + for ( int i = 0; i < numFields; i++ ) + { + typedescription_t* td = &pFields[i]; + int fieldType = td->fieldType; + int fieldOffset = td->fieldOffset[ TD_OFFSET_NORMAL ]; + + if ( td->flags & (FTYPEDESC_FUNCTIONTABLE | FTYPEDESC_INPUT | FTYPEDESC_OUTPUT) ) + continue; + + if ( fieldType == FIELD_VOID || fieldType == FIELD_FUNCTION ) + continue; + + if ( !V_strcmp( td->fieldName, szName ) ) { - pProp = RecurseTable(pProp->GetDataTable(), pszPropName); - if (pProp) - return pProp; - } - else - { - if (FStrEq( pProp->GetName(), pszPropName )) - return pProp; + *offset += fieldOffset; + + if ( td->flags & FTYPEDESC_PTR ) + { + // Follow the pointer + char * const pRef = *(char**)( pBase + *offset ); + Assert( pRef ); + *offset = pRef - pBase; + } + + return td; } } return NULL; } -#ifdef CLIENT_DLL - RecvProp *RecurseNetworkClass( ClientClass *pClass, const char *pszPropName ) -#else - SendProp *RecurseNetworkClass( ServerClass *pClass, const char *pszPropName ) -#endif + NetProp *FindProp( char *pBase, NetTable *pTable, const char *szName, int *offset ) { -#ifdef CLIENT_DLL - RecvProp *pProp = RecurseTable( pClass->m_pRecvTable, pszPropName ); -#else - SendProp *pProp = RecurseTable( pClass->m_pTable, pszPropName ); -#endif - if (pProp) + int numProps = pTable->GetNumProps(); + + for ( int i = 0; i < numProps; i++ ) + { + NetProp* pProp = pTable->GetProp(i); + + if ( pProp->IsInsideArray() ) + continue; + + if ( !V_strcmp( pProp->GetName(), szName ) ) + { + *offset += pProp->GetOffset(); + return pProp; + } + + // Go into inherited fields but not member tables, they are looked up explicitly + // This is only a problem with m_AnimOverlay + if ( ( pProp->GetFlags() & SPROP_COLLAPSIBLE ) || + ( pProp->GetType() == DPT_DataTable && pProp->GetOffset() == 0 ) ) + { + // Don't go into lengthproxy + if ( pProp->GetDataTableProxyFn() == DataTableProxy_TableLength ) + continue; + + NetProp *p = FindProp( pBase + pProp->GetOffset(), pProp->GetDataTable(), szName, offset ); + if ( p ) + { + *offset += pProp->GetOffset(); + return p; + } + } + } + + return NULL; + } + + typedescription_t *FindInDataMap( char * const pBase, datamap_t *map, const char *szFullProp, int *offset ) + { + *offset = 0; + + // Look for exact match + typedescription_t *pField = FindField( pBase, map, szFullProp, offset ); + if ( pField ) + return pField; + + // Look for members + const char *pszProp = szFullProp; + const char *pszPropEnd = V_strnchr( pszProp, '.', 512 ); + if ( !pszPropEnd ) + return NULL; + do + { + // this string comes from squirrel stringtable, it can be modified + *((char*)pszPropEnd) = 0; + pField = FindField( pBase, map, pszProp, offset ); + *((char*)pszPropEnd) = '.'; + pszProp = pszPropEnd + 1; + + if ( !pField || ( map = pField->td ) == NULL ) + return NULL; + + // Look for exact match again, just in case + pField = FindField( pBase, map, pszProp, offset ); + if ( pField ) + return pField; + } while ( ( pszPropEnd = V_strnchr( pszProp, '.', 512 ) ) != NULL ); + + return FindField( pBase, map, pszProp, offset ); + } + + NetProp *FindInNetTable( char * const pBase, NetTable *pTable, const char *szFullProp, int *offset ) + { + *offset = 0; + + // Look for exact match + NetProp *pProp = FindProp( pBase, pTable, szFullProp, offset ); + if ( pProp ) return pProp; - if (pClass->m_pNext) - return RecurseNetworkClass( pClass->m_pNext, pszPropName ); - else + // Look for members + const char *pszProp = szFullProp; + const char *pszPropEnd = V_strnchr( pszProp, '.', 512 ); + if ( !pszPropEnd ) return NULL; + do + { + // this string comes from squirrel stringtable, it can be modified + *((char*)pszPropEnd) = 0; + pProp = FindProp( pBase, pTable, pszProp, offset ); + *((char*)pszPropEnd) = '.'; + pszProp = pszPropEnd + 1; + + if ( !pProp || ( pTable = pProp->GetDataTable() ) == NULL ) + return NULL; + + // Look for exact match again for fields such as m_Local{m_skybox3d.scale} + pProp = FindProp( pBase, pTable, pszProp, offset ); + if ( pProp ) + return pProp; + } while ( ( pszPropEnd = V_strnchr( pszProp, '.', 512 ) ) != NULL ); + + return FindProp( pBase, pTable, pszProp, offset ); } + // Searches NetTable first to handle overwritten member network variables - see + // CPlayerResource::m_iHealth and CBaseEntity::m_iHealth + varinfo_t *GetVarInfo( CBaseEntity *pEnt, const char *szProp, int index ) + { + int offset = 0; + NetTable *pTable = GetNetTable( GetNetworkClass( pEnt ) ); + NetProp *pProp = FindInNetTable( (char*)pEnt, pTable, szProp, &offset ); + if ( pProp ) + { + +#define SetVarInfo()\ + varinfo_t *pInfo = CacheNew( pEnt, szProp );\ + pInfo->isNotNetworked = 0;\ + pInfo->elemsize = pProp->GetElementStride();\ + pInfo->arraysize = pProp->GetNumElements();\ + pInfo->offset = offset; + + switch ( pProp->GetType() ) + { + case DPT_Int: + { + if ( IsUtlVector( pProp ) ) + { + return NULL; + } + + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + + if ( IsEHandle( pProp ) ) + { + Assert( pProp->GetElementStride() == sizeof(int) || pProp->GetElementStride() < 0 ); + + SetVarInfo(); + pInfo->datatype = types::_EHANDLE; + return pInfo; + } + else + { + const int size = GetIntPropSize( pProp ); #ifdef CLIENT_DLL - RecvProp *GetPropByName( CBaseEntity *pEnt, const char *pszPropName ) - { - if (pEnt) - { - return RecurseNetworkClass( pEnt->GetClientClass(), pszPropName ); - } - - return NULL; - } -#else - SendProp *GetPropByName( CBaseEntity *pEnt, const char *pszPropName ) - { - if (pEnt) - { - return RecurseNetworkClass( pEnt->GetServerClass(), pszPropName ); - } - - return NULL; - } + // Client might be reading any amount of bits in a custom RecvProxy + // Break and check the datamaps + if ( size == 0 ) + break; #endif + Assert( size <= pProp->GetElementStride() || pProp->GetElementStride() < 0 ); - int GetPropArraySize( HSCRIPT hEnt, const char *pszPropName ) + SetVarInfo(); + pInfo->mask = MASK_INT_SIZE( size ); + pInfo->datatype = types::_INT32; + return pInfo; + } + } + case DPT_Float: + { + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + Assert( pProp->GetElementStride() == sizeof(float) || pProp->GetElementStride() < 0 ); + + SetVarInfo(); + pInfo->datatype = types::_FLOAT; + return pInfo; + } + case DPT_Vector: + { + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + Assert( pProp->GetElementStride() == sizeof(float)*3 || pProp->GetElementStride() < 0 ); + + SetVarInfo(); + pInfo->datatype = types::_VEC3; + return pInfo; + } + case DPT_VectorXY: + { + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + Assert( pProp->GetElementStride() == sizeof(float)*2 || pProp->GetElementStride() < 0 ); + + SetVarInfo(); + pInfo->datatype = types::_VEC2; + return pInfo; + } + case DPT_String: + { + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + Assert( index == 0 || pProp->GetElementStride() > 0 ); + + SetVarInfo(); +#ifdef GAME_DLL + pInfo->stringsize = 0; +#else + pInfo->stringsize = pProp->m_StringBufferSize; +#endif +#ifdef GAME_DLL + if ( pProp->GetProxyFn() == SendProxy_StringT_To_String ) + { + pInfo->datatype = types::_STRING_T; + } + else +#endif + { + Assert( pProp->GetProxyFn() == DataTableProxy_String ); + pInfo->datatype = types::_CSTRING; + } + return pInfo; + } + case DPT_DataTable: + { + NetTable* pArray = pProp->GetDataTable(); + + if ( V_strcmp( pProp->GetName(), pArray->GetName() ) != 0 ) + { + Warning( "DT is not an array! %s(%s)\n", pProp->GetName(), pArray->GetName() ); + return NULL; + } + + if ( index < 0 || index >= pArray->GetNumProps() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + pProp = pArray->GetProp( index ); + + switch ( pProp->GetType() ) + { + case DPT_Int: + { + if ( IsEHandle( pProp ) ) + { + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + pInfo->elemsize = sizeof(int); + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->datatype = types::_EHANDLE; + return pInfo; + } + else + { + const int size = GetIntPropSize( pProp ); +#ifdef CLIENT_DLL + // Client might be reading any amount of bits in a custom RecvProxy + // Break and check the datamaps + if ( size == 0 ) + break; +#endif + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + + if ( pArray->GetNumProps() > 1 ) + { + pInfo->elemsize = pArray->GetProp(1)->GetOffset() - pArray->GetProp(0)->GetOffset(); + } + else + { + // Doesn't matter for an array of a single element + pInfo->elemsize = 0; + } + + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->mask = MASK_INT_SIZE( size ); + pInfo->datatype = types::_INT32; + return pInfo; + } + } + case DPT_Float: + { + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + pInfo->elemsize = sizeof(float); + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->datatype = types::_FLOAT; + return pInfo; + } + case DPT_Vector: + { + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + pInfo->elemsize = sizeof(float)*3; + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->datatype = types::_VEC3; + return pInfo; + } + case DPT_VectorXY: + { + varinfo_t *pInfo = CacheNew( pEnt, szProp ); + pInfo->elemsize = sizeof(float)*2; + pInfo->arraysize = pArray->GetNumProps(); + pInfo->offset = offset; + pInfo->datatype = types::_VEC2; + return pInfo; + } + case DPT_DataTable: + { + AssertMsg( 0, "DT in DT" ); + return NULL; + } + case DPT_Array: + { + AssertMsg( 0, "Array in DT" ); + return NULL; + } + case DPT_String: + { + AssertMsg( 0, "String in DT" ); + return NULL; + } + default: UNREACHABLE(); + } +#ifdef CLIENT_DLL + // DPT_Int can break into here for datamap fallback + break; +#else + UNREACHABLE(); +#endif + } // DPT_DataTable + case DPT_Array: + { + Assert( pProp->GetArrayProp() ); + + NetProp *pArray = pProp->GetArrayProp(); + offset += pArray->GetOffset(); + + if ( index < 0 || index >= pProp->GetNumElements() ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + + switch ( pArray->GetType() ) + { + case DPT_Int: + { + Assert( index == 0 || pProp->GetElementStride() > 0 ); + + if ( IsEHandle( pArray ) ) + { + SetVarInfo(); + pInfo->datatype = types::_EHANDLE; + return pInfo; + } + else + { + const int size = GetIntPropSize( pArray ); +#ifdef CLIENT_DLL + // Client might be reading any amount of bits in a custom RecvProxy + // Break and check the datamaps + if ( size == 0 ) + break; +#endif + SetVarInfo(); + pInfo->mask = MASK_INT_SIZE( size ); + pInfo->datatype = types::_INT32; + return pInfo; + } + } + case DPT_Float: + { + SetVarInfo(); + pInfo->datatype = types::_FLOAT; + return pInfo; + } + case DPT_Vector: + { + SetVarInfo(); + pInfo->datatype = types::_VEC3; + return pInfo; + } + case DPT_VectorXY: + { + SetVarInfo(); + pInfo->datatype = types::_VEC2; + return pInfo; + } + case DPT_String: + { + AssertMsg( 0, "String array not implemented" ); + return NULL; + } + case DPT_Array: + case DPT_DataTable: AssertMsg( 0, "DT in array" ); + default: UNREACHABLE(); + } +#ifdef CLIENT_DLL + // DPT_Int can break into here for datamap fallback + break; +#else + UNREACHABLE(); +#endif + } // DPT_Array + default: UNREACHABLE(); + } + // ambigious int size on client, check the datamaps +#undef SetVarInfo + } + + datamap_t *map = pEnt->GetDataDescMap(); + typedescription_t *pField = FindInDataMap( (char*)pEnt, map, szProp, &offset ); + if ( pField ) + { +#ifdef CLIENT_DLL +find_field: +#endif + if ( index < 0 || index >= pField->fieldSize ) + { + Warning( "NetProp element index out of range! %s[%d]\n", szProp, index ); + return NULL; + } + +#define SetVarInfo()\ + varinfo_t *pInfo = CacheNew( pEnt, szProp );\ + pInfo->isNotNetworked = 1;\ + pInfo->elemsize = pField->fieldSizeInBytes / pField->fieldSize;\ + pInfo->arraysize = pField->fieldSize;\ + pInfo->offset = offset; + + switch ( pField->fieldType ) + { + case FIELD_INTEGER: + case FIELD_MATERIALINDEX: + case FIELD_MODELINDEX: + case FIELD_COLOR32: + case FIELD_TICK: + case FIELD_BOOLEAN: + case FIELD_CHARACTER: + case FIELD_SHORT: + { + SetVarInfo(); + pInfo->isUnsigned = ( pField->flags & SPROP_UNSIGNED ) != 0; + pInfo->isNotNetworked = 1; + switch ( pField->fieldType ) + { + case FIELD_INTEGER: + case FIELD_MATERIALINDEX: + case FIELD_MODELINDEX: + case FIELD_COLOR32: + case FIELD_TICK: + pInfo->datatype = types::_INT32; break; + case FIELD_BOOLEAN: + pInfo->datatype = types::_INT1; break; + case FIELD_CHARACTER: + Assert( pField->fieldSizeInBytes == pField->fieldSize ); + pInfo->stringsize = pField->fieldSizeInBytes; + pInfo->datatype = types::_INT8; break; + case FIELD_SHORT: + pInfo->datatype = types::_INT16; break; + default: UNREACHABLE(); + } + return pInfo; + } + case FIELD_FLOAT: + case FIELD_TIME: + { + Assert( sizeof(float) == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_FLOAT; + return pInfo; + } + case FIELD_EHANDLE: + { + Assert( sizeof(int) == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_EHANDLE; + return pInfo; + } +#ifdef GAME_DLL + case FIELD_CLASSPTR: + { + Assert( sizeof(int*) == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_CLASSPTR; + return pInfo; + } + case FIELD_EDICT: + { + Assert( sizeof(int*) == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_EDICT; + return pInfo; + } +#endif + case FIELD_VECTOR: + case FIELD_POSITION_VECTOR: + { + Assert( sizeof(float)*3 == pField->fieldSizeInBytes / pField->fieldSize ); + + SetVarInfo(); + pInfo->datatype = types::_VEC3; + return pInfo; + } + case FIELD_STRING: + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: + { + SetVarInfo(); + pInfo->stringsize = 0; + pInfo->datatype = types::_STRING_T; + return pInfo; + } + case FIELD_CUSTOM: + { + if ( pField->pSaveRestoreOps == GetPhysObjSaveRestoreOps( PIID_IPHYSICSOBJECT ) ) + { + SetVarInfo(); + pInfo->datatype = types::_PHYS; + return pInfo; + } + else if ( pField->pSaveRestoreOps == ActivityDataOps() ) + { + SetVarInfo(); + pInfo->datatype = types::_INT32; + return pInfo; + } +#ifdef GAME_DLL + else if ( IS_EHANDLE_UTLVECTOR( pField ) ) + { + SetVarInfo(); + pInfo->arraysize = ( 1 << VARINFO_ARRAYSIZE_BITS ) - 1; // dynamic, check on get + pInfo->datatype = types::_DAR_EHANDLE; + } + else if ( pField->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_CLASSPTR, CBaseEntity* ) ) + { + SetVarInfo(); + pInfo->arraysize = ( 1 << VARINFO_ARRAYSIZE_BITS ) - 1; // dynamic, check on get + pInfo->datatype = types::_DAR_CLASSPTR; + } + else if ( pField->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_INTEGER, int ) ) + { + SetVarInfo(); + pInfo->arraysize = ( 1 << VARINFO_ARRAYSIZE_BITS ) - 1; // dynamic, check on get + pInfo->datatype = types::_DAR_INT; + } + else if ( pField->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_FLOAT, float ) || + pField->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_TIME, float ) ) + { + SetVarInfo(); + pInfo->arraysize = ( 1 << VARINFO_ARRAYSIZE_BITS ) - 1; // dynamic, check on get + pInfo->datatype = types::_DAR_FLOAT; + } + // Only used by CAI_PlayerAlly::m_PendingConcept + else if ( pField->pSaveRestoreOps == GetStdStringDataOps() ) + { + SetVarInfo(); + pInfo->datatype = types::_STDSTRING; + return pInfo; + } +#endif + return NULL; + } + case FIELD_EMBEDDED: + return NULL; + default: + AssertMsg( 0, "Unknown type %d\n", pField->fieldType ); + return NULL; + } + UNREACHABLE(); +#undef SetVarInfo + } +#ifdef CLIENT_DLL + else + { + map = pEnt->GetPredDescMap(); + pField = FindInDataMap( (char*)pEnt, map, szProp, &offset ); + if ( pField ) + { + goto find_field; + } + } +#endif + return NULL; + } + +public: + // FIXME: Cannot get datatable/arrays at the moment + bool HasProp( HSCRIPT hEnt, const char *szProp ) { CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp) + if ( !pEnt ) + return false; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) { - // TODO: Is this what this function wants? - return pProp->GetNumElements(); + pInfo = GetVarInfo( pEnt, szProp, INDEX_GET_TYPE ); + + if ( !pInfo ) + return false; + } + + return true; + } + + // FIXME: Cannot get datatable/arrays at the moment + const char *GetPropType( HSCRIPT hEnt, const char *szProp ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return NULL; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, INDEX_GET_TYPE ); + + if ( !pInfo ) + return NULL; + } + + switch ( pInfo->datatype ) + { + case types::_INT1: + case types::_INT8: + case types::_INT16: + case types::_INT32: + return "integer"; + case types::_FLOAT: + return "float"; + case types::_VEC3: + return "vector"; + case types::_VEC2: + return "vector2d"; + case types::_CSTRING: + case types::_STRING_T: + case types::_STDSTRING: + return "string"; + case types::_EHANDLE: + case types::_CLASSPTR: + case types::_EDICT: + return "entity"; + case types::_PHYS: + return "phys"; + case types::_ARRAY: + return "array"; + case types::_DATATABLE: + return "datatable"; + } + + if ( pInfo->arraysize > 1 ) + return "array"; + + return ""; + } + + int GetPropArraySize( HSCRIPT hEnt, const char *szProp ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return -1; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, INDEX_GET_TYPE ); + + if ( !pInfo ) + return -1; + } +#ifdef GAME_DLL + switch ( pInfo->datatype ) + { + case types::_DAR_EHANDLE: + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + return vec.Count(); + } + case types::_DAR_CLASSPTR: + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + return vec.Count(); + } + case types::_DAR_INT: + { + CUtlVector< int > &vec = *(CUtlVector< int >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + return vec.Count(); + } + case types::_DAR_FLOAT: + { + CUtlVector< float > &vec = *(CUtlVector< float >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + return vec.Count(); + } + } +#endif + return pInfo->arraysize; + } + +public: + int GetPropIntArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return -1; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return -1; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return -1; + + if ( pInfo->isNotNetworked ) + { + switch ( pInfo->datatype ) + { + case types::_INT32: + if ( pInfo->isUnsigned ) + return *(unsigned int*)((char*)pEnt + pInfo->GetOffset( index )); + return *(int*)((char*)pEnt + pInfo->GetOffset( index )); + case types::_INT1: + return *(bool*)((char*)pEnt + pInfo->GetOffset( index )); + case types::_INT8: + if ( pInfo->isUnsigned ) + return *(unsigned char*)((char*)pEnt + pInfo->GetOffset( index )); + return *(char*)((char*)pEnt + pInfo->GetOffset( index )); + case types::_INT16: + if ( pInfo->isUnsigned ) + return *(unsigned short*)((char*)pEnt + pInfo->GetOffset( index )); + return *(short*)((char*)pEnt + pInfo->GetOffset( index )); +#ifdef GAME_DLL + case types::_DAR_INT: + { + CUtlVector< int > &vec = *(CUtlVector< int >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + if ( index >= vec.Count() ) + return -1; + return vec[ index ]; + } +#endif + } + } + else + { + switch ( pInfo->datatype ) + { + case types::_INT32: + return (*(int*)((char*)pEnt + pInfo->GetOffset( index ))) & pInfo->mask; + } } return -1; } - #define GetPropFunc( name, varType, propType, defaultval ) \ - varType name( HSCRIPT hEnt, const char *pszPropName ) \ - { \ - CBaseEntity *pEnt = ToEnt( hEnt ); \ - auto *pProp = GetPropByName( pEnt, pszPropName ); \ - if (pProp && pProp->GetType() == propType) \ - { \ - return *(varType*)((char *)pEnt + pProp->GetOffset()); \ - } \ - return defaultval; \ - } \ - - #define GetPropFuncArray( name, varType, propType, defaultval ) \ - varType name( HSCRIPT hEnt, const char *pszPropName, int iArrayElement ) \ - { \ - CBaseEntity *pEnt = ToEnt( hEnt ); \ - auto *pProp = GetPropByName( pEnt, pszPropName ); \ - if (pProp && pProp->GetType() == propType) \ - { \ - return ((varType*)((char *)pEnt + pProp->GetOffset()))[iArrayElement]; \ - } \ - return defaultval; \ - } \ - - GetPropFunc( GetPropFloat, float, DPT_Float, -1 ); - GetPropFuncArray( GetPropFloatArray, float, DPT_Float, -1 ); - GetPropFunc( GetPropInt, int, DPT_Int, -1 ); - GetPropFuncArray( GetPropIntArray, int, DPT_Int, -1 ); - GetPropFunc( GetPropVector, Vector, DPT_Vector, vec3_invalid ); - GetPropFuncArray( GetPropVectorArray, Vector, DPT_Vector, vec3_invalid ); - - HSCRIPT GetPropEntity( HSCRIPT hEnt, const char *pszPropName ) + void SetPropIntArray( HSCRIPT hEnt, const char *szProp, int value, int index ) { CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) { - return ToHScript( *(CHandle*)((char *)pEnt + pProp->GetOffset()) ); + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; } - return NULL; - } + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; - HSCRIPT GetPropEntityArray( HSCRIPT hEnt, const char *pszPropName, int iArrayElement ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) + if ( pInfo->isNotNetworked ) { - return ToHScript( ((CHandle*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] ); - } - - return NULL; - } - - const char *GetPropString( HSCRIPT hEnt, const char *pszPropName ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) - { - return (const char*)((char *)pEnt + pProp->GetOffset()); - } - - return NULL; - } - - const char *GetPropStringArray( HSCRIPT hEnt, const char *pszPropName, int iArrayElement ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) - { - return ((const char**)((char *)pEnt + pProp->GetOffset()))[iArrayElement]; - } - - return NULL; - } - - const char *GetPropType( HSCRIPT hEnt, const char *pszPropName ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp) - { - switch (pProp->GetType()) + switch ( pInfo->datatype ) { - case DPT_Int: return "integer"; - case DPT_Float: return "float"; - case DPT_Vector: return "vector"; - case DPT_VectorXY: return "vector2d"; - case DPT_String: return "string"; - case DPT_Array: return "array"; - case DPT_DataTable: return "datatable"; + case types::_INT32: + if ( pInfo->isUnsigned ) + { + *(unsigned int*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + *(int*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + case types::_INT1: + *(bool*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + case types::_INT8: + if ( pInfo->isUnsigned ) + { + *(unsigned char*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + *(char*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + case types::_INT16: + if ( pInfo->isUnsigned ) + { + *(unsigned short*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + *(short*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; +#ifdef GAME_DLL + case types::_DAR_INT: + { + CUtlVector< int > &vec = *(CUtlVector< int >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return; + if ( index >= vec.Count() ) + return; + vec[ index ] = value; + NetworkStateChanged( pEnt, pInfo->offset ); + break; + } +#endif + } + } + else + { + switch ( pInfo->datatype ) + { + case types::_INT32: + { + int *dest = (int*)((char*)pEnt + pInfo->GetOffset( index )); + *dest = (*dest & ~pInfo->mask) | (value & pInfo->mask); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + } + } + } + + float GetPropFloatArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return -1; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return -1; + } + + if ( pInfo->datatype == types::_VEC3 ) + index /= 3; + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return -1; + + switch ( pInfo->datatype ) + { + case types::_VEC3: + case types::_FLOAT: + return *(float*)((char*)pEnt + pInfo->GetOffset( index )); +#ifdef GAME_DLL + case types::_DAR_FLOAT: + { + CUtlVector< float > &vec = *(CUtlVector< float >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return -1; + if ( index >= vec.Count() ) + return -1; + return vec[ index ]; + } +#endif + } + + return -1; + } + + void SetPropFloatArray( HSCRIPT hEnt, const char *szProp, float value, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; + } + + if ( pInfo->datatype == types::_VEC3 ) + index /= 3; + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; + + switch ( pInfo->datatype ) + { + case types::_VEC3: + case types::_FLOAT: + *(float*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; +#ifdef GAME_DLL + case types::_DAR_FLOAT: + { + CUtlVector< float > &vec = *(CUtlVector< float >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return; + if ( index >= vec.Count() ) + return; + vec[ index ] = value; + NetworkStateChanged( pEnt, pInfo->offset ); + break; + } +#endif + } + } + + HSCRIPT GetPropEntityArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return NULL; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return NULL; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return NULL; + + switch ( pInfo->datatype ) + { + case types::_EHANDLE: + { + EHANDLE &iEHandle = *(EHANDLE*)((char*)pEnt + pInfo->GetOffset( index )); + return ToHScript( iEHandle ); + } +#ifdef GAME_DLL + case types::_CLASSPTR: + { + CBaseEntity* ptr = *(CBaseEntity**)((char*)pEnt + pInfo->GetOffset( index )); + return ToHScript( ptr ); + } + case types::_EDICT: + { + edict_t* ptr = *(edict_t**)((char*)pEnt + pInfo->GetOffset( index )); + return ToHScript( GetContainingEntity( ptr ) ); + } + case types::_DAR_EHANDLE: + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return NULL; + if ( index >= vec.Count() ) + return NULL; + return ToHScript( vec[ index ] ); + } + case types::_DAR_CLASSPTR: + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return NULL; + if ( index >= vec.Count() ) + return NULL; + return ToHScript( vec[ index ] ); + } +#endif + case types::_PHYS: + { + IPhysicsObject* ptr = *(IPhysicsObject**)((char*)pEnt + pInfo->GetOffset( index )); + return ptr ? g_pScriptVM->RegisterInstance( ptr ) : NULL; + } + } + + return NULL; + } + + void SetPropEntityArray( HSCRIPT hEnt, const char *szProp, HSCRIPT value, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; + + switch ( pInfo->datatype ) + { + case types::_EHANDLE: + *(EHANDLE*)((char*)pEnt + pInfo->GetOffset( index )) = ToEnt( value ); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; +#ifdef GAME_DLL + case types::_CLASSPTR: + *(CBaseEntity**)((char*)pEnt + pInfo->GetOffset( index )) = ToEnt( value ); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + case types::_EDICT: + { + CBaseEntity* ptr = ToEnt( value ); + *(edict_t**)((char*)pEnt + pInfo->GetOffset( index )) = ptr ? ptr->edict() : NULL; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + case types::_DAR_EHANDLE: + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return; + if ( index >= vec.Count() ) + return; + vec[ index ] = ToEnt( value ); + NetworkStateChanged( pEnt, pInfo->offset ); + break; + } + case types::_DAR_CLASSPTR: + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)((char*)pEnt + pInfo->offset); + if ( !vec.Base() ) + return; + if ( index >= vec.Count() ) + return; + vec[ index ] = ToEnt( value ); + NetworkStateChanged( pEnt, pInfo->offset ); + break; + } +#endif + } + } + + const Vector &GetPropVectorArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return vec3_invalid; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return vec3_invalid; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return vec3_invalid; + + switch ( pInfo->datatype ) + { + case types::_VEC3: + return *(Vector*)((char*)pEnt + pInfo->GetOffset( index )); + } + + return vec3_invalid; + } + + void SetPropVectorArray( HSCRIPT hEnt, const char *szProp, const Vector &value, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; + + switch ( pInfo->datatype ) + { + case types::_VEC3: + *(Vector*)((char*)pEnt + pInfo->GetOffset( index )) = value; + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + } + + const char *GetPropStringArray( HSCRIPT hEnt, const char *szProp, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return NULL; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return NULL; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return NULL; + + switch ( pInfo->datatype ) + { + case types::_CSTRING: + return (const char*)((char*)pEnt + pInfo->GetOffset( index )); + case types::_STRING_T: // Identical to _CSTRING on client + return STRING( *(string_t*)((char*)pEnt + pInfo->GetOffset( index )) ); + case types::_INT8: + { + if ( !pInfo->stringsize ) + return NULL; + + char * const pVar = ((char*)pEnt + pInfo->GetOffset( index )); + + // Is this null terminated? + int i = 0; + char *c = pVar; + while ( *(c++) && i++ < pInfo->stringsize ); + + if ( i >= pInfo->stringsize ) + { + // Not a null terminated string, don't talk to me ever again + pInfo->stringsize = 0; + return NULL; + } + + return pVar; + } +#ifdef GAME_DLL + case types::_STDSTRING: + return ( (std::string*)((char*)pEnt + pInfo->GetOffset( index )) )->c_str(); +#endif + } + + return NULL; + } + + void SetPropStringArray( HSCRIPT hEnt, const char *szProp, const char *value, int index ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + varinfo_t *pInfo = CacheFetch( pEnt, szProp ); + if ( !pInfo ) + { + pInfo = GetVarInfo( pEnt, szProp, index ); + + if ( !pInfo ) + return; + } + + if ( index < 0 || (unsigned int)index >= pInfo->arraysize ) + return; + + switch ( pInfo->datatype ) + { + case types::_CSTRING: + case types::_INT8: + { + if ( pInfo->stringsize ) + { + V_strncpy( (char*)pEnt + pInfo->GetOffset( index ), value, pInfo->stringsize ); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } + } + case types::_STRING_T: + { + extern string_t FindPooledString( const char* ); + extern string_t AllocPooledString( const char* ); + + string_t src = FindPooledString( value ); + if ( src == NULL_STRING ) + src = AllocPooledString( value ); +#ifdef GAME_DLL + *(string_t*)((char*)pEnt + pInfo->GetOffset( index )) = src; +#else + V_strcpy( (char*)pEnt + pInfo->GetOffset( index ), src ); +#endif + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } +#ifdef GAME_DLL + case types::_STDSTRING: + { + ( (std::string*)((char*)pEnt + pInfo->GetOffset( index )) )->assign( value, V_strlen(value) ); + NetworkStateChanged( pEnt, pInfo->GetOffset( index ) ); + break; + } +#endif + } + } + +#define GetProp( type, name )\ + type GetProp##name( HSCRIPT hEnt, const char* szProp )\ + {\ + return GetProp##name##Array( hEnt, szProp, 0 );\ + } + +#define SetProp( type, name )\ + void SetProp##name( HSCRIPT hEnt, const char* szProp, type value )\ + {\ + SetProp##name##Array( hEnt, szProp, value, 0 );\ + } + + GetProp( int, Int ); + SetProp( int, Int ); + GetProp( float, Float ); + SetProp( float, Float ); + GetProp( HSCRIPT, Entity ); + SetProp( HSCRIPT, Entity ); + GetProp( const Vector&, Vector ); + SetProp( const Vector&, Vector ); + GetProp( const char*, String ); + SetProp( const char*, String ); + +#undef GetProp +#undef SetProp + +#ifdef _DEBUG +private: + CUtlBuffer m_output; + CUtlString m_indent; + int m_indent_level; + + void IndentStart() + { + m_indent = ""; + m_indent_level = 0; + } + + void Indent1() + { + m_indent_level++; + m_indent.Append("\t"); + } + + void Indent0() + { + m_indent_level--; + m_indent = m_indent.Slice( 0, m_indent_level ); + } + + void PrintVec3( float *pVar ) + { + if ( *(Vector*)pVar != vec3_invalid ) + { + Print( "[%f %f %f]", pVar[0], pVar[1], pVar[2] ); + } + else + { + Print("vec3_invalid"); + } + } + + void PrintVec2( float *pVar ) + { + Print( "[%f %f]", pVar[0], pVar[1] ); + } + + void PrintEntity( EHANDLE* pVar ) + { + CBaseEntity* ent = *pVar; + if ( ent ) + { + Print("[%d]%s", ent->entindex(), ent->GetDebugName()); + } + else + { + Print("null"); + } + } +#ifdef GAME_DLL + void PrintEntity( CBaseEntity* pVar ) + { + CBaseEntity* ent = pVar; + if ( ent ) + { + Print("[%d]%s", ent->entindex(), ent->GetDebugName()); + } + else + { + Print("null"); + } + } + + void PrintEntity( edict_t* pVar ) + { + CBaseEntity* ent = GetContainingEntity( pVar ); + if ( ent ) + { + Print("[%d]%s", ent->entindex(), ent->GetDebugName()); + } + else + { + Print("null"); + } + } +#endif +#ifdef GAME_DLL + void PrintString( string_t pVar ) + { + if ( STRING(pVar) ) + { + Print("\"%s\"", STRING(pVar)); + } + else + { + Print("null"); + } + } +#endif + void PrintString( const char *pVar ) + { + if ( pVar ) + { + Print("\"%s\"", pVar); + } + else + { + Print("null"); + } + } + + void PrintPropType( NetProp *pProp ) + { + switch ( pProp->GetType() ) + { + case DPT_Int: + if ( IsUtlVector( pProp ) ) + { + Print("UtlVector"); + } + else if ( IsEHandle( pProp ) ) + { + Print( "entity" ); + } + else + { + Print( "int" ); + } + break; +#ifdef SUPPORTS_INT64 + case DPT_Int64: + AssertMsg( 0, "not implemented" ); + Print( "int64" ); + break; +#endif + case DPT_Float: + Print( "float" ); + break; + case DPT_Vector: + Print( "vec3" ); + break; + case DPT_VectorXY: + Print( "vec2" ); + break; + case DPT_String: + { +#ifdef GAME_DLL + if ( pProp->GetProxyFn() == SendProxy_StringT_To_String ) + { + Print("string_t"); + } + else +#endif + { +#ifdef CLIENT_DLL + Print("string[%d]", pProp->m_StringBufferSize); +#else + Print("string"); +#endif + } + break; + } + case DPT_Array: + case DPT_DataTable: + break; + default: UNREACHABLE(); + } + } + + void PrintProp_r( char *pVar, NetProp *pProp ) + { + switch ( pProp->GetType() ) + { + case DPT_Int: + { + if ( IsUtlVector( pProp ) ) + { + } + else if ( IsEHandle( pProp ) ) + { + PrintEntity( (EHANDLE*)pVar ); + } + else + { +#ifdef GAME_DLL + // Is this value larger than networked size? + AssertMsg( (*(int*)pVar & MASK_NEAREST_BYTE( pProp->m_nBits )) == 0, + "%s(%i) %d bits doesn't fit networked %d bits", + pProp->GetName(), *(int*)pVar & MASK_NEAREST_BYTE( pProp->m_nBits ), ALIGN_TO_NEAREST_BYTE(pProp->m_nBits), pProp->m_nBits ); +#endif + int size = GetIntPropSize( pProp ); + if ( size ) + { + Print( "%i", *(int*)pVar & MASK_INT_SIZE( size ) ); + } + else + { + Print( " 0x%08x", *(int*)pVar ); + } + } + break; + } +#ifdef SUPPORTS_INT64 + case DPT_Int64: + { + Print( "%lli", *(int64*)pVar ); + break; + } +#endif + case DPT_Float: + { + Assert( pProp->GetElementStride() == sizeof(float) || pProp->GetElementStride() < 0 ); + if ( *(float*)pVar == FLT_MAX ) + { + Print("FLT_MAX"); + } + else + { + Print("%f", *(float*)pVar); + } + break; + } + case DPT_Vector: + { + PrintVec3( (float*)pVar ); + break; + } + case DPT_VectorXY: + { + PrintVec2( (float*)pVar ); + break; + } + case DPT_String: + { +#ifdef GAME_DLL + if ( pProp->GetProxyFn() == SendProxy_StringT_To_String ) + { + PrintString( *(string_t*)pVar ); + } + else +#endif + { + Assert( pProp->GetProxyFn() == DataTableProxy_String ); + PrintString( (char*)pVar ); + } + break; + } + case DPT_DataTable: + { + NetTable* pArray = pProp->GetDataTable(); + Assert( pArray->GetNumProps() ); + + if ( V_strcmp( pProp->GetName(), pArray->GetName() ) != 0 ) + { + Print( " -> (%s)\n", pArray->GetName() ); + DumpNetTable_r( pVar, pArray ); + break; + } + + // Double check that each element is the same size + // Array indexing ints gets element size from this + int diff1 = pArray->GetProp(1)->GetOffset() - pArray->GetProp(0)->GetOffset(); + for ( int k = 0; k < pArray->GetNumProps()-1; k++ ) + { + int diff2 = pArray->GetProp(k+1)->GetOffset() - pArray->GetProp(k)->GetOffset(); + Assert( diff1 == diff2 ); + } + + Print(" <"); + PrintPropType( pArray->GetProp(0) ); + Print(" array> #%d", pArray->GetNumProps()); + Print("\n%s[", m_indent.Get()); + Indent1(); + + for ( int j = 0; j < pArray->GetNumProps(); j++ ) + { + Print("\n%s", m_indent.Get()); + PrintProp_r( pVar + pArray->GetProp(j)->GetOffset(), pArray->GetProp(j) ); + } + + Indent0(); + Print( "\n%s]", m_indent.Get() ); + + break; + } + case DPT_Array: + { + Assert( pProp->GetArrayProp() ); + NetProp *pArray = pProp->GetArrayProp(); + pVar += pArray->GetOffset(); + + int numElements = pProp->GetNumElements(); + int elementStride = pProp->GetElementStride(); + + Print(" <"); + PrintPropType( pArray ); + Print(" array> #%d", numElements); + Print("\n%s[", m_indent.Get()); + Indent1(); + + for ( int j = 0; j < numElements; j++ ) + { + Print("\n%s", m_indent.Get()); + PrintProp_r( pVar + j * elementStride, pArray ); + } + + Indent0(); + Print( "\n%s]", m_indent.Get() ); + + break; + } + default: UNREACHABLE(); + } + } + + void DumpNetTable_r( void *pEnt, NetTable *pTable ) + { + Print("%s{\n", m_indent.Get()); + Indent1(); + + int numProps = pTable->GetNumProps(); + + for ( int i = 0; i < numProps; i++ ) + { + NetProp* pProp = pTable->GetProp(i); + char* pVar = (char*)pEnt + pProp->GetOffset(); + + if ( pProp->IsInsideArray() ) + continue; + + Print( "%s%s", m_indent.Get(), pProp->GetName() ); + + if ( pProp->GetOffset() == 0 ) + Print("<0>"); + + if ( pProp->GetType() != DPT_DataTable ) + Print(" <"); + PrintPropType( pProp ); + if ( pProp->GetType() != DPT_DataTable ) + Print("> "); + PrintProp_r( pVar, pProp ); + Print("\n"); + } + + Indent0(); + Print("%s}", m_indent.Get()); + } + + void PrintFieldType( char *pVar, typedescription_t *td ) + { + switch ( td->fieldType ) + { + case FIELD_INTEGER: + case FIELD_MATERIALINDEX: + case FIELD_MODELINDEX: + case FIELD_TICK: + Print( "int" ); + break; + case FIELD_SHORT: + Print( "short" ); + break; + case FIELD_CHARACTER: + Print( "char" ); + break; + case FIELD_BOOLEAN: + Print( "bool" ); + break; + case FIELD_COLOR32: + Print( "clr32" ); + break; + case FIELD_FLOAT: + case FIELD_TIME: + Print( "float" ); + break; + case FIELD_VECTOR: + case FIELD_POSITION_VECTOR: + Print( "vec3" ); + break; + case FIELD_VECTOR2D: + Print( "vec2" ); + break; + case FIELD_STRING: + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: + Print( "string" ); + break; + case FIELD_EHANDLE: +#ifdef GAME_DLL + case FIELD_CLASSPTR: + case FIELD_EDICT: +#endif + Print( "entity" ); + break; + case FIELD_VMATRIX: + Print( "VMatrix" ); + break; + case FIELD_VMATRIX_WORLDSPACE: + Print( "VMatrix WORLDSPACE" ); + break; + case FIELD_MATRIX3X4_WORLDSPACE: + Print( "matrix3x4 WORLDSPACE" ); + break; + case FIELD_INTERVAL: + Print( "interval_t" ); + break; + case FIELD_CUSTOM: + PrintCustomFieldType( pVar, td ); + break; + case FIELD_EMBEDDED: + if ( td->fieldSize > 1 ) + Print( "DT" ); + break; + default: + Print( "unknown %d", td->fieldType ); + } + } + + void PrintCustomFieldType( char *pVar, typedescription_t *td ) + { + Assert( td->fieldType == FIELD_CUSTOM ); + + const char *g_ppszPhysTypeNames[PIID_NUM_TYPES] = + { + "Unknown Phys", + "IPhysicsObject", + "IPhysicsFluidController", + "IPhysicsSpring", + "IPhysicsConstraintGroup", + "IPhysicsConstraint", + "IPhysicsShadowController", + "IPhysicsPlayerController", + "IPhysicsMotionController", + "IPhysicsVehicleController", + }; + + for ( int i = 0; i < PIID_NUM_TYPES; i++ ) + { + if ( td->pSaveRestoreOps == GetPhysObjSaveRestoreOps( (PhysInterfaceId_t)i ) ) + { + Print("%s", g_ppszPhysTypeNames[i]); + return; } } - return NULL; - } - - bool HasProp( HSCRIPT hEnt, const char *pszPropName ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - return GetPropByName( pEnt, pszPropName ) != NULL; - } - - #define SetPropFunc( name, varType, propType ) \ - void name( HSCRIPT hEnt, const char *pszPropName, varType value ) \ - { \ - CBaseEntity *pEnt = ToEnt( hEnt ); \ - auto *pProp = GetPropByName( pEnt, pszPropName ); \ - if (pProp && pProp->GetType() == propType) \ - { \ - *(varType*)((char *)pEnt + pProp->GetOffset()) = value; \ - } \ - } \ - - #define SetPropFuncArray( name, varType, propType ) \ - void name( HSCRIPT hEnt, const char *pszPropName, varType value, int iArrayElement ) \ - { \ - CBaseEntity *pEnt = ToEnt( hEnt ); \ - auto *pProp = GetPropByName( pEnt, pszPropName ); \ - if (pProp && pProp->GetType() == propType) \ - { \ - ((varType*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] = value; \ - } \ - } \ - - SetPropFunc( SetPropFloat, float, DPT_Float ); - SetPropFuncArray( SetPropFloatArray, float, DPT_Float ); - SetPropFunc( SetPropInt, int, DPT_Int ); - SetPropFuncArray( SetPropIntArray, int, DPT_Int ); - SetPropFunc( SetPropVector, Vector, DPT_Vector ); - SetPropFuncArray( SetPropVectorArray, Vector, DPT_Vector ); - SetPropFunc( SetPropString, const char*, DPT_String ); - SetPropFuncArray( SetPropStringArray, const char*, DPT_String ); - - void SetPropEntity( HSCRIPT hEnt, const char *pszPropName, HSCRIPT value ) - { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) + if ( td->pSaveRestoreOps == ActivityDataOps() ) { - *((CHandle*)((char *)pEnt + pProp->GetOffset())) = ToEnt(value); + Print("int"); + } + else if ( td->pSaveRestoreOps == GetSoundSaveRestoreOps() ) + { + Print("CSoundPatch"); + } + else if ( td->pSaveRestoreOps == GetStdStringDataOps() ) + { + Print("stdstring"); + } +#ifdef GAME_DLL + else if ( IS_EHANDLE_UTLVECTOR( td ) ) + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)pVar; + if ( vec.Base() ) + Print("entity utlvector #%d", vec.Count()); + else + Print("entity utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_INTEGER, int ) ) + { + CUtlVector< int > &vec = *(CUtlVector< int >*)pVar; + if ( vec.Base() ) + Print("int utlvector #%d", vec.Count()); + else + Print("int utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_FLOAT, float ) || + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_TIME, float ) ) + { + CUtlVector< float > &vec = *(CUtlVector< float >*)pVar; + if ( vec.Base() ) + Print("float utlvector #%d", vec.Count()); + else + Print("float utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_STRING, string_t ) ) + { + CUtlVector< string_t > &vec = *(CUtlVector< string_t >*)pVar; + if ( vec.Base() ) + Print("string utlvector #%d", vec.Count()); + else + Print("string utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_CLASSPTR, CBaseEntity* ) ) + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)pVar; + if ( vec.Base() ) + Print("entity utlvector #%d", vec.Count()); + else + Print("entity utlvector"); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_VECTOR, Vector ) ) + { + AssertMsg( 0, "Implement me" ); + CUtlVector< Vector > &vec = *(CUtlVector< Vector >*)pVar; + if ( vec.Base() ) + Print("Vector utlvector #%d", vec.Count()); + else + Print("Vector utlvector"); + } + else if ( !V_strcmp( td->fieldName, "m_pIk" ) ) + { + Print("IK"); + } + else if ( td->pSaveRestoreOps == thinkcontextFuncs ) + { + Print("thinkfunc"); + } + else if ( td->pSaveRestoreOps == (ISaveRestoreOps*)(&g_AI_MemoryListSaveRestoreOps) ) + { + Print("AI memory map"); + } + else if ( td->pSaveRestoreOps == (ISaveRestoreOps*)(&g_VguiScreenStringOps)) + { + Print("string (vgui screen)"); + } + else if ( td->pSaveRestoreOps == (ISaveRestoreOps*)(&g_ConceptHistoriesSaveDataOps) ) + { + Print("concept histories"); + } +#endif // GAME_DLL + else + { + Print("custom"); } } - HSCRIPT SetPropEntityArray( HSCRIPT hEnt, const char *pszPropName, HSCRIPT value, int iArrayElement ) + void PrintCustomField( char *pVar, typedescription_t *td ) { - CBaseEntity *pEnt = ToEnt( hEnt ); - auto *pProp = GetPropByName( pEnt, pszPropName ); - if (pProp && pProp->GetType() == DPT_Int) + Assert( td->fieldType == FIELD_CUSTOM ); + + for ( int i = 0; i < PIID_NUM_TYPES; i++ ) { - ((CHandle*)((char *)pEnt + pProp->GetOffset()))[iArrayElement] = ToEnt(value); + if ( td->pSaveRestoreOps == GetPhysObjSaveRestoreOps( (PhysInterfaceId_t)i ) ) + { + Print("0x%x", pVar); + return; + } } - return NULL; + if ( td->pSaveRestoreOps == ActivityDataOps() ) + { + Print("%i", *(int*)pVar); + } + else if ( td->pSaveRestoreOps == GetSoundSaveRestoreOps() ) + { + if ( *pVar ) + { + CSoundPatch *pSound = *(CSoundPatch**)pVar; + PrintString( CSoundEnvelopeController::GetController().SoundGetName( pSound ) ); + } + else + { + Print( "null" ); + } + } + else if ( td->pSaveRestoreOps == GetStdStringDataOps() ) + { + Print("%s", ((std::string*)pVar)->c_str()); + } +#ifdef GAME_DLL + else if ( IS_EHANDLE_UTLVECTOR( td ) ) + { + CUtlVector< EHANDLE > &vec = *(CUtlVector< EHANDLE >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + PrintEntity( vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_INTEGER, int ) ) + { + CUtlVector< int > &vec = *(CUtlVector< int >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + Print( "%i", vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_FLOAT, float ) || + td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_TIME, float ) ) + { + CUtlVector< float > &vec = *(CUtlVector< float >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + Print( "%f", vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_STRING, string_t ) ) + { + CUtlVector< string_t > &vec = *(CUtlVector< string_t >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + PrintString( vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == UTLVECTOR_DATAOPS( FIELD_CLASSPTR, CBaseEntity* ) ) + { + CUtlVector< CBaseEntity* > &vec = *(CUtlVector< CBaseEntity* >*)pVar; + if ( !vec.Base() ) + { + Print("null"); + return; + } + Print("\n%s[", m_indent.Get()); + Indent1(); + FOR_EACH_VEC( vec, i ) + { + Print("\n%s", m_indent.Get()); + PrintEntity( vec[i] ); + } + Indent0(); + Print("\n%s]", m_indent.Get()); + } + else if ( td->pSaveRestoreOps == (ISaveRestoreOps*)(&g_VguiScreenStringOps) ) + { + const char *pString = g_pStringTableVguiScreen->GetString( *(int*)pVar ); + PrintString( (char*)pString ); + } +#endif // GAME_DLL + else + { + Print("0x%x", pVar); + } } -private: + void PrintField_r( char *pVar, typedescription_t *td ) + { + switch ( td->fieldType ) + { + case FIELD_INTEGER: + case FIELD_MATERIALINDEX: + case FIELD_MODELINDEX: + case FIELD_TICK: + if ( td->flags & SPROP_UNSIGNED ) + { + Print("%u", *(unsigned int*)pVar); + } + else + { + Print("%i", *(int*)pVar); + } + break; + case FIELD_COLOR32: + Print("0x%08x", *(int*)pVar); + break; + case FIELD_BOOLEAN: + Print("%i", *(bool*)pVar & 1); + break; + case FIELD_CHARACTER: + if ( *pVar < 0x20 ) + { + Print("%i (0x%x)", *pVar, *pVar); + } + else + { + Print("%i '%c'", *pVar, *pVar); + } + break; + case FIELD_SHORT: + if ( td->flags & SPROP_UNSIGNED ) + { + Print("%u", *(unsigned short*)pVar); + } + else + { + Print("%i", *(short*)pVar); + } + break; + case FIELD_FLOAT: + case FIELD_TIME: + if ( *(float*)pVar == FLT_MAX ) + { + Print("FLT_MAX"); + } + else + { + Print("%f", *(float*)pVar); + } + break; + case FIELD_VECTOR: + case FIELD_POSITION_VECTOR: + PrintVec3( (float*)pVar ); + break; + case FIELD_VECTOR2D: + PrintVec2( (float*)pVar ); + break; + case FIELD_STRING: + case FIELD_MODELNAME: + case FIELD_SOUNDNAME: +#ifdef GAME_DLL + PrintString( *(string_t*)pVar ); +#else + PrintString( *(char**)pVar ); +#endif + break; + case FIELD_EHANDLE: + PrintEntity( (EHANDLE*)pVar ); + break; +#ifdef GAME_DLL + case FIELD_CLASSPTR: + PrintEntity( *(CBaseEntity**)pVar ); + break; + case FIELD_EDICT: + PrintEntity( *(edict_t**)pVar ); + break; +#endif + case FIELD_EMBEDDED: + Print(" -> (%s)\n", td->td->dataClassName); + DumpDataFields_r( pVar, td->td ); + break; + case FIELD_CUSTOM: + PrintCustomField( pVar, td ); + break; + default: + Print( "", td->fieldType ); + } + } + + void DumpDataFields_r( void *pEnt, datamap_t *map ) + { + Print("%s{\n", m_indent.Get()); + Indent1(); + + if ( map->baseMap ) + { + Print("%sbaseclass -> (%s)\n", m_indent.Get(), map->baseMap->dataClassName); + DumpDataFields_r( pEnt, map->baseMap ); + Print("\n"); + } + + typedescription_t *pFields = map->dataDesc; + int numFields = map->dataNumFields; + + for ( int i = 0; i < numFields; i++ ) + { + typedescription_t* td = &pFields[i]; + + if ( td->flags & (FTYPEDESC_FUNCTIONTABLE | FTYPEDESC_INPUT | FTYPEDESC_OUTPUT) ) + continue; + + if ( td->fieldType == FIELD_VOID || td->fieldType == FIELD_FUNCTION ) + continue; + + char *pVar = (char*)pEnt + td->fieldOffset[ TD_OFFSET_NORMAL ]; + + if ( td->flags & FTYPEDESC_PTR ) + { + AssertMsg( *(char**)pVar, "NULL ptr ref" ); + pVar = *(char**)pVar; + } + + Print( "%s%s", m_indent.Get(), td->fieldName ); + + if ( td->fieldSize == 1 ) + { + if ( td->fieldType != FIELD_EMBEDDED ) + Print(" <"); + PrintFieldType( pVar, td ); + if ( td->fieldType != FIELD_EMBEDDED ) + Print("> "); + PrintField_r( pVar, td ); + } + else + { + Print(" <"); + PrintFieldType( pVar, td ); + Print(" array> #%d", td->fieldSize); + + Print("\n%s[", m_indent.Get()); + Indent1(); + + for ( int j = 0; j < td->fieldSize; j++ ) + { + Print("\n%s", m_indent.Get()); + PrintField_r( pVar + j * td->fieldSizeInBytes / td->fieldSize, td ); + } + + Indent0(); + Print("\n%s]", m_indent.Get()); + } + + Print("\n"); + } + + Indent0(); + Print("%s}", m_indent.Get()); + } + + void Print( const char *fmt, ... ) + { + char buf[2048]; + va_list va; + va_start( va, fmt ); + V_vsnprintf( buf, sizeof(buf) - 1, fmt, va ); + va_end( va ); + + m_output.PutString( buf ); + } + +public: + void Dump( HSCRIPT hEnt, const char* filename ) + { + CBaseEntity *pEnt = ToEnt( hEnt ); + if ( !pEnt ) + return; + + if ( !filename || !*filename ) + return; + + m_output.SetBufferType( true, false ); + IndentStart(); + + Print( "\n" ); + Print( "(%s)\n", GetNetTable( GetNetworkClass(pEnt) )->GetName() ); + DumpNetTable_r( pEnt, GetNetTable( GetNetworkClass(pEnt) ) ); + Print( "\n\n" ); + + Print( "\n" ); + Print( "(%s)\n", pEnt->GetDataDescMap()->dataClassName ); + DumpDataFields_r( pEnt, pEnt->GetDataDescMap() ); + Print( "\n\n" ); +#ifdef CLIENT_DLL + Print( "\n" ); + Print( "(%s)\n", pEnt->GetPredDescMap()->dataClassName ); + DumpDataFields_r( pEnt, pEnt->GetPredDescMap() ); + Print( "\n\n" ); +#endif + const char *pszFile = V_GetFileName( filename ); + filesystem->WriteFile( pszFile, "MOD", m_output ); + + m_indent.Purge(); + m_output.Purge(); + } +#endif // _DEBUG } g_ScriptNetPropManager; -BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptNetPropManager, "CNetPropManager", SCRIPT_SINGLETON "Allows reading and updating the network properties of an entity." ) - DEFINE_SCRIPTFUNC( GetPropArraySize, "Returns the size of an netprop array, or -1." ) - DEFINE_SCRIPTFUNC( GetPropEntity, "Reads an EHANDLE valued netprop (21 bit integer). Returns the script handle of the entity." ) - DEFINE_SCRIPTFUNC( GetPropEntityArray, "Reads an EHANDLE valued netprop (21 bit integer) from an array. Returns the script handle of the entity." ) - DEFINE_SCRIPTFUNC( GetPropFloat, "Reads a float valued netprop." ) - DEFINE_SCRIPTFUNC( GetPropFloatArray, "Reads a float valued netprop from an array." ) - DEFINE_SCRIPTFUNC( GetPropInt, "Reads an integer valued netprop." ) - DEFINE_SCRIPTFUNC( GetPropIntArray, "Reads an integer valued netprop from an array." ) - DEFINE_SCRIPTFUNC( GetPropString, "Reads a string valued netprop." ) - DEFINE_SCRIPTFUNC( GetPropStringArray, "Reads a string valued netprop from an array." ) - DEFINE_SCRIPTFUNC( GetPropVector, "Reads a 3D vector valued netprop." ) - DEFINE_SCRIPTFUNC( GetPropVectorArray, "Reads a 3D vector valued netprop from an array." ) - DEFINE_SCRIPTFUNC( GetPropType, "Returns the name of the netprop type as a string." ) - DEFINE_SCRIPTFUNC( HasProp, "Checks if a netprop exists." ) - DEFINE_SCRIPTFUNC( SetPropEntity, "Sets an EHANDLE valued netprop (21 bit integer) to reference the specified entity." ) - DEFINE_SCRIPTFUNC( SetPropEntityArray, "Sets an EHANDLE valued netprop (21 bit integer) from an array to reference the specified entity." ) - DEFINE_SCRIPTFUNC( SetPropFloat, "Sets a netprop to the specified float." ) - DEFINE_SCRIPTFUNC( SetPropFloatArray, "Sets a netprop from an array to the specified float." ) - DEFINE_SCRIPTFUNC( SetPropInt, "Sets a netprop to the specified integer." ) - DEFINE_SCRIPTFUNC( SetPropIntArray, "Sets a netprop from an array to the specified integer." ) - DEFINE_SCRIPTFUNC( SetPropString, "Sets a netprop to the specified string." ) - DEFINE_SCRIPTFUNC( SetPropStringArray, "Sets a netprop from an array to the specified string." ) - DEFINE_SCRIPTFUNC( SetPropVector, "Sets a netprop to the specified vector." ) - DEFINE_SCRIPTFUNC( SetPropVectorArray, "Sets a netprop from an array to the specified vector." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptNetPropManager, "CNetPropManager", SCRIPT_SINGLETON "Allows reading and updating the network properties and data fields of an entity." ) + DEFINE_SCRIPTFUNC( GetPropArraySize, "Returns the size of an array." ) + DEFINE_SCRIPTFUNC( GetPropEntity, "Reads an entity." ) + DEFINE_SCRIPTFUNC( GetPropEntityArray, "Reads an entity from an array." ) + DEFINE_SCRIPTFUNC( GetPropFloat, "Reads a float." ) + DEFINE_SCRIPTFUNC( GetPropFloatArray, "Reads a float from an array." ) + DEFINE_SCRIPTFUNC( GetPropInt, "Reads an integer." ) + DEFINE_SCRIPTFUNC( GetPropIntArray, "Reads an integer from an array." ) + DEFINE_SCRIPTFUNC( GetPropString, "Reads a string." ) + DEFINE_SCRIPTFUNC( GetPropStringArray, "Reads a string from an array." ) + DEFINE_SCRIPTFUNC( GetPropVector, "Reads a 3D vector." ) + DEFINE_SCRIPTFUNC( GetPropVectorArray, "Reads a 3D vector from an array." ) + DEFINE_SCRIPTFUNC( GetPropType, "Returns the netprop type as a string." ) + DEFINE_SCRIPTFUNC( HasProp, "Checks if netprop/datafield exists." ) + DEFINE_SCRIPTFUNC( SetPropEntity, "Sets an entity." ) + DEFINE_SCRIPTFUNC( SetPropEntityArray, "Sets an entity in an array." ) + DEFINE_SCRIPTFUNC( SetPropFloat, "Sets to the specified float." ) + DEFINE_SCRIPTFUNC( SetPropFloatArray, "Sets a float in an array." ) + DEFINE_SCRIPTFUNC( SetPropInt, "Sets to the specified integer." ) + DEFINE_SCRIPTFUNC( SetPropIntArray, "Sets an integer in an array." ) + DEFINE_SCRIPTFUNC( SetPropString, "Sets to the specified string." ) + DEFINE_SCRIPTFUNC( SetPropStringArray, "Sets a string in an array." ) + DEFINE_SCRIPTFUNC( SetPropVector, "Sets to the specified vector." ) + DEFINE_SCRIPTFUNC( SetPropVectorArray, "Sets a 3D vector in an array." ) +#ifdef _DEBUG + DEFINE_SCRIPTFUNC( Dump, "Dump all readable netprop and datafield values of this entity. Pass in file name to write into." ); +#endif END_SCRIPTDESC(); //============================================================================= diff --git a/sp/src/game/shared/ragdoll_shared.cpp b/sp/src/game/shared/ragdoll_shared.cpp index a9da2613..494c9ebe 100644 --- a/sp/src/game/shared/ragdoll_shared.cpp +++ b/sp/src/game/shared/ragdoll_shared.cpp @@ -1178,6 +1178,32 @@ void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImpo #endif } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Remove it from the LRU +//----------------------------------------------------------------------------- +void CRagdollLRURetirement::RemoveFromLRU( CBaseAnimating *pRagdoll ) +{ + for (int i = 0; i < m_LRU.Count(); i++) + { + if (m_LRU[i].Get() == pRagdoll) + { + m_LRU.Remove( i ); + return; + } + } + + for (int i = 0; i < m_LRUImportantRagdolls.Count(); i++) + { + if (m_LRUImportantRagdolls[i].Get() == pRagdoll) + { + m_LRUImportantRagdolls.Remove( i ); + return; + } + } +} +#endif + //EFFECT/ENTITY TRANSFERS diff --git a/sp/src/game/shared/ragdoll_shared.h b/sp/src/game/shared/ragdoll_shared.h index 5f4f7058..db2bd7b2 100644 --- a/sp/src/game/shared/ragdoll_shared.h +++ b/sp/src/game/shared/ragdoll_shared.h @@ -114,8 +114,9 @@ public: virtual void FrameUpdatePostEntityThink( void ); // Move it to the top of the LRU -#ifdef MAPBASE // From Alien Swarm SDK - void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false, float flForcedRetireTime = 0.0f ); +#ifdef MAPBASE + void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false, float flForcedRetireTime = 0.0f ); // From Alien Swarm SDK + void RemoveFromLRU( CBaseAnimating *pRagdoll ); #else void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false ); #endif diff --git a/sp/src/game/shared/vscript_shared.cpp b/sp/src/game/shared/vscript_shared.cpp index 8ab2ac97..c41ddea6 100644 --- a/sp/src/game/shared/vscript_shared.cpp +++ b/sp/src/game/shared/vscript_shared.cpp @@ -624,6 +624,9 @@ public: if ( g_pScriptVM->GetValue( STRING(pEnt->m_iszScriptId), &variant ) && variant.m_type == FIELD_HSCRIPT ) { pEnt->m_ScriptScope.Init( variant.m_hScript, false ); +#ifdef MAPBASE_VSCRIPT + g_pScriptVM->SetValue( pEnt->m_ScriptScope, "self", pEnt->m_hScriptInstance ); +#endif #ifndef CLIENT_DLL pEnt->RunPrecacheScripts(); #endif diff --git a/sp/src/materialsystem/stdshaders/BlurFilterY.cpp b/sp/src/materialsystem/stdshaders/BlurFilterY.cpp index 57db29c0..f252fea5 100644 --- a/sp/src/materialsystem/stdshaders/BlurFilterY.cpp +++ b/sp/src/materialsystem/stdshaders/BlurFilterY.cpp @@ -85,7 +85,7 @@ BEGIN_VS_SHADER_FLAGS( BlurFilterY, "Help for BlurFilterY", SHADER_NOT_EDITABLE // The temp buffer is 1/4 back buffer size ITexture *src_texture = params[BASETEXTURE]->GetTextureValue(); - int height = src_texture->GetActualWidth(); + int height = src_texture->GetActualHeight(); float dY = 1.0f / height; // dY *= 0.4; float v[4]; diff --git a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp index 6f64a15d..2273db49 100644 --- a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp +++ b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp @@ -1537,7 +1537,7 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar** float envMapOrigin[4] = {0,0,0,0}; params[info.m_nEnvmapOrigin]->GetVecValue( envMapOrigin, 3 ); #ifdef MAPBASE - envMapOrigin[4] = bEditorBlend ? 1.0f : 0.0f; + envMapOrigin[3] = bEditorBlend ? 1.0f : 0.0f; #endif pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 21, envMapOrigin ); diff --git a/sp/src/public/tier0/platform.h b/sp/src/public/tier0/platform.h index 457e5ec9..25bf9bc1 100644 --- a/sp/src/public/tier0/platform.h +++ b/sp/src/public/tier0/platform.h @@ -1281,8 +1281,8 @@ PLATFORM_INTERFACE bool Is64BitOS(); //----------------------------------------------------------------------------- // General Mapbase version constants compiled into projects for versioning purposes //----------------------------------------------------------------------------- -#define MAPBASE_VERSION "7.2" -#define MAPBASE_VER_INT 7200 // For use in #if in a similar fashion to macros like _MSC_VER +#define MAPBASE_VERSION "7.3" +#define MAPBASE_VER_INT 7300 // For use in #if in a similar fashion to macros like _MSC_VER #endif diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 5efb2314..9f46d68c 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -2776,7 +2776,7 @@ void* SquirrelVM::GetInstanceValue(HSCRIPT hInstance, ScriptClassDesc_t* pExpect bool SquirrelVM::GenerateUniqueKey(const char* pszRoot, char* pBuf, int nBufSize) { - static int keyIdx = 0; + static unsigned keyIdx = 0; // This gets used for script scope, still confused why it needs to be inside IScriptVM // is it just to be a compatible name for CreateScope? V_snprintf(pBuf, nBufSize, "%08X_%s", ++keyIdx, pszRoot);