mapvote 2.0.0

Added support for zombies mode.
Using the mapvote_maps dvar players can set a display name, the map name and the cfg name

Added mapvote_limits_maps dvar
Added mapvote_limits_modes dvar
Added mapvote_limits_max dvar
Users can now define maps and/or modes limits to have a precise amount of maps and/or modes on screen even if the available amount is above the max limit. The max limit is now 12 but can be lowered using a dvar

Changed right click listener wait time from 0.35s to 0.25s for a better user experience

Hide the map or mode when there's only one in the mapvote.
It will still rotate to it but it's hidden so that the menu looks cleaner. The menu is centered accordingly

Fixed the menu centering calculation, it's now really centered

Removed the need to write map names in a certain way to work, users can now write map names the way they want
This commit is contained in:
Resxt
2022-10-27 15:17:27 +02:00
parent 6e44160fc1
commit ff3e41c419
7 changed files with 614 additions and 152 deletions

View File

@ -45,8 +45,7 @@ InitMapvote()
}
else
{
// Starting the mapvote normally is handled in mp\mapvote_mp_extend.gsc
//replaceFunc(maps\mp\gametypes\_killcam::finalkillcamwaiter, ::OnKillcamEnd);
// Starting the mapvote normally is handled in mp\mapvote_mp_extend.gsc and zm\mapvote_zm_extend.gsc
}
}
@ -54,8 +53,21 @@ InitDvars()
{
SetDvarIfNotInitialized("mapvote_debug", false);
SetDvarIfNotInitialized("mapvote_maps", "Aftermath:Cargo:Carrier:Drone:Express:Hijacked:Meltdown:Overflow:Plaza:Raid:Slums:Standoff:Turbine:Yemen:Nuketown:Downhill:Mirage:Hydro:Grind:Encore:Magma:Vertigo:Studio:Uplink:Detour:Cove:Rush:Dig:Frost:Pod:Takeoff");
SetDvarIfNotInitialized("mapvote_modes", "Team Deathmatch,tdm:Domination,dom:Hardpoint,koth");
if (IsMultiplayerMode())
{
SetDvarIfNotInitialized("mapvote_maps", "Aftermath:Cargo:Carrier:Drone:Express:Hijacked:Meltdown:Overflow:Plaza:Raid:Slums:Standoff:Turbine:Yemen:Nuketown:Downhill:Mirage:Hydro:Grind:Encore:Magma:Vertigo:Studio:Uplink:Detour:Cove:Rush:Dig:Frost:Pod:Takeoff");
SetDvarIfNotInitialized("mapvote_modes", "Team Deathmatch,tdm:Domination,dom:Hardpoint,koth");
SetDvarIfNotInitialized("mapvote_limits_maps", 0);
SetDvarIfNotInitialized("mapvote_limits_modes", 0);
SetDvarIfNotInitialized("mapvote_sounds_menu_enabled", 1);
SetDvarIfNotInitialized("mapvote_sounds_timer_enabled", 1);
}
else
{
SetDvarIfNotInitialized("mapvote_maps", "Bus Depot,Bus Depot,zm_standard_transit:Town,Town,zm_standard_town:Farm,Farm,zm_standard_farm:Mob of The Dead,Mob of The Dead,zm_classic_prison:Nuketown,Nuketown,zm_standard_nuked:Origins,Origins,zm_classic_tomb:Buried,Buried,zm_classic_processing:Die Rise,Die Rise,zm_classic_rooftop");
}
SetDvarIfNotInitialized("mapvote_limits_max", 12);
SetDvarIfNotInitialized("mapvote_colors_selected", "blue");
SetDvarIfNotInitialized("mapvote_colors_unselected", "white");
SetDvarIfNotInitialized("mapvote_colors_timer", "blue");
@ -63,8 +75,6 @@ InitDvars()
SetDvarIfNotInitialized("mapvote_colors_help_text", "white");
SetDvarIfNotInitialized("mapvote_colors_help_accent", "blue");
SetDvarIfNotInitialized("mapvote_colors_help_accent_mode", "standard");
SetDvarIfNotInitialized("mapvote_sounds_menu_enabled", 1);
SetDvarIfNotInitialized("mapvote_sounds_timer_enabled", 1);
SetDvarIfNotInitialized("mapvote_vote_time", 30);
SetDvarIfNotInitialized("mapvote_blur_level", 2.5);
SetDvarIfNotInitialized("mapvote_blur_fade_in_time", 2);
@ -74,8 +84,51 @@ InitDvars()
InitVariables()
{
mapsArray = StrTok(GetDvar("mapvote_maps"), ":");
voteLimits = [];
if (IsMultiplayerMode())
{
modesArray = StrTok(GetDvar("mapvote_modes"), ":");
if (GetDvarInt("mapvote_limits_maps") == 0 && GetDvarInt("mapvote_limits_modes") == 0)
{
voteLimits = GetVoteLimits(mapsArray.size, modesArray.size);
}
else if (GetDvarInt("mapvote_limits_maps") > 0 && GetDvarInt("mapvote_limits_modes") == 0)
{
voteLimits = GetVoteLimits(GetDvarInt("mapvote_limits_maps"), modesArray.size);
}
else if (GetDvarInt("mapvote_limits_maps") == 0 && GetDvarInt("mapvote_limits_modes") > 0)
{
voteLimits = GetVoteLimits(mapsArray.size, GetDvarInt("mapvote_limits_modes"));
}
else
{
voteLimits = GetVoteLimits(GetDvarInt("mapvote_limits_maps"), GetDvarInt("mapvote_limits_modes"));
}
level.mapvote["limit"]["maps"] = voteLimits["maps"];
level.mapvote["limit"]["modes"] = voteLimits["modes"];
}
else
{
if (GetDvarInt("mapvote_limits_maps") == 0)
{
level.mapvote["limit"]["maps"] = GetVoteLimits(mapsArray.size);
}
else
{
level.mapvote["limit"]["maps"] = GetVoteLimits(GetDvarInt("mapvote_limits_maps"));
}
}
SetMapvoteData("map");
SetMapvoteData("mode");
if (IsMultiplayerMode())
{
SetMapvoteData("mode");
}
level.mapvote["vote"]["maps"] = [];
level.mapvote["vote"]["modes"] = [];
@ -90,7 +143,7 @@ InitVariables()
/*
This is used instead of notifyonplayercommand("mapvote_up", "speed_throw")
to fix an issue where players using toggle ads would have to press right click twice for it to register one right click.
With this instead it keeps scrolling every 0.35s until they right click again which is a better user experience
With this instead it keeps scrolling every 0.25s until they right click again which is a better user experience
*/
ListenForRightClick()
{
@ -101,7 +154,7 @@ ListenForRightClick()
if (self AdsButtonPressed())
{
self notify("mapvote_up");
wait 0.35;
wait 0.25;
}
wait 0.05;
@ -134,6 +187,10 @@ ListenForVoteInputs()
{
continue; // stop/skip execution
}
else if (section == "mode" && level.mapvote["modes"]["by_index"].size <= 1 && input != "mapvote_unselect" && input != "mapvote_debug")
{
continue; // stop/skip execution
}
if (input == "mapvote_down")
{
@ -192,16 +249,30 @@ ListenForVoteInputs()
}
else
{
Print(player.name + " voted for map [" + player.mapvote["map"]["selected_index"] +"] " + level.mapvote["maps"]["by_index"][player.mapvote["map"]["selected_index"]]);
mapName = "";
if (IsMultiplayerMode())
{
mapName = level.mapvote["maps"]["by_index"][player.mapvote["map"]["selected_index"]];
}
else
{
mapName = level.mapvote["maps"]["by_index"][player.mapvote["map"]["selected_index"]][0];
}
Print(player.name + " voted for map [" + player.mapvote["map"]["selected_index"] +"] " + mapName);
}
if (player.mapvote["mode"]["selected_index"] == -1)
if (IsMultiplayerMode())
{
Print(player.name + " did not vote for any mode");
}
else
{
Print(player.name + " voted for mode [" + player.mapvote["mode"]["selected_index"] + "] " + level.mapvote["modes"]["by_index"][player.mapvote["mode"]["selected_index"]]);
if (player.mapvote["mode"]["selected_index"] == -1)
{
Print(player.name + " did not vote for any mode");
}
else
{
Print(player.name + " voted for mode [" + player.mapvote["mode"]["selected_index"] + "] " + level.mapvote["modes"]["by_index"][player.mapvote["mode"]["selected_index"]]);
}
}
}
}
@ -217,7 +288,23 @@ ListenForVoteInputs()
CreateVoteMenu()
{
spacing = 20;
hudLastPosY = -(((level.mapvote["maps"]["by_index"].size + level.mapvote["modes"]["by_index"].size + 1) * spacing) / 2);
hudLastPosY = 0;
if (IsMultiplayerMode())
{
sectionsSeparation = 0;
if (level.mapvote["modes"]["by_index"].size > 1)
{
sectionsSeparation = 1;
}
hudLastPosY = -((((level.mapvote["maps"]["by_index"].size + level.mapvote["modes"]["by_index"].size + sectionsSeparation) * spacing) / 2) - (spacing / 2));
}
else
{
hudLastPosY = -(((level.mapvote["maps"]["by_index"].size * spacing) / 2) - (spacing / 2));
}
for (mapIndex = 0; mapIndex < level.mapvote["maps"]["by_index"].size; mapIndex++)
{
@ -228,7 +315,18 @@ CreateVoteMenu()
foreach (player in GetHumanPlayers())
{
player.mapvote["map"][mapIndex]["hud"] = player CreateHudText(level.mapvote["maps"]["by_index"][mapIndex], "objective", 1.5, "LEFT", "CENTER", -(GetDvarInt("mapvote_horizontal_spacing")), hudLastPosY);
mapName = "";
if (IsMultiplayerMode())
{
mapName = level.mapvote["maps"]["by_index"][mapIndex];
}
else
{
mapName = level.mapvote["maps"]["by_index"][mapIndex][0];
}
player.mapvote["map"][mapIndex]["hud"] = player CreateHudText(mapName, "objective", 1.5, "LEFT", "CENTER", -(GetDvarInt("mapvote_horizontal_spacing")), hudLastPosY);
if (mapIndex == 0)
{
@ -243,23 +341,26 @@ CreateVoteMenu()
hudLastPosY += spacing;
}
hudLastPosY += spacing; // Space between maps and modes sections
for (modeIndex = 0; modeIndex < level.mapvote["modes"]["by_index"].size; modeIndex++)
if (IsMultiplayerMode() && level.mapvote["modes"]["by_index"].size > 1)
{
modeVotesHud = CreateHudText("", "objective", 1.5, "LEFT", "CENTER", GetDvarInt("mapvote_horizontal_spacing"), hudLastPosY, true, 0);
modeVotesHud.color = GetGscColor(GetDvar("mapvote_colors_selected"));
hudLastPosY += spacing; // Space between maps and modes sections
level.mapvote["hud"]["modes"][modeIndex] = modeVotesHud;
foreach (player in GetHumanPlayers())
for (modeIndex = 0; modeIndex < level.mapvote["modes"]["by_index"].size; modeIndex++)
{
player.mapvote["mode"][modeIndex]["hud"] = player CreateHudText(level.mapvote["modes"]["by_index"][modeIndex], "objective", 1.5, "LEFT", "CENTER", -(GetDvarInt("mapvote_horizontal_spacing")), hudLastPosY);
modeVotesHud = CreateHudText("", "objective", 1.5, "LEFT", "CENTER", GetDvarInt("mapvote_horizontal_spacing"), hudLastPosY, true, 0);
modeVotesHud.color = GetGscColor(GetDvar("mapvote_colors_selected"));
SetElementUnselected(player.mapvote["mode"][modeIndex]["hud"]);
level.mapvote["hud"]["modes"][modeIndex] = modeVotesHud;
foreach (player in GetHumanPlayers())
{
player.mapvote["mode"][modeIndex]["hud"] = player CreateHudText(level.mapvote["modes"]["by_index"][modeIndex], "objective", 1.5, "LEFT", "CENTER", -(GetDvarInt("mapvote_horizontal_spacing")), hudLastPosY);
SetElementUnselected(player.mapvote["mode"][modeIndex]["hud"]);
}
hudLastPosY += spacing;
}
hudLastPosY += spacing;
}
foreach(player in GetHumanPlayers())
@ -326,9 +427,12 @@ StartVote()
level.mapvote["vote"]["maps"][i] = 0;
}
for (i = 0; i < level.mapvote["modes"]["by_index"].size; i++)
if (IsMultiplayerMode())
{
level.mapvote["vote"]["modes"][i] = 0;
for (i = 0; i < level.mapvote["modes"]["by_index"].size; i++)
{
level.mapvote["vote"]["modes"][i] = 0;
}
}
level thread CreateVoteMenu();
@ -405,10 +509,22 @@ ListenForEndVote()
}
}
modeName = level.mapvote["modes"]["by_index"][mostVotedModeIndex];
modeCfg = level.mapvote["modes"]["by_name"][level.mapvote["modes"]["by_index"][mostVotedModeIndex]];
mapName = GetMapCodeName(level.mapvote["maps"]["by_index"][mostVotedMapIndex]);
modeName = "";
modeCfg = "";
mapName = "";
if (IsMultiplayerMode())
{
modeName = level.mapvote["modes"]["by_index"][mostVotedModeIndex];
modeCfg = level.mapvote["modes"]["by_name"][level.mapvote["modes"]["by_index"][mostVotedModeIndex]];
mapName = GetMapCodeName(level.mapvote["maps"]["by_index"][mostVotedMapIndex]);
}
else
{
modeCfg = level.mapvote["maps"]["by_index"][mostVotedMapIndex][2];
mapName = GetMapCodeName(level.mapvote["maps"]["by_index"][mostVotedMapIndex][1]);
}
if (GetDvarInt("mapvote_debug"))
{
Print("[MAPVOTE] mapName: " + mapName);
@ -417,40 +533,42 @@ ListenForEndVote()
Print("[MAPVOTE] Rotating to " + mapName + " | " + modeName + " (" + modeCfg + ".cfg)");
}
setdvar("sv_maprotationcurrent", "exec " + modeCfg + ".cfg map " + mapName);
setdvar("sv_maprotation", "exec " + modeCfg + ".cfg map " + mapName);
SetDvar("sv_maprotationcurrent", "exec " + modeCfg + ".cfg map " + mapName);
SetDvar("sv_maprotation", "exec " + modeCfg + ".cfg map " + mapName);
}
SetMapvoteData(type)
{
limit = 0;
limit = level.mapvote["limit"][type + "s"];
availableElements = StrTok(GetDvar("mapvote_" + type + "s"), ":");
if (availableElements.size < limit)
{
limit = availableElements.size;
}
if (type == "map")
{
if (availableElements.size < 6)
if (IsMultiplayerMode())
{
limit = availableElements.size;
level.mapvote["maps"]["by_index"] = GetRandomUniqueElementsInArray(availableElements, limit);
}
else
{
limit = 6;
}
zombiesArrays = GetRandomUniqueElementsInArray(availableElements, limit);
level.mapvote["maps"]["by_index"] = GetRandomUniqueElementsInArray(availableElements, limit);
level.mapvote["maps"]["by_index"] = [];
foreach (element in zombiesArrays)
{
splittedElement = StrTok(element, ",");
level.mapvote["maps"]["by_index"] = AddElementToArray(level.mapvote["maps"]["by_index"], array(splittedElement[0], splittedElement[1], splittedElement[2]));
}
}
}
else if (type == "mode")
{
if (availableElements.size < 4)
{
limit = availableElements.size;
}
else
{
limit = 4;
}
finalElements = [];
foreach (mode in GetRandomUniqueElementsInArray(availableElements, limit))
@ -465,6 +583,68 @@ SetMapvoteData(type)
}
}
/*
Gets the amount of maps and modes to display on screen
This is used to get default values if the limits dvars are not set
It will dynamically adjust the amount of maps and modes to show
*/
GetVoteLimits(mapsAmount, modesAmount)
{
maxLimit = GetDvarInt("mapvote_limits_max");
limits = [];
if (!IsDefined(modesAmount))
{
if (mapsAmount <= maxLimit)
{
return mapsAmount;
}
else
{
return maxLimit;
}
}
if ((mapsAmount + modesAmount) <= maxLimit)
{
limits["maps"] = mapsAmount;
limits["modes"] = modesAmount;
}
else
{
if (mapsAmount >= (maxLimit / 2) && modesAmount >= (maxLimit))
{
limits["maps"] = (maxLimit / 2);
limits["modes"] = (maxLimit / 2);
}
else
{
if (mapsAmount > (maxLimit / 2))
{
finalMapsAmount = 0;
if (modesAmount <= 1)
{
limits["maps"] = maxLimit;
}
else
{
limits["maps"] = (maxLimit - modesAmount);
}
limits["modes"] = modesAmount;
}
else if (modesAmount > (maxLimit / 2))
{
limits["maps"] = mapsAmount;
limits["modes"] = (maxLimit - mapsAmount);
}
}
}
return limits;
}
/* HUD section */
@ -619,6 +799,11 @@ IsBot()
return IsDefined(self.pers["isBot"]) && self.pers["isBot"];
}
IsMultiplayerMode()
{
return !IsDefined(level.zombiemode) || !level.zombiemode;
}
GetHumanPlayers()
{
humanPlayers = [];
@ -627,7 +812,7 @@ GetHumanPlayers()
{
if (!player IsBot())
{
humanPlayers[humanPlayers.size] = player;
humanPlayers = AddElementToArray(humanPlayers, player);
}
}
@ -689,100 +874,134 @@ AddElementToArray(array, element)
GetMapCodeName(mapName)
{
switch(mapName)
formattedMapName = ToUpper(mapName);
if (IsMultiplayerMode())
{
case "Nuketown":
return "mp_nuketown_2020";
switch(formattedMapName)
{
case "NUKETOWN":
return "mp_nuketown_2020";
case "Hijacked":
return "mp_hijacked";
case "HIJACKED":
return "mp_hijacked";
case "Meltdown":
return "mp_meltdown";
case "MELTDOWN":
return "mp_meltdown";
case "Express":
return "mp_express";
case "EXPRESS":
return "mp_express";
case "Carrier":
return "mp_carrier";
case "CARRIER":
return "mp_carrier";
case "Overflow":
return "mp_overflow";
case "OVERFLOW":
return "mp_overflow";
case "Slums":
return "mp_slums";
case "SLUMS":
return "mp_slums";
case "Aftermath":
return "mp_la";
case "AFTERMATH":
return "mp_la";
case "Cargo":
return "mp_dockside";
case "CARGO":
return "mp_dockside";
case "Turbine":
return "mp_turbine";
case "TURBINE":
return "mp_turbine";
case "Drone":
return "mp_drone";
case "DRONE":
return "mp_drone";
case "Raid":
return "mp_raid";
case "RAID":
return "mp_raid";
case "Standoff":
return "mp_village";
case "STANDOFF":
return "mp_village";
case "Plaza":
return "mp_nightclub";
case "PLAZA":
return "mp_nightclub";
case "Yemen":
return "mp_socotra";
case "YEMEN":
return "mp_socotra";
case "Uplink":
return "mp_uplink";
case "UPLINK":
return "mp_uplink";
case "Detour":
return "mp_bridge";
case "DETOUR":
return "mp_bridge";
case "Cove":
return "mp_castaway";
case "COVE":
return "mp_castaway";
case "Rush":
return "mp_paintball";
case "RUSH":
return "mp_paintball";
case "Studio":
return "mp_studio";
case "STUDIO":
return "mp_studio";
case "Magma":
return "mp_magma";
case "MAGMA":
return "mp_magma";
case "Vertigo":
return "mp_vertigo";
case "VERTIGO":
return "mp_vertigo";
case "Encore":
return "mp_concert";
case "ENCORE":
return "mp_concert";
case "Downhill":
return "mp_downhill";
case "DOWNHILL":
return "mp_downhill";
case "Grind":
return "mp_skate";
case "GRIND":
return "mp_skate";
case "Hydro":
return "mp_hydro";
case "HYDRO":
return "mp_hydro";
case "Mirage":
return "mp_mirage";
case "MIRAGE":
return "mp_mirage";
case "Frost":
return "mp_frostbite";
case "FROST":
return "mp_frostbite";
case "Takeoff":
return "mp_takeoff";
case "TAKEOFF":
return "mp_takeoff";
case "Pod":
return "mp_pod";
case "POD":
return "mp_pod";
case "Dig":
return "mp_dig";
case "DIG":
return "mp_dig";
}
}
else
{
switch(formattedMapName)
{
case "BURIED":
return "zm_buried";
case "DIE RISE":
return "zm_highrise";
case "MOB OF THE DEAD":
return "zm_prison";
case "NUKETOWN":
return "zm_nuked";
case "ORIGINS":
return "zm_tomb";
case "TRANZIT":
case "FARM":
case "TOWN":
case "BUS DEPOT":
return "zm_transit";
case "DINER":
return "zm_transit_dr";
}
}
}

View File

@ -0,0 +1,155 @@
/*
All the credits for this script go to DoktorSAS for both the source code and for helping me figuring this out
https://github.com/DoktorSAS/PlutoniumT6Mapvote/blob/master/Zombies/mapvote.gsc
menuSounds = array("zmb_meteor_activate", "zmb_spawn_powerup", "zmb_powerup_grabbed", "zmb_switch_flip", "zmb_elec_start", "zmb_perks_packa_ready");
*/
#include common_scripts\utility;
#include maps\mp\_utility;
Init()
{
if (GetDvarInt("mapvote_enable"))
{
replaceFunc(maps\mp\zombies\_zm::intermission, ::OnIntermissionStart);
}
}
OnIntermissionStart()
{
level.intermission = 1;
level notify("intermission");
for (i = 0; i < level.players.size; i++)
{
level.players[i] thread player_intermission();
level.players[i] hide();
level.players[i] setclientuivisibilityflag("hud_visible", 0);
level.players[i] setclientthirdperson(0);
level.players[i].health = 100;
level.players[i] stopsounds();
level.players[i] stopsounds();
}
wait GetDvarInt("mapvote_display_wait_time");
[[level.mapvote_start_function]]();
[[level.mapvote_end_function]]();
for (i = 0; i < level.players.size; i++)
{
level.players[i] notify("_zombie_game_over");
level.players[i].sessionstate = "intermission";
}
players = get_players();
i = 0;
while (i < players.size)
{
setclientsysstate("levelNotify", "zi", players[i]);
i++;
}
wait 0.25;
players = get_players();
i = 0;
while (i < players.size)
{
setclientsysstate("lsm", "0", players[i]);
i++;
}
level thread maps\mp\zombies\_zm::zombie_game_over_death();
}
player_intermission()
{
self closemenu();
self closeingamemenu();
level endon("stop_intermission");
self endon("disconnect");
self endon("death");
self.score = self.score_total;
self.spectatorclient = -1;
self.killcamentity = -1;
self.archivetime = 0;
self.psoffsettime = 0;
self.friendlydamage = undefined;
points = getstructarray("intermission", "targetname");
if (!isDefined(points) || points.size == 0)
{
points = getentarray("info_intermission", "classname");
location = getDvar("ui_zm_mapstartlocation");
for(i = 0;i < points.size;i++)
{
if(points[i].script_string == location)
{
points = points[i];
}
}
if (points.size < 1)
{
return;
}
}
if (isdefined(self.game_over_bg))
self.game_over_bg destroy();
org = undefined;
while (1)
{
points = array_randomize(points);
i = 0;
while (i < points.size)
{
point = points[i];
if (!isDefined(org))
{
self spawn(point.origin, point.angles);
}
if (isDefined(points[i].target))
{
if (!isDefined(org))
{
org = spawn("script_model", self.origin + vectorScale((0, 0, -1), 60));
org setmodel("tag_origin");
}
org.origin = points[i].origin;
org.angles = points[i].angles;
j = 0;
while (j < get_players().size)
{
player = get_players()[j];
player camerasetposition(org);
player camerasetlookat();
player cameraactivate(1);
j++;
}
speed = 20;
if (isDefined(points[i].speed))
{
speed = points[i].speed;
}
target_point = getstruct(points[i].target, "targetname");
dist = distance(points[i].origin, target_point.origin);
time = dist / speed;
q_time = time * 0.25;
if (q_time > 1)
{
q_time = 1;
}
org moveto(target_point.origin, time, q_time, q_time);
org rotateto(target_point.angles, time, q_time, q_time);
wait(time - q_time);
wait q_time;
i++;
continue;
}
i++;
}
}
}