Compare commits

...

5 Commits

10 changed files with 691 additions and 22 deletions

View File

@ -1143,6 +1143,69 @@
"en" "HP: {1}" "en" "HP: {1}"
} }
// ===========================
// ZVolume (module)
// ===========================
"Volume_Menu_Title"
{
"en" "[ZR] Volume Control Menu\nCommand: !zvolume"
}
"Zombie Voice"
{
"en" "Zombie Voice"
}
"Ambient"
{
"en" "Ambient"
}
"ZombieVoice_Usage"
{
"en" "Usage: zr_zombie_volume <0 - 100>"
}
"ZombieVoice_Title_Menu"
{
"#format" "{1:d}"
"en" "[ZR] Zombie Voice Volume (Current: {1:d}%)"
}
"ZombieVoice_CommandUsage"
{
"en" "Command: !zombie_volume <1-100>"
}
"Set_ZombieVoice_Volume"
{
"#format" "{1:d}"
"en" "Set Zombie Voice Volume to {lightgreen}{1:d}%."
}
"Ambient_Usage"
{
"en" "Usage: zr_ambient_volume <0 - 100>"
}
"Ambient_Title_Menu"
{
"#format" "{1:d}"
"en" "[ZR] Ambient Volume (Current: {1:d}%)"
}
"Ambient_CommandUsage"
{
"en" "Command: !ambient_volume <1-100>"
}
"Set_Ambient_Volume"
{
"#format" "{1:d}"
"en" "Set Ambient Volume to {lightgreen}{1:d}%."
}
// =========================== // ===========================
// Volumetric features (module) // Volumetric features (module)
// =========================== // ===========================

26
env/include/unloze_playtime.inc vendored Executable file
View File

@ -0,0 +1,26 @@
#if defined _unloze_playtime_included_
#endinput
#endif
#define _unloze_playtime_included_
/**
* @returns the average playtime of all connected players excluding autism bots, fakeclients, AFKS and nosteamers
*/
native int GetAveragePlayerTimeOnServer();
/**
* @returns the players rtv amount boost
*/
native int GetPlayerWorthRTV_boost_(int client);
/**
* returns a players hours for a specific server
*
* @int the actual client
* @int Game time hours that the client has on the server.
* @int Game time minutes the client has on the server.
*/
native int GetPlayerTier_native(int client); //just the clients tier
forward void GetPlayerHoursServer(int client, int hours, int minutes);
forward void GetPlayerTier(int client, int tier);

View File

