diff --git a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt index 2574211..e685153 100644 --- a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt +++ b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt @@ -532,6 +532,16 @@ "en" "Weapon @green{1} @defaulthas a purchase limit of @green{2}@default. Wait until you respawn to try again." } + "Weapons zmarket updated loadout" + { + "en" "You are not able to purchase a weapon at this time, but your loadout has been updated with this weapon." + } + + "Weapons zmarket get current loadout" + { + "en" "Updated current loadout, use rebuy option to purchase these weapons again." + } + // Commands "Weapons command restrict syntax" @@ -597,22 +607,82 @@ // Menu (ZMarket) + "Weapons menu zmarket main title" + { + "en" "ZMarket\nSelect an Option:" + } + + "Weapons menu zmarket main get loadout" + { + "en" "Get Current Loadout" + } + + "Weapons menu zmarket main view loadout" + { + "en" "View My Loadout" + } + + "Weapons menu zmarket main rebuy" + { + "en" "Rebuy My Loadout" + } + + "Weapons menu zmarket main auto-rebuy" + { + "#format" "{1:s}" + "en" "Auto-Rebuy: {1}" + } + + "Weapons menu zmarket main weapons list" + { + "en" "View Weapons List" + } + + "Weapons menu zmarket loadout title" + { + "en" "ZMarket\nMy Current Loadout:\nRebuy refers to these weapons" + } + + "Weapons menu zmarket loadout primary" + { + "#format" "{1:s}" + "en" "Primary: {1}" + } + + "Weapons menu zmarket loadout secondary" + { + "#format" "{1:s}" + "en" "Secondary: {1}" + } + + "Weapons menu zmarket loadout melee" + { + "#format" "{1:s}" + "en" "Melee: {1}" + } + + "Weapons menu zmarket loadout projectile" + { + "#format" "{1:s}" + "en" "Projectile: {1}" + } + + "Weapons menu zmarket loadout explosive" + { + "#format" "{1:s}" + "en" "Explosive: {1}" + } + + "Weapons menu zmarket loadout empty" + { + "en" "(None)" + } + "Weapons menu zmarket types title" { "en" "ZMarket\nSelect Weapon Type:" } - "Weapons menu zmarket types rebuy" - { - "en" "Rebuy (1 weapon per slot)" - } - - "Weapons menu zmarket types auto-rebuy" - { - "#format" "{1:s}" - "en" "Auto-Rebuy: {1}\n " - } - "Weapons menu zmarket types weapon type title" { "#format" "{1:s}" diff --git a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg index 32d538b..1389a17 100644 --- a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg +++ b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg @@ -260,15 +260,19 @@ zr_infect_weapons_drop "1" // Effects -// Spawn a fireball effect around player on infection. +Disabling this will disable the fireball, smoke cloud, and sparks in a more efficient way. +// Default: "1" +zr_infect_explosion "1" + +// Spawn a fireball effect around player on infection. [Dependency: zr_infect_explosion] // Default: "1" zr_infect_fireball "1" -// Spawn a smoke cloud effect around player on infection. +// Spawn a smoke cloud effect around player on infection. [Dependency: zr_infect_explosion] // Default: "1" zr_infect_smoke "1" -// Emit sparks from player on infection. +// Emit sparks from player on infection. [Dependency: zr_infect_explosion] // Default: "1" zr_infect_sparks "1" @@ -613,7 +617,11 @@ zr_zspawn_timelimit "1" // Default: "120.0" zr_zspawn_timelimit_time "120.0" +// Spawn player on the zombie team AFTER the timelimit is up. ['-1' = Block ZSpawn | '0' = Spawn as human | '1' = Spawn as zombie | Dependency: zr_zspawn_timelimit] +// Default: "1" +zr_zspawn_timelimit_zombie "1" + // ---------------------------------------------------------------------------- // ZTele (module) // ---------------------------------------------------------------------------- diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index 0a16839..604ed0a 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -28,6 +28,7 @@ #pragma semicolon 1 #include #include +#include #include #include @@ -42,9 +43,10 @@ #include "zr/cvars" #include "zr/log" #include "zr/config" -#include "zr/serial" +#include "zr/steamidcache" #include "zr/sayhooks" #include "zr/tools" +#include "zr/cookies" #include "zr/paramtools" #include "zr/models" #include "zr/downloads" @@ -116,6 +118,7 @@ public OnPluginStart() TranslationInit(); CvarsInit(); ToolsInit(); + CookiesInit(); CommandsInit(); WeaponsInit(); EventInit(); @@ -127,7 +130,6 @@ public OnPluginStart() public OnMapStart() { // Forward event to modules. - SerialOnMapStart(); OverlaysOnMapStart(); RoundEndOnMapStart(); InfectOnMapStart(); @@ -166,6 +168,14 @@ public OnConfigsExecuted() ClassOnModulesLoaded(); } +/** + * Client cookies just finished loading from the database. + */ +public OnClientCookiesCached() +{ + // Forward event to modules. +} + /** * Client is joining the server. * diff --git a/src/zr/cookies.inc b/src/zr/cookies.inc new file mode 100644 index 0000000..64ccbec --- /dev/null +++ b/src/zr/cookies.inc @@ -0,0 +1,70 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: cookies.inc + * Type: Module + * Description: Client cookie API. + * + * Copyright (C) 2009 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 . + * + * ============================================================================ + */ + +/** + * Cookies module init function. + */ +CookiesInit() +{ + // Forward event to modules. + ClassOnCookiesCreate(); + WeaponsOnCookiesCreate(); + ZHPOnCookiesCreate(); +} + +/** + * Accepts a bools for setting client cookies. + * + * @param client The client index. + * @param cookie The handle to the cookie. + * @param cookievalue The bool value to set cookie as. + */ +CookiesSetClientCookieBool(client, Handle:cookie, bool:cookievalue) +{ + // Convert bool to string. + decl String:strCookievalue[8]; + ZRBoolToString(cookievalue, strCookievalue, sizeof(strCookievalue)); + + // Set the converted string to the cookie. + SetClientCookie(client, cookie, strCookievalue); +} + +/** + * Returns a cookie value as a bool. + * + * @param client The client index. + * @param cookie The handle to the cookie. + */ +bool:CookiesGetClientCookieBool(client, Handle:cookie) +{ + // Get cookie string. + decl String:cookievalue[8]; + GetClientCookie(client, cookie, cookievalue, sizeof(cookievalue)); + + // Return string casted into an int, then to bool. + return bool:StringToInt(cookievalue); +} \ No newline at end of file diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index 2900ae6..f7d9032 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -88,11 +88,12 @@ enum CvarsList Handle:CVAR_INFECT_WEAPONS_DROP, Handle:CVAR_INFECT_MZOMBIE_RATIO, Handle:CVAR_INFECT_MZOMBIE_RESPAWN, - Handle:CVAR_INFECT_SOUND, - Handle:CVAR_INFECT_ESPLASH, + Handle:CVAR_INFECT_EXPLOSION, Handle:CVAR_INFECT_FIREBALL, Handle:CVAR_INFECT_SMOKE, Handle:CVAR_INFECT_SPARKS, + Handle:CVAR_INFECT_SOUND, + Handle:CVAR_INFECT_ESPLASH, Handle:CVAR_INFECT_SHAKE, Handle:CVAR_INFECT_SHAKE_AMP, Handle:CVAR_INFECT_SHAKE_FREQUENCY, @@ -280,9 +281,10 @@ CvarsCreate() g_hCvarsList[CVAR_INFECT_WEAPONS_DROP] = CreateConVar("zr_infect_weapons_drop", "1", "Force player to drop all weapons on infect, disabling this will strip weapons instead."); // Effects - g_hCvarsList[CVAR_INFECT_FIREBALL] = CreateConVar("zr_infect_fireball", "1", "Spawn a fireball effect around player on infection."); - g_hCvarsList[CVAR_INFECT_SMOKE] = CreateConVar("zr_infect_smoke", "1", "Spawn a smoke cloud effect around player on infection."); - g_hCvarsList[CVAR_INFECT_SPARKS] = CreateConVar("zr_infect_sparks", "1", "Emit sparks from player on infection."); + g_hCvarsList[CVAR_INFECT_EXPLOSION] = CreateConVar("zr_infect_explosion", "1", "Disabling this will disable the fireball, smoke cloud, and sparks in a more efficient way."); + g_hCvarsList[CVAR_INFECT_FIREBALL] = CreateConVar("zr_infect_fireball", "1", "Spawn a fireball effect around player on infection. [Dependency: zr_infect_explosion]"); + g_hCvarsList[CVAR_INFECT_SMOKE] = CreateConVar("zr_infect_smoke", "1", "Spawn a smoke cloud effect around player on infection. [Dependency: zr_infect_explosion]"); + g_hCvarsList[CVAR_INFECT_SPARKS] = CreateConVar("zr_infect_sparks", "1", "Emit sparks from player on infection. [Dependency: zr_infect_explosion]"); g_hCvarsList[CVAR_INFECT_SOUND] = CreateConVar("zr_infect_sound", "npc/fast_zombie/fz_scream1.wav", "Sound, relative to \"sounds\" folder, to play from player on infection. ['\"\"' = No sound]"); g_hCvarsList[CVAR_INFECT_ESPLASH] = CreateConVar("zr_infect_esplash", "1", "Emit an energy splash from player on infection."); g_hCvarsList[CVAR_INFECT_SHAKE] = CreateConVar("zr_infect_shake", "1", "Shake player's view on infect."); @@ -432,7 +434,7 @@ CvarsCreate() g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT] = CreateConVar("zr_zspawn_timelimit", "1", "Put a time limit on the use of ZSpawn."); g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_TIME] = CreateConVar("zr_zspawn_timelimit_time", "120.0", "Time from the start of the round to allow ZSpawn. [Dependency: zr_zspawn_timelimit]"); - g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_ZOMBIE] = CreateConVar("zr_zspawn_timelimit_zombie", "1", "Spawn player on the zombie team AFTER the timelimit is up. ['-1' = Block ZSpawn | '0' = Spawn as human | '1' = Spawn as zombie | Dependency: zr_zspawn_timelimit]"); + g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_ZOMBIE] = CreateConVar("zr_zspawn_timelimit_zombie", "1", "Spawn player on the zombie team AFTER the timelimit is up. ['-1' = Block ZSpawn | '0' = Spawn as human | '1' = Spawn as zombie | Dependency: zr_zspawn_timelimit]"); // =========================== diff --git a/src/zr/event.inc b/src/zr/event.inc index 9400637..4146b19 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -106,7 +106,6 @@ public Action:EventRoundStart(Handle:event, const String:name[], bool:dontBroadc public Action:EventRoundStartPost(Handle:timer, any:index) { // Forward event to modules. - WeaponsOnRoundStartPost(); } /** @@ -139,7 +138,6 @@ public Action:EventRoundEnd(Handle:event, const String:name[], bool:dontBroadcas new reason = GetEventInt(event, "reason"); // Forward event to modules. - WeaponsOnRoundEnd(); RoundEndOnRoundEnd(reason); InfectOnRoundEnd(); SEffectsOnRoundEnd(); @@ -224,6 +222,7 @@ public Action:EventPlayerSpawnPost(Handle:timer, any:index) } // Forward event to modules. + WeaponsOnClientSpawnPost(index); SpawnProtectOnClientSpawnPost(index); } diff --git a/src/zr/infect.inc b/src/zr/infect.inc index 969b0e2..ab5d6a8 100644 --- a/src/zr/infect.inc +++ b/src/zr/infect.inc @@ -726,6 +726,37 @@ InfectFireEffects(client) GetClientAbsOrigin(client, clientloc); clientloc[2] += 30; + new bool:explosion = GetConVarBool(g_hCvarsList[CVAR_INFECT_EXPLOSION]); + if (explosion) + { + // Initialize explosion flags variable. + new flags; + + // Set "nofireball" flag if fireball is disabled. + new bool:fireball = GetConVarBool(g_hCvarsList[CVAR_INFECT_FIREBALL]); + if (!fireball) + { + flags = flags | EXP_NOFIREBALL; + } + + // Set "nosmoke" flag if smoke is disabled. + new bool:smoke = GetConVarBool(g_hCvarsList[CVAR_INFECT_SMOKE]); + if (!smoke) + { + flags = flags | EXP_NOSMOKE; + } + + // Set "nosparks" flag if sparks are disabled. + new bool:sparks = GetConVarBool(g_hCvarsList[CVAR_INFECT_SPARKS]); + if (!sparks) + { + flags = flags | EXP_NOSPARKS; + } + + // Create explosion at client's origin. + VEffectsCreateExplosion(clientloc, flags); + } + // If cvar contains path, then continue. decl String:sound[PLATFORM_MAX_PATH]; GetConVarString(g_hCvarsList[CVAR_INFECT_SOUND], sound, sizeof(sound)); @@ -743,33 +774,6 @@ InfectFireEffects(client) VEffectsCreateEnergySplash(clientloc, direction, true); } - // Initialize explosion flags variable. - new flags; - - // Set "nofireball" flag if fireball is disabled. - new bool:fireball = GetConVarBool(g_hCvarsList[CVAR_INFECT_FIREBALL]); - if (!fireball) - { - flags = flags | EXP_NOFIREBALL; - } - - // Set "nosmoke" flag if smoke is disabled. - new bool:smoke = GetConVarBool(g_hCvarsList[CVAR_INFECT_SMOKE]); - if (!smoke) - { - flags = flags | EXP_NOSMOKE; - } - - // Set "nosparks" flag if sparks are disabled. - new bool:sparks = GetConVarBool(g_hCvarsList[CVAR_INFECT_SPARKS]); - if (!sparks) - { - flags = flags | EXP_NOSPARKS; - } - - // Create explosion at client's origin. - VEffectsCreateExplosion(clientloc, flags); - // If shake effect is enabled, then continue. new bool:shake = GetConVarBool(g_hCvarsList[CVAR_INFECT_SHAKE]); if (shake) diff --git a/src/zr/menu.inc b/src/zr/menu.inc index c409e76..bde8b33 100644 --- a/src/zr/menu.inc +++ b/src/zr/menu.inc @@ -168,7 +168,7 @@ public MenuMainHandle(Handle:menu, MenuAction:action, client, slot) case 5: { // Send ZMarket menu. - resend = !ZMarketMenuTypes(client); + resend = !ZMarketMenuMain(client); } } diff --git a/src/zr/overlays.inc b/src/zr/overlays.inc index 79fa079..bbeaf21 100644 --- a/src/zr/overlays.inc +++ b/src/zr/overlays.inc @@ -210,7 +210,7 @@ OverlaysClientUpdateOverlay(client, OverlaysChannel:channel = OVERLAYS_CHANNEL_N } // Display overlay to client. - ClientCommand(client, "r_screenoverlay %s", g_strOverlayPath[client][channel]); + ClientCommand(client, "r_screenoverlay \"%s\"", g_strOverlayPath[client][channel]); } OverlaysChannel:OverlaysClientFindChannel(client) @@ -236,8 +236,11 @@ OverlaysChannel:OverlaysClientFindChannel(client) * * @param client The client index. * @param channel The channel to change state of. - * @param toggle Set to true to toggle state, false to use value param. + * @param update (Optional) Update the overlay when this function is called. + * @param toggle (Optional) Set to true to toggle state, false to use value param. * @param value (Optional) New value of the state, only used if toggle is false. + * @param reset (Optional) Resets the channel path. + * @return The overlay's new state. */ bool:OverlaysClientSetChannelState(client, OverlaysChannel:channel, bool:update = false, bool:toggle = true, bool:value = false, bool:reset = false) { @@ -300,6 +303,12 @@ public Action:OverlaysTimer(Handle:timer) continue; } + // If no overlay is on the client's screen, then stop. + if (OverlaysClientFindChannel(x) == OVERLAYS_CHANNEL_NONE) + { + continue; + } + // Update client's overlay. OverlaysClientUpdateOverlay(x); } diff --git a/src/zr/playerclasses/classevents.inc b/src/zr/playerclasses/classevents.inc index f8a4eda..43f60bf 100644 --- a/src/zr/playerclasses/classevents.inc +++ b/src/zr/playerclasses/classevents.inc @@ -17,6 +17,24 @@ * ------------------------------------ */ +/** + * Create class-related cookies here. + */ +ClassOnCookiesCreate() +{ + // Forward event to sub-modules. + ClassOverlayOnCookiesCreate(); +} + +/** + * Called when all modules are done loading. + */ +ClassOnModulesLoaded() +{ + // Set default classes on all player slots. + ClassClientSetDefaultIndexes(); +} + /** * Called when a client connects to the server (OnClientPutInServer). */ @@ -35,15 +53,6 @@ ClassClientInit(client) ClassOverlayClientInit(client); } -/** - * Called when all modules are done loading. - */ -ClassOnModulesLoaded() -{ - // Set default classes on all player slots. - ClassClientSetDefaultIndexes(); -} - /** * Called a client disconnects. */ @@ -124,9 +133,6 @@ ClassOnClientSpawn(client) ClassReloadPlayerCache(client, ClassGetActiveIndex(client)); ClassApplyAttributes(client); } - - // Forward event to sub-modules. - ClassOverlayOnClientSpawn(client); } /** @@ -206,7 +212,4 @@ ClassOnClientInfected(client, bool:motherzombie = false) // Apply the new attributes. ClassApplyAttributes(client, motherzombie); - - // Forward event to sub-modules. - ClassOverlayOnClientInfected(client); } diff --git a/src/zr/playerclasses/clientoverlays.inc b/src/zr/playerclasses/clientoverlays.inc index 1605fce..77e53e7 100644 --- a/src/zr/playerclasses/clientoverlays.inc +++ b/src/zr/playerclasses/clientoverlays.inc @@ -33,26 +33,16 @@ /** * @endsection */ - -/** - * Array to store default class overlay enable flag. - */ -new bool:h_bClassOverlay[MAXPLAYERS + 1]; /** - * Client is joining the server. - * - * @param client The client index. + * Name of the cookie for toggle state the class overlay. */ -ClassOverlayClientInit(client) -{ - // Get overlay toggle cvar values. - new bool:overlaytoggle = GetConVarBool(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLE]); - new bool:overlaydefault = GetConVarBool(g_hCvarsList[CVAR_CLASSES_OVERLAY_DEFAULT]); - - // Apply default value if toggle is enabled, default to true if toggle is disabled. - h_bClassOverlay[client] = overlaytoggle ? overlaydefault : true; -} +#define CLASSOVERLAY_COOKIE_ENABLED "zr_overlay" + +/** + * Cookie handle for the toggle state of an overlay. + */ +new Handle:g_hOverlayEnabledCookie = INVALID_HANDLE; /** * Hook commands related to overlay here. @@ -79,28 +69,40 @@ ClassOverlayOnCommandsHook() } /** - * Client is spawning into the game. - * - * @param client The client index. + * Create class overlay-related cookies here. */ -ClassOverlayOnClientSpawn(client) +ClassOverlayOnCookiesCreate() { - // If overlay toggle is enabled and class has an overlay, then send center text. - new bool:overlaytoggle = GetConVarBool(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLE]); - - decl String:overlaypath[PLATFORM_MAX_PATH]; - ClassGetOverlayPath(client, overlaypath, sizeof(overlaypath)); - - if (overlaytoggle && overlaypath[0]) + // If cookie doesn't already exist, then create it. + g_hOverlayEnabledCookie = FindClientCookie(CLASSOVERLAY_COOKIE_ENABLED); + if (g_hOverlayEnabledCookie == INVALID_HANDLE) { - decl String:togglecmds[CLASSOVERLAY_TOGGLE_MAX_CMDS * CLASSOVERLAY_TOGGLE_MAX_LENGTH]; - GetConVarString(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLECMDS], togglecmds, sizeof(togglecmds)); - - TranslationPrintHUDText(client, "Classes overlay toggle", togglecmds); + g_hOverlayEnabledCookie = RegClientCookie(CLASSOVERLAY_COOKIE_ENABLED, "The toggle state of the class overlay.", CookieAccess_Public); } +} + +/** + * Client is joining the server. + * + * @param client The client index. + */ +ClassOverlayClientInit(client) +{ + // Get overlay toggle cvar values. + new bool:overlaytoggle = GetConVarBool(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLE]); + new bool:overlaydefault = GetConVarBool(g_hCvarsList[CVAR_CLASSES_OVERLAY_DEFAULT]); - // Update class overlay. - OverlaysClientUpdateOverlay(client, OVERLAYS_CHANNEL_CLASSES); + // Get ZHP enabled cookie value. + decl String:overlayenabled[8]; + GetClientCookie(client, g_hOverlayEnabledCookie, overlayenabled, sizeof(overlayenabled)); + + // If the cookie is empty, then set the default value. + if (!overlayenabled[0]) + { + // Set cookie to default value from cvar. + new bool:overlayvalue = overlaytoggle ? overlaydefault : true; + CookiesSetClientCookieBool(client, g_hOverlayEnabledCookie, overlayvalue); + } } /** @@ -114,28 +116,6 @@ ClassOverlayOnClientDeath(client) OverlaysClientSetChannelState(client, OVERLAYS_CHANNEL_CLASSES, true, false, false, true); } -/** - * Client has been infected. - * - * @param client The client index. - */ -ClassOverlayOnClientInfected(client) -{ - // If overlay toggle is enabled and class has an overlay, then send center text. - new bool:overlaytoggle = GetConVarBool(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLE]); - - decl String:overlaypath[PLATFORM_MAX_PATH]; - ClassGetOverlayPath(client, overlaypath, sizeof(overlaypath)); - - if (overlaytoggle && overlaypath[0]) - { - decl String:togglecmds[CLASSOVERLAY_TOGGLE_MAX_CMDS * CLASSOVERLAY_TOGGLE_MAX_LENGTH]; - GetConVarString(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLECMDS], togglecmds, sizeof(togglecmds)); - - TranslationPrintCenterText(client, "Classes overlay toggle", togglecmds); - } -} - ClassOverlayInitialize(client, const String:overlay[]) { if (IsFakeClient(client)) @@ -150,9 +130,23 @@ ClassOverlayInitialize(client, const String:overlay[]) return; } + // If overlay toggle is enabled and class has an overlay, then send center text. + new bool:overlaytoggle = GetConVarBool(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLE]); + + decl String:overlaypath[PLATFORM_MAX_PATH]; + ClassGetOverlayPath(client, overlaypath, sizeof(overlaypath)); + + if (overlaytoggle && overlaypath[0]) + { + decl String:togglecmds[CLASSOVERLAY_TOGGLE_MAX_CMDS * CLASSOVERLAY_TOGGLE_MAX_LENGTH]; + GetConVarString(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLECMDS], togglecmds, sizeof(togglecmds)); + + TranslationPrintHUDText(client, "Classes overlay toggle", togglecmds); + } + // Display class overlays. OverlaysClientSetChannelPath(client, OVERLAYS_CHANNEL_CLASSES, overlay); - OverlaysClientSetChannelState(client, OVERLAYS_CHANNEL_CLASSES, true, false, h_bClassOverlay[client]); + OverlaysClientSetChannelState(client, OVERLAYS_CHANNEL_CLASSES, true, false, CookiesGetClientCookieBool(client, g_hOverlayEnabledCookie)); } /** @@ -171,6 +165,7 @@ public Action:ClassOverlayEnableCommand(client, argc) return; } - // Toggle current overlay channel, and retrieve new value. - h_bClassOverlay[client] = OverlaysClientSetChannelState(client, OVERLAYS_CHANNEL_CLASSES, true, true); + // Toggle current overlay channel, retrieve new value, and update cookie. + new bool:overlayenabled = OverlaysClientSetChannelState(client, OVERLAYS_CHANNEL_CLASSES, true, true); + CookiesSetClientCookieBool(client, g_hOverlayEnabledCookie, overlayenabled); } diff --git a/src/zr/roundend.inc b/src/zr/roundend.inc index c88e51f..83ae80a 100644 --- a/src/zr/roundend.inc +++ b/src/zr/roundend.inc @@ -109,6 +109,9 @@ RoundEndOnClientInfected() */ RoundEndOnRoundStart() { + // Stop all overlays. + RoundEndOverlayStop(); + // If round end timer is running, then kill it. if (tRoundEnd != INVALID_HANDLE) { @@ -160,7 +163,7 @@ RoundEndOnRoundEnd(reason) new RoundEndOutcome:outcome = RoundEndReasonToOutcome(reason); // Display the overlay to all clients. - RoundEndOverlayStart(ROUNDEND_DELAY, outcome); + RoundEndOverlayStart(outcome); // Balance teams. RoundEndBalanceTeams(); @@ -355,7 +358,7 @@ RoundEndBalanceTeams() * @param time Time to display overlays. * @param outcome The outcome of the round. */ -RoundEndOverlayStart(Float:time, RoundEndOutcome:outcome) +RoundEndOverlayStart(RoundEndOutcome:outcome) { // If round end overlays are disabled, then stop. new bool:overlay = GetConVarBool(g_hCvarsList[CVAR_ROUNDEND_OVERLAY]); @@ -403,8 +406,6 @@ RoundEndOverlayStart(Float:time, RoundEndOutcome:outcome) OverlaysClientSetChannelPath(x, OVERLAYS_CHANNEL_ROUNDEND, overlaypath); OverlaysClientSetChannelState(x, OVERLAYS_CHANNEL_ROUNDEND, true, false, true); } - - CreateTimer(time, RoundEndOverlayTimer, _, TIMER_FLAG_NO_MAPCHANGE); } RoundEndOverlayStop() @@ -427,15 +428,4 @@ RoundEndOverlayStop() // Disable roundend overlay channel. OverlaysClientSetChannelState(x, OVERLAYS_CHANNEL_ROUNDEND, true, false, false, true); } -} - -/** - * Timer callback, stops overlays on all clients. - * - * @param timer The timer handle. - */ -public Action:RoundEndOverlayTimer(Handle:timer) -{ - // Stop all overlays. - RoundEndOverlayStop(); -} +} \ No newline at end of file diff --git a/src/zr/serial.inc b/src/zr/serial.inc deleted file mode 100644 index f2f8d8c..0000000 --- a/src/zr/serial.inc +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ============================================================================ - * - * Zombie:Reloaded - * - * File: serial.inc - * Type: Core - * Description: Client serial number tracking API. - * - * Copyright (C) 2009 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 . - * - * ============================================================================ - */ - -/** - * Maximum length of a client's serial number. - */ -#define SERIAL_MAX_LENGTH 8 - -/** - * Array to store client serial numbers. - */ -new Handle:arraySerial = INVALID_HANDLE; - -/** - * Map is starting. -*/ -SerialOnMapStart() -{ - // If array exists, destroy before recreating. - if (arraySerial != INVALID_HANDLE) - { - CloseHandle(arraySerial); - } - - // Create array. - arraySerial = CreateArray(); -} - -/** - * Add client serial number to global array. - * - * @param client The client index. - * @return True if the client was added successfully, false if the client already exists. - */ -bool:SerialAddClient(client) -{ - // Check if client is already added. - new bool:exists = SerialClientExists(client); - if (exists) - { - return false; - } - - // Get client's serial number. - new serial = GetClientSerial(client); - - // Push serial number into the global array. - PushArrayCell(arraySerial, serial); - - // Client added successfully. - return true; -} - -/** - * Check if a client has been added to the global array. - * - * @param client The client index. - * @return True if the client exists, false otherwise. - */ -bool:SerialClientExists(client) -{ - // Get client's serial number. - new serial = GetClientSerial(client); - - // Return true if value was found, false otherwise. - return (FindValueInArray(arraySerial, serial) != -1); -} - -/** - * Reset serial number array. - */ -SerialReset() -{ - // Clear array. - ClearArray(arraySerial); -} diff --git a/src/zr/steamidcache.inc b/src/zr/steamidcache.inc new file mode 100644 index 0000000..ad7c173 --- /dev/null +++ b/src/zr/steamidcache.inc @@ -0,0 +1,96 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: steamidcache.inc + * Type: Core + * Description: A SteamID caching API. + * + * Copyright (C) 2009 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 . + * + * ============================================================================ + */ + +/** + * The maximum length of a SteamID + */ +#define STEAMIDCACHE_MAX_LENGTH 16 + +/** + * Creates a steamid cache. + * + * @return Handle to SteamID cache. + */ +stock Handle:SteamidCacheCreate() +{ + // Return steamid cache handle. + return CreateArray(STEAMIDCACHE_MAX_LENGTH); +} + +/** + * Add client serial number to the SteamID cache. + * + * @param steamidcache The SteamID cache to add client to. + * @param client The client index. + * @return True if the client was added successfully, false if the client already exists. + */ +stock bool:SteamidCacheAddClient(Handle:steamidcache, client) +{ + // Check if client is in the cache. + if (SteamidCacheClientExists(steamidcache, client)) + { + return false; + } + + // Get client's SteamID. + decl String:steamid[STEAMIDCACHE_MAX_LENGTH]; + GetClientAuthString(client, steamid, sizeof(steamid)); + + // Push SteamID into the SteamID cache. + PushArrayString(steamidcache, steamid); + + // Client added successfully. + return true; +} + +/** + * Check if a client is in the SteamID cache. + * + * @param steamidcache The SteamID cache to check in. + * @param client The client index. + * @return True if the client exists, false otherwise. + */ +stock bool:SteamidCacheClientExists(Handle:steamidcache, client) +{ + // Get client's SteamID. + decl String:steamid[STEAMIDCACHE_MAX_LENGTH]; + GetClientAuthString(client, steamid, sizeof(steamid)); + + // Return true if client was found, false otherwise. + return (FindStringInArray(steamidcache, steamid) != -1); +} + +/** + * Reset SteamID cache. + * + * @param steamidcache The SteamID cache to reset. + */ +stock SteamidCacheReset(Handle:steamidcache) +{ + // Clear array. + ClearArray(steamidcache); +} diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index 17c07cc..1b71e42 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -581,8 +581,8 @@ public ZRTools_Action:RestrictCanUse(client, weapon) return ZRTools_Handled; } - // Forward event to modules. (item pickup) - WeaponAlphaOnItemPickup(client, weapon); + // Forward event to weapons module. + WeaponsOnItemPickup(client, weapon); // Allow pickup. return ZRTools_Continue; diff --git a/src/zr/weapons/weaponalpha.inc b/src/zr/weapons/weaponalpha.inc index 3f33240..0485092 100644 --- a/src/zr/weapons/weaponalpha.inc +++ b/src/zr/weapons/weaponalpha.inc @@ -35,11 +35,6 @@ */ new g_iWeaponDropHookID[MAXPLAYERS + 1] = {-1, ...}; -/** - * Global variable that stops render mode modifying - */ -new bool:g_bWeaponAlpha; - /** * Client is joining the server. * @@ -66,40 +61,14 @@ WeaponAlphaOnClientDisconnect(client) } } -/** - * The round is starting. - */ -WeaponAlphaOnRoundStartPost() -{ - // Allow weapon render mode to be modified. - g_bWeaponAlpha = true; -} - -/** - * The round is ending. - * - * @param reason Reason the round has ended. - */ -WeaponAlphaOnRoundEnd() -{ - // Disallow weapon render mode to be modified. - g_bWeaponAlpha = false; -} - /** * Client has just picked up a weapon. * * @param client The client index. * @param weapon The weapon index. */ -WeaponAlphaOnItemPickup(client, weapon) +WeaponAlphaOnItemPickupPost(client, weapon) { - // If weapon alpha updating is disabled, then stop. - if (!g_bWeaponAlpha) - { - return; - } - // Get client's current alpha. new alpha = ToolsGetEntityAlpha(client); @@ -116,12 +85,6 @@ WeaponAlphaOnItemPickup(client, weapon) */ public ZRTools_Action:WeaponAlphaDrop(client, weapon) { - // If weapon alpha updating is disabled, then stop. - if (!g_bWeaponAlpha) - { - return; - } - // If weapon isn't a valid entity, then stop. if (weapon < MaxClients) { diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index 6921d64..a92374b 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -88,7 +88,7 @@ new Handle:arrayWeapons = INVALID_HANDLE; /** * Weapons module init function. - */ + */ WeaponsInit() { // Forward event to sub-modules. @@ -121,6 +121,15 @@ WeaponsOnCommandsCreate() ZMarketOnCommandsCreate(); } +/** + * Create weapon-related cookies here. + */ +WeaponsOnCookiesCreate() +{ + // Forward event to sub-modules. + ZMarketOnCookiesCreate(); +} + /** * Loads weapon data from file. */ @@ -303,27 +312,67 @@ WeaponsOnClientSpawn(client) { // Forward event to sub-modules. RestrictOnClientSpawn(client); - ZMarketOnClientSpawn(client); } /** - * The round is starting. - */ -WeaponsOnRoundStartPost() -{ - // Forward event to sub-modules - WeaponAlphaOnRoundStartPost(); -} - -/** - * The round is ending. + * Client is spawning into the game. *Post * - * @param reason Reason the round has ended. + * @param client The client index. */ -WeaponsOnRoundEnd() +WeaponsOnClientSpawnPost(client) { - // Forward event to sub-modules - WeaponAlphaOnRoundEnd(); + // Forward event to sub-modules. + ZMarketOnClientSpawnPost(client); +} + +/** + * Called when a client picks up an item. + * + * @param client The client index. + * @param weapon The weapon index. + */ +WeaponsOnItemPickup(client, weapon) +{ + // Forward event to sub-modules. + + // Fire post OnItemPickup event. + + // Fill datapack with event information. + new Handle:eventinfo = CreateDataPack(); + WritePackCell(eventinfo, client); + WritePackCell(eventinfo, weapon); + + // Create post delay timer. + CreateTimer(0.0, WeaponsOnItemPickupPost, eventinfo); +} + +/** + * Called when a client picks up an item. *Post + * + * @param client The client index. + * @param weapon The weapon index. + */ +public Action:WeaponsOnItemPickupPost(Handle:timer, Handle:eventinfo) +{ + // Get event info. + ResetPack(eventinfo); + new client = ReadPackCell(eventinfo); + new weapon = ReadPackCell(eventinfo); + + // If client isn't in the game anymore, then stop. + if (!IsClientInGame(client)) + { + return; + } + + // If the weapon entity isn't valid anymore, then stop. + if (!IsValidEdict(weapon)) + { + return; + } + + // Forward event to sub-modules. + WeaponAlphaOnItemPickupPost(client, weapon); } /** @@ -371,6 +420,32 @@ stock WeaponsNameToIndex(const String:weapon[]) return -1; } +/** + * Takes a weapon's classname and returns the display name in weapons config file. + * + * @param + */ +stock WeaponsClassnameToDisplay(String:classname[], classnamemaxlen, String:display[], displaymaxlen) +{ + // Strip off classnames' weapon prefix. + ReplaceString(classname, classnamemaxlen, "weapon_", ""); + ReplaceString(classname, classnamemaxlen, "item_", ""); + + // Get the index of the weapon. + new weaponindex = WeaponsNameToIndex(classname); + + // If weapon index is invalid, then return an empty string. + if (weaponindex == -1) + { + // Return an empty string. + strcopy(display, displaymaxlen, ""); + return; + } + + // Return the display name. + WeaponsGetName(weaponindex, display, displaymaxlen); +} + /** * Checks if a weapon is valid. (E.G. listed in weapons.txt) * @param weapon The weapon name. diff --git a/src/zr/weapons/zmarket.inc b/src/zr/weapons/zmarket.inc index d342a35..a388315 100644 --- a/src/zr/weapons/zmarket.inc +++ b/src/zr/weapons/zmarket.inc @@ -25,6 +25,15 @@ * ============================================================================ */ +/** + * @section Name of the cookies for ZMarket rebuy/auto-rebuy data. + */ +#define ZMARKET_COOKIE_AUTOREBUY "zr_zmarket_autorebuy" +#define ZMARKET_COOKIE_REBUY "zr_zmarket_rebuy" +/** + * @endsection + */ + /** * Variable to store buyzone offset value. */ @@ -41,14 +50,9 @@ new g_iZMarketCurType[MAXPLAYERS + 1]; new Handle:g_hZMarketPurchaseCount[MAXPLAYERS + 1]; /** - * Array to store a weapon of each type last purchased from ZMarket. + * Cookie handle for auti-rebuy. */ -new String:g_strZMarketLastWeapon[MAXPLAYERS + 1][WeaponsSlot][WEAPONS_MAX_LENGTH]; - -/** - * Array to store clients' auto-rebuy setting. - */ -new bool:g_bZMarketAutoRebuy[MAXPLAYERS + 1]; +new Handle:g_hZMarketAutoRebuyCookie = INVALID_HANDLE; /** * Create commands specific to ZMarket. @@ -59,6 +63,30 @@ ZMarketOnCommandsCreate() RegConsoleCmd(SAYHOOKS_KEYWORD_ZMARKET, ZMarketCommand, "Opens custom buymenu."); } +ZMarketOnCookiesCreate() +{ + // If auto-rebuy cookie doesn't already exist, then create all ZMarket cookies. + g_hZMarketAutoRebuyCookie = FindClientCookie(ZMARKET_COOKIE_AUTOREBUY); + if (g_hZMarketAutoRebuyCookie == INVALID_HANDLE) + { + g_hZMarketAutoRebuyCookie = RegClientCookie(ZMARKET_COOKIE_AUTOREBUY, "The toggle state of auto-rebuy.", CookieAccess_Public); + + decl String:rebuycookiename[32]; + decl String:rebuycookiedesc[64]; + + // x = Weapon slot. + for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) + { + // Format cookie name and description. + Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, x); + Format(rebuycookiedesc, sizeof(rebuycookiedesc), "Current loadout weapon for slot %d", x); + + // Register client cookie. + RegClientCookie(rebuycookiename, rebuycookiedesc, CookieAccess_Public); + } + } +} + /** * Find ZMarket-specific offsets here. */ @@ -89,7 +117,15 @@ ZMarketClientInit(client) g_hZMarketPurchaseCount[client] = CreateTrie(); // Initialize auto-rebuy data. - g_bZMarketAutoRebuy[client] = false; + decl String:zmarketautorebuy[8]; + GetClientCookie(client, g_hZMarketAutoRebuyCookie, zmarketautorebuy, sizeof(zmarketautorebuy)); + + // If the cookie is empty, then set the default value. + if (!zmarketautorebuy[0]) + { + // Set cookie to false. + CookiesSetClientCookieBool(client, g_hZMarketAutoRebuyCookie, false); + } } /** @@ -114,13 +150,19 @@ ZMarketOnClientDisconnect(client) * * @param client The client index. */ -ZMarketOnClientSpawn(client) +ZMarketOnClientSpawnPost(client) { // Reset purchase counts for client. ZMarketResetPurchaseCount(client); + // If client hasn't spawned into the game yet, then stop. + if (!IsPlayerAlive(client)) + { + return; + } + // If auto-rebuy is enabled, then force client to rebuy weapons. - if (g_bZMarketAutoRebuy[client]) + if (CookiesGetClientCookieBool(client, g_hZMarketAutoRebuyCookie)) { ZMarketRebuy(client, true); } @@ -175,11 +217,12 @@ ZMarketGetPurchaseCount(client, const String:weapon[]) } /** - * Sends weapon type list to client. + * Sends main ZMarket menu to client. + * * @param client The client index. * @return True if the menu was sent successfully, false if not. */ -bool:ZMarketMenuTypes(client) +bool:ZMarketMenuMain(client) { // If weapons module is disabled, then stop. new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); @@ -199,6 +242,245 @@ bool:ZMarketMenuTypes(client) return false; } + // Create menu handle. + new Handle:menu_zmarket_main = CreateMenu(ZMarketMenuMainHandle); + + // Set translation target as client. + SetGlobalTransTarget(client); + + // Set menu title. + SetMenuTitle(menu_zmarket_main, "%t\n ", "Weapons menu zmarket main title"); + + // If rebuy is enabled, then add it to the menu. + new bool:zmarketrebuy = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY]); + new bool:zmarketrebuyauto = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_AUTO]); + + // Add "Get Current Loadout" option. + decl String:getloadout[WEAPONS_MAX_LENGTH]; + decl String:viewloadout[WEAPONS_MAX_LENGTH]; + decl String:rebuy[WEAPONS_MAX_LENGTH]; + decl String:rebuyauto[WEAPONS_MAX_LENGTH]; + decl String:weaponslist[WEAPONS_MAX_LENGTH]; + + // Get auto-rebuy setting. + decl String:rebuyautosetting[8]; + ConfigBoolToSetting(CookiesGetClientCookieBool(client, g_hZMarketAutoRebuyCookie), rebuyautosetting, sizeof(rebuyautosetting)); + + // Format menu options. + Format(getloadout, sizeof(getloadout), "%t", "Weapons menu zmarket main get loadout"); + Format(viewloadout, sizeof(viewloadout), "%t", "Weapons menu zmarket main view loadout"); + Format(rebuy, sizeof(rebuy), "%t", "Weapons menu zmarket main rebuy"); + Format(rebuyauto, sizeof(rebuyauto), "%t", "Weapons menu zmarket main auto-rebuy", rebuyautosetting); + Format(weaponslist, sizeof(weaponslist), "%t", "Weapons menu zmarket main weapons list"); + + // Add formatted options to menu. + AddMenuItem(menu_zmarket_main, "Get Loadout", getloadout, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto)); + AddMenuItem(menu_zmarket_main, "View Loadout", viewloadout, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto)); + AddMenuItem(menu_zmarket_main, "Rebuy", rebuy, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto)); + AddMenuItem(menu_zmarket_main, "Auto-Rebuy", rebuyauto, MenuGetItemDraw(zmarketrebuyauto)); + AddMenuItem(menu_zmarket_main, "Weapons List", weaponslist); + + // Set exit back button. + SetMenuExitBackButton(menu_zmarket_main, true); + + DisplayMenu(menu_zmarket_main, client, MENU_TIME_FOREVER); + + // Menu sent successfully. + return true; +} + +/** + * Called when client selects option in the main ZMarket menu, and handles it. + * + * @param menu_zmarket_main Handle of the menu being used. + * @param action The action done on the menu (see menus.inc, enum MenuAction). + * @param client The client index. + * @param slot The slot index selected (starting from 0). + */ +public ZMarketMenuMainHandle(Handle:menu_zmarket_main, MenuAction:action, client, slot) +{ + // Client selected an option. + if (action == MenuAction_Select) + { + switch(slot) + { + // Get loadout. + case 0: + { + // Gets a client's current loadout. + ZMarketGetCurrentLoadout(client); + + // Resend menu. + ZMarketMenuMain(client); + } + // View loadout. + case 1: + { + // Show a client their current loadout. + ZMarketMenuLoadout(client); + } + // Rebuy. + case 2: + { + // Force client to rebuy weapons. + ZMarketRebuy(client); + + // Resend menu. + ZMarketMenuMain(client); + } + // Auto-rebuy. + case 3: + { + // Toggle rebuy. + new bool:autorebuyenabled = CookiesGetClientCookieBool(client, g_hZMarketAutoRebuyCookie); + CookiesSetClientCookieBool(client, g_hZMarketAutoRebuyCookie, !autorebuyenabled); + + // Resend menu. + ZMarketMenuMain(client); + } + // Weapons list. + case 4: + { + // Send the weapon types list. + ZMarketMenuTypes(client); + } + } + } + // Client closed the menu. + if (action == MenuAction_Cancel) + { + // Client hit "Back" button. + if (slot == MenuCancel_ExitBack) + { + MenuMain(client); + } + } + // Client hit "Exit" button. + else if (action == MenuAction_End) + { + CloseHandle(menu_zmarket_main); + } +} + +/** + * Sends list of weapons in a client's loadout to the client. + * + * @param client The client index. + */ +bool:ZMarketMenuLoadout(client) +{ + // Create menu handle. + new Handle:menu_zmarket_loadout = CreateMenu(ZMarketMenuLoadoutHandle); + + // Set translation target as client. + SetGlobalTransTarget(client); + + // Set menu title. + SetMenuTitle(menu_zmarket_loadout, "%t\n ", "Weapons menu zmarket loadout title"); + + decl String:primaryweapon[WEAPONS_MAX_LENGTH]; + decl String:secondaryweapon[WEAPONS_MAX_LENGTH]; + decl String:meleeweapon[WEAPONS_MAX_LENGTH]; + decl String:projectileweapon[WEAPONS_MAX_LENGTH]; + decl String:explosiveweapon[WEAPONS_MAX_LENGTH]; + + // Transfer cookie values into an array. + new String:rebuyweapons[WeaponsSlot][WEAPONS_MAX_LENGTH]; + ZMarketCookiesToArray(client, rebuyweapons, WEAPONS_SLOTS_MAX, sizeof(rebuyweapons[])); + + // Return the display name for all the client's weapon classname's. + WeaponsClassnameToDisplay(rebuyweapons[Slot_Primary], sizeof(rebuyweapons[]), primaryweapon, sizeof(primaryweapon)); + WeaponsClassnameToDisplay(rebuyweapons[Slot_Secondary], sizeof(rebuyweapons[]), secondaryweapon, sizeof(secondaryweapon)); + WeaponsClassnameToDisplay(rebuyweapons[Slot_Melee], sizeof(rebuyweapons[]), meleeweapon, sizeof(meleeweapon)); + WeaponsClassnameToDisplay(rebuyweapons[Slot_Projectile], sizeof(rebuyweapons[]), projectileweapon, sizeof(projectileweapon)); + WeaponsClassnameToDisplay(rebuyweapons[Slot_Explosive], sizeof(rebuyweapons[]), explosiveweapon, sizeof(explosiveweapon)); + + // Get the empty translation. + decl String:empty[64]; + Format(empty, sizeof(empty), "%t", "Weapons menu zmarket loadout empty"); + + // If the client doesn't have a weapon in this slot, then set the weapon to the empty translation. + if (!primaryweapon[0]) + { + strcopy(primaryweapon, sizeof(primaryweapon), empty); + } + if (!secondaryweapon[0]) + { + strcopy(secondaryweapon, sizeof(secondaryweapon), empty); + } + if (!meleeweapon[0]) + { + strcopy(meleeweapon, sizeof(meleeweapon), empty); + } + if (!projectileweapon[0]) + { + strcopy(projectileweapon, sizeof(projectileweapon), empty); + } + if (!explosiveweapon[0]) + { + strcopy(explosiveweapon, sizeof(explosiveweapon), empty); + } + + decl String:primary[64]; + decl String:secondary[64]; + decl String:melee[64]; + decl String:projectile[64]; + decl String:explosive[64]; + + // Format all the lines of the menu. + Format(primary, sizeof(primary), "%t", "Weapons menu zmarket loadout primary", primaryweapon); + Format(secondary, sizeof(secondary), "%t", "Weapons menu zmarket loadout secondary", secondaryweapon); + Format(melee, sizeof(melee), "%t", "Weapons menu zmarket loadout melee", meleeweapon); + Format(projectile, sizeof(projectile), "%t", "Weapons menu zmarket loadout projectile", projectileweapon); + Format(explosive, sizeof(explosive), "%t", "Weapons menu zmarket loadout explosive", explosiveweapon); + + // Add formatted options to menu. + AddMenuItem(menu_zmarket_loadout, primary, primary, ITEMDRAW_DISABLED); + AddMenuItem(menu_zmarket_loadout, secondary, secondary, ITEMDRAW_DISABLED); + AddMenuItem(menu_zmarket_loadout, melee, melee, ITEMDRAW_DISABLED); + AddMenuItem(menu_zmarket_loadout, projectile, projectile, ITEMDRAW_DISABLED); + AddMenuItem(menu_zmarket_loadout, explosive, explosive, ITEMDRAW_DISABLED); + + // Set exit back button. + SetMenuExitBackButton(menu_zmarket_loadout, true); + + // Send menu to client. + DisplayMenu(menu_zmarket_loadout, client, MENU_TIME_FOREVER); +} + +/** + * Allow the user to press the "Back" button to go to main ZMarket menu. + * + * @param menu_zmarket_loadout Handle of the menu being used. + * @param action The action done on the menu (see menus.inc, enum MenuAction). + * @param client The client index. + * @param slot The slot index selected (starting from 0). + */ +public ZMarketMenuLoadoutHandle(Handle:menu_zmarket_loadout, MenuAction:action, client, slot) +{ + // Client closed the menu. + if (action == MenuAction_Cancel) + { + // Client hit "Back" button. + if (slot == MenuCancel_ExitBack) + { + ZMarketMenuMain(client); + } + } + // Client hit "Exit" button. + else if (action == MenuAction_End) + { + CloseHandle(menu_zmarket_loadout); + } +} + +/** + * Sends weapon type list to client. + * + * @param client The client index. + */ +ZMarketMenuTypes(client) +{ // Create menu handle. new Handle:menu_zmarket_types = CreateMenu(ZMarketMenuTypesHandle); @@ -208,32 +490,6 @@ bool:ZMarketMenuTypes(client) // Set menu title. SetMenuTitle(menu_zmarket_types, "%t\n ", "Weapons menu zmarket types title"); - // If rebuy is enabled, then add it to the menu. - new bool:zmarketrebuy = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY]); - new bool:zmarketrebuyauto = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_AUTO]); - - // If rebuy or auto-rebuy is enabled, then add it to the menu. - if (zmarketrebuy || zmarketrebuyauto) - { - // Add "Rebuy" option. - decl String:rebuy[WEAPONS_MAX_LENGTH]; - Format(rebuy, sizeof(rebuy), "%t", "Weapons menu zmarket types rebuy"); - AddMenuItem(menu_zmarket_types, "Rebuy", rebuy); - } - - // If auto-rebuy is enabled, then add it to the menu. - if (zmarketrebuyauto) - { - // Get current auto-rebuy setting. - decl String:rebuyautosetting[8]; - ConfigBoolToSetting(g_bZMarketAutoRebuy[client], rebuyautosetting, sizeof(rebuyautosetting)); - - // Add "Auto-Rebuy" option. - decl String:rebuyauto[WEAPONS_MAX_LENGTH]; - Format(rebuyauto, sizeof(rebuyauto), "%t", "Weapons menu zmarket types auto-rebuy", rebuyautosetting); - AddMenuItem(menu_zmarket_types, "Auto-Rebuy", rebuyauto); - } - decl String:typename[WEAPONS_MAX_LENGTH]; // x = Array index. @@ -260,13 +516,11 @@ bool:ZMarketMenuTypes(client) SetMenuExitBackButton(menu_zmarket_types, true); DisplayMenu(menu_zmarket_types, client, MENU_TIME_FOREVER); - - // Menu sent successfully. - return true; } /** * Called when client selects option in the weapons list menu, and handles it. + * * @param menu_zmarket_types Handle of the menu being used. * @param action The action done on the menu (see menus.inc, enum MenuAction). * @param client The client index. @@ -280,28 +534,6 @@ public ZMarketMenuTypesHandle(Handle:menu_zmarket_types, MenuAction:action, clie decl String:weapontype[WEAPONS_MAX_LENGTH]; GetMenuItem(menu_zmarket_types, slot, weapontype, sizeof(weapontype)); - if (StrEqual(weapontype, "Rebuy")) - { - // Force client to rebuy weapons. - ZMarketRebuy(client); - - // Resend menu. - ZMarketMenuTypes(client); - - return; - } - - if (StrEqual(weapontype, "Auto-Rebuy")) - { - // Toggle rebuy. - g_bZMarketAutoRebuy[client] = !g_bZMarketAutoRebuy[client]; - - // Resend menu. - ZMarketMenuTypes(client); - - return; - } - // Get weapon index. new weapontypeindex = RestrictTypeToIndex(weapontype); @@ -326,7 +558,7 @@ public ZMarketMenuTypesHandle(Handle:menu_zmarket_types, MenuAction:action, clie // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { - MenuMain(client); + ZMarketMenuMain(client); } } // Client hit "Exit" button. @@ -338,6 +570,7 @@ public ZMarketMenuTypesHandle(Handle:menu_zmarket_types, MenuAction:action, clie /** * Sends a list of weapons of a certain type in a menu to the client. + * * @param client The client index. */ ZMarketMenuTypeWeapons(client) @@ -455,6 +688,7 @@ ZMarketMenuTypeWeapons(client) /** * Called when client selects option in the weapon group menu, and handles it. + * * @param menu_zmarket_typeweapons Handle of the menu being used. * @param action The action done on the menu (see menus.inc, enum MenuAction). * @param client The client index. @@ -498,37 +732,44 @@ public ZMarketMenuTypeWeaponsHandle(Handle:menu_zmarket_typeweapons, MenuAction: * Equip a weapon on a client. * * @param client The client index. - * @param weapon The weapon to equip (must be in weapons config file) + * @param weapon The weapon to equip. (must be in weapons config file) * @param rebuy (Optional) If client is rebuying, ammo will be ignored. */ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) { - // If client is a zombie, then stop. - if (InfectIsClientInfected(client)) - { - TranslationPrintToChat(client, "Must be human"); - return false; - } - - new bool:zmarketbuyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); - if (!rebuy && zmarketbuyzone && !ZMarketIsClientInBuyZone(client)) - { - TranslationPrintToChat(client, "Weapons zmarket buyzone"); - return false; - } - // Get weapon index. new weaponindex = WeaponsNameToIndex(weapon); // If weapon index is -1, then something went very wrong. if (weaponindex == -1) { + LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Weapons, "ZMarket Equip", "Invalid weapon (%s) selected from the ZMarket menu.", weapon); return false; } // Get slot index of the weapon being purchased. new WeaponsSlot:slot = WeaponsGetSlot(weaponindex); + // If client is a zombie, then update weapon loadout and stop. + if (InfectIsClientInfected(client)) + { + // Update cookie with new weapon. + ZMarketSetRebuyCookie(client, slot, weapon); + + TranslationPrintToChat(client, "Weapons zmarket updated loadout"); + return false; + } + + new bool:zmarketbuyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); + if (!rebuy && zmarketbuyzone && !ZMarketIsClientInBuyZone(client)) + { + // Update cookie with new weapon. + ZMarketSetRebuyCookie(client, slot, weapon); + + TranslationPrintToChat(client, "Weapons zmarket updated loadout"); + return false; + } + // Get the appropriate price of the item being purchased. new bool:hasweapon = WeaponsClientHasWeapon(client, weapon); new itemprice = (hasweapon && slot != Slot_Invalid && slot != Slot_Projectile) ? WeaponsGetAmmoPrice(weaponindex) : WeaponsGetZMarketPrice(weaponindex); @@ -545,7 +786,10 @@ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) // If client doesn't have enough money, tell them, resend menu, and then stop. if (cash < itemprice) { - TranslationPrintToChat(client, "Not enough money"); + // Update cookie with new weapon. + ZMarketSetRebuyCookie(client, slot, weapon); + + TranslationPrintToChat(client, "Weapons zmarket updated loadout"); return false; } @@ -605,8 +849,8 @@ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) // Give client the weapon. GivePlayerItem(client, weaponentity); - // Copy weapon to array for this slot. - strcopy(g_strZMarketLastWeapon[client][slot], sizeof(g_strZMarketLastWeapon), weapon); + // Update cookie with new weapon. + ZMarketSetRebuyCookie(client, slot, weapon); // Add 1 to the client's purchase count. ZMarketSetPurchaseCount(client, weapon, 1, true); @@ -636,12 +880,133 @@ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) return true; } +/** + * Gets the client's current weapons and puts them in the rebuy cache. + * + * @param client The client index. + * @return True if the menu sent successfully, false if not. + */ +bool:ZMarketGetCurrentLoadout(client) +{ + // If client is dead, then tell them they must be alive and stop. + if (!IsPlayerAlive(client)) + { + TranslationPrintToChat(client, "Must be alive"); + return false; + } + + // If client is a zombie, then tell them they must be human and stop. + if (!IsPlayerAlive(client)) + { + TranslationPrintToChat(client, "Must be human"); + return false; + } + + // Get all of client's current weapons. + new weapons[WeaponsSlot]; + WeaponsGetClientWeapons(client, weapons); + + decl String:weaponname[WEAPONS_MAX_LENGTH]; + + // x = Weapon slot. + for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) + { + // If slot is empty, then clear this slot in rebuy cache and stop. + if (weapons[x] == -1) + { + // Empty rebuy slot. + ZMarketSetRebuyCookie(client, WeaponsSlot:x, ""); + continue; + } + + // Get the name of the weapon. + GetEdictClassname(weapons[x], weaponname, sizeof(weaponname)); + ReplaceString(weaponname, sizeof(weaponname), "weapon_", ""); + + // Copy the name to the rebuy cache. + ZMarketSetRebuyCookie(client, WeaponsSlot:x, weaponname); + } + + // Tell client their loadout has been updated. + TranslationPrintToChat(client, "Weapons zmarket get current loadout"); + + return true; +} + +/** + * Transfer array values to rebuy cookies. + * + * @param client The client index. + * @param rebuyweapons The string array to copy results from. + * @param maxweapons The max amount of weapons in the array. + * @param maxlen The max length of each cookie result. + */ +stock ZMarketArrayToCookies(client, String:rebuyweapons[WeaponsSlot][], maxweapons, maxlen) +{ + decl String:rebuycookiename[32]; + new Handle:rebuycookie; + + // x = Weapon slot. + for (new x = 0; x < maxweapons; x++) + { + // Format cookie name. + Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, x); + + // Find cookie handle, and retrieve its value. + rebuycookie = FindClientCookie(rebuycookiename); + SetClientCookie(client, rebuycookie, rebuyweapons[x]); + } +} + +/** + * Transfer rebuy cookies to an array for easier access. + * + * @param client The client index. + * @param rebuyweapons The string array to copy results to + * @param maxweapons The max amount of weapons in the array. + * @param maxlen The max length of each cookie result. + */ +stock ZMarketCookiesToArray(client, String:rebuyweapons[WeaponsSlot][], maxweapons, maxlen) +{ + decl String:rebuycookiename[32]; + new Handle:rebuycookie; + + // x = Weapon slot. + for (new x = 0; x < maxweapons; x++) + { + // Format cookie name. + Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, x); + + // Find cookie handle, and retrieve its value. + rebuycookie = FindClientCookie(rebuycookiename); + GetClientCookie(client, rebuycookie, rebuyweapons[x], maxlen); + } +} + +/** + * Set a weapon slot cookie given the slot and value. + * + * @param client The client index. + * @param slot The weapon slot to set value to. + * @param value The value (weaponname) of the slot. + */ +stock ZMarketSetRebuyCookie(client, WeaponsSlot:slot, const String:value[]) +{ + // Format cookie name. + decl String:rebuycookiename[32]; + Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, _:slot); + + // Find cookie handle, and retrieve its value. + new Handle:rebuycookie = FindClientCookie(rebuycookiename); + SetClientCookie(client, rebuycookie, value); +} + /** * Force a client to rebuy their weapons. * * @param client The client index. */ -ZMarketRebuy(client, bool:rebuy = false) +ZMarketRebuy(client, bool:autorebuy = false) { // If client is a zombie, then stop. if (InfectIsClientInfected(client)) @@ -651,23 +1016,30 @@ ZMarketRebuy(client, bool:rebuy = false) } new bool:zmarketbuyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); - if (!rebuy && zmarketbuyzone && !ZMarketIsClientInBuyZone(client)) + if (!autorebuy && zmarketbuyzone && !ZMarketIsClientInBuyZone(client)) { TranslationPrintToChat(client, "Weapons zmarket buyzone"); return; } + // Transfer cookie values into an array. + new String:rebuyweapons[WeaponsSlot][WEAPONS_MAX_LENGTH]; + ZMarketCookiesToArray(client, rebuyweapons, WEAPONS_SLOTS_MAX, sizeof(rebuyweapons[])); + // x = Weapon slot. for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) { - new bool:equipped = ZMarketEquip(client, g_strZMarketLastWeapon[client][x], true); - - // Remove weapon from last weapons. - if (!equipped) + // If slot is empty, then stop. + if (!rebuyweapons[x][0]) { - strcopy(g_strZMarketLastWeapon[client][x], sizeof(g_strZMarketLastWeapon), ""); + continue; } + + ZMarketEquip(client, rebuyweapons[x], true); } + + // Copy values back to cookies. + ZMarketArrayToCookies(client, rebuyweapons, WEAPONS_SLOTS_MAX, sizeof(rebuyweapons)); } /** @@ -687,7 +1059,7 @@ public Action:ZMarketCommand(client, argc) } // Send ZMarket menu. - ZMarketMenuTypes(client); + ZMarketMenuMain(client); // This stops the "Unknown command" message in client's console. return Plugin_Handled; diff --git a/src/zr/zhp.inc b/src/zr/zhp.inc index 226e5d9..bba4cd5 100644 --- a/src/zr/zhp.inc +++ b/src/zr/zhp.inc @@ -25,15 +25,20 @@ * ============================================================================ */ +/** + * Name of the cookie for toggle state of ZHP + */ +#define ZHP_COOKIE_ENABLED "zr_zhp" + /** * Array for storing ZHP timer handles per client. */ new Handle:tZHP[MAXPLAYERS + 1]; /** - * Array for flagging client to display HP + * Cookie handle for the toggle state of ZHP on a client. */ -new bool:pZHP[MAXPLAYERS + 1]; +new Handle:g_hZHPEnabledCookie = INVALID_HANDLE; /** * Create commands specific to ZHP. @@ -44,6 +49,19 @@ ZHPOnCommandsCreate() RegConsoleCmd(SAYHOOKS_KEYWORD_ZHP, ZHPCommand, "Shows real HP as zombie."); } +/** + * Create ZHP-related cookies here. + */ +ZHPOnCookiesCreate() +{ + // If cookie doesn't already exist, then create it. + g_hZHPEnabledCookie = FindClientCookie(ZHP_COOKIE_ENABLED); + if (g_hZHPEnabledCookie == INVALID_HANDLE) + { + g_hZHPEnabledCookie = RegClientCookie(ZHP_COOKIE_ENABLED, "The toggle state of ZHP.", CookieAccess_Public); + } +} + /** * Client is joining the server. * @@ -54,8 +72,16 @@ ZHPClientInit(client) // Get default client setting from cvar. new bool:zhp = GetConVarBool(g_hCvarsList[CVAR_ZHP_DEFAULT]); - // Set flag to default value. - pZHP[client] = zhp; + // Get ZHP enabled cookie value. + decl String:zhpenabled[8]; + GetClientCookie(client, g_hZHPEnabledCookie, zhpenabled, sizeof(zhpenabled)); + + // If the cookie is empty, then set the default value. + if (!zhpenabled[0]) + { + // Set cookie to default value from cvar. + CookiesSetClientCookieBool(client, g_hZHPEnabledCookie, zhp); + } // Reset timer handle. tZHP[client] = INVALID_HANDLE; @@ -162,12 +188,18 @@ bool:ZHPToggle(client) return false; } - // If ZHP is enabled, then tell client it's being disabled. - if (pZHP[client]) + // Get the cookie value. + new bool:zhpstate = CookiesGetClientCookieBool(client, g_hZHPEnabledCookie); + + // Toggle the value. + CookiesSetClientCookieBool(client, g_hZHPEnabledCookie, !zhpstate); + + // If ZHP was enabled, then tell client it has been disabled. + if (zhpstate) { TranslationPrintToChat(client, "ZHP disable"); } - // If ZHP is disabled, then tell client it's being enabled. + // If ZHP was disabled, then tell client it has been enabled. else { TranslationPrintToChat(client, "ZHP enable"); @@ -176,9 +208,6 @@ bool:ZHPToggle(client) ZHPUpdateHUD(client); } - // Toggle ZHP flag. - pZHP[client] = !pZHP[client]; - return true; } @@ -196,8 +225,11 @@ ZHPUpdateHUD(client) return; } + // Get ZHP enabled cookie as a bool. + new bool:zhpstate = CookiesGetClientCookieBool(client, g_hZHPEnabledCookie); + // If player is a zombie, or has ZHP disabled, then stop. - if (!InfectIsClientInfected(client) || !pZHP[client]) + if (!InfectIsClientInfected(client) || !zhpstate) { return; } diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index 2d27bd7..1b877d7 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -333,3 +333,24 @@ stock ZRPrintToConsoleLong(client, const String:text[], splitsize = 1022) pos += cellswritten; } } + +/** + * Converts a boolean value into a string. + * + * @param value The value to convert to string. + * @param output The converted string. + * @param maxlen The maximum length of the string. + */ +ZRBoolToString(bool:value, String:output[], maxlen) +{ + // If the value is true, then set string to "1". + if (value) + { + strcopy(output, maxlen, "1"); + } + // If the value is false, then set string to "0". + else + { + strcopy(output, maxlen, "0"); + } +} diff --git a/src/zr/zspawn.inc b/src/zr/zspawn.inc index 029f46c..f746588 100644 --- a/src/zr/zspawn.inc +++ b/src/zr/zspawn.inc @@ -30,6 +30,11 @@ */ new Handle:tZSpawn = INVALID_HANDLE; +/** + * Global variable to store SteamID cache handle. + */ +new Handle:g_hZSpawnSteamIDCache = INVALID_HANDLE; + /** * Create commands specific to ZSpawn. */ @@ -46,6 +51,15 @@ ZSpawnOnMapStart() { // Reset timer handle. tZSpawn = INVALID_HANDLE; + + // If SteamID cache hasn't been created yet, then create. + if (g_hZSpawnSteamIDCache == INVALID_HANDLE) + { + g_hZSpawnSteamIDCache = SteamidCacheCreate(); + } + + // Reset the SteamID cache. + SteamidCacheReset(g_hZSpawnSteamIDCache); } /** @@ -61,8 +75,8 @@ ZSpawnOnClientDisconnect(client) return; } - // Add client serial to global array. - SerialAddClient(client); + // Add client to the SteamID cache. + SteamidCacheAddClient(g_hZSpawnSteamIDCache, client); } /** @@ -72,8 +86,8 @@ ZSpawnOnClientDisconnect(client) */ ZSpawnOnClientDeath(client) { - // Add client serial to global array. - SerialAddClient(client); + // Add client to the SteamID cache. + SteamidCacheAddClient(g_hZSpawnSteamIDCache, client); } /** @@ -81,8 +95,8 @@ ZSpawnOnClientDeath(client) */ ZSpawnOnRoundStart() { - // Reset serial number array. - SerialReset(); + // Reset the SteamID cache. + SteamidCacheReset(g_hZSpawnSteamIDCache); // If zspawn timer is running, then kill it. if (tZSpawn != INVALID_HANDLE) @@ -177,7 +191,7 @@ bool:ZSpawnClient(client) } // Block if client has already played during this round. - if (SerialClientExists(client)) + if (SteamidCacheClientExists(g_hZSpawnSteamIDCache, client)) { // Tell client the command may only be used when joining late. TranslationPrintToChat(client, "ZSpawn double spawn");