├── cstrike ├── sprites │ └── map_manager │ │ ├── maps.spr │ │ └── cursor2.spr ├── models │ └── map_manager │ │ └── blackbox2.mdl └── addons │ └── amxmodx │ ├── configs │ ├── maplists.ini │ ├── maps.ini │ ├── map_manager_settings.ini │ ├── mappacks.ini │ ├── plugins-map_manager.ini │ └── map_manager.cfg │ ├── scripting │ ├── include │ │ ├── map_manager_blocklist.inc │ │ ├── map_manager_adv_lists.inc │ │ ├── map_manager_nomination.inc │ │ ├── map_manager_consts.inc │ │ ├── map_manager_scheduler.inc │ │ ├── map_manager_stocks.inc │ │ └── map_manager.inc │ ├── map_manager_priority.sma │ ├── map_manager_online_sorter.sma │ ├── map_manager_online_checker.sma │ ├── map_manager_sounds.sma │ ├── map_manager_informer.sma │ ├── map_manager_blocklist.sma │ ├── map_manager_rtv.sma │ ├── map_manager_effects.sma │ ├── map_manager_adv_lists.sma │ ├── map_manager_gui.sma │ ├── map_manager_scheduler.sma │ ├── map_manager_nomination.sma │ └── map_manager_core.sma │ └── data │ └── lang │ └── mapmanager.txt └── .github ├── workflows ├── draft_release.yml └── CI.yml ├── release-drafter.yml └── README.md /cstrike/sprites/map_manager/maps.spr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mistrick/MapManagerModular/HEAD/cstrike/sprites/map_manager/maps.spr -------------------------------------------------------------------------------- /cstrike/models/map_manager/blackbox2.mdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mistrick/MapManagerModular/HEAD/cstrike/models/map_manager/blackbox2.mdl -------------------------------------------------------------------------------- /cstrike/sprites/map_manager/cursor2.spr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mistrick/MapManagerModular/HEAD/cstrike/sprites/map_manager/cursor2.spr -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/configs/maplists.ini: -------------------------------------------------------------------------------- 1 | ; Configuration file for "Advanced lists" addon 2 | ; 3 | ; Format: 4 | ; 5 | ; filename - file must be in amxx configs dir 6 | ; anytime - this list will be always loaded 7 | ; 8 | ; Examples: 9 | ; "Day Maps" "maps.ini" "1" "6:00" "22:59" 10 | ; "Night Maps" "nightmaps.ini" "1" "23:00" "5:59" 11 | ; "Another maps" "another.ini" "0" "anytime" 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/draft_release.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | pull_request: 5 | types: [closed] 6 | 7 | jobs: 8 | update_release_draft: 9 | runs-on: ubuntu-latest 10 | if: github.event.pull_request.merged == true 11 | steps: 12 | - uses: release-drafter/release-drafter@v5 13 | with: 14 | config-name: release-drafter.yml 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/include/map_manager_blocklist.inc: -------------------------------------------------------------------------------- 1 | #if defined _map_manager_blocklist_included 2 | #endinput 3 | #endif 4 | #define _map_manager_blocklist_included 5 | 6 | #if AMXX_VERSION_NUM >= 175 7 | #pragma reqlib map_manager_blocklist 8 | #if !defined AMXMODX_NOAUTOLOAD 9 | #pragma loadlib map_manager_blocklist 10 | #endif 11 | #else 12 | #pragma library map_manager_blocklist 13 | #endif 14 | 15 | /** 16 | * Check map if it in blocklist. 17 | * 18 | * @param map Map name 19 | * 20 | * @return Blocked count 21 | */ 22 | native mapm_get_blocked_count(map[]); -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/configs/maps.ini: -------------------------------------------------------------------------------- 1 | ; Doc for Map Manager maplist ini file 2 | ; 3 | ; Format: 4 | ; [min players, def 0] [max players, def 32] [priority, def 100] 5 | ; 6 | ; map name - map name as is 7 | ; min players - lower range for "Online sorter" addon, valid values from 0 to 32 8 | ; max player - higher range for "Online sorter" addon, valid values from 0 to 32, should be bigger than min players 9 | ; priority - value for "Priority" addon, valid values from 1 to 100; 10 | ; with 1 map has 1% chance to be in vote list, 11 | ; with 100 map has no limits in "Priority" addon but can be blocked with another addon 12 | ; 13 | ; Examples: 14 | ; de_nuke 15 | ; de_dust 0 10 16 | ; de_dust2 5 32 70 17 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/configs/map_manager_settings.ini: -------------------------------------------------------------------------------- 1 | ;nomination 2 | 3 | ; Say command for opening maplist menu. 4 | [nomination_maplist_commands] 5 | maps 6 | /maps 7 | 8 | ; Say command for nominated maps. 9 | [nomination_nominated_maps_commands] 10 | nominations 11 | /nominations 12 | 13 | ;sounds 14 | 15 | ; Sound played when vote started 16 | ; Can be empty 17 | [sound_vote_started] 18 | "sound/Gman/Gman_Choose2.wav" 19 | 20 | ; Sound played when vote finished 21 | ; Can be empty 22 | [sound_vote_finished] 23 | ; 24 | 25 | ; Sounds for countdown 26 | ; key should be number for countdown 27 | ; value should be sound for this countdown 28 | [sounds_countdown] 29 | "1" = "sound/fvox/one.wav" 30 | "2" = "sound/fvox/two.wav" 31 | "3" = "sound/fvox/three.wav" 32 | "4" = "sound/fvox/four.wav" 33 | "5" = "sound/fvox/five.wav" 34 | "6" = "sound/fvox/six.wav" 35 | "7" = "sound/fvox/seven.wav" 36 | "8" = "sound/fvox/eight.wav" 37 | "9" = "sound/fvox/nine.wav" 38 | "10" = "sound/fvox/ten.wav" 39 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: "Release v$RESOLVED_VERSION" 2 | tag-template: "v$RESOLVED_VERSION" 3 | categories: 4 | - title: "🚀 Features" 5 | labels: 6 | - "feature" 7 | - "enhancement" 8 | - title: "🐛 Bug Fixes" 9 | labels: 10 | - "fix" 11 | - "bugfix" 12 | - "bug" 13 | - title: "🧰 Maintenance" 14 | labels: 15 | - "maintenance" 16 | change-template: "- $TITLE @$AUTHOR (#$NUMBER)" 17 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 18 | version-resolver: 19 | major: 20 | labels: 21 | - "major" 22 | - "breaking" 23 | minor: 24 | labels: 25 | - "minor" 26 | - "feature" 27 | patch: 28 | labels: 29 | - "patch" 30 | - "bug" 31 | - "maintenance" 32 | - "docs" 33 | - "dependencies" 34 | - "security" 35 | default: patch 36 | prerelease: true 37 | template: | 38 | ## What's Changed 39 | 40 | $CHANGES 41 | 42 | ### Contributors 43 | 44 | $CONTRIBUTORS 45 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/include/map_manager_adv_lists.inc: -------------------------------------------------------------------------------- 1 | #if defined _map_manager_adv_lists_included 2 | #endinput 3 | #endif 4 | #define _map_manager_adv_lists_included 5 | 6 | #if AMXX_VERSION_NUM >= 175 7 | #pragma reqlib map_manager_adv_lists 8 | #if !defined AMXMODX_NOAUTOLOAD 9 | #pragma loadlib map_manager_adv_lists 10 | #endif 11 | #else 12 | #pragma library map_manager_adv_lists 13 | #endif 14 | 15 | /** 16 | * Array size of advanced list. 17 | * 18 | * @return Number of active lists 19 | */ 20 | native mapm_advl_get_active_lists(); 21 | 22 | /** 23 | * Get list name. 24 | * 25 | * @param item Number of active list 26 | * @param list_name String for list name 27 | * @param size String size 28 | * 29 | * @noreturn 30 | */ 31 | native mapm_advl_get_list_name(item, list_name[], size); 32 | 33 | /** 34 | * Get Array pointer by index 35 | * 36 | * @param item Number of active list 37 | * 38 | * @return Array pointer 39 | */ 40 | native Array:mapm_advl_get_list_array(item); 41 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_priority.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PLUGIN "Map Manager: Priority" 5 | #define VERSION "0.0.2" 6 | #define AUTHOR "Mistrick" 7 | 8 | #pragma semicolon 1 9 | 10 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 11 | 12 | enum Cvars { 13 | IGNORE_NOMINATION 14 | }; 15 | 16 | new g_pCvars[Cvars]; 17 | new Array:g_aMapList; 18 | 19 | public plugin_init() 20 | { 21 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 22 | 23 | g_pCvars[IGNORE_NOMINATION] = register_cvar("mapm_priority_ignore_nomination", "1"); 24 | } 25 | 26 | public mapm_maplist_loaded(Array:maplist, const nextmap[]) 27 | { 28 | g_aMapList = maplist; 29 | } 30 | 31 | public mapm_can_be_in_votelist(const map[], type, index) 32 | { 33 | if(type == PUSH_BY_NOMINATION && get_num(IGNORE_NOMINATION)) { 34 | return MAP_ALLOWED; 35 | } 36 | 37 | new map_info[MapStruct]; 38 | ArrayGetArray(g_aMapList, index, map_info); 39 | new rnd = random_num(0, 99); 40 | 41 | return rnd < map_info[MapPriority] ? MAP_ALLOWED : MAP_BLOCKED; 42 | } 43 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/include/map_manager_nomination.inc: -------------------------------------------------------------------------------- 1 | #if defined _map_manager_nom_included 2 | #endinput 3 | #endif 4 | #define _map_manager_nom_included 5 | 6 | #if AMXX_VERSION_NUM >= 175 7 | #pragma reqlib map_manager_nomination 8 | #if !defined AMXMODX_NOAUTOLOAD 9 | #pragma loadlib map_manager_nomination 10 | #endif 11 | #else 12 | #pragma library map_manager_nomination 13 | #endif 14 | 15 | /** 16 | * Returns true if nomination ignore vote. 17 | * 18 | * @return true/false 19 | */ 20 | native bool:is_nomination_ignore_vote(); 21 | 22 | /** 23 | * Set ignore or not adding nominated maps to vote. 24 | * 25 | * @param ignore Yes or not 26 | * 27 | * @noreturn 28 | */ 29 | native map_nomination_set_ignore(bool:ignore); 30 | 31 | /** 32 | * Called when player want to nominate map. 33 | * 34 | * @param id Player index 35 | * @param map Map which player want to nominate 36 | * 37 | * @return NOMINATION_ALLOWED to allow nomination 38 | * NOMINATION_BLOCKED to block nomination 39 | */ 40 | forward mapm_can_be_nominated(id, map[]); 41 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/configs/mappacks.ini: -------------------------------------------------------------------------------- 1 | ; Configuration file for "GUI" addon 2 | ; 3 | ; Sprite doc: 4 | ; All pics should be same size(512x512, 256x256, etc) 5 | ; Zero frame - reserved for "unknown map" frame, you should add "unknown map" frame in each pack. 6 | ; First frame - reserved for "extend map" frame, you should add "extend map" frame in each pack. 7 | ; From second frame begin frames for maps. 8 | ; 9 | ; Example 10 | ; [sprite scale, def 0.1] 11 | ; <2-nd frame map in sprite> [count of pics with this map, def 1, for animation] 12 | ; <3-d frame map in sprite> [count] 13 | ; <4-th frame map in sprite> [count] 14 | ; 15 | ; 16 | ; Sprite scale info 17 | ; 0.09 - for 512x512 sprites 18 | ; 0.18 - for 256x256 sprites 19 | ; 20 | ; Examples: 21 | ; sprites/map_manager/pack.spr 22 | ; de_dust2 23 | ; de_dust 24 | ; de_inferno 25 | ; sprites/map_manager/pack2.spr 26 | ; cs_assault 27 | ; cs_italy 28 | 29 | sprites/map_manager/maps.spr 0.18 30 | as_oilrig 4 31 | cs_747 3 32 | cs_assault 4 33 | cs_backalley 3 34 | cs_italy 3 35 | cs_militia 3 36 | cs_office 3 37 | cs_siege 3 38 | de_airstrip 4 39 | de_aztec 4 40 | de_cbble 5 41 | de_chateau 4 42 | de_dust 4 43 | de_dust2 6 44 | de_inferno 4 45 | de_nuke 6 46 | de_piranesi 5 47 | de_prodigy 4 48 | de_storm 4 49 | de_survivor 6 50 | de_torn 4 51 | de_train 5 52 | de_vertigo 6 53 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/include/map_manager_consts.inc: -------------------------------------------------------------------------------- 1 | #if defined _map_manager_consts_included 2 | #endinput 3 | #endif 4 | #define _map_manager_consts_included 5 | 6 | #define VERSION_HASH "" 7 | 8 | const MAPNAME_LENGTH = 32; 9 | 10 | enum _:MapStruct { 11 | Map[MAPNAME_LENGTH], 12 | MinPlayers, 13 | MaxPlayers, 14 | MapPriority 15 | }; 16 | 17 | enum _:NomStruct { 18 | NomMap[MAPNAME_LENGTH], 19 | NomPlayer 20 | }; 21 | 22 | // used as return value in forward "mapm_can_be_in_votelist" 23 | enum { 24 | MAP_ALLOWED, 25 | MAP_BLOCKED 26 | }; 27 | 28 | enum (<<=1) { 29 | CHECK_NOT_IGNORED = 0, 30 | CHECK_IGNORE_MAP_ALLOWED = 1 << 0, 31 | CHECK_IGNORE_VALID_MAP 32 | }; 33 | 34 | // used as return value in native "mapm_push_map_to_votelist" 35 | enum { 36 | PUSH_BLOCKED = -1, 37 | PUSH_CANCELED, 38 | PUSH_SUCCESS 39 | }; 40 | 41 | // used for type param in native "mapm_push_map_to_votelist" 42 | enum { 43 | PUSH_BY_CORE, 44 | PUSH_BY_NATIVE, 45 | PUSH_BY_SECOND_VOTE, 46 | PUSH_BY_NOMINATION, 47 | PUSH_BY_ONLINE_SORTER 48 | }; 49 | 50 | enum { 51 | VOTE_BY_CMD, 52 | VOTE_BY_RTV, 53 | VOTE_BY_SCHEDULER, 54 | VOTE_BY_SCHEDULER_SECOND, 55 | VOTE_BY_INCORRECT_ONLINE 56 | }; 57 | 58 | // used as return value in forward "mapm_analysis_of_results" 59 | enum { 60 | ALLOW_VOTE, 61 | ABORT_VOTE, 62 | ABORT_VOTE_WITH_FORWARD 63 | }; 64 | 65 | // used for cvar "mapm_extended_type" 66 | enum { 67 | EXTEND_MINUTES, 68 | EXTEND_ROUNDS 69 | }; 70 | 71 | // used as return value in forward "mapm_can_be_extended" 72 | enum { 73 | EXTEND_ALLOWED, 74 | EXTEND_BLOCKED 75 | }; 76 | 77 | const INVALID_MAP_INDEX = -1; 78 | 79 | // used for type param in forward "mapm_countdown" 80 | enum { 81 | COUNTDOWN_UNKNOWN = -1, 82 | COUNTDOWN_PREPARE, 83 | COUNTDOWN_VOTETIME 84 | } 85 | 86 | // used for cvar "mapm_show_result_type" 87 | enum { 88 | SHOW_DISABLED, 89 | SHOW_MENU, 90 | SHOW_HUD 91 | }; 92 | 93 | // used for cvar "mapm_show_percent" 94 | enum { 95 | PERCENT_DISABLED, 96 | PERCENT_ALWAYS, 97 | PERCENT_AFTER_VOTE 98 | }; 99 | 100 | // used for forward "mapm_can_be_nominated" 101 | enum { 102 | NOMINATION_ALLOWED, 103 | NOMINATION_BLOCKED 104 | }; 105 | 106 | enum MCustomItem { 107 | Invalid_Custom_Item = -1 108 | }; 109 | 110 | enum MCI_Type { 111 | mci_before, 112 | mci_after 113 | } 114 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_online_sorter.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PLUGIN "Map Manager: Online sorter" 5 | #define VERSION "0.0.4" 6 | #define AUTHOR "Mistrick" 7 | 8 | #pragma semicolon 1 9 | 10 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 11 | 12 | enum Cvars { 13 | CHECK_NOMINATED_MAPS 14 | }; 15 | 16 | new g_pCvars[Cvars]; 17 | 18 | new Array:g_aMapsList; 19 | new g_sCurMap[MAPNAME_LENGTH]; 20 | 21 | public plugin_init() 22 | { 23 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 24 | 25 | g_pCvars[CHECK_NOMINATED_MAPS] = register_cvar("mapm_sort_check_nominated_maps", "0"); // 0 - disable, 1 - enable 26 | } 27 | public plugin_natives() 28 | { 29 | get_mapname(g_sCurMap, charsmax(g_sCurMap)); 30 | } 31 | public mapm_maplist_loaded(Array:maplist) 32 | { 33 | g_aMapsList = maplist; 34 | } 35 | public mapm_prepare_votelist(type) 36 | { 37 | if(type == VOTE_BY_SCHEDULER_SECOND) { 38 | return; 39 | } 40 | 41 | new players_num = get_players_num(); 42 | 43 | new Array:array = ArrayCreate(MAPNAME_LENGTH, 1); 44 | new map_info[MapStruct], size = ArraySize(g_aMapsList); 45 | 46 | for(new i; i < size; i++) { 47 | ArrayGetArray(g_aMapsList, i, map_info); 48 | if(map_info[MinPlayers] <= players_num <= map_info[MaxPlayers]) { 49 | if(equali(map_info[Map], g_sCurMap)) { 50 | continue; 51 | } 52 | ArrayPushString(array, map_info[Map]); 53 | } 54 | } 55 | 56 | new map[MAPNAME_LENGTH], max_items = mapm_get_votelist_size(); 57 | for(new i, index; i < max_items && ArraySize(array); i++) { 58 | index = random_num(0, ArraySize(array) - 1); 59 | ArrayGetString(array, index, map, charsmax(map)); 60 | ArrayDeleteItem(array, index); 61 | if(mapm_push_map_to_votelist(map, PUSH_BY_ONLINE_SORTER) != PUSH_SUCCESS) { 62 | i--; 63 | } 64 | } 65 | 66 | ArrayDestroy(array); 67 | } 68 | public mapm_can_be_in_votelist(const map[], type, index) 69 | { 70 | // add online checks for another addons? 71 | 72 | if(type == PUSH_BY_NOMINATION && index != INVALID_MAP_INDEX && get_num(CHECK_NOMINATED_MAPS)) { 73 | new map_info[MapStruct]; ArrayGetArray(g_aMapsList, index, map_info); 74 | new players_num = get_players_num(); 75 | if(map_info[MinPlayers] > players_num || map_info[MaxPlayers] < players_num) { 76 | return MAP_BLOCKED; 77 | } 78 | } 79 | return MAP_ALLOWED; 80 | } 81 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/include/map_manager_scheduler.inc: -------------------------------------------------------------------------------- 1 | #if defined _map_manager_scheduler_included 2 | #endinput 3 | #endif 4 | #define _map_manager_scheduler_included 5 | 6 | #if AMXX_VERSION_NUM >= 175 7 | #pragma reqlib map_manager_scheduler 8 | #if !defined AMXMODX_NOAUTOLOAD 9 | #pragma loadlib map_manager_scheduler 10 | #endif 11 | #else 12 | #pragma library map_manager_scheduler 13 | #endif 14 | 15 | enum IgnoreFlags (<<=1) { 16 | IGNORE_DISABLED = 0, 17 | IGNORE_TIMER_CHECK = 1 << 0, 18 | IGNORE_ROUND_CHECK, 19 | IGNORE_FRAGS_CHECK 20 | }; 21 | 22 | enum LastRoundState { 23 | LRS_Not, // Not last round 24 | LRS_Last, // Last round, round that can be played after voting 25 | LRS_Final // Final round, one more round after the last one if the last one ended in a draw 26 | } 27 | 28 | /** 29 | * Get ignore flags for starting vote. 30 | * 31 | * @return Ignore flags 32 | */ 33 | native IgnoreFlags:map_scheduler_get_ignore_check(); 34 | 35 | /** 36 | * Set ignore flags for starting vote. 37 | * 38 | * @param flags Flags from IgnoreFlags enum 39 | * 40 | * @noreturn 41 | */ 42 | native map_scheduler_set_ignore_check(IgnoreFlags:flags); 43 | 44 | /** 45 | * Start vote by scheduler, work with own cvars. 46 | * 47 | * @param type Type of vote, used const VOTE_BY_* 48 | * 49 | * @noreturn 50 | */ 51 | native map_scheduler_start_vote(type); 52 | 53 | /** 54 | * Stop vote by scheduler. 55 | * 56 | * @noreturn 57 | */ 58 | native map_scheduler_stop_vote(); 59 | 60 | /** 61 | * Extend current map time. 62 | * 63 | * @param count Extend time param, bonus time = count * cvarnum(extend_time) 64 | * 65 | * @noreturn 66 | */ 67 | native map_scheduler_extend_map(count = 1); 68 | 69 | /** 70 | * Returns true if vote will in next round. 71 | * 72 | * @return true/false 73 | */ 74 | native bool:is_vote_will_in_next_round(); 75 | 76 | /** 77 | * Returns state of last round. 78 | * 79 | * @return LastRoundState value 80 | */ 81 | native LastRoundState:get_last_round_state(); 82 | 83 | /** 84 | * Returns true if one map mode active. 85 | * 86 | * @return true/false 87 | */ 88 | native bool:is_one_map_mode(); 89 | 90 | /** 91 | * Called after map extended 92 | * 93 | * @param type Type of vote, used const VOTE_BY_* 94 | * @param extended Current number of extended 95 | * 96 | * @noreturn 97 | */ 98 | forward mapm_scheduler_map_extended(type, extended); 99 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/include/map_manager_stocks.inc: -------------------------------------------------------------------------------- 1 | #if defined _map_manager_stocks_included 2 | #endinput 3 | #endif 4 | #define _map_manager_stocks_included 5 | 6 | stock valid_map(map[]) 7 | { 8 | if(is_map_valid(map)) return true; 9 | 10 | new len = strlen(map) - 4; 11 | 12 | if(len < 0) return false; 13 | 14 | if(equali(map[len], ".bsp")) { 15 | map[len] = '^0'; 16 | if(is_map_valid(map)) return true; 17 | } 18 | 19 | return false; 20 | } 21 | stock get_map_prefix(map[], prefix[], size) 22 | { 23 | copy(prefix, size, map); 24 | for(new i; prefix[i]; i++) { 25 | if(prefix[i] == '_') { 26 | prefix[i + 1] = 0; 27 | return 1; 28 | } 29 | } 30 | return 0; 31 | } 32 | stock bool:is_string_with_space(string[]) 33 | { 34 | for(new i; string[i]; i++) { 35 | if(string[i] == ' ') return true; 36 | } 37 | return false; 38 | } 39 | stock trim_bracket(text[]) 40 | { 41 | for(new i; text[i]; i++) { 42 | if(text[i] == '[') { 43 | text[i] = 0; 44 | break; 45 | } 46 | } 47 | } 48 | stock intermission() 49 | { 50 | emessage_begin(MSG_ALL, SVC_INTERMISSION); 51 | emessage_end(); 52 | } 53 | stock get_players_num(ignore = 0) 54 | { 55 | static maxplayers; 56 | if(!maxplayers) { 57 | maxplayers = get_maxplayers(); 58 | } 59 | new pnum; 60 | for(new i = 1; i <= maxplayers; i++) { 61 | if(ignore > 0 && i == ignore 62 | || !is_user_connected(i) 63 | || is_user_bot(i) 64 | || is_user_hltv(i)) { 65 | continue; 66 | } 67 | 68 | if(ignore == -1) { 69 | new team = get_user_team(i); 70 | if(team == 0 || team == 3) { 71 | continue; 72 | } 73 | } 74 | 75 | pnum++; 76 | } 77 | return pnum; 78 | } 79 | stock send_audio(id, audio[], pitch) 80 | { 81 | static msg_send_audio; 82 | 83 | if(!msg_send_audio) { 84 | msg_send_audio = get_user_msgid("SendAudio"); 85 | } 86 | 87 | message_begin( id ? MSG_ONE_UNRELIABLE : MSG_BROADCAST, msg_send_audio, _, id); 88 | write_byte(id); 89 | write_string(audio); 90 | write_short(pitch); 91 | message_end(); 92 | } 93 | stock replace_color_tag(string[], len) 94 | { 95 | while(replace(string, len, "^^1", "^1")) {} 96 | while(replace(string, len, "^^3", "^3")) {} 97 | while(replace(string, len, "^^4", "^4")) {} 98 | while(replace(string, len, "!d", "^1")) {} 99 | while(replace(string, len, "!t", "^3")) {} 100 | while(replace(string, len, "!g", "^4")) {} 101 | } 102 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_online_checker.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define PLUGIN "Map Manager: Online checker" 6 | #define VERSION "1.0.4" 7 | #define AUTHOR "Sergey Shorokhov" 8 | 9 | #pragma semicolon 1 10 | 11 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 12 | #define get_float(%0) get_pcvar_float(g_pCvars[%0]) 13 | 14 | enum (+=100) { 15 | TASK_CHECK_ONLINE = 100 16 | }; 17 | 18 | enum Cvars { 19 | CHECK_INTERVAL, 20 | CHECKS_COUNT, 21 | CHECK_TIMEOUT 22 | }; 23 | 24 | new g_sPrefix[48]; 25 | new g_pCvars[Cvars]; 26 | 27 | new g_CurrentMap[MapStruct]; 28 | new g_Warnings; 29 | 30 | public plugin_init() 31 | { 32 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 33 | 34 | g_pCvars[CHECK_INTERVAL] = register_cvar("mapm_online_check_interval", "30"); 35 | g_pCvars[CHECKS_COUNT] = register_cvar("mapm_online_check_count", "3"); 36 | g_pCvars[CHECK_TIMEOUT] = register_cvar("mapm_online_check_timeout", "120"); 37 | 38 | get_mapname(g_CurrentMap[Map], charsmax(g_CurrentMap[Map])); 39 | } 40 | 41 | public plugin_cfg() 42 | { 43 | mapm_get_prefix(g_sPrefix, charsmax(g_sPrefix)); 44 | } 45 | 46 | public task_check_online() 47 | { 48 | if(is_vote_will_in_next_round() || is_vote_started() || is_vote_finished()) { 49 | return; 50 | } 51 | if(is_one_map_mode()) { 52 | return; 53 | } 54 | if(get_num(CHECKS_COUNT) <= 0) { 55 | return; 56 | } 57 | 58 | new current_online = get_players_num(); 59 | if(current_online != 0 && get_float(CHECK_TIMEOUT) > get_gametime()) { 60 | return; 61 | } 62 | 63 | new bool: is_online_incorrect = (current_online < g_CurrentMap[MinPlayers] || current_online > g_CurrentMap[MaxPlayers]); 64 | 65 | g_Warnings = clamp(is_online_incorrect ? ++g_Warnings : --g_Warnings, 0, get_num(CHECKS_COUNT)); 66 | if(g_Warnings != get_num(CHECKS_COUNT)) { 67 | return; 68 | } 69 | 70 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_FORCE_VOTE_BY_ONLINE"); 71 | 72 | map_scheduler_start_vote(VOTE_BY_INCORRECT_ONLINE); 73 | } 74 | 75 | public mapm_maplist_loaded(Array: maplist, const nextmap[]) 76 | { 77 | remove_task(TASK_CHECK_ONLINE); 78 | 79 | new idx = mapm_get_map_index(g_CurrentMap[Map]); 80 | if(idx == INVALID_MAP_INDEX) { 81 | return; 82 | } 83 | 84 | g_Warnings = 0; 85 | set_task(get_float(CHECK_INTERVAL), "task_check_online", .flags = "b", .id = TASK_CHECK_ONLINE); 86 | ArrayGetArray(maplist, idx, g_CurrentMap); 87 | } 88 | 89 | public mapm_can_be_extended(type) 90 | { 91 | if(type != VOTE_BY_INCORRECT_ONLINE) { 92 | return EXTEND_ALLOWED; 93 | } 94 | 95 | return EXTEND_BLOCKED; 96 | } 97 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 |

2 | Map Manager Modular 3 |

4 | 5 |

Modular map management system with rich features.

6 | 7 |

8 | 9 | Build status 11 | 12 | Build status 14 | 15 | Release 17 | 18 | AMXModX dependency 20 |

21 | 22 |

23 | About • 24 | Requirements • 25 | Installation • 26 | Updating • 27 | Downloads • 28 | Features • 29 | Wiki 30 |

