66#include <dhooks>
77#include <left4dhooks>
88
9- #define PLUGIN_VERSION " 1.2 "
9+ #define PLUGIN_VERSION " 1.3 "
1010
1111public Plugin myinfo =
1212{
1313 name = " [L4D2] Fix Changelevel" ,
1414 author = " Lux (for \" l4d2_changelevel\" ), Forgetest" ,
15- description = " Fix issues due to forced changelevel (i.e. No gascans in scavenge, incorrect behavior of \" OnGameplayStart \" ) ." ,
15+ description = " Fix issues due to forced changelevel + resolve partial map names before the engine sees them ." ,
1616 version = PLUGIN_VERSION ,
1717 url = " https://github.com/Target5150/MoYu_Server_Stupid_Plugins"
1818}
@@ -119,17 +119,17 @@ public void OnPluginStart()
119119 {SDKType_Bool , SDKPass_Plain }
120120 };
121121 g_CallClearTeamScores = gd .CreateSDKCallOrFail (SDKCall_Raw , SDKConf_Signature , " CDirector::ClearTeamScores" , params , sizeof (params ), false );
122-
122+
123123 SDKCallParamsWrapper params2 [] = {
124124 {SDKType_Bool , SDKPass_Plain }
125125 };
126126 g_CallOnBeginTransition = gd .CreateSDKCallOrFail (SDKCall_Raw , SDKConf_Signature , " CDirector::OnBeginTransition" , params2 , sizeof (params2 ), false );
127-
127+
128128 SDKCallParamsWrapper params3 [] = {
129129 {SDKType_String , SDKPass_Pointer }
130130 };
131131 g_CallOnBeginChangeLevel = gd .CreateSDKCallOrFail (SDKCall_GameRules , SDKConf_Signature , " CTerrorGameRules::OnBeginChangeLevel" , params3 , sizeof (params3 ), false );
132-
132+
133133 g_iOffs_m_mapDurationTimer = gd .GetOffsetOrFail (" CDirector::m_mapDurationTimer" );
134134 g_iOffs_m_flTotalMissionElaspedTime = gd .GetOffsetOrFail (" CDirector::m_flTotalMissionElaspedTime" );
135135 g_iOffs_m_szOriginalMap = gd .GetOffsetOrFail (" CDirector::m_szOriginalMap" );
@@ -154,17 +154,33 @@ MRESReturn DTR__CVEngineServer__ChangeLevel(DHookParam hParams)
154154{
155155 if (! TheDirector )
156156 return MRES_Ignored ;
157-
157+
158158 char map [64 ]/* , reason[64]*/ ;
159159 hParams .GetString (1 , map , sizeof (map ));
160160 // if (!hParams.IsNull(2))
161161 // hParams.GetString(2, reason, sizeof(reason));
162-
162+
163+ /*
164+ sm_map (and possible other callers) accept partial names like "c4m1" for "c4m1_milltown_a"
165+ these get resolved for display via FindMap() but pass the original "c4m1" back to the
166+ engine, which then gets stuck trying to load a non-existent map.
167+ This way we don't have to modify official SourceMod files with every update.
168+ */
169+ bool changedParam = false ;
170+ char fullMap [64 ];
171+
172+ if (GetMapDisplayName (map , fullMap , sizeof (fullMap )))
173+ {
174+ strcopy (map , sizeof (map ), fullMap );
175+ hParams .SetString (1 , fullMap );
176+ changedParam = true ;
177+ }
178+
163179 if (TheDirector .IsTransitioning ())
164- return MRES_Ignored ;
165-
180+ return changedParam ? MRES_ChangedHandled : MRES_Ignored ;
181+
166182 TheDirector .ClearTeamScores (true );
167-
183+
168184 ITimer_Start (TheDirector .m_mapDurationTimer );
169185 TheDirector .m_flTotalMissionElaspedTime = 0.0 ;
170186
@@ -173,7 +189,7 @@ MRESReturn DTR__CVEngineServer__ChangeLevel(DHookParam hParams)
173189 TheDirector .OnBeginTransition (false );
174190 GameRules__OnBeginChangeLevel (map );
175191
176- return MRES_Ignored ;
192+ return changedParam ? MRES_ChangedHandled : MRES_Ignored ;
177193}
178194
179195void GameRules__OnBeginChangeLevel (const char [] map )
@@ -198,4 +214,4 @@ void UTIL_StoreToAddressString(Address dest, const char[] src, int maxlength)
198214 StoreToAddress (dest + view_as <Address >(i ), src [i ], NumberType_Int8 );
199215 }
200216 StoreToAddress (dest + view_as <Address >(len ), 0 , NumberType_Int8 );
201- }
217+ }
0 commit comments