@ -351,6 +351,7 @@ public OnClientCookiesCached(client)
ClassOnCookiesCached(client); ClassOnCookiesCached(client);
WeaponsOnCookiesCached(client); WeaponsOnCookiesCached(client);
ZHPOnCookiesCached(client); ZHPOnCookiesCached(client);
ZVolumeOnCookiesCached(client);
} }
/** /**

View File

@ -45,6 +45,7 @@ CommandsInit()
ZTele_OnCommandsCreate(); ZTele_OnCommandsCreate();
ZHPOnCommandsCreate(); ZHPOnCommandsCreate();
VolOnCommandsCreate(); VolOnCommandsCreate();
ZVolumeOnCommandsCreate();
ZombieSoundsOnCommandsCreate(); ZombieSoundsOnCommandsCreate();
ImmunityOnCommandsCreate(); ImmunityOnCommandsCreate();

View File

@ -34,6 +34,7 @@ CookiesInit()
ClassOnCookiesCreate(); ClassOnCookiesCreate();
WeaponsOnCookiesCreate(); WeaponsOnCookiesCreate();
ZHPOnCookiesCreate(); ZHPOnCookiesCreate();
ZVolumeOnCookiesCreate();
} }
/** /**

View File

@ -152,6 +152,7 @@ enum CvarsList
Handle:CVAR_SEFFECTS_DEATH, Handle:CVAR_SEFFECTS_DEATH,
Handle:CVAR_SEFFECTS_COMMAND_LIMIT, Handle:CVAR_SEFFECTS_COMMAND_LIMIT,
Handle:CVAR_SEFFECTS_COMMAND_TIMESPAN, Handle:CVAR_SEFFECTS_COMMAND_TIMESPAN,
Handle:CVAR_SEFFECTS_VOLUME,
Handle:CVAR_AMBIENTSOUNDS, Handle:CVAR_AMBIENTSOUNDS,
Handle:CVAR_AMBIENTSOUNDS_FILE, Handle:CVAR_AMBIENTSOUNDS_FILE,
Handle:CVAR_AMBIENTSOUNDS_LENGTH, Handle:CVAR_AMBIENTSOUNDS_LENGTH,
@ -450,6 +451,7 @@ CvarsCreate()
g_hCvarsList[CVAR_SEFFECTS_DEATH] = CreateConVar("zr_seffects_death", "1", "Emit a death sound when a zombie dies."); g_hCvarsList[CVAR_SEFFECTS_DEATH] = CreateConVar("zr_seffects_death", "1", "Emit a death sound when a zombie dies.");
g_hCvarsList[CVAR_SEFFECTS_COMMAND_LIMIT] = CreateConVar("zr_seffects_command_limit", "4", "Number of sound commands allowed within the time span, or total limit if time span is disabled. ['0' = Disable sound command limit]"); g_hCvarsList[CVAR_SEFFECTS_COMMAND_LIMIT] = CreateConVar("zr_seffects_command_limit", "4", "Number of sound commands allowed within the time span, or total limit if time span is disabled. ['0' = Disable sound command limit]");
g_hCvarsList[CVAR_SEFFECTS_COMMAND_TIMESPAN] = CreateConVar("zr_seffects_command_timespan", "10", "Time span for sound command limiter (in seconds). ['0' = Disable time span check | positive number = Time span]"); g_hCvarsList[CVAR_SEFFECTS_COMMAND_TIMESPAN] = CreateConVar("zr_seffects_command_timespan", "10", "Time span for sound command limiter (in seconds). ['0' = Disable time span check | positive number = Time span]");
g_hCvarsList[CVAR_SEFFECTS_VOLUME] = CreateConVar("zr_seffects_volume", "0.8", "Default volume of the zombie voice sounds, used as each client's starting !zsound value. [1.0 = Max volume | 0.0001 = Not audible]");
// Ambient Sounds // Ambient Sounds
g_hCvarsList[CVAR_AMBIENTSOUNDS] = CreateConVar("zr_ambientsounds", "1", "Play an ambient sound to all players during gameplay."); g_hCvarsList[CVAR_AMBIENTSOUNDS] = CreateConVar("zr_ambientsounds", "1", "Play an ambient sound to all players during gameplay.");

View File

@ -32,6 +32,7 @@
#tryinclude "AFKManager.inc" #tryinclude "AFKManager.inc"
#tryinclude "TeamManager.inc" #tryinclude "TeamManager.inc"
#include "unloze_playtime.inc"
/* Restore old REQUIRE_PLUGIN value if necessary */ /* Restore old REQUIRE_PLUGIN value if necessary */
#if defined TEMP_REQUIRE_PLUGIN #if defined TEMP_REQUIRE_PLUGIN
@ -234,6 +235,7 @@ InfectClientInit(client)
if(!IsClientInGame(x)) if(!IsClientInGame(x))
continue; continue;
/*
#if defined _AFKManager_Included #if defined _AFKManager_Included
if(g_AFKManagerLoaded) if(g_AFKManagerLoaded)
{ {
@ -241,6 +243,7 @@ InfectClientInit(client)
continue; continue;
} }
#endif #endif
*/
players++; players++;
@ -704,18 +707,24 @@ public Action:InfectMotherZombie(Handle:timer)
// Infect one of the main candidates. // Infect one of the main candidates.
if (candidatesMain) if (candidatesMain)
{ {
// Get a random array index. // Find lowest tier candidate.
new i = Math_GetRandomInt(0, candidatesMain - 1); new lowestIndex = 0;
new lowestTier = GetPlayerTier_native(GetArrayCell(aCandidatesMain, 0));
for (new n = 1; n < candidatesMain; n++)
{
new tier = GetPlayerTier_native(GetArrayCell(aCandidatesMain, n));
if (tier < lowestTier)
{
lowestTier = tier;
lowestIndex = n;
}
}
new client = GetArrayCell(aCandidatesMain, lowestIndex);
// Get the client stored in the random array index.
new client = GetArrayCell(aCandidatesMain, i);
// Infect player.
if (InfectHumanToZombie(client, _, true)) if (InfectHumanToZombie(client, _, true))
infected++; infected++;
// Remove player from eligible client list. RemoveFromArray(aCandidatesMain, lowestIndex);
RemoveFromArray(aCandidatesMain, i);
candidatesMain--; candidatesMain--;
} }
else else
@ -735,18 +744,24 @@ public Action:InfectMotherZombie(Handle:timer)
// Infect one of the alternate candidates. // Infect one of the alternate candidates.
if (candidatesAlt) if (candidatesAlt)
{ {
// Get a random array index. // Find lowest tier candidate.
new i = Math_GetRandomInt(0, candidatesAlt - 1); new lowestIndex = 0;
new lowestTier = GetPlayerTier_native(GetArrayCell(aCandidatesAlt, 0));
for (new n = 1; n < candidatesAlt; n++)
{
new tier = GetPlayerTier_native(GetArrayCell(aCandidatesAlt, n));
if (tier < lowestTier)
{
lowestTier = tier;
lowestIndex = n;
}
}
new client = GetArrayCell(aCandidatesAlt, lowestIndex);
// Get the client stored in the random array index.
new client = GetArrayCell(aCandidatesAlt, i);
// Infect player.
if (InfectHumanToZombie(client, _, true)) if (InfectHumanToZombie(client, _, true))
infected++; infected++;
// Remove player from eligible client list. RemoveFromArray(aCandidatesAlt, lowestIndex);
RemoveFromArray(aCandidatesAlt, i);
candidatesAlt--; candidatesAlt--;
} }
else // We have no candidates at all. time to fuck over random people! else // We have no candidates at all. time to fuck over random people!