31 | 32 | --- 33 | 34 | ## About 35 | - TODO 36 | 37 | ## Requirements 38 | - HLDS installed; 39 | - Installed AMXModX ([`v1.9`](https://www.amxmodx.org/downloads-new.php) or [`v1.10`](https://www.amxmodx.org/downloads-new.php?branch=master)); 40 | 41 | ## Installation 42 | - [Download the latest](https://github.com/Mistrick/MapManagerModular/releases/latest) stable version from the release section. 43 | - Extract the `cstrike` folder to the root folder of the HLDS server; 44 | - Make sure that all plugins are running and in the correct order, using the `amxx list` command. 45 | 46 | ## Updating 47 | - Put new plugins and lang-files (`plugins/*.amxx` & `data/lang/*.txt`) into `amxmodx/` folder on the HLDS server; 48 | - Restart the server (command `restart` or change the map); 49 | - Make sure that the versions of the plugins are up to date with the command `amxx list`. 50 | 51 | ## Downloads 52 | - [Release builds](https://github.com/Mistrick/MapManagerModular/releases) 53 | - [Dev builds](https://github.com/Mistrick/MapManagerModular/actions/workflows/CI.yml) 54 | 55 | ## Features 56 | - TODO 57 | 58 | ## Wiki 59 | Do you **need some help**? Check the _articles_ from the [wiki](https://github.com/Mistrick/MapManagerModular/wiki). 60 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/configs/plugins-map_manager.ini: -------------------------------------------------------------------------------- 1 | ; Main plugins 2 | 3 | ; Core functions for setting up voting. 4 | map_manager_core.amxx 5 | 6 | ; Module for automatic launch of voting. 7 | ; Functions: 8 | ; - Start vote by timeleft, rounds left(works with cvars "mp_winlimit", "mp_maxrounds"), 9 | ; fragsleft(only regamedll function, cvar "mp_fraglimit"). 10 | ; - Vote in new round - allows you to end the current round 11 | ; - Last round - allows you to end the round after voting 12 | ; - Second vote - additional vote with two maps with the most votes. 13 | ; - Change to default map - changes a map by default only when the last player left, 14 | ; after that the usual rotation of cards in the list continues. 15 | ; - Map extension. 16 | map_manager_scheduler.amxx 17 | 18 | ; Addons 19 | 20 | ; Rock the vote 21 | map_manager_rtv.amxx 22 | 23 | ; Module for map nomination. 24 | ; Function: 25 | ; - Fast nomination with message in chat. 26 | ; Example: You have "de_dust" and "de_dust2" in your map list. When writing "dust" in the chat, 27 | ; you will be shown a menu with all maps containing "dust" to clarify the nomination. 28 | ; - Menu with a list of all maps(by default "/maps" in chat) 29 | map_manager_nomination.amxx 30 | 31 | ; Module for blocking the last played maps from getting into the voting. 32 | map_manager_blocklist.amxx 33 | 34 | ; Module for displaying maps in voting for the current online. 35 | ; Read "maps.ini" for setup information. 36 | ; Read about cvar "mapm_only_external_vote_items". By default, maps not for the current online are added 37 | ; if there are not enough maps for the current online to fill all the slots. 38 | map_manager_online_sorter.amxx 39 | 40 | ; Module for visual effects. 41 | ; Function: 42 | ; - Black screen when voting is in progress. 43 | ; - Block chat and voice. 44 | ; - Freeze players. 45 | map_manager_effects.amxx 46 | 47 | ; Chat commands for info. 48 | ; Timeleft, thetime, nextmap, currentmap. 49 | map_manager_informer.amxx 50 | 51 | ; Module for sounds in vote. 52 | ; Check settings in "map_manager_settings.ini" 53 | map_manager_sounds.amxx 54 | 55 | ; Scheduler for lists of maps. 56 | ; Allows you to set specific maps lists at specific times of the day. 57 | ; Check settings in "maplists.ini" 58 | ; map_manager_adv_lists.amxx 59 | 60 | ; Module for setting simple map priorities 61 | ; Priority meaning: 62 | ; With a priority of 100, there are no restrictions for the map, if the priority is 1 then 63 | ; the map has 1% to get into the vote. 64 | ; 65 | ; You can set -1 to disable auto-adding the map to the vote but you can nominate this map. 66 | ; 67 | ; Read "maps.ini" for setup information. 68 | ; map_manager_priority.amxx 69 | 70 | ; Starts the vote if the current online does not match the map online settings. 71 | ; map_manager_online_checker.amxx 72 | 73 | ; Experimental GUI version of vote based on sprites. Try if you can handle sprites and module config. 74 | ; map_manager_gui.amxx 75 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths-ignore: 7 | - "**.md" 8 | 9 | pull_request: 10 | types: [opened, reopened, synchronize] 11 | release: 12 | types: [published] 13 | 14 | jobs: 15 | build: 16 | name: "Build" 17 | runs-on: ubuntu-latest 18 | outputs: 19 | sha: ${{ steps.declare_sha.outputs.sha }} 20 | semver: ${{ steps.declare_sha.outputs.semver }} 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4.1.1 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: Parse SemVer string (release) 28 | id: semver_parser 29 | if: | 30 | github.event_name == 'release' && 31 | github.event.action == 'published' && 32 | startsWith(github.ref, 'refs/tags/') 33 | uses: booxmedialtd/ws-action-parse-semver@v1 34 | with: 35 | input_string: ${{ github.ref }} 36 | version_extractor_regex: '\/v(.*)$' 37 | 38 | - name: Declare SHA & package name 39 | id: declare_sha 40 | shell: bash 41 | run: | 42 | SHA=$(git rev-parse --short HEAD) 43 | echo "SHA_SHORT=${SHA}" >> $GITHUB_ENV 44 | echo "::set-output name=sha::$SHA" 45 | echo "::set-output name=semver::${{ steps.semver_parser.outputs.fullversion }}" 46 | 47 | - name: Update versions for plugins 48 | working-directory: cstrike/addons/amxmodx/scripting/include/ 49 | env: 50 | SHA_SHORT: "${{ env.SHA_SHORT }}" 51 | FILE: map_manager_consts.inc 52 | run: sed -i "s|VERSION_HASH \"\"|VERSION_HASH \"-$SHA_SHORT\"|g" $FILE 53 | 54 | - name: Setup AMXXPawn Compiler 55 | uses: wopox1337/setup-amxxpawn@v1.1.0 56 | with: 57 | version: "1.10.5467" 58 | 59 | - name: Compile plugins 60 | working-directory: cstrike/addons/amxmodx/scripting/ 61 | run: | 62 | for sourcefile in *.sma; 63 | do 64 | amxxfile="`echo $sourcefile | sed -e 's/\.sma$/.amxx/'`" 65 | output_path="../plugins/$amxxfile" 66 | 67 | mkdir -p $(dirname $output_path) 68 | 69 | echo -n "Compiling $sourcefile ... " 70 | amxxpc $sourcefile -i"include" -o"$output_path" 71 | done 72 | 73 | - name: Move files 74 | run: | 75 | mkdir publish 76 | mv cstrike/ publish/ 77 | 78 | - name: Upload artifact 79 | uses: actions/upload-artifact@v4.3.1 80 | with: 81 | name: MapManager-${{ env.SHA_SHORT }}-dev 82 | path: publish/* 83 | 84 | publish: 85 | name: "Publish" 86 | runs-on: ubuntu-latest 87 | needs: [build] 88 | if: | 89 | github.event_name == 'release' && 90 | github.event.action == 'published' && 91 | startsWith(github.ref, 'refs/tags/') 92 | steps: 93 | - name: Download artifacts 94 | uses: actions/download-artifact@v4.1.4 95 | with: 96 | name: MapManager-${{needs.build.outputs.sha}}-dev 97 | 98 | - name: Packaging binaries 99 | id: packaging 100 | run: 7z a -mm=Deflate -mfb=258 -mpass=15 -r MapManager-v${{needs.build.outputs.semver}}.zip cstrike/ 101 | 102 | - name: Publish artifacts 103 | uses: softprops/action-gh-release@v2.0.4 104 | id: publish-job 105 | if: | 106 | startsWith(github.ref, 'refs/tags/') && 107 | steps.packaging.outcome == 'success' 108 | env: 109 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 110 | with: 111 | files: | 112 | *.zip 113 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_sounds.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PLUGIN "Map Manager: Sounds" 5 | #define VERSION "0.0.3" 6 | #define AUTHOR "Mistrick" 7 | 8 | #pragma semicolon 1 9 | 10 | new const SETTINGS_FILE[] = "map_manager_settings.ini"; 11 | 12 | enum Sections { 13 | UNUSED_SECTION, 14 | SOUND_VOTE_STARTED, 15 | SOUND_VOTE_FINISHED, 16 | SOUNDS_COUNTDOWN 17 | } 18 | enum ParserData { 19 | Sections:SECTION 20 | }; 21 | new parser_info[ParserData]; 22 | 23 | new g_sVoteStarted[128]; 24 | new g_sVoteFinished[128]; 25 | new Trie:g_tCountdownSounds; 26 | 27 | public plugin_precache() 28 | { 29 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 30 | 31 | g_tCountdownSounds = TrieCreate(); 32 | load_settings(); 33 | } 34 | load_settings() 35 | { 36 | new configdir[256]; 37 | get_localinfo("amxx_configsdir", configdir, charsmax(configdir)); 38 | 39 | new INIParser:parser = INI_CreateParser(); 40 | 41 | INI_SetParseEnd(parser, "ini_parse_end"); 42 | INI_SetReaders(parser, "ini_key_value", "ini_new_section"); 43 | new bool:result = INI_ParseFile(parser, fmt("%s/%s", configdir, SETTINGS_FILE)); 44 | 45 | if(!result) { 46 | set_fail_state("Can't read from ini file."); 47 | } 48 | } 49 | public ini_new_section(INIParser:handle, const section[], bool:invalid_tokens, bool:close_bracket, bool:extra_tokens, curtok, any:data) 50 | { 51 | if(equal(section, "sound_vote_started")) { 52 | parser_info[SECTION] = SOUND_VOTE_STARTED; 53 | } else if(equal(section, "sound_vote_finished")) { 54 | parser_info[SECTION] = SOUND_VOTE_FINISHED; 55 | } else if(equal(section, "sounds_countdown")) { 56 | parser_info[SECTION] = SOUNDS_COUNTDOWN; 57 | } else { 58 | parser_info[SECTION] = UNUSED_SECTION; 59 | } 60 | return true; 61 | } 62 | public ini_key_value(INIParser:handle, const key[], const value[], bool:invalid_tokens, bool:equal_token, bool:quotes, curtok, any:data) 63 | { 64 | switch(parser_info[SECTION]) { 65 | case SOUND_VOTE_STARTED: { 66 | copy(g_sVoteStarted, charsmax(g_sVoteStarted), key); 67 | remove_quotes(g_sVoteStarted); 68 | precache_generic(g_sVoteStarted); 69 | } 70 | case SOUND_VOTE_FINISHED: { 71 | copy(g_sVoteFinished, charsmax(g_sVoteFinished), key); 72 | remove_quotes(g_sVoteFinished); 73 | precache_generic(g_sVoteFinished); 74 | } 75 | case SOUNDS_COUNTDOWN: { 76 | new k[16]; 77 | copy(k, charsmax(k), key); 78 | remove_quotes(k); 79 | precache_generic(value); 80 | TrieSetString(g_tCountdownSounds, k, value); 81 | } 82 | } 83 | return true; 84 | } 85 | public ini_parse_end(INIParser:handle, bool:halted, any:data) 86 | { 87 | INI_DestroyParser(handle); 88 | } 89 | public mapm_countdown(type, time) 90 | { 91 | if(type == COUNTDOWN_PREPARE) { 92 | new key[4], sound[128]; 93 | num_to_str(time, key, charsmax(key)); 94 | if(TrieKeyExists(g_tCountdownSounds, key)) { 95 | TrieGetString(g_tCountdownSounds, key, sound, charsmax(sound)); 96 | play_sound(0, sound); 97 | } 98 | } 99 | } 100 | public mapm_vote_started(type) 101 | { 102 | if(g_sVoteStarted[0]) { 103 | play_sound(0, g_sVoteStarted); 104 | } 105 | } 106 | public mapm_vote_finished(const map[], type, total_votes) 107 | { 108 | if(g_sVoteFinished[0]) { 109 | play_sound(0, g_sVoteFinished); 110 | } 111 | } 112 | play_sound(id, sound[]) 113 | { 114 | new len = strlen(sound); 115 | if(equali(sound[len - 3], "wav")) { 116 | send_audio(id, sound, PITCH_NORM); 117 | } else if(equali(sound[len - 3], "mp3")) { 118 | client_cmd(id, "mp3 play ^"%s^"", sound); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_informer.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if AMXX_VERSION_NUM < 183 6 | #include 7 | #endif 8 | 9 | #define PLUGIN "Map Manager: Informer" 10 | #define VERSION "0.0.5" 11 | #define AUTHOR "Mistrick" 12 | 13 | #pragma semicolon 1 14 | 15 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 16 | 17 | enum Cvars { 18 | TIMELIMIT, 19 | WINLIMIT, 20 | MAXROUNDS, 21 | NEXTMAP, 22 | EXTENDED_TYPE 23 | }; 24 | 25 | new g_pCvars[Cvars]; 26 | 27 | new g_iTeamScore[2]; 28 | new g_sCurMap[MAPNAME_LENGTH]; 29 | new g_sPrefix[48]; 30 | 31 | public plugin_init() 32 | { 33 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 34 | 35 | register_clcmd("say timeleft", "clcmd_timeleft"); 36 | register_clcmd("say thetime", "clcmd_thetime"); 37 | register_clcmd("say nextmap", "clcmd_nextmap"); 38 | register_clcmd("say currentmap", "clcmd_currentmap"); 39 | 40 | register_event("TeamScore", "event_teamscore", "a"); 41 | 42 | get_mapname(g_sCurMap, charsmax(g_sCurMap)); 43 | } 44 | public plugin_cfg() 45 | { 46 | g_pCvars[TIMELIMIT] = get_cvar_pointer("mp_timelimit"); 47 | g_pCvars[WINLIMIT] = get_cvar_pointer("mp_winlimit"); 48 | g_pCvars[MAXROUNDS] = get_cvar_pointer("mp_maxrounds"); 49 | g_pCvars[NEXTMAP] = get_cvar_pointer("amx_nextmap"); 50 | g_pCvars[EXTENDED_TYPE] = get_cvar_pointer("mapm_extended_type"); 51 | 52 | mapm_get_prefix(g_sPrefix, charsmax(g_sPrefix)); 53 | } 54 | public event_teamscore() 55 | { 56 | new team[2]; read_data(1, team, charsmax(team)); 57 | g_iTeamScore[(team[0] == 'C') ? 0 : 1] = read_data(2); 58 | } 59 | public clcmd_timeleft(id) 60 | { 61 | if(is_vote_finished()) { 62 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_CHANGELEVEL_NEXTROUND"); 63 | return; 64 | } 65 | 66 | new win_limit = get_num(WINLIMIT); 67 | new max_rounds = get_num(MAXROUNDS); 68 | 69 | // TODO: need subtract left_wins/left_rounds if mapm_change_type 0 or 1 70 | if((win_limit || max_rounds) && get_num(EXTENDED_TYPE) == EXTEND_ROUNDS) { 71 | new text[128], len; 72 | len = formatex(text, charsmax(text), "%L ", LANG_PLAYER, "MAPM_TIME_TO_END"); 73 | if(win_limit) { 74 | new left_wins = win_limit - max(g_iTeamScore[0], g_iTeamScore[1]); 75 | len += formatex(text[len], charsmax(text) - len, "%d %L", left_wins, LANG_PLAYER, "MAPM_WINS"); 76 | } 77 | if(win_limit && max_rounds) { 78 | len += formatex(text[len], charsmax(text) - len, " %L ", LANG_PLAYER, "MAPM_TIMELEFT_OR"); 79 | } 80 | if(max_rounds) { 81 | new left_rounds = max_rounds - g_iTeamScore[0] - g_iTeamScore[1]; 82 | len += formatex(text[len], charsmax(text) - len, "%d %L", left_rounds, LANG_PLAYER, "MAPM_ROUNDS"); 83 | } 84 | client_print_color(0, print_team_default, "%s^1 %s.", g_sPrefix, text); 85 | } else { 86 | if (get_num(TIMELIMIT)) { 87 | new a = get_timeleft(); 88 | client_print_color(0, id, "%s^1 %L:^3 %d:%02d", g_sPrefix, LANG_PLAYER, "MAPM_TIME_TO_END", (a / 60), (a % 60)); 89 | } else { 90 | if(is_vote_will_in_next_round()) { 91 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_VOTE_IN_NEXTROUND"); 92 | } else { 93 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_NO_TIMELIMIT"); 94 | } 95 | } 96 | } 97 | } 98 | public clcmd_thetime(id) 99 | { 100 | new curtime[64]; get_time("%Y/%m/%d - %H:%M:%S", curtime, charsmax(curtime)); 101 | client_print_color(0, print_team_default, "%s^3 %L", g_sPrefix, LANG_PLAYER, "MAPM_THETIME", curtime); 102 | } 103 | public clcmd_nextmap(id) 104 | { 105 | if(is_vote_finished()) { 106 | new map[MAPNAME_LENGTH]; get_pcvar_string(g_pCvars[NEXTMAP], map, charsmax(map)); 107 | client_print_color(0, id, "%s^1 %L %s^1.", g_sPrefix, LANG_PLAYER, "MAPM_NEXTMAP", map); 108 | } else { 109 | client_print_color(0, id, "%s^1 %L %L^1.", g_sPrefix, LANG_PLAYER, "MAPM_NEXTMAP", LANG_PLAYER, "MAPM_NOT_SELECTED"); 110 | } 111 | } 112 | public clcmd_currentmap(id) 113 | { 114 | client_print_color(0, id, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_CURRENT_MAP", g_sCurMap); 115 | } 116 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_blocklist.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PLUGIN "Map Manager: BlockList" 5 | #define VERSION "0.0.6" 6 | #define AUTHOR "Mistrick" 7 | 8 | #pragma semicolon 1 9 | 10 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 11 | 12 | enum Cvars { 13 | BAN_LAST_MAPS 14 | }; 15 | 16 | new g_pCvars[Cvars]; 17 | 18 | new const FILE_BLOCKED_MAPS[] = "blockedmaps.ini"; //datadir 19 | 20 | new Trie:g_tBlockedList; 21 | new g_iMaxItems; 22 | new bool:g_bNeedCheck; 23 | 24 | public plugin_init() 25 | { 26 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 27 | 28 | g_pCvars[BAN_LAST_MAPS] = register_cvar("mapm_blocklist_ban_last_maps", "10"); 29 | } 30 | public plugin_natives() 31 | { 32 | register_library("map_manager_blocklist"); 33 | register_native("mapm_get_blocked_count", "native_get_blocked_count"); 34 | } 35 | public native_get_blocked_count(plugin, params) 36 | { 37 | enum { arg_map = 1 }; 38 | 39 | if(!get_num(BAN_LAST_MAPS)) { 40 | return 0; 41 | } 42 | 43 | new map[MAPNAME_LENGTH]; 44 | get_string(arg_map, map, charsmax(map)); 45 | strtolower(map); 46 | 47 | if(!TrieKeyExists(g_tBlockedList, map)) { 48 | return 0; 49 | } 50 | 51 | new count; TrieGetCell(g_tBlockedList, map, count); 52 | 53 | return count; 54 | } 55 | public mapm_maplist_loaded(Array:mapslist) 56 | { 57 | if(!g_tBlockedList) { 58 | g_tBlockedList = TrieCreate(); 59 | load_blocklist(); 60 | } 61 | 62 | new map_info[MapStruct], blocked, size = ArraySize(mapslist); 63 | for(new i; i < size; i++) { 64 | ArrayGetArray(mapslist, i, map_info); 65 | if(TrieKeyExists(g_tBlockedList, map_info[Map])) { 66 | blocked++; 67 | } 68 | } 69 | 70 | new votelist_size = min(mapm_get_votelist_size(), size); 71 | new valid_maps = size - blocked; 72 | 73 | g_iMaxItems = 0; 74 | 75 | if(valid_maps <= 0) { 76 | TrieClear(g_tBlockedList); 77 | log_amx("Blocklist cleared. More blocked maps than available."); 78 | } 79 | else if(valid_maps < votelist_size) { 80 | g_iMaxItems = valid_maps; 81 | } 82 | } 83 | load_blocklist() 84 | { 85 | new file_dir[256]; get_localinfo("amxx_datadir", file_dir, charsmax(file_dir)); 86 | new file_path[256]; formatex(file_path, charsmax(file_path), "%s/%s", file_dir, FILE_BLOCKED_MAPS); 87 | 88 | new block_value = get_num(BAN_LAST_MAPS); 89 | 90 | new cur_map[MAPNAME_LENGTH]; get_mapname(cur_map, charsmax(cur_map)); strtolower(cur_map); 91 | TrieSetCell(g_tBlockedList, cur_map, block_value); 92 | 93 | new f, temp; 94 | 95 | if(file_exists(file_path)) { 96 | new temp_file_path[256]; formatex(temp_file_path, charsmax(temp_file_path), "%s/temp.ini", file_dir); 97 | f = fopen(file_path, "rt"); 98 | temp = fopen(temp_file_path, "wt"); 99 | 100 | new buffer[40], map[MAPNAME_LENGTH], str_count[6], count; 101 | 102 | while(!feof(f)) { 103 | fgets(f, buffer, charsmax(buffer)); 104 | parse(buffer, map, charsmax(map), str_count, charsmax(str_count)); 105 | strtolower(map); 106 | 107 | if(!is_map_valid(map) || TrieKeyExists(g_tBlockedList, map)) continue; 108 | 109 | count = min(str_to_num(str_count) - 1, block_value); 110 | 111 | if(count <= 0) continue; 112 | 113 | fprintf(temp, "^"%s^" ^"%d^"^n", map, count); 114 | strtolower(map); 115 | TrieSetCell(g_tBlockedList, map, count); 116 | } 117 | 118 | fprintf(temp, "^"%s^" ^"%d^"^n", cur_map, block_value); 119 | 120 | fclose(f); 121 | fclose(temp); 122 | 123 | delete_file(file_path); 124 | rename_file(temp_file_path, file_path, 1); 125 | } else { 126 | f = fopen(file_path, "wt"); 127 | if(f) { 128 | fprintf(f, "^"%s^" ^"%d^"^n", cur_map, block_value); 129 | } 130 | fclose(f); 131 | } 132 | } 133 | public mapm_prepare_votelist(type) 134 | { 135 | if(type == VOTE_BY_SCHEDULER_SECOND) { 136 | return; 137 | } 138 | if(g_iMaxItems) { 139 | mapm_set_votelist_max_items(g_iMaxItems); 140 | } 141 | g_bNeedCheck = get_num(BAN_LAST_MAPS) > 0; 142 | } 143 | public mapm_can_be_in_votelist(const map[]) 144 | { 145 | if(!g_bNeedCheck) { 146 | return MAP_ALLOWED; 147 | } 148 | new lower[MAPNAME_LENGTH]; 149 | copy(lower, charsmax(lower), map); 150 | strtolower(lower); 151 | return TrieKeyExists(g_tBlockedList, lower) ? MAP_BLOCKED : MAP_ALLOWED; 152 | } 153 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_rtv.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if AMXX_VERSION_NUM < 183 6 | #include 7 | #endif 8 | 9 | #define PLUGIN "Map Manager: Rtv" 10 | #define VERSION "0.1.5" 11 | #define AUTHOR "Mistrick" 12 | 13 | #pragma semicolon 1 14 | 15 | #if !defined client_disconnected 16 | #define client_disconnected client_disconnect 17 | #endif 18 | 19 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 20 | 21 | enum Cvars { 22 | MODE, 23 | PERCENT, 24 | PLAYERS, 25 | DELAY, 26 | CHANGE_AFTER_VOTE, 27 | CHANGE_TYPE, 28 | ALLOW_EXTEND, 29 | IGNORE_SPECTATORS, 30 | CHATTIME 31 | }; 32 | 33 | enum { 34 | MODE_PERCENTS, 35 | MODE_PLAYERS 36 | }; 37 | 38 | new g_pCvars[Cvars]; 39 | new g_iMapStartTime; 40 | new bool:g_bVoted[33]; 41 | new g_iVotes; 42 | 43 | new g_sPrefix[48]; 44 | 45 | new g_sNextMap[MAPNAME_LENGTH]; 46 | 47 | public plugin_init() 48 | { 49 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 50 | 51 | g_pCvars[MODE] = register_cvar("mapm_rtv_mode", "0"); // 0 - percents, 1 - players 52 | g_pCvars[CHANGE_AFTER_VOTE] = register_cvar("mapm_rtv_change_after_vote", "0"); // 0 - disable, 1 - enable 53 | g_pCvars[PERCENT] = register_cvar("mapm_rtv_percent", "60"); 54 | g_pCvars[PLAYERS] = register_cvar("mapm_rtv_players", "5"); 55 | g_pCvars[DELAY] = register_cvar("mapm_rtv_delay", "0"); // minutes 56 | g_pCvars[ALLOW_EXTEND] = register_cvar("mapm_rtv_allow_extend", "0"); // 0 - disable, 1 - enable 57 | g_pCvars[IGNORE_SPECTATORS] = register_cvar("mapm_rtv_ignore_spectators", "0"); // 0 - disable, 1 - enable 58 | 59 | register_clcmd("say rtv", "clcmd_rtv"); 60 | register_clcmd("say /rtv", "clcmd_rtv"); 61 | 62 | // reset it with sv_restart? 63 | g_iMapStartTime = get_systime(); 64 | } 65 | public plugin_cfg() 66 | { 67 | mapm_get_prefix(g_sPrefix, charsmax(g_sPrefix)); 68 | g_pCvars[CHANGE_TYPE] = get_cvar_pointer("mapm_change_type"); 69 | g_pCvars[CHATTIME] = get_cvar_pointer("mp_chattime"); 70 | } 71 | public client_disconnected(id) 72 | { 73 | if(g_bVoted[id]) { 74 | g_bVoted[id] = false; 75 | g_iVotes--; 76 | } 77 | } 78 | public clcmd_rtv(id) 79 | { 80 | if(is_vote_started()) { 81 | client_print_color(id, print_team_default, "%s^1 %L", g_sPrefix, id, "MAPM_VOTE_ALREADY_STARTED"); 82 | return PLUGIN_HANDLED; 83 | } 84 | else if(is_vote_finished()) { 85 | client_print_color(id, print_team_default, "%s^1 %L %L %s^1.", g_sPrefix, id, "MAPM_VOTE_ALREADY_FINISHED", id, "MAPM_NEXTMAP", g_sNextMap); 86 | return PLUGIN_HANDLED; 87 | } 88 | else if(is_vote_will_in_next_round()) { 89 | client_print_color(id, print_team_default, "%s^1 %L", g_sPrefix, id, "MAPM_VOTE_WILL_BEGIN"); 90 | return PLUGIN_HANDLED; 91 | } 92 | 93 | if(is_one_map_mode()) { 94 | return PLUGIN_HANDLED; 95 | } 96 | 97 | new delay = get_num(DELAY) * 60 - (get_systime() - g_iMapStartTime); 98 | if(delay > 0) { 99 | client_print_color(id, print_team_default, "%s^1 %L", g_sPrefix, id, "MAPM_RTV_DELAY", delay / 60, delay % 60); 100 | return PLUGIN_HANDLED; 101 | } 102 | 103 | if(!g_bVoted[id]) { 104 | g_iVotes++; 105 | } 106 | 107 | new need_votes; 108 | if(get_num(MODE) == MODE_PERCENTS) { 109 | need_votes = floatround(get_players_num(get_num(IGNORE_SPECTATORS) ? -1 : 0) * get_num(PERCENT) / 100.0, floatround_ceil) - g_iVotes; 110 | } else { 111 | need_votes = min(get_num(PLAYERS), get_players_num(get_num(IGNORE_SPECTATORS) ? -1 : 0)) - g_iVotes; 112 | } 113 | 114 | if(need_votes <= 0) { 115 | map_scheduler_start_vote(VOTE_BY_RTV); 116 | return PLUGIN_HANDLED; 117 | } 118 | 119 | if(!g_bVoted[id]) { 120 | g_bVoted[id] = true; 121 | new name[32]; get_user_name(id, name, charsmax(name)); 122 | client_print_color(0, print_team_default, "%s^3 %L.", g_sPrefix, LANG_PLAYER, "MAPM_RTV_VOTED", name, need_votes); 123 | } else { 124 | client_print_color(id, print_team_default, "%s^1 %L.", g_sPrefix, id, "MAPM_RTV_ALREADY_VOTED", need_votes); 125 | } 126 | 127 | return PLUGIN_HANDLED; 128 | } 129 | public mapm_can_be_extended(type) 130 | { 131 | if(type == VOTE_BY_RTV && !get_num(ALLOW_EXTEND)) { 132 | return EXTEND_BLOCKED; 133 | } 134 | return EXTEND_ALLOWED; 135 | } 136 | public mapm_vote_started(type) 137 | { 138 | g_iVotes = 0; 139 | arrayset(g_bVoted, false, sizeof(g_bVoted)); 140 | } 141 | public mapm_vote_finished(const map[], type, total_votes) 142 | { 143 | copy(g_sNextMap, charsmax(g_sNextMap), map); 144 | 145 | if(type == VOTE_BY_RTV && get_num(CHANGE_TYPE) && get_num(CHANGE_AFTER_VOTE)) { 146 | client_print_color(0, print_team_default, "%s^1 %L^1 %L.", g_sPrefix, LANG_PLAYER, "MAPM_MAP_CHANGE", get_num(CHATTIME), LANG_PLAYER, "MAPM_SECONDS"); 147 | intermission(); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_effects.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define PLUGIN "Map Manager: Effects" 7 | #define VERSION "0.1.3" 8 | #define AUTHOR "Mistrick" 9 | 10 | #pragma semicolon 1 11 | 12 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 13 | #define set_num(%0,%1) set_pcvar_num(g_pCvars[%0],%1) 14 | #define get_float(%0) get_pcvar_float(g_pCvars[%0]) 15 | #define set_float(%0,%1) set_pcvar_float(g_pCvars[%0],%1) 16 | 17 | enum (+=100) { 18 | TASK_FULLBLACK = 100 19 | }; 20 | 21 | enum Cvars { 22 | BLACK_SCREEN, 23 | BLOCK_CHAT, 24 | BLOCK_VOICE, 25 | FREEZE_IN_VOTE, 26 | VOICE_ENABLED, 27 | FREEZETIME, 28 | VOTE_IN_NEW_ROUND, 29 | PREPARE_TIME, 30 | VOTE_TIME 31 | }; 32 | 33 | enum { 34 | FREEZE_DISABLED, 35 | FREEZE_TIME_ENABLED, 36 | FREEZE_FORCE_USE_FLAGS 37 | }; 38 | 39 | new g_pCvars[Cvars]; 40 | new bool:g_bBlockChat; 41 | new bool:g_bFreezeTimeChanged; 42 | new bool:g_bFreezeFlagsChanged; 43 | new HamHook:g_hHamSpawn; 44 | 45 | public plugin_init() 46 | { 47 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 48 | 49 | g_pCvars[BLACK_SCREEN] = register_cvar("mapm_black_screen", "1"); // 0 - disable, 1 - enable 50 | g_pCvars[BLOCK_CHAT] = register_cvar("mapm_block_chat", "1"); // 0 - disable, 1 - enable 51 | g_pCvars[BLOCK_VOICE] = register_cvar("mapm_block_voice", "1"); // 0 - disable, 1 - enable 52 | g_pCvars[FREEZE_IN_VOTE] = register_cvar("mapm_freeze_in_vote", "1"); //0 - disable, 1 - enable, 2 - force use flags 53 | 54 | g_pCvars[VOICE_ENABLED] = get_cvar_pointer("sv_voiceenable"); 55 | 56 | DisableHamForward(g_hHamSpawn = RegisterHam(Ham_Spawn, "player", "player_spawn_post", 1)); 57 | } 58 | public plugin_precache() 59 | { 60 | register_clcmd("say", "clcmd_say"); 61 | register_clcmd("say_team", "clcmd_say"); 62 | } 63 | public plugin_cfg() 64 | { 65 | g_pCvars[FREEZETIME] = get_cvar_pointer("mp_freezetime"); 66 | g_pCvars[VOTE_IN_NEW_ROUND] = get_cvar_pointer("mapm_vote_in_new_round"); 67 | g_pCvars[PREPARE_TIME] = get_cvar_pointer("mapm_prepare_time"); 68 | g_pCvars[VOTE_TIME] = get_cvar_pointer("mapm_vote_time"); 69 | } 70 | public plugin_end() 71 | { 72 | if(g_bFreezeTimeChanged) { 73 | set_float(FREEZETIME, get_float(FREEZETIME) - get_float(PREPARE_TIME) - get_float(VOTE_TIME) - 1); 74 | } 75 | } 76 | public clcmd_say(id) 77 | { 78 | if(!g_bBlockChat) return PLUGIN_CONTINUE; 79 | 80 | new args[2]; read_args(args, charsmax(args)); 81 | 82 | return (args[0] == '/') ? PLUGIN_HANDLED_MAIN : PLUGIN_HANDLED; 83 | } 84 | public player_spawn_post(id) 85 | { 86 | if(g_bFreezeFlagsChanged) { 87 | set_pev(id, pev_flags, pev(id, pev_flags) | FL_FROZEN); 88 | } 89 | if(get_num(BLACK_SCREEN)) { 90 | set_black_screenfade(1); 91 | } 92 | } 93 | public mapm_countdown(type, time) 94 | { 95 | if(type == COUNTDOWN_PREPARE) { 96 | // hud timer 97 | new players[32], pnum; get_players(players, pnum, "ch"); 98 | set_hudmessage(50, 255, 50, -1.0, 0.3, 0, 0.0, 1.0, 0.0, 0.0, 4); 99 | for(new i, id; i < pnum; i++) { 100 | id = players[i]; 101 | show_hudmessage(id, "%L %L!", id, "MAPM_HUD_TIMER", time, id, "MAPM_SECONDS"); 102 | } 103 | } 104 | } 105 | public mapm_prepare_votelist(type) 106 | { 107 | if(get_num(BLACK_SCREEN)) { 108 | set_black_screenfade(2); 109 | set_task(1.0, "set_full_black", TASK_FULLBLACK); 110 | } 111 | if(get_num(BLOCK_CHAT)) { 112 | g_bBlockChat = true; 113 | } 114 | if(get_num(BLOCK_VOICE)) { 115 | set_num(VOICE_ENABLED, 0); 116 | } 117 | if(get_num(FREEZE_IN_VOTE)) { 118 | if(get_num(FREEZE_IN_VOTE) == FREEZE_TIME_ENABLED 119 | && (type == VOTE_BY_SCHEDULER || type == VOTE_BY_RTV || type == VOTE_BY_CMD) 120 | && get_num(VOTE_IN_NEW_ROUND)) { 121 | // increase freezetime 122 | g_bFreezeTimeChanged = true; 123 | set_float(FREEZETIME, get_float(FREEZETIME) + get_float(PREPARE_TIME) + get_float(VOTE_TIME) + 1); 124 | } else { 125 | g_bFreezeFlagsChanged = true; 126 | freeze_unfreeze(0); 127 | } 128 | } 129 | EnableHamForward(g_hHamSpawn); 130 | } 131 | public mapm_vote_finished(const map[], type, total_votes) 132 | { 133 | disable_effects(); 134 | } 135 | public mapm_vote_canceled(type) 136 | { 137 | disable_effects(); 138 | } 139 | disable_effects() 140 | { 141 | if(get_num(BLACK_SCREEN)) { 142 | remove_task(TASK_FULLBLACK); 143 | set_black_screenfade(0); 144 | } 145 | if(get_num(BLOCK_CHAT)) { 146 | g_bBlockChat = false; 147 | } 148 | if(get_num(BLOCK_VOICE)) { 149 | set_num(VOICE_ENABLED, 1); 150 | } 151 | if(get_num(FREEZE_IN_VOTE) != FREEZE_DISABLED) { 152 | if(g_bFreezeTimeChanged) { 153 | // decrease freezetime 154 | g_bFreezeTimeChanged = false; 155 | set_float(FREEZETIME, get_float(FREEZETIME) - get_float(PREPARE_TIME) - get_float(VOTE_TIME) - 1); 156 | } 157 | if(g_bFreezeFlagsChanged) { 158 | g_bFreezeFlagsChanged = false; 159 | freeze_unfreeze(1); 160 | } 161 | } 162 | DisableHamForward(g_hHamSpawn); 163 | } 164 | public set_full_black(taskid) 165 | { 166 | set_black_screenfade(1); 167 | } 168 | stock freeze_unfreeze(type) 169 | { 170 | new players[32], pnum; get_players(players, pnum, "a"); 171 | for(new id, i; i < pnum; i++) { 172 | id = players[i]; 173 | set_pev(id, pev_flags, type ? (pev(id, pev_flags) & ~FL_FROZEN) : pev(id, pev_flags) | FL_FROZEN); 174 | } 175 | } 176 | stock set_black_screenfade(fade) 177 | { 178 | new time, hold, flags; 179 | static msg_screenfade; if(!msg_screenfade) msg_screenfade = get_user_msgid("ScreenFade"); 180 | 181 | switch (fade) { 182 | case 1: { time = 1; hold = 1; flags = 4; } 183 | case 2: { time = 4096; hold = 1024; flags = 1; } 184 | default: { time = 4096; hold = 1024; flags = 2; } 185 | } 186 | 187 | message_begin(MSG_ALL, msg_screenfade); 188 | write_short(time); 189 | write_short(hold); 190 | write_short(flags); 191 | write_byte(0); 192 | write_byte(0); 193 | write_byte(0); 194 | write_byte(255); 195 | message_end(); 196 | } 197 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/data/lang/mapmanager.txt: -------------------------------------------------------------------------------- 1 | [en] 2 | MAPM_VOTE_WILL_BEGIN = The voting will begin in next round. 3 | MAPM_CANCEL_VOTE = %s^1 canceled voting. 4 | MAPM_TIME_TO_END = Until map end left 5 | MAPM_TIMELEFT_OR = or 6 | MAPM_NO_TIMELIMIT = Map has no time limit. 7 | MAPM_THETIME = Current time^1:^4 %s^1. 8 | MAPM_NEXTMAP = Next map:^3 9 | MAPM_NOT_SELECTED = not selected 10 | MAPM_CURRENT_MAP = Current map:^3 %s^1. 11 | MAPM_RTV_DELAY = You cant vote for rtv. Left:^3 %d:%02d^1. 12 | MAPM_RTV_VOTED = %s^1 has voted to change map. Left:^3 %d^1 13 | MAPM_RTV_ALREADY_VOTED = You have already rocked the vote. Left:^3 %d^1 14 | MAPM_NOM_NOT_AVAILABLE_MAP = This map is not available for nomination. 15 | MAPM_NOM_REMOVE_NOM = %s^1 has denominated map^3 %s^1. 16 | MAPM_NOM_SPAM = Don't spam with removing a nomination. 17 | MAPM_NOM_ALREADY_NOM = This map is already nominated. 18 | MAPM_NOM_CANT_NOM = You can't nominate any more maps. 19 | MAPM_NOM_CANT_NOM2 = All nomination slots reserved. 20 | MAPM_NOM_MAP = %s^1 nominated^3 %s^1. 21 | MAPM_NOM_NOMINATED_LIST = Nominated maps: 22 | MAPM_NOM_NOMINATED_NOTHING = No nominated maps. 23 | MAPM_NOM_REMOVED_MAPS = These nominated maps have been removed from the vote: ^4%s 24 | MAPM_MENU_FAST_NOM = Found some maps: 25 | MAPM_MENU_MAP_LIST = Maps list 26 | MAPM_MENU_BACK = Back 27 | MAPM_MENU_NEXT = Next 28 | MAPM_MENU_EXIT = Exit 29 | MAPM_HUD_TIMER = Voting will begin in %d 30 | MAPM_MENU_VOTE_RESULTS = Voting result 31 | MAPM_MENU_CHOOSE_MAP = Choose map 32 | MAPM_MENU_EXTEND = Extend 33 | MAPM_MENU_LEFT = Left 34 | MAPM_CHOSE_EXTEND = %s^1 has chosen to extend the current map. 35 | MAPM_CHOSE_MAP = %s^1 has chosen^3 %s^1. 36 | MAPM_NOBODY_VOTE = Nobody voted. 37 | MAPM_NEXTMAP_BY_VOTE = Next map is^3 %s^1. 38 | MAPM_LASTROUND = Last round. 39 | MAPM_FINAL_ROUND = The last round ended in a draw. The winner will be determined in ^3the final round^1. 40 | MAPM_MAP_CHANGE = Map will change in^3 %d 41 | MAPM_MAP_CHANGE_NEXTROUND = Map change will happen after this round. 42 | MAPM_MAP_EXTEND = Current map has been extended to^3 %d^1 43 | MAPM_SECONDS = sec 44 | MAPM_MINUTES = min 45 | MAPM_ROUNDS = rounds 46 | MAPM_WINS = wins 47 | MAPM_VOTE_IN_NEXTROUND = Wait vote in next round. 48 | MAPM_SECOND_VOTE = Second vote. 49 | MAPM_CHANGELEVEL_NEXTROUND = Map will change in next round. 50 | MAPM_VOTE_ALREADY_STARTED = Voting has already started. 51 | MAPM_VOTE_ALREADY_FINISHED = Voting has already ended. 52 | MAPM_EARLY_FINISH_VOTE = All players have voted, so we are ending voting^3 early^1. 53 | MAPM_FORCE_VOTE_BY_ONLINE = Forced voting to change the map. Current map does not match the current map online. 54 | 55 | [pl] 56 | MAPM_VOTE_WILL_BEGIN = Glosowanie rozpocznie sie w nastepnej rundzie. 57 | MAPM_CANCEL_VOTE = %s^1 Anulowal glowoanie 58 | MAPM_TIME_TO_END = do konca mapy pozostalo 59 | MAPM_TIMELEFT_OR = lub 60 | MAPM_NO_TIMELIMIT = Brak limitu czasowego. 61 | MAPM_THETIME = Aktualna godzina^1:^4 %s^1. 62 | MAPM_NEXTMAP = Nastepna mapa:^3 63 | MAPM_NOT_SELECTED = nie wybrano 64 | MAPM_CURRENT_MAP = Aktualna mapa:^3 %s^1. 65 | MAPM_RTV_DELAY = Nie mozna glosowac na zmiane mapy. Pozostalo:^3 %d:%02d^1. 66 | MAPM_RTV_VOTED = %s^1 Zaglosowal na zmiane mapy. Potrzebnych glosow:^3 %d^1 67 | MAPM_RTV_ALREADY_VOTED = Juz raz uzyles^3 rtv^1. Pozostalo:^3 %d^1 68 | MAPM_NOM_NOT_AVAILABLE_MAP = Ta mapa nie jest dostepna do nominacji. 69 | MAPM_NOM_REMOVE_NOM = %s^1 Nomoniowal mape^4 %s^1. 70 | MAPM_NOM_SPAM = Prosze nie spamowac. Dzieki. 71 | MAPM_NOM_ALREADY_NOM = Ta mapa jest juz nominowana. 72 | MAPM_NOM_CANT_NOM = Nie mozesz nominowac wiecej map. 73 | MAPM_NOM_CANT_NOM2 = Nie mozesz nominowac juz wiecej map. 74 | MAPM_NOM_MAP = %s^1 nominowal^3 %s^1. 75 | MAPM_NOM_NOMINATED_LIST = Nominated maps: 76 | MAPM_NOM_NOMINATED_NOTHING = No nominated maps. 77 | MAPM_NOM_REMOVED_MAPS = These nominated maps have been removed from the vote: ^4%s 78 | MAPM_MENU_FAST_NOM = Szybka nominacja map: 79 | MAPM_MENU_MAP_LIST = Lista map 80 | MAPM_MENU_BACK = Wroc 81 | MAPM_MENU_NEXT = Dalej 82 | MAPM_MENU_EXIT = Wyjdz 83 | MAPM_HUD_TIMER = Glosowanie rozpocznie sie za %d 84 | MAPM_MENU_VOTE_RESULTS = Rezultat glosowania 85 | MAPM_MENU_CHOOSE_MAP = Wybierz mape 86 | MAPM_MENU_EXTEND = Przedluz 87 | MAPM_MENU_LEFT = Koniec glosowania za: 88 | MAPM_CHOSE_EXTEND = %s^1 Wybral^4 przedluzenie^1 aktualnej mapy. 89 | MAPM_CHOSE_MAP = %s^1 wybral^4 %s^1. 90 | MAPM_NOBODY_VOTE = Nikt nie oddal glosu. 91 | MAPM_NEXTMAP_BY_VOTE = Nastepna mapa ^3 %s^1. 92 | MAPM_LASTROUND = Ostatnia runda. 93 | MAPM_FINAL_ROUND = The last round ended in a draw. The winner will be determined in ^3the final round^1. 94 | MAPM_MAP_CHANGE = Mapa zmieni sie za^3 %d 95 | MAPM_MAP_CHANGE_NEXTROUND = Zmiana mapy nastapi po tej rundzie. 96 | MAPM_MAP_EXTEND = Aktualna mapa zostala przedluzona o^4 %d^1 97 | MAPM_SECONDS = sec 98 | MAPM_MINUTES = min 99 | MAPM_ROUNDS = roundy 100 | MAPM_WINS = wygrane 101 | MAPM_VOTE_IN_NEXTROUND = Poczekaj na glosowanie w nastepnej rundzie. 102 | MAPM_SECOND_VOTE = Drugie glosowanie. 103 | MAPM_CHANGELEVEL_NEXTROUND = Mapa zostanie zmieniona w nastepnej rundzie. 104 | MAPM_VOTE_ALREADY_STARTED = Głosowanie już się rozpoczęło. 105 | MAPM_VOTE_ALREADY_FINISHED = Głosowanie już się zakończyło. 106 | MAPM_EARLY_FINISH_VOTE = Wszyscy gracze oddali juz glosy. Konczymy glosowanie^3 wczesniej^1. 107 | MAPM_FORCE_VOTE_BY_ONLINE = Wymuszone głosowanie w sprawie zmiany mapy. Obecna mapa nie zgadza się z aktualną mapą online. 108 | 109 | [ru] 110 | MAPM_VOTE_WILL_BEGIN = Голосование начнется в следующем раунде. 111 | MAPM_CANCEL_VOTE = %s^1 отменил голосование. 112 | MAPM_TIME_TO_END = До конца карты осталось 113 | MAPM_TIMELEFT_OR = либо 114 | MAPM_NO_TIMELIMIT = Карта не ограничена по времени. 115 | MAPM_THETIME = Текущее время^1:^4 %s^1. 116 | MAPM_NEXTMAP = Следующая карта:^3 117 | MAPM_NOT_SELECTED = ещё не выбрана 118 | MAPM_CURRENT_MAP = Текущая карта:^3 %s^1. 119 | MAPM_RTV_DELAY = Вы не можете голосовать за досрочную смену карты. Осталось:^3 %d:%02d^1. 120 | MAPM_RTV_VOTED = %s^1 проголосовал за смену карты. Осталось:^3 %d^1 121 | MAPM_RTV_ALREADY_VOTED = Вы уже голосовали. Осталось:^3 %d^1 122 | MAPM_NOM_NOT_AVAILABLE_MAP = Эта карта недоступна для номинации. 123 | MAPM_NOM_REMOVE_NOM = %s^1 убрал номинацию с карты^3 %s^1. 124 | MAPM_NOM_SPAM = Прекратите злоупотреблять отменой номинации. 125 | MAPM_NOM_ALREADY_NOM = Эта карта уже номинирована. 126 | MAPM_NOM_CANT_NOM = Вы не можете больше номинировать карты. 127 | MAPM_NOM_CANT_NOM2 = Уже номинировано максимальное число карт. 128 | MAPM_NOM_MAP = %s^1 номинировал на голосование^3 %s^1. 129 | MAPM_NOM_NOMINATED_LIST = Номинированные карты: 130 | MAPM_NOM_NOMINATED_NOTHING = Нет номинированных карт. 131 | MAPM_NOM_REMOVED_MAPS = Эти номинированные карты были исключены из голосования: ^4%s 132 | MAPM_MENU_FAST_NOM = Найдено несколько карт: 133 | MAPM_MENU_MAP_LIST = Список карт 134 | MAPM_MENU_BACK = Назад 135 | MAPM_MENU_NEXT = Далее 136 | MAPM_MENU_EXIT = Выход 137 | MAPM_HUD_TIMER = До голосования осталось %d 138 | MAPM_MENU_VOTE_RESULTS = Результаты голосования 139 | MAPM_MENU_CHOOSE_MAP = Выберите карту 140 | MAPM_MENU_EXTEND = Продлить 141 | MAPM_MENU_LEFT = Осталось 142 | MAPM_CHOSE_EXTEND = %s^1 выбрал продление карты. 143 | MAPM_CHOSE_MAP = %s^1 выбрал^3 %s^1. 144 | MAPM_NOBODY_VOTE = Никто не голосовал. 145 | MAPM_NEXTMAP_BY_VOTE = Следующей будет^3 %s^1. 146 | MAPM_LASTROUND = Это последний раунд. 147 | MAPM_FINAL_ROUND = Последний раунд закончился вничью. Победитель определится в ^3финальном раунде^1. 148 | MAPM_MAP_CHANGE = Карта сменится через^3 %d 149 | MAPM_MAP_CHANGE_NEXTROUND = Карта сменится в следующем раунде. 150 | MAPM_MAP_EXTEND = Текущая карта продлена на^3 %d^1 151 | MAPM_SECONDS = сек 152 | MAPM_MINUTES = мин 153 | MAPM_ROUNDS = раунда 154 | MAPM_WINS = побед 155 | MAPM_VOTE_IN_NEXTROUND = Подождите, голосование начнется в следующем раунде. 156 | MAPM_SECOND_VOTE = Второе голосование. 157 | MAPM_CHANGELEVEL_NEXTROUND = Карта сменится в следующем раунде. 158 | MAPM_VOTE_ALREADY_STARTED = Голосование уже началось. 159 | MAPM_VOTE_ALREADY_FINISHED = Голосование уже завершилось. 160 | MAPM_EARLY_FINISH_VOTE = Проголосовали все игроки,^3 досрочно^1 завершаем голосование. 161 | MAPM_FORCE_VOTE_BY_ONLINE = Принудительное голосование за смену карты. Несоответствие онлайна текущей карте. 162 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_adv_lists.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PLUGIN "Map Manager: Advanced lists" 5 | #define VERSION "0.1.0" 6 | #define AUTHOR "Mistrick" 7 | 8 | #pragma semicolon 1 9 | 10 | #define MAX_MAPLISTS 16 11 | 12 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 13 | 14 | new const FILE_MAP_LISTS[] = "maplists.ini"; 15 | 16 | enum (+=100) { 17 | TASK_CHECK_LIST = 150 18 | }; 19 | 20 | enum _:MapListInfo { 21 | AnyTime, 22 | StartTime, 23 | StopTime, 24 | bool:ClearOldList, 25 | ListName[32], 26 | FileList[128] 27 | }; 28 | 29 | enum Cvars { 30 | SHOW_LIST_NAME 31 | }; 32 | 33 | new g_pCvars[Cvars]; 34 | 35 | new Array:g_aLists; 36 | new Array:g_aActiveLists; 37 | new Array:g_aMapLists[MAX_MAPLISTS]; 38 | 39 | new Trie:g_tMapPull; 40 | new g_sCurMap[MAPNAME_LENGTH]; 41 | 42 | public plugin_init() 43 | { 44 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 45 | 46 | g_pCvars[SHOW_LIST_NAME] = register_cvar("mapm_show_list_name_in_vote", "0"); 47 | 48 | mapm_block_load_maplist(); 49 | } 50 | public plugin_natives() 51 | { 52 | g_tMapPull = TrieCreate(); 53 | get_mapname(g_sCurMap, charsmax(g_sCurMap)); 54 | 55 | register_library("map_manager_adv_lists"); 56 | 57 | register_native("mapm_advl_get_active_lists", "native_get_active_lists"); 58 | register_native("mapm_advl_get_list_name", "native_get_list_name"); 59 | register_native("mapm_advl_get_list_array", "native_get_list_array"); 60 | } 61 | public native_get_active_lists(plugin, params) 62 | { 63 | return ArraySize(g_aActiveLists); 64 | } 65 | public native_get_list_name(plugin, params) 66 | { 67 | enum { 68 | arg_item = 1, 69 | arg_list_name, 70 | arg_size 71 | }; 72 | 73 | new item = ArrayGetCell(g_aActiveLists, get_param(arg_item)); 74 | new list_info[MapListInfo]; 75 | ArrayGetArray(g_aLists, item, list_info); 76 | set_string(arg_list_name, list_info[ListName], get_param(arg_size)); 77 | } 78 | public Array:native_get_list_array(plugin, params) 79 | { 80 | enum { 81 | arg_item = 1 82 | }; 83 | 84 | new item = ArrayGetCell(g_aActiveLists, get_param(arg_item)); 85 | return g_aMapLists[item]; 86 | } 87 | public plugin_cfg() 88 | { 89 | new file_path[256]; get_localinfo("amxx_configsdir", file_path, charsmax(file_path)); 90 | format(file_path, charsmax(file_path), "%s/%s", file_path, FILE_MAP_LISTS); 91 | 92 | if(!file_exists(file_path)) { 93 | set_fail_state("Maplists file doesn't exist."); 94 | } 95 | 96 | new f = fopen(file_path, "rt"); 97 | 98 | if(!f) { 99 | set_fail_state("Can't read maplists file."); 100 | } 101 | 102 | // 103 | 104 | g_aLists = ArrayCreate(MapListInfo, 1); 105 | g_aActiveLists = ArrayCreate(1, 1); 106 | 107 | new list_info[MapListInfo]; 108 | new text[256], name[32], start[8], stop[8], file_list[128], clr[4], i = 0; 109 | new bool:have_any = false, time[1440 + 1]; 110 | 111 | while(!feof(f)) { 112 | fgets(f, text, charsmax(text)); 113 | trim(text); 114 | 115 | if(!text[0] || text[0] == ';') continue; 116 | 117 | parse(text, name, charsmax(name), file_list, charsmax(file_list), clr, charsmax(clr), start, charsmax(start), stop, charsmax(stop)); 118 | 119 | copy(list_info[ListName], charsmax(list_info[ListName]), name); 120 | copy(list_info[FileList], charsmax(list_info[FileList]), file_list); 121 | list_info[ClearOldList] = bool:str_to_num(clr); 122 | 123 | if(!start[0] || equal(start, "anytime")) { 124 | list_info[AnyTime] = true; 125 | have_any = true; 126 | } else { 127 | list_info[StartTime] = get_int_time(start); 128 | list_info[StopTime] = get_int_time(stop); 129 | 130 | if(list_info[StartTime] > list_info[StopTime]) { 131 | for(new i = list_info[StartTime]; i <= 1440; i++) { 132 | time[i] = 1; 133 | } 134 | for(new i = 0; i <= list_info[StopTime]; i++) { 135 | time[i] = 1; 136 | } 137 | } else { 138 | for(new i = list_info[StartTime]; i <= list_info[StopTime]; i++) { 139 | time[i] = 1; 140 | } 141 | } 142 | } 143 | 144 | // load maps from file to local list 145 | g_aMapLists[i] = ArrayCreate(MapStruct, 1); 146 | 147 | if(!mapm_load_maplist_to_array(g_aMapLists[i], list_info[FileList])) { 148 | log_amx("nothing loaded from ^"%s^"", list_info[FileList]); 149 | ArrayDestroy(g_aMapLists[i]); 150 | continue; 151 | } 152 | 153 | i++; 154 | 155 | ArrayPushArray(g_aLists, list_info); 156 | 157 | list_info[AnyTime] = false; 158 | list_info[StartTime] = 25 * 60; 159 | list_info[StopTime] = -1; 160 | } 161 | fclose(f); 162 | 163 | new size = ArraySize(g_aLists); 164 | 165 | if(!size) { 166 | // pause plugin? 167 | log_amx("nothing loaded."); 168 | } else { 169 | task_check_list(); 170 | set_task(60.0, "task_check_list", TASK_CHECK_LIST, .flags = "b"); 171 | 172 | if(!have_any) { 173 | new start = -1, s[8], e[8]; 174 | for(new i; i < 1440; i++) { 175 | if(start == -1 && !time[i]) { 176 | start = i; 177 | } 178 | if(start != -1 && (time[i + 1] || (i + 1) == 1440)) { 179 | get_string_time(start, s, charsmax(s)); 180 | get_string_time(i, e, charsmax(e)); 181 | 182 | log_amx("WARN: you have time without active maplist %s-%s", s, e); 183 | 184 | start = -1; 185 | } 186 | } 187 | } 188 | } 189 | } 190 | public task_check_list() 191 | { 192 | new hours, mins; time(hours, mins); 193 | new cur_time = hours * 60 + mins; 194 | 195 | new list_info[MapListInfo]; 196 | 197 | new Array:temp = ArrayCreate(1, 1); 198 | 199 | for(new i, found_newlist, size = ArraySize(g_aLists); i < size; i++) { 200 | ArrayGetArray(g_aLists, i, list_info); 201 | 202 | if(list_info[AnyTime]) { 203 | found_newlist = true; 204 | } else if(list_info[StartTime] <= list_info[StopTime]) { 205 | if(list_info[StartTime] <= cur_time <= list_info[StopTime]) { 206 | found_newlist = true; 207 | } 208 | } else { 209 | if(list_info[StartTime] <= cur_time <= 24 * 60 || cur_time <= list_info[StopTime]) { 210 | found_newlist = true; 211 | } 212 | } 213 | 214 | if(found_newlist) { 215 | found_newlist = false; 216 | if(list_info[ClearOldList]) { 217 | ArrayClear(temp); 218 | } 219 | ArrayPushCell(temp, i); 220 | } 221 | } 222 | 223 | new bool:reload = false; 224 | 225 | if(ArraySize(g_aActiveLists) != ArraySize(temp)) { 226 | reload = true; 227 | } else { 228 | for(new i, size = ArraySize(g_aActiveLists); i < size; i++) { 229 | if(ArrayGetCell(g_aActiveLists, i) != ArrayGetCell(temp, i)) { 230 | reload = true; 231 | break; 232 | } 233 | } 234 | } 235 | 236 | if(reload) { 237 | ArrayDestroy(g_aActiveLists); 238 | g_aActiveLists = temp; 239 | TrieClear(g_tMapPull); 240 | for(new i, item, size = ArraySize(g_aActiveLists); i < size; i++) { 241 | item = ArrayGetCell(g_aActiveLists, i); 242 | ArrayGetArray(g_aLists, item, list_info); 243 | push_maps_to_pull(g_aMapLists[item], list_info[ListName]); 244 | log_amx("loaded new maplist ^"%s^"", list_info[FileList]); 245 | mapm_load_maplist(list_info[FileList], list_info[ClearOldList], i != size - 1); 246 | } 247 | } 248 | } 249 | public mapm_displayed_item_name(type, item, name[]) 250 | { 251 | if(!get_num(SHOW_LIST_NAME)) { 252 | return 0; 253 | } 254 | 255 | if(equali(name, g_sCurMap)) { 256 | return 0; 257 | } 258 | 259 | if(TrieKeyExists(g_tMapPull, name)) { 260 | new list_name[32]; 261 | TrieGetString(g_tMapPull, name, list_name, charsmax(list_name)); 262 | mapm_set_displayed_name(item, fmt("%s\y[%s]", name, list_name)); 263 | } 264 | 265 | return 0; 266 | } 267 | push_maps_to_pull(Array:array, const list_name[]) 268 | { 269 | new map_info[MapStruct]; 270 | for(new i, size = ArraySize(array); i < size; i++) { 271 | ArrayGetArray(array, i, map_info); 272 | TrieSetString(g_tMapPull, map_info[Map], list_name); 273 | } 274 | } 275 | get_int_time(string[]) 276 | { 277 | new left[4], right[4]; strtok(string, left, charsmax(left), right, charsmax(right), ':'); 278 | return str_to_num(left) * 60 + str_to_num(right); 279 | } 280 | get_string_time(time, out[], size) 281 | { 282 | formatex(out, size, "%02d:%02d", time / 60, time % 60); 283 | } 284 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/include/map_manager.inc: -------------------------------------------------------------------------------- 1 | #if defined _map_manager_core_included 2 | #endinput 3 | #endif 4 | #define _map_manager_core_included 5 | 6 | #if AMXX_VERSION_NUM >= 175 7 | #pragma reqlib map_manager_core 8 | #if !defined AMXMODX_NOAUTOLOAD 9 | #pragma loadlib map_manager_core 10 | #endif 11 | #else 12 | #pragma library map_manager_core 13 | #endif 14 | 15 | #include 16 | #include 17 | 18 | /** 19 | * Load maps from file. 20 | * File loads from configs dir. 21 | * 22 | * @param filename File name 23 | * @param clearlist Clear old maplist before new load. 24 | * @param silent If false then will be call forward mapm_maplist_loaded. 25 | * 26 | * @noreturn 27 | */ 28 | native mapm_load_maplist(filename[], bool:clearlist = true, bool:silent = false); 29 | 30 | /** 31 | * Load maps from file. 32 | * File loads from configs dir. 33 | * 34 | * @param array Array with item size MapStruct. 35 | * @param filename File name 36 | * 37 | * @return 1 if success load, 0 otherwise 38 | */ 39 | native mapm_load_maplist_to_array(Array:array, filename[]); 40 | 41 | /** 42 | * Block default load maplist. 43 | * Use before call plugin_cfg(). 44 | * 45 | * @noreturn 46 | */ 47 | native mapm_block_load_maplist(); 48 | 49 | /** 50 | * Add map to maplist 51 | * 52 | * @param name Map name 53 | * @param minplayers Min players for sort 54 | * @param maxplayers Max players for sort 55 | * @param priority Map priority 56 | * 57 | * @return 0 if invalid map or already in array 58 | */ 59 | native mapm_add_map_to_list(name[], minplayers = 0, maxplayers = 32, priority = 0); 60 | 61 | /** 62 | * Get map index in mapslist array. 63 | * 64 | * @param map Map name 65 | * 66 | * @return Map index or INVALID_MAP_INDEX if map not exist in mapslist 67 | */ 68 | native mapm_get_map_index(map[]); 69 | 70 | /** 71 | * Get prefix from core. 72 | * 73 | * @param prefix Prefix string 74 | * @param len String lenght 75 | * 76 | * @noreturn 77 | */ 78 | native mapm_get_prefix(prefix[], len); 79 | 80 | /** 81 | * Set value for vote finished variable. 82 | * 83 | * @param value Bool value 84 | * 85 | * @noreturn 86 | */ 87 | native mapm_set_vote_finished(bool:value); 88 | 89 | /** 90 | * Start vote. 91 | * 92 | * @param type Vote type, use const VOTE_BY_* 93 | * 94 | * @noreturn 95 | */ 96 | native mapm_start_vote(type); 97 | 98 | /** 99 | * Stop vote. 100 | * 101 | * @noreturn 102 | */ 103 | native mapm_stop_vote(); 104 | 105 | /** 106 | * Blocks show vote menu from core. 107 | * 108 | * @noreturn 109 | */ 110 | native mapm_block_show_vote(); 111 | 112 | /** 113 | * Get votelist size const from core. 114 | * 115 | * @return Votelist size 116 | */ 117 | native mapm_get_votelist_size(); 118 | 119 | /** 120 | * Set max items in vote. 121 | * 122 | * @param value Amount items in vote 123 | * 124 | * @noreturn 125 | */ 126 | native mapm_set_votelist_max_items(value); 127 | 128 | /** 129 | * Push map in votelist. 130 | * 131 | * @note Use native in forward mapm_prepare_votelist(). 132 | * 133 | * @param map Map name 134 | * @param type Type for addons 135 | * @param ignore_check Allow ignore some checks, bit sum, use const CHECK_* 136 | * 137 | * @return Result of pushing, const PUSH_* 138 | */ 139 | native mapm_push_map_to_votelist(map[], type = PUSH_BY_NATIVE, ignore_check = CHECK_NOT_IGNORED); 140 | 141 | /** 142 | * Get amount maps in votelist. 143 | * 144 | * @note Use in mapm_analysis_of_results() 145 | * 146 | * @noreturn 147 | */ 148 | native mapm_get_count_maps_in_vote(); 149 | 150 | /** 151 | * Get info about votelist item. 152 | * 153 | * @note Use in mapm_analysis_of_results() 154 | * 155 | * @param item Index in votelist 156 | * @param map Map name 157 | * @param len Map name string lenght 158 | * 159 | * @return Votes 160 | */ 161 | native mapm_get_voteitem_info(item, map[], len); 162 | 163 | /** 164 | * Returns vote type. 165 | * 166 | * @return Type of vote, used const VOTE_BY_* 167 | */ 168 | native mapm_get_vote_type(); 169 | 170 | /** 171 | * Adds votes to vote item. 172 | * 173 | * @note Use while vote continues. 174 | * 175 | * @param item Index in votelist 176 | * @param value Map name 177 | * 178 | * @return 1 if success 179 | */ 180 | native mapm_add_vote_to_item(item, value); 181 | 182 | /** 183 | * Set displayed name for item. 184 | * 185 | * @note Use in forward mapm_displayed_item_name 186 | * 187 | * @param item Index in votelist 188 | * @param name Displayed name 189 | * 190 | * @noreturn 191 | */ 192 | native mapm_set_displayed_name(item, name[]); 193 | 194 | /** 195 | * Adds a custom item that will always be displayed with the vote. 196 | * 197 | * @note The handler function should be prototyped as: 198 | * public (id, MCustomItem:item) 199 | * id - client index who used the custom item 200 | * item - custom item index 201 | * 202 | * @param type Item type 203 | * @param name Displayed name 204 | * @param handler Handler function, which will be called after selecting a custom item in the voting 205 | * @param add_blank Adds blank line before custom item 206 | * @param add_number Adds number in vote menu, if false handler will be ignored 207 | * 208 | * @return Custom item index 209 | * Invalid_Custom_Item - If can't register handler 210 | */ 211 | native MCustomItem:mapm_add_custom_item(MCI_Type:type, name[], handler[], bool:add_blank = false, bool:add_number = true); 212 | 213 | /** 214 | * Returns if vote started. 215 | * 216 | * @return true/false 217 | */ 218 | native bool:is_vote_started(); 219 | 220 | /** 221 | * Returns if vote finished. 222 | * 223 | * @return true/false 224 | */ 225 | native bool:is_vote_finished(); 226 | 227 | /** 228 | * Called after load map list. 229 | * 230 | * @param maplist Array with loaded maps 231 | * @param nextmap Nextmap after current map in loaded list 232 | * 233 | * @noreturn 234 | */ 235 | forward mapm_maplist_loaded(Array:maplist, const nextmap[]); 236 | 237 | /** 238 | * Called after clear maplist. 239 | * 240 | * @noreturn 241 | */ 242 | forward mapm_maplist_unloaded(); 243 | 244 | /** 245 | * Called every second before vote or in vote. 246 | * 247 | * @param type Type of countdown, used const COUNTDOWN_* 248 | * @param time Current second of countdown 249 | * 250 | * @noreturn 251 | */ 252 | forward mapm_countdown(type, time); 253 | 254 | /** 255 | * Called before vote. 256 | * 257 | * @param type Type of vote, used const VOTE_BY_* 258 | * 259 | * @return Return 1 to block the vote 260 | */ 261 | forward mapm_prepare_votelist(type); 262 | 263 | /** 264 | * Called when core or addons are trying add map in votelist. 265 | * 266 | * @param map Map name 267 | * @param type Type of vote, used const VOTE_BY_* 268 | * @param index Index in mapslist array 269 | * 270 | * @return MAP_ALLOWED 271 | * MAP_BLOCKED 272 | */ 273 | forward mapm_can_be_in_votelist(const map[], type, index); 274 | 275 | /** 276 | * Called for permission to extend current map. 277 | * 278 | * @param type Type of vote, used const VOTE_BY_* 279 | * 280 | * @return EXTEND_ALLOWED to allow extend current map 281 | * EXTEND_BLOCKED to block extend current map 282 | */ 283 | forward mapm_can_be_extended(type); 284 | 285 | /** 286 | * Called when can change displayed name. 287 | * 288 | * @param type Type of vote, used const VOTE_BY_* 289 | * @param item Vote item index, from 0 to MAX_VOTELIST_SIZE 290 | * @param name Original vote item name 291 | * 292 | * @noreturn 293 | */ 294 | forward mapm_displayed_item_name(type, item, name[]); 295 | 296 | /** 297 | * Called when core start show menu with vote. 298 | * 299 | * @param type Type of vote, used const VOTE_BY_* 300 | * 301 | * @noreturn 302 | */ 303 | forward mapm_vote_started(type); 304 | 305 | /** 306 | * Called when core canceled vote. 307 | * 308 | * @param type Type of vote, used const VOTE_BY_* 309 | * 310 | * @noreturn 311 | */ 312 | forward mapm_vote_canceled(type); 313 | 314 | /** 315 | * Called before vote finish. 316 | * 317 | * @param type Type of vote, used const VOTE_BY_* 318 | * @param total_votes Count of players votes 319 | * 320 | * @return ALLOW_VOTE to allow finish vote 321 | * ABORT_VOTE to block finish vote, forward mapm_vote_finished() will not be called 322 | */ 323 | forward mapm_analysis_of_results(type, total_votes); 324 | 325 | /** 326 | * Called when vote finished. 327 | * 328 | * @note Can be blocked in forward mapm_analysis_of_results() 329 | * 330 | * @param map Nextmap 331 | * @param type Type of vote, used const VOTE_BY_* 332 | * @param total_votes Count of players votes 333 | * 334 | * @noreturn 335 | */ 336 | forward mapm_vote_finished(const map[], type, total_votes); 337 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/configs/map_manager.cfg: -------------------------------------------------------------------------------- 1 | echo "Executing Map Manager Configuration File" 2 | 3 | // Core 4 | 5 | // EN: Prefix for addon messages in chat. 6 | // RU: Префикс перед сообщениями плагина. 7 | // !d - default, !t - team, !g - green 8 | // ^1 - default, ^3 - team, ^4 - green 9 | mapm_prefix "^4[MapManager]" 10 | 11 | // EN: The number of maps in the vote. 12 | // RU: Число карт в голосовании. 13 | mapm_votelist_size "5" 14 | 15 | // EN: How to display voting results. 16 | // If you need to switch weapons, set to 2. Using the menu will disable weapon switching. 17 | // RU: Как отображать состояния голосования. 18 | // Если вам требуется смена оружия, ставить 2. Использование меню блокирует смену оружия. 19 | // 0 - disable, 1 - menu, 2 - hud 20 | mapm_show_result_type "1" 21 | 22 | // EN: Show chat message about selected map. 23 | // RU: Вывод сообщений о выбранной карте. 24 | // 0 - disable, 1 - all 25 | mapm_show_selects "1" 26 | 27 | // EN: Show percent in vote menu. 28 | // RU: Вывод процентов в меню голосования. 29 | // 0 - disable, 1 - always, 2 - after vote 30 | mapm_show_percent "1" 31 | 32 | // EN: Changes the numbering order in the menu. 33 | // Example: first row of menu but you need to click on 4. 34 | // RU: Меняет порядок нумерации в меню. 35 | // Пример: первая строка меню, но нужно нажать на 4. 36 | // 0 - disable, 1 - enable 37 | mapm_random_nums "0" 38 | 39 | // EN: Time before voting starts. 40 | // RU: Время перед голосованием. 41 | // seconds 42 | mapm_prepare_time "5" 43 | 44 | // EN: Time to vote. 45 | // RU: Время на голосование. 46 | // seconds 47 | mapm_vote_time "10" 48 | 49 | // EN: Offset for voting menu keys. 50 | // By default keys start at 1, set cvar to 4 and it will start at 5. 51 | // RU: Смещение пунктов голосования. 52 | // По умолчанию пункты начинаются с 1, ставите квар равным 4 и начало будет с 5. 53 | mapm_vote_item_offset "0" 54 | 55 | // EN: Blocks the built-in core adding maps to voting. 56 | // With "1" you can achieve a hard limit on maps for the current online when voting, if addon "Online Sorter" is enabled 57 | // RU: Блокирует встроенное в ядро добавление карт в голосование. 58 | // При "1" можно добиться жесткого ограничения карт по текущему онлайну при голосовании, если вклчен аддон "Online Sorter" 59 | mapm_only_external_vote_items "0" 60 | 61 | // EN: Allows voting to end early if all players have voted. 62 | // RU: Позволяет завершить голосование досрочно, если проголосовали все игроки. 63 | // 0 - disable, 1 - enable 64 | mapm_early_finish_vote "0" 65 | 66 | 67 | // Scheduler 68 | 69 | // EN: Type of map change after voting. 70 | // Type 2 can be blocked by "mapm_last_round" 71 | // RU: Тип смены карты после голосования. 72 | // Тип 2 может быть заблокирован кваром "mapm_last_round" 73 | // 0 - after end vote, 1 - in round end, 2 - after end map 74 | mapm_change_type "1" 75 | 76 | // EN: Start voting N minutes before the end of the map. 77 | // RU: Запуск голосования за N минут до конца карты. 78 | // minutes 79 | mapm_timeleft_to_vote "2" 80 | 81 | // EN: Start voting N rounds before mp_winlimit or mp_maxrounds. 82 | // Should be above zero. 83 | // RU: Запуск голосования за N раундов до mp_winlimit или mp_maxrounds. 84 | // Должно быть больше нуля. 85 | // rounds 86 | mapm_rounds_to_vote "2" 87 | 88 | // EN: Start voting for N frags up to mp_fraglimit. 89 | // RU: Запуск голосования за N фрагов до mp_fraglimit. 90 | // frags 91 | mapm_frags_to_vote "5" 92 | 93 | // EN: Voting only at the beginning of a new round. 94 | // RU: Голосование только в начале нового раунда. 95 | // 0 - disable, 1 - enable 96 | mapm_vote_in_new_round "0" 97 | 98 | // EN: Allows you to finish the round after voting. 99 | // RU: Позволяет доиграть раунд после голосования. 100 | // 0 - disable, 1 - enable 101 | mapm_last_round "0" 102 | 103 | // EN: Allows you to play one more round if the last round finished in a draw. 104 | // Works with "mapm_last_round 1" or "mapm_change_type 1" 105 | // RU: Позволяет сыграть еще один раунд, если последний раунд завершился ничьей. 106 | // Работает с "mapm_last_round 1" или "mapm_change_type 1" 107 | // 0 - disable, 1 - enable 108 | mapm_final_round "0" 109 | 110 | // EN: Second vote with the two maps that received the most votes. 111 | // RU: Второе голосование с двумя картами, которые набрали больше всех голосов. 112 | // 0 - disable, 1 - enable 113 | mapm_second_vote "0" 114 | 115 | // EN: If the card gains less percent than in the cvar, then a second vote takes place. 116 | // RU: Если карта набирает меньше процентов, чем в кваре, то происходит второе голосование. 117 | mapm_second_vote_percent "50" 118 | 119 | // EN: If the last player left, after how many minutes to change to the default card. 120 | // RU: Если вышел последний игрок, через сколько минут сменить на карту поумолчанию. 121 | // 0 - disable 122 | // minutes 123 | mapm_change_to_default_map "0" 124 | 125 | // EN: Default map for previous cvar. 126 | // RU: Карта поумолчанию для предыдущего квара. 127 | mapm_default_map "de_dust2" 128 | 129 | // EN: Type of map extension 130 | // RU: Тип продления карты. 131 | // 0 - minutes, 1 - rounds 132 | mapm_extended_type "0" 133 | 134 | // EN: The maximum number of map extensions. 135 | // RU: Максимальное число продлений карты. 136 | // -1 - бесконечное число продлений 137 | mapm_extended_map_max "3" 138 | 139 | // EN: Extension in minutes for mapm_extended_type "0". 140 | // RU: Продление в минутах для mapm_extended_type "0". 141 | // minutes 142 | mapm_extended_time "15" 143 | 144 | // EN: Extension in rounds for mapm_extended_type "1". 145 | // RU: Продление в раундах для mapm_extended_type "1". 146 | // rounds 147 | mapm_extended_rounds "3" 148 | 149 | // EN: Extends the current map if no one voted. Depends on mapm_extended_map_max. 150 | // RU: Продляет текущую карту, если никто не голосовал. Зависит от mapm_extended_map_max. 151 | // 0 - disable, 1 - enable 152 | mapm_extend_map_if_no_votes "0" 153 | 154 | 155 | // GUI 156 | 157 | // EN: Cursor speed 158 | // The value is cached, updates after changing the map. 159 | // RU: Скорость курсора 160 | // Значение кешировано, обновляет после смены карты. 161 | mapm_cursor_sens "2.5" 162 | 163 | 164 | // Advanced lists 165 | 166 | // EN: When voting, show the name of the list the map is in. 167 | // RU: При голосовании показывать имя списка, в котором состоит карта. 168 | // 0 - disable, 1 - enable 169 | mapm_show_list_name_in_vote "0" 170 | 171 | // Blocklist 172 | 173 | // EN: The number of last maps that will block from being voted. 174 | // RU: Количество последних карт, которые заблокирует от попадания в голосование. 175 | mapm_blocklist_ban_last_maps "10" 176 | 177 | 178 | // Rtv 179 | 180 | // EN: Type of RTV 181 | // RU: Тип ртв. 182 | // 0 - percents, 1 - players 183 | mapm_rtv_mode "0" 184 | 185 | // EN: Change map after vote from rtv if "mapm_change_type" is non-zero. 186 | // RU: Сменить карту после голосования от rtv, если "mapm_change_type" не ноль. 187 | // 0 - disable, 1 - enable 188 | mapm_rtv_change_after_vote "0" 189 | 190 | // EN: Required percentage of votes for early voting. 191 | // RU: Необходимый процент голосов для досрочного голосования. 192 | mapm_rtv_percent "60" 193 | 194 | // EN: The required number of votes for early voting. 195 | // RU: Необходимое число голосов для досрочного голосования. 196 | mapm_rtv_players "5" 197 | 198 | // EN: Disables RTV for N minutes after the start of the map. 199 | // RU: Запрещает ртв на N минут после начала карты. 200 | // minutes 201 | mapm_rtv_delay "0" 202 | 203 | // EN: Allows you to extend the map at rtv. 204 | // RU: Позволяет продлевать карту при ртв. 205 | // 0 - disable, 1 - enable 206 | mapm_rtv_allow_extend "0" 207 | 208 | // EN: Ignores spectators when counting required votes for RTV. 209 | // RU: Игнорирует спектаторов в подсчете необходимых голосов для ртв. 210 | // 0 - disable, 1 - enable 211 | mapm_rtv_ignore_spectators "0" 212 | 213 | 214 | // Nomination 215 | 216 | // EN: Nomination type. 217 | // 0 - standard, allows players to nominate multiple maps, of which a few random ones will be voted. 218 | // 1 - fixed, the first players fill the nomination slots and no one else can nominate. 219 | // RU: Тип номинирования. 220 | // 0 - стандартный, позволяет игрокам номировать несколько карт, из которых несколько случайных попадут в голосование. 221 | // 1 - фиксированный, первые игроки забивают слоты номинирования и больше никто номинировать не может. 222 | mapm_nom_type "0" 223 | 224 | // EN: The maximum number of nominated maps in a vote. 225 | // RU: Максимальное число номинированных карт в голосовании. 226 | mapm_nom_maps_in_vote "3" 227 | 228 | // EN: How many maps each player can nominate. 229 | // RU: Сколько карт может номинировать каждый игрок. 230 | mapm_nom_maps_per_player "3" 231 | 232 | // EN: Do not close the nomination menu if the player has nominated the maximum number of cards. 233 | // RU: Не закрывать меню номинирования, если игрок номировал максимум карт. 234 | // 0 - disable, 1 - enable 235 | mapm_nom_dont_close_menu "1" 236 | 237 | // EN: Nomination spam protection. Forbids to remove the nomination more often than indicated in the cvar. 238 | // RU: Защита от спама номинированием. Запрещает снимать номинирование чаще чем указано в кваре. 239 | // seconds 240 | mapm_nom_denominate_time "5" 241 | 242 | // EN: Display maps in random order in the nomination menu. 243 | // RU: Вывод карт в случайном порядке в меню номинирования. 244 | // 0 - disable, 1 - enable 245 | mapm_nom_random_sort "0" 246 | 247 | // EN: Delete maps from the nomination that are not in the new list of maps. Occurs when "Advanced lists" changes the current map list. 248 | // RU: Удалять карты из номинирования, которых нет в новом списке карт. Происходит, когда "Advanced lists" меняет текущий список карт. 249 | // 0 - disable, 1 - enable 250 | mapm_nom_remove_maps "1" 251 | 252 | // EN: In the nomination menu, display active map lists (from "Advanced lists") 253 | // RU: В меню номинирования выводить активные списки карт (из "Advanced lists") 254 | // 0 - disable, 1 - enable 255 | mapm_nom_show_lists "0" 256 | 257 | // EN: Open to the map list menu after exiting the nominations menu. 258 | // RU: Открыть меню списков карт после выхода из меню номинаций. 259 | // 0 - disable, 1 - enable 260 | mapm_nom_return_to_list "1" 261 | 262 | // EN: Enables a nomination for writing part of the map name in chat. 263 | // RU: Включает номинирование по написанию части названия карты в чате. 264 | // 0 - disable, 1 - enable 265 | mapm_nom_fast_nomination "1" 266 | 267 | // Online sorter 268 | 269 | // EN: Will check the nominated maps against the current online when voting. 270 | // RU: Проверит номирированные карты на соответсвие текущему онлайну при голосовании. 271 | // 0 - disable, 1 - enable 272 | mapm_sort_check_nominated_maps "0" 273 | 274 | 275 | // Effects 276 | 277 | // EN: Black screen when voting. 278 | // RU: Черный экран при голосовании. 279 | // 0 - disable, 1 - enable 280 | mapm_black_screen "1" 281 | 282 | // EN: Chat blocking when voting. 283 | // 284 | // If you have a chat manager, then it should be listed below in the list of plugins 285 | // By default, all MM plugins are placed in a separate plugins.ini, which reads later main plugins.ini, 286 | // because of which the chat manager is higher and the addon cannot block the chat during voting. 287 | // 288 | // RU: Блокировка чата при голосовании. 289 | // 290 | // Если у вас стоит чат менеджер, то он должен быть прописан ниже в списке плагинов 291 | // По умолчанию все плагины ММ вынесены в отдельный plugins.ini, который читает позже 292 | // основного, из-за чего ЧМ стоит выше и аддон не может блокировать чат во время голосования. 293 | // 294 | // 0 - disable, 1 - enable 295 | mapm_block_chat "1" 296 | 297 | // EN: Blocking the voice while voting. 298 | // RU: Блокировка голоса при голосовании. 299 | // 0 - disable, 1 - enable 300 | mapm_block_voice "1" 301 | 302 | // EN: Freeze players when voting. 303 | // mapm_vote_in_new_round "1" uses mp_freezetime. 304 | // If you set the cvar value to "2", then freezing with flags will always be used. 305 | // 306 | // Important: freezing with flags disables the addons "GUI" cursor. 307 | // 308 | // RU: Заморозка игроков при голосовании. 309 | // При mapm_vote_in_new_round "1" используется mp_freezetime. 310 | // Если поставить значение квара "2", то всегда будет использоваться заморозка с помощью флагов. 311 | // 312 | // Важно: заморозка флагами блокирует курсор "GUI" аддона. 313 | // 314 | // 0 - disable, 1 - enable, 2 - force use flags 315 | mapm_freeze_in_vote "1" 316 | 317 | 318 | // Priority 319 | 320 | // EN: Ignore priorities for nominated cards. 321 | // RU: Игнорировать приоритеты для номированных карт. 322 | // 0 - disable, 1 - enable 323 | mapm_priority_ignore_nomination "1" 324 | 325 | 326 | // Online checker 327 | 328 | // EN: Number of online checks. 329 | // RU: Кол-во проверок онлайна. 330 | // 0 - disable 331 | mapm_online_check_count "3" 332 | 333 | // EN: Online check interval 334 | // Important: the settings are applied only after restarting the map. 335 | // 336 | // RU: Интервал проверок онлайна 337 | // Важно: настройки применяются только после перезапуска карты. 338 | // 339 | // seconds 340 | mapm_online_check_interval "30" 341 | 342 | // EN: The time before the start of the online check. 343 | // RU: Время до начала проверок онлайна. 344 | // seconds 345 | mapm_online_check_timeout "120" 346 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_gui.sma: -------------------------------------------------------------------------------- 1 | /* 2 | Credits: [WPMG]PRoSToTeM@, Sanlerus 3 | Models, sprites for test by 8dp 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if AMXX_VERSION_NUM < 183 11 | #include 12 | #include 13 | #endif 14 | 15 | #define PLUGIN "Map Manager: GUI" 16 | #define VERSION "0.0.7" 17 | #define AUTHOR "Mistrick" 18 | 19 | #pragma semicolon 1 20 | 21 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 22 | #define get_float(%0) get_pcvar_float(g_pCvars[%0]) 23 | #define hide_ent(%0) set_pev(%0, pev_effects, pev(%0, pev_effects) | EF_NODRAW) 24 | #define show_ent(%0) set_pev(%0, pev_effects, pev(%0, pev_effects) & ~EF_NODRAW) 25 | 26 | #define BOX_MODEL "models/map_manager/blackbox2.mdl" 27 | #define MODEL_CURSOR "sprites/map_manager/cursor2.spr" 28 | 29 | #define FILE_PACKS "mappacks.ini" 30 | 31 | #define MAX_MAP_CUBES 9 32 | 33 | #define MAX_CURSOR_X 140.0 34 | #define MAX_CURSOR_Y 103.0 35 | #define CURSOR_SENSITIVITY 2.2 36 | 37 | #define UNKNOWN_MAP_FRAME 0.0 38 | #define EXTEND_MAP_FRAME 1.0 39 | 40 | #define COORD_X 0 41 | #define COORD_Y 1 42 | 43 | new const SELECTED_COLOR[3] = {55, 200, 55}; 44 | 45 | enum _:FramesStruct { 46 | BeginFrame, 47 | EndFrame 48 | }; 49 | 50 | enum { 51 | UNKNOWN_MAP, 52 | PACK_MAP, 53 | CURRENT_MAP 54 | }; 55 | 56 | enum Cvars { 57 | CURSOR_SENS, 58 | HIDE_MAP_PREFIX, 59 | SHOW_SELECTS, 60 | BLACK_SCREEN, 61 | SHOW_PERCENT 62 | }; 63 | 64 | new g_pCvars[Cvars]; 65 | 66 | new g_pPointOfView; 67 | new g_pCursorEntity; 68 | 69 | new Float:g_vecCursorPos[33][3]; 70 | new Float:g_vecPOVOrigin[3]; 71 | 72 | new g_bShowGUI[33]; 73 | new g_iCurEnt[33]; 74 | 75 | enum _:CubeInfo { 76 | Name[MAPNAME_LENGTH], 77 | Float:Begin, 78 | Float:End 79 | }; 80 | 81 | new g_eCubesInfo[MAX_MAP_CUBES][CubeInfo]; 82 | new g_pMapCubes[MAX_MAP_CUBES]; 83 | new Float:g_fMapCubesOrigin[MAX_MAP_CUBES][3]; 84 | 85 | new Float:g_fDhudCoords[MAX_MAP_CUBES][2]; 86 | new g_bShowName[MAX_MAP_CUBES]; 87 | 88 | new g_iMapsCount; 89 | new g_bVoted[33]; 90 | 91 | new g_iCurPos[33]; 92 | new Float:g_fCurFrame[33]; 93 | 94 | enum _:PackStruct { 95 | Path[64], 96 | Float:Scale, 97 | Trie:Maps 98 | }; 99 | 100 | new Array:g_aPacks; 101 | 102 | new bool:g_bShowSelects; 103 | new g_iCurMap; 104 | 105 | new g_sCurMap[MAPNAME_LENGTH]; 106 | new g_sPrefix[32]; 107 | 108 | new Float:g_fCursorSens = CURSOR_SENSITIVITY; 109 | 110 | enum Forwards { 111 | AddToFullPack_Pre, 112 | AddToFullPack_Post, 113 | CmdStart_Post, 114 | CheckVisibility_Pre 115 | }; 116 | 117 | new g_hForwards[Forwards]; 118 | 119 | public plugin_init() 120 | { 121 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 122 | 123 | g_pCvars[CURSOR_SENS] = register_cvar("mapm_cursor_sens", "2.5"); 124 | 125 | // TODO: cvars 126 | // g_pCvars[HIDE_MAP_PREFIX] = register_cvar("mapm_hide_map_prefix", "1"); 127 | } 128 | public plugin_cfg() 129 | { 130 | mapm_get_prefix(g_sPrefix, charsmax(g_sPrefix)); 131 | 132 | g_pCvars[SHOW_SELECTS] = get_cvar_pointer("mapm_show_selects"); 133 | g_pCvars[SHOW_PERCENT] = get_cvar_pointer("mapm_show_percent"); 134 | g_pCvars[BLACK_SCREEN] = get_cvar_pointer("mapm_black_screen"); 135 | 136 | g_fCursorSens = get_float(CURSOR_SENS); 137 | 138 | set_task(1.0, "check_cvar"); 139 | } 140 | public check_cvar() 141 | { 142 | if(g_pCvars[BLACK_SCREEN] && get_num(BLACK_SCREEN)) { 143 | log_amx("WARNING: set config value ^"mapm_black_screen^" to 0."); 144 | set_pcvar_num(g_pCvars[BLACK_SCREEN], 0); 145 | } 146 | } 147 | public plugin_precache() 148 | { 149 | precache_model(BOX_MODEL); 150 | precache_model(MODEL_CURSOR); 151 | 152 | g_pPointOfView = create_entity("info_target"); 153 | set_pev(g_pPointOfView, pev_classname, "PointOfView"); 154 | entity_set_model(g_pPointOfView, BOX_MODEL); 155 | entity_set_size(g_pPointOfView, Float:{ -5.0, -5.0, -5.0 }, Float:{ 5.0, 5.0, 5.0 }); 156 | set_pev(g_pPointOfView, pev_effects, EF_BRIGHTLIGHT); 157 | 158 | g_pCursorEntity = create_entity("info_target"); 159 | set_pev(g_pCursorEntity, pev_classname, "CursorEntity"); 160 | set_pev(g_pCursorEntity, pev_scale, 0.1); 161 | entity_set_model(g_pCursorEntity, MODEL_CURSOR); 162 | 163 | for(new i; i < sizeof(g_pMapCubes); i++) { 164 | g_pMapCubes[i] = create_entity("info_target"); 165 | set_pev(g_pMapCubes[i], pev_classname, "MapCube"); 166 | set_pev(g_pMapCubes[i], pev_scale, 0.2); 167 | set_pev(g_pMapCubes[i], pev_effects, EF_BRIGHTLIGHT); 168 | entity_set_size(g_pMapCubes[i], Float:{ -5.0, -5.0, -5.0 }, Float:{ 5.0, 5.0, 5.0 }); 169 | } 170 | 171 | new Float:origin[3] = { -4000.0, -3800.0, -4000.0 }; 172 | 173 | entity_set_origin(g_pPointOfView, origin); 174 | g_vecPOVOrigin = origin; 175 | 176 | // TODO: Move offsets to defines 177 | origin[0] += 144.0; 178 | origin[1] += 96.0; 179 | origin[2] += 48.0; 180 | 181 | for(new i; i < sizeof(g_pMapCubes); i++) { 182 | entity_set_origin(g_pMapCubes[i], origin); 183 | g_fMapCubesOrigin[i] = origin; 184 | 185 | origin[1] -= 96.0; 186 | 187 | if((i + 1) % 3 == 0) { 188 | origin[2] -= 48.0; 189 | origin[1] += 96.0 * 3.0; 190 | } 191 | } 192 | 193 | get_mapname(g_sCurMap, charsmax(g_sCurMap)); 194 | 195 | load_packs(); 196 | 197 | get_dhud_coords(); 198 | hide_gui(); 199 | } 200 | 201 | get_dhud_coords() 202 | { 203 | new Float:start[3]; 204 | pev(g_pPointOfView, pev_origin, start); 205 | start[1] += MAX_CURSOR_X; 206 | start[2] += MAX_CURSOR_Y; 207 | 208 | new Float:cube[3], Float:diff[2]; 209 | 210 | for(new i; i < sizeof(g_pMapCubes); i++) { 211 | cube = g_fMapCubesOrigin[i]; 212 | diff[COORD_X] = start[1] - cube[1]; 213 | diff[COORD_Y] = start[2] - cube[2]; 214 | 215 | g_fDhudCoords[i][COORD_X] = diff[COORD_X] / (MAX_CURSOR_X * 2.0) - 0.07; 216 | g_fDhudCoords[i][COORD_Y] = diff[COORD_Y] / (MAX_CURSOR_Y * 2.0); 217 | g_fDhudCoords[i][COORD_Y] += (g_fDhudCoords[i][COORD_Y] > 0.5) ? 0.058 : 0.073; 218 | 219 | // server_print("%d - %f %f", i, g_fDhudCoords[i][COORD_X], g_fDhudCoords[i][COORD_Y]); 220 | } 221 | } 222 | 223 | load_packs() 224 | { 225 | new file_path[256]; get_localinfo("amxx_configsdir", file_path, charsmax(file_path)); 226 | format(file_path, charsmax(file_path), "%s/%s", file_path, FILE_PACKS); 227 | 228 | if(!file_exists(file_path)) { 229 | new error[192]; formatex(error, charsmax(error), "File doesn't exist ^"%s^".", file_path); 230 | set_fail_state(error); 231 | return 0; 232 | } 233 | 234 | new f = fopen(file_path, "rt"); 235 | 236 | if(!f) { 237 | set_fail_state("Can't read map packs file."); 238 | return 0; 239 | } 240 | 241 | g_aPacks = ArrayCreate(PackStruct, 1); 242 | 243 | new text[128], pack_info[PackStruct], map[MAPNAME_LENGTH], frames_info[FramesStruct], cur_frame, frames, str_frames[8]; 244 | 245 | while(!feof(f)) { 246 | fgets(f, text, charsmax(text)); 247 | trim(text); 248 | 249 | if(!text[0] || text[0] == ';') { 250 | continue; 251 | } 252 | 253 | // found new pack 254 | if(containi(text, ".spr") != -1) { 255 | new Float:scale, str_scale[8]; 256 | parse(text, pack_info[Path], charsmax(pack_info[Path]), str_scale, charsmax(str_scale)); 257 | 258 | scale = str_to_float(str_scale); 259 | if(!scale) { 260 | scale = 0.1; 261 | } 262 | 263 | pack_info[Scale] = _:scale; 264 | pack_info[Maps] = _:TrieCreate(); 265 | ArrayPushArray(g_aPacks, pack_info); 266 | precache_model(pack_info[Path]); 267 | cur_frame = 2; 268 | // log_amx("pack: %s, scale: %f", pack_info[Path], scale); 269 | continue; 270 | } 271 | 272 | parse(text, map, charsmax(map), str_frames, charsmax(str_frames)); 273 | 274 | frames = str_to_num(str_frames); 275 | if(!frames) { 276 | frames = 1; 277 | } 278 | 279 | frames_info[BeginFrame] = cur_frame; 280 | frames_info[EndFrame] = cur_frame + frames - 1; 281 | 282 | // load maps to last pack 283 | TrieSetArray(pack_info[Maps], map, frames_info, sizeof(frames_info)); 284 | // log_amx("map: %s, begin: %d, end: %d", map, frames_info[BeginFrame], frames_info[EndFrame]); 285 | 286 | cur_frame = frames_info[EndFrame] + 1; 287 | str_frames = ""; 288 | } 289 | fclose(f); 290 | 291 | return 1; 292 | } 293 | 294 | find_map_frame(map[], pack[], plen, &Float:scale,&Float:begin, &Float:end) 295 | { 296 | new pack_info[PackStruct]; 297 | if(equali(map, g_sCurMap)) { 298 | ArrayGetArray(g_aPacks, 0, pack_info); 299 | copy(pack, plen, pack_info[Path]); 300 | scale = pack_info[Scale]; 301 | begin = end = EXTEND_MAP_FRAME; 302 | return CURRENT_MAP; 303 | } 304 | 305 | new size = ArraySize(g_aPacks), frames_info[FramesStruct]; 306 | for(new i; i < size; i++) { 307 | ArrayGetArray(g_aPacks, i, pack_info); 308 | if(TrieGetArray(pack_info[Maps], map, frames_info, sizeof(frames_info))) { 309 | copy(pack, plen, pack_info[Path]); 310 | scale = pack_info[Scale]; 311 | begin = float(frames_info[BeginFrame]); 312 | end = float(frames_info[EndFrame]); 313 | return PACK_MAP; 314 | } 315 | } 316 | 317 | copy(pack, plen, pack_info[Path]); 318 | scale = pack_info[Scale]; 319 | begin = end = UNKNOWN_MAP_FRAME; 320 | 321 | return UNKNOWN_MAP; 322 | } 323 | 324 | public mapm_vote_started(type) 325 | { 326 | mapm_block_show_vote(); 327 | 328 | show_gui(); 329 | 330 | g_iMapsCount = mapm_get_count_maps_in_vote(); 331 | g_iCurMap = -1; 332 | 333 | new map[MAPNAME_LENGTH]; 334 | new pack[64], Float:scale, Float:frames_begin, Float:frames_end, ret; 335 | 336 | for(new i; i < g_iMapsCount; i++) { 337 | mapm_get_voteitem_info(i, map, charsmax(map)); 338 | 339 | ret = find_map_frame(map, pack, charsmax(pack), scale, frames_begin, frames_end); 340 | 341 | if(ret == CURRENT_MAP) { 342 | g_iCurMap = i; 343 | } 344 | 345 | g_bShowName[i] = !ret; 346 | 347 | entity_set_model(g_pMapCubes[i], pack); 348 | set_pev(g_pMapCubes[i], pev_frame, frames_begin); 349 | set_pev(g_pMapCubes[i], pev_scale, scale); 350 | 351 | copy(g_eCubesInfo[i][Name], charsmax(g_eCubesInfo[][Name]), map); 352 | g_eCubesInfo[i][Begin] = _:frames_begin; 353 | g_eCubesInfo[i][End] = _:frames_end; 354 | } 355 | 356 | arrayset(g_bVoted, false, sizeof(g_bVoted)); 357 | 358 | new players[32], pnum; 359 | get_players(players, pnum, "ch"); 360 | 361 | for(new i, id; i < pnum; i++) { 362 | id = players[i]; 363 | g_bShowGUI[id] = true; 364 | attach_view(id, g_pPointOfView); 365 | } 366 | 367 | g_bShowSelects = bool:get_num(SHOW_SELECTS); 368 | 369 | switch_hud(0, false); 370 | 371 | g_hForwards[AddToFullPack_Pre] = register_forward(FM_AddToFullPack, "fm_add_to_full_pack_pre", false); 372 | g_hForwards[AddToFullPack_Post] = register_forward(FM_AddToFullPack, "fm_add_to_full_pack_post", true); 373 | g_hForwards[CmdStart_Post] = register_forward(FM_CmdStart, "fm_cmd_start_post", true); 374 | g_hForwards[CheckVisibility_Pre] = register_forward(FM_CheckVisibility, "fm_check_visibility_pre", false); 375 | } 376 | 377 | public mapm_countdown(type, time) 378 | { 379 | if(type != COUNTDOWN_VOTETIME) { 380 | return; 381 | } 382 | 383 | const Float:TIME = 1.0; 384 | 385 | for(new i; i < g_iMapsCount; i++) { 386 | // TODO: show percent 387 | if(!g_bShowName[i]) { 388 | continue; 389 | } 390 | set_dhudmessage(255, 255, 255, g_fDhudCoords[i][COORD_X], g_fDhudCoords[i][COORD_Y], 0, _, TIME); 391 | show_dhudmessage(0, "%s", g_eCubesInfo[i][Name]); 392 | } 393 | } 394 | 395 | hide_gui() 396 | { 397 | for(new i; i < MAX_MAP_CUBES; i++) { 398 | hide_ent(g_pMapCubes[i]); 399 | } 400 | hide_ent(g_pCursorEntity); 401 | hide_ent(g_pPointOfView); 402 | } 403 | 404 | show_gui() 405 | { 406 | for(new i; i < MAX_MAP_CUBES; i++) { 407 | show_ent(g_pMapCubes[i]); 408 | } 409 | show_ent(g_pCursorEntity); 410 | show_ent(g_pPointOfView); 411 | } 412 | 413 | disable_gui() 414 | { 415 | new players[32], pnum; 416 | get_players(players, pnum, "ch"); 417 | 418 | for(new i, id; i < pnum; i++) { 419 | id = players[i]; 420 | g_bShowGUI[id] = false; 421 | attach_view(id, id); 422 | } 423 | 424 | for(new i; i < 8; i++) { 425 | show_dhudmessage(0, ""); 426 | } 427 | 428 | switch_hud(0, true); 429 | 430 | unregister_forward(FM_AddToFullPack, g_hForwards[AddToFullPack_Pre], false); 431 | unregister_forward(FM_AddToFullPack, g_hForwards[AddToFullPack_Post], true); 432 | unregister_forward(FM_CmdStart, g_hForwards[CmdStart_Post], true); 433 | unregister_forward(FM_CheckVisibility, g_hForwards[CheckVisibility_Pre], false); 434 | 435 | hide_gui(); 436 | } 437 | 438 | public mapm_vote_finished(const map[], type, total_votes) 439 | { 440 | disable_gui(); 441 | } 442 | 443 | public mapm_vote_canceled(type) 444 | { 445 | disable_gui(); 446 | } 447 | 448 | stock is_inside(Float:corigin[3], Float:borigin[3], Float:w, Float:h) 449 | { 450 | if(floatabs(corigin[1] - borigin[1]) <= w && floatabs(corigin[2] - borigin[2]) <= h) { 451 | return true; 452 | } 453 | return false; 454 | } 455 | 456 | public fm_cmd_start_post(id, cmd, seed) 457 | { 458 | if (!g_bShowGUI[id]) { 459 | return FMRES_IGNORED; 460 | } 461 | 462 | static Float:old_viewangles[33][3], old_buttons[33]; 463 | new Float:view_angles[3], buttons; 464 | get_uc(cmd, UC_ViewAngles, view_angles); 465 | buttons = get_uc(cmd, UC_Buttons); 466 | 467 | new Float:flDelta = (view_angles[1] - old_viewangles[id][1]); 468 | if (flDelta > 180.0) { 469 | flDelta -= 360.0; 470 | } else if (flDelta < -180.0) { 471 | flDelta += 360.0; 472 | } 473 | 474 | g_vecCursorPos[id][1] += flDelta * g_fCursorSens; 475 | g_vecCursorPos[id][2] += -(view_angles[0] - old_viewangles[id][0]) * g_fCursorSens; 476 | 477 | g_vecCursorPos[id][1] = floatclamp(g_vecCursorPos[id][1], -MAX_CURSOR_X, MAX_CURSOR_X); 478 | g_vecCursorPos[id][2] = floatclamp(g_vecCursorPos[id][2], -MAX_CURSOR_Y, MAX_CURSOR_Y); 479 | 480 | if(!g_bVoted[id]) { 481 | new Float:origin[3], Float:coord[3]; 482 | coord[0] = g_vecCursorPos[id][0] + g_vecPOVOrigin[0] + 144.0; 483 | coord[1] = g_vecCursorPos[id][1] + g_vecPOVOrigin[1]; 484 | coord[2] = g_vecCursorPos[id][2] + g_vecPOVOrigin[2]; 485 | 486 | new pos = -1; 487 | for(new i; i < g_iMapsCount; i++) { 488 | origin = g_fMapCubesOrigin[i]; 489 | // TODO: find better sizes 490 | if(is_inside(coord, origin, 28.0, 24.0)) { 491 | pos = i; 492 | } 493 | } 494 | 495 | if(pos >= 0 && pos != g_iCurPos[id]) { 496 | g_iCurPos[id] = pos; 497 | g_iCurEnt[id] = g_pMapCubes[pos]; 498 | g_fCurFrame[id] = g_eCubesInfo[pos][Begin]; 499 | } else if (pos == -1 && g_iCurPos[id] >= 0) { 500 | g_iCurPos[id] = -1; 501 | g_iCurEnt[id] = 0; 502 | } 503 | 504 | if(buttons & IN_ATTACK && !(old_buttons[id] & IN_ATTACK) && pos != -1) { 505 | // console_print(id, "x: %f, y: %f, z: %f", coord[0], coord[1], coord[2]); 506 | if(g_bShowSelects) { 507 | new name[32]; get_user_name(id, name, charsmax(name)); 508 | if(pos == g_iCurMap) { 509 | client_print_color(0, id, "%s^3 %L", g_sPrefix, LANG_PLAYER, "MAPM_CHOSE_EXTEND", name); 510 | } else { 511 | client_print_color(0, id, "%s^3 %L", g_sPrefix, LANG_PLAYER, "MAPM_CHOSE_MAP", name, g_eCubesInfo[pos][Name]); 512 | } 513 | } 514 | g_bVoted[id] = true; 515 | mapm_add_vote_to_item(pos, 1); 516 | } 517 | } 518 | 519 | old_viewangles[id] = view_angles; 520 | old_buttons[id] = buttons; 521 | 522 | return FMRES_IGNORED; 523 | } 524 | 525 | is_gui_part(ent) 526 | { 527 | if(ent == g_pCursorEntity || ent == g_pPointOfView) { 528 | return true; 529 | } 530 | for(new i; i < sizeof(g_pMapCubes); i++) { 531 | if(ent == g_pMapCubes[i]) { 532 | return true; 533 | } 534 | } 535 | return false; 536 | } 537 | is_not_included(ent) 538 | { 539 | for(new i = g_iMapsCount; i < sizeof(g_pMapCubes); i++) { 540 | if(ent == g_pMapCubes[i]) { 541 | return true; 542 | } 543 | } 544 | return false; 545 | } 546 | 547 | public fm_add_to_full_pack_pre(es, e, ent, host, flags, player, pSet) 548 | { 549 | if(!g_bShowGUI[host] && is_gui_part(ent)) { 550 | return FMRES_SUPERCEDE; 551 | } 552 | if(g_bShowGUI[host] && is_not_included(ent)) { 553 | return FMRES_SUPERCEDE; 554 | } 555 | return FMRES_IGNORED; 556 | } 557 | 558 | public fm_add_to_full_pack_post(es, e, ent, host, flags, player, pSet) 559 | { 560 | if(g_bShowGUI[host]) 561 | { 562 | if(ent == g_iCurEnt[host] /* && !g_bVoted[host] */) 563 | { 564 | // set_rendering(g_pMapCubes[pos], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 20); 565 | set_es(es, ES_RenderMode, kRenderNormal); 566 | set_es(es, ES_RenderAmt, 20); 567 | set_es(es, ES_RenderColor, SELECTED_COLOR); 568 | set_es(es, ES_RenderFx, kRenderFxGlowShell); 569 | 570 | new pos = g_iCurPos[host]; 571 | 572 | if(g_bVoted[host] || g_eCubesInfo[pos][Begin] == g_eCubesInfo[pos][End]) { 573 | return FMRES_IGNORED; 574 | } 575 | 576 | static Float:frame_rate = 0.5; 577 | static Float:last_anim[33]; 578 | 579 | new Float:ftime = get_gametime(); 580 | 581 | if(ftime - last_anim[host] >= frame_rate) { 582 | last_anim[host] = ftime; 583 | if(g_fCurFrame[host] < g_eCubesInfo[pos][End]) { 584 | g_fCurFrame[host]++; 585 | } else if(g_fCurFrame[host] == g_eCubesInfo[pos][End]) { 586 | g_fCurFrame[host] = g_eCubesInfo[pos][Begin]; 587 | } 588 | // log_amx("pos: %d, cur fr %f", pos, g_fCurFrame[host]); 589 | } 590 | set_es(es, ES_Frame, g_fCurFrame[host]); 591 | } 592 | else if(ent == g_pCursorEntity) { 593 | new Float:origin[3]; 594 | origin[0] = g_vecCursorPos[host][0] + g_vecPOVOrigin[0] + 143.0; 595 | origin[1] = g_vecCursorPos[host][1] + g_vecPOVOrigin[1]; 596 | origin[2] = g_vecCursorPos[host][2] + g_vecPOVOrigin[2]; 597 | 598 | set_es(es, ES_Origin, origin); 599 | } 600 | } 601 | return FMRES_IGNORED; 602 | } 603 | 604 | public fm_check_visibility_pre(pEnt, pSet) 605 | { 606 | if (is_gui_part(pEnt)) { 607 | forward_return(FMV_CELL, 1); 608 | return FMRES_SUPERCEDE; 609 | } 610 | return FMRES_IGNORED; 611 | } 612 | 613 | public switch_hud(id, enable) 614 | { 615 | static msg_hide_weapon; 616 | static hud_flags = (1<<0) | (1<<1) | (1<<3) | (1<<4) | (1<<5) | (1<<6); 617 | if(!msg_hide_weapon) { 618 | msg_hide_weapon = get_user_msgid("HideWeapon"); 619 | } 620 | message_begin((id) ? MSG_ONE : MSG_ALL, msg_hide_weapon, _, id); 621 | write_byte(enable ? 0 : hud_flags); 622 | message_end(); 623 | } 624 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_scheduler.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if AMXX_VERSION_NUM < 183 8 | #include 9 | #endif 10 | 11 | #define PLUGIN "Map Manager: Scheduler" 12 | #define VERSION "0.2.4" 13 | #define AUTHOR "Mistrick" 14 | 15 | #pragma semicolon 1 16 | 17 | #if !defined client_disconnected 18 | #define client_disconnected client_disconnect 19 | #endif 20 | 21 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 22 | #define set_num(%0,%1) set_pcvar_num(g_pCvars[%0],%1) 23 | #define get_float(%0) get_pcvar_float(g_pCvars[%0]) 24 | #define set_float(%0,%1) set_pcvar_float(g_pCvars[%0],%1) 25 | #define get_string(%0,%1,%2) get_pcvar_string(g_pCvars[%0],%1,%2) 26 | 27 | #define EVENT_SVC_INTERMISSION "30" 28 | 29 | enum (+=100) { 30 | TASK_CHECKTIME, 31 | TASK_DELAYED_CHANGE, 32 | TASK_CHANGE_TO_DEFAULT 33 | }; 34 | 35 | enum { 36 | CHANGE_AFTER_VOTE, 37 | CHANGE_NEXT_ROUND, 38 | CHANGE_MAP_END 39 | }; 40 | 41 | enum Forwards { 42 | MAP_EXTENDED 43 | }; 44 | 45 | enum Cvars { 46 | CHANGE_TYPE, 47 | TIMELEFT_TO_VOTE, 48 | ROUNDS_TO_VOTE, 49 | FRAGS_TO_VOTE, 50 | VOTE_IN_NEW_ROUND, 51 | LAST_ROUND, 52 | FINAL_ROUND, 53 | SECOND_VOTE, 54 | SECOND_VOTE_PERCENT, 55 | CHANGE_TO_DEFAULT, 56 | DEFAULT_MAP, 57 | EXTENDED_TYPE, 58 | EXTENDED_MAX, 59 | EXTENDED_TIME, 60 | EXTENDED_ROUNDS, 61 | MAXROUNDS, 62 | WINLIMIT, 63 | TIMELIMIT, 64 | CHATTIME, 65 | FRAGLIMIT, 66 | FRAGSLEFT, 67 | NEXTMAP, 68 | EXTEND_MAP_IF_NO_VOTES 69 | }; 70 | 71 | new g_pCvars[Cvars]; 72 | new g_hForwards[Forwards]; 73 | 74 | new bool:g_bVoteInNewRound; 75 | new g_iTeamScore[2]; 76 | new Float:g_fOldTimeLimit; 77 | new g_iExtendedNum; 78 | new g_iVoteType; 79 | 80 | new g_sSecondVoteMaps[2][MAPNAME_LENGTH]; 81 | 82 | new LastRoundState:g_eLastRoundState; 83 | new IgnoreFlags:g_bIgnoreCheckStart; 84 | 85 | new bool:g_bOneMapMode; 86 | 87 | new g_sPrefix[32]; 88 | new g_sCurMap[MAPNAME_LENGTH]; 89 | 90 | public plugin_init() 91 | { 92 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 93 | 94 | g_pCvars[CHANGE_TYPE] = register_cvar("mapm_change_type", "1"); // 0 - after end vote, 1 - in round end, 2 - after end map 95 | g_pCvars[TIMELEFT_TO_VOTE] = register_cvar("mapm_timeleft_to_vote", "2"); // minutes 96 | g_pCvars[ROUNDS_TO_VOTE] = register_cvar("mapm_rounds_to_vote", "2"); // rounds 97 | g_pCvars[FRAGS_TO_VOTE] = register_cvar("mapm_frags_to_vote", "5"); // frags 98 | g_pCvars[VOTE_IN_NEW_ROUND] = register_cvar("mapm_vote_in_new_round", "0"); // 0 - disable, 1 - enable 99 | g_pCvars[LAST_ROUND] = register_cvar("mapm_last_round", "0"); // 0 - disable, 1 - enable 100 | g_pCvars[FINAL_ROUND] = register_cvar("mapm_final_round", "0"); // 0 - disable, 1 - enable 101 | 102 | g_pCvars[SECOND_VOTE] = register_cvar("mapm_second_vote", "0"); // 0 - disable, 1 - enable 103 | g_pCvars[SECOND_VOTE_PERCENT] = register_cvar("mapm_second_vote_percent", "50"); 104 | 105 | g_pCvars[CHANGE_TO_DEFAULT] = register_cvar("mapm_change_to_default_map", "0"); // minutes, 0 - disable 106 | g_pCvars[DEFAULT_MAP] = register_cvar("mapm_default_map", "de_dust2"); 107 | 108 | g_pCvars[EXTENDED_TYPE] = register_cvar("mapm_extended_type", "0"); // 0 - minutes, 1 - rounds 109 | g_pCvars[EXTENDED_MAX] = register_cvar("mapm_extended_map_max", "3"); 110 | g_pCvars[EXTENDED_TIME] = register_cvar("mapm_extended_time", "15"); // minutes 111 | g_pCvars[EXTENDED_ROUNDS] = register_cvar("mapm_extended_rounds", "3"); // rounds 112 | g_pCvars[EXTEND_MAP_IF_NO_VOTES] = register_cvar("mapm_extend_map_if_no_votes", "0"); // 0 - disable, 1 - enable 113 | 114 | g_pCvars[MAXROUNDS] = get_cvar_pointer("mp_maxrounds"); 115 | g_pCvars[WINLIMIT] = get_cvar_pointer("mp_winlimit"); 116 | g_pCvars[TIMELIMIT] = get_cvar_pointer("mp_timelimit"); 117 | g_pCvars[CHATTIME] = get_cvar_pointer("mp_chattime"); 118 | g_pCvars[FRAGLIMIT] = get_cvar_pointer("mp_fraglimit"); 119 | g_pCvars[FRAGSLEFT] = get_cvar_pointer("mp_fragsleft"); 120 | 121 | g_pCvars[NEXTMAP] = register_cvar("amx_nextmap", "", FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY); 122 | 123 | g_hForwards[MAP_EXTENDED] = CreateMultiForward("mapm_scheduler_map_extended", ET_IGNORE, FP_CELL, FP_CELL); 124 | 125 | register_concmd("mapm_start_vote", "concmd_startvote", ADMIN_MAP); 126 | register_concmd("mapm_stop_vote", "concmd_stopvote", ADMIN_MAP); 127 | 128 | register_clcmd("votemap", "clcmd_votemap"); 129 | 130 | if(g_pCvars[FRAGLIMIT]) { 131 | register_event("DeathMsg", "event_deathmsg", "a"); 132 | } 133 | register_event("TeamScore", "event_teamscore", "a"); 134 | register_event("HLTV", "event_newround", "a", "1=0", "2=0"); 135 | // register_event("TextMsg", "event_restart", "a", "2=#Game_Commencing", "2=#Game_will_restart_in"); 136 | register_event(EVENT_SVC_INTERMISSION, "event_intermission", "a"); 137 | 138 | set_task(10.0, "task_checktime", TASK_CHECKTIME, .flags = "b"); 139 | } 140 | public plugin_cfg() 141 | { 142 | get_mapname(g_sCurMap, charsmax(g_sCurMap)); 143 | mapm_get_prefix(g_sPrefix, charsmax(g_sPrefix)); 144 | } 145 | public plugin_natives() 146 | { 147 | register_library("map_manager_scheduler"); 148 | 149 | set_module_filter("module_filter_handler"); 150 | set_native_filter("native_filter_handler"); 151 | 152 | register_native("map_scheduler_get_ignore_check", "native_get_ignore_check"); 153 | register_native("map_scheduler_set_ignore_check", "native_set_ignore_check"); 154 | register_native("map_scheduler_start_vote", "native_start_vote"); 155 | register_native("map_scheduler_stop_vote", "native_stop_vote"); 156 | register_native("map_scheduler_extend_map", "native_extend_map"); 157 | register_native("is_vote_will_in_next_round", "native_vote_will_in_next_round"); 158 | register_native("get_last_round_state", "native_get_last_round_state"); 159 | register_native("is_one_map_mode", "native_is_one_map_mode"); 160 | } 161 | public module_filter_handler(const library[], LibType:type) 162 | { 163 | if(equal(library, "map_manager_nomination")) { 164 | return PLUGIN_HANDLED; 165 | } 166 | return PLUGIN_CONTINUE; 167 | } 168 | public native_filter_handler(const native_func[], index, trap) 169 | { 170 | if(equal(native_func, "map_nomination_set_ignore")) { 171 | return PLUGIN_HANDLED; 172 | } 173 | return PLUGIN_CONTINUE; 174 | } 175 | public native_get_ignore_check(plugin, params) 176 | { 177 | return _:g_bIgnoreCheckStart; 178 | } 179 | public native_set_ignore_check(plugin, params) 180 | { 181 | enum { arg_flags = 1 }; 182 | g_bIgnoreCheckStart = IgnoreFlags:get_param(arg_flags); 183 | } 184 | public native_start_vote(plugin, params) 185 | { 186 | if(g_bVoteInNewRound) { 187 | return 0; 188 | } 189 | 190 | if(g_bOneMapMode) { 191 | return 0; 192 | } 193 | 194 | enum { arg_type = 1 }; 195 | planning_vote(get_param(arg_type)); 196 | 197 | return 1; 198 | } 199 | public native_stop_vote(plugin, params) 200 | { 201 | if(!is_vote_started()) { 202 | return 0; 203 | } 204 | 205 | stop_vote(); 206 | 207 | return 1; 208 | } 209 | public native_extend_map(plugin, params) 210 | { 211 | enum { arg_count = 1 }; 212 | new count = get_param(arg_count); 213 | g_iExtendedNum += count; 214 | // TODO: rounds support? 215 | set_float(TIMELIMIT, get_float(TIMELIMIT) + float(get_num(EXTENDED_TIME)) * float(count)); 216 | return 1; 217 | } 218 | public native_vote_will_in_next_round(plugin, params) 219 | { 220 | return g_bVoteInNewRound; 221 | } 222 | public native_get_last_round_state(plugin, params) 223 | { 224 | return _:g_eLastRoundState; 225 | } 226 | public native_is_one_map_mode(plugin, params) 227 | { 228 | return g_bOneMapMode; 229 | } 230 | public plugin_end() 231 | { 232 | if(g_fOldTimeLimit > 0.0) { 233 | set_float(TIMELIMIT, g_fOldTimeLimit); 234 | } 235 | restore_limits(); 236 | } 237 | restore_limits() 238 | { 239 | if(g_iExtendedNum) { 240 | if(get_num(EXTENDED_TYPE) == EXTEND_ROUNDS) { 241 | new win_limit = get_num(WINLIMIT); 242 | if(win_limit) { 243 | set_pcvar_num(g_pCvars[WINLIMIT], win_limit - g_iExtendedNum * get_num(EXTENDED_ROUNDS)); 244 | } 245 | new max_rounds = get_num(MAXROUNDS); 246 | if(max_rounds) { 247 | set_pcvar_num(g_pCvars[MAXROUNDS], max_rounds - g_iExtendedNum * get_num(EXTENDED_ROUNDS)); 248 | } 249 | } else { 250 | new Float:timelimit = get_float(TIMELIMIT); 251 | if(timelimit) { 252 | new Float:restored_value = timelimit - float(g_iExtendedNum * get_num(EXTENDED_TIME)); 253 | set_float(TIMELIMIT, restored_value); 254 | } 255 | } 256 | g_iExtendedNum = 0; 257 | } 258 | } 259 | public concmd_startvote(id, level, cid) 260 | { 261 | if(!cmd_access(id, level, cid, 1)) { 262 | return PLUGIN_HANDLED; 263 | } 264 | 265 | if(g_bOneMapMode) { 266 | return PLUGIN_HANDLED; 267 | } 268 | 269 | new name[32]; get_user_name(id, name, charsmax(name)); 270 | log_amx("%s started vote", id ? name : "Server"); 271 | 272 | planning_vote(VOTE_BY_CMD); 273 | 274 | return PLUGIN_HANDLED; 275 | } 276 | public concmd_stopvote(id, level, cid) 277 | { 278 | if(!is_vote_started()) { 279 | return PLUGIN_HANDLED; 280 | } 281 | 282 | if(!cmd_access(id, level, cid, 1)) { 283 | return PLUGIN_HANDLED; 284 | } 285 | 286 | new name[32]; get_user_name(id, name, charsmax(name)); 287 | log_amx("%s stopped vote", id ? name : "Server"); 288 | 289 | stop_vote(); 290 | 291 | return PLUGIN_HANDLED; 292 | } 293 | stop_vote() 294 | { 295 | mapm_stop_vote(); 296 | 297 | if(mapm_get_vote_type() == VOTE_BY_SCHEDULER_SECOND) { 298 | map_nomination_set_ignore(false); 299 | } 300 | 301 | if(g_bVoteInNewRound) { 302 | g_bVoteInNewRound = false; 303 | 304 | if(g_fOldTimeLimit > 0.0) { 305 | set_float(TIMELIMIT, g_fOldTimeLimit); 306 | } 307 | } 308 | } 309 | public clcmd_votemap() 310 | { 311 | // Block default vote 312 | return PLUGIN_HANDLED; 313 | } 314 | public client_putinserver(id) 315 | { 316 | if(!is_user_bot(id) && !is_user_hltv(id)) { 317 | remove_task(TASK_CHANGE_TO_DEFAULT); 318 | } 319 | } 320 | public client_disconnected(id) 321 | { 322 | new Float:change_time = get_float(CHANGE_TO_DEFAULT); 323 | if(change_time > 0.0 && !get_players_num(id)) { 324 | set_task(change_time * 60, "task_change_to_default", TASK_CHANGE_TO_DEFAULT); 325 | } 326 | } 327 | public task_change_to_default() 328 | { 329 | if(get_players_num()) { 330 | return; 331 | } 332 | 333 | new default_map[MAPNAME_LENGTH]; get_string(DEFAULT_MAP, default_map, charsmax(default_map)); 334 | 335 | if(!is_map_valid(default_map)) { 336 | return; 337 | } 338 | 339 | log_amx("map changed to default[%s]", default_map); 340 | set_pcvar_string(g_pCvars[NEXTMAP], default_map); 341 | intermission(); 342 | } 343 | public task_checktime() 344 | { 345 | if(is_vote_started() || is_vote_finished() || get_float(TIMELIMIT) <= 0.0) { 346 | return 0; 347 | } 348 | 349 | if(g_bIgnoreCheckStart & IGNORE_TIMER_CHECK) { 350 | return 0; 351 | } 352 | 353 | if(g_bOneMapMode) { 354 | return 0; 355 | } 356 | 357 | new Float:time_to_vote = get_float(TIMELEFT_TO_VOTE); 358 | 359 | new timeleft = get_timeleft(); 360 | if(timeleft <= floatround(time_to_vote * 60.0) && get_players_num()) { 361 | log_amx("[checktime]: start vote, timeleft %d", timeleft); 362 | 363 | planning_vote(VOTE_BY_SCHEDULER); 364 | } 365 | 366 | return 0; 367 | } 368 | public event_deathmsg() 369 | { 370 | if(g_bIgnoreCheckStart & IGNORE_FRAGS_CHECK) { 371 | return 0; 372 | } 373 | 374 | if(g_bOneMapMode) { 375 | return 0; 376 | } 377 | 378 | if(get_num(FRAGLIMIT)) { 379 | if(get_num(FRAGSLEFT) <= get_num(FRAGS_TO_VOTE)) { 380 | log_amx("[deathmsg]: start vote, fragsleft %d", get_num(FRAGSLEFT)); 381 | mapm_start_vote(VOTE_BY_SCHEDULER); 382 | } 383 | } 384 | 385 | return 0; 386 | } 387 | public event_teamscore() 388 | { 389 | new team[2]; read_data(1, team, charsmax(team)); 390 | g_iTeamScore[(team[0] == 'C') ? 0 : 1] = read_data(2); 391 | } 392 | public event_newround() 393 | { 394 | if(is_vote_finished() && g_eLastRoundState) { 395 | if(g_eLastRoundState == LRS_Last && g_iTeamScore[0] == g_iTeamScore[1] && get_num(FINAL_ROUND)) { 396 | g_eLastRoundState = LRS_Final; 397 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_FINAL_ROUND"); 398 | } else { 399 | new nextmap[MAPNAME_LENGTH]; get_string(NEXTMAP, nextmap, charsmax(nextmap)); 400 | client_print_color(0, print_team_default, "%s^1 %L %s^1.", g_sPrefix, LANG_PLAYER, "MAPM_NEXTMAP", nextmap); 401 | intermission(); 402 | } 403 | } 404 | 405 | if(g_bIgnoreCheckStart & IGNORE_ROUND_CHECK) { 406 | return 0; 407 | } 408 | 409 | if(g_bOneMapMode) { 410 | return 0; 411 | } 412 | 413 | new max_rounds = get_num(MAXROUNDS); 414 | if(!is_vote_finished() && max_rounds && (g_iTeamScore[0] + g_iTeamScore[1]) >= max_rounds - get_num(ROUNDS_TO_VOTE)) { 415 | log_amx("[newround]: start vote, maxrounds %d [%d]", max_rounds, g_iTeamScore[0] + g_iTeamScore[1]); 416 | mapm_start_vote(VOTE_BY_SCHEDULER); 417 | } 418 | 419 | new win_limit = get_num(WINLIMIT) - get_num(ROUNDS_TO_VOTE); 420 | if(!is_vote_finished() && win_limit > 0 && (g_iTeamScore[0] >= win_limit || g_iTeamScore[1] >= win_limit)) { 421 | log_amx("[newround]: start vote, winlimit %d [CT: %d, T: %d]", win_limit, g_iTeamScore[0], g_iTeamScore[1]); 422 | mapm_start_vote(VOTE_BY_SCHEDULER); 423 | } 424 | 425 | if(g_bVoteInNewRound && !is_vote_started()) { 426 | log_amx("[newround]: start vote, timeleft %d, new round", get_timeleft()); 427 | mapm_start_vote(g_iVoteType); 428 | } 429 | 430 | return 0; 431 | } 432 | /* 433 | public event_restart() 434 | { 435 | if(get_num(RESTORE_MAP_LIMITS)) { 436 | restore_limits(); 437 | } 438 | } 439 | */ 440 | public event_intermission() 441 | { 442 | if(task_exists(TASK_DELAYED_CHANGE)) { 443 | log_amx("double intermission, how?"); 444 | return; 445 | } 446 | new Float:chattime = get_float(CHATTIME); 447 | set_float(CHATTIME, chattime + 1.0); 448 | set_task(chattime, "delayed_change", TASK_DELAYED_CHANGE); 449 | } 450 | public delayed_change() 451 | { 452 | new nextmap[MAPNAME_LENGTH]; get_string(NEXTMAP, nextmap, charsmax(nextmap)); 453 | set_float(CHATTIME, get_float(CHATTIME) - 1.0); 454 | engine_changelevel(nextmap); 455 | } 456 | planning_vote(type) 457 | { 458 | g_iVoteType = type; 459 | if(get_num(VOTE_IN_NEW_ROUND)) { 460 | g_bVoteInNewRound = true; 461 | 462 | g_fOldTimeLimit = get_float(TIMELIMIT); 463 | if(g_fOldTimeLimit > 0.0) { 464 | set_float(TIMELIMIT, 0.0); 465 | } 466 | 467 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_VOTE_WILL_BEGIN"); 468 | log_amx("[planning_vote]: vote in new round."); 469 | } else { 470 | mapm_start_vote(type); 471 | } 472 | } 473 | public mapm_maplist_loaded(Array:maplist, const nextmap[]) 474 | { 475 | if(!g_eLastRoundState) { 476 | set_pcvar_string(g_pCvars[NEXTMAP], nextmap); 477 | } 478 | 479 | if(ArraySize(maplist) == 1) { 480 | new map_info[MapStruct]; 481 | ArrayGetArray(maplist, 0, map_info); 482 | if(equali(g_sCurMap, map_info[Map])) { 483 | g_bOneMapMode = true; 484 | } 485 | } else { 486 | g_bOneMapMode = false; 487 | } 488 | } 489 | public mapm_can_be_extended(type) 490 | { 491 | if(type == VOTE_BY_SCHEDULER_SECOND) { 492 | return EXTEND_BLOCKED; 493 | } 494 | 495 | new extended_max = get_num(EXTENDED_MAX); 496 | 497 | if(g_iExtendedNum >= extended_max && extended_max != -1) { 498 | return EXTEND_BLOCKED; 499 | } 500 | return EXTEND_ALLOWED; 501 | } 502 | public mapm_prepare_votelist(type) 503 | { 504 | if(type != VOTE_BY_SCHEDULER_SECOND) { 505 | return; 506 | } 507 | 508 | for(new i; i < sizeof(g_sSecondVoteMaps); i++) { 509 | mapm_push_map_to_votelist(g_sSecondVoteMaps[i], PUSH_BY_SECOND_VOTE, CHECK_IGNORE_MAP_ALLOWED); 510 | } 511 | mapm_set_votelist_max_items(2); 512 | } 513 | public mapm_analysis_of_results(type, total_votes) 514 | { 515 | if(type == VOTE_BY_SCHEDULER_SECOND || !get_num(SECOND_VOTE)) { 516 | return ALLOW_VOTE; 517 | } 518 | 519 | if(get_players_num() == 0) { 520 | return ALLOW_VOTE; 521 | } 522 | 523 | new max_items = mapm_get_count_maps_in_vote(); 524 | 525 | if(max_items <= 2) { 526 | return ALLOW_VOTE; 527 | } 528 | 529 | new first, second, max_votes_first, max_votes_second; 530 | new map[MAPNAME_LENGTH], votes; 531 | 532 | for(new i, temp_votes, temp_index; i < max_items; i++) { 533 | votes = mapm_get_voteitem_info(i, map, charsmax(map)); 534 | if(votes >= max_votes_first) { 535 | temp_votes = max_votes_first; 536 | temp_index = first; 537 | max_votes_first = votes; 538 | first = i; 539 | 540 | if(temp_votes > max_votes_second) { 541 | max_votes_second = temp_votes; 542 | second = temp_index; 543 | } 544 | } else if(votes >= max_votes_second) { 545 | max_votes_second = votes; 546 | second = i; 547 | } 548 | } 549 | 550 | new percent = total_votes ? floatround(max_votes_first * 100.0 / total_votes) : 0; 551 | 552 | if(percent >= get_num(SECOND_VOTE_PERCENT)) { 553 | return ALLOW_VOTE; 554 | } 555 | 556 | mapm_get_voteitem_info(first, g_sSecondVoteMaps[0], charsmax(g_sSecondVoteMaps[])); 557 | mapm_get_voteitem_info(second, g_sSecondVoteMaps[1], charsmax(g_sSecondVoteMaps[])); 558 | 559 | log_amx("[analysis]: second vote started. (%s, %s)", g_sSecondVoteMaps[0], g_sSecondVoteMaps[1]); 560 | 561 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_SECOND_VOTE"); 562 | map_nomination_set_ignore(true); 563 | mapm_start_vote(VOTE_BY_SCHEDULER_SECOND); 564 | 565 | return ABORT_VOTE; 566 | } 567 | public mapm_vote_finished(const map[], type, total_votes) 568 | { 569 | if(type == VOTE_BY_SCHEDULER_SECOND) { 570 | map_nomination_set_ignore(false); 571 | } 572 | if(g_fOldTimeLimit > 0.0) { 573 | set_float(TIMELIMIT, g_fOldTimeLimit); 574 | g_fOldTimeLimit = 0.0; 575 | } 576 | g_bVoteInNewRound = false; 577 | 578 | new extend_map_no_votes = get_num(EXTEND_MAP_IF_NO_VOTES); 579 | new extended_max = get_num(EXTENDED_MAX); 580 | 581 | new bool:can_be_extend = bool:(equali(map, g_sCurMap) || !total_votes && extend_map_no_votes && g_iExtendedNum < extended_max && extended_max != -1); 582 | 583 | // map extended 584 | if(can_be_extend) { 585 | g_iExtendedNum++; 586 | 587 | new win_limit = get_num(WINLIMIT); 588 | new max_rounds = get_num(MAXROUNDS); 589 | new num, lang[32]; 590 | 591 | if(get_num(EXTENDED_TYPE) == EXTEND_ROUNDS && (win_limit || max_rounds)) { 592 | num = get_num(EXTENDED_ROUNDS); 593 | lang = "MAPM_ROUNDS"; 594 | 595 | if(win_limit > 0) { 596 | set_num(WINLIMIT, win_limit + num); 597 | } 598 | if(max_rounds > 0) { 599 | set_num(MAXROUNDS, max_rounds + num); 600 | } 601 | } else { 602 | num = get_num(EXTENDED_TIME); 603 | lang = "MAPM_MINUTES"; 604 | set_float(TIMELIMIT, get_float(TIMELIMIT) + float(num)); 605 | } 606 | 607 | if(!total_votes && extend_map_no_votes) { 608 | client_print_color(0, print_team_default, "%s^1 %L %L %L.", g_sPrefix, LANG_PLAYER, "MAPM_NOBODY_VOTE", LANG_PLAYER, "MAPM_MAP_EXTEND", num, LANG_PLAYER, lang); 609 | } 610 | else { 611 | client_print_color(0, print_team_default, "%s^1 %L %L.", g_sPrefix, LANG_PLAYER, "MAPM_MAP_EXTEND", num, LANG_PLAYER, lang); 612 | } 613 | 614 | mapm_set_vote_finished(false); 615 | 616 | log_amx("[vote_finished]: map extended[%d].", g_iExtendedNum); 617 | 618 | new ret; 619 | ExecuteForward(g_hForwards[MAP_EXTENDED], ret, type, g_iExtendedNum); 620 | 621 | return 0; 622 | } 623 | 624 | // change map 625 | if(!total_votes) { 626 | client_print_color(0, print_team_default, "%s^1 %L %L", g_sPrefix, LANG_PLAYER, "MAPM_NOBODY_VOTE", LANG_PLAYER, "MAPM_NEXTMAP_BY_VOTE", map); 627 | } else { 628 | client_print_color(0, print_team_default, "%s^1 %L %s^1.", g_sPrefix, LANG_PLAYER, "MAPM_NEXTMAP", map); 629 | } 630 | 631 | set_pcvar_string(g_pCvars[NEXTMAP], map); 632 | 633 | log_amx("[vote_finished]: nextmap is %s.", map); 634 | 635 | if(get_num(LAST_ROUND)) { 636 | // What if timelimit 0? 637 | g_fOldTimeLimit = get_float(TIMELIMIT); 638 | set_float(TIMELIMIT, 0.0); 639 | g_eLastRoundState = LRS_Last; 640 | 641 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_LASTROUND"); 642 | 643 | log_amx("[vote_finished]: last round - saved timelimit is %f", g_fOldTimeLimit); 644 | } else if(get_num(CHANGE_TYPE) == CHANGE_AFTER_VOTE) { 645 | client_print_color(0, print_team_default, "%s^1 %L^1 %L.", g_sPrefix, LANG_PLAYER, "MAPM_MAP_CHANGE", get_num(CHATTIME), LANG_PLAYER, "MAPM_SECONDS"); 646 | intermission(); 647 | } else if(get_num(CHANGE_TYPE) == CHANGE_NEXT_ROUND) { 648 | g_fOldTimeLimit = get_float(TIMELIMIT); 649 | set_float(TIMELIMIT, 0.0); 650 | g_eLastRoundState = LRS_Last; 651 | 652 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_MAP_CHANGE_NEXTROUND"); 653 | } 654 | 655 | return 0; 656 | } 657 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_nomination.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if AMXX_VERSION_NUM < 183 8 | #include 9 | #endif 10 | 11 | #define PLUGIN "Map Manager: Nomination" 12 | #define VERSION "0.3.8" 13 | #define AUTHOR "Mistrick" 14 | 15 | #pragma semicolon 1 16 | 17 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 18 | 19 | #if !defined client_disconnected 20 | #define client_disconnected client_disconnect 21 | #endif 22 | 23 | new const SETTINGS_FILE[] = "map_manager_settings.ini"; 24 | 25 | enum { 26 | NOMINATION_FAIL, 27 | NOMINATION_SUCCESS, 28 | NOMINATION_REMOVED 29 | }; 30 | 31 | enum { 32 | TYPE_STANDART, 33 | TYPE_FIXED 34 | }; 35 | 36 | enum Cvars { 37 | TYPE, 38 | MAPS_IN_VOTE, 39 | MAPS_PER_PLAYER, 40 | DONT_CLOSE_MENU, 41 | DENOMINATE_TIME, 42 | RANDOM_SORT, 43 | REMOVE_MAPS, 44 | SHOW_LISTS, 45 | RETURN_TO_LIST, 46 | FAST_NOMINATION 47 | }; 48 | 49 | new g_pCvars[Cvars]; 50 | 51 | enum Forwards { 52 | CAN_BE_NOMINATED 53 | }; 54 | 55 | new g_hForwards[Forwards]; 56 | 57 | new Array:g_aNomList; 58 | new Array:g_aMapsList; 59 | new g_hCallbackDisabled; 60 | new g_iNomMaps[33]; 61 | new g_iLastDenominate[33]; 62 | new bool:g_bIgnoreVote = false; 63 | new bool:g_bReturnToList[33]; 64 | 65 | new g_sPrefix[48]; 66 | new g_szCurMap[32]; 67 | 68 | enum Sections { 69 | UNUSED_SECTION, 70 | MAPLIST_COMMANDS, 71 | NOMINATED_MAPS_COMMANDS 72 | } 73 | enum ParserData { 74 | Sections:SECTION, 75 | MAPLIST_COMMAND_FOUND, 76 | NOMINATED_MAPS_COMMAND_FOUND 77 | }; 78 | new parser_info[ParserData]; 79 | 80 | public plugin_init() 81 | { 82 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 83 | 84 | g_pCvars[TYPE] = register_cvar("mapm_nom_type", "0"); // 0 - standart, 1 - fixed 85 | g_pCvars[MAPS_IN_VOTE] = register_cvar("mapm_nom_maps_in_vote", "3"); 86 | g_pCvars[MAPS_PER_PLAYER] = register_cvar("mapm_nom_maps_per_player", "3"); 87 | g_pCvars[DONT_CLOSE_MENU] = register_cvar("mapm_nom_dont_close_menu", "1"); // 0 - disable, 1 - enable 88 | g_pCvars[DENOMINATE_TIME] = register_cvar("mapm_nom_denominate_time", "5"); // seconds 89 | g_pCvars[RANDOM_SORT] = register_cvar("mapm_nom_random_sort", "0"); // 0 - disable, 1 - enable 90 | g_pCvars[REMOVE_MAPS] = register_cvar("mapm_nom_remove_maps", "1"); // 0 - disable, 1 - enable 91 | g_pCvars[SHOW_LISTS] = register_cvar("mapm_nom_show_lists", "0"); // 0 - disable, 1 - enable 92 | g_pCvars[RETURN_TO_LIST] = register_cvar("mapm_nom_return_to_list", "1"); // 0 - disable, 1 - enable 93 | g_pCvars[FAST_NOMINATION] = register_cvar("mapm_nom_fast_nomination", "1"); // 0 - disable, 1 - enable 94 | 95 | g_hForwards[CAN_BE_NOMINATED] = CreateMultiForward("mapm_can_be_nominated", ET_CONTINUE, FP_CELL, FP_STRING); 96 | 97 | register_clcmd("say", "clcmd_say"); 98 | register_clcmd("say_team", "clcmd_say"); 99 | 100 | load_settings(); 101 | 102 | g_hCallbackDisabled = menu_makecallback("callback_disable_item"); 103 | } 104 | load_settings() 105 | { 106 | new configdir[256]; 107 | get_localinfo("amxx_configsdir", configdir, charsmax(configdir)); 108 | 109 | new INIParser:parser = INI_CreateParser(); 110 | 111 | INI_SetParseEnd(parser, "ini_parse_end"); 112 | INI_SetReaders(parser, "ini_key_value", "ini_new_section"); 113 | new bool:result = INI_ParseFile(parser, fmt("%s/%s", configdir, SETTINGS_FILE)); 114 | 115 | if(!result) { 116 | register_default_cmds(); 117 | } 118 | } 119 | public ini_new_section(INIParser:handle, const section[], bool:invalid_tokens, bool:close_bracket, bool:extra_tokens, curtok, any:data) 120 | { 121 | if(equal(section, "nomination_maplist_commands")) { 122 | parser_info[SECTION] = MAPLIST_COMMANDS; 123 | } else if(equal(section, "nomination_nominated_maps_commands")) { 124 | parser_info[SECTION] = NOMINATED_MAPS_COMMANDS; 125 | } else { 126 | parser_info[SECTION] = UNUSED_SECTION; 127 | } 128 | return true; 129 | } 130 | public ini_key_value(INIParser:handle, const key[], const value[], bool:invalid_tokens, bool:equal_token, bool:quotes, curtok, any:data) 131 | { 132 | switch(parser_info[SECTION]) { 133 | case MAPLIST_COMMANDS: { 134 | register_clcmd(fmt("say %s", key), "clcmd_mapslist"); 135 | parser_info[MAPLIST_COMMAND_FOUND] = true; 136 | } 137 | case NOMINATED_MAPS_COMMANDS: { 138 | register_clcmd(fmt("say %s", key), "clcmd_nominated_maps"); 139 | parser_info[NOMINATED_MAPS_COMMAND_FOUND] = true; 140 | } 141 | } 142 | return true; 143 | } 144 | public ini_parse_end(INIParser:handle, bool:halted, any:data) 145 | { 146 | register_default_cmds(); 147 | INI_DestroyParser(handle); 148 | } 149 | register_default_cmds() 150 | { 151 | if(!parser_info[MAPLIST_COMMAND_FOUND]) { 152 | register_clcmd("say maps", "clcmd_mapslist"); 153 | register_clcmd("say /maps", "clcmd_mapslist"); 154 | } 155 | if(!parser_info[NOMINATED_MAPS_COMMAND_FOUND]) { 156 | register_clcmd("say nominations", "clcmd_nominated_maps"); 157 | register_clcmd("say /nominations", "clcmd_nominated_maps"); 158 | } 159 | } 160 | public plugin_natives() 161 | { 162 | get_mapname(g_szCurMap, charsmax(g_szCurMap)); 163 | 164 | set_module_filter("module_filter_handler"); 165 | set_native_filter("native_filter_handler"); 166 | 167 | register_library("map_manager_nomination"); 168 | register_native("is_nomination_ignore_vote", "native_get_ignore"); 169 | register_native("map_nomination_set_ignore", "native_set_ignore"); 170 | } 171 | public module_filter_handler(const library[], LibType:type) 172 | { 173 | if(equal(library, "map_manager_blocklist")) { 174 | return PLUGIN_HANDLED; 175 | } 176 | if(equal(library, "map_manager_adv_lists")) { 177 | return PLUGIN_HANDLED; 178 | } 179 | return PLUGIN_CONTINUE; 180 | } 181 | public native_filter_handler(const native_func[], index, trap) 182 | { 183 | if(equal(native_func, "mapm_get_blocked_count")) { 184 | return PLUGIN_HANDLED; 185 | } 186 | if(equal(native_func, "mapm_advl_get_active_lists")) { 187 | return PLUGIN_HANDLED; 188 | } 189 | if(equal(native_func, "mapm_advl_get_list_name")) { 190 | return PLUGIN_HANDLED; 191 | } 192 | if(equal(native_func, "mapm_advl_get_list_array")) { 193 | return PLUGIN_HANDLED; 194 | } 195 | return PLUGIN_CONTINUE; 196 | } 197 | public native_get_ignore(plugin, params) 198 | { 199 | return g_bIgnoreVote; 200 | } 201 | public native_set_ignore(plugin, params) 202 | { 203 | enum { arg_ignore = 1 }; 204 | g_bIgnoreVote = bool:get_param(arg_ignore); 205 | } 206 | public callback_disable_item() 207 | { 208 | return ITEM_DISABLED; 209 | } 210 | public mapm_maplist_loaded(Array:maplist) 211 | { 212 | g_aMapsList = maplist; 213 | 214 | if(!g_aNomList) { 215 | g_aNomList = ArrayCreate(NomStruct, 1); 216 | } 217 | 218 | if(get_num(REMOVE_MAPS)) { 219 | remove_maps(); 220 | } 221 | 222 | mapm_get_prefix(g_sPrefix, charsmax(g_sPrefix)); 223 | } 224 | public client_disconnected(id) 225 | { 226 | if(g_iNomMaps[id]) { 227 | clear_nominated_maps(id); 228 | } 229 | } 230 | public clcmd_say(id) 231 | { 232 | if(is_one_map_mode()) { 233 | return PLUGIN_CONTINUE; 234 | } 235 | 236 | new text[MAPNAME_LENGTH]; read_args(text, charsmax(text)); 237 | remove_quotes(text); trim(text); strtolower(text); 238 | 239 | if(is_string_with_space(text)) { 240 | return PLUGIN_CONTINUE; 241 | } 242 | 243 | new map_index = mapm_get_map_index(text); 244 | 245 | if(map_index != INVALID_MAP_INDEX) { 246 | nominate_map(id, text); 247 | return PLUGIN_CONTINUE; 248 | } 249 | 250 | if(get_num(FAST_NOMINATION) && strlen(text) >= 3) { 251 | new Array:nominate_list = ArrayCreate(1, 1), array_size; 252 | 253 | map_index = 0; 254 | while( (map_index = find_similar_map(map_index, text)) != INVALID_MAP_INDEX ) { 255 | ArrayPushCell(nominate_list, map_index); 256 | array_size++; 257 | map_index++; 258 | } 259 | 260 | if(array_size == 1) { 261 | map_index = ArrayGetCell(nominate_list, 0); 262 | new map_info[MapStruct]; ArrayGetArray(g_aMapsList, map_index, map_info); 263 | nominate_map(id, map_info[Map]); 264 | } else if(array_size > 1) { 265 | show_nomlist(id, nominate_list, array_size); 266 | } 267 | 268 | ArrayDestroy(nominate_list); 269 | } 270 | 271 | return PLUGIN_CONTINUE; 272 | } 273 | nominate_map(id, map[]) 274 | { 275 | if(mapm_get_blocked_count(map)) { 276 | client_print_color(id, print_team_default, "%s^1 %L", g_sPrefix, id, "MAPM_NOM_NOT_AVAILABLE_MAP"); 277 | return NOMINATION_FAIL; 278 | } 279 | 280 | new nom_info[NomStruct], name[32]; 281 | get_user_name(id, name, charsmax(name)); 282 | 283 | new nom_index = map_nominated(map); 284 | if(nom_index != INVALID_MAP_INDEX) { 285 | ArrayGetArray(g_aNomList, nom_index, nom_info); 286 | if(id != nom_info[NomPlayer]) { 287 | client_print_color(id, print_team_default, "%s^1 %L", g_sPrefix, id, "MAPM_NOM_ALREADY_NOM"); 288 | return NOMINATION_FAIL; 289 | } 290 | 291 | new systime = get_systime(); 292 | if(g_iLastDenominate[id] + get_num(DENOMINATE_TIME) >= systime) { 293 | client_print_color(id, print_team_default, "%s^1 %L", g_sPrefix, id, "MAPM_NOM_SPAM"); 294 | return NOMINATION_FAIL; 295 | } 296 | 297 | g_iLastDenominate[id] = systime; 298 | g_iNomMaps[id]--; 299 | ArrayDeleteItem(g_aNomList, nom_index); 300 | 301 | client_print_color(0, id, "%s^3 %L", g_sPrefix, LANG_PLAYER, "MAPM_NOM_REMOVE_NOM", name, map); 302 | return NOMINATION_REMOVED; 303 | } 304 | 305 | if(get_num(TYPE) == TYPE_FIXED && ArraySize(g_aNomList) >= get_num(MAPS_IN_VOTE)) { 306 | client_print_color(id, print_team_default, "%s^1 %L", g_sPrefix, id, "MAPM_NOM_CANT_NOM2"); 307 | return NOMINATION_FAIL; 308 | } 309 | 310 | if(g_iNomMaps[id] >= get_num(MAPS_PER_PLAYER)) { 311 | client_print_color(id, print_team_default, "%s^1 %L", g_sPrefix, id, "MAPM_NOM_CANT_NOM"); 312 | return NOMINATION_FAIL; 313 | } 314 | 315 | new ret; 316 | ExecuteForward(g_hForwards[CAN_BE_NOMINATED], ret, id, map); 317 | 318 | if(ret == NOMINATION_BLOCKED) { 319 | return NOMINATION_FAIL; 320 | } 321 | 322 | copy(nom_info[NomMap], charsmax(nom_info[NomMap]), map); 323 | nom_info[NomPlayer] = id; 324 | ArrayPushArray(g_aNomList, nom_info); 325 | 326 | g_iNomMaps[id]++; 327 | 328 | client_print_color(0, id, "%s^3 %L", g_sPrefix, LANG_PLAYER, "MAPM_NOM_MAP", name, map); 329 | 330 | return NOMINATION_SUCCESS; 331 | } 332 | show_nomlist(id, Array: array, size) 333 | { 334 | new text[64]; formatex(text, charsmax(text), "%L", LANG_PLAYER, "MAPM_MENU_FAST_NOM"); 335 | new menu = menu_create(text, "nomlist_handler"); 336 | new map_info[MapStruct], item_name[MAPNAME_LENGTH + 16], map_index, nom_index, block_count; 337 | 338 | for(new i; i < size; i++) { 339 | map_index = ArrayGetCell(array, i); 340 | ArrayGetArray(g_aMapsList, map_index, map_info); 341 | 342 | nom_index = map_nominated(map_info[Map]); 343 | block_count = mapm_get_blocked_count(map_info[Map]); 344 | 345 | if(block_count) { 346 | formatex(item_name, charsmax(item_name), "%s[\r%d\d]", map_info[Map], block_count); 347 | menu_additem(menu, item_name, .callback = g_hCallbackDisabled); 348 | } else if(nom_index != INVALID_MAP_INDEX) { 349 | new nom_info[NomStruct]; ArrayGetArray(g_aNomList, nom_index, nom_info); 350 | if(id == nom_info[NomPlayer]) { 351 | formatex(item_name, charsmax(item_name), "%s[\y*\w]", map_info[Map]); 352 | menu_additem(menu, item_name); 353 | } else { 354 | formatex(item_name, charsmax(item_name), "%s[\y*\d]", map_info[Map]); 355 | menu_additem(menu, item_name, .callback = g_hCallbackDisabled); 356 | } 357 | } else { 358 | menu_additem(menu, map_info[Map]); 359 | } 360 | } 361 | 362 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_BACK"); 363 | menu_setprop(menu, MPROP_BACKNAME, text); 364 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_NEXT"); 365 | menu_setprop(menu, MPROP_NEXTNAME, text); 366 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_EXIT"); 367 | menu_setprop(menu, MPROP_EXITNAME, text); 368 | 369 | menu_display(id, menu); 370 | } 371 | public nomlist_handler(id, menu, item) 372 | { 373 | if(item == MENU_EXIT) { 374 | menu_destroy(menu); 375 | return PLUGIN_HANDLED; 376 | } 377 | 378 | new item_info[8], item_name[MAPNAME_LENGTH + 16], access, callback; 379 | menu_item_getinfo(menu, item, access, item_info, charsmax(item_info), item_name, charsmax(item_name), callback); 380 | 381 | trim_bracket(item_name); 382 | new nominated = nominate_map(id, item_name); 383 | 384 | if(nominated == NOMINATION_REMOVED || get_num(DONT_CLOSE_MENU)) { 385 | if(nominated == NOMINATION_SUCCESS) { 386 | format(item_name, charsmax(item_name), "%s[\y*\w]", item_name); 387 | menu_item_setname(menu, item, item_name); 388 | } else if(nominated == NOMINATION_REMOVED) { 389 | menu_item_setname(menu, item, item_name); 390 | } 391 | menu_display(id, menu); 392 | } else { 393 | menu_destroy(menu); 394 | } 395 | 396 | return PLUGIN_HANDLED; 397 | } 398 | public clcmd_mapslist(id) 399 | { 400 | if(is_one_map_mode()) { 401 | return PLUGIN_HANDLED; 402 | } 403 | if(!is_user_connected(id)) { 404 | return PLUGIN_HANDLED; 405 | } 406 | 407 | if(get_num(SHOW_LISTS) && mapm_advl_get_active_lists() > 1) { 408 | g_bReturnToList[id] = false; 409 | show_lists_menu(id); 410 | } else { 411 | show_nomination_menu(id, g_aMapsList); 412 | } 413 | 414 | return PLUGIN_CONTINUE; 415 | } 416 | show_lists_menu(id) 417 | { 418 | new text[64]; 419 | // TODO: add ML 420 | new menu = menu_create("Maps lists:", "lists_handler"); 421 | 422 | new list[32], size = mapm_advl_get_active_lists(); 423 | for(new i; i < size; i++) { 424 | mapm_advl_get_list_name(i, list, charsmax(list)); 425 | menu_additem(menu, list); 426 | } 427 | 428 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_BACK"); 429 | menu_setprop(menu, MPROP_BACKNAME, text); 430 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_NEXT"); 431 | menu_setprop(menu, MPROP_NEXTNAME, text); 432 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_EXIT"); 433 | menu_setprop(menu, MPROP_EXITNAME, text); 434 | 435 | menu_display(id, menu); 436 | } 437 | public lists_handler(id, menu, item) 438 | { 439 | if(item == MENU_EXIT) { 440 | menu_destroy(menu); 441 | return PLUGIN_HANDLED; 442 | } 443 | 444 | menu_destroy(menu); 445 | 446 | if(item >= mapm_advl_get_active_lists()) { 447 | clcmd_mapslist(id); 448 | return PLUGIN_HANDLED; 449 | } 450 | 451 | new list_name[32]; 452 | mapm_advl_get_list_name(item, list_name, charsmax(list_name)); 453 | new Array:maplist = mapm_advl_get_list_array(item); 454 | 455 | g_bReturnToList[id] = true; 456 | 457 | show_nomination_menu(id, maplist, list_name); 458 | 459 | return PLUGIN_HANDLED; 460 | } 461 | show_nomination_menu(id, Array:maplist, custom_title[] = "") 462 | { 463 | new text[64]; 464 | if(!custom_title[0]) { 465 | formatex(text, charsmax(text), "%L", LANG_PLAYER, "MAPM_MENU_MAP_LIST"); 466 | } else { 467 | formatex(text, charsmax(text), "%s", custom_title); 468 | } 469 | new menu = menu_create(text, "mapslist_handler"); 470 | 471 | new map_info[MapStruct], item_name[MAPNAME_LENGTH + 16], block_count, size = ArraySize(maplist); 472 | new random_sort = get_num(RANDOM_SORT), Array:array = ArrayCreate(1, 1); 473 | 474 | for(new i = 0, index, nom_index; i < size; i++) { 475 | if(random_sort) { 476 | do { 477 | index = random_num(0, size - 1); 478 | } while(in_array(array, index)); 479 | ArrayPushCell(array, index); 480 | } else { 481 | index = i; 482 | } 483 | 484 | ArrayGetArray(maplist, index, map_info); 485 | 486 | if(equali(map_info[Map], g_szCurMap)) { 487 | continue; 488 | } 489 | 490 | nom_index = map_nominated(map_info[Map]); 491 | block_count = mapm_get_blocked_count(map_info[Map]); 492 | 493 | if(block_count) { 494 | formatex(item_name, charsmax(item_name), "%s[\r%d\d]", map_info[Map], block_count); 495 | menu_additem(menu, item_name, .callback = g_hCallbackDisabled); 496 | } else if(nom_index != INVALID_MAP_INDEX) { 497 | new nom_info[NomStruct]; ArrayGetArray(g_aNomList, nom_index, nom_info); 498 | if(id == nom_info[NomPlayer]) { 499 | formatex(item_name, charsmax(item_name), "%s[\y*\w]", map_info[Map]); 500 | menu_additem(menu, item_name); 501 | } else { 502 | formatex(item_name, charsmax(item_name), "%s[\y*\d]", map_info[Map]); 503 | menu_additem(menu, item_name, .callback = g_hCallbackDisabled); 504 | } 505 | } else { 506 | menu_additem(menu, map_info[Map]); 507 | } 508 | } 509 | 510 | ArrayDestroy(array); 511 | 512 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_BACK"); 513 | menu_setprop(menu, MPROP_BACKNAME, text); 514 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_NEXT"); 515 | menu_setprop(menu, MPROP_NEXTNAME, text); 516 | formatex(text, charsmax(text), "%L", id, "MAPM_MENU_EXIT"); 517 | menu_setprop(menu, MPROP_EXITNAME, text); 518 | 519 | menu_display(id, menu); 520 | } 521 | bool:in_array(Array:array, index) 522 | { 523 | for(new i, size = ArraySize(array); i < size; i++) { 524 | if(ArrayGetCell(array, i) == index) { 525 | return true; 526 | } 527 | } 528 | return false; 529 | } 530 | public mapslist_handler(id, menu, item) 531 | { 532 | if(item == MENU_EXIT) { 533 | menu_destroy(menu); 534 | 535 | if(g_bReturnToList[id] && get_num(RETURN_TO_LIST)) { 536 | g_bReturnToList[id] = false; 537 | show_lists_menu(id); 538 | } 539 | 540 | return PLUGIN_HANDLED; 541 | } 542 | 543 | new item_info[8], item_name[MAPNAME_LENGTH + 16], access, callback; 544 | menu_item_getinfo(menu, item, access, item_info, charsmax(item_info), item_name, charsmax(item_name), callback); 545 | 546 | trim_bracket(item_name); 547 | new nominated = nominate_map(id, item_name); 548 | 549 | if(g_iNomMaps[id] < get_num(MAPS_PER_PLAYER) || get_num(DONT_CLOSE_MENU)) { 550 | if(nominated == NOMINATION_SUCCESS) { 551 | format(item_name, charsmax(item_name), "%s[\y*\w]", item_name); 552 | menu_item_setname(menu, item, item_name); 553 | } else if(nominated == NOMINATION_REMOVED) { 554 | menu_item_setname(menu, item, item_name); 555 | } 556 | menu_display(id, menu, item / 7); 557 | } else { 558 | menu_destroy(menu); 559 | } 560 | 561 | return PLUGIN_HANDLED; 562 | } 563 | 564 | public clcmd_nominated_maps(id) 565 | { 566 | new size = ArraySize(g_aNomList); 567 | 568 | if(!size) { 569 | client_print_color(id, print_team_default, "%s ^1%L", g_sPrefix, id, "MAPM_NOM_NOMINATED_NOTHING"); 570 | return PLUGIN_HANDLED; 571 | } 572 | 573 | client_print_color(id, print_team_default, "%s ^1%L", g_sPrefix, id, "MAPM_NOM_NOMINATED_LIST"); 574 | 575 | new nom_info[NomStruct]; 576 | new nominated_list[192], len, map_len; 577 | 578 | for(new i; i < size; i++) { 579 | ArrayGetArray(g_aNomList, i, nom_info); 580 | map_len = strlen(nom_info[NomMap]); 581 | 582 | if(len + map_len > 100) { 583 | client_print_color(id, print_team_default, "%s ^1%s", g_sPrefix, nominated_list); 584 | nominated_list = ""; 585 | } 586 | 587 | len = formatex(nominated_list, charsmax(nominated_list), "%s%s, ", nominated_list, nom_info[NomMap]); 588 | } 589 | 590 | nominated_list[len - 2] = 0; 591 | client_print_color(id, print_team_default, "%s ^1%s.", g_sPrefix, nominated_list); 592 | 593 | return PLUGIN_HANDLED; 594 | } 595 | 596 | public mapm_prepare_votelist(type) 597 | { 598 | if(g_bIgnoreVote) { 599 | return; 600 | } 601 | new nom_info[NomStruct]; 602 | new max_items = mapm_get_votelist_size(); 603 | new Array:a = ArrayCreate(MAPNAME_LENGTH, 0); 604 | for(new i = mapm_get_count_maps_in_vote(), result, index; i < max_items && ArraySize(g_aNomList); i++) { 605 | index = random_num(0, ArraySize(g_aNomList) - 1); 606 | ArrayGetArray(g_aNomList, index, nom_info); 607 | ArrayDeleteItem(g_aNomList, index); 608 | g_iNomMaps[nom_info[NomPlayer]]--; 609 | 610 | result = mapm_push_map_to_votelist(nom_info[NomMap], PUSH_BY_NOMINATION); 611 | if(result != PUSH_SUCCESS) { 612 | i--; 613 | if(result == PUSH_BLOCKED) { 614 | ArrayPushString(a, nom_info[NomMap]); 615 | } 616 | } 617 | } 618 | 619 | new size = ArraySize(a); 620 | if(size) { 621 | new removed_maps[192], map[MAPNAME_LENGTH], len; 622 | for(new i; i < size; i++) { 623 | ArrayGetString(a, i, map, charsmax(map)); 624 | len += formatex(removed_maps[len], charsmax(removed_maps) - len, "%s, ", map); 625 | } 626 | removed_maps[len - 2] = 0; 627 | client_print_color(0, print_team_default, "%s ^1%L.", g_sPrefix, LANG_PLAYER, "MAPM_NOM_REMOVED_MAPS", removed_maps); 628 | } 629 | ArrayDestroy(a); 630 | } 631 | 632 | map_nominated(map[]) 633 | { 634 | new nom_info[NomStruct], size = ArraySize(g_aNomList); 635 | for(new i; i < size; i++) { 636 | ArrayGetArray(g_aNomList, i, nom_info); 637 | if(equali(map, nom_info[NomMap])) { 638 | return i; 639 | } 640 | } 641 | return INVALID_MAP_INDEX; 642 | } 643 | clear_nominated_maps(id) 644 | { 645 | new nom_info[NomStruct]; 646 | for(new i = ArraySize(g_aNomList) - 1; i >= 0 ; i--) { 647 | ArrayGetArray(g_aNomList, i, nom_info); 648 | if(id == nom_info[NomPlayer]) { 649 | ArrayDeleteItem(g_aNomList, i); 650 | if(!--g_iNomMaps[id]) { 651 | break; 652 | } 653 | } 654 | } 655 | } 656 | find_similar_map(map_index, string[MAPNAME_LENGTH]) 657 | { 658 | new map_info[MapStruct], end = ArraySize(g_aMapsList); 659 | for(new i = map_index; i < end; i++) { 660 | ArrayGetArray(g_aMapsList, i, map_info); 661 | if(containi(map_info[Map], string) != -1) { 662 | return i; 663 | } 664 | } 665 | return INVALID_MAP_INDEX; 666 | } 667 | remove_maps() 668 | { 669 | new nom_info[NomStruct]; 670 | for(new i; i < ArraySize(g_aNomList); i++) { 671 | ArrayGetArray(g_aNomList, i, nom_info); 672 | if(mapm_get_map_index(nom_info[NomMap]) == INVALID_MAP_INDEX) { 673 | g_iNomMaps[nom_info[NomPlayer]]--; 674 | ArrayDeleteItem(g_aNomList, i--); 675 | } 676 | } 677 | } 678 | -------------------------------------------------------------------------------- /cstrike/addons/amxmodx/scripting/map_manager_core.sma: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if AMXX_VERSION_NUM < 183 6 | #include 7 | #endif 8 | 9 | #define PLUGIN "Map Manager: Core" 10 | #define VERSION "3.3.1" 11 | #define AUTHOR "Mistrick" 12 | 13 | #pragma semicolon 1 14 | 15 | //-----------------------------------------------------// 16 | // Consts 17 | //-----------------------------------------------------// 18 | #define MAX_VOTELIST_SIZE 10 19 | new const FILE_MAPS[] = "maps.ini"; 20 | //-----------------------------------------------------// 21 | 22 | #define get_num(%0) get_pcvar_num(g_pCvars[%0]) 23 | 24 | const NOT_VOTED = -1; 25 | 26 | enum (+=100) { 27 | TASK_PREPARE_VOTE = 100, 28 | TASK_VOTE_TIME 29 | }; 30 | 31 | enum Forwards { 32 | MAPLIST_LOADED, 33 | MAPLIST_UNLOADED, 34 | CAN_BE_IN_VOTELIST, 35 | CAN_BE_EXTENDED, 36 | PREPARE_VOTELIST, 37 | VOTE_STARTED, 38 | VOTE_CANCELED, 39 | ANALYSIS_OF_RESULTS, 40 | VOTE_FINISHED, 41 | COUNTDOWN, 42 | DISPLAYED_ITEM_NAME 43 | }; 44 | 45 | enum Cvars { 46 | PREFIX, 47 | VOTELIST_SIZE, 48 | SHOW_RESULT_TYPE, 49 | SHOW_SELECTS, 50 | SHOW_PERCENT, 51 | RANDOM_NUMS, 52 | PREPARE_TIME, 53 | VOTE_TIME, 54 | VOTE_ITEM_OFFSET, 55 | ONLY_EXTERNAL_VOTE_ITEMS, 56 | EARLY_FINISH_VOTE 57 | }; 58 | 59 | new g_pCvars[Cvars]; 60 | 61 | new g_iOffset; 62 | new g_iVoteItems; 63 | new g_iVotes[MAX_VOTELIST_SIZE]; 64 | new g_iTotalVotes; 65 | new g_iVoted[33]; 66 | 67 | new g_hForwards[Forwards]; 68 | 69 | new Array:g_aMapsList = Invalid_Array; 70 | 71 | new bool:g_bBlockLoad = false; 72 | new g_iShowType; 73 | new g_iShowPercent; 74 | new g_bShowSelects; 75 | new g_iTimer; 76 | new g_bCanExtend; 77 | new g_iExternalMaxItems; 78 | new g_iCurMap; 79 | 80 | new g_iRandomNums[MAX_VOTELIST_SIZE]; 81 | 82 | new bool:g_bBlockShowVote = false; 83 | new g_iVoteType; 84 | new bool:g_bVoteStarted; 85 | new bool:g_bVoteFinished; 86 | 87 | new g_sCurMap[MAPNAME_LENGTH]; 88 | new g_sPrefix[48]; 89 | 90 | new g_iPlayersNum; 91 | 92 | enum _:CustomItemStruct { 93 | ci_name[64], 94 | MCI_Type:ci_type, 95 | ci_handler, 96 | bool:ci_add_blank, 97 | bool:ci_add_number 98 | }; 99 | 100 | new Array:g_aCustomItems; 101 | 102 | enum ItemType { 103 | it_normal, 104 | it_custom 105 | }; 106 | 107 | enum _:ItemStruct { 108 | is_name[64], 109 | is_displayed_name[128], 110 | ItemType:is_type, 111 | is_custom_index 112 | }; 113 | 114 | new Array:g_aMenuItems; 115 | new g_iStartPos; 116 | new g_iPushPos; 117 | new g_iKeyToIndex[MAX_VOTELIST_SIZE]; 118 | 119 | public plugin_init() 120 | { 121 | register_plugin(PLUGIN, VERSION + VERSION_HASH, AUTHOR); 122 | 123 | register_cvar("mapm_version", VERSION, FCVAR_SERVER | FCVAR_SPONLY); 124 | 125 | g_pCvars[PREFIX] = register_cvar("mapm_prefix", "^4[MapManager]"); 126 | g_pCvars[VOTELIST_SIZE] = register_cvar("mapm_votelist_size", "5"); 127 | g_pCvars[SHOW_RESULT_TYPE] = register_cvar("mapm_show_result_type", "1"); //0 - disable, 1 - menu, 2 - hud 128 | g_pCvars[SHOW_SELECTS] = register_cvar("mapm_show_selects", "1"); // 0 - disable, 1 - all 129 | g_pCvars[SHOW_PERCENT] = register_cvar("mapm_show_percent", "1"); // 0 - disable, 1 - always, 2 - after vote 130 | g_pCvars[RANDOM_NUMS] = register_cvar("mapm_random_nums", "0"); // 0 - disable, 1 - enable 131 | g_pCvars[PREPARE_TIME] = register_cvar("mapm_prepare_time", "5"); // seconds 132 | g_pCvars[VOTE_TIME] = register_cvar("mapm_vote_time", "10"); // seconds 133 | g_pCvars[VOTE_ITEM_OFFSET] = register_cvar("mapm_vote_item_offset", "0"); 134 | g_pCvars[ONLY_EXTERNAL_VOTE_ITEMS] = register_cvar("mapm_only_external_vote_items", "0"); 135 | g_pCvars[EARLY_FINISH_VOTE] = register_cvar("mapm_early_finish_vote", "0"); 136 | 137 | g_hForwards[MAPLIST_LOADED] = CreateMultiForward("mapm_maplist_loaded", ET_IGNORE, FP_CELL, FP_STRING); 138 | g_hForwards[MAPLIST_UNLOADED] = CreateMultiForward("mapm_maplist_unloaded", ET_IGNORE); 139 | g_hForwards[PREPARE_VOTELIST] = CreateMultiForward("mapm_prepare_votelist", ET_CONTINUE, FP_CELL); 140 | g_hForwards[VOTE_STARTED] = CreateMultiForward("mapm_vote_started", ET_IGNORE, FP_CELL); 141 | g_hForwards[VOTE_CANCELED] = CreateMultiForward("mapm_vote_canceled", ET_IGNORE, FP_CELL); 142 | g_hForwards[ANALYSIS_OF_RESULTS] = CreateMultiForward("mapm_analysis_of_results", ET_CONTINUE, FP_CELL, FP_CELL); 143 | g_hForwards[VOTE_FINISHED] = CreateMultiForward("mapm_vote_finished", ET_IGNORE, FP_STRING, FP_CELL, FP_CELL); 144 | g_hForwards[CAN_BE_IN_VOTELIST] = CreateMultiForward("mapm_can_be_in_votelist", ET_CONTINUE, FP_STRING, FP_CELL, FP_CELL); 145 | g_hForwards[CAN_BE_EXTENDED] = CreateMultiForward("mapm_can_be_extended", ET_CONTINUE, FP_CELL); 146 | g_hForwards[COUNTDOWN] = CreateMultiForward("mapm_countdown", ET_IGNORE, FP_CELL, FP_CELL); 147 | g_hForwards[DISPLAYED_ITEM_NAME] = CreateMultiForward("mapm_displayed_item_name", ET_CONTINUE, FP_CELL, FP_CELL, FP_STRING); 148 | 149 | register_menucmd(register_menuid("VoteMenu"), 1023, "votemenu_handler"); 150 | 151 | register_dictionary("mapmanager.txt"); 152 | } 153 | 154 | public plugin_natives() 155 | { 156 | register_library("map_manager_core"); 157 | 158 | g_aMapsList = ArrayCreate(MapStruct, 1); 159 | get_mapname(g_sCurMap, charsmax(g_sCurMap)); 160 | 161 | g_aCustomItems = ArrayCreate(CustomItemStruct, 1); 162 | 163 | register_native("mapm_load_maplist", "native_load_maplist"); 164 | register_native("mapm_load_maplist_to_array", "native_load_maplist_to_array"); 165 | register_native("mapm_block_load_maplist", "native_block_load_maplist"); 166 | register_native("mapm_add_map_to_list", "native_add_map_to_list"); 167 | register_native("mapm_get_map_index", "native_get_map_index"); 168 | register_native("mapm_get_prefix", "native_get_prefix"); 169 | register_native("mapm_set_vote_finished", "native_set_vote_finished"); 170 | register_native("mapm_start_vote", "native_start_vote"); 171 | register_native("mapm_stop_vote", "native_stop_vote"); 172 | register_native("mapm_block_show_vote", "native_block_show_vote"); 173 | register_native("mapm_get_votelist_size", "native_get_votelist_size"); 174 | register_native("mapm_set_votelist_max_items", "native_set_votelist_max_items"); 175 | register_native("mapm_push_map_to_votelist", "native_push_map_to_votelist"); 176 | register_native("mapm_get_count_maps_in_vote", "native_get_count_maps_in_vote"); 177 | register_native("mapm_get_voteitem_info", "native_get_voteitem_info"); 178 | register_native("mapm_get_vote_type", "native_get_vote_type"); 179 | register_native("mapm_add_vote_to_item", "native_add_vote_to_item"); 180 | register_native("mapm_set_displayed_name", "native_set_displayed_name"); 181 | register_native("mapm_add_custom_item", "native_add_custom_item"); 182 | register_native("is_vote_started", "native_is_vote_started"); 183 | register_native("is_vote_finished", "native_is_vote_finished"); 184 | } 185 | public native_load_maplist(plugin, params) 186 | { 187 | enum { 188 | arg_filename = 1, 189 | arg_clearlist, 190 | arg_silent 191 | }; 192 | 193 | if(get_param(arg_clearlist)) { 194 | if(g_aMapsList == Invalid_Array) { 195 | set_fail_state("Clear empty Array. Don't use this navite before core load maplist."); 196 | return; 197 | } 198 | ArrayClear(g_aMapsList); 199 | new ret; 200 | ExecuteForward(g_hForwards[MAPLIST_UNLOADED], ret); 201 | } 202 | 203 | new filename[256]; 204 | get_string(arg_filename, filename, charsmax(filename)); 205 | load_maplist(g_aMapsList, filename, bool:get_param(arg_silent)); 206 | } 207 | public native_load_maplist_to_array(plugin, params) 208 | { 209 | enum { 210 | arg_array = 1, 211 | arg_filename 212 | }; 213 | 214 | new filename[256]; 215 | get_string(arg_filename, filename, charsmax(filename)); 216 | 217 | return load_maplist(Array:get_param(arg_array), filename, true); 218 | } 219 | public native_block_load_maplist(plugin, params) 220 | { 221 | g_bBlockLoad = true; 222 | } 223 | public native_add_map_to_list(plugin, params) 224 | { 225 | enum { 226 | arg_name = 1, 227 | arg_minplayers, 228 | arg_maxplayers, 229 | arg_priority 230 | }; 231 | 232 | new map_info[MapStruct]; 233 | get_string(arg_name, map_info[Map], charsmax(map_info[Map])); 234 | 235 | if(!valid_map(map_info[Map]) || get_map_index(g_aMapsList, map_info[Map]) != INVALID_MAP_INDEX) { 236 | return 0; 237 | } 238 | 239 | map_info[MinPlayers] = get_param(arg_minplayers); 240 | map_info[MaxPlayers] = get_param(arg_maxplayers); 241 | 242 | new priority = clamp(get_param(arg_priority), 0, 100); 243 | map_info[MapPriority] = priority ? priority : 100; 244 | 245 | ArrayPushArray(g_aMapsList, map_info); 246 | 247 | return 1; 248 | } 249 | public native_get_map_index(plugin, params) 250 | { 251 | enum { arg_map = 1 }; 252 | new map[MAPNAME_LENGTH]; get_string(arg_map, map, charsmax(map)); 253 | return get_map_index(g_aMapsList, map); 254 | } 255 | public native_get_prefix(plugin, params) 256 | { 257 | enum { 258 | arg_prefix = 1, 259 | arg_len 260 | }; 261 | set_string(arg_prefix, g_sPrefix, get_param(arg_len)); 262 | } 263 | public native_set_vote_finished(plugin, params) 264 | { 265 | enum { arg_value = 1 }; 266 | g_bVoteFinished = bool:get_param(arg_value); 267 | } 268 | public native_start_vote(plugin, params) 269 | { 270 | enum { arg_type = 1 }; 271 | return prepare_vote(get_param(arg_type)); 272 | } 273 | public native_stop_vote(plugin, params) 274 | { 275 | stop_vote(); 276 | } 277 | public native_block_show_vote(plugin, params) 278 | { 279 | g_bBlockShowVote = true; 280 | } 281 | public native_get_votelist_size(plugin, params) 282 | { 283 | if(g_iExternalMaxItems) { 284 | return g_iExternalMaxItems; 285 | } 286 | return min(min(get_num(VOTELIST_SIZE), MAX_VOTELIST_SIZE), ArraySize(g_aMapsList)); 287 | } 288 | public native_set_votelist_max_items(plugin, params) 289 | { 290 | enum { arg_value = 1 }; 291 | g_iExternalMaxItems = get_param(arg_value); 292 | } 293 | public native_push_map_to_votelist(plugin, params) 294 | { 295 | enum { 296 | arg_map = 1, 297 | arg_type, 298 | arg_ignore_check 299 | }; 300 | 301 | if(g_iExternalMaxItems && g_iVoteItems >= g_iExternalMaxItems) { 302 | return PUSH_CANCELED; 303 | } 304 | 305 | if(g_iVoteItems >= min(min(get_num(VOTELIST_SIZE), MAX_VOTELIST_SIZE), ArraySize(g_aMapsList))) { 306 | return PUSH_CANCELED; 307 | } 308 | 309 | new map[MAPNAME_LENGTH]; get_string(arg_map, map, charsmax(map)); 310 | 311 | new ignore_checks = get_param(arg_ignore_check); 312 | 313 | if(!(ignore_checks & CHECK_IGNORE_VALID_MAP) && !is_map_valid(map)) { 314 | return PUSH_CANCELED; 315 | } 316 | 317 | if(is_map_in_vote(map)) { 318 | return PUSH_BLOCKED; 319 | } 320 | 321 | if(!(ignore_checks & CHECK_IGNORE_MAP_ALLOWED) && !is_map_allowed(map, get_param(arg_type), get_map_index(g_aMapsList, map))) { 322 | return PUSH_BLOCKED; 323 | } 324 | 325 | new item_data[ItemStruct]; 326 | copy(item_data[is_name], charsmax(item_data[is_name]), map); 327 | item_data[is_type] = it_normal; 328 | 329 | ArrayInsertArrayAfter(g_aMenuItems, g_iPushPos++, item_data); 330 | 331 | g_iVoteItems++; 332 | 333 | return PUSH_SUCCESS; 334 | } 335 | public native_get_count_maps_in_vote(plugin, params) 336 | { 337 | return g_iPushPos - g_iStartPos + 1; 338 | } 339 | public native_get_voteitem_info(plugin, params) 340 | { 341 | enum { 342 | arg_item = 1, 343 | arg_map, 344 | arg_len 345 | }; 346 | 347 | new item = get_param(arg_item); 348 | 349 | if(item < 0 || item >= g_iPushPos - g_iStartPos + 1) { 350 | return 0; 351 | } 352 | 353 | item += g_iStartPos; 354 | 355 | new item_data[ItemStruct]; 356 | ArrayGetArray(g_aMenuItems, item, item_data); 357 | set_string(arg_map, item_data[is_name], get_param(arg_len)); 358 | 359 | return g_iVotes[item]; 360 | } 361 | public native_get_vote_type(plugin, params) 362 | { 363 | return g_iVoteType; 364 | } 365 | public native_add_vote_to_item(plugin, params) 366 | { 367 | enum { 368 | arg_item = 1, 369 | arg_value 370 | }; 371 | 372 | new item = get_param(arg_item); 373 | if(item < 0 || item >= g_iPushPos - g_iStartPos + 1) { 374 | return 0; 375 | } 376 | 377 | item += g_iStartPos; 378 | 379 | new value = get_param(arg_value); 380 | add_item_votes(item, value); 381 | 382 | return 1; 383 | } 384 | public native_set_displayed_name(plugin, params) 385 | { 386 | enum { 387 | arg_item = 1, 388 | arg_displayed_name 389 | } 390 | 391 | new item = get_param(arg_item); 392 | if(item < 0 || item >= ArraySize(g_aMenuItems)) { 393 | return 0; 394 | } 395 | 396 | new displayed_name[128]; 397 | get_string(arg_displayed_name, displayed_name, charsmax(displayed_name)); 398 | 399 | new item_data[ItemStruct]; 400 | ArrayGetArray(g_aMenuItems, item, item_data); 401 | copy(item_data[is_displayed_name], charsmax(item_data[is_displayed_name]), displayed_name); 402 | ArraySetArray(g_aMenuItems, item, item_data); 403 | 404 | return 0; 405 | } 406 | public native_add_custom_item(plugin, params) 407 | { 408 | enum { 409 | arg_type = 1, 410 | arg_name, 411 | arg_handler, 412 | arg_add_blank, 413 | arg_add_number 414 | } 415 | 416 | new custom_item[CustomItemStruct]; 417 | new handler[32]; 418 | get_string(arg_name, custom_item[ci_name], charsmax(custom_item[ci_name])); 419 | get_string(arg_handler, handler, charsmax(handler)); 420 | custom_item[ci_add_blank] = bool:get_param(arg_add_blank); 421 | custom_item[ci_add_number] = bool:get_param(arg_add_number); 422 | custom_item[ci_type] = MCI_Type:get_param(arg_type); 423 | 424 | if(custom_item[ci_add_number]) { 425 | custom_item[ci_handler] = CreateOneForward(plugin, handler, FP_CELL, FP_CELL); 426 | 427 | if(custom_item[ci_handler] == -1) { 428 | return -1; 429 | } 430 | } 431 | 432 | return ArrayPushArray(g_aCustomItems, custom_item); 433 | } 434 | public native_is_vote_started(plugin, params) 435 | { 436 | return g_bVoteStarted; 437 | } 438 | public native_is_vote_finished(plugin, params) 439 | { 440 | return g_bVoteFinished; 441 | } 442 | //-----------------------------------------------------// 443 | // Maplist stuff 444 | //-----------------------------------------------------// 445 | public plugin_cfg() 446 | { 447 | new configsdir[256]; get_localinfo("amxx_configsdir", configsdir, charsmax(configsdir)); 448 | server_cmd("exec %s/map_manager.cfg", configsdir); 449 | server_exec(); 450 | 451 | get_pcvar_string(g_pCvars[PREFIX], g_sPrefix, charsmax(g_sPrefix)); 452 | replace_color_tag(g_sPrefix, charsmax(g_sPrefix)); 453 | 454 | // add forward for change file? 455 | if(!g_bBlockLoad) { 456 | load_maplist(g_aMapsList, FILE_MAPS); 457 | } 458 | } 459 | load_maplist(Array:array, const file[], bool:silent = false) 460 | { 461 | new file_path[256]; get_localinfo("amxx_configsdir", file_path, charsmax(file_path)); 462 | format(file_path, charsmax(file_path), "%s/%s", file_path, file); 463 | 464 | if(!file_exists(file_path)) { 465 | if(!silent) { 466 | new error[192]; formatex(error, charsmax(error), "File doesn't exist ^"%s^".", file_path); 467 | set_fail_state(error); 468 | } 469 | return 0; 470 | } 471 | 472 | new f = fopen(file_path, "rt"); 473 | 474 | if(!f) { 475 | if(!silent) { 476 | set_fail_state("Can't read maps file."); 477 | } 478 | return 0; 479 | } 480 | 481 | new map_info[MapStruct], text[48], map[MAPNAME_LENGTH], next_map[MAPNAME_LENGTH], min[3], max[3], priority[4], bool:found_nextmap; 482 | 483 | while(!feof(f)) { 484 | fgets(f, text, charsmax(text)); 485 | parse(text, map, charsmax(map), min, charsmax(min), max, charsmax(max), priority, charsmax(priority)); 486 | 487 | if(!map[0] || map[0] == ';' || !valid_map(map) || get_map_index(array, map) != INVALID_MAP_INDEX) continue; 488 | 489 | if(!next_map[0]) { 490 | copy(next_map, charsmax(next_map), map); 491 | } 492 | 493 | map_info[Map] = map; 494 | map_info[MinPlayers] = str_to_num(min); 495 | map_info[MaxPlayers] = str_to_num(max) == 0 ? 32 : str_to_num(max); 496 | map_info[MapPriority] = str_to_num(priority) == 0 ? 100 : str_to_num(priority); 497 | 498 | ArrayPushArray(array, map_info); 499 | min = ""; max = ""; priority = ""; 500 | 501 | if(equali(map, g_sCurMap)) { 502 | found_nextmap = true; 503 | continue; 504 | } 505 | if(found_nextmap) { 506 | found_nextmap = false; 507 | copy(next_map, charsmax(next_map), map); 508 | } 509 | } 510 | fclose(f); 511 | 512 | if(!ArraySize(array)) { 513 | if(!silent) { 514 | new error[192]; formatex(error, charsmax(error), "Nothing loaded from ^"%s^".", file_path); 515 | set_fail_state(error); 516 | } 517 | return 0; 518 | } 519 | 520 | if(!silent) { 521 | new ret; 522 | ExecuteForward(g_hForwards[MAPLIST_LOADED], ret, array, next_map); 523 | } 524 | 525 | return 1; 526 | } 527 | //-----------------------------------------------------// 528 | // Vote stuff 529 | //-----------------------------------------------------// 530 | prepare_vote(type) 531 | { 532 | if(g_bVoteStarted) { 533 | return 0; 534 | } 535 | 536 | g_bVoteStarted = true; 537 | g_bVoteFinished = false; 538 | 539 | g_iVoteType = type; 540 | 541 | g_iVoteItems = 0; 542 | g_iTotalVotes = 0; 543 | arrayset(g_iVoted, NOT_VOTED, sizeof(g_iVoted)); 544 | arrayset(g_iVotes, 0, sizeof(g_iVotes)); 545 | 546 | new array_size = ArraySize(g_aMapsList); 547 | new is_current_map_in_array = get_map_index(g_aMapsList, g_sCurMap) != INVALID_MAP_INDEX; 548 | new vote_max_items = min(min(get_num(VOTELIST_SIZE), MAX_VOTELIST_SIZE), array_size - is_current_map_in_array); 549 | 550 | if(g_aMenuItems != Invalid_Array) { 551 | ArrayClear(g_aMenuItems); 552 | } else { 553 | g_aMenuItems = ArrayCreate(ItemStruct, 0); 554 | } 555 | 556 | new item_data[ItemStruct]; 557 | // push pre custom items 558 | g_iStartPos = (g_iPushPos = push_custom_items()) + 1; 559 | 560 | // push from addons 561 | new ret; 562 | ExecuteForward(g_hForwards[PREPARE_VOTELIST], ret, type); 563 | 564 | if(ret) { 565 | return 0; 566 | } 567 | 568 | if(g_iExternalMaxItems) { 569 | vote_max_items = g_iExternalMaxItems; 570 | g_iExternalMaxItems = 0; 571 | } 572 | 573 | // push from core 574 | if(!get_num(ONLY_EXTERNAL_VOTE_ITEMS) && g_iVoteItems < vote_max_items) { 575 | new map_info[MapStruct]; 576 | for(new random_map; g_iVoteItems < vote_max_items; g_iVoteItems++) { 577 | do { 578 | random_map = random_num(0, array_size - 1); 579 | ArrayGetArray(g_aMapsList, random_map, map_info); 580 | } while(is_map_in_vote(map_info[Map]) || !is_map_allowed(map_info[Map], PUSH_BY_CORE, random_map) || equali(map_info[Map], g_sCurMap)); 581 | 582 | copy(item_data[is_name], charsmax(item_data[is_name]), map_info[Map]); 583 | item_data[is_type] = it_normal; 584 | 585 | ArrayInsertArrayAfter(g_aMenuItems, g_iPushPos++, item_data); 586 | } 587 | } 588 | 589 | if(!g_iVoteItems) { 590 | log_amx("Started vote with ZERO items. Check your maps list!"); 591 | } 592 | 593 | // push current map 594 | ExecuteForward(g_hForwards[CAN_BE_EXTENDED], ret, type); 595 | g_bCanExtend = !ret; 596 | 597 | if(g_bCanExtend) { 598 | copy(item_data[is_name], charsmax(item_data[is_name]), g_sCurMap); 599 | item_data[is_type] = it_normal; 600 | 601 | ArrayInsertArrayAfter(g_aMenuItems, g_iPushPos++, item_data); 602 | } 603 | 604 | g_iCurMap = -1; 605 | 606 | for(new i = g_iStartPos; i <= g_iPushPos; i++) { 607 | ArrayGetArray(g_aMenuItems, i, item_data); 608 | if(equali(g_sCurMap, item_data[is_name])) { 609 | g_iCurMap = i; 610 | break; 611 | } 612 | } 613 | 614 | while(ArraySize(g_aMenuItems) > MAX_VOTELIST_SIZE) { 615 | log_amx("WARNING: Check your settings. You have more custom items than can add to vote. (Deleted %d)", ArraySize(g_aMenuItems) - 1); 616 | ArrayDeleteItem(g_aMenuItems, ArraySize(g_aMenuItems) - 1); 617 | } 618 | 619 | new size = ArraySize(g_aMenuItems); 620 | 621 | if(get_num(RANDOM_NUMS)) { 622 | arrayset(g_iRandomNums, -1, sizeof(g_iRandomNums)); 623 | for(new i; i < size; i++) { 624 | do { 625 | g_iRandomNums[i] = random_num(0, size - 1); 626 | } while(in_array(i, g_iRandomNums[i])); 627 | } 628 | } else { 629 | for(new i; i < size; i++) { 630 | g_iRandomNums[i] = i; 631 | } 632 | } 633 | 634 | g_iOffset = get_num(VOTE_ITEM_OFFSET); 635 | 636 | if(g_iOffset + size >= MAX_VOTELIST_SIZE) { 637 | g_iOffset = MAX_VOTELIST_SIZE - size; 638 | } 639 | 640 | // displayed name 641 | for(new i; i < size; i++) { 642 | ArrayGetArray(g_aMenuItems, i, item_data); 643 | ExecuteForward(g_hForwards[DISPLAYED_ITEM_NAME], ret, type, i, item_data[is_name]); 644 | } 645 | 646 | // start vote 647 | g_iTimer = get_num(PREPARE_TIME) + 1; 648 | countdown(TASK_PREPARE_VOTE); 649 | 650 | return 1; 651 | } 652 | push_custom_items() 653 | { 654 | new item_data[ItemStruct]; 655 | new custom_item[CustomItemStruct]; 656 | new size = ArraySize(g_aCustomItems); 657 | new pre_items = -1; 658 | 659 | for(new i; i < size; i++) { 660 | ArrayGetArray(g_aCustomItems, i, custom_item); 661 | copy(item_data[is_name], charsmax(item_data[is_name]), custom_item[ci_name]); 662 | item_data[is_type] = it_custom; 663 | item_data[is_custom_index] = i; 664 | 665 | if(custom_item[ci_type] == mci_before) { 666 | ArrayInsertArrayAfter(g_aMenuItems, pre_items, item_data); 667 | pre_items++; 668 | } else { 669 | ArrayPushArray(g_aMenuItems, item_data); 670 | } 671 | } 672 | 673 | return pre_items; 674 | } 675 | is_map_allowed(map[], type, index) 676 | { 677 | new ret; 678 | ExecuteForward(g_hForwards[CAN_BE_IN_VOTELIST], ret, map, type, index); 679 | return ret == MAP_ALLOWED; 680 | } 681 | in_array(index, num) 682 | { 683 | for(new i; i < index; i++) { 684 | if(num == g_iRandomNums[i]) { 685 | return true; 686 | } 687 | } 688 | return false; 689 | } 690 | get_original_num(num) 691 | { 692 | for(new i, size = ArraySize(g_aMenuItems); i < size; i++) { 693 | if(g_iRandomNums[i] == num) { 694 | return i; 695 | } 696 | } 697 | return 0; 698 | } 699 | public countdown(taskid) 700 | { 701 | if(--g_iTimer > 0) { 702 | if(taskid == TASK_VOTE_TIME && !g_bBlockShowVote) { 703 | new dont_show_result = get_num(SHOW_RESULT_TYPE) == SHOW_DISABLED; 704 | g_iShowType = get_num(SHOW_RESULT_TYPE); 705 | g_iShowPercent = get_num(SHOW_PERCENT); 706 | g_bShowSelects = get_num(SHOW_SELECTS); 707 | 708 | new players[32]; get_players(players, g_iPlayersNum, "ch"); 709 | for(new i, id; i < g_iPlayersNum; i++) { 710 | id = players[i]; 711 | if(!dont_show_result || g_iVoted[id] == NOT_VOTED) { 712 | show_votemenu(id); 713 | } 714 | } 715 | } 716 | 717 | new type = COUNTDOWN_UNKNOWN; 718 | switch(taskid) { 719 | case TASK_PREPARE_VOTE: type = COUNTDOWN_PREPARE; 720 | case TASK_VOTE_TIME: type = COUNTDOWN_VOTETIME; 721 | } 722 | new ret; 723 | ExecuteForward(g_hForwards[COUNTDOWN], ret, type, g_iTimer); 724 | 725 | set_task(1.0, "countdown", taskid); 726 | } else { 727 | if(taskid == TASK_PREPARE_VOTE) { 728 | start_vote(); 729 | } else if(taskid == TASK_VOTE_TIME) { 730 | show_menu(0, 0, "^n", 1); 731 | finish_vote(); 732 | } 733 | } 734 | } 735 | start_vote() 736 | { 737 | // server_print("--start vote--"); 738 | 739 | new ret; 740 | ExecuteForward(g_hForwards[VOTE_STARTED], ret, g_iVoteType); 741 | 742 | // TODO: add preview for N seconds 743 | 744 | g_iTimer = get_num(VOTE_TIME) + 1; 745 | countdown(TASK_VOTE_TIME); 746 | } 747 | public show_votemenu(id) 748 | { 749 | static menu[512]; 750 | new len, keys, percent, item; 751 | 752 | len = formatex(menu, charsmax(menu), "\y%L:^n^n", id, g_iVoted[id] != NOT_VOTED ? "MAPM_MENU_VOTE_RESULTS" : "MAPM_MENU_CHOOSE_MAP"); 753 | 754 | new item_data[ItemStruct], custom_item_data[CustomItemStruct]; 755 | 756 | for(new i, size = ArraySize(g_aMenuItems); i < size; i++) { 757 | if(g_bCanExtend && i == g_iPushPos) { 758 | len += formatex(menu[len], charsmax(menu) - len, "^n"); 759 | } 760 | 761 | ArrayGetArray(g_aMenuItems, i, item_data); 762 | if(item_data[is_type] == it_custom) { 763 | ArrayGetArray(g_aCustomItems, item_data[is_custom_index], custom_item_data); 764 | 765 | if(custom_item_data[ci_add_blank]) { 766 | len += formatex(menu[len], charsmax(menu) - len, "^n"); 767 | } 768 | } 769 | 770 | if(g_iVoted[id] == NOT_VOTED && item_data[is_type] == it_normal 771 | || item_data[is_type] == it_custom && custom_item_data[ci_add_number]) { 772 | len += formatex(menu[len], charsmax(menu) - len, "\r%d.\w ", (g_iRandomNums[item] + 1 + g_iOffset == 10 ? 0 : g_iRandomNums[item] + 1 + g_iOffset)); 773 | keys |= (1 << (g_iRandomNums[item] + g_iOffset)); 774 | g_iKeyToIndex[item] = i; 775 | item++; 776 | } else { 777 | len += formatex(menu[len], charsmax(menu) - len, "%s", (i == g_iVoted[id]) ? "\r" : "\d"); 778 | 779 | if(item_data[is_type] == it_normal) { 780 | item++; 781 | } 782 | } 783 | 784 | if(item_data[is_displayed_name][0]) { 785 | len += formatex(menu[len], charsmax(menu) - len, "%s", item_data[is_displayed_name]); 786 | } else { 787 | len += formatex(menu[len], charsmax(menu) - len, "%s", item_data[is_name]); 788 | } 789 | 790 | if(item_data[is_type] == it_normal && (g_iShowPercent == PERCENT_ALWAYS || g_iVoted[id] != NOT_VOTED && g_iShowPercent == PERCENT_AFTER_VOTE)) { 791 | percent = g_iTotalVotes ? floatround(g_iVotes[i] * 100.0 / g_iTotalVotes) : 0; 792 | len += formatex(menu[len], charsmax(menu) - len, "\d[\r%d%%\d]", percent); 793 | } 794 | 795 | if(i == g_iCurMap) { 796 | len += formatex(menu[len], charsmax(menu) - len, "\y[%L]", id, "MAPM_MENU_EXTEND"); 797 | } 798 | 799 | len += formatex(menu[len], charsmax(menu) - len, "^n"); 800 | } 801 | 802 | len += formatex(menu[len], charsmax(menu) - len, "^n\d%L \r%d\d %L", id, "MAPM_MENU_LEFT", g_iTimer, id, "MAPM_SECONDS"); 803 | 804 | if(!keys) keys = (1 << 9); 805 | 806 | if(g_iVoted[id] != NOT_VOTED && g_iShowType == SHOW_HUD) { 807 | while(replace(menu, charsmax(menu), "\r", "")){} 808 | while(replace(menu, charsmax(menu), "\d", "")){} 809 | while(replace(menu, charsmax(menu), "\w", "")){} 810 | while(replace(menu, charsmax(menu), "\y", "")){} 811 | 812 | set_hudmessage(0, 55, 255, 0.02, -1.0, 0, 6.0, 1.0, 0.1, 0.2, 4); 813 | show_hudmessage(id, "%s", menu); 814 | } else { 815 | show_menu(id, keys, menu, -1, "VoteMenu"); 816 | } 817 | } 818 | public votemenu_handler(id, key) 819 | { 820 | new original = get_original_num(key - g_iOffset); 821 | 822 | new item = g_iKeyToIndex[original]; 823 | new item_data[ItemStruct], custom_item_data[CustomItemStruct]; 824 | ArrayGetArray(g_aMenuItems, item, item_data); 825 | 826 | // custom items 827 | if(item_data[is_type] == it_custom) { 828 | ArrayGetArray(g_aCustomItems, item_data[is_custom_index], custom_item_data); 829 | 830 | new ret; 831 | ExecuteForward(custom_item_data[ci_handler], ret, id, item_data[is_custom_index]); 832 | 833 | show_votemenu(id); 834 | return PLUGIN_HANDLED; 835 | } 836 | 837 | if(g_iVoted[id] != NOT_VOTED) { 838 | show_votemenu(id); 839 | return PLUGIN_HANDLED; 840 | } 841 | 842 | add_item_votes(item, 1); 843 | 844 | g_iVoted[id] = item; 845 | 846 | if(g_bShowSelects) { 847 | new name[32]; get_user_name(id, name, charsmax(name)); 848 | if(item == g_iCurMap) { 849 | client_print_color(0, id, "%s^3 %L", g_sPrefix, LANG_PLAYER, "MAPM_CHOSE_EXTEND", name); 850 | } else { 851 | client_print_color(0, id, "%s^3 %L", g_sPrefix, LANG_PLAYER, "MAPM_CHOSE_MAP", name, item_data[is_name]); 852 | } 853 | } 854 | 855 | if(g_iShowType != SHOW_DISABLED) { 856 | show_votemenu(id); 857 | } 858 | 859 | return PLUGIN_HANDLED; 860 | } 861 | add_item_votes(item, value) 862 | { 863 | // TODO: add forward if someone want add more votes for admin, etc. 864 | 865 | g_iVotes[item] += value; 866 | g_iTotalVotes += value; 867 | 868 | if(get_num(EARLY_FINISH_VOTE) && g_iTotalVotes == g_iPlayersNum) { 869 | g_iTimer = 0; 870 | client_print_color(0, print_team_default, "%s^1 %L", g_sPrefix, LANG_PLAYER, "MAPM_EARLY_FINISH_VOTE"); 871 | } 872 | } 873 | finish_vote() 874 | { 875 | g_bVoteStarted = false; 876 | g_bBlockShowVote = false; 877 | 878 | // vote results 879 | 880 | // pre forward 881 | new ret; 882 | ExecuteForward(g_hForwards[ANALYSIS_OF_RESULTS], ret, g_iVoteType, g_iTotalVotes); 883 | 884 | if(ret) { 885 | if(ret == ABORT_VOTE_WITH_FORWARD) { 886 | ExecuteForward(g_hForwards[VOTE_CANCELED], ret, g_iVoteType); 887 | } 888 | return; 889 | } 890 | 891 | g_bVoteFinished = true; 892 | 893 | new max_vote = g_iStartPos; 894 | if(g_iTotalVotes) { 895 | for(new i = g_iStartPos; i <= g_iPushPos; i++) { 896 | if(random_num(0, 99) >= 50) { 897 | if(g_iVotes[max_vote] < g_iVotes[i]) max_vote = i; 898 | } else { 899 | if(g_iVotes[max_vote] <= g_iVotes[i]) max_vote = i; 900 | } 901 | } 902 | } 903 | else { 904 | max_vote = random_num(g_iStartPos, g_iPushPos); 905 | } 906 | 907 | new item_data[ItemStruct]; 908 | ArrayGetArray(g_aMenuItems, max_vote, item_data); 909 | // post forward 910 | // add blocking? 911 | ExecuteForward(g_hForwards[VOTE_FINISHED], ret, item_data[is_name], g_iVoteType, g_iTotalVotes); 912 | } 913 | 914 | stop_vote() 915 | { 916 | if(task_exists(TASK_VOTE_TIME)) { 917 | show_menu(0, 0, "^n", 1); 918 | } 919 | 920 | remove_task(TASK_PREPARE_VOTE); 921 | remove_task(TASK_VOTE_TIME); 922 | 923 | g_bVoteStarted = false; 924 | g_bVoteFinished = false; 925 | 926 | new ret; 927 | ExecuteForward(g_hForwards[VOTE_CANCELED], ret, g_iVoteType); 928 | } 929 | 930 | //-----------------------------------------------------// 931 | // Usefull func 932 | //-----------------------------------------------------// 933 | get_map_index(Array:array, map[]) 934 | { 935 | for(new i = 0, map_info[MapStruct], size = ArraySize(array); i < size; i++) { 936 | ArrayGetArray(array, i, map_info); 937 | if(equali(map, map_info[Map])) return i; 938 | } 939 | return INVALID_MAP_INDEX; 940 | } 941 | bool:is_map_in_vote(map[]) 942 | { 943 | new item_data[ItemStruct]; 944 | 945 | for(new i, size = ArraySize(g_aMenuItems); i < size; i++) { 946 | ArrayGetArray(g_aMenuItems, i, item_data); 947 | if(equali(map, item_data[is_name])) { 948 | return true; 949 | } 950 | } 951 | return false; 952 | } 953 | --------------------------------------------------------------------------------