Advertisement
Guest User

L4D Force Mission Changer

a guest
Mar 28th, 2015
300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.30 KB | None | 0 0
  1. /**
  2. * L4D Force Mission Changer
  3. * For Sourcemod 1.2.0
  4. *
  5. * CREDITS:
  6. * DDR Khat
  7. * Red Alex
  8. *
  9. * Version 1.4.0: New plugin and config name sm_l4d_mapchanger (old sm_l4dvs_mapchanger.smx will be automatically deleted)
  10. * Hook change gamemode event and autoload mission list for new gamemode on the server
  11. * Add support sm_l4dco_mapchanger.txt and sm_l4dvs_mapchanger.txt for coop and versus gamemodes
  12. * Plugin stop activity if discovered survival gamemode and wait for change gamemode to coop or versus or change map
  13. * Version 1.3.6: Fix autoloading of a following map bug
  14. * Fix custom settings for versus map bug
  15. * Version 1.3.5: Add autoloading of a following map of the list if the server has become empty
  16. * Version 1.3.4: Any critical bugs fixes (thx Red Alex)
  17. * Version 1.3.3: Add support of wrong custom versus map
  18. * Add server commands:
  19. * sm_l4d_fmc_crec_add - Add custom value sm_l4d_fmc_crec for the specified map. Max 50.
  20. * Use: sm_l4d_fmc_crec_add <existing custom map> <custom sm_l4d_fmc_crec integer value (max 99)> <custom sm_l4d_fmc_re_timer_block float value>
  21. * sm_l4d_fmc_crec_clear - Clear all custom value sm_l4d_fmc_crec.
  22. * sm_l4d_fmc_crec_list - Show all custom value sm_l4d_fmc_crec.
  23. * Manual set next mission name in sm_l4dvs_mapchanger.txt
  24. * Add displays and log team winner index at round_end in debug mode
  25. * Version 1.3.2: Fix mission announce bug
  26. * Add cvar sm_l4d_fmc_dbug write event log to file
  27. * Add cvar sm_l4d_fmc_re_timer_block block double event round_end
  28. * Version 1.3.1: Ready for L4D version 1.0.1.2
  29. */
  30.  
  31. #pragma semicolon 1
  32. #include <sourcemod>
  33.  
  34. #define Version "1.4.0"
  35. #define MAX_ARRAY_LINE 50
  36. #define MAX_MAPNAME_LEN 64
  37. #define MAX_CREC_LEN 2
  38. #define MAX_REBFl_LEN 8
  39.  
  40. new Handle:cvarAnnounce = INVALID_HANDLE;
  41. new Handle:Allowed = INVALID_HANDLE;
  42. new Handle:AllowedDie = INVALID_HANDLE;
  43. new Handle:DebugEvent = INVALID_HANDLE;
  44. new Handle:DefM;
  45. new Handle:CheckRoundCounter;
  46. new Handle:ChDelayVS;
  47. new Handle:ChDelayCOOP;
  48. new Handle:TimerRoundEndBlockVS;
  49.  
  50. new Handle:hKVSettings = INVALID_HANDLE;
  51.  
  52. new Handle:CurrentGameMode = INVALID_HANDLE;
  53.  
  54. new Handle:logfile;
  55.  
  56. new String:FMC_FileSettings[128];
  57. new String:current_map[64];
  58. new String:announce_map[64];
  59. new String:next_mission_def[64];
  60. new String:next_mission_force[64];
  61. new String:force_mission_name[64];
  62. new RoundEndCounter = 0;
  63. new RoundEndCounterValue = 0;
  64. new RoundEndBlock = 0;
  65. new Float:RoundEndBlockValue = 0.0;
  66.  
  67. new String:MapNameArrayLine[MAX_ARRAY_LINE][MAX_MAPNAME_LEN];
  68. new String:CrecNumArrayLine[MAX_ARRAY_LINE][MAX_CREC_LEN];
  69. new String:reBlkFlArrayLine[MAX_ARRAY_LINE][MAX_REBFl_LEN];
  70. new g_ArrayCount = 0;
  71.  
  72. public Plugin:myinfo =
  73. {
  74. name = "L4D Force Mission Changer",
  75. author = "Dionys",
  76. description = "Force change to next mission when current mission end.",
  77. version = Version,
  78. url = "skiner@inbox.ru"
  79. };
  80.  
  81. public OnPluginStart()
  82. {
  83. decl String:ModName[50];
  84. GetGameFolderName(ModName, sizeof(ModName));
  85.  
  86. if(!StrEqual(ModName, "left4dead2", false))
  87. SetFailState("Use this Left 4 Dead only.");
  88.  
  89. hKVSettings=CreateKeyValues("ForceMissionChangerSettings");
  90.  
  91. HookEvent("round_end", Event_RoundEnd);
  92. HookEvent("finale_win", Event_FinalWin);
  93. HookEvent("mission_lost", Event_FinalLost);
  94.  
  95. CreateConVar("sm_l4d_fmc_version", Version, "Version of L4D Force Mission Changer plugin.", FCVAR_NOTIFY);
  96. DebugEvent = CreateConVar("sm_l4d_fmc_dbug", "0", "on-off Write event to log file.");
  97. Allowed = CreateConVar("sm_l4d_fmc", "1", "Enables Force changelevel when mission end.");
  98. AllowedDie = CreateConVar("sm_l4d_fmc_ifdie", "1", "Enables Force changelevel when all player die on final map in coop gamemode.");
  99. DefM = CreateConVar("sm_l4d_fmc_def", "l4d_vs_hospital01_apartment", "Mission for change by default.");
  100. CheckRoundCounter = CreateConVar("sm_l4d_fmc_crec", "4", "Quantity of events RoundEnd before force of changelevel in versus: 4 for l4d <> 1.0.1.2");
  101. ChDelayVS = CreateConVar("sm_l4d_fmc_chdelayvs", "0.0", "Delay before versus mission change (float in sec).");
  102. ChDelayCOOP = CreateConVar("sm_l4d_fmc_chdelaycoop", "0.0", "Delay before coop mission change (float in sec).");
  103. TimerRoundEndBlockVS = CreateConVar("sm_l4d_fmc_re_timer_block", "0.5", "Time in which current event round_end is not considered (float in sec).");
  104. cvarAnnounce = CreateConVar("sm_l4d_fmc_announce", "1", "Enables next mission to advertise to players.");
  105.  
  106. //For custom crec
  107. RegServerCmd("sm_l4d_fmc_crec_add", Command_CrecAdd, "Add custom value sm_l4d_fmc_crec and sm_l4d_fmc_re_timer_block for the specified map. Max 50.");
  108. RegServerCmd("sm_l4d_fmc_crec_clear", Command_CrecClear, "Clear all custom value sm_l4d_fmc_crec and sm_l4d_fmc_re_timer_block.");
  109. RegServerCmd("sm_l4d_fmc_crec_list", Command_CrecList, "Show all custom value sm_l4d_fmc_crec and sm_l4d_fmc_re_timer_block.");
  110.  
  111. CurrentGameMode = FindConVar("mp_gamemode");
  112. HookConVarChange(CurrentGameMode, OnCVGameModeChange);
  113.  
  114. logfile = OpenFile("/addons/sourcemod/logs/fmc_event.log", "w");
  115. }
  116.  
  117. public OnMapStart()
  118. {
  119. // Execute the config file
  120. AutoExecConfig(true, "sm_l4d_mapchanger");
  121.  
  122. RoundEndCounter = 0;
  123. RoundEndBlock = 0;
  124.  
  125. if (GetConVarInt(DebugEvent) == 1)
  126. WriteFileLine(logfile, "***New map start***");
  127.  
  128. if(GetConVarInt(Allowed) == 1)
  129. {
  130. PluginInitialization();
  131.  
  132. if (GetConVarInt(DebugEvent) == 1)
  133. {
  134. PrintToChatAll("\x04[FMC DEBUG]\x03 MapStart: RECV: \"%d\" REBV: \"%d\"", RoundEndCounterValue, RoundEndBlockValue);
  135. decl String:mBuffer[128];
  136. Format(mBuffer, sizeof(mBuffer), "MapStart: RECV: \"%d\" REBV: \"%d\"", RoundEndCounterValue, RoundEndBlockValue);
  137. WriteFileLine(logfile, mBuffer);
  138. }
  139. }
  140. }
  141.  
  142. public OnMapEnd()
  143. {
  144. if (GetConVarInt(DebugEvent) == 1)
  145. {
  146. PrintToChatAll("\x04[FMC DEBUG]\x03 MapEnd");
  147. FlushFile(logfile);
  148. WriteFileLine(logfile, "***Map end***");
  149. }
  150. }
  151.  
  152. public OnClientPutInServer(client)
  153. {
  154. // Make the announcement in 20 seconds unless announcements are turned off
  155. if(client && !IsFakeClient(client) && GetConVarBool(cvarAnnounce))
  156. CreateTimer(20.0, TimerAnnounce, client);
  157. }
  158.  
  159. public OnClientDisconnect(client)
  160. {
  161. if (GetClientCount(true) <= 0)
  162. {
  163. decl String:EmptyServerMap[64];
  164.  
  165. if (StrEqual(next_mission_force, "none") == true) EmptyServerMap = next_mission_def;
  166. else EmptyServerMap = next_mission_force;
  167.  
  168. if (GetConVarInt(DebugEvent) == 1)
  169. {
  170. decl String:mBuffer[128];
  171. Format(mBuffer, sizeof(mBuffer), "MODE: \"%d\" MAP: \"%s\" EVENT: changemission to \"%s\" REASON: Server is empty", l4d_gamemode(), current_map, EmptyServerMap);
  172. WriteFileLine(logfile, mBuffer);
  173. }
  174.  
  175. ServerCommand("changelevel %s", EmptyServerMap);
  176. }
  177. }
  178.  
  179. public Action:Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
  180. {
  181. if (RoundEndBlock == 0)
  182. {
  183. RoundEndCounter += 1;
  184. RoundEndBlock = 1;
  185. CreateTimer(GetConVarFloat(TimerRoundEndBlockVS), TimerRoundEndBlock);
  186. }
  187.  
  188. if (GetConVarInt(DebugEvent) == 1)
  189. {
  190. new winnerteam = GetEventInt(event, "winner");
  191.  
  192. PrintToChatAll("\x04[FMC DEBUG]\x03 MODE: \"%d\" EVENT: \"%s\" NUM: \"%d\" TWIN: \"%d\"", l4d_gamemode(), name, RoundEndCounter, winnerteam);
  193. decl String:mBuffer[128];
  194. Format(mBuffer, sizeof(mBuffer), "MODE: \"%d\" MAP: \"%s\" EVENT: \"%s\" NUM: \"%d\" TWIN: \"%d\"", l4d_gamemode(), current_map, name, RoundEndCounter, winnerteam);
  195. WriteFileLine(logfile, mBuffer);
  196. }
  197.  
  198. if(GetConVarInt(Allowed) == 1 && l4d_gamemode() == 2 && StrEqual(next_mission_force, "none") != true && GetConVarInt(CheckRoundCounter) != 0 && RoundEndCounter >= RoundEndCounterValue)
  199. {
  200. if (GetConVarInt(DebugEvent) == 1)
  201. {
  202. PrintToChatAll("\x04[FMC DEBUG]\x03 MODE: \"%d\" EVENT: START FMC TIMER ", l4d_gamemode());
  203. decl String:mBuffer[128];
  204. Format(mBuffer, sizeof(mBuffer), "MODE: \"%d\" MAP: \"%s\" EVENT: START FMC TIMER ", l4d_gamemode(), current_map);
  205. WriteFileLine(logfile, mBuffer);
  206. }
  207.  
  208. CreateTimer(RoundEndBlockValue, TimerChDelayVS);
  209. RoundEndCounter = 0;
  210. }
  211. }
  212.  
  213. public Action:Event_FinalWin(Handle:event, const String:name[], bool:dontBroadcast)
  214. {
  215. if (GetConVarInt(DebugEvent) == 1)
  216. {
  217. PrintToChatAll("\x04[FMC DEBUG]\x03 MODE: \"%d\" EVENT: \"%s\" ", l4d_gamemode(), name);
  218. decl String:mBuffer[128];
  219. Format(mBuffer, sizeof(mBuffer), "MODE: \"%d\" MAP: \"%s\" EVENT: \"%s\" ", l4d_gamemode(), current_map, name);
  220. WriteFileLine(logfile, mBuffer);
  221. }
  222.  
  223. if(GetConVarInt(Allowed) == 1 && l4d_gamemode() == 1 && StrEqual(next_mission_force, "none") != true)
  224. CreateTimer(GetConVarFloat(ChDelayCOOP), TimerChDelayCOOP);
  225. }
  226.  
  227. public Action:Event_FinalLost(Handle:event, const String:name[], bool:dontBroadcast)
  228. {
  229. if (GetConVarInt(DebugEvent) == 1)
  230. {
  231. PrintToChatAll("\x04[FMC DEBUG]\x03 MODE: \"%d\" EVENT: \"%s\" ", l4d_gamemode(), name);
  232. decl String:mBuffer[128];
  233. Format(mBuffer, sizeof(mBuffer), "MODE: \"%d\" MAP: \"%s\" EVENT: \"%s\" ", l4d_gamemode(), current_map, name);
  234. WriteFileLine(logfile, mBuffer);
  235. }
  236.  
  237. if(GetConVarInt(Allowed) == 1 && GetConVarInt(AllowedDie) && l4d_gamemode() == 1 && StrEqual(next_mission_force, "none") != true)
  238. CreateTimer(GetConVarFloat(ChDelayCOOP), TimerChDelayCOOP);
  239. }
  240.  
  241. public OnCVGameModeChange(Handle:convar, const String:oldValue[], const String:newValue[])
  242. {
  243. //If game mode actually changed
  244. if (strcmp(oldValue, newValue) != 0)
  245. {
  246. new GameMode = l4d_gamemode();
  247. if (GameMode == 1 || GameMode == 2 || GameMode == 3)
  248. {
  249. HookEvent("round_end", Event_RoundEnd);
  250. HookEvent("finale_win", Event_FinalWin);
  251. HookEvent("mission_lost", Event_FinalLost);
  252. }
  253.  
  254. if(GetConVarInt(Allowed) == 1)
  255. PluginInitialization();
  256. }
  257. }
  258.  
  259. public Action:TimerAnnounce(Handle:timer, any:client)
  260. {
  261. if(IsClientInGame(client))
  262. {
  263. if (StrEqual(next_mission_force, "none") != true)
  264. {
  265. PrintToChat(client, "\x04[FMC]\x03 Is a finale of mission. Finish them all!");
  266. PrintToChat(client, "\x04[FMC]\x03 Next mission: \x04%s.", announce_map);
  267. }
  268. else
  269. PrintToChat(client, "\x04[FMC]\x03 A mission proceeds. Have fun!");
  270. }
  271. }
  272.  
  273. public Action:TimerRoundEndBlock(Handle:timer)
  274. {
  275. RoundEndBlock = 0;
  276. }
  277.  
  278. public Action:TimerChDelayVS(Handle:timer)
  279. {
  280. if (GetConVarInt(DebugEvent) == 1)
  281. {
  282. PrintToChatAll("\x04[FMC DEBUG]\x03 MODE: \"%d\" EVENT: changemission to \"%s\" ", l4d_gamemode(), next_mission_force);
  283. decl String:mBuffer[128];
  284. Format(mBuffer, sizeof(mBuffer), "MODE: \"%d\" MAP: \"%s\" EVENT: changemission to \"%s\" ", l4d_gamemode(), current_map, next_mission_force);
  285. WriteFileLine(logfile, mBuffer);
  286. }
  287.  
  288. ServerCommand("changelevel %s", next_mission_force);
  289. }
  290.  
  291. public Action:TimerChDelayCOOP(Handle:timer)
  292. {
  293. ServerCommand("changelevel %s", next_mission_force);
  294. }
  295.  
  296. public Action:Command_CrecClear(args)
  297. {
  298. g_ArrayCount = 0;
  299. PrintToServer("[FMC] Custom value sm_l4d_fmc_crec now is clear.");
  300. }
  301.  
  302. public Action:Command_CrecAdd(args)
  303. {
  304. if (g_ArrayCount == MAX_ARRAY_LINE)
  305. {
  306. PrintToServer("[FMC] Max number of array line for sm_l4d_fmc_crec_add reached.");
  307. return;
  308. }
  309.  
  310. decl String:cmdarg1[MAX_MAPNAME_LEN];
  311. GetCmdArg(1, cmdarg1, sizeof(cmdarg1));
  312. decl String:cmdarg2[MAX_CREC_LEN];
  313. GetCmdArg(2, cmdarg2, sizeof(cmdarg2));
  314. decl String:cmdarg3[MAX_REBFl_LEN];
  315. GetCmdArg(3, cmdarg3, sizeof(cmdarg3));
  316.  
  317. // Check for doubles
  318. new bool:isDouble = false;
  319. for (new i = 0; i < g_ArrayCount; i++)
  320. {
  321. if (StrEqual(cmdarg1, MapNameArrayLine[i]) == true)
  322. {
  323. isDouble = true;
  324. break;
  325. }
  326. }
  327.  
  328. if (IsMapValid(cmdarg1) && StringToInt(cmdarg2) != 0 && StringToFloat(cmdarg3) != 0.0)
  329. {
  330. if (!isDouble)
  331. {
  332. strcopy(MapNameArrayLine[g_ArrayCount], MAX_MAPNAME_LEN, cmdarg1);
  333. strcopy(CrecNumArrayLine[g_ArrayCount], MAX_CREC_LEN, cmdarg2);
  334. strcopy(reBlkFlArrayLine[g_ArrayCount], MAX_REBFl_LEN, cmdarg3);
  335. g_ArrayCount++;
  336. }
  337. }
  338. else
  339. PrintToServer("[FMC] Error command. Use: sm_l4d_fmc_crec_add <existing custom map> <custom sm_l4d_fmc_crec integer value (max 99)> <custom sm_l4d_fmc_re_timer_block float value>.");
  340. }
  341.  
  342. public Action:Command_CrecList(args)
  343. {
  344. PrintToServer("[FMC] Custom value sm_l4d_fmc_crec and sm_l4d_fmc_re_timer_block list:");
  345. for (new i = 0; i < g_ArrayCount; i++)
  346. {
  347. PrintToServer("[%d] %s - %s - %s", i, MapNameArrayLine[i], CrecNumArrayLine[i], reBlkFlArrayLine[i]);
  348. }
  349. PrintToServer("[FMC] Custom value sm_l4d_fmc_crec and sm_l4d_fmc_re_timer_block list end.");
  350. }
  351.  
  352. l4d_gamemode()
  353. {
  354. // 1 - coop / 2 - versus / 3 - survival / or false (thx DDR Khat for code)
  355. new String:gmode[32];
  356. GetConVarString(FindConVar("mp_gamemode"), gmode, sizeof(gmode));
  357.  
  358. if (strcmp(gmode, "coop") == 0)
  359. {
  360. return 1;
  361. }
  362. else if (strcmp(gmode, "versus", false) == 0)
  363. {
  364. return 2;
  365. }
  366. else if (strcmp(gmode, "survival", false) == 0)
  367. {
  368. return 3;
  369. }
  370. else
  371. {
  372. return false;
  373. }
  374. }
  375.  
  376. ClearKV(Handle:kvhandle)
  377. {
  378. KvRewind(kvhandle);
  379. if (KvGotoFirstSubKey(kvhandle))
  380. {
  381. do
  382. {
  383. KvDeleteThis(kvhandle);
  384. KvRewind(kvhandle);
  385. }
  386. while (KvGotoFirstSubKey(kvhandle));
  387. KvRewind(kvhandle);
  388. }
  389. }
  390.  
  391. PluginInitialization()
  392. {
  393. decl String:OldPlugin[128];
  394. BuildPath(Path_SM, OldPlugin, sizeof(OldPlugin), "plugins/sm_l4dvs_mapchanger.smx");
  395. if(FileExists(OldPlugin))
  396. {
  397. ServerCommand("sm plugins unload sm_l4dvs_mapchanger");
  398. DeleteFile(OldPlugin);
  399. PrintToServer("[FMC] Old sm_l4dvs_mapchanger has been unload and deleted.");
  400. }
  401.  
  402. ClearKV(hKVSettings);
  403. new GameMode = l4d_gamemode();
  404. if (GameMode == 1)
  405. {
  406. BuildPath(Path_SM, FMC_FileSettings, 128, "data/sm_l4dco_mapchanger.txt");
  407. PrintToServer("[FMC] Discovered coop gamemode. Link to sm_l4dco_mapchanger.");
  408. }
  409. else if (GameMode == 2)
  410. {
  411. BuildPath(Path_SM, FMC_FileSettings, 128, "data/sm_l4dvs_mapchanger.txt");
  412. PrintToServer("[FMC] Discovered versus gamemode. Link to sm_l4dvs_mapchanger.");
  413. }
  414. else if (GameMode == 3)
  415. {
  416. SetConVarInt(Allowed, 0);
  417. PrintToServer("[FMC] Discovered survival gamemode. Plugin stop activity. Wait for coop or versus.");
  418. return;
  419. }
  420. else
  421. SetFailState("[FMC] Current gamemode dont checked. Shutdown.");
  422.  
  423. if(!FileToKeyValues(hKVSettings, FMC_FileSettings))
  424. SetFailState("Force Mission Changer settings not found! Shutdown.");
  425.  
  426. next_mission_force = "none";
  427. GetCurrentMap(current_map, 64);
  428. GetConVarString(DefM, next_mission_def, 64);
  429.  
  430. KvRewind(hKVSettings);
  431. if(KvJumpToKey(hKVSettings, current_map))
  432. {
  433. KvGetString(hKVSettings, "next mission map", next_mission_force, 64, next_mission_def);
  434. KvGetString(hKVSettings, "next mission name", force_mission_name, 64, "none");
  435. }
  436. KvRewind(hKVSettings);
  437.  
  438. if (StrEqual(next_mission_force, "none") != true)
  439. {
  440. if (!IsMapValid(next_mission_force))
  441. next_mission_force = next_mission_def;
  442.  
  443. if (StrEqual(force_mission_name, "none") != true)
  444. announce_map = force_mission_name;
  445. else
  446. announce_map = next_mission_force;
  447.  
  448. RoundEndCounterValue = 0;
  449. RoundEndBlockValue = 0.0;
  450. for (new i = 0; i < g_ArrayCount; i++)
  451. {
  452. if (StrEqual(current_map, MapNameArrayLine[i]) == true)
  453. {
  454. RoundEndCounterValue = StringToInt(CrecNumArrayLine[g_ArrayCount]);
  455. RoundEndBlockValue = StringToFloat(reBlkFlArrayLine[g_ArrayCount]);
  456. break;
  457. }
  458. }
  459. if (RoundEndCounterValue == 0)
  460. RoundEndCounterValue = GetConVarInt(CheckRoundCounter);
  461. if (RoundEndBlockValue == 0.0)
  462. RoundEndBlockValue = GetConVarFloat(ChDelayVS);
  463. }
  464. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement