diff --git a/mapchooser_extended/scripting/mapchooser_extended_unloze.sp b/mapchooser_extended/scripting/mapchooser_extended_unloze.sp index 41fd971..b28e6e7 100755 --- a/mapchooser_extended/scripting/mapchooser_extended_unloze.sp +++ b/mapchooser_extended/scripting/mapchooser_extended_unloze.sp @@ -147,6 +147,9 @@ int g_mapFileSerial = -1; int g_iSkipAllRestrictions; int g_iDontCooldownMap; int g_iMapsFromCasualPool; +int g_iImpactExtraCooldownTime; + +float g_avg_net_change; int g_iInterval; char player_mapvote[MAXPLAYERS + 1][PLATFORM_MAX_PATH]; @@ -298,6 +301,11 @@ public void OnPluginStart() g_bCasualPoolFromImpactPlayTime = cvar2_.BoolValue; delete cvar2_; + ConVar cvar2_1; + HookConVarChange((cvar2_1 = CreateConVar("mce_impact_extra_cooldown_addition", "100", "How much additional cooldowntime do we apply for negative impact rate. 0 disables the feature.")), Cvar_impact_extra_cooldown); + g_iImpactExtraCooldownTime = cvar2_1.IntValue; + delete cvar2_1; + ConVar cvar1; HookConVarChange((cvar1 = CreateConVar("mce_skip_map_restrictions_player_count", "15", "Amount of players required for any restrictions are enabled.")), Cvar_playerActiveRequired); g_iSkipAllRestrictions = cvar1.IntValue; @@ -330,7 +338,7 @@ public void OnPluginStart() g_Cvar_NoRestrictionTimeframeEnable = CreateConVar("mce_no_restriction_timeframe_enable", "1", "Enable timeframe where all nomination restrictions and cooldowns are disabled?", _, true, 0.0, true, 1.0); g_Cvar_NoRestrictionTimeframeMinTime = CreateConVar("mce_no_restriction_timeframe_mintime", "0100", "Start of the timeframe where all nomination restrictions and cooldowns are disabled (Format: HHMM)", _, true, 0000.0, true, 2359.0); g_Cvar_NoRestrictionTimeframeMaxTime = CreateConVar("mce_no_restriction_timeframe_maxtime", "0700", "End of the timeframe where all nomination restrictions and cooldowns are disabled (Format: HHMM)", _, true, 0000.0, true, 2359.0); - g_Cvar_MultipleNominationsTier = CreateConVar("mce_multiple_nominations_tier", "3", "Tier required for having multiple nominations available."); + g_Cvar_MultipleNominationsTier = CreateConVar("mce_multiple_nominations_tier", "8", "Tier required for having multiple nominations available."); RegAdminCmd("sm_mapvote", Command_Mapvote, ADMFLAG_CHANGEMAP, "sm_mapvote - Forces MapChooser to attempt to run a map vote now."); RegAdminCmd("sm_setnextmap", Command_SetNextmap, ADMFLAG_CHANGEMAP, "sm_setnextmap "); @@ -439,8 +447,8 @@ public void OnPluginStart() g_first_map_no_cooldown = true; - int total_time = (GetConVarInt(g_Cvar_VoteDuration) * 2) + GetConVarInt(g_Cvar_RunOffWarningTime) + 10; - ServerCommand("sm_cvar mp_chattime %i", total_time); //prevents map switching supposedly. + //int total_time = (GetConVarInt(g_Cvar_VoteDuration) * 2) + GetConVarInt(g_Cvar_RunOffWarningTime) + 10; + //ServerCommand("sm_cvar mp_chattime %i", total_time); //prevents map switching supposedly. } public void Cvar_mapsFromCasualPool(ConVar convar, const char[] oldValue, const char[] newValue) @@ -448,6 +456,11 @@ public void Cvar_mapsFromCasualPool(ConVar convar, const char[] oldValue, const g_iMapsFromCasualPool = convar.IntValue; } +public void Cvar_impact_extra_cooldown(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_iImpactExtraCooldownTime = convar.IntValue; +} + public void Cvar_casual_pool_impact_enabled(ConVar convar, const char[] oldValue, const char[] newValue) { g_bCasualPoolFromImpactPlayTime = convar.BoolValue; @@ -529,8 +542,9 @@ public void OnMapStart() g_iNextmapState = 0; CreateTimer(1.0, GetInternalGetCvars); - int total_time = (GetConVarInt(g_Cvar_VoteDuration) * 2) + GetConVarInt(g_Cvar_RunOffWarningTime) + 10; - ServerCommand("sm_cvar mp_chattime %i", total_time); //prevents map switching supposedly. + //int total_time = (GetConVarInt(g_Cvar_VoteDuration) * 2) + GetConVarInt(g_Cvar_RunOffWarningTime) + 10; + //ServerCommand("sm_cvar mp_chattime %i", total_time); //prevents map switching supposedly. + g_iInterval = 0; static char folder[64]; GetGameFolderName(folder, sizeof(folder)); @@ -569,14 +583,31 @@ public void OnMapStart() return; } g_Config.Rewind(); + FillMapsByImpact(0); - char sRequest[256]; - FormatEx(sRequest, sizeof(sRequest), "https://playtime-sessions.unloze.com/api/maps/impact?sortBy=impact&direction=desc&offset=0"); - HTTPRequest hRequest = new HTTPRequest(sRequest); - hRequest.Get(OnTransferComplete, _); + char currentmap[256]; + GetCurrentMap(currentmap, PLATFORM_MAX_PATH); + g_avg_net_change = 0.0; + GetMapsImpact(currentmap); } -public void OnTransferComplete(HTTPResponse response, any s) +public void GetMapsImpact(char[] currentmap) +{ + char sRequest[512]; + FormatEx(sRequest, sizeof(sRequest), "https://playtime-sessions.unloze.com/api/maps/impact?mapName=%s", currentmap); + HTTPRequest hRequest = new HTTPRequest(sRequest); + hRequest.Get(OnTransferComplete1, _); +} + +public void FillMapsByImpact(int offset) +{ + char sRequest[256]; + FormatEx(sRequest, sizeof(sRequest), "https://playtime-sessions.unloze.com/api/maps/impact?sortBy=impact&direction=desc&offset=%i", offset); + HTTPRequest hRequest = new HTTPRequest(sRequest); + hRequest.Get(OnTransferComplete, offset); +} + +public void OnTransferComplete(HTTPResponse response, int offset) { if (response.Status != HTTPStatus_OK || response.Data == null) { @@ -594,8 +625,11 @@ public void OnTransferComplete(HTTPResponse response, any s) } ClearArray(g_hTopImpactMaps); + Handle tempMaps = CloneArray(g_MapList); + int count = maps.Length; char mapName[PLATFORM_MAX_PATH]; + int maps_added = 0; for (int i = 0; i < count; i++) { JSONObject entry = view_as(maps.Get(i)); @@ -604,10 +638,46 @@ public void OnTransferComplete(HTTPResponse response, any s) continue; } entry.GetString("map_name", mapName, sizeof(mapName)); - PushArrayString(g_hTopImpactMaps, mapName); + //make sure that the map actually is in the map pool and not admin only or deleted from the server again + if (FindStringInArray(tempMaps, mapName) != -1) + { + PushArrayString(g_hTopImpactMaps, mapName); + maps_added++; + } delete entry; } + delete tempMaps; + delete root; + delete maps; + if (maps_added < 45) + { + FillMapsByImpact(offset + 50); //did not get enough maps from the public maplist, set offset to pick the next. + } +} + +public void OnTransferComplete1(HTTPResponse response, any i) +{ + if (response.Status != HTTPStatus_OK || response.Data == null) + { + LogError("Request-Error: %d", response.Status); + return; + } + + JSONObject root = view_as(response.Data); + JSONArray maps = view_as(root.Get("maps")); + if (maps == null) + { + delete root; + return; + } + + JSONObject entry = view_as(maps.Get(0)); + if (entry != null) + { + g_avg_net_change = entry.GetFloat("avg_net_change"); + } + delete entry; delete root; delete maps; } @@ -698,8 +768,8 @@ public void OnMapEnd() { g_first_map_no_cooldown = false; g_iNextmapState = 0; - int total_time = (GetConVarInt(g_Cvar_VoteDuration) * 2) + GetConVarInt(g_Cvar_RunOffWarningTime) + 10; - ServerCommand("sm_cvar mp_chattime %i", total_time); + //int total_time = (GetConVarInt(g_Cvar_VoteDuration) * 2) + GetConVarInt(g_Cvar_RunOffWarningTime) + 10; + //ServerCommand("sm_cvar mp_chattime %i", total_time); g_iInterval = 0; g_HasVoteStarted = false; @@ -712,22 +782,20 @@ public void OnMapEnd() g_WarningTimer = INVALID_HANDLE; g_RunoffCount = 0; - static char map[PLATFORM_MAX_PATH]; - GetCurrentMap(map, PLATFORM_MAX_PATH); - int Cooldown = InternalGetMapCooldown(map); - //resetting all again so they are added again onmapstart StringMapSnapshot CooldownList = g_CooldownList.Snapshot(); for(int i = 0; i < CooldownList.Length; i++) { + char map[PLATFORM_MAX_PATH]; CooldownList.GetKey(i, map, sizeof(map)); g_CooldownList.Remove(map); } - StringMapSnapshot OldMapListSnapshot = g_OldMapList.Snapshot(); for(int i = 0; i < OldMapListSnapshot.Length; i++) { + char map[PLATFORM_MAX_PATH]; + int Cooldown = 0; OldMapListSnapshot.GetKey(i, map, sizeof(map)); g_OldMapList.GetValue(map, Cooldown); @@ -737,21 +805,21 @@ public void OnMapEnd() else g_OldMapList.Remove(map); } - delete OldMapListSnapshot; StringMapSnapshot TimeMapListSnapshot = g_TimeMapList.Snapshot(); - Cooldown = GetTime() + InternalGetMapCooldownTime(map) - RoundToFloor(GetGameTime()); for(int i = 0; i < TimeMapListSnapshot.Length; i++) { + char map[PLATFORM_MAX_PATH]; + int Cooldown = 0; TimeMapListSnapshot.GetKey(i, map, sizeof(map)); g_TimeMapList.GetValue(map, Cooldown); if(Cooldown < GetTime()) g_TimeMapList.Remove(map); } - delete TimeMapListSnapshot; delete OldMapListSnapshot; + delete TimeMapListSnapshot; InternalStoreMapCooldowns(); } @@ -1025,6 +1093,9 @@ public Action CS_OnTerminateRound(float &delay, CSRoundEndReason &reason) g_OldMapList.SetValue(map, Cooldown, true); Cooldown = GetTime() + InternalGetMapCooldownTime(map) - RoundToFloor(GetGameTime()); + + //set extra cooldowntime for the map based on the playtime frontend impact for average population loss + Cooldown += additionalCooldownHoursCurrentMap(); g_TimeMapList.SetValue(map, Cooldown, true); //2026 march 18th: set cooldown on all maps that share a cooldown with this one including itself. SetSharedCooldowns(map); @@ -3235,6 +3306,20 @@ stock int InternalGetMapCooldownTime(const char[] map) return Cooldown; } +public int additionalCooldownHoursCurrentMap() +{ + int Cooldown = 0; + //0 == g_iImpactExtraCooldownTime means feature was disabled, so not adding any extra cooldown hours. + // g_avg_net_change < 0 means the map on average has a negative impact on player population + if (g_avg_net_change < 0 && g_iImpactExtraCooldownTime > 0) + { + //map has a negative impact on population and should be punished by additioanl g_iImpactExtraCooldownTime hours. + int extraCooldownHours = RoundToFloor((g_avg_net_change * -1) * g_iImpactExtraCooldownTime); + Cooldown += extraCooldownHours * 60 * 60; //Hours -> minutes -> seconds + } + return Cooldown; +} + stock int InternalGetMapMinTime(const char[] map) { int MinTime = 0; diff --git a/mapchooser_extended/scripting/nominations_extended_avg.sp b/mapchooser_extended/scripting/nominations_extended_avg.sp index 443c97e..4adcb53 100755 --- a/mapchooser_extended/scripting/nominations_extended_avg.sp +++ b/mapchooser_extended/scripting/nominations_extended_avg.sp @@ -560,8 +560,8 @@ public Action Command_Nominate(int client, int args) return Plugin_Handled; } - //July 2024 edit: any person who is potential leader can just skip all cooldowns and map restrictions. same for admins. - if(!CheckCommandAccess(client, "sm_nominate_ignore", ADMFLAG_KICK, true) && !Leader_Is(client)) + //October 2026: admins can just skip all cooldowns and map restrictions + if(!CheckCommandAccess(client, "sm_nominate_ignore", ADMFLAG_KICK, true) /* && !Leader_Is(client)*/ ) { bool RestrictionsActive = AreRestrictionsActive(); @@ -1158,7 +1158,7 @@ public int Handler_MapSelectMenu(Menu menu, MenuAction action, int param1, int p return 0; } - if (!CheckCommandAccess(param1, "sm_nominate_ignore", ADMFLAG_KICK, true) && !Leader_Is(param1)) + if (!CheckCommandAccess(param1, "sm_nominate_ignore", ADMFLAG_KICK, true) /*&& !Leader_Is(param1)*/ ) { if(AreRestrictionsActive() && ( GetMapCooldownTime(map) > GetTime() ||