View File

@ -38,6 +38,7 @@
#include "zr/soundeffects/voice" #include "zr/soundeffects/voice"
#include "zr/soundeffects/ambientsounds" #include "zr/soundeffects/ambientsounds"
#include "zr/soundeffects/zombiesounds" #include "zr/soundeffects/zombiesounds"
#include "zr/soundeffects/volumecontrol"
/** /**
* Load sound effects data. * Load sound effects data.
@ -172,8 +173,17 @@ SEffectsEmitAmbientSound(const String:sound[], Float:ambientvolume = 1.0, client
if (ZRIsClientValid(client)) if (ZRIsClientValid(client))
{ {
// Scale by this client's personal ambient volume setting.
new Float:finalvolume = ambientvolume * ZVolume_GetAmbientVolume(client);
// If client has muted ambient sounds, then stop.
if (finalvolume <= 0.0)
{
return;
}
// Emit ambient sound. // Emit ambient sound.
EmitSoundToClient(client, sound, SOUND_FROM_PLAYER, SOUND_AMBIENT_CHANNEL, _, _, ambientvolume); EmitSoundToClient(client, sound, SOUND_FROM_PLAYER, SOUND_AMBIENT_CHANNEL, _, _, finalvolume);
// Flag client that sound is playing. // Flag client that sound is playing.
bAmbientSoundsIsPlaying[client] = true; bAmbientSoundsIsPlaying[client] = true;
@ -188,8 +198,17 @@ SEffectsEmitAmbientSound(const String:sound[], Float:ambientvolume = 1.0, client
continue; continue;
} }
// Scale by this client's personal ambient volume setting.
new Float:finalvolume = ambientvolume * ZVolume_GetAmbientVolume(x);
// If client has muted ambient sounds, then skip them.
if (finalvolume <= 0.0)
{
continue;
}
// Emit ambient sound. // Emit ambient sound.
EmitSoundToClient(x, sound, SOUND_FROM_PLAYER, SNDCHAN_AUTO, _, _, ambientvolume); EmitSoundToClient(x, sound, SOUND_FROM_PLAYER, SNDCHAN_AUTO, _, _, finalvolume);
} }
} }
} }
@ -233,6 +252,25 @@ SEffectsEmitSoundFromClient(client, const String:sound[], level = SNDLEVEL_NORMA
// Precache sound before playing. // Precache sound before playing.
PrecacheSound(sound); PrecacheSound(sound);
// Emit sound from client. // x = receiving client index.
EmitSoundToAll(sound, client, _, level); for (new x = 1; x <= MaxClients; x++)
{
// If client isn't in-game, then skip.
if (!IsClientInGame(x))
{
continue;
}
// Get this client's personal zombie-voice volume.
new Float:zvolume = ZVolume_GetZSoundVolume(x);
// If client has muted zombie voice sounds, then skip them.
if (zvolume <= 0.0)
{
continue;
}
// Emit sound from client, at this receiving client's personal volume.
EmitSoundToClient(x, sound, client, _, level, _, zvolume);
}
} }

View File

@ -0,0 +1,408 @@
/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: volumecontrol.inc
* Type: Core
* Description: Basic volume control for player to change.
*
* Copyright (C) 2009-2013 Greyscale, Richard Helgeby
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ============================================================================
*/
/**
* Cookie names for client volume settings.
*/
#define ZVOLUME_COOKIE_ZSOUND "zr_zombie_volume"
#define ZVOLUME_COOKIE_AMBIENT "zr_ambient_volume"
/**
* Cookie handles for client volume settings.
*/
new Handle:g_hZSoundVolumeCookie = INVALID_HANDLE;
new Handle:g_hAmbientVolumeCookie = INVALID_HANDLE;
/**
* Per-client volume, as a fraction (0.0 - 1.0), applied on top of sounds
* emitted through SEffectsEmitSoundFromClient() and SEffectsEmitAmbientSound().
*/
new Float:zfZSoundVolume[MAXPLAYERS + 1];
new Float:zfAmbientVolume[MAXPLAYERS + 1];
/**
* Create commands specific to ZVolume.
*/
ZVolumeOnCommandsCreate()
{
RegConsoleCmd("sm_zvol", Command_ZVolume, "Brings up the zvolume menu");
RegConsoleCmd("sm_zvolume", Command_ZVolume, "Brings up the zvolume menu");
RegConsoleCmd("sm_zsound", Command_ZSound, "Brings up the zsound menu");
RegConsoleCmd("sm_zombie_volume", Command_ZSound, "Brings up the zsound menu");
RegConsoleCmd("sm_zambient", Command_ZAmbient, "Brings up the ambient menu");
RegConsoleCmd("sm_ambient_volume", Command_ZAmbient, "Brings up the ambient menu");
}
/**
* Create ZVolume-related cookies here.
*/
ZVolumeOnCookiesCreate()
{
if (g_hZSoundVolumeCookie == INVALID_HANDLE)
{
g_hZSoundVolumeCookie = RegClientCookie(ZVOLUME_COOKIE_ZSOUND, "Control Zombie Sound.", CookieAccess_Protected);
}
if (g_hAmbientVolumeCookie == INVALID_HANDLE)
{
g_hAmbientVolumeCookie = RegClientCookie(ZVOLUME_COOKIE_AMBIENT, "Control Ambient Sound.", CookieAccess_Protected);
}
}
/**
* Called once a client's saved cookies have been loaded from the database.
*
* @param client The client index.
*/
ZVolumeOnCookiesCached(client)
{
decl String:sValue[8];
sValue[0] = '\0';
GetClientCookie(client, g_hZSoundVolumeCookie, sValue, sizeof(sValue));
if (!sValue[0])
{
new Float:seffectsvolume = GetConVarFloat(g_hCvarsList[CVAR_SEFFECTS_VOLUME]);
IntToString(RoundToNearest(seffectsvolume * 100.0), sValue, sizeof(sValue));
}
SetZombieVoiceVolume(client, StringToInt(sValue));
sValue[0] = '\0';
GetClientCookie(client, g_hAmbientVolumeCookie, sValue, sizeof(sValue));
if (!sValue[0])
{
new Float:ambientvolume = GetConVarFloat(g_hCvarsList[CVAR_AMBIENTSOUNDS_VOLUME]);
IntToString(RoundToNearest(ambientvolume * 100.0), sValue, sizeof(sValue));
}
SetAmbientVolume(client, StringToInt(sValue));
}
/**
* Returns the client's personal zombie-voice volume, as a fraction (0.0 - 1.0).
*
* @param client The client index.
*/
Float:ZVolume_GetZSoundVolume(client)
{
return zfZSoundVolume[client];
}
/**
* Returns the client's personal ambient-sound volume, as a fraction (0.0 - 1.0).
*
* @param client The client index.
*/
Float:ZVolume_GetAmbientVolume(client)
{
return zfAmbientVolume[client];
}
/**
* Command callback (sm_zvol, sm_zvolume)
* Opens the volume control menu.
*/
public Action:Command_ZVolume(client, args)
{
if (IsClientInGame(client))
{
VolumeControlMenu(client);
return Plugin_Handled;
}
return Plugin_Handled;
}
VolumeControlMenu(client)
{
new Handle:menu = CreateMenu(VolumeControlMenuHandler);
decl String:sMenuTitle[128];
Format(sMenuTitle, sizeof(sMenuTitle), "%t", "Volume_Menu_Title");
SetMenuTitle(menu, sMenuTitle);
decl String:sItem[64];
Format(sItem, sizeof(sItem), "%t", "Zombie Voice");
AddMenuItem(menu, "1", sItem);
Format(sItem, sizeof(sItem), "%t", "Ambient");
AddMenuItem(menu, "2", sItem);
SetMenuExitBackButton(menu, true);
DisplayMenu(menu, client, MENU_TIME_FOREVER);
}
public VolumeControlMenuHandler(Handle:menu, MenuAction:action, param1, param2)
{
switch (action)
{
case MenuAction_Select:
{
decl String:info[32];
GetMenuItem(menu, param2, info, sizeof(info));
if (StrEqual(info, "1", false))
{
ZombieVoiceVolumeMenu(param1);
}
else if (StrEqual(info, "2"))
{
AmbientVolumeMenu(param1);
}
}
case MenuAction_Cancel:
{
if (param2 == MenuCancel_ExitBack)
{
ZMenuMain(param1);
}
}
case MenuAction_End:
{
CloseHandle(menu);
}
}
return 0;
}
// Zombie Voice Section
/**
* Command callback (sm_zsound, sm_zombie_volume)
*/
public Action:Command_ZSound(client, args)
{
if (args == 0)
{
ZombieVoiceVolumeMenu(client);
return Plugin_Handled;
}
decl String:sArg[32];
GetCmdArg(1, sArg, sizeof(sArg));
new iVolume = StringToInt(sArg);
if (iVolume < 0 || iVolume > 100)
{
TranslationReplyToCommand(client, "ZombieVoice_Usage");
return Plugin_Handled;
}
else if (0 <= iVolume <= 100)
{
SetZombieVoiceVolume(client, iVolume);
return Plugin_Handled;
}
return Plugin_Handled;
}
ZombieVoiceVolumeMenu(client)
{
new Handle:menu = CreateMenu(ZombieVoiceVolumeMenuHandler);
decl String:sMenuTitle[128];
Format(sMenuTitle, sizeof(sMenuTitle), "%t\n%t", "ZombieVoice_Title_Menu", RoundToNearest(zfZSoundVolume[client] * 100), "ZombieVoice_CommandUsage");
SetMenuTitle(menu, sMenuTitle);
AddMenuItem(menu, "1", "100%");
AddMenuItem(menu, "2", "80%");
AddMenuItem(menu, "3", "60%");
AddMenuItem(menu, "4", "40%");
AddMenuItem(menu, "5", "20%");
SetMenuExitBackButton(menu, true);
DisplayMenu(menu, client, MENU_TIME_FOREVER);
}
public ZombieVoiceVolumeMenuHandler(Handle:menu, MenuAction:action, param1, param2)
{
switch (action)
{
case MenuAction_Select:
{
decl String:info[32];
GetMenuItem(menu, param2, info, sizeof(info));
if (StrEqual(info, "1", false))
{
SetZombieVoiceVolume(param1, 100);
ZombieVoiceVolumeMenu(param1);
}
else if (StrEqual(info, "2"))
{
SetZombieVoiceVolume(param1, 80);
ZombieVoiceVolumeMenu(param1);
}
else if (StrEqual(info, "3"))
{
SetZombieVoiceVolume(param1, 60);
ZombieVoiceVolumeMenu(param1);
}
else if (StrEqual(info, "4"))
{
SetZombieVoiceVolume(param1, 40);
ZombieVoiceVolumeMenu(param1);
}
else if (StrEqual(info, "5"))
{
SetZombieVoiceVolume(param1, 20);
ZombieVoiceVolumeMenu(param1);
}
}
case MenuAction_Cancel:
{
if (param2 == MenuCancel_ExitBack)
{
VolumeControlMenu(param1);
}
}
case MenuAction_End:
{
CloseHandle(menu);
}
}
return 0;
}
SetZombieVoiceVolume(client, volume)
{
zfZSoundVolume[client] = volume * 0.01;
decl String:sValue[8];
IntToString(volume, sValue, sizeof(sValue));
SetClientCookie(client, g_hZSoundVolumeCookie, sValue);
if (IsClientInGame(client))
{
TranslationPrintToChat(client, "Set_ZombieVoice_Volume", volume);
}
}
// Ambient Section
/**
* Command callback (sm_zambient, sm_ambient_volume)
*/
public Action:Command_ZAmbient(client, args)
{
if (args == 0)
{
AmbientVolumeMenu(client);
return Plugin_Handled;
}
decl String:sArg[32];
GetCmdArg(1, sArg, sizeof(sArg));
new iVolume = StringToInt(sArg);
if (iVolume < 0 || iVolume > 100)
{
TranslationReplyToCommand(client, "Ambient_Usage");
return Plugin_Handled;
}
else if (0 <= iVolume <= 100)
{
SetAmbientVolume(client, iVolume);
return Plugin_Handled;
}
return Plugin_Handled;
}
AmbientVolumeMenu(client)
{
new Handle:menu = CreateMenu(AmbientVolumeMenuHandler);
decl String:sMenuTitle[128];
Format(sMenuTitle, sizeof(sMenuTitle), "%t\n%t", "Ambient_Title_Menu", RoundToNearest(zfAmbientVolume[client] * 100), "Ambient_CommandUsage");
SetMenuTitle(menu, sMenuTitle);
AddMenuItem(menu, "1", "100%");
AddMenuItem(menu, "2", "80%");
AddMenuItem(menu, "3", "60%");
AddMenuItem(menu, "4", "40%");
AddMenuItem(menu, "5", "20%");
SetMenuExitBackButton(menu, true);
DisplayMenu(menu, client, MENU_TIME_FOREVER);
}
public AmbientVolumeMenuHandler(Handle:menu, MenuAction:action, param1, param2)
{
switch (action)
{
case MenuAction_Select:
{
decl String:info[32];
GetMenuItem(menu, param2, info, sizeof(info));
if (StrEqual(info, "1", false))
{
SetAmbientVolume(param1, 100);
AmbientVolumeMenu(param1);
}
else if (StrEqual(info, "2"))
{
SetAmbientVolume(param1, 80);
AmbientVolumeMenu(param1);
}
else if (StrEqual(info, "3"))
{
SetAmbientVolume(param1, 60);
AmbientVolumeMenu(param1);
}
else if (StrEqual(info, "4"))
{
SetAmbientVolume(param1, 40);
AmbientVolumeMenu(param1);
}
else if (StrEqual(info, "5"))
{
SetAmbientVolume(param1, 20);
AmbientVolumeMenu(param1);
}
}
case MenuAction_Cancel:
{
if (param2 == MenuCancel_ExitBack)
{
VolumeControlMenu(param1);
}
}
case MenuAction_End:
{
CloseHandle(menu);
}
}
return 0;
}
SetAmbientVolume(client, volume)
{
zfAmbientVolume[client] = volume * 0.01;
decl String:sValue[8];
IntToString(volume, sValue, sizeof(sValue));
SetClientCookie(client, g_hAmbientVolumeCookie, sValue);
if (IsClientInGame(client))
{
TranslationPrintToChat(client, "Set_Ambient_Volume", volume);
}
}

