From af85131debb14477ca991597e04c89c83091661f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 2 May 2020 02:06:02 +0000 Subject: [PATCH] Mapbase v3.1 - Fixed filter_damage_mod blocking all damage which doesn't match the secondary filter regardless of secondary filter mode - Fixed impulse 101 and other give-related commands leaving behind weapons with occupied slots - Fixed a crash with scripted_sound's PlaySoundOnEntity when the entity doesn't exist - Added OnSoundFinished output to ambient_generic - Added the ability to use custom models/nuggets with item_grubnugget - Fixed a crash with citizen medics healing nonexistent targets - Added "SetDistLook" and "SetDistTooFar" inputs for NPCs, allowing manual adjustment of NPC sight distance - Added keyvalue and input to env_microphone for utilizing a different audio channel - Added "SetPitchScale" input to env_microphone - Fixed info_player_view_proxy not using angles - Fixed dirt variant elite model not being recognized as elite - Made headcrab hints properly register the start of use (for hint outputs) - Made RPG use a more realistic firing rate for NPCs which aren't constrained by slow RPG animations, like soldiers - Added spawnflag for func_breakable_surf to correctly play the break sound - Added keyvalue for using cheaper warn sound code for combine_mines - Added "OnSpawnNPC" output for npc_combinedropship when it spawns a soldier, rollermine, or strider - Added signal gesture activities - Fixed stunstick not using metrocop knockout/stun code correctly - Fixed a possible crash involving a NPC's weapon being removed during alt-fire - Fixed(?) flashlight shadow filters - Added support for multiple look entities in trigger_look - Added npc_metropolice alt-firing - Fixed npc_metropolice using pistol burst firing on weapon_357 - Fixed npc_metropolice not deploying manhacks/throwing grenades in standoffs - Fixed npc_metropolice not recognizing some crouch activities correctly - Changed weapon_357 so it runs a tracer each shot from NPCs - Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass - Added "SetSpeedModifier" to NPCs, based on 1upD's shadow walker code - Made game_convar_mod much more reliable - Fixed non-mirrored npc_turret_lab refusing to die - Made npc_turret_lab use SMG1 ammo instead of AR2 ammo - Fixed block LOS brushes sometimes not working with players (and possibly similar issues) - Raised maximum renderable entities from 4096 to 16384, based on ficool2's limit research - Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass. Can display parallax corrected cubemaps from its unbroken form - Fixed VBSP breaking func_breakable_surf, etc. when using parallax corrected cubemaps - Raised maximum VBSP entities from 8192 to 65536, based on ficool2's limit research - Raised maximum VBSP worldlights from 8192 to 65536, based on ficool2's limit research - Raised maximum VBSP overlays from 512 to 8192, based on ficool2's limit research - Other misc. fixes --- README | 2 +- sp/src/game/client/clientleafsystem.cpp | 2 + sp/src/game/client/clientleafsystem.h | 4 + sp/src/game/client/clientshadowmgr.cpp | 3 +- sp/src/game/client/hl2/c_script_intro.cpp | 5 +- sp/src/game/server/ai_activity.cpp | 8 + sp/src/game/server/ai_basenpc.cpp | 82 ++++ sp/src/game/server/ai_basenpc.h | 13 + sp/src/game/server/basecombatcharacter.cpp | 23 +- sp/src/game/server/basecombatcharacter.h | 4 + sp/src/game/server/envmicrophone.cpp | 25 ++ sp/src/game/server/envmicrophone.h | 3 + sp/src/game/server/filters.cpp | 8 + sp/src/game/server/func_breakablesurf.cpp | 11 + sp/src/game/server/hl2/combine_mine.cpp | 69 ++++ sp/src/game/server/hl2/combine_mine.h | 4 + sp/src/game/server/hl2/npc_antliongrub.cpp | 11 + sp/src/game/server/hl2/npc_citizen17.cpp | 5 + .../game/server/hl2/npc_combinedropship.cpp | 20 + sp/src/game/server/hl2/npc_combines.cpp | 5 + sp/src/game/server/hl2/npc_headcrab.cpp | 3 + sp/src/game/server/hl2/npc_manhack.cpp | 1 - sp/src/game/server/hl2/npc_metropolice.cpp | 225 ++++++++++- sp/src/game/server/hl2/npc_metropolice.h | 27 ++ sp/src/game/server/hl2/npc_playercompanion.h | 6 - sp/src/game/server/hl2/npc_strider.cpp | 5 + sp/src/game/server/hl2/npc_turret_ceiling.cpp | 50 +-- sp/src/game/server/hl2/script_intro.cpp | 4 +- sp/src/game/server/hl2/weapon_357.cpp | 2 +- sp/src/game/server/hl2/weapon_rpg.cpp | 3 +- sp/src/game/server/hl2/weapon_rpg.h | 7 + .../game/server/mapbase/SystemConvarMod.cpp | 46 ++- sp/src/game/server/mapbase/SystemConvarMod.h | 1 + sp/src/game/server/mapbase/ai_grenade.h | 15 +- sp/src/game/server/player.cpp | 40 ++ sp/src/game/server/player.h | 4 + sp/src/game/server/scripted.cpp | 7 +- sp/src/game/server/sound.cpp | 30 +- sp/src/game/server/triggers.cpp | 82 +++- sp/src/game/shared/activitylist.cpp | 8 + sp/src/game/shared/ai_activity.h | 9 + sp/src/game/shared/hl2mp/weapon_stunstick.cpp | 29 ++ .../stdshaders/SDK_ShatteredGlass_ps2x.fxc | 159 ++++++++ .../stdshaders/SDK_ShatteredGlass_vs20.fxc | 67 ++++ .../stdshaders/common_flashlight_fxc.h | 2 +- .../stdshaders/game_shader_dx9_mapbase.vpc | 1 + .../lightmappedgeneric_dx9_helper.h | 2 +- .../stdshaders/shatteredglass.cpp | 349 ++++++++++++++++++ .../stdshaders/stdshader_dx9_20b.txt | 4 +- sp/src/public/bspfile.h | 12 + sp/src/utils/vbsp/cubemap.cpp | 4 +- 51 files changed, 1442 insertions(+), 69 deletions(-) create mode 100644 sp/src/materialsystem/stdshaders/SDK_ShatteredGlass_ps2x.fxc create mode 100644 sp/src/materialsystem/stdshaders/SDK_ShatteredGlass_vs20.fxc create mode 100644 sp/src/materialsystem/stdshaders/shatteredglass.cpp diff --git a/README b/README index 8f14a4e1..284ab51d 100644 --- a/README +++ b/README @@ -7,7 +7,7 @@ The original code for phong reflections on LightmappedGeneric-derived shaders ar The Alien Swarm-based radial fog and rope code as well as the multiple skybox support are from Half-Life 2: Downfall. (https://github.com/DownFall-Team/DownFall) The dynamic RTT shadow angles code is from Saul Rennison on the VDC. (https://developer.valvesoftware.com/wiki/Dynamic_RTT_shadow_angles_in_Source_2007) The vortigaunt LOS fix is from Half-Life 2: Community Edition (dky.tehkingd.u in particular). (https://gitlab.com/RaraCerberus/HL2CE) -The parallax corrected cubemap code (which is partly in Mapbase's code, but not yet usable) was originally created by Brian Charles. (https://developer.valvesoftware.com/wiki/Parallax_Corrected_Cubemaps) +The parallax corrected cubemap code was originally created by Brian Charles. (https://developer.valvesoftware.com/wiki/Parallax_Corrected_Cubemaps) Various other code and contributions were based off of pull requests in the Source 2013 SDK (https://github.com/ValveSoftware/source-sdk-2013/pulls) and snippets on the Valve Developer Community (http://developer.valvesoftware.com/). All of the work mentioned above was open source when it was borrowed. diff --git a/sp/src/game/client/clientleafsystem.cpp b/sp/src/game/client/clientleafsystem.cpp index 0a4018f1..03d36cd5 100644 --- a/sp/src/game/client/clientleafsystem.cpp +++ b/sp/src/game/client/clientleafsystem.cpp @@ -1433,10 +1433,12 @@ inline void AddRenderableToRenderList( CClientRenderablesList &renderList, IClie pEntry->m_RenderHandle = renderHandle; curCount++; } +#ifndef MAPBASE // According to ficool2, this message can cause significant lag else { engine->Con_NPrintf( 10, "Warning: overflowed CClientRenderablesList group %d", group ); } +#endif } diff --git a/sp/src/game/client/clientleafsystem.h b/sp/src/game/client/clientleafsystem.h index dd48ec0b..5caa8914 100644 --- a/sp/src/game/client/clientleafsystem.h +++ b/sp/src/game/client/clientleafsystem.h @@ -52,7 +52,11 @@ class CClientRenderablesList : public CRefCounted<> public: enum { +#ifdef MAPBASE + MAX_GROUP_ENTITIES = 16834 // According to ficool2, this limit is bogus/not enforced by the engine and can be "safely" raised. +#else MAX_GROUP_ENTITIES = 4096 +#endif }; struct CEntry diff --git a/sp/src/game/client/clientshadowmgr.cpp b/sp/src/game/client/clientshadowmgr.cpp index 8a18ae86..76b162dd 100644 --- a/sp/src/game/client/clientshadowmgr.cpp +++ b/sp/src/game/client/clientshadowmgr.cpp @@ -1468,8 +1468,7 @@ void CClientShadowMgr::InitDepthTextureShadows() m_DummyColorTexture.InitRenderTargetSurface( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), IMAGE_FORMAT_BGR565, true ); #else #if defined(MAPBASE) //&& !defined(ASW_PROJECTED_TEXTURES) - // SAUL: we want to create a render target of specific size, so use RT_SIZE_NO_CHANGE - m_DummyColorTexture.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_NO_CHANGE, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" ); + m_DummyColorTexture.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_OFFSCREEN, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" ); #else m_DummyColorTexture.InitRenderTarget( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), RT_SIZE_OFFSCREEN, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" ); #endif diff --git a/sp/src/game/client/hl2/c_script_intro.cpp b/sp/src/game/client/hl2/c_script_intro.cpp index aaf5349b..62a20989 100644 --- a/sp/src/game/client/hl2/c_script_intro.cpp +++ b/sp/src/game/client/hl2/c_script_intro.cpp @@ -440,7 +440,7 @@ const QAngle &C_PlayerViewProxy::EyeAngles( void ) float fldummy; pPlayer->CalcView( vecOrigin, angAngles, fldummy, fldummy, fldummy ); - return angAngles; + return GetAbsAngles() + (angAngles - pPlayer->GetAbsAngles()); //return m_hPlayer.Get()->EyeAngles(); } @@ -460,6 +460,7 @@ void C_PlayerViewProxy::GetEyePosition( Vector &vecOrigin, QAngle &angAngles ) pPlayer->CalcView( vecOrigin, angAngles, fldummy, fldummy, fldummy ); vecOrigin = GetAbsOrigin() + (vecOrigin - pPlayer->GetAbsOrigin()); + angAngles = GetAbsAngles() + (angAngles - pPlayer->GetAbsAngles()); } else { @@ -474,7 +475,7 @@ const QAngle &C_PlayerViewProxy::LocalEyeAngles( void ) { C_BasePlayer *pPlayer = GetPlayer(); if (pPlayer) - return pPlayer->LocalEyeAngles(); + return GetAbsAngles() + (pPlayer->LocalEyeAngles() - pPlayer->GetAbsAngles()); else return BaseClass::LocalEyeAngles(); } diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 9190ea7f..475bdbce 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2188,6 +2188,14 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) #ifdef SHARED_COMBINE_ACTIVITIES ADD_ACTIVITY_TO_SR( ACT_COMBINE_THROW_GRENADE ); ADD_ACTIVITY_TO_SR( ACT_COMBINE_AR2_ALTFIRE ); + + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_ADVANCE ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_FORWARD ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_GROUP ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_HALT ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_LEFT ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_RIGHT ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_TAKECOVER ); #endif #ifdef COMPANION_HOLSTER_WORKAROUND diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index ad1961d7..1a5f36b7 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -1876,6 +1876,46 @@ void CAI_BaseNPC::InputSetThinkNPC( inputdata_t &inputdata ) SetThink ( &CAI_BaseNPC::CallNPCThink ); SetNextThink(gpGlobals->curtime + inputdata.value.Float()); } + +//------------------------------------------------------------------------------ +// Purpose: Sets our look distance +//------------------------------------------------------------------------------ +void CAI_BaseNPC::InputSetDistLook( inputdata_t &inputdata ) +{ + if ( inputdata.value.Float() != 0.0f ) + { + SetDistLook( inputdata.value.Float() ); + } + else + { + SetDistLook( 2048.0 ); + + if ( HasSpawnFlags( SF_NPC_LONG_RANGE ) ) + { + SetDistLook( 6000.0 ); + } + } +} + +//------------------------------------------------------------------------------ +// Purpose: Sets our distance too far +//------------------------------------------------------------------------------ +void CAI_BaseNPC::InputSetDistTooFar( inputdata_t &inputdata ) +{ + if ( inputdata.value.Float() != 0.0f ) + { + m_flDistTooFar = inputdata.value.Float(); + } + else + { + m_flDistTooFar = 1024.0; + + if ( HasSpawnFlags( SF_NPC_LONG_RANGE ) ) + { + m_flDistTooFar = 1e9f; + } + } +} #endif //--------------------------------------------------------- @@ -11599,6 +11639,8 @@ BEGIN_DATADESC( CAI_BaseNPC ) #ifdef MAPBASE DEFINE_KEYFIELD( m_FriendlyFireOverride, FIELD_INTEGER, "FriendlyFireOverride" ), + + DEFINE_KEYFIELD( m_flSpeedModifier, FIELD_FLOAT, "BaseSpeedModifier" ), #endif // Satisfy classcheck @@ -11700,6 +11742,11 @@ BEGIN_DATADESC( CAI_BaseNPC ) DEFINE_INPUTFUNC( FIELD_FLOAT, "SetThinkNPC", InputSetThinkNPC ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetDistLook", InputSetDistLook ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetDistTooFar", InputSetDistTooFar ), + + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetSpeedModifier", InputSetSpeedModifier ), + DEFINE_OUTPUT( m_OnStateChange, "OnStateChange" ), #endif @@ -12356,6 +12403,7 @@ CAI_BaseNPC::CAI_BaseNPC(void) #ifdef MAPBASE m_iDynamicInteractionsAllowed = TRS_NONE; + m_flSpeedModifier = 1.0f; #endif } @@ -13967,6 +14015,34 @@ void CAI_BaseNPC::InputSetSpeedModifierSpeed( inputdata_t &inputdata ) m_iSpeedModSpeed = inputdata.value.Int(); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Get movement speed, multipled by modifier +//----------------------------------------------------------------------------- +float CAI_BaseNPC::GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence ) +{ + float t = SequenceDuration( pStudioHdr, iSequence ); + + if (t > 0) + { + return (GetSequenceMoveDist( pStudioHdr, iSequence ) * m_flSpeedModifier / t); + } + else + { + return 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Hammer input to change the speed of the NPC (based on 1upD's npc_shadow_walker code) +// Not to be confused with the inputs above +//----------------------------------------------------------------------------- +void CAI_BaseNPC::InputSetSpeedModifier( inputdata_t &inputdata ) +{ + this->m_flSpeedModifier = inputdata.value.Float(); +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -15534,6 +15610,12 @@ bool CAI_BaseNPC::IsCrouchedActivity( Activity activity ) case ACT_RANGE_AIM_AR2_LOW: case ACT_RANGE_AIM_SMG1_LOW: case ACT_RANGE_AIM_PISTOL_LOW: + + case ACT_RANGE_ATTACK1_LOW: + case ACT_RANGE_ATTACK_AR2_LOW: + case ACT_RANGE_ATTACK_SMG1_LOW: + case ACT_RANGE_ATTACK_PISTOL_LOW: + case ACT_RANGE_ATTACK2_LOW: #endif return true; } diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index 51f85631..d05b4a2f 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1041,6 +1041,10 @@ public: const CAI_Senses * GetSenses() const { return m_pSenses; } void SetDistLook( float flDistLook ); +#ifdef MAPBASE + void InputSetDistLook( inputdata_t &inputdata ); + void InputSetDistTooFar( inputdata_t &inputdata ); +#endif virtual bool QueryHearSound( CSound *pSound ); virtual bool QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC = false ); @@ -2276,6 +2280,15 @@ public: void InputSetSpeedModifierRadius( inputdata_t &inputdata ); void InputSetSpeedModifierSpeed( inputdata_t &inputdata ); +#ifdef MAPBASE + // Hammer input to change the speed of the NPC (based on 1upD's npc_shadow_walker code) + // Not to be confused with the inputs above + virtual float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence ); + inline float GetSequenceGroundSpeed( int iSequence ) { return GetSequenceGroundSpeed( GetModelPtr(), iSequence ); } + void InputSetSpeedModifier( inputdata_t &inputdata ); + float m_flSpeedModifier; +#endif + virtual bool ShouldProbeCollideAgainstEntity( CBaseEntity *pEntity ); bool m_bPlayerAvoidState; diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index aab5d4e3..d96b9345 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -73,12 +73,17 @@ ConVar ai_force_serverside_ragdoll( "ai_force_serverside_ragdoll", "0" ); ConVar nb_last_area_update_tolerance( "nb_last_area_update_tolerance", "4.0", FCVAR_CHEAT, "Distance a character needs to travel in order to invalidate cached area" ); // 4.0 tested as sweet spot (for wanderers, at least). More resulted in little benefit, less quickly diminished benefit [7/31/2008 tom] +#ifdef MAPBASE +// ShouldUseVisibilityCache() is used as an actual function now +ConVar ai_use_visibility_cache( "ai_use_visibility_cache", "1" ); +#else #ifndef _RETAIL ConVar ai_use_visibility_cache( "ai_use_visibility_cache", "1" ); #define ShouldUseVisibilityCache() ai_use_visibility_cache.GetBool() #else #define ShouldUseVisibilityCache() true #endif +#endif BEGIN_DATADESC( CBaseCombatCharacter ) @@ -366,11 +371,16 @@ bool CBaseCombatCharacter::FVisible( CBaseEntity *pEntity, int traceMask, CBaseE { VPROF( "CBaseCombatCharacter::FVisible" ); +#ifdef MAPBASE + if ( traceMask != MASK_BLOCKLOS || !ShouldUseVisibilityCache( pEntity ) || pEntity == this || !ai_use_visibility_cache.GetBool() + ) +#else if ( traceMask != MASK_BLOCKLOS || !ShouldUseVisibilityCache() || pEntity == this #if defined(HL2_DLL) || Classify() == CLASS_BULLSEYE || pEntity->Classify() == CLASS_BULLSEYE #endif ) +#endif { return BaseClass::FVisible( pEntity, traceMask, ppBlocker ); } @@ -476,6 +486,17 @@ void CBaseCombatCharacter::ResetVisibilityCache( CBaseCombatCharacter *pBCC ) } } +#ifdef MAPBASE +bool CBaseCombatCharacter::ShouldUseVisibilityCache( CBaseEntity *pEntity ) +{ +#ifdef HL2_DLL + return Classify() != CLASS_BULLSEYE && pEntity->Classify() != CLASS_BULLSEYE; +#else + return true; +#endif +} +#endif + #ifdef PORTAL bool CBaseCombatCharacter::FVisibleThroughPortal( const CProp_Portal *pPortal, CBaseEntity *pEntity, int traceMask, CBaseEntity **ppBlocker ) { @@ -4070,7 +4091,7 @@ void CBaseCombatCharacter::InputPickupWeaponInstant( inputdata_t &inputdata ) } else { - Warning("%s received PickupWeaponInstant with invalid entity %s\n", inputdata.value.Entity() ? "null" : inputdata.value.Entity()->GetDebugName()); + Warning("%s received PickupWeaponInstant with invalid entity %s\n", GetDebugName(), inputdata.value.Entity() ? "null" : inputdata.value.Entity()->GetDebugName()); } } diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index c6208cf9..a9a5c815 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -136,6 +136,10 @@ public: virtual bool FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ) { return BaseClass::FVisible( vecTarget, traceMask, ppBlocker ); } static void ResetVisibilityCache( CBaseCombatCharacter *pBCC = NULL ); +#ifdef MAPBASE + virtual bool ShouldUseVisibilityCache( CBaseEntity *pEntity ); +#endif + #ifdef PORTAL virtual bool FVisibleThroughPortal( const CProp_Portal *pPortal, CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); #endif diff --git a/sp/src/game/server/envmicrophone.cpp b/sp/src/game/server/envmicrophone.cpp index 14a5d56d..ee78f87f 100644 --- a/sp/src/game/server/envmicrophone.cpp +++ b/sp/src/game/server/envmicrophone.cpp @@ -48,6 +48,7 @@ BEGIN_DATADESC( CEnvMicrophone ) DEFINE_KEYFIELD(m_iszLandmarkName, FIELD_STRING, "landmark"), DEFINE_FIELD(m_hLandmark, FIELD_EHANDLE), DEFINE_KEYFIELD(m_flPitchScale, FIELD_FLOAT, "PitchScale"), + DEFINE_KEYFIELD(m_nChannel, FIELD_INTEGER, "channel"), #endif // DEFINE_FIELD(m_bAvoidFeedback, FIELD_BOOLEAN), // DONT SAVE DEFINE_KEYFIELD(m_iSpeakerDSPPreset, FIELD_INTEGER, "speaker_dsp_preset" ), @@ -59,6 +60,8 @@ BEGIN_DATADESC( CEnvMicrophone ) DEFINE_INPUTFUNC(FIELD_STRING, "SetSpeakerName", InputSetSpeakerName), #ifdef MAPBASE DEFINE_INPUTFUNC(FIELD_INTEGER, "SetDSPPreset", InputSetDSPPreset), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPitchScale", InputSetPitchScale ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetChannel", InputSetChannel ), #endif DEFINE_OUTPUT(m_SoundLevel, "SoundLevel"), @@ -259,6 +262,24 @@ void CEnvMicrophone::InputSetDSPPreset( inputdata_t &inputdata ) m_iSpeakerDSPPreset = inputdata.value.Int(); ActivateSpeaker(); } + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CEnvMicrophone::InputSetPitchScale( inputdata_t &inputdata ) +{ + m_flPitchScale = inputdata.value.Float(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CEnvMicrophone::InputSetChannel( inputdata_t &inputdata ) +{ + m_nChannel = inputdata.value.Int(); +} #endif //----------------------------------------------------------------------------- @@ -522,7 +543,11 @@ MicrophoneResult_t CEnvMicrophone::SoundPlayed( int entindex, const char *soundn CPASAttenuationFilter filter( m_hSpeaker ); EmitSound_t ep; +#ifdef MAPBASE + ep.m_nChannel = m_nChannel; +#else ep.m_nChannel = CHAN_STATIC; +#endif ep.m_pSoundName = soundname; ep.m_flVolume = flVolume; ep.m_SoundLevel = soundlevel; diff --git a/sp/src/game/server/envmicrophone.h b/sp/src/game/server/envmicrophone.h index 27591f7c..cf8e729e 100644 --- a/sp/src/game/server/envmicrophone.h +++ b/sp/src/game/server/envmicrophone.h @@ -56,6 +56,8 @@ public: void InputSetSpeakerName( inputdata_t &inputdata ); #ifdef MAPBASE void InputSetDSPPreset( inputdata_t &inputdata ); + void InputSetPitchScale( inputdata_t &inputdata ); + void InputSetChannel( inputdata_t &inputdata ); #endif DECLARE_DATADESC(); @@ -86,6 +88,7 @@ private: string_t m_iszLandmarkName; EHANDLE m_hLandmark; float m_flPitchScale = 1.0f; + int m_nChannel = CHAN_STATIC; #endif COutputFloat m_SoundLevel; // Fired when the sampled volume level changes. diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index c67d6e50..f9380dc7 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -1899,6 +1899,14 @@ public: return true; } + bool PassesDamageFilterImpl( CBaseEntity *pCaller, const CTakeDamageInfo &info ) + { + if (GetTargetFilter() && m_iSecondaryFilterMode == REDIRECT_MUST_PASS_TO_DAMAGE_CALLER) + return RedirectToDamageFilter( pCaller, info ); + + return true; + } + bool DamageMod( CBaseEntity *pCaller, CTakeDamageInfo &info ) { if (GetTargetFilter()) diff --git a/sp/src/game/server/func_breakablesurf.cpp b/sp/src/game/server/func_breakablesurf.cpp index 4b8e0ba5..ddd8542f 100644 --- a/sp/src/game/server/func_breakablesurf.cpp +++ b/sp/src/game/server/func_breakablesurf.cpp @@ -35,6 +35,9 @@ // Spawn flags #define SF_BREAKABLESURF_CRACK_DECALS 0x00000001 #define SF_BREAKABLESURF_DAMAGE_FROM_HELD_OBJECTS 0x00000002 +#ifdef MAPBASE +#define SF_BREAKABLESURF_PLAY_BREAK_SOUND 0x00000004 +#endif //############################################################################# // > CWindowPane @@ -611,7 +614,15 @@ void CBreakableSurface::Die( CBaseEntity *pBreaker, const Vector &vAttackDir ) return; // Play a break sound +#ifdef MAPBASE + if ( HasSpawnFlags(SF_BREAKABLESURF_PLAY_BREAK_SOUND) ) + { + Vector centerPos = (m_vLLVertex + m_vURVertex) / 2; + PhysBreakSound( this, VPhysicsGetObject(), centerPos ); + } +#else PhysBreakSound( this, VPhysicsGetObject(), GetAbsOrigin() ); +#endif m_bIsBroken = true; m_iHealth = 0.0f; diff --git a/sp/src/game/server/hl2/combine_mine.cpp b/sp/src/game/server/hl2/combine_mine.cpp index c3b54a82..b0145366 100644 --- a/sp/src/game/server/hl2/combine_mine.cpp +++ b/sp/src/game/server/hl2/combine_mine.cpp @@ -89,6 +89,7 @@ BEGIN_DATADESC( CBounceBomb ) DEFINE_KEYFIELD( m_bDisarmed, FIELD_BOOLEAN, "StartDisarmed" ), #ifdef MAPBASE DEFINE_KEYFIELD( m_iInitialState, FIELD_INTEGER, "InitialState" ), + DEFINE_KEYFIELD( m_bCheapWarnSound, FIELD_BOOLEAN, "CheapWarnSound" ), #endif DEFINE_KEYFIELD( m_iModification, FIELD_INTEGER, "Modification" ), @@ -306,8 +307,12 @@ void CBounceBomb::SetMineState( int iState ) { case MINE_STATE_DORMANT: { +#ifdef MAPBASE + SilenceWarnSound( 0.1 ); +#else CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); controller.SoundChangeVolume( m_pWarnSound, 0.0, 0.1 ); +#endif UpdateLight( false, 0, 0, 0, 0 ); SetThink( NULL ); } @@ -315,8 +320,12 @@ void CBounceBomb::SetMineState( int iState ) case MINE_STATE_CAPTIVE: { +#ifdef MAPBASE + SilenceWarnSound( 0.2 ); +#else CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); controller.SoundChangeVolume( m_pWarnSound, 0.0, 0.2 ); +#endif // Unhook unsigned int flags = VPhysicsGetObject()->GetCallbackFlags(); @@ -359,8 +368,12 @@ void CBounceBomb::SetMineState( int iState ) // Scare NPC's CSoundEnt::InsertSound( SOUND_DANGER, GetAbsOrigin(), 300, 1.0f, this ); +#ifdef MAPBASE + SilenceWarnSound( 0.2 ); +#else CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); controller.SoundChangeVolume( m_pWarnSound, 0.0, 0.2 ); +#endif SetTouch( &CBounceBomb::ExplodeTouch ); unsigned int flags = VPhysicsGetObject()->GetCallbackFlags(); @@ -822,7 +835,11 @@ void CBounceBomb::Wake( bool bAwake ) CReliableBroadcastRecipientFilter filter; +#ifdef MAPBASE + if( !m_pWarnSound && !m_bCheapWarnSound ) +#else if( !m_pWarnSound ) +#endif { m_pWarnSound = controller.SoundCreate( filter, entindex(), "NPC_CombineMine.ActiveLoop" ); controller.Play( m_pWarnSound, 1.0, PITCH_NORM ); @@ -834,7 +851,11 @@ void CBounceBomb::Wake( bool bAwake ) if( m_bFoeNearest ) { EmitSound( "NPC_CombineMine.TurnOn" ); +#ifdef MAPBASE + UpdateWarnSound( 1.0, 0.1 ); +#else controller.SoundChangeVolume( m_pWarnSound, 1.0, 0.1 ); +#endif } unsigned char r, g, b; @@ -860,7 +881,11 @@ void CBounceBomb::Wake( bool bAwake ) } SetNearestNPC( NULL ); +#ifdef MAPBASE + SilenceWarnSound( 0.1 ); +#else controller.SoundChangeVolume( m_pWarnSound, 0.0, 0.1 ); +#endif UpdateLight( false, 0, 0, 0, 0 ); } @@ -1313,6 +1338,50 @@ bool CBounceBomb::HandleInteraction( int interactionType, void *data, CBaseComba return BaseClass::HandleInteraction(interactionType, data, sourceEnt); } + +//----------------------------------------------------------------------------- +void CBounceBomb::UpdateWarnSound( float flVolume, float flDelta ) +{ + CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); + if (m_bCheapWarnSound && !m_pWarnSound) + { + CReliableBroadcastRecipientFilter filter; + //m_pWarnSound = controller.SoundCreate( filter, entindex(), "NPC_CombineMine.ActiveLoop" ); + //controller.Play( m_pWarnSound, flVolume, PITCH_NORM ); + + EmitSound_t params; + params.m_pSoundName = "NPC_CombineMine.ActiveLoop"; + params.m_flVolume = flVolume; + params.m_nPitch = PITCH_NORM; + + EmitSound( filter, entindex(), params ); + } + else + { + controller.SoundChangeVolume( m_pWarnSound, flVolume, flDelta ); + } +} + +void CBounceBomb::SilenceWarnSound( float flDelta ) +{ + CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); + if (m_bCheapWarnSound) + { + //if ( m_pWarnSound ) + //{ + // controller.SoundDestroy( m_pWarnSound ); + //} + + StopSound( "NPC_CombineMine.ActiveLoop" ); + } + else + { + if ( m_pWarnSound ) + { + controller.SoundChangeVolume( m_pWarnSound, 0.0, flDelta ); + } + } +} #endif //--------------------------------------------------------- diff --git a/sp/src/game/server/hl2/combine_mine.h b/sp/src/game/server/hl2/combine_mine.h index 21205955..9d0d78e3 100644 --- a/sp/src/game/server/hl2/combine_mine.h +++ b/sp/src/game/server/hl2/combine_mine.h @@ -86,6 +86,9 @@ public: #ifdef MAPBASE // Uses the new CBaseEntity interaction implementation and replaces the dynamic_casting from npc_barnacle bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ); + + void UpdateWarnSound( float flVolume, float flDelta ); + void SilenceWarnSound( float flDelta ); #endif DECLARE_DATADESC(); @@ -118,6 +121,7 @@ private: bool m_bDisarmed; #ifdef MAPBASE int m_iInitialState; + bool m_bCheapWarnSound; #endif bool m_bPlacedByPlayer; diff --git a/sp/src/game/server/hl2/npc_antliongrub.cpp b/sp/src/game/server/hl2/npc_antliongrub.cpp index 7e9ef2d0..07444e9a 100644 --- a/sp/src/game/server/hl2/npc_antliongrub.cpp +++ b/sp/src/game/server/hl2/npc_antliongrub.cpp @@ -857,6 +857,13 @@ void CGrubNugget::Spawn( void ) { Precache(); +#ifdef MAPBASE + if ( GetModelName() != NULL_STRING ) + { + SetModel( STRING(GetModelName()) ); + } + else +#endif if ( m_nDenomination == NUGGET_LARGE ) { SetModel( "models/grub_nugget_large.mdl" ); @@ -888,6 +895,10 @@ void CGrubNugget::Precache( void ) PrecacheModel("models/grub_nugget_small.mdl"); PrecacheModel("models/grub_nugget_medium.mdl"); PrecacheModel("models/grub_nugget_large.mdl"); +#ifdef MAPBASE + if (GetModelName() != NULL_STRING) + PrecacheModel( STRING(GetModelName()) ); +#endif PrecacheScriptSound( "GrubNugget.Touch" ); PrecacheScriptSound( "NPC_Antlion_Grub.Explode" ); diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index d3283642..292aff08 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -3978,6 +3978,11 @@ void CNPC_Citizen::Heal() CBaseEntity *pTarget = GetTarget(); +#ifdef MAPBASE + if ( !pTarget ) + return; +#endif + Vector target = pTarget->GetAbsOrigin() - GetAbsOrigin(); if ( target.Length() > HEAL_TARGET_RANGE * 2 ) return; diff --git a/sp/src/game/server/hl2/npc_combinedropship.cpp b/sp/src/game/server/hl2/npc_combinedropship.cpp index 0e7e973c..fa40fd76 100644 --- a/sp/src/game/server/hl2/npc_combinedropship.cpp +++ b/sp/src/game/server/hl2/npc_combinedropship.cpp @@ -373,6 +373,10 @@ private: COutputFloat m_OnContainerShotDownBeforeDropoff; COutputEvent m_OnContainerShotDownAfterDropoff; +#ifdef MAPBASE + COutputEHANDLE m_OnSpawnNPC; +#endif + protected: // Because the combine dropship is a leaf class, we can use // static variables to store this information, and save some memory. @@ -866,6 +870,10 @@ BEGIN_DATADESC( CNPC_CombineDropship ) DEFINE_OUTPUT( m_OnContainerShotDownBeforeDropoff, "OnCrateShotDownBeforeDropoff" ), DEFINE_OUTPUT( m_OnContainerShotDownAfterDropoff, "OnCrateShotDownAfterDropoff" ), +#ifdef MAPBASE + DEFINE_OUTPUT( m_OnSpawnNPC, "OnSpawnNPC" ), +#endif + END_DATADESC() @@ -955,6 +963,9 @@ void CNPC_CombineDropship::Spawn( void ) m_hContainer->SetOwnerEntity(this); m_hContainer->Spawn(); m_hContainer->SetAbsOrigin( GetAbsOrigin() - Vector( 0, 0 , 100 ) ); +#ifdef MAPBASE + m_OnSpawnNPC.Set( m_hContainer, m_hContainer, this ); +#endif break; case CRATE_APC: @@ -2602,6 +2613,10 @@ void CNPC_CombineDropship::SpawnTroop( void ) pSequence->AcceptInput( "BeginSequence", this, this, emptyVariant, 0 ); m_hLastTroopToLeave = pNPC; + +#ifdef MAPBASE + m_OnSpawnNPC.Set( pNPC, pNPC, this ); +#endif } //----------------------------------------------------------------------------- @@ -2765,7 +2780,12 @@ float CNPC_CombineDropship::GetAltitude( void ) //----------------------------------------------------------------------------- void CNPC_CombineDropship::DropMine( void ) { +#ifdef MAPBASE + CBaseEntity *pMine = NPC_Rollermine_DropFromPoint( GetAbsOrigin(), this, STRING( m_sRollermineTemplateData ) ); + m_OnSpawnNPC.Set( pMine, pMine, this ); +#else NPC_Rollermine_DropFromPoint( GetAbsOrigin(), this, STRING(m_sRollermineTemplateData) ); +#endif } //------------------------------------------------------------------------------ diff --git a/sp/src/game/server/hl2/npc_combines.cpp b/sp/src/game/server/hl2/npc_combines.cpp index cd4e07b7..be85d895 100644 --- a/sp/src/game/server/hl2/npc_combines.cpp +++ b/sp/src/game/server/hl2/npc_combines.cpp @@ -96,7 +96,12 @@ void CNPC_CombineS::Precache() { const char *pModelName = STRING( GetModelName() ); +#ifdef MAPBASE + // Need to do this for dirt variant + if( !Q_strnicmp( pModelName, "models/combine_super_sold", 25 ) ) +#else if( !Q_stricmp( pModelName, "models/combine_super_soldier.mdl" ) ) +#endif { m_fIsElite = true; } diff --git a/sp/src/game/server/hl2/npc_headcrab.cpp b/sp/src/game/server/hl2/npc_headcrab.cpp index 26c7dbfb..33f21107 100644 --- a/sp/src/game/server/hl2/npc_headcrab.cpp +++ b/sp/src/game/server/hl2/npc_headcrab.cpp @@ -2243,6 +2243,9 @@ void CBaseHeadcrab::GrabHintNode( CAI_Hint *pHint ) { SetHintNode( pHint ); pHint->Lock( this ); +#ifdef MAPBASE + pHint->NPCStartedUsing( this ); +#endif } } diff --git a/sp/src/game/server/hl2/npc_manhack.cpp b/sp/src/game/server/hl2/npc_manhack.cpp index 64ee9343..91d011fa 100644 --- a/sp/src/game/server/hl2/npc_manhack.cpp +++ b/sp/src/game/server/hl2/npc_manhack.cpp @@ -3242,7 +3242,6 @@ void CNPC_Manhack::SetEyeState( int state ) { //Toggle our state #ifdef MAPBASE - // Something from Half-Laugh. // Makes it easier to distinguish between hostile and friendly manhacks. if( m_bHackedByAlyx ) { diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index 31de6e8e..03a170f6 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -123,6 +123,10 @@ ConVar metropolice_chase_use_follow( "metropolice_chase_use_follow", "0" ); ConVar metropolice_move_and_melee("metropolice_move_and_melee", "1" ); ConVar metropolice_charge("metropolice_charge", "1" ); +#ifdef MAPBASE +ConVar metropolice_new_component_behavior("metropolice_new_component_behavior", "1"); +#endif + // How many clips of pistol ammo a metropolice carries. #define METROPOLICE_NUM_CLIPS 5 #define METROPOLICE_BURST_RELOAD_COUNT 20 @@ -256,6 +260,7 @@ BEGIN_DATADESC( CNPC_MetroPolice ) #ifdef MAPBASE DEFINE_AIGRENADE_DATADESC() + DEFINE_INPUT( m_iGrenadeCapabilities, FIELD_INTEGER, "SetGrenadeCapabilities" ), #endif END_DATADESC() @@ -503,6 +508,9 @@ void CNPC_MetroPolice::NotifyDeadFriend( CBaseEntity* pFriend ) //----------------------------------------------------------------------------- CNPC_MetroPolice::CNPC_MetroPolice() { +#ifdef MAPBASE + m_iGrenadeCapabilities = GRENCAP_GRENADE; +#endif } @@ -1508,12 +1516,8 @@ void CNPC_MetroPolice::OnUpdateShotRegulator( ) { BaseClass::OnUpdateShotRegulator(); -#ifdef MAPBASE - if ( GetActiveWeapon() && GetActiveWeapon()->WeaponClassify() == WEPCLASS_HANDGUN ) -#else // FIXME: This code (except the burst interval) could be used for all weapon types if( Weapon_OwnsThisType( "weapon_pistol" ) ) -#endif { if ( m_nBurstMode == BURST_NOT_ACTIVE ) { @@ -4383,6 +4387,148 @@ int CNPC_MetroPolice::SelectAirboatCombatSchedule() } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Standoff schedule selection +//----------------------------------------------------------------------------- +int CNPC_MetroPolice::SelectBehaviorOverrideSchedule() +{ + // Announce a new enemy + if ( HasCondition( COND_NEW_ENEMY ) ) + { + AnnounceEnemyType( GetEnemy() ); + } + + int nResult = SelectScheduleNewEnemy(); + if ( nResult != SCHED_NONE ) + return nResult; + + if (!HasBaton() && ((float)m_nRecentDamage / (float)GetMaxHealth()) > RECENT_DAMAGE_THRESHOLD) + { + m_nRecentDamage = 0; + m_flRecentDamageTime = 0; +#ifdef METROPOLICE_USES_RESPONSE_SYSTEM + SpeakIfAllowed(TLK_COP_COVER_HEAVY_DAMAGE, SENTENCE_PRIORITY_MEDIUM, SENTENCE_CRITERIA_NORMAL); +#else + m_Sentences.Speak( "METROPOLICE_COVER_HEAVY_DAMAGE", SENTENCE_PRIORITY_MEDIUM, SENTENCE_CRITERIA_NORMAL ); +#endif + + return SCHED_TAKE_COVER_FROM_ENEMY; + } + + if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) ) + { + nResult = SelectRangeAttackSchedule(); + if ( !GetShotRegulator()->IsInRestInterval() && nResult != SCHED_METROPOLICE_ADVANCE && nResult != SCHED_RANGE_ATTACK1 ) + return nResult; + } + + if ( HasCondition( COND_TOO_CLOSE_TO_ATTACK ) ) + { + return SCHED_BACK_AWAY_FROM_ENEMY; + } + + if ( HasCondition( COND_LOW_PRIMARY_AMMO ) || HasCondition( COND_NO_PRIMARY_AMMO ) ) + { + AnnounceOutOfAmmo( ); + return SCHED_HIDE_AND_RELOAD; + } + + if ( HasCondition(COND_WEAPON_SIGHT_OCCLUDED) && !HasBaton() ) + { + // If they are hiding behind something that we can destroy, start shooting at it. + CBaseEntity *pBlocker = GetEnemyOccluder(); + if ( pBlocker && pBlocker->GetHealth() > 0 && OccupyStrategySlotRange( SQUAD_SLOT_POLICE_ATTACK_OCCLUDER1, SQUAD_SLOT_POLICE_ATTACK_OCCLUDER2 ) ) + { +#ifdef METROPOLICE_USES_RESPONSE_SYSTEM + SpeakIfAllowed(TLK_COP_SHOOTCOVER); +#else + m_Sentences.Speak( "METROPOLICE_SHOOT_COVER" ); +#endif + return SCHED_SHOOT_ENEMY_COVER; + } + } + + if (HasCondition(COND_ENEMY_OCCLUDED)) + { + if ( GetEnemy() && !(GetEnemy()->GetFlags() & FL_NOTARGET) ) + { + if ( HasGrenades() ) + { + // We don't see our enemy. If it hasn't been long since I last saw him, + // and he's pretty close to the last place I saw him, throw a grenade in + // to flush him out. A wee bit of cheating here... + + float flTime; + float flDist; + + flTime = gpGlobals->curtime - GetEnemies()->LastTimeSeen( GetEnemy() ); + flDist = ( GetEnemy()->GetAbsOrigin() - GetEnemies()->LastSeenPosition( GetEnemy() ) ).Length(); + + //Msg("Time: %f Dist: %f\n", flTime, flDist ); + if ( flTime <= COMBINE_GRENADE_FLUSH_TIME && flDist <= COMBINE_GRENADE_FLUSH_DIST && CanGrenadeEnemy( false ) && OccupyStrategySlot( SQUAD_SLOT_SPECIAL_ATTACK ) ) + { + return SCHED_RANGE_ATTACK2; + } + } + } + } + + // If you can't attack, but you can deploy a manhack, do it! + if( CanDeployManhack() && OccupyStrategySlot( SQUAD_SLOT_POLICE_DEPLOY_MANHACK ) ) + return SCHED_METROPOLICE_DEPLOY_MANHACK; + + return SCHED_NONE; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CNPC_MetroPolice::IsCrouchedActivity( Activity activity ) +{ + Activity realActivity = TranslateActivity(activity); + + switch ( realActivity ) + { + case ACT_RELOAD_LOW: + case ACT_COVER_LOW: + case ACT_COVER_PISTOL_LOW: + case ACT_COVER_SMG1_LOW: + case ACT_RELOAD_SMG1_LOW: + //case ACT_RELOAD_AR2_LOW: + case ACT_RELOAD_PISTOL_LOW: + case ACT_RELOAD_SHOTGUN_LOW: + + // These animations aren't actually "low" on metrocops + //case ACT_RANGE_AIM_LOW: + //case ACT_RANGE_AIM_AR2_LOW: + //case ACT_RANGE_AIM_SMG1_LOW: + //case ACT_RANGE_AIM_PISTOL_LOW: + + //case ACT_RANGE_ATTACK1_LOW: + //case ACT_RANGE_ATTACK_AR2_LOW: + //case ACT_RANGE_ATTACK_SMG1_LOW: + //case ACT_RANGE_ATTACK_PISTOL_LOW: + //case ACT_RANGE_ATTACK2_LOW: + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Standoff schedule selection +//----------------------------------------------------------------------------- +int CNPC_MetroPolice::CMetroPoliceStandoffBehavior::SelectScheduleAttack() +{ + int result = metropolice_new_component_behavior.GetBool() ? GetOuter()->SelectBehaviorOverrideSchedule() : SCHED_NONE; + if (result == SCHED_NONE) + result = BaseClass::SelectScheduleAttack(); + return result; +} +#endif + + //----------------------------------------------------------------------------- // Purpose: // Input : &info - @@ -4641,13 +4787,29 @@ int CNPC_MetroPolice::SelectSchedule( void ) if ( m_flNextGrenadeCheck < gpGlobals->curtime ) { Vector vecTarget = m_hForcedGrenadeTarget->WorldSpaceCenter(); + + // The fact we have a forced grenade target overrides whether we're marked as "capable". + // If we're *only* alt-fire capable, use an energy ball. If not, throw a grenade. + if (!IsAltFireCapable() || IsGrenadeCapable()) { - // If we can, throw a grenade at the target. - // Ignore grenade count / distance / etc - if ( CheckCanThrowGrenade( vecTarget ) ) + Vector vecTarget = m_hForcedGrenadeTarget->WorldSpaceCenter(); { + // If we can, throw a grenade at the target. + // Ignore grenade count / distance / etc + if ( CheckCanThrowGrenade( vecTarget ) ) + { + m_hForcedGrenadeTarget = NULL; + return SCHED_METROPOLICE_FORCED_GRENADE_THROW; + } + } + } + else + { + if ( FVisible( m_hForcedGrenadeTarget ) ) + { + m_vecAltFireTarget = vecTarget; m_hForcedGrenadeTarget = NULL; - return SCHED_METROPOLICE_FORCED_GRENADE_THROW; + return SCHED_METROPOLICE_AR2_ALTFIRE; } } } @@ -4876,6 +5038,14 @@ int CNPC_MetroPolice::TranslateSchedule( int scheduleType ) if ( nSched != SCHED_NONE ) return nSched; } +#ifdef MAPBASE + if ( CanAltFireEnemy(false) && OccupyStrategySlot(SQUAD_SLOT_SPECIAL_ATTACK) ) + { + // If this metrocop has the balls to alt-fire the enemy's last known position, + // do so! + return SCHED_METROPOLICE_AR2_ALTFIRE; + } +#endif return SCHED_METROPOLICE_ESTABLISH_LINE_OF_FIRE; case SCHED_WAKE_ANGRY: @@ -4902,6 +5072,16 @@ int CNPC_MetroPolice::TranslateSchedule( int scheduleType ) return SCHED_METROPOLICE_DRAW_PISTOL; } +#ifdef MAPBASE + if (CanAltFireEnemy( true ) && OccupyStrategySlot( SQUAD_SLOT_SPECIAL_ATTACK )) + { + // Since I'm holding this squadslot, no one else can try right now. If I die before the shot + // goes off, I won't have affected anyone else's ability to use this attack at their nearest + // convenience. + return SCHED_METROPOLICE_AR2_ALTFIRE; + } +#endif + #ifdef MAPBASE if (GetActiveWeapon() && EntIsClass(GetActiveWeapon(), gm_isz_class_SMG1)) #else @@ -5154,6 +5334,10 @@ void CNPC_MetroPolice::StartTask( const Task_t *pTask ) case TASK_METROPOLICE_FACE_TOSS_DIR: break; + + case TASK_METROPOLICE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET: + StartTask_FaceAltFireTarget( pTask ); + break; #endif case TASK_METROPOLICE_GET_PATH_TO_STITCH: @@ -5520,6 +5704,10 @@ void CNPC_MetroPolice::RunTask( const Task_t *pTask ) break; #ifdef MAPBASE + case TASK_METROPOLICE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET: + RunTask_FaceAltFireTarget( pTask ); + break; + case TASK_METROPOLICE_GET_PATH_TO_FORCED_GREN_LOS: RunTask_GetPathToForced( pTask ); break; @@ -5901,6 +6089,10 @@ AI_BEGIN_CUSTOM_NPC( npc_metropolice, CNPC_MetroPolice ) DECLARE_ANIMEVENT( AE_METROPOLICE_START_DEPLOY ); DECLARE_ANIMEVENT( AE_METROPOLICE_DRAW_PISTOL ); DECLARE_ANIMEVENT( AE_METROPOLICE_DEPLOY_MANHACK ); +#ifdef MAPBASE + DECLARE_ANIMEVENT( COMBINE_AE_BEGIN_ALTFIRE ) + DECLARE_ANIMEVENT( COMBINE_AE_ALTFIRE ) +#endif DECLARE_SQUADSLOT( SQUAD_SLOT_POLICE_CHARGE_ENEMY ); DECLARE_SQUADSLOT( SQUAD_SLOT_POLICE_HARASS ); @@ -5948,6 +6140,7 @@ AI_BEGIN_CUSTOM_NPC( npc_metropolice, CNPC_MetroPolice ) DECLARE_TASK( TASK_METROPOLICE_GET_PATH_TO_FORCED_GREN_LOS ) DECLARE_TASK( TASK_METROPOLICE_DEFER_SQUAD_GRENADES ) DECLARE_TASK( TASK_METROPOLICE_FACE_TOSS_DIR ) + DECLARE_TASK( TASK_METROPOLICE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET ) #endif DECLARE_CONDITION( COND_METROPOLICE_ON_FIRE ); @@ -6630,6 +6823,22 @@ DEFINE_SCHEDULE "" " Interrupts" ) + + //========================================================= + // AR2 Alt Fire Attack + //========================================================= + DEFINE_SCHEDULE + ( + SCHED_METROPOLICE_AR2_ALTFIRE, + + " Tasks" + " TASK_STOP_MOVING 0" + " TASK_ANNOUNCE_ATTACK 1" + " TASK_METROPOLICE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET ACTIVITY:ACT_COMBINE_AR2_ALTFIRE" + "" + " Interrupts" + " COND_TOO_CLOSE_TO_ATTACK" + ) #endif AI_END_CUSTOM_NPC() diff --git a/sp/src/game/server/hl2/npc_metropolice.h b/sp/src/game/server/hl2/npc_metropolice.h index 6d3f065d..c9d02fee 100644 --- a/sp/src/game/server/hl2/npc_metropolice.h +++ b/sp/src/game/server/hl2/npc_metropolice.h @@ -66,6 +66,9 @@ public: virtual void OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior ); const char* GetGrenadeAttachment() { return "LHand"; } + + virtual bool IsAltFireCapable() { return (m_iGrenadeCapabilities & GRENCAP_ALTFIRE) != 0; } + virtual bool IsGrenadeCapable() { return (m_iGrenadeCapabilities & GRENCAP_GRENADE) != 0; } #endif Vector EyeDirection3D( void ) { return CAI_BaseHumanoid::EyeDirection3D(); } // cops don't have eyes @@ -242,6 +245,21 @@ private: int SelectAirboatCombatSchedule(); int SelectAirboatRangeAttackSchedule(); +#ifdef MAPBASE + int SelectBehaviorOverrideSchedule(); + + bool IsCrouchedActivity( Activity activity ); + + // This is something Valve did with Combine soldiers so they would throw grenades during standoffs. + // We're using a similar thing here so metrocops deploy manhacks. + class CMetroPoliceStandoffBehavior : public CAI_ComponentWithOuter + { + typedef CAI_ComponentWithOuter BaseClass; + + virtual int SelectScheduleAttack(); + }; +#endif + // Handle flinching bool IsHeavyDamage( const CTakeDamageInfo &info ); @@ -405,6 +423,7 @@ private: SCHED_METROPOLICE_FORCED_GRENADE_THROW, SCHED_METROPOLICE_MOVE_TO_FORCED_GREN_LOS, SCHED_METROPOLICE_RANGE_ATTACK2, + SCHED_METROPOLICE_AR2_ALTFIRE, #endif }; @@ -436,6 +455,7 @@ private: TASK_METROPOLICE_GET_PATH_TO_FORCED_GREN_LOS, TASK_METROPOLICE_DEFER_SQUAD_GRENADES, TASK_METROPOLICE_FACE_TOSS_DIR, + TASK_METROPOLICE_PLAY_SEQUENCE_FACE_ALTFIRE_TARGET, #endif }; @@ -494,13 +514,20 @@ private: #ifdef MAPBASE COutputEHANDLE m_OnHitByPhysicsObject; COutputEHANDLE m_OutManhack; + + // Determines whether this NPC is allowed to use grenades or alt-fire stuff. + eGrenadeCapabilities m_iGrenadeCapabilities; #endif AIHANDLE m_hManhack; CHandle m_hBlockingProp; CAI_ActBusyBehavior m_ActBusyBehavior; +#ifdef MAPBASE + CMetroPoliceStandoffBehavior m_StandoffBehavior; +#else CAI_StandoffBehavior m_StandoffBehavior; +#endif CAI_AssaultBehavior m_AssaultBehavior; CAI_FuncTankBehavior m_FuncTankBehavior; CAI_RappelBehavior m_RappelBehavior; diff --git a/sp/src/game/server/hl2/npc_playercompanion.h b/sp/src/game/server/hl2/npc_playercompanion.h index 150eaec0..81ba080c 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.h +++ b/sp/src/game/server/hl2/npc_playercompanion.h @@ -342,12 +342,6 @@ public: private: - enum eGrenadeCapabilities - { - GRENCAP_GRENADE = (1 << 0), - GRENCAP_ALTFIRE = (1 << 1), - }; - // Determines whether this NPC is allowed to use grenades or alt-fire stuff. eGrenadeCapabilities m_iGrenadeCapabilities; #endif diff --git a/sp/src/game/server/hl2/npc_strider.cpp b/sp/src/game/server/hl2/npc_strider.cpp index 4d762783..de59feca 100644 --- a/sp/src/game/server/hl2/npc_strider.cpp +++ b/sp/src/game/server/hl2/npc_strider.cpp @@ -442,6 +442,11 @@ CNPC_Strider::CNPC_Strider() //--------------------------------------------------------- CNPC_Strider::~CNPC_Strider() { +#ifdef MAPBASE + if (m_hFocus) + UTIL_Remove( m_hFocus ); +#endif + delete m_pMinigun; } diff --git a/sp/src/game/server/hl2/npc_turret_ceiling.cpp b/sp/src/game/server/hl2/npc_turret_ceiling.cpp index 6151db75..bc4f6821 100644 --- a/sp/src/game/server/hl2/npc_turret_ceiling.cpp +++ b/sp/src/game/server/hl2/npc_turret_ceiling.cpp @@ -176,6 +176,8 @@ protected: virtual const char *GetDieSound() { return "NPC_CeilingTurret.Die"; } virtual float GetFireRate(bool bFightingPlayer = false) { return bFightingPlayer ? 0.5f : 0.1f; } + + virtual void SetIdleGoalAngles() { m_vecGoalAngles = GetAbsAngles(); } #endif #ifdef MAPBASE @@ -629,15 +631,6 @@ bool CNPC_CeilingTurret::UpdateFacing( void ) NDebugOverlay::Cross3D( vecMuzzle, -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMuzzle+(vecGoalDir*256), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 0.05 ); NDebugOverlay::Line( vecMuzzle, vecMuzzle+(vecGoalDir*256), 255, 0, 0, false, 0.05 ); - -#ifdef MAPBASE - NDebugOverlay::Cross3D( vecMuzzle, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); - NDebugOverlay::Cross3D( vecMuzzle+(vecGoalLocalDir*256), -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); - NDebugOverlay::Line( vecMuzzle, vecMuzzle+(vecGoalLocalDir*256), 0, 255, 0, false, 0.05 ); - - DevMsg("Pitch: %f, Yaw: %f\n", GetPoseParameter( m_poseAim_Pitch ), GetPoseParameter( m_poseAim_Yaw )); - DevMsg("Goal Angles: [%f, %f, %f]\n", m_vecGoalAngles.x, m_vecGoalAngles.y, m_vecGoalAngles.z); -#endif } QAngle vecGoalLocalAngles; @@ -645,10 +638,6 @@ bool CNPC_CeilingTurret::UpdateFacing( void ) // Update pitch float flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.x, 0.0, 0.1f * MaxYawSpeed() ) ); - -#ifdef MAPBASE - DevMsg("flDiff = %f\n", flDiff); -#endif SetPoseParameter( m_poseAim_Pitch, GetPoseParameter( m_poseAim_Pitch ) + ( flDiff / 1.5f ) ); @@ -657,10 +646,6 @@ bool CNPC_CeilingTurret::UpdateFacing( void ) bMoved = true; } -#ifdef MAPBASE - DevMsg("flDiff Yaw = %f\n\n", flDiff); -#endif - // Update yaw flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.y, 0.0, 0.1f * MaxYawSpeed() ) ); @@ -1313,7 +1298,11 @@ void CNPC_CeilingTurret::DeathThink( void ) return; //Level out our angles +#ifdef MAPBASE + SetIdleGoalAngles(); +#else m_vecGoalAngles = GetAbsAngles(); +#endif SetNextThink( gpGlobals->curtime ); if ( m_lifeState != LIFE_DEAD ) @@ -1429,6 +1418,8 @@ public: const char *GetTracerType( void ) { return "Tracer"; } bool PreThink( turretState_e state ); + void SetIdleGoalAngles(); + void Precache( void ); void Spawn(); Activity NPC_TranslateActivity( Activity activity ); @@ -1527,6 +1518,8 @@ void CNPC_LabTurret::Spawn( void ) { BaseClass::Spawn(); + m_iAmmoType = GetAmmoDef()->Index( "SMG1" ); + if (m_bMirrored) SetActivity((Activity)ACT_CEILING_TURRET_MIRROR_CLOSED_IDLE); @@ -1576,6 +1569,25 @@ bool CNPC_LabTurret::PreThink( turretState_e state ) return BaseClass::PreThink(state); } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CNPC_LabTurret::SetIdleGoalAngles( void ) +{ + m_vecGoalAngles = GetAbsAngles(); + + if (m_bMirrored) + { + //m_vecGoalAngles.x = AngleNormalize( m_vecGoalAngles.x + 90 ); + m_vecGoalAngles.y = AngleNormalize( m_vecGoalAngles.y + 270 ); + } + else + { + //m_vecGoalAngles.x = AngleNormalize( m_vecGoalAngles.x + 270 ); + m_vecGoalAngles.y = AngleNormalize( m_vecGoalAngles.y + 90 ); + } +} + //----------------------------------------------------------------------------- // Purpose: // Input : height - @@ -1654,10 +1666,6 @@ bool CNPC_LabTurret::UpdateFacing( void ) // Update yaw float flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.y, 0.0, 0.1f * MaxYawSpeed() ) ); -#ifdef MAPBASE - DevMsg("Arm Yaw = %f, Diff: %f\n", GetPoseParameter( m_poseMove_Yaw ), flDiff); -#endif - SetPoseParameter( m_poseMove_Yaw, GetPoseParameter( m_poseMove_Yaw ) + ( flDiff / 1.5f ) * 0.5f ); // Recalculate muzzle diff --git a/sp/src/game/server/hl2/script_intro.cpp b/sp/src/game/server/hl2/script_intro.cpp index 7b15d136..d992496e 100644 --- a/sp/src/game/server/hl2/script_intro.cpp +++ b/sp/src/game/server/hl2/script_intro.cpp @@ -581,7 +581,7 @@ const QAngle &CPlayerViewProxy::EyeAngles( void ) float fldummy; m_hPlayer->CalcView( vecOrigin, angAngles, fldummy, fldummy, fldummy ); - return angAngles; + return GetAbsAngles() + (angAngles - m_hPlayer->GetAbsAngles()); //return m_hPlayer.Get()->EyeAngles(); } @@ -595,7 +595,7 @@ const QAngle &CPlayerViewProxy::EyeAngles( void ) const QAngle &CPlayerViewProxy::LocalEyeAngles( void ) { if (m_hPlayer.Get()) - return m_hPlayer.Get()->LocalEyeAngles(); + return GetAbsAngles() + (m_hPlayer->LocalEyeAngles() - m_hPlayer->GetAbsAngles()); else return BaseClass::LocalEyeAngles(); } diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index acba33c5..3fa3fab8 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -182,7 +182,7 @@ void CWeapon357::FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, Vector & CSoundEnt::InsertSound( SOUND_COMBAT|SOUND_CONTEXT_GUNFIRE, pOperator->GetAbsOrigin(), SOUNDENT_VOLUME_PISTOL, 0.2, pOperator, SOUNDENT_CHANNEL_WEAPON, pOperator->GetEnemy() ); WeaponSound( SINGLE_NPC ); - pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 ); + pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 1 ); pOperator->DoMuzzleFlash(); m_iClip1 = m_iClip1 - 1; } diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index b53b47b7..3ae41e28 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -44,7 +44,8 @@ static ConVar sk_apc_missile_damage("sk_apc_missile_damage", "15"); ConVar rpg_missle_use_custom_detonators( "rpg_missle_use_custom_detonators", "1" ); #ifdef MAPBASE -ConVar weapon_rpg_use_old_behavior("weapon_rpg_use_old_behavior", "0"); +ConVar weapon_rpg_use_old_behavior( "weapon_rpg_use_old_behavior", "0" ); +ConVar weapon_rpg_fire_rate( "weapon_rpg_fire_rate", "4.0" ); #endif #define APC_MISSILE_DAMAGE sk_apc_missile_damage.GetFloat() diff --git a/sp/src/game/server/hl2/weapon_rpg.h b/sp/src/game/server/hl2/weapon_rpg.h index aceb8a35..3c9dae5f 100644 --- a/sp/src/game/server/hl2/weapon_rpg.h +++ b/sp/src/game/server/hl2/weapon_rpg.h @@ -165,6 +165,9 @@ private: //----------------------------------------------------------------------------- CAPCMissile *FindAPCMissileInCone( const Vector &vecOrigin, const Vector &vecDirection, float flAngle ); +#ifdef MAPBASE +extern ConVar weapon_rpg_fire_rate; +#endif //----------------------------------------------------------------------------- // RPG @@ -182,7 +185,11 @@ public: void Precache( void ); void PrimaryAttack( void ); +#ifdef MAPBASE + virtual float GetFireRate( void ) { return weapon_rpg_fire_rate.GetFloat(); }; +#else virtual float GetFireRate( void ) { return 1; }; +#endif void ItemPostFrame( void ); void Activate( void ); diff --git a/sp/src/game/server/mapbase/SystemConvarMod.cpp b/sp/src/game/server/mapbase/SystemConvarMod.cpp index 7b0c52e1..9bd72188 100644 --- a/sp/src/game/server/mapbase/SystemConvarMod.cpp +++ b/sp/src/game/server/mapbase/SystemConvarMod.cpp @@ -10,6 +10,8 @@ #include "SystemConvarMod.h" +ConVar g_debug_convarmod( "g_debug_convarmod", "0" ); + BEGIN_SIMPLE_DATADESC( modifiedconvars_t ) DEFINE_ARRAY( pszConvar, FIELD_CHARACTER, MAX_MODIFIED_CONVAR_STRING ), DEFINE_ARRAY( pszCurrentValue, FIELD_CHARACTER, MAX_MODIFIED_CONVAR_STRING ), @@ -121,6 +123,11 @@ void CVEnt_Activate(CMapbaseCVarModEntity *modent) pszCommands = szTmp; } + CV_InitMod(); + + if (m_ModEntities.Find(modent) == m_ModEntities.InvalidIndex()) + m_ModEntities.AddToTail( modent ); + if (modent->m_bUseServer) { SetChangingCVars( modent ); @@ -160,6 +167,8 @@ void CVEnt_Deactivate(CMapbaseCVarModEntity *modent) } } + modent->m_ModifiedConvars.Purge(); + if (m_bModActive) { m_ModEntities.FindAndRemove(modent); @@ -198,6 +207,8 @@ BEGIN_DATADESC( CMapbaseCVarModEntity ) DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ), DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ), + DEFINE_THINKFUNC( CvarModActivate ), + END_DATADESC() @@ -230,10 +241,21 @@ void CMapbaseCVarModEntity::Spawn( void ) if (HasSpawnFlags(SF_CVARMOD_START_ACTIVATED)) { - CVEnt_Activate(this); + if (!m_bUseServer && !UTIL_GetLocalPlayer()) + { + // The local player doesn't exist yet, so we should wait until they do + SetContextThink( &CMapbaseCVarModEntity::CvarModActivate, gpGlobals->curtime, NULL ); + } + else + CVEnt_Activate(this); } } +void CMapbaseCVarModEntity::CvarModActivate() +{ + CVEnt_Activate(this); +} + void CMapbaseCVarModEntity::OnRestore( void ) { BaseClass::OnRestore(); @@ -246,7 +268,8 @@ void CMapbaseCVarModEntity::OnRestore( void ) ConVar *pConVar = (ConVar *)cvar->FindVar( m_ModifiedConvars[i].pszConvar ); if ( pConVar ) { - //Msg(" %s Restoring Convar %s: value %s (org %s)\n", GetDebugName(), m_ModifiedConvars[i].pszConvar, m_ModifiedConvars[i].pszCurrentValue, m_ModifiedConvars[i].pszOrgValue ); + if (g_debug_convarmod.GetBool()) + Msg(" %s Restoring Convar %s: value %s (org %s)\n", GetDebugName(), m_ModifiedConvars[i].pszConvar, m_ModifiedConvars[i].pszCurrentValue, m_ModifiedConvars[i].pszOrgValue ); pConVar->SetValue( m_ModifiedConvars[i].pszCurrentValue ); } } @@ -276,14 +299,16 @@ bool CMapbaseCVarModEntity::NewCVar( ConVarRef *var, const char *pOldString, CBa if (modent == this) { Q_strncpy( modvar.pszCurrentValue, var->GetString(), MAX_MODIFIED_CONVAR_STRING ); - //Msg(" %s Updating Convar %s: value %s (org %s)\n", GetDebugName(), modvar.pszConvar, modvar.pszCurrentValue, modvar.pszOrgValue ); + if (g_debug_convarmod.GetBool()) + Msg(" %s Updating Convar %s: value %s (org %s)\n", GetDebugName(), modvar.pszConvar, modvar.pszCurrentValue, modvar.pszOrgValue ); return true; } else { // A different entity is using this CVar now, remove ours m_ModifiedConvars.Remove(i); - //Msg(" %s Removing Convar %s: value %s (org %s)\n", GetDebugName(), modvar.pszConvar, modvar.pszCurrentValue, modvar.pszOrgValue ); + if (g_debug_convarmod.GetBool()) + Msg(" %s Removing Convar %s: value %s (org %s)\n", GetDebugName(), modvar.pszConvar, modvar.pszCurrentValue, modvar.pszOrgValue ); return false; } } @@ -299,14 +324,15 @@ bool CMapbaseCVarModEntity::NewCVar( ConVarRef *var, const char *pOldString, CBa Q_strncpy( newConvar.pszOrgValue, pOldString, MAX_MODIFIED_CONVAR_STRING ); m_ModifiedConvars.AddToTail( newConvar ); - /* - Msg(" %s changed '%s' to '%s' (was '%s')\n", GetDebugName(), var->GetName(), var->GetString(), pOldString ); - Msg(" Convars stored: %d\n", m_ModifiedConvars.Count() ); - for ( int i = 0; i < m_ModifiedConvars.Count(); i++ ) + if (g_debug_convarmod.GetBool()) { - Msg(" Convar %d: %s, value %s (org %s)\n", i, m_ModifiedConvars[i].pszConvar, m_ModifiedConvars[i].pszCurrentValue, m_ModifiedConvars[i].pszOrgValue ); + Msg(" %s changed '%s' to '%s' (was '%s')\n", GetDebugName(), var->GetName(), var->GetString(), pOldString ); + Msg(" Convars stored: %d\n", m_ModifiedConvars.Count() ); + for ( int i = 0; i < m_ModifiedConvars.Count(); i++ ) + { + Msg(" Convar %d: %s, value %s (org %s)\n", i, m_ModifiedConvars[i].pszConvar, m_ModifiedConvars[i].pszCurrentValue, m_ModifiedConvars[i].pszOrgValue ); + } } - */ return true; } diff --git a/sp/src/game/server/mapbase/SystemConvarMod.h b/sp/src/game/server/mapbase/SystemConvarMod.h index 10c583da..b20707a4 100644 --- a/sp/src/game/server/mapbase/SystemConvarMod.h +++ b/sp/src/game/server/mapbase/SystemConvarMod.h @@ -33,6 +33,7 @@ public: void Precache( void ); void Spawn( void ); + void CvarModActivate(); void OnRestore( void ); diff --git a/sp/src/game/server/mapbase/ai_grenade.h b/sp/src/game/server/mapbase/ai_grenade.h index 887fef1f..398ba405 100644 --- a/sp/src/game/server/mapbase/ai_grenade.h +++ b/sp/src/game/server/mapbase/ai_grenade.h @@ -61,6 +61,12 @@ extern int COMBINE_AE_BEGIN_ALTFIRE; extern int COMBINE_AE_ALTFIRE; +enum eGrenadeCapabilities +{ + GRENCAP_GRENADE = (1 << 0), + GRENCAP_ALTFIRE = (1 << 1), +}; + //----------------------------------------------------------------------------- // Other classes can use this and access some CAI_GrenadeUser functions. //----------------------------------------------------------------------------- @@ -156,7 +162,9 @@ void CAI_GrenadeUser::HandleAnimEvent( animevent_t *pEvent ) { if ( pEvent->event == COMBINE_AE_BEGIN_ALTFIRE ) { - EmitSound( "Weapon_CombineGuard.Special1" ); + if (GetActiveWeapon()) + GetActiveWeapon()->WeaponSound( SPECIAL1 ); + //SpeakIfAllowed( TLK_CMB_THROWGRENADE, "altfire:1" ); return; } @@ -166,7 +174,10 @@ void CAI_GrenadeUser::HandleAnimEvent( animevent_t *pEvent ) fakeEvent.pSource = this; fakeEvent.event = EVENT_WEAPON_AR2_ALTFIRE; - GetActiveWeapon()->Operator_HandleAnimEvent( &fakeEvent, this ); + + // Weapon could've been dropped while playing animation + if (GetActiveWeapon()) + GetActiveWeapon()->Operator_HandleAnimEvent( &fakeEvent, this ); // Stop other squad members from combine balling for a while. DelaySquadAltFireAttack( 10.0f ); diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 9f78a595..af5ef0cb 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -195,6 +195,10 @@ ConVar sv_player_display_usercommand_errors( "sv_player_display_usercommand_err ConVar player_debug_print_damage( "player_debug_print_damage", "0", FCVAR_CHEAT, "When true, print amount and type of all damage received by player to console." ); +#ifdef MAPBASE +ConVar player_use_visibility_cache( "player_use_visibility_cache", "0", FCVAR_NONE, "Allows the player to use the visibility cache." ); +#endif + void CC_GiveCurrentAmmo( void ) { @@ -5749,6 +5753,25 @@ CBaseEntity *CBasePlayer::GiveNamedItem( const char *pszName, int iSubType ) DispatchSpawn( pent ); +#ifdef MAPBASE + if ( pWeapon ) + { + for (int i=0;iGetSlot() == pWeapon->GetSlot() && m_hMyWeapons[i]->GetPosition() == pWeapon->GetPosition() ) + { + // Make sure it matches the subtype + if ( m_hMyWeapons[i]->GetSubType() == iSubType ) + { + // Don't use this weapon if the slot is already occupied + UTIL_Remove( pWeapon ); + return NULL; + } + } + } + } +#endif + if ( pent != NULL && !(pent->IsMarkedForDeletion()) ) { pent->Touch( this ); @@ -7651,6 +7674,23 @@ void CBasePlayer::PlayWearableAnimsForPlaybackEvent( wearableanimplayback_t iPla } #endif // USES_ECON_ITEMS +#ifdef MAPBASE +bool CBasePlayer::ShouldUseVisibilityCache( CBaseEntity *pEntity ) +{ + // In CBaseEntity::FVisible(), players are allowed to see through CONTENTS_BLOCKLOS, which is used for + // nodraw, block LOS brushes, etc. This is so some code doesn't erronesouly assume the player can't see + // an entity (when the player can, in fact, see it) and therefore do something the player is not supposed to see. + // + // However, to reduce the number of traces FVisible() runs, CBaseCombatCharacter uses a "visibility cache" shared + // by all entities derived from it. The player is normally a part of this visibility cache, so when it runs a trace + // through a CONTENTS_BLOCKLOS surface, the visibility cache assumes entities can now see through it and therefore + // NPCs to see through the brush which should normally block their LOS. + // + // This solution stops the player from using the visibility cache altogether, toggled by a convar. + return player_use_visibility_cache.GetBool(); +} +#endif + //================================================================================ // TEAM HANDLING //================================================================================ diff --git a/sp/src/game/server/player.h b/sp/src/game/server/player.h index 7d487747..1e547fea 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -627,6 +627,10 @@ public: void PlayWearableAnimsForPlaybackEvent( wearableanimplayback_t iPlayback ); #endif +#ifdef MAPBASE + bool ShouldUseVisibilityCache( CBaseEntity *pEntity ); +#endif + public: // Player Physics Shadow void SetupVPhysicsShadow( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity, CPhysCollide *pStandModel, const char *pStandHullName, CPhysCollide *pCrouchModel, const char *pCrouchHullName ); diff --git a/sp/src/game/server/scripted.cpp b/sp/src/game/server/scripted.cpp index 31d7cb57..081998aa 100644 --- a/sp/src/game/server/scripted.cpp +++ b/sp/src/game/server/scripted.cpp @@ -2424,8 +2424,11 @@ void CScriptedSound::InputPlaySound( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CScriptedSound::InputPlaySoundOnEntity( inputdata_t &inputdata ) { - inputdata.value.Entity()->PrecacheScriptSound(STRING(m_message)); - inputdata.value.Entity()->EmitSound(STRING(m_message)); + if (inputdata.value.Entity()) + { + inputdata.value.Entity()->PrecacheScriptSound(STRING(m_message)); + inputdata.value.Entity()->EmitSound(STRING(m_message)); + } } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/sound.cpp b/sp/src/game/server/sound.cpp index 19db8076..cb7df905 100644 --- a/sp/src/game/server/sound.cpp +++ b/sp/src/game/server/sound.cpp @@ -173,6 +173,9 @@ public: void ToggleSound(); void SendSound( SoundFlags_t flags ); +#ifdef MAPBASE + void SoundEnd(); +#endif // Input handlers void InputPlaySound( inputdata_t &inputdata ); @@ -203,6 +206,8 @@ public: #ifdef MAPBASE int m_iSoundFlags; + + COutputEvent m_OnSoundFinished; #endif }; @@ -235,6 +240,9 @@ BEGIN_DATADESC( CAmbientGeneric ) // Function Pointers DEFINE_FUNCTION( RampThink ), +#ifdef MAPBASE + DEFINE_THINKFUNC( SoundEnd ), +#endif // Inputs DEFINE_INPUTFUNC(FIELD_VOID, "PlaySound", InputPlaySound ), @@ -246,6 +254,8 @@ BEGIN_DATADESC( CAmbientGeneric ) DEFINE_INPUTFUNC(FIELD_FLOAT, "FadeOut", InputFadeOut ), #ifdef MAPBASE DEFINE_INPUTFUNC(FIELD_STRING, "SetSound", InputSetSound ), + + DEFINE_OUTPUT( m_OnSoundFinished, "OnSoundFinished" ), #endif END_DATADESC() @@ -255,6 +265,10 @@ END_DATADESC() #define SF_AMBIENT_SOUND_START_SILENT 16 #define SF_AMBIENT_SOUND_NOT_LOOPING 32 +#ifdef MAPBASE +static const char *g_SoundEndContext = "SoundEnd"; +#endif + //----------------------------------------------------------------------------- // Spawn @@ -933,12 +947,17 @@ void CAmbientGeneric::SendSound( SoundFlags_t flags) UTIL_EmitAmbientSound(pSoundSource->GetSoundSourceIndex(), pSoundSource->GetAbsOrigin(), szSoundFile, 0, SNDLVL_NONE, iFlags, 0); + SetContextThink( NULL, TICK_NEVER_THINK, g_SoundEndContext ); + m_fActive = false; } else { + float duration = 0.0f; UTIL_EmitAmbientSound(pSoundSource->GetSoundSourceIndex(), pSoundSource->GetAbsOrigin(), szSoundFile, - (m_dpv.vol * 0.01), m_iSoundLevel, iFlags, m_dpv.pitch); + (m_dpv.vol * 0.01), m_iSoundLevel, iFlags, m_dpv.pitch, 0.0f, &duration); + + SetContextThink( &CAmbientGeneric::SoundEnd, gpGlobals->curtime + duration, g_SoundEndContext ); // Only mark active if this is a looping sound. If not looping, each // trigger will cause the sound to play. If the sound is still @@ -957,6 +976,8 @@ void CAmbientGeneric::SendSound( SoundFlags_t flags) UTIL_EmitAmbientSound(m_nSoundSourceEntIndex, GetAbsOrigin(), szSoundFile, 0, SNDLVL_NONE, iFlags, 0); + SetContextThink( NULL, TICK_NEVER_THINK, g_SoundEndContext ); + m_fActive = false; } } @@ -988,6 +1009,13 @@ void CAmbientGeneric::SendSound( SoundFlags_t flags) #endif } +#ifdef MAPBASE +void CAmbientGeneric::SoundEnd() +{ + m_OnSoundFinished.FireOutput(this, this); +} +#endif + //----------------------------------------------------------------------------- // Purpose: Input handler that stops playing the sound. diff --git a/sp/src/game/server/triggers.cpp b/sp/src/game/server/triggers.cpp index ca3c921b..c6722384 100644 --- a/sp/src/game/server/triggers.cpp +++ b/sp/src/game/server/triggers.cpp @@ -1036,7 +1036,11 @@ class CTriggerLook : public CTriggerOnce DECLARE_CLASS( CTriggerLook, CTriggerOnce ); public: +#ifdef MAPBASE + CUtlVector m_hLookTargets; +#else EHANDLE m_hLookTarget; +#endif float m_flFieldOfView; float m_flLookTime; // How long must I look for float m_flLookTimeTotal; // How long have I looked @@ -1046,6 +1050,7 @@ public: EHANDLE m_hActivator; // The entity that triggered us. #ifdef MAPBASE bool m_bUseLOS; // Makes lookers use LOS calculations in addition to viewcone calculations + bool m_bUseLookEntityAsCaller; // Fires OnTrigger with the seen entity #endif void Spawn( void ); @@ -1058,7 +1063,11 @@ public: private: +#ifdef MAPBASE + void Trigger(CBaseEntity *pActivator, bool bTimeout, CBaseEntity *pCaller = NULL); +#else void Trigger(CBaseEntity *pActivator, bool bTimeout); +#endif void TimeoutThink(); COutputEvent m_OnTimeout; @@ -1067,7 +1076,11 @@ private: LINK_ENTITY_TO_CLASS( trigger_look, CTriggerLook ); BEGIN_DATADESC( CTriggerLook ) +#ifdef MAPBASE + DEFINE_UTLVECTOR( m_hLookTargets, FIELD_EHANDLE ), +#else DEFINE_FIELD( m_hLookTarget, FIELD_EHANDLE ), +#endif DEFINE_FIELD( m_flLookTimeTotal, FIELD_FLOAT ), DEFINE_FIELD( m_flLookTimeLast, FIELD_TIME ), DEFINE_KEYFIELD( m_flTimeoutDuration, FIELD_FLOAT, "timeout" ), @@ -1075,6 +1088,7 @@ BEGIN_DATADESC( CTriggerLook ) DEFINE_FIELD( m_hActivator, FIELD_EHANDLE ), #ifdef MAPBASE DEFINE_KEYFIELD( m_bUseLOS, FIELD_BOOLEAN, "UseLOS" ), + DEFINE_KEYFIELD( m_bUseLookEntityAsCaller, FIELD_BOOLEAN, "LookEntityCaller" ), #endif DEFINE_OUTPUT( m_OnTimeout, "OnTimeout" ), @@ -1093,7 +1107,9 @@ END_DATADESC() //------------------------------------------------------------------------------ void CTriggerLook::Spawn( void ) { +#ifndef MAPBASE m_hLookTarget = NULL; +#endif m_flLookTimeTotal = -1; m_bTimeoutFired = false; @@ -1158,6 +1174,17 @@ void CTriggerLook::Touch(CBaseEntity *pOther) // -------------------------------- // Make sure we have a look target // -------------------------------- +#ifdef MAPBASE + if (m_hLookTargets.Count() <= 0) + { + CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, m_target, this, m_hActivator, this ); + while (pEntity) + { + m_hLookTargets.AddToTail(pEntity); + pEntity = gEntList.FindEntityByName( pEntity, m_target, this, m_hActivator, this ); + } + } +#else if (m_hLookTarget == NULL) { m_hLookTarget = GetNextTarget(); @@ -1166,6 +1193,7 @@ void CTriggerLook::Touch(CBaseEntity *pOther) return; } } +#endif // This is designed for single player only // so we'll always have the same player @@ -1194,15 +1222,52 @@ void CTriggerLook::Touch(CBaseEntity *pOther) vLookDir = ((CBaseCombatCharacter*)pOther)->EyeDirection3D( ); } +#ifdef MAPBASE + // Check if the player is looking at any of the entities, even if they turn to look at another entity candidate. + // This is how we're doing support for multiple entities without redesigning trigger_look. + EHANDLE hLookingAtEntity = NULL; + for (int i = 0; i < m_hLookTargets.Count(); i++) + { + Vector vTargetDir = m_hLookTargets[i]->GetAbsOrigin() - pOther->EyePosition(); + VectorNormalize(vTargetDir); + + float fDotPr = DotProduct(vLookDir,vTargetDir); + if (fDotPr > m_flFieldOfView && (!m_bUseLOS || pOther->FVisible(pOther))) + { + hLookingAtEntity = m_hLookTargets[i]; + break; + } + } + + if (hLookingAtEntity != NULL) + { + // Is it the first time I'm looking? + if (m_flLookTimeTotal == -1) + { + m_flLookTimeLast = gpGlobals->curtime; + m_flLookTimeTotal = 0; + } + else + { + m_flLookTimeTotal += gpGlobals->curtime - m_flLookTimeLast; + m_flLookTimeLast = gpGlobals->curtime; + } + + if (m_flLookTimeTotal >= m_flLookTime) + { + Trigger(pOther, false, hLookingAtEntity); + } + } + else + { + m_flLookTimeTotal = -1; + } +#else Vector vTargetDir = m_hLookTarget->GetAbsOrigin() - pOther->EyePosition(); VectorNormalize(vTargetDir); float fDotPr = DotProduct(vLookDir,vTargetDir); -#ifdef MAPBASE - if (fDotPr > m_flFieldOfView && (!m_bUseLOS || pOther->FVisible(pOther))) -#else if (fDotPr > m_flFieldOfView) -#endif { // Is it the first time I'm looking? if (m_flLookTimeTotal == -1) @@ -1225,6 +1290,7 @@ void CTriggerLook::Touch(CBaseEntity *pOther) { m_flLookTimeTotal = -1; } +#endif } } @@ -1232,7 +1298,11 @@ void CTriggerLook::Touch(CBaseEntity *pOther) //----------------------------------------------------------------------------- // Purpose: Called when the trigger is fired by look logic or timeout. //----------------------------------------------------------------------------- +#ifdef MAPBASE +void CTriggerLook::Trigger(CBaseEntity *pActivator, bool bTimeout, CBaseEntity *pCaller) +#else void CTriggerLook::Trigger(CBaseEntity *pActivator, bool bTimeout) +#endif { if (bTimeout) { @@ -1245,7 +1315,11 @@ void CTriggerLook::Trigger(CBaseEntity *pActivator, bool bTimeout) else { // Fire because the player looked at the target. +#ifdef MAPBASE + m_OnTrigger.FireOutput(pActivator, m_bUseLookEntityAsCaller ? pCaller : this); +#else m_OnTrigger.FireOutput(pActivator, this); +#endif m_flLookTimeTotal = -1; // Cancel the timeout think. diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 68805571..9e986cb7 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2304,6 +2304,14 @@ void ActivityList_RegisterSharedActivities( void ) #ifdef SHARED_COMBINE_ACTIVITIES REGISTER_SHARED_ACTIVITY( ACT_COMBINE_THROW_GRENADE ); REGISTER_SHARED_ACTIVITY( ACT_COMBINE_AR2_ALTFIRE ); + + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_ADVANCE ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_FORWARD ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_GROUP ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_HALT ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_LEFT ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_RIGHT ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_TAKECOVER ); #endif #ifdef COMPANION_HOLSTER_WORKAROUND diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index c813b5ae..7a8d2897 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -2176,6 +2176,15 @@ typedef enum #ifdef SHARED_COMBINE_ACTIVITIES ACT_COMBINE_THROW_GRENADE, ACT_COMBINE_AR2_ALTFIRE, + + // New gesture-based signals as activities for people who want to use them + ACT_GESTURE_SIGNAL_ADVANCE, + ACT_GESTURE_SIGNAL_FORWARD, + ACT_GESTURE_SIGNAL_GROUP, + ACT_GESTURE_SIGNAL_HALT, + ACT_GESTURE_SIGNAL_LEFT, + ACT_GESTURE_SIGNAL_RIGHT, + ACT_GESTURE_SIGNAL_TAKECOVER, #endif #ifdef COMPANION_HOLSTER_WORKAROUND diff --git a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp index 4f1dc8d6..1d68b529 100644 --- a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp +++ b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp @@ -285,6 +285,35 @@ void CWeaponStunStick::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseComba CBasePlayer *pPlayer = ToBasePlayer( pHurt ); bool bFlashed = false; + +#ifdef MAPBASE + CNPC_MetroPolice *pCop = dynamic_cast(pOperator); + + if ( pCop != NULL && pPlayer != NULL ) + { + // See if we need to knock out this target + if ( pCop->ShouldKnockOutTarget( pHurt ) ) + { + float yawKick = random->RandomFloat( -48, -24 ); + + //Kick the player angles + pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) ); + + color32 white = {255,255,255,255}; + UTIL_ScreenFade( pPlayer, white, 0.2f, 1.0f, FFADE_OUT|FFADE_PURGE|FFADE_STAYOUT ); + bFlashed = true; + + pCop->KnockOutTarget( pHurt ); + + break; + } + else + { + // Notify that we've stunned a target + pCop->StunnedTarget( pHurt ); + } + } +#endif // Punch angles if ( pPlayer != NULL && !(pPlayer->GetFlags() & FL_GODMODE) ) diff --git a/sp/src/materialsystem/stdshaders/SDK_ShatteredGlass_ps2x.fxc b/sp/src/materialsystem/stdshaders/SDK_ShatteredGlass_ps2x.fxc new file mode 100644 index 00000000..85d55107 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/SDK_ShatteredGlass_ps2x.fxc @@ -0,0 +1,159 @@ +//========== Copyright (c) Valve Corporation, All rights reserved. ==========// + +// STATIC: "CUBEMAP" "0..1" +// STATIC: "VERTEXCOLOR" "0..1" +// STATIC: "ENVMAPMASK" "0..1" +// STATIC: "BASEALPHAENVMAPMASK" "0..1" +// STATIC: "HDRTYPE" "0..2" +// STATIC: "PARALLAXCORRECT" "0..1" + +// DYNAMIC: "PIXELFOGTYPE" "0..1" + +// SKIP: $PARALLAXCORRECT && !$CUBEMAP +// SKIP: $PARALLAXCORRECT [ps20] + +#include "common_ps_fxc.h" + +// HDRFIXME: Need to make this work. + +#define USE_32BIT_LIGHTMAPS_ON_360 //uncomment to use 32bit lightmaps, be sure to keep this in sync with the same #define in materialsystem/cmatlightmaps.cpp + +#include "common_ps_fxc.h" +#include "common_lightmappedgeneric_fxc.h" + +const HALF4 g_EnvmapTint : register( c0 ); +const HALF3 g_DiffuseModulation : register( c1 ); +const HALF3 g_EnvmapContrast : register( c2 ); +const HALF3 g_EnvmapSaturation : register( c3 ); +const HALF4 g_FresnelReflection : register( c4 ); +const HALF3 g_EyePos : register( c5 ); +const HALF3 g_OverbrightFactor : register( c6 ); + +const HALF4 g_FogParams : register( c12 ); + +// Parallax cubemaps +#if (PARALLAXCORRECT) +const float3 cubemapPos : register(c7); +const float4x4 obbMatrix : register(c8); //through c11 +#endif + +// CENTROID: TEXCOORD2 + +sampler BaseTextureSampler : register( s0 ); +sampler LightmapSampler : register( s1 ); +sampler EnvmapSampler : register( s2 ); +sampler DetailSampler : register( s3 ); +sampler EnvmapMaskSampler : register( s5 ); + +sampler NormalizeSampler : register( s6 ); + +struct PS_INPUT +{ + HALF2 baseTexCoord : TEXCOORD0; + HALF2 detailTexCoord : TEXCOORD1; + HALF2 lightmapTexCoord : TEXCOORD2; + HALF2 envmapMaskTexCoord : TEXCOORD3; + HALF4 worldPos_projPosZ : TEXCOORD4; + HALF3 worldSpaceNormal : TEXCOORD5; + HALF4 vertexColor : COLOR; +}; + +float4 main( PS_INPUT i ) : COLOR +{ + bool bCubemap = CUBEMAP ? true : false; + bool bVertexColor = VERTEXCOLOR ? true : false; + bool bEnvmapMask = ENVMAPMASK ? true : false; + bool bBaseAlphaEnvmapMask = BASEALPHAENVMAPMASK ? true : false; + + HALF4 baseColor = tex2D( BaseTextureSampler, i.baseTexCoord ); + HALF4 detailColor = tex2D( DetailSampler, i.detailTexCoord ); + + HALF2 lightmapCoordinates = i.lightmapTexCoord; + HALF3 lightmapColor = LightMapSample( LightmapSampler, lightmapCoordinates ); + + HALF3 specularFactor = 1.0f; + if( bEnvmapMask ) + { + specularFactor = tex2D( EnvmapMaskSampler, i.detailTexCoord ).xyz; + } + + if( bBaseAlphaEnvmapMask ) + { + specularFactor *= 1.0 - baseColor.a; // this blows! + } + + HALF3 diffuseLighting = lightmapColor; + diffuseLighting *= g_DiffuseModulation; + diffuseLighting *= LIGHT_MAP_SCALE; + + HALF3 albedo = baseColor; + HALF alpha = 1.0f; + + if( !bBaseAlphaEnvmapMask ) + { + alpha *= baseColor.a; + } + + albedo *= detailColor; + alpha *= detailColor.a; + + // FIXME: seperate vertexcolor and vertexalpha? + // vertex alpha is ignored if vertexcolor isn't set. . need to check other version. + if( bVertexColor ) + { + albedo *= i.vertexColor; + alpha *= i.vertexColor.a; // not sure about this one + } + + HALF3 specularLighting = HALF3( 0.0f, 0.0f, 0.0f ); + if( bCubemap ) + { + float3 worldVertToEyeVector = g_EyePos - i.worldPos_projPosZ.xyz; + worldVertToEyeVector = NormalizeWithCubemap( NormalizeSampler, worldVertToEyeVector ); + HALF3 reflectVect = CalcReflectionVectorUnnormalized( i.worldSpaceNormal, worldVertToEyeVector ); + + // Calc Fresnel factor + HALF3 worldSpaceNormal = NormalizeWithCubemap( NormalizeSampler, i.worldSpaceNormal ); + HALF fresnel = 1.0 - dot( worldSpaceNormal, worldVertToEyeVector ); + fresnel = pow( fresnel, 5.0 ); + fresnel = fresnel * g_FresnelReflection.b + g_FresnelReflection.a; + + //Parallax correction (2_0b and beyond) + //Adapted from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ +#if !(defined(SHADER_MODEL_PS_1_1) || defined(SHADER_MODEL_PS_1_4) || defined(SHADER_MODEL_PS_2_0)) +#if (PARALLAXCORRECT) + float3 worldPos = i.worldPos_projPosZ.xyz; + float3 positionLS = mul(float4(worldPos, 1), obbMatrix); + float3 rayLS = mul(reflectVect, (float3x3) obbMatrix); + + float3 firstPlaneIntersect = (float3(1.0f, 1.0f, 1.0f) - positionLS) / rayLS; + float3 secondPlaneIntersect = (-positionLS) / rayLS; + float3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect); + float distance = min(furthestPlane.x, min(furthestPlane.y, furthestPlane.z)); + + // Use distance in WS directly to recover intersection + float3 intersectPositionWS = worldPos + reflectVect * distance; + reflectVect = intersectPositionWS - cubemapPos; +#endif +#endif + + specularLighting = texCUBE( EnvmapSampler, reflectVect ); + specularLighting *= specularFactor; + + specularLighting *= g_EnvmapTint; +#if HDRTYPE == HDR_TYPE_NONE + HALF3 specularLightingSquared = specularLighting * specularLighting; + specularLighting = lerp( specularLighting, specularLightingSquared, g_EnvmapContrast ); + HALF3 greyScale = dot( specularLighting, HALF3( 0.299f, 0.587f, 0.114f ) ); + specularLighting = lerp( greyScale, specularLighting, g_EnvmapSaturation ); +#endif + specularLighting *= fresnel; + } + + // Do it somewhat unlit + HALF3 result = albedo*(g_OverbrightFactor.z*diffuseLighting + g_OverbrightFactor.y) + specularLighting; + + float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos.xyz, i.worldPos_projPosZ.xyz, i.worldPos_projPosZ.w ); + return FinalOutput( HALF4( result, alpha ), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR ); +} + diff --git a/sp/src/materialsystem/stdshaders/SDK_ShatteredGlass_vs20.fxc b/sp/src/materialsystem/stdshaders/SDK_ShatteredGlass_vs20.fxc new file mode 100644 index 00000000..fec0b49f --- /dev/null +++ b/sp/src/materialsystem/stdshaders/SDK_ShatteredGlass_vs20.fxc @@ -0,0 +1,67 @@ +// STATIC: "ENVMAP_MASK" "0..1" + +// DYNAMIC: "DOWATERFOG" "0..1" +#include "common_vs_fxc.h" + +static const int g_FogType = DOWATERFOG; +static const bool g_UseSeparateEnvmapMask = ENVMAP_MASK; + +const float4 cBaseTexCoordTransform[2] : register( SHADER_SPECIFIC_CONST_0 ); +const float4 cDetailTexCoordTransform[2] : register( SHADER_SPECIFIC_CONST_2 ); + +struct VS_INPUT +{ + float3 vPos : POSITION; + float4 vNormal : NORMAL; + float2 vBaseTexCoord : TEXCOORD0; + float2 vLightmapTexCoord : TEXCOORD1; + float2 vDetailTexCoord : TEXCOORD2; +}; + +struct VS_OUTPUT +{ + float4 projPos : POSITION; +#if !defined( _X360 ) && !defined( SHADER_MODEL_VS_3_0 ) + float fog : FOG; +#endif + float2 baseTexCoord : TEXCOORD0; + float2 detailTexCoord : TEXCOORD1; + float2 lightmapTexCoord : TEXCOORD2; + float2 envmapMaskTexCoord : TEXCOORD3; + float4 worldPos_projPosZ : TEXCOORD4; + float3 worldNormal : TEXCOORD5; + float4 vertexColor : COLOR; +}; + +VS_OUTPUT main( const VS_INPUT v ) +{ + VS_OUTPUT o = ( VS_OUTPUT )0; + + float3 vObjNormal; + DecompressVertex_Normal( v.vNormal, vObjNormal ); + + float4 projPos; + projPos = mul( float4( v.vPos, 1 ), cModelViewProj ); + o.projPos = projPos; + + o.worldPos_projPosZ.w = projPos.z; + o.worldPos_projPosZ.xyz = mul( float4( v.vPos, 1 ), cModel[0] ); + o.worldNormal = mul( vObjNormal, ( float3x3 )cModel[0] ); + o.baseTexCoord.x = dot( v.vBaseTexCoord, cBaseTexCoordTransform[0] ) + cBaseTexCoordTransform[0].w; + o.baseTexCoord.y = dot( v.vBaseTexCoord, cBaseTexCoordTransform[1] ) + cBaseTexCoordTransform[1].w; + o.detailTexCoord.x = dot( v.vDetailTexCoord, cDetailTexCoordTransform[0] ) + cDetailTexCoordTransform[0].w; + o.detailTexCoord.y = dot( v.vDetailTexCoord, cDetailTexCoordTransform[1] ) + cDetailTexCoordTransform[1].w; + o.envmapMaskTexCoord.x = dot( v.vDetailTexCoord, cDetailTexCoordTransform[0] ) + cDetailTexCoordTransform[0].w; + o.envmapMaskTexCoord.y = dot( v.vDetailTexCoord, cDetailTexCoordTransform[1] ) + cDetailTexCoordTransform[1].w; + o.lightmapTexCoord = v.vLightmapTexCoord; + +#if !defined( _X360 ) && !defined( SHADER_MODEL_VS_3_0 ) + o.fog = CalcFixedFunctionFog( o.worldPos_projPosZ.xyz, g_FogType ); +#endif + + o.vertexColor = cModulationColor; + + return o; +} + + diff --git a/sp/src/materialsystem/stdshaders/common_flashlight_fxc.h b/sp/src/materialsystem/stdshaders/common_flashlight_fxc.h index 6f56f966..c14f6c03 100644 --- a/sp/src/materialsystem/stdshaders/common_flashlight_fxc.h +++ b/sp/src/materialsystem/stdshaders/common_flashlight_fxc.h @@ -629,7 +629,7 @@ float DoFlashlightShadow( sampler DepthSampler, sampler RandomRotationSampler, f if( nShadowLevel == NVIDIA_PCF_POISSON ) #if defined( NEW_SHADOW_FILTERS ) && defined( SHADER_MODEL_PS_3_0 ) // Let's replace noise filter with gaussian blur, like in Portal 2. - flShadow = DoShadowNvidiaPCF5x5Gaussian( DepthSampler, vProjCoords, float2( 1.0 / 2048.0, 1.0 / 2048.0 ) ); + flShadow = DoShadowNvidiaPCF5x5Gaussian( DepthSampler, vProjCoords, float2( vShadowTweaks.x, vShadowTweaks.x ) ); #else flShadow = DoShadowPoisson16Sample( DepthSampler, RandomRotationSampler, vProjCoords, vScreenPos, vShadowTweaks, true, false ); #endif diff --git a/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc b/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc index fc9b4378..36477749 100644 --- a/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc +++ b/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc @@ -59,6 +59,7 @@ $Project $File "unlittwotexture_dx9.cpp" $File "MonitorScreen_dx9.cpp" + $File "shatteredglass.cpp" } //$Shaders "mapbase_dx9_20b.txt" diff --git a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.h b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.h index 9f5d26f6..1b79ca18 100644 --- a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.h +++ b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.h @@ -96,7 +96,7 @@ struct LightmappedGeneric_DX9_Vars_t #ifdef PARALLAX_CORRECTED_CUBEMAPS // Parallax cubemaps - int m_nEnvmapParallax; + int m_nEnvmapParallax; // Needed for editor int m_nEnvmapParallaxObb1; int m_nEnvmapParallaxObb2; int m_nEnvmapParallaxObb3; diff --git a/sp/src/materialsystem/stdshaders/shatteredglass.cpp b/sp/src/materialsystem/stdshaders/shatteredglass.cpp new file mode 100644 index 00000000..e98889ea --- /dev/null +++ b/sp/src/materialsystem/stdshaders/shatteredglass.cpp @@ -0,0 +1,349 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Lightmap only shader +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#include "BaseVSShader.h" + +#include "SDK_ShatteredGlass_ps20.inc" +#include "SDK_ShatteredGlass_ps20b.inc" +#include "SDK_ShatteredGlass_vs20.inc" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +BEGIN_VS_SHADER( SDK_ShatteredGlass, + "Help for SDK_ShatteredGlass" ) + + BEGIN_SHADER_PARAMS + SHADER_PARAM_OVERRIDE( BASETEXTURE, SHADER_PARAM_TYPE_TEXTURE, "Glass/glasswindowbreak070b", "unused", SHADER_PARAM_NOT_EDITABLE ) + SHADER_PARAM( DETAIL, SHADER_PARAM_TYPE_TEXTURE, "Glass/glasswindowbreak070b", "detail" ) + SHADER_PARAM( DETAILSCALE, SHADER_PARAM_TYPE_FLOAT, "1.0", "detail scale" ) + SHADER_PARAM( ENVMAP, SHADER_PARAM_TYPE_TEXTURE, "shadertest/shadertest_env", "envmap" ) + SHADER_PARAM( ENVMAPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "" ) + SHADER_PARAM( ENVMAPMASK, SHADER_PARAM_TYPE_TEXTURE, "glass/glasswindowbreak070b_mask", "envmap mask" ) + SHADER_PARAM( ENVMAPMASKFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "" ) + SHADER_PARAM( ENVMAPMASKTRANSFORM, SHADER_PARAM_TYPE_MATRIX, "center .5 .5 scale 1 1 rotate 0 translate 0 0", "$envmapmask texcoord transform" ) + SHADER_PARAM( ENVMAPTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "envmap tint" ) + SHADER_PARAM( ENVMAPCONTRAST, SHADER_PARAM_TYPE_FLOAT, "0.0", "contrast 0 == normal 1 == color*color" ) + SHADER_PARAM( ENVMAPSATURATION, SHADER_PARAM_TYPE_FLOAT, "1.0", "saturation 0 == greyscale 1 == normal" ) + SHADER_PARAM( FRESNELREFLECTION, SHADER_PARAM_TYPE_FLOAT, "1.0", "1.0 == mirror, 0.0 == water" ) + SHADER_PARAM( UNLITFACTOR, SHADER_PARAM_TYPE_FLOAT, "0.7", "0.0 == multiply by lightmap, 1.0 == multiply by 1" ) +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Parallax cubemaps + SHADER_PARAM( ENVMAPPARALLAX, SHADER_PARAM_TYPE_BOOL, "0", "Enables parallax correction code for env_cubemaps" ) + SHADER_PARAM( ENVMAPPARALLAXOBB1, SHADER_PARAM_TYPE_VEC4, "[1 0 0 0]", "The first line of the parallax correction OBB matrix" ) + SHADER_PARAM( ENVMAPPARALLAXOBB2, SHADER_PARAM_TYPE_VEC4, "[0 1 0 0]", "The second line of the parallax correction OBB matrix" ) + SHADER_PARAM( ENVMAPPARALLAXOBB3, SHADER_PARAM_TYPE_VEC4, "[0 0 1 0]", "The third line of the parallax correction OBB matrix" ) + SHADER_PARAM( ENVMAPORIGIN, SHADER_PARAM_TYPE_VEC3, "[0 0 0]", "The world space position of the env_cubemap being corrected" ) +#endif + END_SHADER_PARAMS + + SHADER_INIT_PARAMS() + { + if( !params[DETAILSCALE]->IsDefined() ) + params[DETAILSCALE]->SetFloatValue( 1.0f ); + + if( !params[ENVMAPTINT]->IsDefined() ) + params[ENVMAPTINT]->SetVecValue( 1.0f, 1.0f, 1.0f ); + + if( !params[ENVMAPCONTRAST]->IsDefined() ) + params[ENVMAPCONTRAST]->SetFloatValue( 0.0f ); + + if( !params[ENVMAPSATURATION]->IsDefined() ) + params[ENVMAPSATURATION]->SetFloatValue( 1.0f ); + + if( !params[UNLITFACTOR]->IsDefined() ) + params[UNLITFACTOR]->SetFloatValue( 0.3f ); + + if( !params[FRESNELREFLECTION]->IsDefined() ) + params[FRESNELREFLECTION]->SetFloatValue( 1.0f ); + + if( !params[ENVMAPMASKFRAME]->IsDefined() ) + params[ENVMAPMASKFRAME]->SetIntValue( 0 ); + + if( !params[ENVMAPFRAME]->IsDefined() ) + params[ENVMAPFRAME]->SetIntValue( 0 ); + + // No texture means no self-illum or env mask in base alpha + if ( !params[BASETEXTURE]->IsDefined() ) + { + CLEAR_FLAGS( MATERIAL_VAR_BASEALPHAENVMAPMASK ); + } + + // If in decal mode, no debug override... + if (IS_FLAG_SET(MATERIAL_VAR_DECAL)) + { + SET_FLAGS( MATERIAL_VAR_NO_DEBUG_OVERRIDE ); + } + } + + SHADER_FALLBACK + { + return 0; + } + + SHADER_INIT + { + if (params[BASETEXTURE]->IsDefined()) + { + LoadTexture( BASETEXTURE ); + + if ( !params[BASETEXTURE]->GetTextureValue()->IsTranslucent() ) + { + if ( IS_FLAG_SET( MATERIAL_VAR_BASEALPHAENVMAPMASK ) ) + CLEAR_FLAGS( MATERIAL_VAR_BASEALPHAENVMAPMASK ); + } + } + + if ( params[DETAIL]->IsDefined() ) + { + LoadTexture( DETAIL ); + } + + // Don't alpha test if the alpha channel is used for other purposes + if ( IS_FLAG_SET(MATERIAL_VAR_BASEALPHAENVMAPMASK) ) + CLEAR_FLAGS( MATERIAL_VAR_ALPHATEST ); + + if (params[ENVMAP]->IsDefined()) + { + LoadCubeMap( ENVMAP ); +#ifdef MAPBASE + if (mat_specular_disable_on_missing.GetBool()) + { + // Revert to defaultcubemap when the envmap texture is missing + // (should be equivalent to toolsblack in Mapbase) + if (params[ENVMAP]->GetTextureValue()->IsError()) + { + params[ENVMAP]->SetStringValue( "engine/defaultcubemap" ); + LoadCubeMap( ENVMAP ); + } + } +#endif + + if ( params[ENVMAPMASK]->IsDefined() ) + { + LoadTexture( ENVMAPMASK ); + } + } + } + + SHADER_DRAW + { + bool bHasEnvmapMask = false; + bool bHasEnvmap = false; +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Parallax cubemaps + bool hasParallaxCorrection = false; +#endif + if ( params[ENVMAP]->IsTexture() ) + { + bHasEnvmap = true; +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Parallax cubemaps + hasParallaxCorrection = params[ENVMAPPARALLAX]->GetIntValue() > 0; +#endif + if ( params[ENVMAPMASK]->IsTexture() ) + { + bHasEnvmapMask = true; + } + } + bool bHasVertexColor = IS_FLAG_SET(MATERIAL_VAR_VERTEXCOLOR); + bool bHasBaseAlphaEnvmapMask = IS_FLAG_SET(MATERIAL_VAR_BASEALPHAENVMAPMASK); + + // Base + SHADOW_STATE + { + // alpha test + pShaderShadow->EnableAlphaTest( IS_FLAG_SET(MATERIAL_VAR_ALPHATEST) ); + + // Alpha blending, enable alpha blending if the detail texture is translucent + bool detailIsTranslucent = TextureIsTranslucent( DETAIL, false ); + if ( detailIsTranslucent ) + { + if ( IS_FLAG_SET( MATERIAL_VAR_ADDITIVE ) ) + EnableAlphaBlending( SHADER_BLEND_SRC_ALPHA, SHADER_BLEND_ONE ); + else + EnableAlphaBlending( SHADER_BLEND_SRC_ALPHA, SHADER_BLEND_ONE_MINUS_SRC_ALPHA ); + } + else + { + SetDefaultBlendingShadowState( BASETEXTURE, true ); + } + + pShaderShadow->EnableSRGBWrite( true ); + + // Base texture + unsigned int flags = VERTEX_POSITION; + pShaderShadow->EnableTexture( SHADER_SAMPLER0, true ); + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER0, true ); + + // Lightmap + pShaderShadow->EnableTexture( SHADER_SAMPLER1, true ); + if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ) + { + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER1, true ); + } + else + { + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER1, false ); + } + + // Detail texture + pShaderShadow->EnableTexture( SHADER_SAMPLER3, true ); + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER3, true ); + + // Envmap + if ( bHasEnvmap ) + { + flags |= VERTEX_NORMAL; + pShaderShadow->EnableTexture( SHADER_SAMPLER2, true ); + if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ) + { + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER2, true ); + } + + if( bHasEnvmapMask ) + { + pShaderShadow->EnableTexture( SHADER_SAMPLER5, true ); + } + } + + // Normalizing cube map + pShaderShadow->EnableTexture( SHADER_SAMPLER6, true ); + + if ( bHasVertexColor ) + { + flags |= VERTEX_COLOR; + } + + pShaderShadow->VertexShaderVertexFormat( flags, 3, 0, 0 ); + + DECLARE_STATIC_VERTEX_SHADER( sdk_shatteredglass_vs20 ); + SET_STATIC_VERTEX_SHADER_COMBO( ENVMAP_MASK, bHasEnvmapMask ); + SET_STATIC_VERTEX_SHADER( sdk_shatteredglass_vs20 ); + + if( g_pHardwareConfig->SupportsPixelShaders_2_b() ) + { + DECLARE_STATIC_PIXEL_SHADER( sdk_shatteredglass_ps20b ); + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap ); + SET_STATIC_PIXEL_SHADER_COMBO( VERTEXCOLOR, bHasVertexColor ); + SET_STATIC_PIXEL_SHADER_COMBO( ENVMAPMASK, bHasEnvmapMask ); + SET_STATIC_PIXEL_SHADER_COMBO( BASEALPHAENVMAPMASK, bHasBaseAlphaEnvmapMask ); + SET_STATIC_PIXEL_SHADER_COMBO( HDRTYPE, g_pHardwareConfig->GetHDRType() ); +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Parallax cubemaps enabled for 2_0b and onwards + SET_STATIC_PIXEL_SHADER_COMBO( PARALLAXCORRECT, hasParallaxCorrection ); +#else + SET_STATIC_PIXEL_SHADER_COMBO( PARALLAXCORRECT, false ); +#endif + SET_STATIC_PIXEL_SHADER( sdk_shatteredglass_ps20b ); + } + else + { + DECLARE_STATIC_PIXEL_SHADER( sdk_shatteredglass_ps20 ); + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap ); + SET_STATIC_PIXEL_SHADER_COMBO( VERTEXCOLOR, bHasVertexColor ); + SET_STATIC_PIXEL_SHADER_COMBO( ENVMAPMASK, bHasEnvmapMask ); + SET_STATIC_PIXEL_SHADER_COMBO( BASEALPHAENVMAPMASK, bHasBaseAlphaEnvmapMask ); + SET_STATIC_PIXEL_SHADER_COMBO( HDRTYPE, g_pHardwareConfig->GetHDRType() ); +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Parallax cubemaps + SET_STATIC_PIXEL_SHADER_COMBO( PARALLAXCORRECT, 0 ); // No parallax cubemaps with ps_2_0 :( +#endif + SET_STATIC_PIXEL_SHADER( sdk_shatteredglass_ps20 ); + } + + DefaultFog(); + } + DYNAMIC_STATE + { + SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, BASETEXTURETRANSFORM ); + SetVertexShaderTextureScale( VERTEX_SHADER_SHADER_SPECIFIC_CONST_2, DETAILSCALE ); + + BindTexture( SHADER_SAMPLER0, BASETEXTURE, FRAME ); + pShaderAPI->BindStandardTexture( SHADER_SAMPLER1, TEXTURE_LIGHTMAP ); + BindTexture( SHADER_SAMPLER3, DETAIL ); + + if( bHasEnvmap ) + { + BindTexture( SHADER_SAMPLER2, ENVMAP, ENVMAPFRAME ); + if( bHasEnvmapMask ) + { + BindTexture( SHADER_SAMPLER5, ENVMAPMASK, ENVMAPMASKFRAME ); + } + } + + pShaderAPI->BindStandardTexture( SHADER_SAMPLER6, TEXTURE_NORMALIZATION_CUBEMAP_SIGNED ); + + DECLARE_DYNAMIC_VERTEX_SHADER( sdk_shatteredglass_vs20 ); + SET_DYNAMIC_VERTEX_SHADER_COMBO( DOWATERFOG, ( pShaderAPI->GetSceneFogMode() == MATERIAL_FOG_LINEAR_BELOW_FOG_Z ) ); + SET_DYNAMIC_VERTEX_SHADER( sdk_shatteredglass_vs20 ); + + if( g_pHardwareConfig->SupportsPixelShaders_2_b() ) + { + DECLARE_DYNAMIC_PIXEL_SHADER( sdk_shatteredglass_ps20b ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); + SET_DYNAMIC_PIXEL_SHADER( sdk_shatteredglass_ps20b ); + } + else + { + DECLARE_DYNAMIC_PIXEL_SHADER( sdk_shatteredglass_ps20 ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); + SET_DYNAMIC_PIXEL_SHADER( sdk_shatteredglass_ps20 ); + } + + SetEnvMapTintPixelShaderDynamicState( 0, ENVMAPTINT, -1 ); + SetModulationPixelShaderDynamicState( 1 ); + SetPixelShaderConstant( 2, ENVMAPCONTRAST ); + SetPixelShaderConstant( 3, ENVMAPSATURATION ); + + // [ 0, 0 ,0, R(0) ] + float fresnel[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + fresnel[3] = params[FRESNELREFLECTION]->GetFloatValue(); + fresnel[0] = fresnel[1] = fresnel[2] = 1.0f - fresnel[3]; + pShaderAPI->SetPixelShaderConstant( 4, fresnel ); + + float eyePos[4]; + pShaderAPI->GetWorldSpaceCameraPosition( eyePos ); + pShaderAPI->SetPixelShaderConstant( 5, eyePos, 1 ); + + pShaderAPI->SetPixelShaderFogParams( 12 ); + + float overbright[4]; + overbright[0] = OVERBRIGHT; + overbright[1] = params[UNLITFACTOR]->GetFloatValue(); + overbright[2] = overbright[3] = 1.0f - params[UNLITFACTOR]->GetFloatValue(); + pShaderAPI->SetPixelShaderConstant( 6, overbright ); + +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Parallax cubemaps + if (hasParallaxCorrection) + { + pShaderAPI->SetPixelShaderConstant( 7, params[ENVMAPORIGIN]->GetVecValue() ); + + float* vecs[3]; + vecs[0] = const_cast(params[ENVMAPPARALLAXOBB1]->GetVecValue()); + vecs[1] = const_cast(params[ENVMAPPARALLAXOBB2]->GetVecValue()); + vecs[2] = const_cast(params[ENVMAPPARALLAXOBB3]->GetVecValue()); + float matrix[4][4]; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 4; j++) + { + matrix[i][j] = vecs[i][j]; + } + } + matrix[3][0] = matrix[3][1] = matrix[3][2] = 0; + matrix[3][3] = 1; + pShaderAPI->SetPixelShaderConstant( 8, &matrix[0][0], 4 ); + } +#endif + } + Draw(); + } +END_SHADER diff --git a/sp/src/materialsystem/stdshaders/stdshader_dx9_20b.txt b/sp/src/materialsystem/stdshaders/stdshader_dx9_20b.txt index 6b5940cb..f16775fd 100644 --- a/sp/src/materialsystem/stdshaders/stdshader_dx9_20b.txt +++ b/sp/src/materialsystem/stdshaders/stdshader_dx9_20b.txt @@ -90,4 +90,6 @@ SDK_decalmodulate_vs20.fxc SDK_unlittwotexture_ps2x.fxc SDK_unlittwotexture_vs20.fxc -SDK_monitorscreen_ps2x.fxc \ No newline at end of file +SDK_monitorscreen_ps2x.fxc +SDK_ShatteredGlass_ps2x.fxc +SDK_ShatteredGlass_vs20.fxc \ No newline at end of file diff --git a/sp/src/public/bspfile.h b/sp/src/public/bspfile.h index 21d9f375..bff7b20a 100644 --- a/sp/src/public/bspfile.h +++ b/sp/src/public/bspfile.h @@ -59,7 +59,11 @@ // 16 bit short limits #define MAX_MAP_MODELS 1024 #define MAX_MAP_BRUSHES 8192 +#ifdef MAPBASE +#define MAX_MAP_ENTITIES 65536 // According to ficool2, this limit is bogus/not enforced by the engine and can be "safely" raised. +#else #define MAX_MAP_ENTITIES 8192 +#endif #define MAX_MAP_TEXINFO 12288 #define MAX_MAP_TEXDATA 2048 #define MAX_MAP_DISPINFO 2048 @@ -90,9 +94,17 @@ #define MAX_MAP_LIGHTING 0x1000000 #define MAX_MAP_VISIBILITY 0x1000000 // increased BSPVERSION 7 #define MAX_MAP_TEXTURES 1024 +#ifdef MAPBASE +#define MAX_MAP_WORLDLIGHTS 65536 // According to ficool2, this limit is bogus/not enforced by the engine and can be "safely" raised. +#else #define MAX_MAP_WORLDLIGHTS 8192 +#endif #define MAX_MAP_CUBEMAPSAMPLES 1024 +#ifdef MAPBASE +#define MAX_MAP_OVERLAYS 8192 // According to ficool2, this limit is bogus/not enforced by the engine and can be "safely" raised. +#else #define MAX_MAP_OVERLAYS 512 +#endif #define MAX_MAP_WATEROVERLAYS 16384 #define MAX_MAP_TEXDATA_STRING_DATA 256000 #define MAX_MAP_TEXDATA_STRING_TABLE 65536 diff --git a/sp/src/utils/vbsp/cubemap.cpp b/sp/src/utils/vbsp/cubemap.cpp index a95a46d9..9156900e 100644 --- a/sp/src/utils/vbsp/cubemap.cpp +++ b/sp/src/utils/vbsp/cubemap.cpp @@ -573,7 +573,7 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons GeneratePatchedName( pMaterialName, info, true, pPatchedMaterialName, 1024 ); #ifdef PARALLAX_CORRECTED_CUBEMAPS - MaterialPatchInfo_t pPatchInfo[6]; + MaterialPatchInfo_t pPatchInfo[7]; #else MaterialPatchInfo_t pPatchInfo[2]; #endif @@ -593,9 +593,11 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons { V_SplitString( pParallaxObbMatrix, ";", matRowList ); + // Needed for editor pPatchInfo[nPatchCount].m_pKey = "$envMapParallax"; pPatchInfo[nPatchCount].m_pValue = "1"; ++nPatchCount; + pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB1"; pPatchInfo[nPatchCount].m_pValue = matRowList[0]; ++nPatchCount;