diff --git a/addons/sourcemod/plugins/hana/l4d2_mixmap.smx b/addons/sourcemod/plugins/hana/l4d2_mixmap.smx
index 4fd2dd231..5661118f4 100644
Binary files a/addons/sourcemod/plugins/hana/l4d2_mixmap.smx and b/addons/sourcemod/plugins/hana/l4d2_mixmap.smx differ
diff --git a/addons/sourcemod/scripting/include/l4d2_mixmap.inc b/addons/sourcemod/scripting/include/l4d2_mixmap.inc
new file mode 100644
index 000000000..629a1b6af
--- /dev/null
+++ b/addons/sourcemod/scripting/include/l4d2_mixmap.inc
@@ -0,0 +1,67 @@
+/*
+ SourcePawn is Copyright (C) 2006-2008 AlliedModders LLC. All rights reserved.
+ SourceMod is Copyright (C) 2006-2008 AlliedModders LLC. All rights reserved.
+ Pawn and SMALL are Copyright (C) 1997-2008 ITB CompuPhase.
+ Source is Copyright (C) Valve Corporation.
+ All trademarks are property of their respective owners.
+
+ This program is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see .
+*/
+#if defined _l4d2_mixmap_included_
+ #endinput
+#endif
+#define _l4d2_mixmap_included_
+
+/**
+ * @brief Called when plugin is about to load first mix map
+ * @note Right before loading first map
+ *
+ * @param iMapCount Total Mix Map Count
+ * @param sMapName First Mix Map Name
+ */
+forward void OnCMTStart(int iMapCount, const char[] sMapName);
+
+/**
+ * @brief Called when mix map is loaded
+ * @note Right after the map is loaded
+ *
+ * @param sMapName Name of Current Mix Map Loaded
+ */
+forward void OnCMTNextKnown(const char[] sMapName);
+
+/**
+ * @brief Called when last map is played and mixmap is finished
+ * @note Right after round ends or final wins
+ *
+ * @param sMapName Name of Current Mix Map Loaded
+ */
+forward void OnCMTEnd();
+
+
+public SharedPlugin __pl_l4d2_mixmap =
+{
+ name = "l4d2_mixmap",
+ file = "l4d2_mixmap.smx",
+#if defined REQUIRE_PLUGIN
+ required = 1,
+#else
+ required = 0,
+#endif
+};
+
+#if !defined REQUIRE_PLUGIN
+public void __pl_l4d2_mixmap_SetNTVOptional()
+{
+}
+#endif
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/l4d2_mixmap.sp b/addons/sourcemod/scripting/l4d2_mixmap.sp
index 855c8ec9b..22754cf75 100644
--- a/addons/sourcemod/scripting/l4d2_mixmap.sp
+++ b/addons/sourcemod/scripting/l4d2_mixmap.sp
@@ -1,32 +1,83 @@
+/**
+ * 來源: https://gitee.com/honghl5/open-source-plug-in/tree/main/l4d2_mixmap
+ * 別人寫的插件: 輸入!mixmap可以投票,通過後隨機切換五個關卡
+ * 1. 可適用於戰役模式
+ * 2. 支援L4D1
+ */
+
#pragma semicolon 1
#pragma newdecls required
#include
-#include
#include
-#include
+#include
#include
-#include
+#include
+#include //https://github.com/fbef0102/Game-Private_Plugin/releases/tag/builtinvotes
#undef REQUIRE_PLUGIN
-#include
-#undef REQUIRE_PLUGIN
-#include
-//#include
+#tryinclude
+#tryinclude
+
+#if !defined _readyup_included_
+ native bool EditFooterStringAtIndex(int index, const char[] string);
+ native int AddStringToReadyFooter(const char[] footer);
+#endif
-#define SECTION_NAME "CTerrorGameRules::SetCampaignScores"
-#define LEFT4FRAMEWORK_GAMEDATA "left4dhooks.l4d2"
public Plugin myinfo =
{
- name = "l4d2_mixmap",
- author = "Bred",
- description = "Randomly select five maps for versus. Adding for fun and reference from CMT",
- version = "2.5",
- url = "https://gitee.com/honghl5/open-source-plug-in/tree/main/l4d2_mixmap"
+ name = "[L4D1/L4D2] Mix Map",
+ author = "Bred, Harry",
+ description = "Randomly select five maps for versus/coop/realism. Adding for fun",
+ version = "1.0h-2024/12/25",
+ url = "https://github.com/fbef0102/L4D1_2-Plugins/tree/master/l4d2_mixmap"
};
-#define DIR_CFGS "mixmap/"
-#define PATH_KV "cfg/mixmap/mapnames.txt"
+Handle g_hForwardStart;
+Handle g_hForwardNext;
+Handle g_hForwardEnd;
+
+bool g_bL4D2Version;
+public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
+{
+ EngineVersion test = GetEngineVersion();
+
+ if( test == Engine_Left4Dead )
+ {
+ g_bL4D2Version = false;
+ }
+ else if( test == Engine_Left4Dead2 )
+ {
+ g_bL4D2Version = true;
+ }
+ else
+ {
+ strcopy(error, err_max, "Plugin only supports Left 4 Dead 1 & 2.");
+ return APLRes_SilentFailure;
+ }
+
+ MarkNativeAsOptional("EditFooterStringAtIndex");
+ MarkNativeAsOptional("AddStringToReadyFooter");
+
+ // Right before loading first map; params: 1 = maplist size; 2 = name of first map
+ g_hForwardStart = CreateGlobalForward("OnCMTStart", ET_Ignore, Param_Cell, Param_String );
+ // After loading a map (to let other plugins know what the next map will be ahead of time); 1 = name of next map
+ g_hForwardNext = CreateGlobalForward("OnCMTNextKnown", ET_Ignore, Param_String );
+ // After last map is played; no params
+ g_hForwardEnd = CreateGlobalForward("OnCMTEnd", ET_Ignore );
+
+ RegPluginLibrary("l4d2_mixmap");
+
+ return APLRes_Success;
+}
+
+#define SECTION_NAME "CTerrorGameRules::SetCampaignScores"
+#define LEFT4FRAMEWORK_GAMEDATA_L4D2 "left4dhooks.l4d2"
+#define LEFT4FRAMEWORK_GAMEDATA_L4D1 "left4dhooks.l4d1"
+
+#define DIR_CFGS_L4D2 "mixmap/"
+#define DIR_CFGS_L4D1 "l4d2_mixmap/l4d1/"
+#define PATH_KV "mapnames.txt"
#define CFG_DEFAULT "default"
#define CFG_DODEFAULT "disorderdefault"
#define CFG_DODEFAULT_ST "do"
@@ -38,185 +89,167 @@ public Plugin myinfo =
#define CFG_UNOF_ST "uof"
#define CFG_DOUNOF "disorderunofficial"
#define CFG_DOUNOF_ST "douof"
-#define BUF_SZ 64
+#define BUF_SZ 128
ConVar g_cvNextMapPrint,
g_cvMaxMapsNum,
- g_cvFinaleEndStart;
+ g_cvFinaleEndCoop,
+ g_cvFinaleEndVersus;
char cfg_exec[BUF_SZ];
-Handle hVoteMixmap;
-Handle hVoteStopMixmap;
-
//与随机抽签相关的变量
-Handle g_hArrayTags; // Stores tags for indexing g_hTriePools 存放地图池标签
-Handle g_hTriePools; // Stores pool array handles by tag name 存放由标签分类的地图
-Handle g_hArrayTagOrder; // Stores tags by rank 存放标签顺序
-Handle g_hArrayMapOrder; // Stores finalised map list in order 存放抽取完成后的地图顺序
-
+ArrayList g_hArrayTags; // Stores tags for indexing g_hTriePools 存放地图池标签
+StringMap g_hTriePools; // Stores pool array handles by tag name 存放由标签分类的地图, tag - ArrayList
+ArrayList g_hArrayTagOrder; // Stores tags by rank 存放标签顺序
+ArrayList g_hArrayMapOrder; // Stores finalised map list in order 存放抽取完成后的地图顺序
+KeyValues g_hKvMapNames;
bool g_bMaplistFinalized;
bool g_bMapsetInitialized;
int g_iMapsPlayed;
int g_iMapCount;
-int
- g_iPointsTeam_A = 0,
- g_iPointsTeam_B = 0;
+bool
+ g_bServerForceStart = false;
-//bool bLeftStartArea;
-//bool bReadyUpAvailable;
-bool g_bCMapTransitioned = false,
- g_bServerForceStart = false;
+Handle g_hCountDownTimer;
-Handle g_hForwardStart;
-Handle g_hForwardNext;
-Handle g_hForwardEnd;
+bool
+ g_bRoundIsLive,
+ g_bReadyUpFooterAdded,
+ g_bDifferAbort;
-Handle g_hCountDownTimer;
-Handle g_hCMapSetCampaignScores;
+Handle
+ g_hUpdateFooterTimer;
+
+char
+ g_slandmarkName[128];
+
+int
+ g_iReadyUpFooterIndex,
+ g_iRoundStart,
+ g_iPlayerSpawn;
// ----------------------------------------------------------
// Setup
// ----------------------------------------------------------
-public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
-{
- // Right before loading first map; params: 1 = maplist size; 2 = name of first map
- g_hForwardStart = CreateGlobalForward("OnCMTStart", ET_Ignore, Param_Cell, Param_String );
- // After loading a map (to let other plugins know what the next map will be ahead of time); 1 = name of next map
- g_hForwardNext = CreateGlobalForward("OnCMTNextKnown", ET_Ignore, Param_String );
- // After last map is played; no params
- g_hForwardEnd = CreateGlobalForward("OnCMTEnd", ET_Ignore );
-
- MarkNativeAsOptional("PLAYSTATS_BroadcastRoundStats");
- MarkNativeAsOptional("PLAYSTATS_BroadcastGameStats");
-
- return APLRes_Success;
-}
-
public void OnPluginStart()
{
- LoadSDK();
-
- g_cvNextMapPrint = CreateConVar("l4d2mm_nextmap_print", "1", "Determine whether to show what the next map will be", _, true, 0.0, true, 1.0);
- g_cvMaxMapsNum = CreateConVar("l4d2mm_max_maps_num", "2", "Determine how many maps of one campaign can be selected; 0 = no limits;", _, true, 0.0, true, 5.0);
- g_cvFinaleEndStart = CreateConVar("l4d2mm_finale_end_start", "1", "Determine whether to remixmap in the end of finale; 0 = disable;1 = enable", _, true, 0.0, true, 1.0);
-
- //Servercmd 服务器指令(用于cfg文件)
- RegServerCmd("sm_addmap", Command_AddMap, "Add a map to the maplist under specified tags");
- RegServerCmd("sm_tagrank", Command_TagRank, "Set tag rank for map selection");
-
- RegAdminCmd("sm_manualmixmap", Command_ManualMixmap, ADMFLAG_ROOT, "Start mixmap with specified maps 启用mixmap加载特定地图顺序的地图组");
- RegAdminCmd("sm_fmixmap", Command_ForceMixmap, ADMFLAG_ROOT, "Force start mixmap (arg1 empty for 'default' maps pool) 强制启用mixmap(随机官方地图)");
- RegConsoleCmd("sm_mixmap", Command_Mixmap, "Vote to start a mixmap (arg1 empty for 'default' maps pool);通过投票启用Mixmap,并可加载特定的地图池;无参数则启用官图顺序随机");
- RegConsoleCmd("sm_stopmixmap", Command_StopMixmap, "Stop a mixmap;中止mixmap,并初始化地图列表");
- RegAdminCmd("sm_fstopmixmap", Command_ForceStopMixmap, ADMFLAG_ROOT, "Force stop a mixmap ;强制中止mixmap,并初始化地图列表");
+ LoadTranslations("l4d2_mixmap.phrases");
- RegConsoleCmd("sm_maplist", Command_Maplist, "Show the map list; 展示mixmap最终抽取出的地图列表");
- RegAdminCmd("sm_allmap", Command_ShowAllMaps, ADMFLAG_ROOT, "Show all official maps code; 展示所有官方地图的地图代码");
- RegAdminCmd("sm_allmaps", Command_ShowAllMaps, ADMFLAG_ROOT, "Show all official maps code; 展示所有官方地图的地图代码");
+ g_cvNextMapPrint = CreateConVar("l4d2mm_nextmap_print", "1", "If 1, show what the next map will be", FCVAR_NOTIFY, true, 0.0, true, 1.0);
+ g_cvMaxMapsNum = CreateConVar("l4d2mm_max_maps_num", "2", "Determine how many maps of one campaign can be selected; 0 = no limits;", FCVAR_NOTIFY, true, 0.0, true, 5.0);
+ g_cvFinaleEndCoop = CreateConVar("l4d2mm_finale_end_coop", "0", "If 1, auto force start mixmap in the end of finale in coop/realism mode (When mixmap is alreaedy on)", FCVAR_NOTIFY, true, 0.0, true, 1.0);
+ g_cvFinaleEndVersus = CreateConVar("l4d2mm_finale_end_verus", "0", "If 1, auto force start mixmap in the end of finale in versus mode (When mixmap is alreaedy on)", FCVAR_NOTIFY, true, 0.0, true, 1.0);
+ //AutoExecConfig(true, "l4d2_mixmap");
- // HookEvent("player_left_start_area", LeftStartArea_Event, EventHookMode_PostNoCopy);
- // HookEvent("round_start", RoundStart_Event, EventHookMode_PostNoCopy);
-
+ //Servercmd 服务器指令(用于cfg文件)
+ RegServerCmd( "sm_addmap", AddMap, "Add a chatper and tag 新增關卡名稱與標記, Usage: sm_addmap ");
+ RegServerCmd( "sm_tagrank", TagRank, "Define map order 決定標記的地圖順序, Usage: sm_addmap , number starting from 0");
+
+ //Start/Stop 启用/中止指令
+ RegAdminCmd( "sm_manualmixmap", ManualMixmap, ADMFLAG_ROOT, "Start mixmap with specified maps 启用mixmap加载特定地图顺序的地图组");
+ RegAdminCmd( "sm_fmixmap", ForceMixmap, ADMFLAG_ROOT, "Force start mixmap (arg1 empty for 'default' maps pool) 强制启用mixmap(随机官方地图)");
+ RegConsoleCmd( "sm_mixmap", Mixmap_Cmd, "Vote to start a mixmap (arg1 empty for 'default' maps pool);通过投票启用Mixmap,并可加载特定的地图池;无参数则启用官图顺序随机");
+ RegConsoleCmd( "sm_stopmixmap", StopMixmap_Cmd, "Vote to Stop a mixmap;中止mixmap,并初始化地图列表");
+ RegAdminCmd( "sm_fstopmixmap", StopMixmap, ADMFLAG_ROOT, "Force stop a mixmap ;强制中止mixmap,并初始化地图列表");
+
+ //Midcommand 插件启用后可使用的指令
+ RegConsoleCmd( "sm_maplist", MixMaplist, "Show the mix map list; 展示mixmap最终抽取出的地图列表");
+ //RegAdminCmd( "sm_allmap", ShowAllMaps, ADMFLAG_ROOT, "Show all official maps code; 展示所有官方地图的地图代码");
+ //RegAdminCmd( "sm_allmaps", ShowAllMaps, ADMFLAG_ROOT, "Show all official maps code; 展示所有官方地图的地图代码");
+
+ HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy);
+ HookEvent("player_spawn", Event_PlayerSpawn);
+ HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy); //trigger twice in versus/survival/scavenge mode, one when all survivors wipe out or make it to saferom, one when first round ends (second round_start begins).
+ HookEvent("map_transition", Event_RoundEnd, EventHookMode_PostNoCopy); //1. all survivors make it to saferoom in and server is about to change next level in coop mode (does not trigger round_end), 2. all survivors make it to saferoom in versus
+ HookEvent("mission_lost", Event_RoundEnd, EventHookMode_PostNoCopy); //all survivors wipe out in coop mode (also triggers round_end)
+ HookEvent("finale_vehicle_leaving", Event_RoundEnd, EventHookMode_PostNoCopy); //final map final rescue vehicle leaving (does not trigger round_end)
+
+ HookEvent("map_transition", map_transition, EventHookMode_PostNoCopy); //1. all survivors make it to saferoom in and server is about to change next level in coop mode (does not trigger round_end), 2. all survivors make it to saferoom in versus
+ HookEvent("finale_win", finale_win);
PluginStartInit();
- LoadTranslations("l4d2_mixmap.phrases");
- //AutoExecConfig(true, "l4d2_mixmap");
}
-void PluginStartInit()
-{
- g_hArrayTags = CreateArray(BUF_SZ/4); //1 block = 4 characters => X characters = X/4 blocks
- g_hTriePools = CreateTrie();
- g_hArrayTagOrder = CreateArray(BUF_SZ/4);
- g_hArrayMapOrder = CreateArray(BUF_SZ/4);
-
- g_bMapsetInitialized = false;
- g_bMaplistFinalized = false;
+bool
+ g_ReadyUpAvailable;
- g_hCountDownTimer = null;
-
- g_iMapsPlayed = 0;
- g_iMapCount = 0;
+public void OnAllPluginsLoaded()
+{
+ g_ReadyUpAvailable = LibraryExists("readyup");
}
-void LoadSDK()
+public void OnLibraryRemoved(const char[] name)
{
- Handle hGameData = LoadGameConfigFile(LEFT4FRAMEWORK_GAMEDATA);
- if (hGameData == null) {
- SetFailState("Could not load gamedata/%s.txt", LEFT4FRAMEWORK_GAMEDATA);
- }
-
- StartPrepSDKCall(SDKCall_GameRules);
- if (!PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, SECTION_NAME)) {
- SetFailState("Function '%s' not found.", SECTION_NAME);
- }
-
- PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
- PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
- g_hCMapSetCampaignScores = EndPrepSDKCall();
-
- if (g_hCMapSetCampaignScores == null) {
- SetFailState("Function '%s' found, but something went wrong.", SECTION_NAME);
- }
-
- delete hGameData;
+ g_ReadyUpAvailable = LibraryExists("readyup");
}
+public void OnLibraryAdded(const char[] name)
+{
+ g_ReadyUpAvailable = LibraryExists("readyup");
+}
-// ----------------------------------------------------------
-// Hooks
-// ----------------------------------------------------------
// Otherwise nextmap would be stuck and people wouldn't be able to play normal campaigns without the plugin 结束后初始化sm_nextmap的值
-public void OnPluginEnd() {
+public void OnPluginEnd()
+{
ServerCommand("sm_nextmap ''");
+ ClearDefault();
}
-public void OnClientPutInServer(int client)
-{
- if (g_bMapsetInitialized)
- {
- CreateTimer(10.0, Timer_ShowMaplist, client);//玩家加入服务器后,10s后提示正在使用mixmap插件。
- }
-}
+// Sourcemod API Forward-------------------------------
-public Action Timer_ShowMaplist(Handle timer, int client)
+public void OnMapStart()
{
- if (IsClientInGame(client))
+ g_bDifferAbort = false;
+
+ delete g_hKvMapNames;
+ g_hKvMapNames = new KeyValues("Mixmap Map Names");
+ char sbuffer[BUF_SZ];
+ if(g_bL4D2Version) Format(sbuffer, sizeof(sbuffer), "cfg/%s%s", DIR_CFGS_L4D2, PATH_KV);
+ else Format(sbuffer, sizeof(sbuffer), "cfg/%s%s", DIR_CFGS_L4D1, PATH_KV);
+
+ if (!FileToKeyValues(g_hKvMapNames, sbuffer))
{
- CPrintToChat(client, "%t", "Auto_Show_Maplist");
+ LogError("Couldn't create KV for map names: %s", sbuffer);
+ g_hKvMapNames = null;
+ return;
}
-
- return Plugin_Handled;
-}
-public void OnMapStart() {
-
- if (g_bCMapTransitioned) {
- CreateTimer(1.0, Timer_OnMapStartDelay, _, TIMER_FLAG_NO_MAPCHANGE); //Clients have issues connecting if team swap happens exactly on map start, so we delay it
- g_bCMapTransitioned = false;
+ if(!g_bL4D2Version)
+ {
+ PrecacheSound("ui/menu_enter05.wav");
+ PrecacheSound("ui/beep_synthtone01.wav");
+ PrecacheSound("ui/beep_error01.wav");
}
ServerCommand("sm_nextmap ''");
-
+
char buffer[BUF_SZ];
-
+
//判断currentmap与预计的map的name是否一致,如果不一致就stopmixmap
if (g_bMapsetInitialized)
{
+ if(g_iMapsPlayed >= g_iMapCount)
+ {
+ PluginStartInit();
+ return;
+ }
+
char OriginalSetMapName[BUF_SZ];
GetCurrentMap(buffer, BUF_SZ);
- GetArrayString(g_hArrayMapOrder, g_iMapsPlayed, OriginalSetMapName, BUF_SZ);
-
- if (! StrEqual(buffer,OriginalSetMapName) && g_bMaplistFinalized)
+ g_hArrayMapOrder.GetString(g_iMapsPlayed, OriginalSetMapName, BUF_SZ);
+
+ if (!StrEqual(buffer,OriginalSetMapName) && g_bMaplistFinalized)
{
PluginStartInit();
- CPrintToChatAll("%t", "Differ_Abort");
+
+ g_bDifferAbort = true;
+ CreateTimer(60.0, Timer_DifferAbort, _, TIMER_FLAG_NO_MAPCHANGE);
return;
}
}
@@ -226,132 +259,67 @@ public void OnMapStart() {
return;
}
- GetArrayString(g_hArrayMapOrder, g_iMapsPlayed+1, buffer, BUF_SZ);
+ g_hArrayMapOrder.GetString(g_iMapsPlayed+1, buffer, BUF_SZ);
+
+ CreateTimer(5.0, Timer_FindInfoChangelevel, _, TIMER_FLAG_NO_MAPCHANGE);
Call_StartForward(g_hForwardNext);
Call_PushString(buffer);
Call_Finish();
}
-public Action Timer_OnMapStartDelay(Handle hTimer)
+public void OnMapEnd()
{
- SetScores();
-
- return Plugin_Handled;
+ delete g_hUpdateFooterTimer;
+ ClearDefault();
}
-void SetScores()
-{
- //If team B is winning, swap teams. Does not change how scores are set
- if (g_iPointsTeam_A < g_iPointsTeam_B) {
- L4D2_SwapTeams();
- }
-
- //Set scores on scoreboard
- SDKCall(g_hCMapSetCampaignScores, g_iPointsTeam_A, g_iPointsTeam_B);
+public void OnClientPutInServer(int client)
+{
+ if(IsFakeClient(client)) return;
- //Set actual scores
- L4D2Direct_SetVSCampaignScore(0, g_iPointsTeam_A);
- L4D2Direct_SetVSCampaignScore(1, g_iPointsTeam_B);
+ CreateTimer(10.0, Timer_ShowMaplist, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);//玩家加入服务器后,10s后提示正在使用mixmap插件。
}
-public void L4D2_OnEndVersusModeRound_Post()
+/*public void OnEntityCreated(int entity, const char[] classname)
{
- if (InSecondHalfOfRound() && g_bMapsetInitialized)
- {
- PerformMapProgression();
+ if (!g_bMapsetInitialized || !IsValidEntityIndex(entity))
return;
- }
- return;
-}
-// ----------------------------------------------------------
-// Map switching logic
-// ----------------------------------------------------------
-
-stock Action PerformMapProgression()
-{
- if (++g_iMapsPlayed < g_iMapCount)
+ switch (classname[0])
{
- GotoNextMap(false);
- return Plugin_Handled;
+ case 'i':
+ {
+ if (StrEqual(classname, "info_landmark"))
+ {
+ RemoveEntity(entity);
+ }
+ }
}
- else if (g_cvFinaleEndStart.IntValue)
- CreateTimer(9.0, Timed_ContinueMixmap);
-
- Call_StartForward(g_hForwardEnd);
- Call_Finish();
-
- return Plugin_Handled;
-}
-
-void GotoNextMap(bool force = false)
-{
- char sMapName[BUF_SZ];
- GetArrayString(g_hArrayMapOrder, g_iMapsPlayed, sMapName, BUF_SZ);
-
- GotoMap(sMapName, force);
-}
+}*/
-void GotoMap(const char[] sMapName, bool force = false)
-{
- if (force)
- {
- ForceChangeLevel(sMapName, "Mixmap");
- return;
- }
- ServerCommand("sm_nextmap %s", sMapName);
- CreateTimer(5.0, Timed_NextMapInfo);
-}
+// Command-------------------------------
-public Action Timed_NextMapInfo(Handle timer)
+Action Timer_ShowMaplist(Handle timer, int client)
{
- char sMapName_New[BUF_SZ], sMapName_Old[BUF_SZ];
- GetArrayString(g_hArrayMapOrder, g_iMapsPlayed, sMapName_New, BUF_SZ);
- GetArrayString(g_hArrayMapOrder, g_iMapsPlayed - 1, sMapName_Old, BUF_SZ);
-
- g_cvNextMapPrint.IntValue ? CPrintToChatAll("%t", "Show_Next_Map", sMapName_New) : CPrintToChatAll("%t%t", "Show_Next_Map", "", "Secret");
-
- if ((StrEqual(sMapName_Old, "c6m2_bedlam") && !StrEqual(sMapName_New, "c7m1_docks")) || (StrEqual(sMapName_Old, "c9m2_lots") && !StrEqual(sMapName_New, "c14m1_junkyard")))
+ client = GetClientOfUserId(client);
+ if (client && IsClientInGame(client))
{
- g_iPointsTeam_A = L4D2Direct_GetVSCampaignScore(0);
- g_iPointsTeam_B = L4D2Direct_GetVSCampaignScore(1);
- g_bCMapTransitioned = true;
- CreateTimer(9.0, Timed_Gotomap); //this command must set ahead of the l4d2_map_transition plugin setting. Otherwise the map will be c7m1_docks/c14m1_junkyard after c6m2_bedlam/c9m2_lots
- }
- else if ((!StrEqual(sMapName_Old, "c6m2_bedlam") && StrEqual(sMapName_New, "c7m1_docks")) || (!StrEqual(sMapName_Old, "c9m2_lots") && StrEqual(sMapName_New, "c14m1_junkyard")))
- {
- g_iPointsTeam_A = L4D2Direct_GetVSCampaignScore(0);
- g_iPointsTeam_B = L4D2Direct_GetVSCampaignScore(1);
- g_bCMapTransitioned = true;
- CreateTimer(10.0, Timed_Gotomap); //this command must set ahead of the l4d2_map_transition plugin setting. Otherwise the map will be c7m1_docks/c14m1_junkyard after c6m2_bedlam/c9m2_lots
+ if(g_bDifferAbort)
+ {
+ CPrintToChat(client, "%T", "Differ_Abort", client);
+ }
+ else if(g_bMapsetInitialized)
+ {
+ CPrintToChat(client, "%T", "Auto_Show_Maplist", client);
+ }
}
return Plugin_Handled;
}
-public Action Timed_Gotomap(Handle timer)
-{
- char sMapName_New[BUF_SZ];
- GetArrayString(g_hArrayMapOrder, g_iMapsPlayed, sMapName_New, BUF_SZ);
-
- GotoMap(sMapName_New, true);
- return Plugin_Handled;
-}
-
-public Action Timed_ContinueMixmap(Handle timer)
-{
- ServerCommand("sm_fmixmap %s", cfg_exec);
- return Plugin_Handled;
-}
-
-
-// ----------------------------------------------------------
-// Commands: Console/Admin
-// ----------------------------------------------------------
-
// Loads a specified set of maps
-public Action Command_ForceMixmap(int client, int args)
+Action ForceMixmap(int client, any args)
{
Format(cfg_exec, sizeof(cfg_exec), CFG_DEFAULT);
@@ -360,7 +328,8 @@ public Action Command_ForceMixmap(int client, int args)
char sbuffer[BUF_SZ];
char arg[BUF_SZ];
GetCmdArg(1, arg, BUF_SZ);
- Format(sbuffer, sizeof(sbuffer), "cfg/%s%s.cfg", DIR_CFGS, arg);
+ if(g_bL4D2Version) Format(sbuffer, sizeof(sbuffer), "cfg/%s%s.cfg", DIR_CFGS_L4D2, arg);
+ else Format(sbuffer, sizeof(sbuffer), "cfg/%s%s.cfg", DIR_CFGS_L4D1, arg);
if (FileExists(sbuffer)) Format(cfg_exec, sizeof(cfg_exec), arg);
else
{
@@ -376,7 +345,7 @@ public Action Command_ForceMixmap(int client, int args)
Format(cfg_exec, sizeof(cfg_exec), CFG_DOUNOF);
else
{
- CReplyToCommand(client, "%t", "Invalid_Cfg");
+ CReplyToCommand(client, "%T", "Invalid_Cfg", client);
return Plugin_Handled;
}
}
@@ -384,19 +353,21 @@ public Action Command_ForceMixmap(int client, int args)
if (client) CPrintToChatAllEx(client, "%t", "Force_Start", client, cfg_exec);
PluginStartInit();
if (client == 0) g_bServerForceStart = true;
- ServerCommand("exec %s%s.cfg", DIR_CFGS, cfg_exec);
+ if(g_bL4D2Version) ServerCommand("exec %s%s.cfg", DIR_CFGS_L4D2, cfg_exec);
+ else ServerCommand("exec %s%s.cfg", DIR_CFGS_L4D1, cfg_exec);
+
g_bMapsetInitialized = true;
- CreateTimer(0.1, Timed_PostMapSet);
+ CreateTimer(0.1, Timed_PostMapSet, _, TIMER_FLAG_NO_MAPCHANGE);
return Plugin_Handled;
}
// Load a specified set of maps
-public Action Command_ManualMixmap(int client, int args)
+Action ManualMixmap(int client, any args)
{
if (args < 1)
{
- CPrintToChat(client, "%t", "Manualmixmap_Syntax");
+ CPrintToChat(client, "%T", "Manualmixmap_Syntax", client);
}
PluginStartInit();
@@ -409,50 +380,62 @@ public Action Command_ManualMixmap(int client, int args)
ServerCommand("sm_tagrank %d %d", i, i-1);
}
g_bMapsetInitialized = true;
- CreateTimer(0.1, Timed_PostMapSet);
+ CreateTimer(0.1, Timed_PostMapSet, _, TIMER_FLAG_NO_MAPCHANGE);
return Plugin_Handled;
}
-
-public Action Command_ShowAllMaps(int client, int args)
+/*
+Action ShowAllMaps(int client, any Args)
{
- CPrintToChat(client, "%t", "AllMaps_Official");
- CPrintToChat(client, "c1m1_hotel,c1m2_streets,c1m3_mall,c1m4_atrium");
- CPrintToChat(client, "c2m1_highway,c2m2_fairgrounds,c2m3_coaster,c2m4_barns,c2m5_concert");
- CPrintToChat(client, "c3m1_plankcountry,c3m2_swamp,c3m3_shantytown,c3m4_plantation");
- CPrintToChat(client, "c4m1_milltown_a,c4m2_sugarmill_a,c4m3_sugarmill_b,c4m4_milltown_b,c4m5_milltown_escape");
- CPrintToChat(client, "c5m1_waterfront,c5m2_park,c5m3_cemetery,c5m4_quarter,c5m5_bridge");
- CPrintToChat(client, "c6m1_riverbank,c6m2_bedlam,c7m1_docks,c7m2_barge,c7m3_port");
- CPrintToChat(client, "c8m1_apartment,c8m2_subway,c8m3_sewers,c8m4_interior,c8m5_rooftop");
- CPrintToChat(client, "c9m1_alleys,c9m2_lots,c14m1_junkyard,c14m2_lighthouse");
- CPrintToChat(client, "c10m1_caves,c10m2_drainage,c10m3_ranchhouse,c10m4_mainstreet,c10m5_houseboat");
- CPrintToChat(client, "c11m1_greenhouse,c11m2_offices,c11m3_garage,c11m4_terminal,c11m5_runway");
- CPrintToChat(client, "c12m1_hilltop,c12m2_traintunnel,c12m3_bridge,c12m4_barn,c12m5_cornfield");
- CPrintToChat(client, "c13m1_alpinecreek,c13m2_southpinestream,c13m3_memorialbridge,c13m4_cutthroatcreek");
- CPrintToChat(client, "%t", "AllMaps_Usage");
-
- return Plugin_Handled;
-}
-
+ CPrintToChat(client, "%T", "AllMaps_Official", client);
-// ----------------------------------------------------------
-// Commands: Client
-// ----------------------------------------------------------
+ if(g_bL4D2Version)
+ {
+ CPrintToChat(client, "c1m1_hotel,c1m2_streets,c1m3_mall,c1m4_atrium");
+ CPrintToChat(client, "c2m1_highway,c2m2_fairgrounds,c2m3_coaster,c2m4_barns,c2m5_concert");
+ CPrintToChat(client, "c3m1_plankcountry,c3m2_swamp,c3m3_shantytown,c3m4_plantation");
+ CPrintToChat(client, "c4m1_milltown_a,c4m2_sugarmill_a,c4m3_sugarmill_b,c4m4_milltown_b,c4m5_milltown_escape");
+ CPrintToChat(client, "c5m1_waterfront,c5m2_park,c5m3_cemetery,c5m4_quarter,c5m5_bridge");
+ CPrintToChat(client, "c6m1_riverbank,c6m2_bedlam,c7m1_docks,c7m2_barge,c7m3_port");
+ CPrintToChat(client, "c8m1_apartment,c8m2_subway,c8m3_sewers,c8m4_interior,c8m5_rooftop");
+ CPrintToChat(client, "c9m1_alleys,c9m2_lots,c14m1_junkyard,c14m2_lighthouse");
+ CPrintToChat(client, "c10m1_caves,c10m2_drainage,c10m3_ranchhouse,c10m4_mainstreet,c10m5_houseboat");
+ CPrintToChat(client, "c11m1_greenhouse,c11m2_offices,c11m3_garage,c11m4_terminal,c11m5_runway");
+ CPrintToChat(client, "c12m1_hilltop,c12m2_traintunnel,c12m3_bridge,c12m4_barn,c12m5_cornfield");
+ CPrintToChat(client, "c13m1_alpinecreek,c13m2_southpinestream,c13m3_memorialbridge,c13m4_cutthroatcreek");
+ }
+ else
+ {
+ CPrintToChat(client, "l4d_vs_hospital01_apartment,l4d_vs_hospital02_subway,l4d_vs_hospital03_sewers,l4d_vs_hospital04_interior,l4d_vs_hospital05_rooftop");
+ CPrintToChat(client, "l4d_vs_smalltown01_caves,l4d_vs_smalltown02_drainage,l4d_vs_smalltown03_ranchhouse,l4d_vs_smalltown04_mainstreet,l4d_vs_smalltown05_houseboat");
+ CPrintToChat(client, "l4d_vs_airport01_greenhouse,l4d_vs_airport02_offices,l4d_vs_airport03_garage,l4d_vs_airport04_terminal,l4d_vs_airport05_runway");
+ CPrintToChat(client, "l4d_vs_farm01_hilltop,l4d_vs_farm02_traintunnel,l4d_vs_farm03_bridge,l4d_vs_farm04_barn,l4d_vs_farm05_cornfield");
+ CPrintToChat(client, "l4d_garage01_alleys,l4d_garage02_lots");
+ CPrintToChat(client, "l4d_river01_docks,l4d_river02_barge,l4d_river03_port");
+ }
-/* public void RoundStart_Event(Event event, const char[] name, bool dontBroadcast)
-{
- bLeftStartArea = false;
+ CPrintToChat(client, "%T", "AllMaps_Usage", client);
+
+ return Plugin_Handled;
}
+*/
-public void LeftStartArea_Event(Event event, const char[] name, bool dontBroadcast)
-{
- bLeftStartArea = true;
-} */
-
-public Action Command_Mixmap(int client, int args)
+Action Mixmap_Cmd(int client, any args)
{
if (IsClientAndInGame(client))
{
+ if(g_ReadyUpAvailable && g_bRoundIsLive)
+ {
+ CPrintToChat(client, "%T", "Round is live", client);
+ return Plugin_Handled;
+ }
+
+ if(GetClientTeam(client) <= 1)
+ {
+ CPrintToChat(client, "%T", "Spectator Blocked", client);
+ return Plugin_Handled;
+ }
+
if (!IsBuiltinVoteInProgress())
{
Format(cfg_exec, sizeof(cfg_exec), CFG_DEFAULT);
@@ -462,7 +445,8 @@ public Action Command_Mixmap(int client, int args)
char sbuffer[BUF_SZ];
char arg[BUF_SZ];
GetCmdArg(1, arg, BUF_SZ);
- Format(sbuffer, sizeof(sbuffer), "cfg/%s%s.cfg", DIR_CFGS, arg);
+ if(g_bL4D2Version) Format(sbuffer, sizeof(sbuffer), "cfg/%s%s.cfg", DIR_CFGS_L4D2, arg);
+ else Format(sbuffer, sizeof(sbuffer), "cfg/%s%s.cfg", DIR_CFGS_L4D1, arg);
if (FileExists(sbuffer)) Format(cfg_exec, sizeof(cfg_exec), arg);
else
{
@@ -478,7 +462,7 @@ public Action Command_Mixmap(int client, int args)
Format(cfg_exec, sizeof(cfg_exec), CFG_DOUNOF);
else
{
- CPrintToChat(client, "%t", "Invalid_Cfg");
+ CPrintToChat(client, "%T", "Invalid_Cfg", client);
return Plugin_Handled;
}
}
@@ -495,22 +479,23 @@ public Action Command_Mixmap(int client, int args)
iPlayers[iNumPlayers++] = i;
}
- char cVoteTitle[32];
+ char cVoteTitle[64];
Format(cVoteTitle, sizeof(cVoteTitle), "%T", "Cvote_Title", LANG_SERVER, cfg_exec);
- hVoteMixmap = CreateBuiltinVote(VoteMixmapActionHandler, BuiltinVoteType_Custom_YesNo, BuiltinVoteAction_Cancel | BuiltinVoteAction_VoteEnd | BuiltinVoteAction_End);
+ Handle hVote = CreateBuiltinVote(VoteActionHandler, BuiltinVoteType_Custom_YesNo, BuiltinVoteAction_Cancel | BuiltinVoteAction_VoteEnd | BuiltinVoteAction_End);
- SetBuiltinVoteArgument(hVoteMixmap, cVoteTitle);
- SetBuiltinVoteInitiator(hVoteMixmap, client);
- SetBuiltinVoteResultCallback(hVoteMixmap, VoteMixmapResultHandler);
- DisplayBuiltinVote(hVoteMixmap, iPlayers, iNumPlayers, 20);
+ SetBuiltinVoteArgument(hVote, cVoteTitle);
+ SetBuiltinVoteInitiator(hVote, client);
+ SetBuiltinVoteResultCallback(hVote, VoteMixmapResultHandler);
+ DisplayBuiltinVote(hVote, iPlayers, iNumPlayers, 20);
CPrintToChatAllEx(client, "%t", "Start_Mixmap", client, cfg_exec);
- FakeClientCommand(client, "Vote Yes");
+ if(g_bL4D2Version) FakeClientCommand(client, "Vote Yes");
+ if(!g_bL4D2Version) EmitSoundToAll("ui/beep_synthtone01.wav");
}
else
{
- PrintToChat(client, "%t", "Vote_Progress");
+ CPrintToChat(client, "%T", "Vote_Blocked", client);
}
return Plugin_Handled;
@@ -519,91 +504,104 @@ public Action Command_Mixmap(int client, int args)
return Plugin_Continue;
}
-public void VoteMixmapActionHandler(Handle vote, BuiltinVoteAction action, int param1, int param2)
+// Specifiy a rank for a given tag
+Action TagRank(any args)
{
- switch (action)
+ if (args < 2)
{
- case BuiltinVoteAction_End:
- {
- hVoteMixmap = null;
- CloseHandle(vote);
- }
- case BuiltinVoteAction_Cancel:
- {
- DisplayBuiltinVoteFail(vote, view_as(param1));
- }
-/* case BuiltinVoteAction_Select:
- {
- char cItemVal[64];
- char cItemName[64];
- GetBuiltinVoteItem(vote, param2, cItemVal, sizeof(cItemVal), cItemName, sizeof(cItemName));
- } */
+ ReplyToCommand(0, "Syntax: sm_tagrank