View File

@ -30,6 +30,7 @@
*/ */
#define ZMARKET_COOKIE_AUTOREBUY "zr_zmarket_autorebuy" #define ZMARKET_COOKIE_AUTOREBUY "zr_zmarket_autorebuy"
#define ZMARKET_COOKIE_REBUY "zr_zmarket_rebuy" #define ZMARKET_COOKIE_REBUY "zr_zmarket_rebuy"
#define ZMARKET_COOKIE_RANDOMIZE "zr_zmarket_randomize"
/** /**
* @endsection * @endsection
*/ */
@ -39,6 +40,14 @@
*/ */
#define ZMARKET_REBUY_WEAPONS_SLOTS_MAX 1 #define ZMARKET_REBUY_WEAPONS_SLOTS_MAX 1
/**
* 2026 randomization of zmarket guns for round start.
*/
new Handle:g_hZMarketRandomizeCookie = INVALID_HANDLE;
new bool:g_bZMarketRandomize[MAXPLAYERS + 1];
new String:g_sZMarketRandomHistoryPrimary[MAXPLAYERS + 1][3][WEAPONS_MAX_LENGTH];
/** /**
* Array to store the client's current weapon type within menu. * Array to store the client's current weapon type within menu.
*/ */
@ -90,6 +99,12 @@ ZMarketOnCookiesCreate()
g_hZMarketLoadoutCookie[x] = RegClientCookie(rebuycookiename, rebuycookiedesc, CookieAccess_Protected); g_hZMarketLoadoutCookie[x] = RegClientCookie(rebuycookiename, rebuycookiedesc, CookieAccess_Protected);
} }
} }
// Randomize toggle cookie.
if (g_hZMarketRandomizeCookie == INVALID_HANDLE)
{
g_hZMarketRandomizeCookie = RegClientCookie(ZMARKET_COOKIE_RANDOMIZE, "Whether weapon randomization is enabled", CookieAccess_Protected);
}
} }
ZMarketLoad() ZMarketLoad()
@ -207,6 +222,12 @@ ZMarketClientInit(client)
// No weapons bought automatically. // No weapons bought automatically.
g_bZMarketWeaponsBought[client] = false; g_bZMarketWeaponsBought[client] = false;
// Clear randomize weapon history.
for (new i = 0; i < 3; i++)
{
g_sZMarketRandomHistoryPrimary[client][i][0] = '\0';
}
} }
/** /**
@ -216,6 +237,10 @@ ZMarketClientInit(client)
*/ */
ZMarketOnCookiesCached(client) ZMarketOnCookiesCached(client)
{ {
decl String:value[4];
GetClientCookie(client, g_hZMarketRandomizeCookie, value, sizeof(value));
g_bZMarketRandomize[client] = (value[0] == '1');
// Rebuy wapons (if auto-rebuy is enabled, and not bought already). // Rebuy wapons (if auto-rebuy is enabled, and not bought already).
if (!g_bZMarketWeaponsBought[client]) if (!g_bZMarketWeaponsBought[client])
{ {
@ -371,6 +396,7 @@ bool:ZMarketMenuMain(client)
decl String:editloadout[MENU_LINE_REG_LENGTH]; decl String:editloadout[MENU_LINE_REG_LENGTH];
decl String:rebuy[MENU_LINE_REG_LENGTH]; decl String:rebuy[MENU_LINE_REG_LENGTH];
decl String:weaponslist[MENU_LINE_REG_LENGTH]; decl String:weaponslist[MENU_LINE_REG_LENGTH];
decl String:randomize[MENU_LINE_REG_LENGTH];
// Format menu options. // Format menu options.
Format(title, sizeof(title), "%t\n ", "Weapons menu zmarket main title"); Format(title, sizeof(title), "%t\n ", "Weapons menu zmarket main title");
@ -378,6 +404,7 @@ bool:ZMarketMenuMain(client)
Format(editloadout, sizeof(editloadout), "%t", "Weapons menu zmarket main edit loadout"); Format(editloadout, sizeof(editloadout), "%t", "Weapons menu zmarket main edit loadout");
Format(rebuy, sizeof(rebuy), "%t", "Weapons menu zmarket main rebuy"); Format(rebuy, sizeof(rebuy), "%t", "Weapons menu zmarket main rebuy");
Format(weaponslist, sizeof(weaponslist), "%t", "Weapons menu zmarket main weapons list"); Format(weaponslist, sizeof(weaponslist), "%t", "Weapons menu zmarket main weapons list");
Format(randomize, sizeof(randomize), "Randomize Weapons: %s", g_bZMarketRandomize[client] ? "ON" : "OFF");
// Add formatted options to menu. // Add formatted options to menu.
SetMenuTitle(menu_zmarket_main, title); SetMenuTitle(menu_zmarket_main, title);
@ -385,6 +412,7 @@ bool:ZMarketMenuMain(client)
AddMenuItem(menu_zmarket_main, "Edit Loadout", editloadout, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto)); AddMenuItem(menu_zmarket_main, "Edit Loadout", editloadout, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto));
AddMenuItem(menu_zmarket_main, "Rebuy", rebuy, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto)); AddMenuItem(menu_zmarket_main, "Rebuy", rebuy, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto));
AddMenuItem(menu_zmarket_main, "Weapons List", weaponslist); AddMenuItem(menu_zmarket_main, "Weapons List", weaponslist);
AddMenuItem(menu_zmarket_main, "Randomize", randomize);
// Set exit back button. // Set exit back button.
SetMenuExitBackButton(menu_zmarket_main, true); SetMenuExitBackButton(menu_zmarket_main, true);
@ -440,6 +468,18 @@ public ZMarketMenuMainHandle(Handle:menu_zmarket_main, MenuAction:action, client
// Send the weapon types list. // Send the weapon types list.
ZMarketMenuTypes(client); ZMarketMenuTypes(client);
} }
case 4:
{
// Toggle randomize.
g_bZMarketRandomize[client] = !g_bZMarketRandomize[client];
decl String:value[4];
Format(value, sizeof(value), "%d", g_bZMarketRandomize[client] ? 1 : 0);
SetClientCookie(client, g_hZMarketRandomizeCookie, value);
PrintToChat(client, "Weapons zmarket randomize toggled: %s", g_bZMarketRandomize[client] ? "ON" : "OFF");
ZMarketMenuMain(client);
}
} }
} }
// Client closed the menu. // Client closed the menu.
@ -1305,6 +1345,75 @@ stock ZMarketSetRebuyCookie(client, WeaponsSlot:slot, const String:value[])
CloseHandle(rebuycookie); CloseHandle(rebuycookie);
} }
/**
* Picks a random weapon name from the given slot, avoiding the client's
* last 3 picks for the primiary slot.
*
* @param client The client index.
* @param slot Slot_Primary
* @param buffer Output buffer for the weapon name.
* @param maxlen Size of buffer.
*/
stock ZMarketGetRandomWeaponForSlot(client, WeaponsSlot:slot, String:buffer[], maxlen)
{
new Handle:candidates = CreateArray(WEAPONS_MAX_LENGTH);
new size = GetArraySize(arrayWeapons);
decl String:weaponname[WEAPONS_MAX_LENGTH];
for (new i = 0; i < size; i++)
{
if (WeaponsGetSlot(i) != slot)
continue;
WeaponsGetName(i, weaponname, sizeof(weaponname));
// Skip if restricted.
if (RestrictIsWeaponRestricted(i))
continue;
// Skip if in the client's last-3 history for this slot.
new bool:inHistory = false;
for (new h = 0; h < 3; h++)
{
decl String:histEntry[WEAPONS_MAX_LENGTH];
if (slot == Slot_Primary)
strcopy(histEntry, sizeof(histEntry), g_sZMarketRandomHistoryPrimary[client][h]);
if (StrEqual(histEntry, weaponname))
{
inHistory = true;
break;
}
}
if (inHistory)
continue;
PushArrayString(candidates, weaponname);
}
new candidateCount = GetArraySize(candidates);
if (candidateCount == 0)
{
buffer[0] = '\0';
CloseHandle(candidates);
return;
}
new pick = Math_GetRandomInt(0, candidateCount - 1);
GetArrayString(candidates, pick, buffer, maxlen);
CloseHandle(candidates);
// Push into history (shift, then insert at front).
if (slot == Slot_Primary)
{
strcopy(g_sZMarketRandomHistoryPrimary[client][2], WEAPONS_MAX_LENGTH, g_sZMarketRandomHistoryPrimary[client][1]);
strcopy(g_sZMarketRandomHistoryPrimary[client][1], WEAPONS_MAX_LENGTH, g_sZMarketRandomHistoryPrimary[client][0]);
strcopy(g_sZMarketRandomHistoryPrimary[client][0], WEAPONS_MAX_LENGTH, buffer);
}
}
/** /**
* Force a client to rebuy their weapons. * Force a client to rebuy their weapons.
* *
@ -1340,9 +1449,14 @@ ZMarketRebuy(client, bool:autorebuy = false)
// x = Weapon slot. // x = Weapon slot.
for (new x = 0; x < ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1; x++) for (new x = 0; x < ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1; x++)
{ {
// If slot is empty, then use the default value. // If randomize is enabled, override any saved loadout for primary/secondary.
if (!rebuyweapons[x][0]) if (g_bZMarketRandomize[client] && (x == Slot_Primary || x == Slot_Secondary))
{ {
ZMarketGetRandomWeaponForSlot(client, WeaponsSlot:x, rebuyweapons[x], sizeof(rebuyweapons[]));
}
else if (!rebuyweapons[x][0])
{
// No saved loadout, fall back to cvar default.
switch(x) switch(x)
{ {
case Slot_Primary: case Slot_Primary: