// vim: set ts=4 sw=4 tw=99 noet: // // AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). // Copyright (C) The AMX Mod X Development Team. // // This software is licensed under the GNU General Public License, version 3 or higher. // Additional exceptions apply. For full license details, see LICENSE.txt or visit: // https://alliedmods.net/amxmodx-license // // Natural Selection NextMap Plugin // enum mapdata { NAME[32], MIN, MAX } #include #include #define MAX_MAPS 128 #define INFO_READ_TIME 5.0 new g_mapCycle[MAX_MAPS][mapdata] new g_numMaps, g_numPlayers, g_nextPos new bool:g_mapChanging, bool:g_changeMapDelay public plugin_init() { register_plugin("NextMap",AMXX_VERSION_STR,"AMXX Dev Team") register_cvar("amx_nextmap","",FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY) register_cvar("amx_mapnum_ignore", "0") register_event("TextMsg", "voteMap", "a", "1=3", "2&executed votemap") register_event("PlayHUDNot", "roundEnded", "bc", "1=0", "2=57") register_clcmd("say nextmap", "sayNextMap", 0, "- displays nextmap") readMapCycle() findNextMap() } stock bool:ValidMap(mapname[]) { if ( is_map_valid(mapname) ) { return true; } // If the is_map_valid check failed, check the end of the string new len = strlen(mapname) - 4; // The mapname was too short to possibly house the .bsp extension if (len < 0) { return false; } if ( equali(mapname[len], ".bsp") ) { // If the ending was .bsp, then cut it off. // the string is byref'ed, so this copies back to the loaded text. mapname[len] = '^0'; // recheck if ( is_map_valid(mapname) ) { return true; } } return false; } public server_changelevel() { if (g_mapChanging) return BLOCK_ONCE // Check if the cvar "amx_nextmap" has changed since the map loaded as it overrides the min/max settings. new szCvarNextMap[32] get_cvar_string("amx_nextmap", szCvarNextMap, charsmax(szCvarNextMap)) if ( !equal(szCvarNextMap, g_mapCycle[g_nextPos][NAME]) ) { if (ValidMap(szCvarNextMap)) { if (g_changeMapDelay) set_task(INFO_READ_TIME, "changeMap", 0, szCvarNextMap, sizeof(szCvarNextMap)) else changeMap(szCvarNextMap) return BLOCK_ONCE } } new szNextMap[32] getNextValidMap(szNextMap) if (ValidMap(szNextMap)) { if (g_changeMapDelay) set_task(INFO_READ_TIME, "changeMap", 0, szNextMap, sizeof(szNextMap)) else changeMap(szNextMap) } else return BLOCK_NOT // When NS trys to change map it disables gameplay, so we MUST change map. // This is a backup incase something unexpected happens to make sure we change map. g_mapChanging = true return BLOCK_ONCE } public getNextValidMap(szNextMap[]) { /* Test min/max player settings. First test with number of players when the round ended, then with the current number of players, as this is how NS does it. */ new startPos = g_nextPos if (!get_cvar_num("amx_mapnum_ignore")) { new curNumPlayers = get_playersnum() if (g_numPlayers == 0) g_numPlayers = curNumPlayers new looped while(looped < 2) { new minPlayers = g_mapCycle[g_nextPos][MIN] new maxPlayers = g_mapCycle[g_nextPos][MAX] if (maxPlayers == 0) maxPlayers = MAX_PLAYERS if (minPlayers <= g_numPlayers <= maxPlayers) break if (minPlayers <= curNumPlayers <= maxPlayers) { g_numPlayers = curNumPlayers break } if (++g_nextPos == g_numMaps) { g_nextPos = 0 looped++ } } } copy(szNextMap, 31, g_mapCycle[g_nextPos][NAME]) if (startPos != g_nextPos) { // Next Map wasn't valid due to min/max player settings client_print(0, print_chat, "Too %s players for %s. Next valid map: %s", (g_mapCycle[startPos][MIN] <= g_numPlayers) ? "many" : "few", g_mapCycle[startPos][NAME], g_mapCycle[g_nextPos][NAME]) new szPos[8] num_to_str(g_nextPos, szPos, charsmax(szPos)) set_localinfo("amx_nextmap_pos", szPos) set_cvar_string("amx_nextmap", g_mapCycle[g_nextPos][NAME]) g_changeMapDelay = true } } public voteMap() { new szVoteMap[128] read_data(2, szVoteMap, charsmax(szVoteMap)) // "YO | Cheesy Peteza executed votemap 2 (co_angst 1/5)" new start, end, szData[64] for (new i; i