Guest User

galileo.sma

a guest
Dec 25th, 2013
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 75.92 KB | None | 0 0
  1. new const PLUGIN_VERSION[] = "1.1 $Revision: 290 $"; // $Date: 2009-02-26 11:20:25 -0500 (Thu, 26 Feb 2009) $;
  2.  
  3. #include <amxmodx>
  4. #include <amxmisc>
  5.  
  6. #pragma semicolon 1
  7.  
  8. #define TASKID_EMPTYSERVER 98176977
  9. #define TASKID_REMINDER 52691153
  10.  
  11. #define RTV_CMD_STANDARD 1
  12. #define RTV_CMD_SHORTHAND 2
  13. #define RTV_CMD_DYNAMIC 4
  14.  
  15. #define SOUND_GETREADYTOCHOOSE 1
  16. #define SOUND_COUNTDOWN 2
  17. #define SOUND_TIMETOCHOOSE 4
  18. #define SOUND_RUNOFFREQUIRED 8
  19.  
  20. #define MAPFILETYPE_SINGLE 1
  21. #define MAPFILETYPE_GROUPS 2
  22.  
  23. #define SHOWSTATUS_VOTE 1
  24. #define SHOWSTATUS_END 2
  25.  
  26. #define SHOWSTATUSTYPE_COUNT 1
  27. #define SHOWSTATUSTYPE_PERCENTAGE 2
  28.  
  29. #define ANNOUNCECHOICE_PLAYERS 1
  30. #define ANNOUNCECHOICE_ADMINS 2
  31.  
  32. #define MAX_NOMINATION_CNT 5
  33.  
  34. #define MAX_PREFIX_CNT 32
  35. #define MAX_RECENT_MAP_CNT 16
  36.  
  37. #define MAX_PLAYER_CNT 32
  38. #define MAX_STANDARD_MAP_CNT 25
  39. #define MAX_MAPNAME_LEN 31
  40. #define MAX_MAPS_IN_VOTE 8
  41. #define MAX_NOM_MATCH_CNT 1000
  42.  
  43. #define VOTE_IN_PROGRESS 1
  44. #define VOTE_FORCED 2
  45. #define VOTE_IS_RUNOFF 4
  46. #define VOTE_IS_OVER 8
  47. #define VOTE_IS_EARLY 16
  48. #define VOTE_HAS_EXPIRED 32
  49.  
  50. #define SRV_START_CURRENTMAP 1
  51. #define SRV_START_NEXTMAP 2
  52. #define SRV_START_MAPVOTE 3
  53. #define SRV_START_RANDOMMAP 4
  54.  
  55. #define LISTMAPS_USERID 0
  56. #define LISTMAPS_LAST 1
  57.  
  58. #define TIMELIMIT_NOT_SET -1.0
  59.  
  60. new MENU_CHOOSEMAP[] = "gal_menuChooseMap";
  61.  
  62. new DIR_CONFIGS[64];
  63. new DIR_DATA[64];
  64.  
  65. new CLR_RED[3]; // \r
  66. new CLR_WHITE[3]; // \w
  67. new CLR_YELLOW[3]; // \y
  68. new CLR_GREY[3]; // \d
  69.  
  70. new bool:g_wasLastRound = false;
  71. new g_mapPrefix[MAX_PREFIX_CNT][16], g_mapPrefixCnt = 1;
  72. new g_currentMap[MAX_MAPNAME_LEN+1], Float:g_originalTimelimit = TIMELIMIT_NOT_SET;
  73.  
  74. new g_nomination[MAX_PLAYER_CNT + 1][MAX_NOMINATION_CNT + 1], g_nominationCnt, g_nominationMatchesMenu[MAX_PLAYER_CNT];
  75. //new g_nonOverlapHudSync;
  76.  
  77. new g_voteWeightFlags[32];
  78.  
  79. new Array:g_emptyCycleMap, bool:g_isUsingEmptyCycle = false, g_emptyMapCnt = 0;
  80.  
  81. new Array:g_mapCycle;
  82.  
  83. new g_recentMap[MAX_RECENT_MAP_CNT][MAX_MAPNAME_LEN + 1], g_cntRecentMap;
  84. new Array:g_nominationMap, g_nominationMapCnt;
  85. new Array:g_fillerMap;
  86. new Float:g_rtvWait;
  87. new bool:g_rockedVote[MAX_PLAYER_CNT + 1], g_rockedVoteCnt;
  88.  
  89. new g_mapChoice[MAX_MAPS_IN_VOTE + 1][MAX_MAPNAME_LEN + 1], g_choiceCnt, g_choiceMax;
  90. new bool:g_voted[MAX_PLAYER_CNT + 1] = {true, ...}, g_mapVote[MAX_MAPS_IN_VOTE + 1];
  91. new g_voteStatus, g_voteDuration, g_votesCast;
  92. new g_runoffChoice[2];
  93. new g_vote[512];
  94. new bool:g_handleMapChange = true;
  95.  
  96. new g_refreshVoteStatus = true, g_voteTallyType[3], g_snuffDisplay[MAX_PLAYER_CNT + 1];
  97.  
  98. new g_menuChooseMap;
  99.  
  100. new g_pauseMapEndVoteTask, g_pauseMapEndManagerTask;
  101.  
  102. new cvar_extendmapMax, cvar_extendmapStep;
  103. new cvar_endOnRound, cvar_endOfMapVote;
  104. new cvar_rtvWait, cvar_rtvRatio, cvar_rtvCommands;
  105. new cvar_cmdVotemap, cvar_cmdListmaps, cvar_listmapsPaginate;
  106. new cvar_banRecent, cvar_banRecentStyle, cvar_voteDuration;
  107. new cvar_nomMapFile, cvar_nomPrefixes;
  108. new cvar_nomQtyUsed, cvar_nomPlayerAllowance;
  109. new cvar_voteExpCountdown, cvar_voteWeightFlags, cvar_voteWeight;
  110. new cvar_voteMapChoiceCnt, cvar_voteAnnounceChoice, cvar_voteUniquePrefixes;
  111. new cvar_voteMapFile, cvar_rtvReminder;
  112. new cvar_srvStart;
  113. new cvar_emptyWait, cvar_emptyMapFile, cvar_emptyCycle;
  114. new cvar_runoffEnabled, cvar_runoffDuration;
  115. new cvar_voteStatus, cvar_voteStatusType;
  116. new cvar_soundsMute;
  117.  
  118. public plugin_init()
  119. {
  120. // build version information
  121. new jnk[1], version[8], rev[8];
  122. parse(PLUGIN_VERSION, version, sizeof(version)-1, jnk, sizeof(jnk)-1, rev, sizeof(rev)-1, jnk, sizeof(jnk)-1);
  123. new pluginVersion[16];
  124. formatex(pluginVersion, sizeof(pluginVersion)-1, "%s.%s", version, rev);
  125.  
  126. register_plugin("Galileo", pluginVersion, "Brad Jones");
  127.  
  128. register_cvar("gal_version", pluginVersion, FCVAR_SERVER|FCVAR_SPONLY);
  129. set_cvar_string("gal_version", pluginVersion);
  130.  
  131. register_cvar("gal_server_starting", "1", FCVAR_SPONLY);
  132. cvar_emptyCycle = register_cvar("gal_in_empty_cycle", "0", FCVAR_SPONLY);
  133.  
  134. register_cvar("gal_debug", "0");
  135.  
  136. register_dictionary("common.txt");
  137. register_dictionary("nextmap.txt");
  138. register_dictionary("galileo.txt");
  139.  
  140. if (module_exists("cstrike"))
  141. {
  142. register_event("HLTV", "event_round_start", "a", "1=0", "2=0");
  143. }
  144. else if (module_exists("dodx"))
  145. {
  146. register_event("RoundState", "event_round_start", "a", "1=1");
  147. }
  148.  
  149. register_event("TextMsg", "event_game_commencing", "a", "2=#Game_Commencing", "2=#Game_will_restart_in");
  150. register_event("30", "event_intermission", "a");
  151.  
  152. g_menuChooseMap = register_menuid(MENU_CHOOSEMAP);
  153. register_menucmd(g_menuChooseMap, MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_5|MENU_KEY_6|MENU_KEY_7|MENU_KEY_8|MENU_KEY_9|MENU_KEY_0, "vote_handleChoice");
  154.  
  155. register_clcmd("say", "cmd_say", -1);
  156. register_clcmd("say nextmap", "cmd_nextmap", 0, "- displays nextmap");
  157. register_clcmd("say currentmap", "cmd_currentmap", 0, "- display current map");
  158. register_clcmd("say ff", "cmd_ff", 0, "- display friendly fire status"); // grrface
  159. register_clcmd("votemap", "cmd_HL1_votemap");
  160. register_clcmd("listmaps", "cmd_HL1_listmaps");
  161.  
  162. register_concmd("gal_startvote", "cmd_startVote", ADMIN_MAP);
  163. register_concmd("gal_createmapfile", "cmd_createMapFile", ADMIN_RCON);
  164.  
  165. register_cvar("amx_nextmap", "", FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY);
  166. cvar_extendmapMax = register_cvar("amx_extendmap_max", "90");
  167. cvar_extendmapStep = register_cvar("amx_extendmap_step", "15");
  168.  
  169. cvar_cmdVotemap = register_cvar("gal_cmd_votemap", "0");
  170. cvar_cmdListmaps = register_cvar("gal_cmd_listmaps", "2");
  171.  
  172. cvar_listmapsPaginate = register_cvar("gal_listmaps_paginate", "10");
  173.  
  174. cvar_banRecent = register_cvar("gal_banrecent", "3");
  175. cvar_banRecentStyle = register_cvar("gal_banrecentstyle", "1");
  176.  
  177. cvar_endOnRound = register_cvar("gal_endonround", "1");
  178. cvar_endOfMapVote = register_cvar("gal_endofmapvote", "1");
  179.  
  180. cvar_emptyWait = register_cvar("gal_emptyserver_wait", "0");
  181. cvar_emptyMapFile = register_cvar("gal_emptyserver_mapfile", "");
  182.  
  183. cvar_srvStart = register_cvar("gal_srv_start", "0");
  184.  
  185. cvar_rtvCommands = register_cvar("gal_rtv_commands", "3");
  186. cvar_rtvWait = register_cvar("gal_rtv_wait", "10");
  187. cvar_rtvRatio = register_cvar("gal_rtv_ratio", "0.60");
  188. cvar_rtvReminder = register_cvar("gal_rtv_reminder", "2");
  189.  
  190. cvar_nomPlayerAllowance = register_cvar("gal_nom_playerallowance", "2");
  191. cvar_nomMapFile = register_cvar("gal_nom_mapfile", "mapcycle");
  192. cvar_nomPrefixes = register_cvar("gal_nom_prefixes", "1");
  193. cvar_nomQtyUsed = register_cvar("gal_nom_qtyused", "0");
  194.  
  195. cvar_voteWeight = register_cvar("gal_vote_weight", "2");
  196. cvar_voteWeightFlags = register_cvar("gal_vote_weightflags", "y");
  197. cvar_voteMapFile = register_cvar("gal_vote_mapfile", "mapcycle.txt");
  198. cvar_voteDuration = register_cvar("gal_vote_duration", "15");
  199. cvar_voteExpCountdown = register_cvar("gal_vote_expirationcountdown", "1");
  200. cvar_voteMapChoiceCnt = register_cvar("gal_vote_mapchoices", "5");
  201. cvar_voteAnnounceChoice = register_cvar("gal_vote_announcechoice", "1");
  202. cvar_voteStatus = register_cvar("gal_vote_showstatus", "1");
  203. cvar_voteStatusType = register_cvar("gal_vote_showstatustype", "2");
  204. cvar_voteUniquePrefixes = register_cvar("gal_vote_uniqueprefixes", "0");
  205.  
  206. cvar_runoffEnabled = register_cvar("gal_runoff_enabled", "0");
  207. cvar_runoffDuration = register_cvar("gal_runoff_duration", "10");
  208.  
  209. cvar_soundsMute = register_cvar("gal_sounds_mute", "0");
  210.  
  211. //set_task(1.0, "dbg_test",_,_,_,"a", 15);
  212. }
  213.  
  214. public dbg_fakeVotes()
  215. {
  216. if (!(g_voteStatus & VOTE_IS_RUNOFF))
  217. {
  218. g_mapVote[0] += 2; // map 1
  219. g_mapVote[1] += 0; // map 2
  220. g_mapVote[2] += 6; // map 3
  221. g_mapVote[3] += 0; // map 4
  222. g_mapVote[4] += 0; // map 5
  223. g_mapVote[5] += 4; // extend option
  224.  
  225. g_votesCast = g_mapVote[0] + g_mapVote[1] + g_mapVote[2] + g_mapVote[3] + g_mapVote[4] + g_mapVote[5];
  226. }
  227. else if (g_voteStatus & VOTE_IS_RUNOFF)
  228. {
  229. g_mapVote[0] += 1; // choice 1
  230. g_mapVote[1] += 0; // choice 2
  231.  
  232. g_votesCast = g_mapVote[0] + g_mapVote[1];
  233. }
  234. }
  235.  
  236. public plugin_cfg()
  237. {
  238. formatex(DIR_CONFIGS[get_configsdir(DIR_CONFIGS, sizeof(DIR_CONFIGS)-1)], sizeof(DIR_CONFIGS)-1, "/galileo");
  239. formatex(DIR_DATA[get_datadir(DIR_DATA, sizeof(DIR_DATA)-1)], sizeof(DIR_DATA)-1, "/galileo");
  240.  
  241. server_cmd("exec %s/galileo.cfg", DIR_CONFIGS);
  242. server_exec();
  243.  
  244. if (colored_menus())
  245. {
  246. copy(CLR_RED, 2, "\r");
  247. copy(CLR_WHITE, 2, "\w");
  248. copy(CLR_YELLOW, 2, "\y");
  249. }
  250.  
  251. g_rtvWait = get_pcvar_float(cvar_rtvWait);
  252. get_pcvar_string(cvar_voteWeightFlags, g_voteWeightFlags, sizeof(g_voteWeightFlags)-1);
  253. get_mapname(g_currentMap, sizeof(g_currentMap)-1);
  254. g_choiceMax = max(min(MAX_MAPS_IN_VOTE, get_pcvar_num(cvar_voteMapChoiceCnt)), 2);
  255. // g_nonOverlapHudSync = CreateHudSyncObj();
  256. g_fillerMap = ArrayCreate(32);
  257. g_nominationMap = ArrayCreate(32);
  258.  
  259. // initialize nominations table
  260. nomination_clearAll();
  261.  
  262. if (get_pcvar_num(cvar_banRecent))
  263. {
  264. register_clcmd("say recentmaps", "cmd_listrecent", 0);
  265.  
  266. map_loadRecentList();
  267.  
  268. if (!(get_cvar_num("gal_server_starting") && get_pcvar_num(cvar_srvStart)))
  269. {
  270. map_writeRecentList();
  271. }
  272. }
  273.  
  274. if (get_pcvar_num(cvar_rtvCommands) & RTV_CMD_STANDARD)
  275. {
  276. register_clcmd("say rockthevote", "cmd_rockthevote", 0);
  277. }
  278.  
  279. if (get_pcvar_num(cvar_nomPlayerAllowance))
  280. {
  281. register_concmd("gal_listmaps", "cmd_listmaps");
  282. register_clcmd("say nominations", "cmd_nominations", 0, "- displays current nominations for next map");
  283.  
  284. if (get_pcvar_num(cvar_nomPrefixes))
  285. {
  286. map_loadPrefixList();
  287. }
  288. map_loadNominationList();
  289. }
  290.  
  291. new mapName[32];
  292. get_mapname(mapName, 31);
  293. dbg_log(6, "[%s]", mapName);
  294. dbg_log(6, "");
  295.  
  296. if (get_cvar_num("gal_server_starting"))
  297. {
  298. srv_handleStart();
  299. }
  300.  
  301. set_task(10.0, "vote_setupEnd");
  302.  
  303. if (get_pcvar_num(cvar_emptyWait))
  304. {
  305. g_emptyCycleMap = ArrayCreate(32);
  306. map_loadEmptyCycleList();
  307. set_task(60.0, "srv_initEmptyCheck");
  308. }
  309. }
  310.  
  311. public plugin_end()
  312. {
  313. map_restoreOriginalTimeLimit();
  314. }
  315.  
  316. public vote_setupEnd()
  317. {
  318. dbg_log(4, "%32s mp_timelimit: %f g_originalTimelimit: %f", "vote_setupEnd(in)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
  319.  
  320. g_originalTimelimit = get_cvar_float("mp_timelimit");
  321.  
  322. new nextMap[32];
  323. if (get_pcvar_num(cvar_endOfMapVote))
  324. {
  325. formatex(nextMap, sizeof(nextMap)-1, "%L", LANG_SERVER, "GAL_NEXTMAP_UNKNOWN");
  326. }
  327. else
  328. {
  329. g_mapCycle = ArrayCreate(32);
  330. map_populateList(g_mapCycle, "mapcycle.txt");
  331. map_getNext(g_mapCycle, g_currentMap, nextMap);
  332. }
  333. map_setNext(nextMap);
  334.  
  335. // as long as the time limit isn't set to 0, we can manage the end of the map automatically
  336. if (g_originalTimelimit)
  337. {
  338. set_task(15.0, "vote_manageEnd", _, _, _, "b");
  339. }
  340.  
  341. dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "vote_setupEnd(out)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
  342. }
  343.  
  344. map_getNext(Array:mapArray, currentMap[], nextMap[32])
  345. {
  346. new thisMap[32], mapCnt = ArraySize(mapArray), nextmapIdx = 0, returnVal = -1;
  347. for (new mapIdx = 0; mapIdx < mapCnt; mapIdx++)
  348. {
  349. ArrayGetString(mapArray, mapIdx, thisMap, sizeof(thisMap)-1);
  350. if (equal(currentMap, thisMap))
  351. {
  352. nextmapIdx = (mapIdx == mapCnt - 1) ? 0 : mapIdx + 1;
  353. returnVal = nextmapIdx;
  354. break;
  355. }
  356. }
  357. ArrayGetString(mapArray, nextmapIdx, nextMap, sizeof(nextMap)-1);
  358.  
  359. return returnVal;
  360. }
  361.  
  362. public srv_handleStart()
  363. {
  364. // this is the key that tells us if this server has been restarted or not
  365. set_cvar_num("gal_server_starting", 0);
  366.  
  367. // take the defined "server start" action
  368. new startAction = get_pcvar_num(cvar_srvStart);
  369. if (startAction)
  370. {
  371. new nextMap[32];
  372.  
  373. if (startAction == SRV_START_CURRENTMAP || startAction == SRV_START_NEXTMAP)
  374. {
  375. new filename[256];
  376. formatex(filename, sizeof(filename)-1, "%s/info.dat", DIR_DATA);
  377.  
  378. new file = fopen(filename, "rt");
  379. if (file) // !feof(file)
  380. {
  381. fgets(file, nextMap, sizeof(nextMap)-1);
  382.  
  383. if (startAction == SRV_START_NEXTMAP)
  384. {
  385. nextMap[0] = 0;
  386. fgets(file, nextMap, sizeof(nextMap)-1);
  387. }
  388. }
  389. fclose(file);
  390. }
  391. else if (startAction == SRV_START_RANDOMMAP)
  392. {
  393. // pick a random map from allowable nominations
  394.  
  395. // if noms aren't allowed, the nomination list hasn't already been loaded
  396. if (get_pcvar_num(cvar_nomPlayerAllowance) == 0)
  397. {
  398. map_loadNominationList();
  399. }
  400.  
  401. if (g_nominationMapCnt)
  402. {
  403. ArrayGetString(g_nominationMap, random_num(0, g_nominationMapCnt - 1), nextMap, sizeof(nextMap)-1);
  404. }
  405. }
  406.  
  407. trim(nextMap);
  408.  
  409. if (nextMap[0] && is_map_valid(nextMap))
  410. {
  411. server_cmd("changelevel %s", nextMap);
  412. }
  413. else
  414. {
  415. vote_manageEarlyStart();
  416. }
  417. }
  418. }
  419.  
  420. vote_manageEarlyStart()
  421. {
  422. g_voteStatus |= VOTE_IS_EARLY;
  423.  
  424. set_task(120.0, "vote_startDirector");
  425. }
  426.  
  427. map_setNext(nextMap[])
  428. {
  429. // set the queryable cvar
  430. set_cvar_string("amx_nextmap", nextMap);
  431.  
  432. // update our data file
  433. new filename[256];
  434. formatex(filename, sizeof(filename)-1, "%s/info.dat", DIR_DATA);
  435.  
  436. new file = fopen(filename, "wt");
  437. if (file)
  438. {
  439. fprintf(file, "%s", g_currentMap);
  440. fprintf(file, "^n%s", nextMap);
  441. fclose(file);
  442. }
  443. else
  444. {
  445. //error
  446. }
  447. }
  448.  
  449. public vote_manageEnd()
  450. {
  451. new secondsLeft = get_timeleft();
  452.  
  453. // are we ready to start an "end of map" vote?
  454. if (secondsLeft < 150 && secondsLeft > 90 && !g_pauseMapEndVoteTask && get_pcvar_num(cvar_endOfMapVote) && !get_pcvar_num(cvar_emptyCycle))
  455. {
  456. vote_startDirector(false);
  457. }
  458.  
  459. // are we managing the end of the map?
  460. if (secondsLeft < 20 && !g_pauseMapEndManagerTask)
  461. {
  462. map_manageEnd();
  463. }
  464. }
  465.  
  466. public map_loadRecentList()
  467. {
  468. new filename[256];
  469. formatex(filename, sizeof(filename)-1, "%s/recentmaps.dat", DIR_DATA);
  470.  
  471. new file = fopen(filename, "rt");
  472. if (file)
  473. {
  474. new buffer[32];
  475.  
  476. while (!feof(file))
  477. {
  478. fgets(file, buffer, sizeof(buffer)-1);
  479. trim(buffer);
  480.  
  481. if (buffer[0])
  482. {
  483. if (g_cntRecentMap == get_pcvar_num(cvar_banRecent))
  484. {
  485. break;
  486. }
  487. copy(g_recentMap[g_cntRecentMap++], sizeof(buffer)-1, buffer);
  488. }
  489. }
  490. fclose(file);
  491. }
  492. }
  493.  
  494. public map_writeRecentList()
  495. {
  496. new filename[256];
  497. formatex(filename, sizeof(filename)-1, "%s/recentmaps.dat", DIR_DATA);
  498.  
  499. new file = fopen(filename, "wt");
  500. if (file)
  501. {
  502. fprintf(file, "%s", g_currentMap);
  503.  
  504. for (new idxMap = 0; idxMap < get_pcvar_num(cvar_banRecent) - 1; ++idxMap)
  505. {
  506. fprintf(file, "^n%s", g_recentMap[idxMap]);
  507. }
  508.  
  509. fclose(file);
  510. }
  511. }
  512.  
  513. public map_loadFillerList(filename[])
  514. {
  515. return map_populateList(g_fillerMap, filename);
  516. }
  517.  
  518. public cmd_rockthevote(id)
  519. {
  520. client_print(id, print_chat, "%L", id, "GAL_CMD_RTV");
  521. vote_rock(id);
  522. return PLUGIN_CONTINUE;
  523. }
  524.  
  525. public cmd_nominations(id)
  526. {
  527. client_print(id, print_chat, "%L", id, "GAL_CMD_NOMS");
  528. nomination_list(id);
  529. return PLUGIN_CONTINUE;
  530. }
  531.  
  532. public cmd_nextmap(id)
  533. {
  534. new map[32];
  535. get_cvar_string("amx_nextmap", map, sizeof(map)-1);
  536. client_print(0, print_chat, "%L %s", LANG_PLAYER, "NEXT_MAP", map);
  537. return PLUGIN_CONTINUE;
  538. }
  539.  
  540. public cmd_currentmap(id)
  541. {
  542. client_print(0, print_chat, "%L: %s", LANG_PLAYER, "PLAYED_MAP", g_currentMap);
  543. return PLUGIN_CONTINUE;
  544. }
  545.  
  546. public cmd_listrecent(id)
  547. {
  548. switch (get_pcvar_num(cvar_banRecentStyle))
  549. {
  550. case 1:
  551. {
  552. new msg[101], msgIdx;
  553. for (new idx = 0; idx < g_cntRecentMap; ++idx)
  554. {
  555. msgIdx += format(msg[msgIdx], sizeof(msg)-1-msgIdx, ", %s", g_recentMap[idx]);
  556. }
  557. client_print(0, print_chat, "%L: %s", LANG_PLAYER, "GAL_MAP_RECENTMAPS", msg[2]);
  558. }
  559. case 2:
  560. {
  561. for (new idx = 0; idx < g_cntRecentMap; ++idx)
  562. {
  563. client_print(0, print_chat, "%L (%i): %s", LANG_PLAYER, "GAL_MAP_RECENTMAP", idx+1, g_recentMap[idx]);
  564. }
  565. }
  566. }
  567.  
  568. return PLUGIN_HANDLED;
  569. }
  570.  
  571. public cmd_startVote(id, level, cid)
  572. {
  573. if (!cmd_access(id, level, cid, 1))
  574. return PLUGIN_HANDLED;
  575.  
  576. if (g_voteStatus & VOTE_IN_PROGRESS)
  577. {
  578. client_print(id, print_chat, "%L", id, "GAL_VOTE_INPROGRESS");
  579. }
  580. else if (g_voteStatus & VOTE_IS_OVER)
  581. {
  582. client_print(id, print_chat, "%L", id, "GAL_VOTE_ENDED");
  583. }
  584. else
  585. {
  586. // we may not want to actually change the map after outcome of vote is determined
  587. if (read_argc() == 2)
  588. {
  589. new arg[32];
  590. read_args(arg, sizeof(arg)-1);
  591.  
  592. if (equali(arg, "-nochange"))
  593. {
  594. g_handleMapChange = false;
  595. }
  596. }
  597.  
  598. vote_startDirector(true);
  599. }
  600.  
  601. return PLUGIN_HANDLED;
  602. }
  603.  
  604. map_populateList(Array:mapArray, mapFilename[])
  605. {
  606. // clear the map array in case we're reusing it
  607. ArrayClear(mapArray);
  608.  
  609. // load the array with maps
  610. new mapCnt;
  611.  
  612. if (!equal(mapFilename, "*"))
  613. {
  614. new file = fopen(mapFilename, "rt");
  615. if (file)
  616. {
  617. new buffer[32];
  618.  
  619. while (!feof(file))
  620. {
  621. fgets(file, buffer, sizeof(buffer)-1);
  622. trim(buffer);
  623.  
  624. if (buffer[0] && !equal(buffer, "//", 2) && !equal(buffer, ";", 1) && is_map_valid(buffer))
  625. {
  626. ArrayPushString(mapArray, buffer);
  627. ++mapCnt;
  628. }
  629. }
  630. fclose(file);
  631. }
  632. else
  633. {
  634. log_error(AMX_ERR_NOTFOUND, "%L", LANG_SERVER, "GAL_MAPS_FILEMISSING", mapFilename);
  635. }
  636. }
  637. else
  638. {
  639. // no file provided, assuming contents of "maps" folder
  640. new dir, mapName[32];
  641. dir = open_dir("maps", mapName, sizeof(mapName)-1);
  642.  
  643. if (dir)
  644. {
  645. new lenMapName;
  646.  
  647. while (next_file(dir, mapName, sizeof(mapName)-1))
  648. {
  649. lenMapName = strlen(mapName);
  650. if (lenMapName > 4 && equali(mapName[lenMapName - 4], ".bsp", 4))
  651. {
  652. mapName[lenMapName-4] = '^0';
  653. if (is_map_valid(mapName))
  654. {
  655. ArrayPushString(mapArray, mapName);
  656. ++mapCnt;
  657. }
  658. }
  659. }
  660. close_dir(dir);
  661. }
  662. else
  663. {
  664. // directory not found, wtf?
  665. log_error(AMX_ERR_NOTFOUND, "%L", LANG_SERVER, "GAL_MAPS_FOLDERMISSING");
  666. }
  667. }
  668. return mapCnt;
  669. }
  670.  
  671. public map_loadNominationList()
  672. {
  673. new filename[256];
  674. get_pcvar_string(cvar_nomMapFile, filename, sizeof(filename)-1);
  675.  
  676. g_nominationMapCnt = map_populateList(g_nominationMap, filename);
  677. }
  678.  
  679. // grrface, this has no place in a map choosing plugin. just replicating it because it's in AMXX's
  680. public cmd_ff()
  681. {
  682. client_print(0, print_chat, "%L: %L", LANG_PLAYER, "FRIEND_FIRE", LANG_PLAYER, get_cvar_num("mp_friendlyfire") ? "ON" : "OFF");
  683. return PLUGIN_CONTINUE;
  684. }
  685.  
  686. public cmd_createMapFile(id, level, cid)
  687. {
  688. if (!cmd_access(id, level, cid, 1))
  689. return PLUGIN_HANDLED;
  690.  
  691. new cntArg = read_argc() - 1;
  692.  
  693. switch (cntArg)
  694. {
  695. case 1:
  696. {
  697. new arg1[256];
  698. read_argv(1, arg1, sizeof(arg1)-1);
  699. remove_quotes(arg1);
  700.  
  701. new mapName[MAX_MAPNAME_LEN+5]; // map name is 31 (i.e. MAX_MAPNAME_LEN), ".bsp" is 4, string terminator is 1.
  702. new dir, file, mapCnt, lenMapName;
  703.  
  704. dir = open_dir("maps", mapName, sizeof(mapName)-1);
  705. if (dir)
  706. {
  707. new filename[256];
  708. formatex(filename, sizeof(filename)-1, "%s/%s", DIR_CONFIGS, arg1);
  709.  
  710. file = fopen(filename, "wt");
  711. if (file)
  712. {
  713. mapCnt = 0;
  714. while (next_file(dir, mapName, sizeof(mapName)-1))
  715. {
  716. lenMapName = strlen(mapName);
  717.  
  718. if (lenMapName > 4 && equali(mapName[lenMapName - 4], ".bsp", 4))
  719. {
  720. mapName[lenMapName- 4] = '^0';
  721. if (is_map_valid(mapName))
  722. {
  723. mapCnt++;
  724. fprintf(file, "%s^n", mapName);
  725. }
  726. }
  727. }
  728. fclose(file);
  729. con_print(id, "%L", LANG_SERVER, "GAL_CREATIONSUCCESS", filename, mapCnt);
  730. }
  731. else
  732. {
  733. con_print(id, "%L", LANG_SERVER, "GAL_CREATIONFAILED", filename);
  734. }
  735. close_dir(dir);
  736. }
  737. else
  738. {
  739. // directory not found, wtf?
  740. con_print(id, "%L", LANG_SERVER, "GAL_MAPSFOLDERMISSING");
  741. }
  742. }
  743. default:
  744. {
  745. // inform of correct usage
  746. con_print(id, "%L", id, "GAL_CMD_CREATEFILE_USAGE1");
  747. con_print(id, "%L", id, "GAL_CMD_CREATEFILE_USAGE2");
  748. }
  749. }
  750. return PLUGIN_HANDLED;
  751. }
  752.  
  753. public map_loadPrefixList()
  754. {
  755. new filename[256];
  756. formatex(filename, sizeof(filename)-1, "%s/prefixes.ini", DIR_CONFIGS);
  757.  
  758. new file = fopen(filename, "rt");
  759. if (file)
  760. {
  761. new buffer[16];
  762. while (!feof(file))
  763. {
  764. fgets(file, buffer, sizeof(buffer)-1);
  765. if (buffer[0] && !equal(buffer, "//", 2))
  766. {
  767. if (g_mapPrefixCnt <= MAX_PREFIX_CNT)
  768. {
  769. trim(buffer);
  770. copy(g_mapPrefix[g_mapPrefixCnt++], sizeof(buffer)-1, buffer);
  771. }
  772. else
  773. {
  774. log_error(AMX_ERR_BOUNDS, "%L", LANG_SERVER, "GAL_PREFIXES_TOOMANY", MAX_PREFIX_CNT, filename);
  775. break;
  776. }
  777. }
  778. }
  779. fclose(file);
  780. }
  781. else
  782. {
  783. log_error(AMX_ERR_NOTFOUND, "%L", LANG_SERVER, "GAL_PREFIXES_NOTFOUND", filename);
  784. }
  785. return PLUGIN_HANDLED;
  786. }
  787.  
  788. map_loadEmptyCycleList()
  789. {
  790. new filename[256];
  791. get_pcvar_string(cvar_emptyMapFile, filename, sizeof(filename)-1);
  792.  
  793. g_emptyMapCnt = map_populateList(g_emptyCycleMap, filename);
  794. }
  795.  
  796. public map_manageEnd()
  797. {
  798. dbg_log(2, "%32s mp_timelimit: %f", "map_manageEnd(in)", get_cvar_float("mp_timelimit"));
  799.  
  800. g_pauseMapEndManagerTask = true;
  801.  
  802. if (get_realplayersnum() <= 1)
  803. {
  804. // at most there is only one player on the server, so no need to stay around
  805. map_change();
  806. }
  807. else
  808. {
  809. if (get_pcvar_num(cvar_endOnRound) && g_wasLastRound == false)
  810. {
  811. // let the server know it's the last round
  812. g_wasLastRound = true;
  813.  
  814. // let the players know it's the last round
  815. if (g_voteStatus & VOTE_FORCED)
  816. {
  817. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CHANGE_NEXTROUND");
  818. }
  819. else
  820. {
  821. client_print(0, print_chat, "%L %L", LANG_PLAYER, "GAL_CHANGE_TIMEEXPIRED", LANG_PLAYER, "GAL_CHANGE_NEXTROUND");
  822. }
  823.  
  824. // prevent the map from ending automatically
  825. server_cmd("mp_timelimit 0");
  826. }
  827. else
  828. {
  829. // freeze the game and show the scoreboard
  830. message_begin(MSG_ALL, SVC_INTERMISSION);
  831. message_end();
  832.  
  833. //new chatTime = floatround(get_cvar_float("mp_chattime"), floatround_floor);
  834.  
  835. // display intermission expiration countdown
  836. //set_task(1.0, "intermission_displayTimer", chatTime, _, _, "a", chatTime);
  837.  
  838. // change the map after "chattime" is over
  839. set_task(floatmax(get_cvar_float("mp_chattime"), 2.0), "map_change");
  840. }
  841.  
  842. new map[MAX_MAPNAME_LEN + 1];
  843. get_cvar_string("amx_nextmap", map, sizeof(map)-1);
  844. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_NEXTMAP", map);
  845. }
  846.  
  847. dbg_log(2, "%32s mp_timelimit: %f", "map_manageEnd(out)", get_cvar_float("mp_timelimit"));
  848. }
  849.  
  850. /*
  851. public intermission_displayTimer(originalChatTime)
  852. {
  853. static secondsLeft = -1;
  854. if (secondsLeft == -1)
  855. {
  856. secondsLeft = originalChatTime;
  857. }
  858. secondsLeft--;
  859.  
  860. client_print(0, print_center, "Intermission ends in %i seconds.", secondsLeft);
  861. client_print(0, print_chat, "%i seconds", secondsLeft);
  862.  
  863. set_hudmessage(255, 0, 90, 0.80, 0.20, 0, 1.0, 2.0, 0.1, 0.1, -1);
  864. // set_hudmessage(0, 222, 50, -1.0, 0.13, 0, 1.0, 0.94, 0.0, 0.0, -1);
  865. show_hudmessage(0, "Intermission ends in %i seconds.", secondsLeft);
  866. // use audio since visual doesn't seem to work
  867. // something like "map will change in 2 seconds"
  868.  
  869. }
  870. */
  871.  
  872. public event_round_start()
  873. {
  874. if (g_wasLastRound)
  875. {
  876. map_manageEnd();
  877. }
  878. }
  879.  
  880. public event_game_commencing()
  881. {
  882. // make sure the reset time is the original time limit
  883. // (can be skewed if map was previously extended)
  884. map_restoreOriginalTimeLimit();
  885. }
  886.  
  887. public event_intermission()
  888. {
  889. // don't let the normal end interfere
  890. g_pauseMapEndManagerTask = true;
  891.  
  892. // change the map after "chattime" is over
  893. set_task(floatmax(get_cvar_float("mp_chattime"), 2.0), "map_change");
  894.  
  895. return PLUGIN_CONTINUE;
  896. }
  897.  
  898. map_getIdx(text[])
  899. {
  900. new map[MAX_MAPNAME_LEN + 1];
  901. new mapIdx;
  902. new nominationMap[32];
  903.  
  904. for (new prefixIdx = 0; prefixIdx < g_mapPrefixCnt; ++prefixIdx)
  905. {
  906. formatex(map, sizeof(map)-1, "%s%s", g_mapPrefix[prefixIdx], text);
  907.  
  908. for (mapIdx = 0; mapIdx < g_nominationMapCnt; ++mapIdx)
  909. {
  910. ArrayGetString(g_nominationMap, mapIdx, nominationMap, sizeof(nominationMap)-1);
  911.  
  912. if (equal(map, nominationMap))
  913. {
  914. return mapIdx;
  915. }
  916. }
  917. }
  918. return -1;
  919. }
  920.  
  921. public cmd_say(id)
  922. {
  923. //-----
  924. // generic say handler to determine if we need to act on what was said
  925. //-----
  926.  
  927. static text[70], arg1[32], arg2[32], arg3[2];
  928. read_args(text, sizeof(text)-1);
  929. remove_quotes(text);
  930. arg1[0] = '^0';
  931. arg2[0] = '^0';
  932. arg3[0] = '^0';
  933. parse(text, arg1, sizeof(arg1)-1, arg2, sizeof(arg2)-1, arg3, sizeof(arg3)-1);
  934.  
  935. // if the chat line has more than 2 words, we're not interested at all
  936. if (arg3[0] == 0)
  937. {
  938. new idxMap;
  939.  
  940. // if the chat line contains 1 word, it could be a map or a one-word command
  941. if (arg2[0] == 0) // "say [rtv|rockthe<anything>vote]"
  942. {
  943. if ((get_pcvar_num(cvar_rtvCommands) & RTV_CMD_SHORTHAND && equali(arg1, "rtv")) || ((get_pcvar_num(cvar_rtvCommands) & RTV_CMD_DYNAMIC && equali(arg1, "rockthe", 7) && equali(arg1[strlen(arg1)-4], "vote"))))
  944. {
  945. vote_rock(id);
  946. return PLUGIN_HANDLED;
  947. }
  948. else if (get_pcvar_num(cvar_nomPlayerAllowance))
  949. {
  950. if (equali(arg1, "noms"))
  951. {
  952. nomination_list(id);
  953. return PLUGIN_HANDLED;
  954. }
  955. else
  956. {
  957. idxMap = map_getIdx(arg1);
  958. if (idxMap >= 0)
  959. {
  960. nomination_toggle(id, idxMap);
  961. return PLUGIN_HANDLED;
  962. }
  963. }
  964. }
  965. }
  966. else if (get_pcvar_num(cvar_nomPlayerAllowance)) // "say <nominate|nom|cancel> <map>"
  967. {
  968. if (equali(arg1, "nominate") || equali(arg1, "nom"))
  969. {
  970. nomination_attempt(id, arg2);
  971. return PLUGIN_HANDLED;
  972. }
  973. else if (equali(arg1, "cancel"))
  974. {
  975. // bpj -- allow ambiguous cancel in which case a menu of their nominations is shown
  976. idxMap = map_getIdx(arg2);
  977. if (idxMap >= 0)
  978. {
  979. nomination_cancel(id, idxMap);
  980. return PLUGIN_HANDLED;
  981. }
  982. }
  983. }
  984. }
  985. return PLUGIN_CONTINUE;
  986. }
  987.  
  988. nomination_attempt(id, nomination[]) // (playerName[], &phraseIdx, matchingSegment[])
  989. {
  990. // all map names are stored as lowercase, so normalize the nomination
  991. strtolower(nomination);
  992.  
  993. // assume there'll be more than one match (because we're lazy) and starting building the match menu
  994. //menu_destroy(g_nominationMatchesMenu[id]);
  995. g_nominationMatchesMenu[id] = menu_create("Nominate Map", "nomination_handleMatchChoice");
  996.  
  997. // gather all maps that match the nomination
  998. new mapIdx, nominationMap[32], matchCnt = 0, matchIdx = -1, info[1], choice[64], disabledReason[16];
  999. for (mapIdx = 0; mapIdx < g_nominationMapCnt && matchCnt <= MAX_NOM_MATCH_CNT; ++mapIdx)
  1000. {
  1001. ArrayGetString(g_nominationMap, mapIdx, nominationMap, sizeof(nominationMap)-1);
  1002.  
  1003. if (contain(nominationMap, nomination) > -1)
  1004. {
  1005. matchCnt++;
  1006. matchIdx = mapIdx; // store in case this is the only match
  1007.  
  1008. // there may be a much better way of doing this, but I didn't feel like
  1009. // storing the matches and mapIdx's only to loop through them again
  1010. info[0] = mapIdx;
  1011.  
  1012. // in most cases, the map will be available for selection, so assume that's the case here
  1013. disabledReason[0] = 0;
  1014.  
  1015. // disable if the map has already been nominated
  1016. if (nomination_getPlayer(mapIdx))
  1017. {
  1018. formatex(disabledReason, sizeof(disabledReason)-1, "%L", id, "GAL_MATCH_NOMINATED");
  1019. }
  1020. // disable if the map is too recent
  1021. else if (map_isTooRecent(nominationMap))
  1022. {
  1023. formatex(disabledReason, sizeof(disabledReason)-1, "%L", id, "GAL_MATCH_TOORECENT");
  1024. }
  1025. else if (equal(g_currentMap, nominationMap))
  1026. {
  1027. formatex(disabledReason, sizeof(disabledReason)-1, "%L", id, "GAL_MATCH_CURRENTMAP");
  1028. }
  1029.  
  1030. formatex(choice, sizeof(choice)-1, "%s %s", nominationMap, disabledReason);
  1031. menu_additem(g_nominationMatchesMenu[id], choice, info, (disabledReason[0] == 0) ? 0 : (1<<26));
  1032. }
  1033. }
  1034.  
  1035. // handle the number of matches
  1036. switch (matchCnt)
  1037. {
  1038. case 0:
  1039. {
  1040. // no matches; pity the poor fool
  1041. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_NOMATCHES", nomination);
  1042. }
  1043. case 1:
  1044. {
  1045. // one match?! omg, this is just like awesome
  1046. map_nominate(id, matchIdx);
  1047.  
  1048. }
  1049. default:
  1050. {
  1051. // this is kinda sexy; we put up a menu of the matches for them to pick the right one
  1052. client_print(id, print_chat, "%L", id, "GAL_NOM_MATCHES", nomination);
  1053. if (matchCnt == MAX_NOM_MATCH_CNT)
  1054. {
  1055. client_print(id, print_chat, "%L", id, "GAL_NOM_MATCHES_MAX", MAX_NOM_MATCH_CNT, MAX_NOM_MATCH_CNT);
  1056. }
  1057. menu_display(id, g_nominationMatchesMenu[id]);
  1058. }
  1059. }
  1060. }
  1061.  
  1062. public nomination_handleMatchChoice(id, menu, item)
  1063. {
  1064. if( item < 0 ) return PLUGIN_CONTINUE;
  1065.  
  1066. // Get item info
  1067. new mapIdx, info[1];
  1068. new access, callback;
  1069.  
  1070. menu_item_getinfo(g_nominationMatchesMenu[id], item, access, info, 1, _, _, callback);
  1071.  
  1072. mapIdx = info[0];
  1073. map_nominate(id, mapIdx);
  1074.  
  1075. return PLUGIN_HANDLED;
  1076. }
  1077.  
  1078. nomination_getPlayer(idxMap)
  1079. {
  1080. // check if the map has already been nominated
  1081. new idxNomination;
  1082. new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);
  1083.  
  1084. for (new idPlayer = 1; idPlayer <= MAX_PLAYER_CNT; ++idPlayer)
  1085. {
  1086. for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
  1087. {
  1088. if (idxMap == g_nomination[idPlayer][idxNomination])
  1089. {
  1090. return idPlayer;
  1091. }
  1092. }
  1093. }
  1094. return 0;
  1095. }
  1096.  
  1097. nomination_toggle(id, idxMap)
  1098. {
  1099. new idNominator = nomination_getPlayer(idxMap);
  1100. if (idNominator == id)
  1101. {
  1102. nomination_cancel(id, idxMap);
  1103. }
  1104. else
  1105. {
  1106. map_nominate(id, idxMap, idNominator);
  1107. }
  1108. }
  1109.  
  1110. nomination_cancel(id, idxMap)
  1111. {
  1112. // cancellations can only be made if a vote isn't already in progress
  1113. if (g_voteStatus & VOTE_IN_PROGRESS)
  1114. {
  1115. client_print(id, print_chat, "%L", id, "GAL_CANCEL_FAIL_INPROGRESS");
  1116. return;
  1117. }
  1118. // and if the outcome of the vote hasn't already been determined
  1119. else if (g_voteStatus & VOTE_IS_OVER)
  1120. {
  1121. client_print(id, print_chat, "%L", id, "GAL_CANCEL_FAIL_VOTEOVER");
  1122. return;
  1123. }
  1124.  
  1125. new bool:nominationFound, idxNomination;
  1126. new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);
  1127.  
  1128. for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
  1129. {
  1130. if (g_nomination[id][idxNomination] == idxMap)
  1131. {
  1132. nominationFound = true;
  1133. break;
  1134. }
  1135. }
  1136.  
  1137. new mapName[32];
  1138. ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
  1139.  
  1140. if (nominationFound)
  1141. {
  1142. g_nomination[id][idxNomination] = -1;
  1143. g_nominationCnt--;
  1144.  
  1145. nomination_announceCancellation(mapName);
  1146. }
  1147. else
  1148. {
  1149. new idNominator = nomination_getPlayer(idxMap);
  1150. if (idNominator)
  1151. {
  1152. new name[32];
  1153. get_user_name(idNominator, name, 31);
  1154.  
  1155. client_print(id, print_chat, "%L", id, "GAL_CANCEL_FAIL_SOMEONEELSE", mapName, name);
  1156. }
  1157. else
  1158. {
  1159. client_print(id, print_chat, "%L", id, "GAL_CANCEL_FAIL_WASNOTYOU", mapName);
  1160. }
  1161. }
  1162. }
  1163.  
  1164. map_nominate(id, idxMap, idNominator = -1)
  1165. {
  1166. // nominations can only be made if a vote isn't already in progress
  1167. if (g_voteStatus & VOTE_IN_PROGRESS)
  1168. {
  1169. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_INPROGRESS");
  1170. return;
  1171. }
  1172. // and if the outcome of the vote hasn't already been determined
  1173. else if (g_voteStatus & VOTE_IS_OVER)
  1174. {
  1175. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_VOTEOVER");
  1176. return;
  1177. }
  1178.  
  1179. new mapName[32];
  1180. ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
  1181.  
  1182. // players can not nominate the current map
  1183. if (equal(g_currentMap, mapName))
  1184. {
  1185. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_CURRENTMAP", g_currentMap);
  1186. return;
  1187. }
  1188.  
  1189. // players may not be able to nominate recently played maps
  1190. if (map_isTooRecent(mapName))
  1191. {
  1192. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_TOORECENT", mapName);
  1193. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_TOORECENT_HLP");
  1194. return;
  1195. }
  1196.  
  1197. // check if the map has already been nominated
  1198. if (idNominator == -1)
  1199. {
  1200. idNominator = nomination_getPlayer(idxMap);
  1201. }
  1202.  
  1203. if (idNominator == 0)
  1204. {
  1205. // determine the number of nominations the player already made
  1206. // and grab an open slot with the presumption that the player can make the nomination
  1207. new nominationCnt = 0, idxNominationOpen, idxNomination;
  1208. new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);
  1209.  
  1210. for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
  1211. {
  1212. if (g_nomination[id][idxNomination] >= 0)
  1213. {
  1214. nominationCnt++;
  1215. }
  1216. else
  1217. {
  1218. idxNominationOpen = idxNomination;
  1219. }
  1220. }
  1221.  
  1222. if (nominationCnt == playerNominationMax)
  1223. {
  1224. new nominatedMaps[256], buffer[32];
  1225. for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
  1226. {
  1227. idxMap = g_nomination[id][idxNomination];
  1228. ArrayGetString(g_nominationMap, idxMap, buffer, sizeof(buffer)-1);
  1229. format(nominatedMaps, sizeof(nominatedMaps)-1, "%s%s%s", nominatedMaps, (idxNomination == 1) ? "" : ", ", buffer);
  1230. }
  1231.  
  1232. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_TOOMANY", playerNominationMax, nominatedMaps);
  1233. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_TOOMANY_HLP");
  1234. }
  1235. else
  1236. {
  1237. // otherwise, allow the nomination
  1238. g_nomination[id][idxNominationOpen] = idxMap;
  1239. g_nominationCnt++;
  1240. map_announceNomination(id, mapName);
  1241. client_print(id, print_chat, "%L", id, "GAL_NOM_GOOD_HLP");
  1242. }
  1243. }
  1244. else if (idNominator == id)
  1245. {
  1246. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_ALREADY", mapName);
  1247. }
  1248. else
  1249. {
  1250. new name[32];
  1251. get_user_name(idNominator, name, 31);
  1252.  
  1253. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_SOMEONEELSE", mapName, name);
  1254. client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_SOMEONEELSE_HLP");
  1255. }
  1256. }
  1257.  
  1258. public nomination_list(id)
  1259. {
  1260. new idxNomination, idxMap; //, hudMessage[512];
  1261. new msg[101], mapCnt;
  1262. new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);
  1263. new mapName[32];
  1264.  
  1265. for (new idPlayer = 1; idPlayer <= MAX_PLAYER_CNT; ++idPlayer)
  1266. {
  1267. for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
  1268. {
  1269. idxMap = g_nomination[idPlayer][idxNomination];
  1270. if (idxMap >= 0)
  1271. {
  1272. ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
  1273. format(msg, sizeof(msg)-1, "%s, %s", msg, mapName);
  1274.  
  1275. if (++mapCnt == 4) // list 4 maps per chat line
  1276. {
  1277. client_print(0, print_chat, "%L: %s", LANG_PLAYER, "GAL_NOMINATIONS", msg[2]);
  1278. mapCnt = 0;
  1279. msg[0] = 0;
  1280. }
  1281. // construct the HUD message
  1282. // format(hudMessage, sizeof(hudMessage)-1, "%s^n%s", hudMessage, mapName);
  1283.  
  1284. // construct the console message
  1285. }
  1286. }
  1287. }
  1288. if (msg[0])
  1289. {
  1290. client_print(0, print_chat, "%L: %s", LANG_PLAYER, "GAL_NOMINATIONS", msg[2]);
  1291. }
  1292. else
  1293. {
  1294. client_print(0, print_chat, "%L: %L", LANG_PLAYER, "GAL_NOMINATIONS", LANG_PLAYER, "NONE");
  1295. }
  1296.  
  1297. // set_hudmessage(255, 0, 90, 0.80, 0.20, 0, 1.0, 12.0, 0.1, 0.1, -1);
  1298. // ShowSyncHudMsg(id, g_nonOverlapHudSync, hudMessage);
  1299. }
  1300.  
  1301. public vote_startDirector(bool:forced)
  1302. {
  1303. new choicesLoaded, voteDuration;
  1304.  
  1305. if (g_voteStatus & VOTE_IS_RUNOFF)
  1306. {
  1307. choicesLoaded = vote_loadRunoffChoices();
  1308. voteDuration = get_pcvar_num(cvar_runoffDuration);
  1309.  
  1310. if (get_realplayersnum())
  1311. {
  1312. dbg_log(4, " [RUNOFF VOTE CHOICES (%i)]", choicesLoaded);
  1313. }
  1314. }
  1315. else
  1316. {
  1317. // make it known that a vote is in progress
  1318. g_voteStatus |= VOTE_IN_PROGRESS;
  1319.  
  1320. // stop RTV reminders
  1321. remove_task(TASKID_REMINDER);
  1322.  
  1323. // set nextmap to "voting"
  1324. if (forced || get_pcvar_num(cvar_endOfMapVote))
  1325. {
  1326. new nextMap[32];
  1327. formatex(nextMap, sizeof(nextMap)-1, "%L", LANG_SERVER, "GAL_NEXTMAP_VOTING");
  1328. map_setNext(nextMap);
  1329. }
  1330.  
  1331. // pause the "end of map" tasks so they don't interfere
  1332. g_pauseMapEndVoteTask = true;
  1333. g_pauseMapEndManagerTask = true;
  1334.  
  1335. if (forced)
  1336. {
  1337. g_voteStatus |= VOTE_FORCED;
  1338. }
  1339.  
  1340. choicesLoaded = vote_loadChoices();
  1341. voteDuration = get_pcvar_num(cvar_voteDuration);
  1342.  
  1343. if (get_realplayersnum())
  1344. {
  1345. dbg_log(4, " [PRIMARY VOTE CHOICES (%i)]", choicesLoaded);
  1346. }
  1347.  
  1348. if (choicesLoaded)
  1349. {
  1350. // clear all nominations
  1351. nomination_clearAll();
  1352. }
  1353. }
  1354.  
  1355. if (choicesLoaded)
  1356. {
  1357. // alphabetize the maps
  1358. SortCustom2D(g_mapChoice, choicesLoaded, "sort_stringsi");
  1359.  
  1360. // dbg code ----
  1361. if (get_realplayersnum())
  1362. {
  1363. for (new dbgChoice = 0; dbgChoice < choicesLoaded; dbgChoice++)
  1364. {
  1365. dbg_log(4, " %i. %s", dbgChoice+1, g_mapChoice[dbgChoice]);
  1366. }
  1367. }
  1368. //--------------
  1369.  
  1370. // mark the players who are in this vote for use later
  1371. new player[32], playerCnt;
  1372. get_players(player, playerCnt, "ch"); // skip bots and hltv
  1373. for (new idxPlayer = 0; idxPlayer < playerCnt; ++idxPlayer)
  1374. {
  1375. g_voted[player[idxPlayer]] = false;
  1376. }
  1377.  
  1378. // make perfunctory announcement: "get ready to choose a map"
  1379. if (!(get_pcvar_num(cvar_soundsMute) & SOUND_GETREADYTOCHOOSE))
  1380. {
  1381. client_cmd(0, "spk ^"get red(e80) ninety(s45) to check(e20) use bay(s18) mass(e42) cap(s50)^"");
  1382. }
  1383.  
  1384. // announce the pending vote countdown from 7 to 1
  1385. set_task(1.0, "vote_countdownPendingVote", _, _, _, "a", 7);
  1386.  
  1387. // display the map choices
  1388. set_task(8.5, "vote_handleDisplay");
  1389.  
  1390. // display the vote outcome
  1391. if (get_pcvar_num(cvar_voteStatus))
  1392. {
  1393. new arg[3] = {-1, -1, false}; // indicates it's the end of vote display
  1394. set_task(8.5 + float(voteDuration) + 1.0, "vote_display", _, arg, 3);
  1395. set_task(8.5 + float(voteDuration) + 6.0, "vote_expire");
  1396. }
  1397. else
  1398. {
  1399. set_task(8.5 + float(voteDuration) + 3.0, "vote_expire");
  1400. }
  1401. }
  1402. else
  1403. {
  1404. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_VOTE_NOMAPS");
  1405. }
  1406. if (get_realplayersnum())
  1407. {
  1408. dbg_log(4, "");
  1409. dbg_log(4, " [PLAYER CHOICES]");
  1410. }
  1411. }
  1412.  
  1413. public vote_countdownPendingVote()
  1414. {
  1415. static countdown = 7;
  1416.  
  1417. // visual countdown
  1418. set_hudmessage(0, 222, 50, -1.0, 0.13, 0, 1.0, 0.94, 0.0, 0.0, -1);
  1419. show_hudmessage(0, "%L", LANG_PLAYER, "GAL_VOTE_COUNTDOWN", countdown);
  1420.  
  1421. // audio countdown
  1422. if (!(get_pcvar_num(cvar_soundsMute) & SOUND_COUNTDOWN))
  1423. {
  1424. new word[6];
  1425. num_to_word(countdown, word, 5);
  1426.  
  1427. client_cmd(0, "spk ^"fvox/%s^"", word);
  1428. }
  1429.  
  1430. // decrement the countdown
  1431. countdown--;
  1432.  
  1433. if (countdown == 0)
  1434. {
  1435. countdown = 7;
  1436. }
  1437. }
  1438.  
  1439. vote_addNominations()
  1440. {
  1441. // dbg code ----
  1442. if (get_realplayersnum())
  1443. {
  1444. dbg_log(4, " [NOMINATIONS (%i)]", g_nominationCnt);
  1445. }
  1446. //--------------
  1447.  
  1448. if (g_nominationCnt)
  1449. {
  1450. // set how many total nominations we can use in this vote
  1451. new maxNominations = get_pcvar_num(cvar_nomQtyUsed);
  1452. new slotsAvailable = g_choiceMax - g_choiceCnt;
  1453. new voteNominationMax = (maxNominations) ? min(maxNominations, slotsAvailable) : slotsAvailable;
  1454.  
  1455. // set how many total nominations each player is allowed
  1456. new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);
  1457.  
  1458. // add as many nominations as we can
  1459. // [TODO: develop a better method of determining which nominations make the cut; either FIFO or random]
  1460. new idxMap, id, mapName[32];
  1461.  
  1462. // dbg code ----
  1463. if (get_realplayersnum())
  1464. {
  1465. new nominator_id, playerName[32];
  1466. for (new idxNomination = playerNominationMax; idxNomination >= 1; --idxNomination)
  1467. {
  1468. for (id = 1; id <= MAX_PLAYER_CNT; ++id)
  1469. {
  1470. idxMap = g_nomination[id][idxNomination];
  1471. if (idxMap >= 0)
  1472. {
  1473. ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
  1474. nominator_id = nomination_getPlayer(idxMap);
  1475. get_user_name(nominator_id, playerName, sizeof(playerName)-1);
  1476.  
  1477. dbg_log(4, " %-32s %s", mapName, playerName);
  1478. }
  1479. }
  1480. }
  1481. dbg_log(4, "");
  1482. }
  1483. //--------------
  1484.  
  1485. for (new idxNomination = playerNominationMax; idxNomination >= 1; --idxNomination)
  1486. {
  1487. for (id = 1; id <= MAX_PLAYER_CNT; ++id)
  1488. {
  1489. idxMap = g_nomination[id][idxNomination];
  1490. if (idxMap >= 0)
  1491. {
  1492. ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
  1493. copy(g_mapChoice[g_choiceCnt++], sizeof(g_mapChoice[])-1, mapName);
  1494.  
  1495. if (g_choiceCnt == voteNominationMax)
  1496. {
  1497. break;
  1498. }
  1499. }
  1500. }
  1501. if (g_choiceCnt == voteNominationMax)
  1502. {
  1503. break;
  1504. }
  1505. }
  1506. }
  1507. }
  1508.  
  1509. vote_addFiller()
  1510. {
  1511. if (g_choiceCnt == g_choiceMax)
  1512. {
  1513. return;
  1514. }
  1515.  
  1516. // grab the name of the filler file
  1517. new filename[256];
  1518. get_pcvar_string(cvar_voteMapFile, filename, sizeof(filename)-1);
  1519.  
  1520. // create an array of files that will be pulled from
  1521. new fillerFile[8][256];
  1522. new mapsPerGroup[8], groupCnt;
  1523.  
  1524. if (!equal(filename, "*"))
  1525. {
  1526. // determine what kind of file it's being used as
  1527. new file = fopen(filename, "rt");
  1528. if (file)
  1529. {
  1530. new buffer[16];
  1531. fgets(file, buffer, sizeof(buffer)-1);
  1532. trim(buffer);
  1533. fclose(file);
  1534.  
  1535. if (equali(buffer, "[groups]"))
  1536. {
  1537. dbg_log(8, " ");
  1538. dbg_log(8, "this is a [groups] file");
  1539. // read the filler file to determine how many groups there are (max of 8)
  1540. new groupIdx;
  1541.  
  1542. file = fopen(filename, "rt");
  1543.  
  1544. while (!feof(file))
  1545. {
  1546. fgets(file, buffer, sizeof(buffer)-1);
  1547. trim(buffer);
  1548. // dbg_log(8, "buffer: %s isdigit: %i groupCnt: %i ", buffer, isdigit(buffer[0]), groupCnt);
  1549.  
  1550. if (isdigit(buffer[0]))
  1551. {
  1552. if (groupCnt < 8)
  1553. {
  1554. groupIdx = groupCnt++;
  1555. mapsPerGroup[groupIdx] = str_to_num(buffer);
  1556. formatex(fillerFile[groupIdx], sizeof(fillerFile[])-1, "%s/%i.ini", DIR_CONFIGS, groupCnt);
  1557. // dbg_log(8, "fillerFile: %s", fillerFile[groupIdx]);
  1558. }
  1559. else
  1560. {
  1561. log_error(AMX_ERR_BOUNDS, "%L", LANG_SERVER, "GAL_GRP_FAIL_TOOMANY", filename);
  1562. break;
  1563. }
  1564. }
  1565. }
  1566.  
  1567. fclose(file);
  1568.  
  1569. if (groupCnt == 0)
  1570. {
  1571. log_error(AMX_ERR_GENERAL, "%L", LANG_SERVER, "GAL_GRP_FAIL_NOCOUNTS", filename);
  1572. return;
  1573. }
  1574. }
  1575. else
  1576. {
  1577. // we presume it's a listing of maps, ala mapcycle.txt
  1578. copy(fillerFile[0], sizeof(filename)-1, filename);
  1579. mapsPerGroup[0] = 8;
  1580. groupCnt = 1;
  1581. }
  1582. }
  1583. else
  1584. {
  1585. log_error(AMX_ERR_NOTFOUND, "%L", LANG_SERVER, "GAL_FILLER_NOTFOUND", fillerFile);
  1586. }
  1587. }
  1588. else
  1589. {
  1590. // we'll be loading all maps in the /maps folder
  1591. copy(fillerFile[0], sizeof(filename)-1, filename);
  1592. mapsPerGroup[0] = 8;
  1593. groupCnt = 1;
  1594. }
  1595.  
  1596. // fill remaining slots with random maps from each filler file, as much as possible
  1597. new mapCnt, mapKey, allowedCnt, unsuccessfulCnt, choiceIdx, mapName[32];
  1598.  
  1599. for (new groupIdx = 0; groupIdx < groupCnt; ++groupIdx)
  1600. {
  1601. mapCnt = map_loadFillerList(fillerFile[groupIdx]);
  1602. dbg_log(8, "[%i] groupCnt:%i mapCnt: %i g_choiceCnt: %i g_choiceMax: %i fillerFile: %s", groupIdx, groupCnt, mapCnt, g_choiceCnt, g_choiceMax, fillerFile[groupIdx]);
  1603.  
  1604. if (g_choiceCnt < g_choiceMax && mapCnt)
  1605. {
  1606. unsuccessfulCnt = 0;
  1607. allowedCnt = min(min(mapsPerGroup[groupIdx], g_choiceMax - g_choiceCnt), mapCnt);
  1608. dbg_log(8, "[%i] allowedCnt: %i mapsPerGroup: %i Max-Cnt: %i", groupIdx, allowedCnt, mapsPerGroup[groupIdx], g_choiceMax - g_choiceCnt);
  1609.  
  1610. for (choiceIdx = 0; choiceIdx < allowedCnt; ++choiceIdx)
  1611. {
  1612. mapKey = random_num(0, mapCnt - 1);
  1613. ArrayGetString(g_fillerMap, mapKey, mapName, sizeof(mapName)-1);
  1614. dbg_log(8, "[%i] choiceIdx: %i allowedCnt: %i mapKey: %i mapName: %s", groupIdx, choiceIdx, allowedCnt, mapKey, mapName);
  1615. unsuccessfulCnt = 0;
  1616.  
  1617. while ((map_isInMenu(mapName) || equal(g_currentMap, mapName) || map_isTooRecent(mapName) || prefix_isInMenu(mapName)) && unsuccessfulCnt < mapCnt)
  1618. {
  1619. unsuccessfulCnt++;
  1620. if (++mapKey == mapCnt)
  1621. {
  1622. mapKey = 0;
  1623. }
  1624. ArrayGetString(g_fillerMap, mapKey, mapName, sizeof(mapName)-1);
  1625. }
  1626.  
  1627. if (unsuccessfulCnt == mapCnt)
  1628. {
  1629. //client_print(0, print_chat, "unsuccessfulCnt: %i mapCnt: %i", unsuccessfulCnt, mapCnt);
  1630. // there aren't enough maps in this filler file to continue adding anymore
  1631. break;
  1632. }
  1633.  
  1634. //client_print(0, print_chat, "mapIdx: %i map: %s", mapIdx, mapName);
  1635. copy(g_mapChoice[g_choiceCnt++], sizeof(g_mapChoice[])-1, mapName);
  1636. dbg_log(8, "[%i] mapName: %s unsuccessfulCnt: %i mapCnt: %i g_choiceCnt: %i", groupIdx, mapName, unsuccessfulCnt, mapCnt, g_choiceCnt);
  1637. }
  1638. }
  1639. }
  1640. }
  1641.  
  1642. vote_loadChoices()
  1643. {
  1644. vote_addNominations();
  1645. vote_addFiller();
  1646.  
  1647. return g_choiceCnt;
  1648. }
  1649.  
  1650. vote_loadRunoffChoices()
  1651. {
  1652. new choiceCnt;
  1653.  
  1654. new runoffChoice[2][MAX_MAPNAME_LEN+1];
  1655. copy(runoffChoice[0], sizeof(runoffChoice[])-1, g_mapChoice[g_runoffChoice[0]]);
  1656. copy(runoffChoice[1], sizeof(runoffChoice[])-1, g_mapChoice[g_runoffChoice[1]]);
  1657.  
  1658. new mapIdx;
  1659. if (g_runoffChoice[0] != g_choiceCnt)
  1660. {
  1661. copy(g_mapChoice[mapIdx++], sizeof(g_mapChoice[])-1, runoffChoice[0]);
  1662. choiceCnt++;
  1663. }
  1664. if (g_runoffChoice[1] != g_choiceCnt)
  1665. {
  1666. choiceCnt++;
  1667. }
  1668. copy(g_mapChoice[mapIdx], sizeof(g_mapChoice[])-1, runoffChoice[1]);
  1669.  
  1670. g_choiceCnt = choiceCnt;
  1671.  
  1672. return choiceCnt;
  1673. }
  1674.  
  1675. public vote_handleDisplay()
  1676. {
  1677. // announce: "time to choose"
  1678. if (!(get_pcvar_num(cvar_soundsMute) & SOUND_TIMETOCHOOSE))
  1679. {
  1680. client_cmd(0, "spk Gman/Gman_Choose%i", random_num(1, 2));
  1681. }
  1682.  
  1683. if (g_voteStatus & VOTE_IS_RUNOFF)
  1684. {
  1685. g_voteDuration = get_pcvar_num(cvar_runoffDuration);
  1686. }
  1687. else
  1688. {
  1689. g_voteDuration = get_pcvar_num(cvar_voteDuration);
  1690. }
  1691.  
  1692. if (get_pcvar_num(cvar_voteStatus) && get_pcvar_num(cvar_voteStatusType) == SHOWSTATUSTYPE_PERCENTAGE)
  1693. {
  1694. copy(g_voteTallyType, sizeof(g_voteTallyType)-1, "%");
  1695. }
  1696.  
  1697. if (get_cvar_num("gal_debug") & 4)
  1698. {
  1699. set_task(2.0, "dbg_fakeVotes");
  1700. }
  1701.  
  1702. // make sure the display is contructed from scratch
  1703. g_refreshVoteStatus = true;
  1704.  
  1705. // ensure the vote status doesn't indicate expired
  1706. g_voteStatus &= ~VOTE_HAS_EXPIRED;
  1707.  
  1708. new arg[3];
  1709. arg[0] = true;
  1710. arg[1] = 0;
  1711. arg[2] = false;
  1712.  
  1713. if (get_pcvar_num(cvar_voteStatus) == SHOWSTATUS_VOTE)
  1714. {
  1715. set_task(1.0, "vote_display", _, arg, sizeof(arg), "a", g_voteDuration);
  1716. }
  1717. else
  1718. {
  1719. set_task(1.0, "vote_display", _, arg, sizeof(arg));
  1720. }
  1721. }
  1722.  
  1723. public vote_display(arg[3])
  1724. {
  1725. static allKeys = MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_5|MENU_KEY_6|MENU_KEY_7|MENU_KEY_8|MENU_KEY_9|MENU_KEY_0;
  1726. static keys, voteStatus[512], voteTally[16];
  1727.  
  1728. new updateTimeRemaining = arg[0];
  1729. new id = arg[1];
  1730.  
  1731. // dbg code ----
  1732. if (get_realplayersnum())
  1733. {
  1734. new snuff = (id > 0) ? g_snuffDisplay[id] : -1;
  1735. dbg_log(4, " [votedisplay()] id: %i updateTimeRemaining: %i unsnuffDisplay: %i g_snuffDisplay: %i g_refreshVoteStatus: %i g_choiceCnt: %i len(g_vote): %i len(voteStatus): %i", arg[1], arg[0], arg[2], snuff, g_refreshVoteStatus, g_choiceCnt, strlen(g_vote), strlen(voteStatus));
  1736. }
  1737.  
  1738. if (id > 0 && g_snuffDisplay[id])
  1739. {
  1740. new unsnuffDisplay = arg[2];
  1741. if (unsnuffDisplay)
  1742. {
  1743. g_snuffDisplay[id] = false;
  1744. }
  1745. else
  1746. {
  1747. return;
  1748. }
  1749. }
  1750.  
  1751. new isVoteOver = (updateTimeRemaining == -1 && id == -1);
  1752. new charCnt;
  1753.  
  1754. if (g_refreshVoteStatus || isVoteOver)
  1755. {
  1756. // wipe the previous vote status clean
  1757. voteStatus[0] = 0;
  1758. keys = MENU_KEY_0;
  1759.  
  1760. new voteCnt;
  1761.  
  1762. new allowStay = (g_voteStatus & VOTE_IS_EARLY);
  1763.  
  1764. new isRunoff = (g_voteStatus & VOTE_IS_RUNOFF);
  1765. new bool:allowExtend = !allowStay && ((isRunoff && g_choiceCnt == 1) || (!(g_voteStatus & VOTE_FORCED) && !isRunoff && get_cvar_float("mp_timelimit") < get_pcvar_float(cvar_extendmapMax)));
  1766. if (get_cvar_num("gal_debug") & 4)
  1767. {
  1768. allowExtend = !allowStay && ((isRunoff && g_choiceCnt == 1) || (!isRunoff && get_cvar_float("mp_timelimit") < get_pcvar_float(cvar_extendmapMax)));
  1769. }
  1770.  
  1771. // add the header
  1772. if (isVoteOver)
  1773. {
  1774. charCnt = formatex(voteStatus, sizeof(voteStatus)-1, "%s%L^n", CLR_YELLOW, LANG_SERVER, "GAL_RESULT");
  1775. }
  1776. else
  1777. {
  1778. charCnt = formatex(voteStatus, sizeof(voteStatus)-1, "%s%L^n", CLR_YELLOW, LANG_SERVER, "GAL_CHOOSE");
  1779. }
  1780.  
  1781. // add maps to the menu
  1782. for (new choiceIdx = 0; choiceIdx < g_choiceCnt; ++choiceIdx)
  1783. {
  1784. voteCnt = g_mapVote[choiceIdx];
  1785. vote_getTallyStr(voteTally, sizeof(voteTally)-1, voteCnt);
  1786.  
  1787. charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n%s%i. %s%s%s", CLR_RED, choiceIdx+1, CLR_WHITE, g_mapChoice[choiceIdx], voteTally);
  1788. keys |= (1<<choiceIdx);
  1789. }
  1790.  
  1791. // add optional menu item
  1792. if (allowExtend || allowStay)
  1793. {
  1794. // if it's not a runoff vote, add a space between the maps and the additional option
  1795. if (g_voteStatus & VOTE_IS_RUNOFF == 0)
  1796. {
  1797. charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n");
  1798. }
  1799.  
  1800. vote_getTallyStr(voteTally, sizeof(voteTally)-1, g_mapVote[g_choiceCnt]);
  1801.  
  1802. if (allowExtend)
  1803. {
  1804. // add the "Extend Map" menu item.
  1805. charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n%s%i. %s%L%s", CLR_RED, g_choiceCnt+1, CLR_WHITE, LANG_SERVER, "GAL_OPTION_EXTEND", g_currentMap, floatround(get_pcvar_float(cvar_extendmapStep)), voteTally);
  1806. }
  1807. else
  1808. {
  1809. // add the "Stay Here" menu item
  1810. charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n%s%i. %s%L%s", CLR_RED, g_choiceCnt+1, CLR_WHITE, LANG_SERVER, "GAL_OPTION_STAY", voteTally);
  1811. }
  1812.  
  1813. keys |= (1<<g_choiceCnt);
  1814. }
  1815.  
  1816. // make a copy of the virgin menu
  1817. if (g_vote[0] == 0)
  1818. {
  1819. new cleanCharCnt = copy(g_vote, sizeof(g_vote)-1, voteStatus);
  1820.  
  1821. // append a "None" option on for people to choose if they don't like any other choice
  1822. formatex(g_vote[cleanCharCnt], sizeof(g_vote)-1-cleanCharCnt, "^n^n%s0. %s%L", CLR_RED, CLR_WHITE, LANG_SERVER, "GAL_OPTION_NONE");
  1823. }
  1824.  
  1825. charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n^n");
  1826.  
  1827. g_refreshVoteStatus = false;
  1828. }
  1829.  
  1830. static voteFooter[32];
  1831. if (updateTimeRemaining && get_pcvar_num(cvar_voteExpCountdown))
  1832. {
  1833. charCnt = copy(voteFooter, sizeof(voteFooter)-1, "^n^n");
  1834.  
  1835. if (--g_voteDuration <= 10)
  1836. {
  1837. formatex(voteFooter[charCnt], sizeof(voteFooter)-1-charCnt, "%s%L: %s%i", CLR_GREY, LANG_SERVER, "GAL_TIMELEFT", CLR_RED, g_voteDuration);
  1838. }
  1839. }
  1840.  
  1841. // create the different displays
  1842. static menuClean[512], menuDirty[512];
  1843. menuClean[0] = 0;
  1844. menuDirty[0] = 0;
  1845.  
  1846. formatex(menuClean, sizeof(menuClean)-1, "%s%s", g_vote, voteFooter);
  1847. if (!isVoteOver)
  1848. {
  1849. formatex(menuDirty, sizeof(menuDirty)-1, "%s%s", voteStatus, voteFooter);
  1850. }
  1851. else
  1852. {
  1853. formatex(menuDirty, sizeof(menuDirty)-1, "%s^n^n%s%L", voteStatus, CLR_YELLOW, LANG_SERVER, "GAL_VOTE_ENDED");
  1854. }
  1855.  
  1856. new menuid, menukeys;
  1857.  
  1858. // display the vote
  1859. new showStatus = get_pcvar_num(cvar_voteStatus);
  1860. if (id > 0)
  1861. {
  1862. // optionally display to single player that just voted
  1863. if (showStatus == SHOWSTATUS_VOTE)
  1864. {
  1865. // dbg code ----
  1866. new name[32];
  1867. get_user_name(id, name, 31);
  1868.  
  1869. dbg_log(4, " [%s (dirty, just voted)]", name);
  1870. dbg_log(4, " %s", menuDirty);
  1871. //--------------
  1872.  
  1873. get_user_menu(id, menuid, menukeys);
  1874. if (menuid == 0 || menuid == g_menuChooseMap)
  1875. {
  1876. show_menu(id, allKeys, menuDirty, max(1, g_voteDuration), MENU_CHOOSEMAP);
  1877. }
  1878. }
  1879. }
  1880. else
  1881. {
  1882. // display to everyone
  1883. new players[32], playerCnt;
  1884. get_players(players, playerCnt, "ch"); // skip bots and hltv
  1885.  
  1886. for (new playerIdx = 0; playerIdx < playerCnt; ++playerIdx)
  1887. {
  1888. id = players[playerIdx];
  1889.  
  1890. if (g_voted[id] == false && !isVoteOver)
  1891. {
  1892. // dbg code ----
  1893. if (playerIdx == 0)
  1894. {
  1895. new name[32];
  1896. get_user_name(id, name, 31);
  1897.  
  1898. dbg_log(4, " [%s (clean)]", name);
  1899. dbg_log(4, " %s", menuClean);
  1900. }
  1901. //--------------
  1902.  
  1903. get_user_menu(id, menuid, menukeys);
  1904. if (menuid == 0 || menuid == g_menuChooseMap)
  1905. {
  1906. show_menu(id, keys, menuClean, g_voteDuration, MENU_CHOOSEMAP);
  1907. }
  1908. }
  1909. else
  1910. {
  1911. if ((isVoteOver && showStatus) || (showStatus == SHOWSTATUS_VOTE && g_voted[id]))
  1912. {
  1913. // dbg code ----
  1914. if (playerIdx == 0)
  1915. {
  1916. new name[32];
  1917. get_user_name(id, name, 31);
  1918.  
  1919. dbg_log(4, " [%s (dirty)]", name);
  1920. dbg_log(4, " %s", menuDirty);
  1921. }
  1922. //--------------
  1923.  
  1924. get_user_menu(id, menuid, menukeys);
  1925. if (menuid == 0 || menuid == g_menuChooseMap)
  1926. {
  1927. show_menu(id, allKeys, menuDirty, (isVoteOver) ? 5 : max(1, g_voteDuration), MENU_CHOOSEMAP);
  1928. }
  1929. }
  1930. }
  1931. // dbg code ----
  1932. if (id == 1)
  1933. {
  1934. dbg_log(4, "");
  1935. }
  1936. //--------------
  1937. }
  1938. }
  1939. }
  1940.  
  1941. vote_getTallyStr(voteTally[], voteTallyLen, voteCnt)
  1942. {
  1943. if (voteCnt && get_pcvar_num(cvar_voteStatusType) == SHOWSTATUSTYPE_PERCENTAGE)
  1944. {
  1945. voteCnt = percent(voteCnt, g_votesCast);
  1946. }
  1947.  
  1948. if (get_pcvar_num(cvar_voteStatus) && voteCnt)
  1949. {
  1950. formatex(voteTally, voteTallyLen, " %s(%i%s)", CLR_GREY, voteCnt, g_voteTallyType);
  1951. }
  1952. else
  1953. {
  1954. voteTally[0] = 0;
  1955. }
  1956. }
  1957.  
  1958. public vote_expire()
  1959. {
  1960. g_voteStatus |= VOTE_HAS_EXPIRED;
  1961.  
  1962. // dbg code ----
  1963. if (get_realplayersnum())
  1964. {
  1965. dbg_log(4, "");
  1966. dbg_log(4, " [VOTE RESULT]");
  1967. new voteTally[16];
  1968. for (new idxChoice = 0; idxChoice <= g_choiceCnt; ++idxChoice)
  1969. {
  1970. vote_getTallyStr(voteTally, sizeof(voteTally)-1, g_mapVote[idxChoice]);
  1971. dbg_log(4, " %2i/%3i %i. %s", g_mapVote[idxChoice], voteTally, idxChoice, g_mapChoice[idxChoice]);
  1972. }
  1973. dbg_log(4, "");
  1974. }
  1975. //--------------
  1976.  
  1977. g_vote[0] = 0;
  1978.  
  1979. // determine the number of votes for 1st and 2nd place
  1980. new firstPlaceVoteCnt, secondPlaceVoteCnt, totalVotes;
  1981. for (new idxChoice = 0; idxChoice <= g_choiceCnt; ++idxChoice)
  1982. {
  1983. totalVotes += g_mapVote[idxChoice];
  1984.  
  1985. if (firstPlaceVoteCnt < g_mapVote[idxChoice])
  1986. {
  1987. secondPlaceVoteCnt = firstPlaceVoteCnt;
  1988. firstPlaceVoteCnt = g_mapVote[idxChoice];
  1989. }
  1990. else if (secondPlaceVoteCnt < g_mapVote[idxChoice])
  1991. {
  1992. secondPlaceVoteCnt = g_mapVote[idxChoice];
  1993. }
  1994. }
  1995.  
  1996. // determine which maps are in 1st and 2nd place
  1997. new firstPlace[MAX_MAPS_IN_VOTE + 1], firstPlaceCnt;
  1998. new secondPlace[MAX_MAPS_IN_VOTE + 1], secondPlaceCnt;
  1999.  
  2000. for (new idxChoice = 0; idxChoice <= g_choiceCnt; ++idxChoice)
  2001. {
  2002. if (g_mapVote[idxChoice] == firstPlaceVoteCnt)
  2003. {
  2004. firstPlace[firstPlaceCnt++] = idxChoice;
  2005. }
  2006. else if (g_mapVote[idxChoice] == secondPlaceVoteCnt)
  2007. {
  2008. secondPlace[secondPlaceCnt++] = idxChoice;
  2009. }
  2010. }
  2011.  
  2012. // announce the outcome
  2013. new idxWinner;
  2014. if (firstPlaceVoteCnt)
  2015. {
  2016. // start a runoff vote, if needed
  2017. if (get_pcvar_num(cvar_runoffEnabled) && !(g_voteStatus & VOTE_IS_RUNOFF))
  2018. {
  2019. // if the top vote getting map didn't receive over 50% of the votes cast, start runoff vote
  2020. if (firstPlaceVoteCnt <= totalVotes / 2)
  2021. {
  2022. // announce runoff voting requirement
  2023. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_RUNOFF_REQUIRED");
  2024. if (!(get_pcvar_num(cvar_soundsMute) & SOUND_RUNOFFREQUIRED))
  2025. {
  2026. client_cmd(0, "spk ^"run officer(e40) voltage(e30) accelerating(s70) is required^"");
  2027. }
  2028.  
  2029. // let the server know the next vote will be a runoff
  2030. g_voteStatus |= VOTE_IS_RUNOFF;
  2031.  
  2032. // determine the two choices that will be facing off
  2033. new choice1Idx, choice2Idx;
  2034. if (firstPlaceCnt > 2)
  2035. {
  2036. choice1Idx = random_num(0, firstPlaceCnt - 1);
  2037. choice2Idx = random_num(0, firstPlaceCnt - 1);
  2038.  
  2039. if (choice2Idx == choice1Idx)
  2040. {
  2041. choice2Idx = (choice2Idx == firstPlaceCnt - 1) ? 0 : ++choice2Idx;
  2042. }
  2043.  
  2044. g_runoffChoice[0] = firstPlace[choice1Idx];
  2045. g_runoffChoice[1] = firstPlace[choice2Idx];
  2046.  
  2047. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_RESULT_TIED1", firstPlaceCnt);
  2048. }
  2049. else if (firstPlaceCnt == 2)
  2050. {
  2051. g_runoffChoice[0] = firstPlace[0];
  2052. g_runoffChoice[1] = firstPlace[1];
  2053. }
  2054. else if (secondPlaceCnt == 1)
  2055. {
  2056. g_runoffChoice[0] = firstPlace[0];
  2057. g_runoffChoice[1] = secondPlace[0];
  2058. }
  2059. else
  2060. {
  2061. g_runoffChoice[0] = firstPlace[0];
  2062. g_runoffChoice[1] = secondPlace[random_num(0, secondPlaceCnt - 1)];
  2063.  
  2064. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_RESULT_TIED2", secondPlaceCnt);
  2065. }
  2066.  
  2067. /*
  2068. // dbg
  2069. new dbg1 = g_runoffChoice[0];
  2070. new dbg2 = g_runoffChoice[1];
  2071. client_print(0, print_chat, "%s, %s", g_mapChoice[dbg1], g_mapChoice[dbg2]);
  2072. */
  2073.  
  2074. // clear all the votes
  2075. vote_resetStats();
  2076.  
  2077. // start the runoff vote
  2078. set_task(5.0, "vote_startDirector");
  2079.  
  2080. return;
  2081. }
  2082. }
  2083.  
  2084. // if there is a tie for 1st, randomly select one as the winner
  2085. if (firstPlaceCnt > 1)
  2086. {
  2087. idxWinner = firstPlace[random_num(0, firstPlaceCnt - 1)];
  2088. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_WINNER_TIED", firstPlaceCnt);
  2089. }
  2090. else
  2091. {
  2092. idxWinner = firstPlace[0];
  2093. }
  2094.  
  2095. if (idxWinner == g_choiceCnt)
  2096. {
  2097. if (get_pcvar_num(cvar_endOfMapVote))
  2098. {
  2099. new nextMap[32];
  2100. formatex(nextMap, sizeof(nextMap)-1, "%L", LANG_SERVER, "GAL_NEXTMAP_UNKNOWN");
  2101. map_setNext(nextMap);
  2102. }
  2103.  
  2104. // restart map end vote task
  2105. g_pauseMapEndVoteTask = false;
  2106.  
  2107. if (g_voteStatus & VOTE_IS_EARLY)
  2108. {
  2109. // "stay here" won
  2110. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_WINNER_STAY");
  2111.  
  2112. // clear all the votes
  2113. vote_resetStats();
  2114.  
  2115. // no longer is an early vote
  2116. g_voteStatus &= ~VOTE_IS_EARLY;
  2117. }
  2118. else
  2119. {
  2120. // "extend map" won
  2121. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_WINNER_EXTEND", floatround(get_pcvar_float(cvar_extendmapStep)));
  2122. map_extend();
  2123. }
  2124. }
  2125. else
  2126. {
  2127. map_setNext(g_mapChoice[idxWinner]);
  2128. server_exec();
  2129.  
  2130. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_NEXTMAP", g_mapChoice[idxWinner]);
  2131.  
  2132. g_voteStatus |= VOTE_IS_OVER;
  2133. }
  2134. }
  2135. else
  2136. {
  2137. // nobody voted. pick a random map from the choices provided.
  2138. idxWinner = random_num(0, g_choiceCnt - 1);
  2139. map_setNext(g_mapChoice[idxWinner]);
  2140.  
  2141. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_WINNER_RANDOM", g_mapChoice[idxWinner]);
  2142.  
  2143. g_voteStatus |= VOTE_IS_OVER;
  2144. }
  2145.  
  2146. g_refreshVoteStatus = true;
  2147.  
  2148. new playerCnt = get_realplayersnum();
  2149.  
  2150. // vote is no longer in progress
  2151. g_voteStatus &= ~VOTE_IN_PROGRESS;
  2152.  
  2153. if (g_handleMapChange)
  2154. {
  2155. if ((g_voteStatus & VOTE_FORCED || (playerCnt == 1 && idxWinner < g_choiceCnt) || playerCnt == 0) && !(get_cvar_num("gal_debug") & 4))
  2156. {
  2157. // tell the map we need to finish up
  2158. set_task(2.0, "map_manageEnd");
  2159. }
  2160. else
  2161. {
  2162. // restart map end task
  2163. g_pauseMapEndManagerTask = false;
  2164. }
  2165. }
  2166. }
  2167.  
  2168. map_extend()
  2169. {
  2170. dbg_log(2, "%32s mp_timelimit: %f g_rtvWait: %f extendmapStep: %f", "map_extend(in)", get_cvar_float("mp_timelimit"), g_rtvWait, get_pcvar_float(cvar_extendmapStep));
  2171.  
  2172. // reset the "rtv wait" time, taking into consideration the map extension
  2173. if (g_rtvWait)
  2174. {
  2175. g_rtvWait = get_cvar_float("mp_timelimit") + g_rtvWait;
  2176. }
  2177.  
  2178. // do that actual map extension
  2179. set_cvar_float("mp_timelimit", get_cvar_float("mp_timelimit") + get_pcvar_float(cvar_extendmapStep));
  2180. server_exec();
  2181.  
  2182. // clear vote stats
  2183. vote_resetStats();
  2184.  
  2185. // if we were in a runoff mode, get out of it
  2186. g_voteStatus &= ~VOTE_IS_RUNOFF;
  2187.  
  2188. dbg_log(2, "%32s mp_timelimit: %f g_rtvWait: %f extendmapStep: %f", "map_extend(out)", get_cvar_float("mp_timelimit"), g_rtvWait, get_pcvar_float(cvar_extendmapStep));
  2189. }
  2190.  
  2191. vote_resetStats()
  2192. {
  2193. // g_vote[0] = 0;
  2194. g_votesCast = 0;
  2195. arrayset(g_mapVote, 0, MAX_MAPS_IN_VOTE + 1);
  2196. // reset everyones' rocks
  2197. arrayset(g_rockedVote, false, sizeof(g_rockedVote));
  2198. g_rockedVoteCnt = 0;
  2199. // reset everyones' votes
  2200. // arrayset(g_voted, false, sizeof(g_voted));
  2201. }
  2202.  
  2203. map_isInMenu(map[])
  2204. {
  2205. for (new idxChoice = 0; idxChoice < g_choiceCnt; ++idxChoice)
  2206. {
  2207. if (equal(map, g_mapChoice[idxChoice]))
  2208. {
  2209. return true;
  2210. }
  2211. }
  2212. return false;
  2213. }
  2214.  
  2215. prefix_isInMenu(map[])
  2216. {
  2217. if (get_pcvar_num(cvar_voteUniquePrefixes))
  2218. {
  2219. new tentativePrefix[8], existingPrefix[8], junk[8];
  2220.  
  2221. strtok(map, tentativePrefix, sizeof(tentativePrefix)-1, junk, sizeof(junk)-1, '_', 1);
  2222.  
  2223. for (new idxChoice = 0; idxChoice < g_choiceCnt; ++idxChoice)
  2224. {
  2225. strtok(g_mapChoice[idxChoice], existingPrefix, sizeof(existingPrefix)-1, junk, sizeof(junk)-1, '_', 1);
  2226.  
  2227. if (equal(tentativePrefix, existingPrefix))
  2228. {
  2229. return true;
  2230. }
  2231. }
  2232. }
  2233. return false;
  2234. }
  2235.  
  2236. map_isTooRecent(map[])
  2237. {
  2238. if (get_pcvar_num(cvar_banRecent))
  2239. {
  2240. for (new idxBannedMap = 0; idxBannedMap < g_cntRecentMap; ++idxBannedMap)
  2241. {
  2242. if (equal(map, g_recentMap[idxBannedMap]))
  2243. {
  2244. return true;
  2245. }
  2246. }
  2247. }
  2248. return false;
  2249. }
  2250.  
  2251. public vote_handleChoice(id, key)
  2252. {
  2253. if (g_voteStatus & VOTE_HAS_EXPIRED)
  2254. {
  2255. client_cmd(id, "^"slot%i^"", key + 1);
  2256. return;
  2257. }
  2258.  
  2259. g_snuffDisplay[id] = true;
  2260.  
  2261. if (g_voted[id] == false)
  2262. {
  2263. new name[32];
  2264. if (get_pcvar_num(cvar_voteAnnounceChoice))
  2265. {
  2266. get_user_name(id, name, sizeof(name)-1);
  2267. }
  2268.  
  2269. // dbg code ----
  2270. get_user_name(id, name, sizeof(name)-1);
  2271. //--------------
  2272.  
  2273. // confirm the player's choice
  2274. if (key == 9)
  2275. {
  2276. dbg_log(4, " %-32s (none)", name);
  2277.  
  2278. if (get_pcvar_num(cvar_voteAnnounceChoice))
  2279. {
  2280. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CHOICE_NONE_ALL", name);
  2281. }
  2282. else
  2283. {
  2284. client_print(id, print_chat, "%L", id, "GAL_CHOICE_NONE");
  2285. }
  2286. }
  2287. else
  2288. {
  2289. // increment votes cast count
  2290. g_votesCast++;
  2291.  
  2292. if (key == g_choiceCnt)
  2293. {
  2294. // only display the "none" vote if we haven't already voted (we can make it here from the vote status menu too)
  2295. if (g_voted[id] == false)
  2296. {
  2297. dbg_log(4, " %-32s (extend)", name);
  2298.  
  2299. if (get_pcvar_num(cvar_voteAnnounceChoice))
  2300. {
  2301. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CHOICE_EXTEND_ALL", name);
  2302. }
  2303. else
  2304. {
  2305. client_print(id, print_chat, "%L", id, "GAL_CHOICE_EXTEND");
  2306. }
  2307. }
  2308. }
  2309. else
  2310. {
  2311. dbg_log(4, " %-32s %s", name, g_mapChoice[key]);
  2312.  
  2313. if (get_pcvar_num(cvar_voteAnnounceChoice))
  2314. {
  2315. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CHOICE_MAP_ALL", name, g_mapChoice[key]);
  2316. }
  2317. else
  2318. {
  2319. client_print(id, print_chat, "%L", id, "GAL_CHOICE_MAP", g_mapChoice[key]);
  2320. }
  2321. }
  2322.  
  2323. // register the player's choice giving extra weight to admin votes
  2324. new voteWeight = get_pcvar_num(cvar_voteWeight);
  2325. if (voteWeight > 1 && has_flag(id, g_voteWeightFlags))
  2326. {
  2327. g_mapVote[key] += voteWeight;
  2328. g_votesCast += (voteWeight - 1);
  2329. client_print(id, print_chat, "%L", id, "GAL_VOTE_WEIGHTED", voteWeight);
  2330. }
  2331. else
  2332. {
  2333. g_mapVote[key]++;
  2334. }
  2335. }
  2336.  
  2337. g_voted[id] = true;
  2338. g_refreshVoteStatus = true;
  2339. }
  2340. else
  2341. {
  2342. client_cmd(id, "^"slot%i^"", key + 1);
  2343. }
  2344.  
  2345. // display the vote again, with status
  2346. if (get_pcvar_num(cvar_voteStatus) == SHOWSTATUS_VOTE)
  2347. {
  2348. new arg[3];
  2349. arg[0] = false;
  2350. arg[1] = id;
  2351. arg[2] = true;
  2352.  
  2353. set_task(0.1, "vote_display", _, arg, sizeof(arg));
  2354. //vote_display(arg);
  2355. }
  2356. }
  2357.  
  2358. public map_change()
  2359. {
  2360. // restore the map's timelimit, just in case we had changed it
  2361. map_restoreOriginalTimeLimit();
  2362.  
  2363. // grab the name of the map we're changing to
  2364. new map[MAX_MAPNAME_LEN + 1];
  2365. get_cvar_string("amx_nextmap", map, sizeof(map)-1);
  2366.  
  2367. // verify we're changing to a valid map
  2368. if (!is_map_valid(map))
  2369. {
  2370. // probably admin did something dumb like changed the map time limit below
  2371. // the time remaining in the map, thus making the map over immediately.
  2372. // since the next map is unknown, just restart the current map.
  2373. copy(map, sizeof(map)-1, g_currentMap);
  2374. }
  2375.  
  2376. // change to the map
  2377. server_cmd("changelevel %s", map);
  2378. }
  2379.  
  2380. Float:map_getMinutesElapsed()
  2381. {
  2382. dbg_log(2, "%32s mp_timelimit: %f", "map_getMinutesElapsed(in/out)", get_cvar_float("mp_timelimit"));
  2383. return get_cvar_float("mp_timelimit") - (float(get_timeleft()) / 60.0);
  2384. }
  2385.  
  2386. public vote_rock(id)
  2387. {
  2388. // if an early vote is pending, don't allow any rocks
  2389. if (g_voteStatus & VOTE_IS_EARLY)
  2390. {
  2391. client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_PENDINGVOTE");
  2392. return;
  2393. }
  2394.  
  2395. new Float:minutesElapsed = map_getMinutesElapsed();
  2396.  
  2397. // if the player is the only one on the server, bring up the vote immediately
  2398. if (get_realplayersnum() == 1 && minutesElapsed > floatmin(2.0, g_rtvWait))
  2399. {
  2400. vote_startDirector(true);
  2401. return;
  2402. }
  2403.  
  2404. // make sure enough time has gone by on the current map
  2405. if (g_rtvWait)
  2406. {
  2407. if (minutesElapsed < g_rtvWait)
  2408. {
  2409. client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_TOOSOON", floatround(g_rtvWait - minutesElapsed, floatround_ceil));
  2410. return;
  2411. }
  2412. }
  2413.  
  2414. // rocks can only be made if a vote isn't already in progress
  2415. if (g_voteStatus & VOTE_IN_PROGRESS)
  2416. {
  2417. client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_INPROGRESS");
  2418. return;
  2419. }
  2420. // and if the outcome of the vote hasn't already been determined
  2421. else if (g_voteStatus & VOTE_IS_OVER)
  2422. {
  2423. client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_VOTEOVER");
  2424. return;
  2425. }
  2426.  
  2427. // determine how many total rocks are needed
  2428. new rocksNeeded = vote_getRocksNeeded();
  2429.  
  2430. // make sure player hasn't already rocked the vote
  2431. if (g_rockedVote[id])
  2432. {
  2433. client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_ALREADY", rocksNeeded - g_rockedVoteCnt);
  2434. rtv_remind(TASKID_REMINDER + id);
  2435. return;
  2436. }
  2437.  
  2438. // allow the player to rock the vote
  2439. g_rockedVote[id] = true;
  2440. client_print(id, print_chat, "%L", id, "GAL_ROCK_SUCCESS");
  2441.  
  2442. // make sure the rtv reminder timer has stopped
  2443. if (task_exists(TASKID_REMINDER))
  2444. {
  2445. remove_task(TASKID_REMINDER);
  2446. }
  2447.  
  2448. // determine if there have been enough rocks for a vote yet
  2449. if (++g_rockedVoteCnt >= rocksNeeded)
  2450. {
  2451. // announce that the vote has been rocked
  2452. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_ROCK_ENOUGH");
  2453.  
  2454. // start up the vote director
  2455. vote_startDirector(true);
  2456. }
  2457. else
  2458. {
  2459. // let the players know how many more rocks are needed
  2460. rtv_remind(TASKID_REMINDER);
  2461.  
  2462. if (get_pcvar_num(cvar_rtvReminder))
  2463. {
  2464. // initialize the rtv reminder timer to repeat how many rocks are still needed, at regular intervals
  2465. set_task(get_pcvar_float(cvar_rtvReminder) * 60.0, "rtv_remind", TASKID_REMINDER, _, _, "b");
  2466. }
  2467. }
  2468. }
  2469.  
  2470. vote_unrock(id)
  2471. {
  2472. if (g_rockedVote[id])
  2473. {
  2474. g_rockedVote[id] = false;
  2475. g_rockedVoteCnt--;
  2476. // and such
  2477. }
  2478. }
  2479.  
  2480. vote_getRocksNeeded()
  2481. {
  2482. return floatround(get_pcvar_float(cvar_rtvRatio) * float(get_realplayersnum()), floatround_ceil);
  2483. }
  2484.  
  2485. public rtv_remind(param)
  2486. {
  2487. new who = param - TASKID_REMINDER;
  2488.  
  2489. // let the players know how many more rocks are needed
  2490. client_print(who, print_chat, "%L", LANG_PLAYER, "GAL_ROCK_NEEDMORE", vote_getRocksNeeded() - g_rockedVoteCnt);
  2491. }
  2492.  
  2493. public cmd_listmaps(id)
  2494. {
  2495. // new arg1[8];
  2496. // new start = read_argv(1, arg1, 7) ? str_to_num(arg1) : 1;
  2497.  
  2498. map_listAll(id);
  2499.  
  2500. return PLUGIN_HANDLED;
  2501. }
  2502.  
  2503. public cmd_HL1_votemap(id)
  2504. {
  2505. if (get_pcvar_num(cvar_cmdVotemap) == 0)
  2506. {
  2507. con_print(id, "%L", id, "GAL_DISABLED");
  2508. return PLUGIN_HANDLED;
  2509. }
  2510. return PLUGIN_CONTINUE;
  2511. }
  2512.  
  2513. public cmd_HL1_listmaps(id)
  2514. {
  2515. switch (get_pcvar_num(cvar_cmdListmaps))
  2516. {
  2517. case 0:
  2518. {
  2519. con_print(id, "%L", id, "GAL_DISABLED");
  2520. }
  2521. case 2:
  2522. {
  2523. map_listAll(id);
  2524. }
  2525. default:
  2526. {
  2527. return PLUGIN_CONTINUE;
  2528. }
  2529. }
  2530. return PLUGIN_HANDLED;
  2531. }
  2532.  
  2533. map_listAll(id)
  2534. {
  2535. static lastMapDisplayed[MAX_PLAYER_CNT + 1][2];
  2536.  
  2537. // determine if the player has requested a listing before
  2538. new userid = get_user_userid(id);
  2539. if (userid != lastMapDisplayed[id][LISTMAPS_USERID])
  2540. {
  2541. lastMapDisplayed[id][LISTMAPS_USERID] = 0;
  2542. }
  2543.  
  2544. new command[32];
  2545. read_argv(0, command, sizeof(command)-1);
  2546.  
  2547. new arg1[8], start;
  2548. new mapCount = get_pcvar_num(cvar_listmapsPaginate);
  2549.  
  2550. if (mapCount)
  2551. {
  2552. if (read_argv(1, arg1, sizeof(arg1)-1))
  2553. {
  2554. if (arg1[0] == '*')
  2555. {
  2556. // if the last map previously displayed belongs to the current user,
  2557. // start them off there, otherwise, start them at 1
  2558. if (lastMapDisplayed[id][LISTMAPS_USERID])
  2559. {
  2560. start = lastMapDisplayed[id][LISTMAPS_LAST] + 1;
  2561. }
  2562. else
  2563. {
  2564. start = 1;
  2565. }
  2566. }
  2567. else
  2568. {
  2569. start = str_to_num(arg1);
  2570. }
  2571. }
  2572. else
  2573. {
  2574. start = 1;
  2575. }
  2576.  
  2577. if (id == 0 && read_argc() == 3 && read_argv(2, arg1, sizeof(arg1)-1))
  2578. {
  2579. mapCount = str_to_num(arg1);
  2580. }
  2581. }
  2582.  
  2583. if (start < 1)
  2584. {
  2585. start = 1;
  2586. }
  2587.  
  2588. if (start >= g_nominationMapCnt)
  2589. {
  2590. start = g_nominationMapCnt - 1;
  2591. }
  2592.  
  2593. new end = mapCount ? start + mapCount - 1 : g_nominationMapCnt;
  2594.  
  2595. if (end > g_nominationMapCnt)
  2596. {
  2597. end = g_nominationMapCnt;
  2598. }
  2599.  
  2600. // this enables us to use 'command *' to get the next group of maps, when paginated
  2601. lastMapDisplayed[id][LISTMAPS_USERID] = userid;
  2602. lastMapDisplayed[id][LISTMAPS_LAST] = end - 1;
  2603.  
  2604. con_print(id, "^n----- %L -----", id, "GAL_LISTMAPS_TITLE", g_nominationMapCnt);
  2605.  
  2606. new nominated[64], nominator_id, name[32], mapName[32], idx;
  2607. for (idx = start - 1; idx < end; idx++)
  2608. {
  2609. nominator_id = nomination_getPlayer(idx);
  2610. if (nominator_id)
  2611. {
  2612. get_user_name(nominator_id, name, sizeof(name)-1);
  2613. formatex(nominated, sizeof(nominated)-1, "%L", id, "GAL_NOMINATEDBY", name);
  2614. }
  2615. else
  2616. {
  2617. nominated[0] = 0;
  2618. }
  2619. ArrayGetString(g_nominationMap, idx, mapName, sizeof(mapName)-1);
  2620. con_print(id, "%3i: %s %s", idx + 1, mapName, nominated);
  2621. }
  2622.  
  2623. if (mapCount && mapCount < g_nominationMapCnt)
  2624. {
  2625. con_print(id, "----- %L -----", id, "GAL_LISTMAPS_SHOWING", start, idx, g_nominationMapCnt);
  2626.  
  2627. if (end < g_nominationMapCnt)
  2628. {
  2629. con_print(id, "----- %L -----", id, "GAL_LISTMAPS_MORE", command, end + 1, command);
  2630. }
  2631. }
  2632. }
  2633.  
  2634. /*
  2635. map_listMatches(id, match[])
  2636. {
  2637. strtolower(match);
  2638. con_print(id, "%L", id, "GAL_MATCHING", match);
  2639. con_print(id, "------------------------------------------");
  2640.  
  2641. new mapName[32], matchCnt;
  2642. new nominated[64], nominator_id, name[32];
  2643.  
  2644. for (new idx = 1; idx <= g_nominationMapCnt; ++idx)
  2645. {
  2646. copy(mapName, sizeof(mapName)-1, g_nominationMap[idx]);
  2647. strtolower(mapName);
  2648.  
  2649. if (containi(mapName, match) > -1)
  2650. {
  2651. nominator_id = nomination_getPlayer(idx);
  2652. if (nominator_id)
  2653. {
  2654. get_user_name(nominator_id, name, sizeof(name)-1);
  2655. formatex(nominated, sizeof(nominated)-1, "(nominated by %s)", name);
  2656. }
  2657. else
  2658. {
  2659. nominated[0] = 0;
  2660. }
  2661. con_print(id, "%3i: %s %s", ++matchCnt, g_nominationMap[idx], nominated);
  2662. }
  2663. }
  2664. }
  2665. */
  2666.  
  2667. con_print(id, message[], {Float,Sql,Result,_}:...)
  2668. {
  2669. new consoleMessage[256];
  2670. vformat(consoleMessage, sizeof(consoleMessage)-1, message, 3);
  2671.  
  2672. if (id)
  2673. {
  2674. new authid[32];
  2675. get_user_authid(id, authid, 31);
  2676.  
  2677. if (!equal(authid, "STEAM_ID_LAN"))
  2678. {
  2679. console_print(id, consoleMessage);
  2680. return;
  2681. }
  2682. }
  2683.  
  2684. server_print(consoleMessage);
  2685. }
  2686.  
  2687. public client_disconnect(id)
  2688. {
  2689. g_voted[id] = false;
  2690.  
  2691. // un-rock the vote
  2692. vote_unrock(id);
  2693.  
  2694. // cancel player's nominations
  2695. new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);
  2696. new nominatedMaps[256], nominationCnt, idxMap, mapName[32];
  2697. for (new idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
  2698. {
  2699. idxMap = g_nomination[id][idxNomination];
  2700. if (idxMap >= 0)
  2701. {
  2702. ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
  2703. nominationCnt++;
  2704. format(nominatedMaps, sizeof(nominatedMaps)-1, "%s%s, ", nominatedMaps, mapName);
  2705. g_nomination[id][idxNomination] = -1;
  2706. }
  2707. }
  2708. if (nominationCnt)
  2709. {
  2710. // strip the extraneous ", " from the string
  2711. nominatedMaps[strlen(nominatedMaps) - 2] = 0;
  2712.  
  2713. // inform the masses that the maps are no longer nominated
  2714. nomination_announceCancellation(nominatedMaps);
  2715. }
  2716.  
  2717. new dbg_playerCnt = get_realplayersnum()-1;
  2718. dbg_log(2, "%32s dbg_playerCnt:%i", "client_disconnect()", dbg_playerCnt);
  2719.  
  2720. if (dbg_playerCnt == 0)
  2721. {
  2722. srv_handleEmpty();
  2723. }
  2724. }
  2725.  
  2726. public client_connect(id)
  2727. {
  2728. set_pcvar_num(cvar_emptyCycle, 0);
  2729.  
  2730. vote_unrock(id);
  2731. }
  2732.  
  2733. public client_putinserver(id)
  2734. {
  2735. if ((g_voteStatus & VOTE_IS_EARLY) && !is_user_bot(id) && !is_user_hltv(id))
  2736. {
  2737. set_task(20.0, "srv_announceEarlyVote", id);
  2738. }
  2739. }
  2740.  
  2741. srv_handleEmpty()
  2742. {
  2743. dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "srv_handleEmpty(in)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
  2744.  
  2745. if (g_originalTimelimit != get_cvar_float("mp_timelimit"))
  2746. {
  2747. // it's possible that the map has been extended at least once. that
  2748. // means that if someone comes into the server, the time limit will
  2749. // be the extended time limit rather than the normal time limit. bad.
  2750. // reset the original time limit
  2751. map_restoreOriginalTimeLimit();
  2752. }
  2753.  
  2754. // might be utilizing "empty server" feature
  2755. if (g_isUsingEmptyCycle && g_emptyMapCnt)
  2756. {
  2757. srv_startEmptyCountdown();
  2758. }
  2759.  
  2760. dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "srv_handleEmpty(out)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
  2761. }
  2762.  
  2763. public srv_announceEarlyVote(id)
  2764. {
  2765. if (is_user_connected(id))
  2766. {
  2767. //client_print(id, print_chat, "%L", id, "GAL_VOTE_EARLY");
  2768. new text[101];
  2769. formatex(text, sizeof(text)-1, "^x04%L", id, "GAL_VOTE_EARLY");
  2770. print_color(id, text);
  2771. }
  2772. }
  2773.  
  2774. public srv_initEmptyCheck()
  2775. {
  2776. if (get_pcvar_num(cvar_emptyWait))
  2777. {
  2778. if ((get_realplayersnum()) == 0 && !get_pcvar_num(cvar_emptyCycle))
  2779. {
  2780. srv_startEmptyCountdown();
  2781. }
  2782. g_isUsingEmptyCycle = true;
  2783. }
  2784. }
  2785.  
  2786. srv_startEmptyCountdown()
  2787. {
  2788. new waitMinutes = get_pcvar_num(cvar_emptyWait);
  2789. if (waitMinutes)
  2790. {
  2791. set_task(float(waitMinutes * 60), "srv_startEmptyCycle", TASKID_EMPTYSERVER);
  2792. }
  2793. }
  2794.  
  2795. public srv_startEmptyCycle()
  2796. {
  2797. set_pcvar_num(cvar_emptyCycle, 1);
  2798.  
  2799. // set the next map from the empty cycle list,
  2800. // or the first one, if the current map isn't part of the cycle
  2801. new nextMap[32], mapIdx;
  2802. mapIdx = map_getNext(g_emptyCycleMap, g_currentMap, nextMap);
  2803. map_setNext(nextMap);
  2804.  
  2805. // if the current map isn't part of the empty cycle,
  2806. // immediately change to next map that is
  2807. if (mapIdx == -1)
  2808. {
  2809. map_change();
  2810. }
  2811. }
  2812.  
  2813. nomination_announceCancellation(nominations[])
  2814. {
  2815. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CANCEL_SUCCESS", nominations);
  2816. }
  2817.  
  2818. nomination_clearAll()
  2819. {
  2820. for (new idxPlayer = 1; idxPlayer <= MAX_PLAYER_CNT; idxPlayer++)
  2821. {
  2822. for (new idxNomination = 1; idxNomination <= MAX_NOMINATION_CNT; idxNomination++)
  2823. {
  2824. g_nomination[idxPlayer][idxNomination] = -1;
  2825. }
  2826. }
  2827. g_nominationCnt = 0;
  2828. }
  2829.  
  2830. map_announceNomination(id, map[])
  2831. {
  2832. new name[32];
  2833. get_user_name(id, name, sizeof(name)-1);
  2834.  
  2835. client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_NOM_SUCCESS", name, map);
  2836. }
  2837.  
  2838. #if AMXX_VERSION_NUM < 180
  2839. has_flag(id, flags[])
  2840. {
  2841. return (get_user_flags(id) & read_flags(flags));
  2842. }
  2843. #endif
  2844.  
  2845. public sort_stringsi(const elem1[], const elem2[], const array[], data[], data_size)
  2846. {
  2847. return strcmp(elem1, elem2, 1);
  2848. }
  2849.  
  2850. stock get_realplayersnum()
  2851. {
  2852. new players[32], playerCnt;
  2853. get_players(players, playerCnt, "ch");
  2854.  
  2855. return playerCnt;
  2856. }
  2857.  
  2858. stock percent(is, of)
  2859. {
  2860. return (of != 0) ? floatround(floatmul(float(is)/float(of), 100.0)) : 0;
  2861. }
  2862.  
  2863. print_color(id, text[])
  2864. {
  2865. message_begin(MSG_ONE, get_user_msgid("SayText"), {0, 0, 0}, id);
  2866. write_byte(id);
  2867. write_string(text);
  2868. message_end();
  2869. }
  2870.  
  2871. map_restoreOriginalTimeLimit()
  2872. {
  2873. dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "map_restoreOriginalTimeLimit(in)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
  2874. if (g_originalTimelimit != TIMELIMIT_NOT_SET)
  2875. {
  2876. server_cmd("mp_timelimit %f", g_originalTimelimit);
  2877. server_exec();
  2878. }
  2879. dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "map_restoreOriginalTimeLimit(out)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
  2880. }
  2881.  
  2882. dbg_log(const mode, const text[] = "", {Float,Sql,Result,_}:...)
  2883. {
  2884. new dbg = get_cvar_num("gal_debug");
  2885. if (mode & dbg)
  2886. {
  2887. // format the text as needed
  2888. new formattedText[1024];
  2889. format_args(formattedText, 1023, 1);
  2890. // grab the current game time
  2891. new Float:gameTime = get_gametime();
  2892. // log text to file
  2893. log_to_file("_galileo.log", "{%3.4f} %s", gameTime, formattedText);
  2894.  
  2895. if (dbg & 1 && formattedText[0])
  2896. {
  2897. // make quotes in log text palatable to 3rd party chat log viewers
  2898. new isFound = 1;
  2899. while (isFound) isFound = replace(formattedText, 1023, "^"", "'");
  2900. // print to the server log so as to be picked up by programs such as HLSW
  2901. log_message("^"<><><>^" triggered ^"amx_chat^" (text ^"[GAL] %s^")", formattedText);
  2902. }
  2903. }
  2904. // not needed but gets rid of stupid compiler error
  2905. if (text[0] == 0) return;
  2906. }
Add Comment
Please, Sign In to add comment