From 05a4931ac82c47d24228f6520d5095832345c4da Mon Sep 17 00:00:00 2001 From: Dolly132 <109222243+Dolly132@users.noreply.github.com> Date: Sun, 18 Jan 2026 07:37:05 +0200 Subject: [PATCH] feat(v2): Bump version to 2.0.0 - Release of FunModes V2 - Possibility to add more modes without having to edit the main plugin file (FunModes.sp) - More fun modes (8) - Some bug fixes - Everything was tested and everything works like a charm --- addons/sourcemod/configs/FM_CrazyShop.cfg | 123 + addons/sourcemod/scripting/FunModes.sp | 816 ++---- .../scripting/Fun_Modes/BlindMode.sp | 336 +++ .../scripting/Fun_Modes/ChaosWeapons.sp | 256 ++ addons/sourcemod/scripting/Fun_Modes/Core.sp | 215 ++ .../scripting/Fun_Modes/CrazyShop.sp | 2276 +++++++++++++++++ .../scripting/Fun_Modes/DamageGame.sp | 345 ++- .../scripting/Fun_Modes/DoubleJump.sp | 202 +- addons/sourcemod/scripting/Fun_Modes/Fog.sp | 221 +- .../sourcemod/scripting/Fun_Modes/GunGame.sp | 719 ++++++ .../scripting/Fun_Modes/HealBeacon.sp | 523 ++-- .../scripting/Fun_Modes/HealBeacon_Menus.sp | 138 +- .../scripting/Fun_Modes/InvertedControls.sp | 134 +- .../sourcemod/scripting/Fun_Modes/MathGame.sp | 467 ++++ .../sourcemod/scripting/Fun_Modes/PullGame.sp | 477 ++++ .../scripting/Fun_Modes/RealityShift.sp | 351 +++ .../scripting/Fun_Modes/RedLightGreenLight.sp | 299 ++- .../sourcemod/scripting/Fun_Modes/Sample.sp | 142 + .../sourcemod/scripting/Fun_Modes/SlapMode.sp | 215 ++ .../sourcemod/scripting/Fun_Modes/VIPMode.sp | 630 +++-- 20 files changed, 7659 insertions(+), 1226 deletions(-) create mode 100644 addons/sourcemod/configs/FM_CrazyShop.cfg create mode 100644 addons/sourcemod/scripting/Fun_Modes/BlindMode.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/ChaosWeapons.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/Core.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/CrazyShop.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/GunGame.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/MathGame.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/PullGame.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/RealityShift.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/Sample.sp create mode 100644 addons/sourcemod/scripting/Fun_Modes/SlapMode.sp diff --git a/addons/sourcemod/configs/FM_CrazyShop.cfg b/addons/sourcemod/configs/FM_CrazyShop.cfg new file mode 100644 index 0000000..f92c42f --- /dev/null +++ b/addons/sourcemod/configs/FM_CrazyShop.cfg @@ -0,0 +1,123 @@ +"Items" +{ + // type: (0 = No amount or time, 1 = amount only, 2 = time only, 3 = both) + // Humans Items + "0" + { + "name" "More HP" + "price" "5" + "type" "1" + + "amount" "100.0" + } + "1" + { + "name" "Infect Protection" + "price" "10" + "type" "2" + + "time" "15.0" + } + "2" + { + "name" "Super Weapon" + "price" "30" + "type" "3" + + "amount" "1.8" + "time" "15.0" + } + "3" + { + "name" "Laser Protection" + "price" "10" + "type" "2" + + "time" "20.0" + } + "4" + { + "name" "Unlimited Ammo" + "price" "10" + "type" "2" + + "time" "20.0" + } + "5" + { + "name" "Buy a smokegrenade" + "price" "10" + "type" "0" + } + "6" + { + "name" "Slow Beacon" + "price" "30" + "type" "3" + + "amount" "0.01" + "time" "15.0" + } + + // Zombies Items + "7" + { + "name" "More Speed" + "price" "10" + "type" "3" + + "amount" "0.2" + "time" "20.0" + } + "8" + { + "name" "KB Protection" + "price" "20" + "type" "3" + + "amount" "0.2" + "time" "15.0" + } + "9" + { + "name" "Lower Gravity" + "price" "10" + "type" "3" + + "amount" "-0.2" + "time" "15.0" + } + "10" + { + "name" "Hurting Machine" + "price" "20" + "type" "3" + + "amount" "80.0" + "time" "15.0" + } + "11" + { + "name" "Ignite Immunity" + "price" "10" + "type" "2" + + "time" "15.0" + } + "12" + { + "name" "Invisibility" + "price" "30" + "type" "2" + + "time" "15.0" + } + "13" + { + "name" "Human Pull" + "price" "30" + "type" "2" + + "time" "15.0" + } +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/FunModes.sp b/addons/sourcemod/scripting/FunModes.sp index 7b55a79..632d0fd 100644 --- a/addons/sourcemod/scripting/FunModes.sp +++ b/addons/sourcemod/scripting/FunModes.sp @@ -1,4 +1,12 @@ +/* + (). FunModes V2: + + @file FunModes.sp + @Usage This is the main plugin file, it contains all the forwards. +*/ + #pragma semicolon 1 +#pragma newdecls required #include #include @@ -11,221 +19,14 @@ #tryinclude #define REQUIRE_PLUGIN -#pragma newdecls required - -/* COLORS VARIABLES */ -int g_ColorCyan[4] = {0, 255, 255, 255}; // cyan -int g_ColorDefault[4] = {255, 215, 55, 255}; // default color - -int g_iClientMenuUserId[MAXPLAYERS + 1] = { -1, ... }; - -int g_LaserSprite = -1; -int g_HaloSprite = -1; - -bool g_bIsVIPModeOn; -bool g_bIsHealBeaconOn; -bool g_bIsBetterDamageModeOn; -bool g_bIsRLGLEnabled; -bool g_bRoundEnd; -bool g_bEnableDetecting; -bool g_bIsDoubleJumpOn; -bool g_bIsDamageGameOn; -bool g_bPlugin_DynamicChannels = false; -bool g_bMotherZombie = false; - -#define HealBeacon_Tag "{gold}[FunModes-HealBeacon]{lightgreen}" -#define BeaconMode_HealBeacon 0 - -#define VIPMode_Tag "{gold}[FunModes-VIPMode]{lightgreen}" -#define BeaconMode_VIP 1 - -#define Fog_Tag "{gold}[FunModes-FOG]{lightgreen}" -#define FOGInput_Color 0 -#define FOGInput_Start 1 -#define FOGInput_End 2 -#define FOGInput_Toggle 3 - -#define RLGL_Tag "{gold}[FunModes-RedLightGreenLight]{lightgreen}" - -#define DoubleJump_Tag "{gold}[FunModes-DoubleJump]{lightgreen}" - -#define IC_TAG "{gold}[FunModes-InvertedControls]{lightgreen}" - -#define Beacon_Sound "buttons/blip1.wav" - -#define DamageGame_Tag "{gold}[FunModes-DamageGame]{lightgreen}" - -/* Arraylist to save client indexes of the heal beaconed players */ -ArrayList g_aHBPlayers; - -/* HUD HANDLER AND TIMERS HANDLERS */ -Handle g_hHudMsg = null; - -Handle g_hRoundStart_Timer[2] = { null, ... }; -Handle g_hDamageTimer = null; -Handle g_hHealTimer = null; -Handle g_hBeaconTimer[MAXPLAYERS + 1] = { null, ... }; - -/* NORMAL VARIABLES */ -int g_iCounter = 0; - -/* HEALBEACON CONVARS */ -ConVar g_cvHealBeaconTimer = null; -ConVar g_cvAlertTimer = null; -ConVar g_cvHealBeaconDamage = null; -ConVar g_cvHealBeaconHeal = null; -ConVar g_cvRandoms = null; -ConVar g_cvDefaultDistance = null; - -enum struct BeaconPlayers -{ - bool hasHealBeacon; - bool hasNeon; - int color[4]; - float distance; - int neonEntity; - - void SetColor(int setColor[4]) - { - this.color[0] = setColor[0]; - this.color[1] = setColor[1]; - this.color[2] = setColor[2]; - this.color[3] = setColor[3]; - } - - void ResetColor() - { - this.color[0] = g_ColorDefault[0]; - this.color[1] = g_ColorDefault[1]; - this.color[2] = g_ColorDefault[2]; - this.color[3] = g_ColorDefault[3]; - } - - void ResetValues() - { - this.hasHealBeacon = false; - this.ResetColor(); - this.distance = g_cvDefaultDistance.FloatValue; - this.neonEntity = -1; - } -} - -BeaconPlayers g_BeaconPlayersData[MAXPLAYERS + 1]; - -enum struct fogData -{ - bool fogEnable; - float fogStart; - float fogEnd; - int fogColor[4]; - - void SetColor(int setColor[4]) - { - this.fogColor[0] = setColor[0]; - this.fogColor[1] = setColor[1]; - this.fogColor[2] = setColor[2]; - this.fogColor[3] = setColor[3]; - } -} - - -/* FOR CONVAR LIST PURPOSE */ -enum struct ConVarInfo -{ - ConVar cvar; - char values[32]; - char type[10]; -} - -fogData g_FogData; - -int g_iFogEntity = -1; - -char colorsList[][] = -{ - "255 255 255 255 White", - "255 0 0 255 Red", - "0 255 0 255 Lime", - "0 0 255 255 Blue", - "255 255 0 255 Yellow", - "0 255 255 255 Cyan", - "255 215 0 255 Gold" -}; - -/* GLOBAL CONVARS */ -ConVar g_cvHUDChannel; - -/* VIP MODE CONVARS */ -ConVar g_cvVIPModeCount; -ConVar g_cvVIPModeLaser; -ConVar g_cvVIPModeTimer; -ConVar g_cvVIPMax; - -/* RLGL CONVARS */ -ConVar g_cvRLGLDetectTimer; -ConVar g_cvRLGLFinishDetectTime; -ConVar g_cvRLGLDetectTimerRepeatMin; -ConVar g_cvRLGLDetectTimerRepeatMax; -ConVar g_cvRLGLDamage; -ConVar g_cvRLGLWarningTime; -ConVar g_cvCountdownFolder; -ConVar g_cvRLGLZombiesSpeed; - -/* DOUBLE JUMP CONVARS */ -ConVar g_cvDoubleJumpBoost; -ConVar g_cvDoubleJumpMaxJumps; -ConVar g_cvDoubleJumpHumansEnable; -ConVar g_cvDoubleJumpZombiesEnable; - -/* DamageGame CONVARS */ -ConVar g_cvDamageGameTimer; -ConVar g_cvDamageGameDamage; - -enum ConVarType -{ - CONVAR_TYPE_HEALBEACON = 0, - CONVAR_TYPE_VIPMode = 1, - CONVAR_TYPE_RLGL = 2, - CONVAR_TYPE_DOUBLEJUMP = 3, - CONVAR_TYPE_DAMAGEGAME = 4 -}; - -ConVarType g_iCurrentConVarType; - -/* TIMERS */ -Handle g_hKillAllTimer = null; -Handle g_hVIPRoundStartTimer = null; -Handle g_hVIPBeaconTimer[MAXPLAYERS + 1] = { null, ... }; -Handle g_hRLGLTimer = null; -Handle g_hRLGLDetectTimer; -Handle g_hRLGLWarningTime; -Handle g_hDamageGameTimer; - -bool g_bIsVIP[MAXPLAYERS + 1]; - -/* Event Hooks Booleans */ -bool g_bEvent_RoundStart; -bool g_bEvent_RoundEnd; -bool g_bEvent_PlayerDeath; -bool g_bEvent_PlayerTeam; -bool g_bEvent_PlayerSpawn; - -/* CUSTOM SP INCLUDE FILES */ -#include "Fun_Modes/HealBeacon.sp" -#include "Fun_Modes/HealBeacon_Menus.sp" -#include "Fun_Modes/VIPMode.sp" -#include "Fun_Modes/Fog.sp" -#include "Fun_Modes/RedLightGreenLight.sp" -#include "Fun_Modes/DoubleJump.sp" -#include "Fun_Modes/InvertedControls.sp" -#include "Fun_Modes/DamageGame.sp" +#include "Fun_Modes/Core.sp" public Plugin myinfo = { name = "FunModes", author = "Dolly", description = "bunch of fun modes for ze mode", - version = "1.4.11", + version = "2.0.0", url = "https://nide.gg" } @@ -239,228 +40,211 @@ public void OnPluginStart() g_hHudMsg = CreateHudSynchronizer(); g_cvHUDChannel = CreateConVar("sm_funmodes_hud_channel", "4", "The channel for the hud if using DynamicChannels", _, true, 0.0, true, 5.0); - - PluginStart_HealBeacon(); - PluginStart_VIPMode(); - PluginStart_Fog(); - PluginStart_RLGL(); - PluginStart_DoubleJump(); - PluginStart_IC(); - PluginStart_DamageGame(); - + + DECLARE_FM_FORWARD(OnPluginStart); + AutoExecConfig(); for(int i = 1; i <= MaxClients; i++) { - if (IsValidClient(i)) + if (IsClientConnected(i)) OnClientPutInServer(i); } static const char commands[][] = { "sm_fm_cvars", "sm_funmodes", "sm_funmode" }; for(int i = 0; i < sizeof(commands); i++) { - RegAdminCmd(commands[i], Cmd_Cvars, ADMFLAG_CONVARS, "Shows All fun modes cvars"); + RegAdminCmd(commands[i], Cmd_FunModes, ADMFLAG_CONVARS, "Show all available funmodes"); } -} - -/* Events Hooks functions */ -void FunModes_HookEvent(bool &modeBool, const char[] name, EventHook callback) -{ - if (!modeBool) + + GameData gd = new GameData("sdkhooks.games/engine.ep2v"); + if (gd == null) + LogError("[FunModes] Could not find \"sdkhooks.games/engine.ep2v.txt\" file."); + else { - modeBool = true; - HookEvent(name, callback); + int offset = gd.GetOffset("Weapon_Switch"); + if (offset == -1) + { + LogError("[FunModes] Could not find the offset of \"Weapon_Switch\", some features may be neglected"); + return; + } + + StartPrepSDKCall(SDKCall_Player); + PrepSDKCall_SetVirtual(offset); + + PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); + PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); + + g_hSwitchSDKCall = EndPrepSDKCall(); + + if (g_hSwitchSDKCall == null) + LogError("[FunModes] Incorrect offset for \"Weapon_Switch\", Cannot get a good SDKCall Handle"); + + delete gd; } } -public void OnAllPluginsLoaded() -{ - g_bPlugin_DynamicChannels = LibraryExists("DynamicChannels"); -} - -public void OnLibraryAdded(const char[] name) +public void OnPluginEnd() { - if (strcmp(name, "DynamicChannels", false) == 0) - g_bPlugin_DynamicChannels = true; -} - -public void OnLibraryRemoved(const char[] name) -{ - if (strcmp(name, "DynamicChannels", false) == 0) - g_bPlugin_DynamicChannels = false; + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i)) + continue; + + OnClientDisconnect(i); + } } public void OnMapStart() { g_LaserSprite = PrecacheModel("sprites/laser.vmt"); g_HaloSprite = PrecacheModel("materials/sprites/halo.vtf"); - + g_iLaserBeam = PrecacheModel("materials/sprites/laserbeam.vmt"); + PrecacheSound(Beacon_Sound, true); - g_FogData.fogStart = 50.0; - g_FogData.fogEnd = 250.0; - g_FogData.fogEnable = false; - - g_bIsVIPModeOn = false; - g_bIsHealBeaconOn = false; - g_bIsRLGLEnabled = false; - g_bIsDoubleJumpOn = false; - g_bIsBetterDamageModeOn = false; - g_bEnableDetecting = false; - g_bIsDamageGameOn = false; - - /* DELETE HEALBEACON ARRAYLIST */ - delete g_aHBPlayers; - - MapStart_RLGL(); + DECLARE_FM_FORWARD(OnMapStart); } public void OnMapEnd() { - /* RLGL Timers */ - g_hRLGLTimer = null; - g_hRLGLDetectTimer = null; - g_hRLGLWarningTime = null; - - /* VIPMode Timers */ - g_hKillAllTimer = null; - g_hVIPRoundStartTimer = null; for (int i = 1; i <= MaxClients; i++) { - // VIP Beacon Timer - g_hVIPBeaconTimer[i] = null; - - // Healbeacon beacon timer - g_hBeaconTimer[i] = null; + g_bSDKHook_OnTakeDamagePost[i] = false; + g_bSDKHook_WeaponEquip[i] = false; + g_bSDKHook_OnTakeDamage[i] = false; } - /* Healbeacon Timers */ - g_hRoundStart_Timer[0] = null; - g_hRoundStart_Timer[1] = null; - g_hDamageTimer = null; - g_hHealTimer = null; - - /* DamageGame Timers */ - g_hDamageGameTimer = null; + DECLARE_FM_FORWARD(OnMapEnd); } public void OnClientPutInServer(int client) { - if (!g_bIsDamageGameOn && !g_bIsVIPModeOn) - return; - - if (IsFakeClient(client)) - return; - - if (g_bIsVIPModeOn) - SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); - else - SDKHook(client, SDKHook_OnTakeDamagePost, OnTakeDamagePost); -} - -void OnTakeDamagePost(int victim, int attacker, int inflictor, float damage, int damagetype) -{ - if (g_bIsDamageGameOn) - DamageGame_OnTakeDamagePost(victim, attacker, damage); + DECLARE_FM_FORWARD_PARAM(OnClientPutInServer, client); } -public Action OnTakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) +public void OnClientDisconnect(int client) { - if (!g_bIsVIPModeOn) - return Plugin_Continue; - - return VIPMode_OnTakeDamage(victim, attacker, damage); + g_bSDKHook_OnTakeDamagePost[client] = false; + g_bSDKHook_WeaponEquip[client] = false; + g_bSDKHook_OnTakeDamage[client] = false; + DECLARE_FM_FORWARD_PARAM(OnClientDisconnect, client); } -/* -*** EVENTS HOOKS CALLBACKS *** -*/ +public void ZR_OnClientInfected(int client, int attacker, bool motherInfect) +{ + DECLARE_FM_FORWARD_PARAM(ZR_OnClientInfected, client); + if (motherInfect && !g_bMotherZombie) + g_bMotherZombie = true; +} void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) { g_bRoundEnd = false; g_bMotherZombie = false; - RequestFrame(RoundStart_Frame); + DECLARE_FM_FORWARD(Event_RoundStart); } -void RoundStart_Frame() +void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) { - RoundStart_HealBeacon(); - RoundStart_Fog(); - RoundStart_VIPMode(); - RoundStart_RLGL(); - RoundStart_DamageGame(); + g_bRoundEnd = true; + DECLARE_FM_FORWARD(Event_RoundEnd); +} + +void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(event.GetInt("userid")); + DECLARE_FM_FORWARD_PARAM(Event_PlayerSpawn, client); +} + +void Event_PlayerTeam(Event event, const char[] name, bool dontBroadcast) +{ + DECLARE_FM_FORWARD_PARAM(Event_PlayerTeam, event); } void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) { - int userid = event.GetInt("userid"); + int client = GetClientOfUserId(event.GetInt("userid")); + DECLARE_FM_FORWARD_PARAM(Event_PlayerDeath, client); +} - PlayerDeath_HealBeacon(userid); - PlayerDeath_VIPMode(userid); - PlayerDeath_DamageGame(userid); +void OnTakeDamagePost(int victim, int attacker, int inflictor, float damage, int damagetype) +{ + DECLARE_FM_FORWARD_PARAM3(OnTakeDamagePost, victim, attacker, damage); } -void Event_PlayerTeam(Event event, const char[] name, bool dontBroadcast) +Action OnWeaponEquip(int client, int weapon) { - int userid = event.GetInt("userid"); - int team = event.GetInt("team"); + Action result = Plugin_Continue; + + DECLARE_FM_FORWARD_PARAM3(OnWeaponEquip, client, weapon, result); + + return result; +} - PlayerTeam_HealBeacon(userid, team); - PlayerTeam_VIPMode(userid, team); +Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype) +{ + Action result = Plugin_Continue; + + DECLARE_FM_FORWARD_PARAM4(OnTakeDamage, victim, attacker, damage, result); + + return result; } -void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) +/* Events Hooks functions */ +void FunModes_HookEvent(bool &modeBool, const char[] name, EventHook callback) { - if (!g_FogData.fogEnable) - return; + if (!modeBool) + { + modeBool = true; + HookEvent(name, callback); + } +} - int userid = event.GetInt("userid"); +public void OnAllPluginsLoaded() +{ + g_bPlugin_DynamicChannels = LibraryExists("DynamicChannels"); +} - PlayerSpawn_Fog(userid); +public void OnLibraryAdded(const char[] name) +{ + if (strcmp(name, "DynamicChannels", false) == 0) + g_bPlugin_DynamicChannels = true; } -void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) +public void OnLibraryRemoved(const char[] name) { - g_bRoundEnd = true; - g_bMotherZombie = false; + if (strcmp(name, "DynamicChannels", false) == 0) + g_bPlugin_DynamicChannels = false; } -public void OnClientDisconnect(int client) +public void OnPlayerRunCmdPost(int client, int buttons, int impulse) { - ClientDisconnect_HealBeacon(client); - ClientDisconnect_VIPMode(client); - ClientDisconnect_DamageGame(client); - ClientDisconnect_RLGL(client); + DECLARE_ONPLAYERRUNCMD_POST(OnPlayerRunCmdPost, client, buttons, impulse); } -float GetDistanceBetween(int origin, int target) +float GetDistanceBetween(int origin, int target, bool squarred = false) { float fOrigin[3], fTarget[3]; GetEntPropVector(origin, Prop_Data, "m_vecOrigin", fOrigin); GetEntPropVector(target, Prop_Data, "m_vecOrigin", fTarget); - return GetVectorDistance(fOrigin, fTarget); + return GetVectorDistance(fOrigin, fTarget, squarred); } -bool IsValidClient(int client) -{ - return (1 <= client && client <= MaxClients && IsClientInGame(client) && !IsClientSourceTV(client)); -} - -stock void BeaconPlayer(int client, int mode) +stock void BeaconPlayer(int client, int mode, float distance = 0.0, int color[4] = {0,0,0,0}) { float fvec[3]; GetClientAbsOrigin(client, fvec); fvec[2] += 10; - if (mode == BeaconMode_HealBeacon) + if (mode == 0) { - TE_SetupBeamRingPoint(fvec, (g_BeaconPlayersData[client].distance - 10.0), g_BeaconPlayersData[client].distance, g_LaserSprite, g_HaloSprite, 0, 15, 0.1, 10.0, 0.0, g_BeaconPlayersData[client].color, 10, 0); + TE_SetupBeamRingPoint(fvec, (distance - 10.0), distance, g_LaserSprite, g_HaloSprite, 0, 15, 0.1, 10.0, 0.0, color, 10, 0); TE_SendToAll(); } - else if (mode == BeaconMode_VIP) + else if (mode == 1) { TE_SetupBeamRingPoint(fvec, 10.0, 375.0, g_LaserSprite, g_HaloSprite, 0, 15, 0.5, 5.0, 0.0, g_ColorCyan, 10, 0); TE_SendToAll(); @@ -478,30 +262,43 @@ stock void BeaconPlayer(int client, int mode) TE_SendToAll(); EmitAmbientSound(Beacon_Sound, fvec, client, SNDLEVEL_RAIDSIREN); } +} - GetClientEyePosition(client, fvec); +void GiveGrenadesToClient(int client, WeaponAmmoGrenadeType type, int amount) +{ + int ammo = FindSendPropInfo("CBasePlayer", "m_iAmmo"); + if (ammo != -1) + { + int grenadesCount = GetEntData(client, ammo + (view_as(type) * 4)); + SetEntData(client, ammo + (view_as(type) * 4), grenadesCount + amount, _, true); + } } -Action Cmd_Cvars(int client, int args) +Action Cmd_FunModes(int client, int args) { if (!client) return Plugin_Handled; - Menu menu = new Menu(Menu_MainCvars); - menu.SetTitle("[FunModes] FunModes Cvars List!"); + Menu menu = new Menu(Menu_MainModes); + menu.SetTitle("[FunModes] Available modes!"); + + for (int i = 0; i < g_iLastModeIndex; i++) + { + ModeInfo info; + info = g_ModesInfo[i]; - menu.AddItem("0", "- HealBeacon Cvars"); - menu.AddItem("1", "- VIP Mode Cvars"); - menu.AddItem("2", "- RedLightGreenLight Cvars"); - menu.AddItem("3", "- DoubleJump Cvars"); - menu.AddItem("4", "- DamageGame Cvars"); + char index[3]; + IntToString(i, index, sizeof(index)); + + menu.AddItem(index, info.name); + } menu.ExitButton = true; menu.Display(client, MENU_TIME_FOREVER); return Plugin_Handled; } - int Menu_MainCvars(Menu menu, MenuAction action, int param1, int param2) +int Menu_MainModes(Menu menu, MenuAction action, int param1, int param2) { switch(action) { @@ -511,23 +308,30 @@ Action Cmd_Cvars(int client, int args) } case MenuAction_Select: { - ConVarType type = view_as(param2); - DisplayConVarsListMenu(param1, type); + char index[3]; + menu.GetItem(param2, index, sizeof(index)); + DisplayModeInfo(param1, StringToInt(index)); } } return 0; } -void DisplayConVarsListMenu(int client, ConVarType type) +void DisplayModeInfo(int client, int modeIndex) { + g_iPreviousModeIndex[client] = modeIndex; + Menu menu = new Menu(Menu_DisplayConVars); - char title[64]; - GetTypeTitle(type, title, sizeof(title)); - menu.SetTitle(title); + ModeInfo info; + info = g_ModesInfo[modeIndex]; + + bool enabled = info.cvarInfo[info.enableIndex].cvar.BoolValue; + + menu.SetTitle("%s - Mode Info\nStatus: %s - %s\n", info.name, enabled?"Enabled":"Disabled", info.isOn?"On":"Off"); - GetTypeConVarsList(menu, type); + menu.AddItem(info.name, "Toggle", enabled?ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); + menu.AddItem(info.name, "Settings"); menu.ExitBackButton = true; menu.Display(client, MENU_TIME_FOREVER); @@ -543,70 +347,123 @@ int Menu_DisplayConVars(Menu menu, MenuAction action, int param1, int param2) case MenuAction_Cancel: { if (param2 == MenuCancel_ExitBack) - Cmd_Cvars(param1, 0); + Cmd_FunModes(param1, 0); } case MenuAction_Select: { - char data[8]; - menu.GetItem(param2, data, sizeof(data)); - - char dataEx[2][5]; - ExplodeString(data, "|", dataEx, 2, 5); + char modeName[32]; + menu.GetItem(param2, modeName, sizeof(modeName)); + + char functionName[46]; + FormatEx(functionName, sizeof(functionName), "Cmd_%s%s", modeName, (param2 == 0) ? "Toggle" : "Settings"); + + Function myFunction = GetFunctionByName(null, functionName); + if (myFunction == INVALID_FUNCTION) + return -1; + + Call_StartFunction(null, myFunction); + + Call_PushCell(param1); + Call_PushCell(0); - ConVarType type = view_as(StringToInt(dataEx[0])); - int index = StringToInt(dataEx[1]); - - int len = GetConVarInfoSize(type); - ConVarInfo[] info = new ConVarInfo[len]; - CopyStructArray(type, info, len); + Call_Finish(); - ShowConVarInfo(param1, info[index], type); + if (param2 == 0) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); } } return 0; } -void ShowConVarInfo(int client, ConVarInfo info, ConVarType type) +void ShowCvarsInfo(int client, ModeInfo info) +{ + Menu menu = new Menu(Menu_CvarsInfo); + + menu.SetTitle("%s - ConVars List", info.name); + + for (int i = 0; i < sizeof(ModeInfo::cvarInfo); i++) + { + if (info.cvarInfo[i].cvar == null || info.cvarInfo[i].type[0] == '\0') + continue; + + char index[3]; + IntToString(i, index, sizeof(index)); + + char cvarName[64]; + info.cvarInfo[i].cvar.GetName(cvarName, sizeof(cvarName)); + + menu.AddItem(index, cvarName); + } + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_CvarsInfo(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + char indexStr[3]; + menu.GetItem(param2, indexStr, sizeof(indexStr)); + + ShowCvarInfo(param1, g_ModesInfo[g_iPreviousModeIndex[param1]].cvarInfo[StringToInt(indexStr)]); + } + } + + return 0; +} + +void ShowCvarInfo(int client, ConVarInfo thisCvarInfo) { - g_iCurrentConVarType = type; - Menu menu = new Menu(Menu_ShowConVarInfo); + Menu menu = new Menu(Menu_ShowCvarInfo); char convarName[32]; - info.cvar.GetName(convarName, sizeof(convarName)); + thisCvarInfo.cvar.GetName(convarName, sizeof(convarName)); - char convarDescription[98]; - info.cvar.GetDescription(convarDescription, sizeof(convarDescription)); + char convarDescription[120]; + thisCvarInfo.cvar.GetDescription(convarDescription, sizeof(convarDescription)); char title[sizeof(convarName) + sizeof(convarDescription) + 2]; FormatEx(title, sizeof(title), "%s\n%s", convarName, convarDescription); menu.SetTitle(title); int valsCount; - for (int i = 0; i < sizeof(info.values); i++) + for (int i = 0; i < sizeof(thisCvarInfo.values); i++) { - if (info.values[i] == ',') + if (thisCvarInfo.values[i] == ',') valsCount++; } - + valsCount++; char[][] dataEx = new char[valsCount][8]; - ExplodeString(info.values, ",", dataEx, valsCount, 8); + ExplodeString(thisCvarInfo.values, ",", dataEx, valsCount, 8); - any currentVal = GetValFromCvar(info.cvar, info.type); + any currentVal = GetValFromCvar(thisCvarInfo.cvar, thisCvarInfo.type); bool currentValExists = false; for (int i = 0; i < valsCount; i++) { - any val = GetValFromCvar(null, info.type, dataEx[i]); + any val = GetValFromCvar(null, thisCvarInfo.type, dataEx[i]); if (val == currentVal) { currentValExists = true; } char data[100]; - FormatEx(data, sizeof(data), "%d|%s|%s|%s", view_as(info.cvar), dataEx[i], info.type, info.values); + FormatEx(data, sizeof(data), "%d|%s|%s|%s", view_as(thisCvarInfo.cvar), dataEx[i], thisCvarInfo.type, thisCvarInfo.values); menu.AddItem(data, dataEx[i], val == currentVal ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT); } @@ -614,15 +471,15 @@ void ShowConVarInfo(int client, ConVarInfo info, ConVarType type) if (!currentValExists) { char val[10]; - info.cvar.GetString(val, sizeof(val)); + thisCvarInfo.cvar.GetString(val, sizeof(val)); menu.AddItem(NULL_STRING, val, ITEMDRAW_DISABLED); } - + menu.ExitBackButton = true; menu.Display(client, MENU_TIME_FOREVER); } -int Menu_ShowConVarInfo(Menu menu, MenuAction action, int param1, int param2) +int Menu_ShowCvarInfo(Menu menu, MenuAction action, int param1, int param2) { switch(action) { @@ -632,7 +489,7 @@ int Menu_ShowConVarInfo(Menu menu, MenuAction action, int param1, int param2) case MenuAction_Cancel: { if (param2 == MenuCancel_ExitBack) - DisplayConVarsListMenu(param1, g_iCurrentConVarType); + ShowCvarsInfo(param1, g_ModesInfo[g_iPreviousModeIndex[param1]]); } case MenuAction_Select: @@ -655,7 +512,7 @@ int Menu_ShowConVarInfo(Menu menu, MenuAction action, int param1, int param2) strcopy(info.values, sizeof(ConVarInfo::values), dataEx[3]); strcopy(info.type, sizeof(ConVarInfo::type), dataEx[2]); - ShowConVarInfo(param1, info, g_iCurrentConVarType); + ShowCvarInfo(param1, info); } } @@ -674,7 +531,8 @@ void SetCvarVal(ConVar cvar, const char[] type, const char[] valStr) cvar.BoolValue = view_as(StringToInt(valStr)); } -any GetValFromCvar(ConVar cvar = null, const char[] type, const char[] valStr = "") { +any GetValFromCvar(ConVar cvar = null, const char[] type, const char[] valStr = "") +{ if (strcmp(type, "int") == 0) { if (cvar != null) @@ -701,164 +559,6 @@ any GetValFromCvar(ConVar cvar = null, const char[] type, const char[] valStr = return 0; } -int GetConVarInfoSize(ConVarType type) -{ - switch(type) - { - case CONVAR_TYPE_HEALBEACON: - return sizeof(g_cvInfoHealBeacon); - - case CONVAR_TYPE_VIPMode: - return sizeof(g_cvInfoVIP); - - case CONVAR_TYPE_RLGL: - return sizeof(g_cvInfoRLGL); - - case CONVAR_TYPE_DOUBLEJUMP: - return sizeof(g_cvInfoDoubleJump); - - case CONVAR_TYPE_DAMAGEGAME: - return sizeof(g_cvInfoDamageGame); - } - - return 1; -} - -void CopyStructArray(ConVarType type, ConVarInfo[] info, int len) -{ - switch(type) - { - case CONVAR_TYPE_HEALBEACON: - { - for (int i = 0; i < len; i++) - { - ConVarInfo infoEx; - infoEx.cvar = g_cvInfoHealBeacon[i].cvar; - strcopy(infoEx.values, sizeof(ConVarInfo::values), g_cvInfoHealBeacon[i].values); - strcopy(infoEx.type, sizeof(ConVarInfo::type), g_cvInfoHealBeacon[i].type); - - info[i] = infoEx; - } - } - - case CONVAR_TYPE_VIPMode: - { - for (int i = 0; i < len; i++) - { - ConVarInfo infoEx; - infoEx.cvar = g_cvInfoVIP[i].cvar; - strcopy(infoEx.values, sizeof(ConVarInfo::values), g_cvInfoVIP[i].values); - strcopy(infoEx.type, sizeof(ConVarInfo::type), g_cvInfoVIP[i].type); - - info[i] = infoEx; - } - } - - case CONVAR_TYPE_RLGL: - { - for (int i = 0; i < len; i++) - { - ConVarInfo infoEx; - infoEx.cvar = g_cvInfoRLGL[i].cvar; - strcopy(infoEx.values, sizeof(ConVarInfo::values), g_cvInfoRLGL[i].values); - strcopy(infoEx.type, sizeof(ConVarInfo::type), g_cvInfoRLGL[i].type); - - info[i] = infoEx; - } - } - - case CONVAR_TYPE_DOUBLEJUMP: - { - for (int i = 0; i < len; i++) - { - ConVarInfo infoEx; - infoEx.cvar = g_cvInfoDoubleJump[i].cvar; - strcopy(infoEx.values, sizeof(ConVarInfo::values), g_cvInfoDoubleJump[i].values); - strcopy(infoEx.type, sizeof(ConVarInfo::type), g_cvInfoDoubleJump[i].type); - - info[i] = infoEx; - } - } - - case CONVAR_TYPE_DAMAGEGAME: - { - for (int i = 0; i < len; i++) - { - ConVarInfo infoEx; - infoEx.cvar = g_cvInfoDamageGame[i].cvar; - strcopy(infoEx.values, sizeof(ConVarInfo::values), g_cvInfoDamageGame[i].values); - strcopy(infoEx.type, sizeof(ConVarInfo::type), g_cvInfoDamageGame[i].type); - - info[i] = infoEx; - } - } - } -} - -void GetTypeTitle(ConVarType type, char[] title, int maxlen) -{ - switch(type) - { - case CONVAR_TYPE_HEALBEACON: - { - FormatEx(title, maxlen, "HealBeacon Cvars List"); - } - case CONVAR_TYPE_VIPMode: - { - FormatEx(title, maxlen, "VIPMode Cvars List"); - } - case CONVAR_TYPE_RLGL: - { - FormatEx(title, maxlen, "RedLightGreenLight Cvars List"); - } - case CONVAR_TYPE_DOUBLEJUMP: - { - FormatEx(title, maxlen, "DoubleJump Cvars List"); - } - case CONVAR_TYPE_DAMAGEGAME: - { - FormatEx(title, maxlen, "DamageGame Cvars List"); - } - } - - return; -} - -void GetTypeConVarsList(Menu menu, ConVarType type) -{ - switch(type) - { - case CONVAR_TYPE_HEALBEACON: - DisplayThisConVars(menu, g_cvInfoHealBeacon, sizeof(g_cvInfoHealBeacon), type); - - case CONVAR_TYPE_VIPMode: - DisplayThisConVars(menu, g_cvInfoVIP, sizeof(g_cvInfoVIP), type); - - case CONVAR_TYPE_RLGL: - DisplayThisConVars(menu, g_cvInfoRLGL, sizeof(g_cvInfoRLGL), type); - - case CONVAR_TYPE_DOUBLEJUMP: - DisplayThisConVars(menu, g_cvInfoDoubleJump, sizeof(g_cvInfoDoubleJump), type); - - case CONVAR_TYPE_DAMAGEGAME: - DisplayThisConVars(menu, g_cvInfoDamageGame, sizeof(g_cvInfoDamageGame), type); - } -} - -void DisplayThisConVars(Menu menu, ConVarInfo[] info, int len, ConVarType type) -{ - for (int i = 0; i < len; i++) - { - char data[8]; - FormatEx(data, sizeof(data), "%d|%d", view_as(type), i); - - char convarName[32]; - info[i].cvar.GetName(convarName, sizeof(convarName)); - - menu.AddItem(data, convarName); - } -} - stock void SendHudText(int client, const char[] sMessage, bool isFar = false, int icolor = -1) { bool bDynamicAvailable = false; @@ -879,7 +579,7 @@ stock void SendHudText(int client, const char[] sMessage, bool isFar = false, in if (isFar) SetHudTextParams(-0.2, 1.0, 0.7, 255, 13, 55, 255); else - SetHudTextParams(-0.2, 1.0, 2.0, 255, 36, 255, 13); + SetHudTextParams(-1.0, 0.1, 2.0, 255, 36, 255, 13); switch(icolor) { @@ -906,16 +606,4 @@ stock void SendHudText(int client, const char[] sMessage, bool isFar = false, in ClearSyncHud(client, g_hHudMsg); ShowSyncHudText(client, g_hHudMsg, "%s", sMessage); } -} - -public void ZR_OnClientInfected(int client, int attacker, bool motherInfect) -{ - if (g_bIsRLGLEnabled && g_bEnableDetecting) - RLGL_OnClientInfected(client); - - if (g_bMotherZombie) - return; - - if (motherInfect) - g_bMotherZombie = true; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/BlindMode.sp b/addons/sourcemod/scripting/Fun_Modes/BlindMode.sp new file mode 100644 index 0000000..c93b957 --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/BlindMode.sp @@ -0,0 +1,336 @@ +/* + (). FunModes V2: + + @file BlindMode.sp + @Usage Functions for the Blind mode. +*/ + +/* + Could add a mode that gives a bunch of random zombies 1 flashbang to blind cts. + Like for example if there is 20 zombies, 5 of them gets a flashbang, + and after an amount of time, another 5 random zombies gets flashbangs again + + By @LowParty +*/ + +#pragma semicolon 1 +#pragma newdecls required + +ModeInfo g_BlindModeInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_BlindModeInfo + +#define BLINDMODE_CONVAR_TIMER_INTERVAL 0 +#define BLINDMODE_CONVAR_PERCENTAGE 1 +#define BLINDMODE_CONVAR_MAX_DISTANCE 2 +#define BLINDMODE_CONVAR_BLIND_TIME 3 +#define BLINDMODE_CONVAR_TOGGLE 4 + +Handle g_hBlindModeTimer; +bool g_bHasFlash[MAXPLAYERS + 1]; + +stock void OnPluginStart_BlindMode() +{ + THIS_MODE_INFO.name = "BlindMode"; + THIS_MODE_INFO.tag = "{gold}[FunModes-BlindMode]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_blindmode", Cmd_BlindModeToggle, ADMFLAG_CONVARS, "Turn BlindMode Mode On/Off"); + RegAdminCmd("sm_blindmode_settings", Cmd_BlindModeSettings, ADMFLAG_CONVARS, "Open BlindMode Sttings Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, BLINDMODE_CONVAR_TIMER_INTERVAL, + "sm_blindmode_time_interval", "20.0", "Every how many seconds to keep giving the zombies flashbang?", + ("15.0,20.0,30.0,40.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, BLINDMODE_CONVAR_PERCENTAGE, + "sm_blindmode_percentage", "33.0", "Percentage value of zombies to give flashbang to", + ("10.0,20.0,50.0,70.0,100.0"), "float" + ); + + THIS_MODE_INFO.cvarInfo[BLINDMODE_CONVAR_PERCENTAGE].cvar.SetBounds(ConVarBound_Lower, false, 0.0); + THIS_MODE_INFO.cvarInfo[BLINDMODE_CONVAR_PERCENTAGE].cvar.SetBounds(ConVarBound_Upper, false, 100.0); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, BLINDMODE_CONVAR_MAX_DISTANCE, + "sm_blindmode_max_distance", "300.0", "Max distance between humans and flashbang to apply blind in units", + ("200.0,300.0,500.0,700.0,1000.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, BLINDMODE_CONVAR_BLIND_TIME, + "sm_blindmode_blind_time", "5", "How many seconds should the humans be blind for?", + ("2,3,5,7,10"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, BLINDMODE_CONVAR_TOGGLE, + "sm_blindmode_enable", "1", "Enable/Disable BlindMode Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = BLINDMODE_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[BLINDMODE_CONVAR_TOGGLE].cvar.AddChangeHook(OnBlindModeModeToggle); +} + +void OnBlindModeModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_BlindMode() {} +stock void OnMapEnd_BlindMode() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + g_hBlindModeTimer = null; +} + +stock void OnClientPutInServer_BlindMode(int client) +{ + #pragma unused client +} + +stock void OnClientDisconnect_BlindMode(int client) +{ + g_bHasFlash[client] = false; +} + +stock void ZR_OnClientInfected_BlindMode(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_BlindMode() +{ + for (int i = 1; i <= MaxClients; i++) + g_bHasFlash[i] = false; +} + +stock void Event_RoundEnd_BlindMode() {} +stock void Event_PlayerSpawn_BlindMode(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_BlindMode(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_BlindMode(int client) +{ + g_bHasFlash[client] = false; +} + +public Action Cmd_BlindModeToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s BlindMode Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s BlindMode Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + if (THIS_MODE_INFO.isOn) + { + FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); + FunModes_HookEvent(g_bEvent_RoundEnd, "round_end", Event_RoundEnd); + + float interval = THIS_MODE_INFO.cvarInfo[BLINDMODE_CONVAR_TIMER_INTERVAL].cvar.FloatValue; + + CPrintToChatAll("%s Zombies will get a {olive}flashbang {lightgreen}that can blind humans.", THIS_MODE_INFO.tag); + CPrintToChatAll("%s %d%% of the zombies team will get the {olive}flashbang {lightgreen}every %.2f seconds", THIS_MODE_INFO.tag, + THIS_MODE_INFO.cvarInfo[BLINDMODE_CONVAR_PERCENTAGE].cvar.IntValue, + interval + ); + + g_hBlindModeTimer = CreateTimer(interval, Timer_BlindMode, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); + } + else + { + delete g_hBlindModeTimer; + } + + return Plugin_Handled; +} + +/* BlindMode Settings */ +public Action Cmd_BlindModeSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_BlindModeSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_BlindModeSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; +} + +void ApplyBlind(int client) +{ + int color[4]; + color[3] = 255; + + int flags = FFADE_OUT; + + int clients[1]; + clients[0] = client; + + int time = THIS_MODE_INFO.cvarInfo[BLINDMODE_CONVAR_BLIND_TIME].cvar.IntValue; + + Handle message = StartMessage("Fade", clients, 1, 1); + if(GetUserMessageType() == UM_Protobuf) + { + Protobuf pb = UserMessageToProtobuf(message); + pb.SetInt("duration", time * 1000); + pb.SetInt("hold_time", time * 1000); + pb.SetInt("flags", flags); + pb.SetColor("clr", color); + } + else + { + BfWrite bf = UserMessageToBfWrite(message); + bf.WriteShort(time * 1000); + bf.WriteShort(time * 1000); + bf.WriteShort(flags); + bf.WriteByte(color[0]); + bf.WriteByte(color[1]); + bf.WriteByte(color[2]); + bf.WriteByte(color[3]); + } + + EndMessage(); +} + +Action Timer_BlindMode(Handle timer) +{ + if (!THIS_MODE_INFO.isOn) + { + g_hBlindModeTimer = null; + return Plugin_Stop; + } + + if (g_bRoundEnd || !g_bMotherZombie) + return Plugin_Handled; + + int zombiesCount = 0; + int zombies[MAXPLAYERS + 1]; + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || !IsPlayerAlive(i) || !ZR_IsClientZombie(i)) + continue; + + zombies[zombiesCount++] = i; + } + + if (zombiesCount == 0) + return Plugin_Handled; + + float percentage = THIS_MODE_INFO.cvarInfo[BLINDMODE_CONVAR_PERCENTAGE].cvar.FloatValue; + int neededZombies = RoundToCeil(zombiesCount * (percentage / 100)); + + int enough = 0; + do + { + int zombie = zombies[GetRandomInt(0, zombiesCount - 1)]; + if (g_bHasFlash[zombie]) + zombie = zombies[GetRandomInt(0, zombiesCount - 1)]; + + g_bHasFlash[zombie] = true; + int entity = GivePlayerItem(zombie, "weapon_flashbang"); + EquipPlayerWeapon(zombie, entity); + SetEntData(zombie, FindSendPropInfo("CBasePlayer", "m_iAmmo") + (view_as(GrenadeType_Flashbang) * 4), 1, _, true); + CPrintToChat(zombie, "%s You have been granted a FlashBang!!!\nBlind some humans.", THIS_MODE_INFO.tag); + enough++; + } while (enough <= neededZombies); + + CPrintToChatAll("%s %d zombies have been granted a Blind grenade (Flashbang), watch out humans!", THIS_MODE_INFO.tag, neededZombies); + return Plugin_Continue; +} + +public void OnEntityCreated(int entity, const char[] classname) +{ + if (strcmp(classname, "flashbang_projectile") == 0) + CreateTimer(1.2, Timer_ApplyBlind, EntIndexToEntRef(entity), TIMER_FLAG_NO_MAPCHANGE); +} + +Action Timer_ApplyBlind(Handle timer, int ref) +{ + int entity = EntRefToEntIndex(ref); + if (!IsValidEntity(entity)) + return Plugin_Stop; + + int owner = GetEntPropEnt(entity, Prop_Data, "m_hOwnerEntity"); + if (!owner) + return Plugin_Stop; + + if (!IsPlayerAlive(owner) || !ZR_IsClientZombie(owner)) + return Plugin_Stop; + + float origin[3]; + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", origin); + + float maxDistance = THIS_MODE_INFO.cvarInfo[BLINDMODE_CONVAR_MAX_DISTANCE].cvar.FloatValue; + + for (int i = 1; i <= MaxClients; i++) + { + if(!IsClientInGame(i) || !IsPlayerAlive(i) || !ZR_IsClientHuman(i)) + continue; + + float plOrigin[3]; + GetClientAbsOrigin(i, plOrigin); + + float distance = GetVectorDistance(origin, plOrigin); + if(distance > maxDistance) + continue; + + ApplyBlind(i); + } + + g_bHasFlash[owner] = false; + return Plugin_Handled; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/ChaosWeapons.sp b/addons/sourcemod/scripting/Fun_Modes/ChaosWeapons.sp new file mode 100644 index 0000000..3b53ea5 --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/ChaosWeapons.sp @@ -0,0 +1,256 @@ +/* + (). FunModes V2: + + @file ChaosWeapons.sp + @Usage Funcitons for the ChaosWeapons mode. + +*/ + +/* + Chaos Weapons: A mode where every 30 seconds or 1 minute, + a global message says what weapon will be used like "Only the AK47 will push the zombies for the next 30 seconds!" + and only the named weapon will have normal knockback, any other weapon will have 0.1 knockback (It wont push zombies) + making the humans buy a certain weapon all the time and buy all the variety of weapons in the shop. + + By @kiku-san +*/ + +#pragma semicolon 1 +#pragma newdecls required + +ModeInfo g_ChaosWeaponsInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_ChaosWeaponsInfo + +#define CHAOSWEAPONS_CONVAR_TIMER_INTERVAL 0 +#define CHAOSWEAPONS_CONVAR_KNOCKBACK 1 +#define CHAOSWEAPONS_CONVAR_TOGGLE 2 + +Handle g_hChaosWeaponsTimer; + +char g_ChaosWeaponsList[][] = +{ + "ELITE", "DEAGLE", /* Pistols */ + "MAC10", "TMP", "MP5NAVY", "UMP45", "P90", /* SMGs */ + "GALIL", "FAMAS", "AK47", "M4A1", "AUG", "SG552", /* Rifles */ + "M3", "XM1014" /* Shotguns */ +}; + +float g_fOriginalWeaponsKB[sizeof(g_ChaosWeaponsList)]; + +stock void OnPluginStart_ChaosWeapons() +{ + THIS_MODE_INFO.name = "ChaosWeapons"; + THIS_MODE_INFO.tag = "{gold}[FunModes-ChaosWeapons]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_chaosweapons", Cmd_ChaosWeaponsToggle, ADMFLAG_CONVARS, "Turn ChaosWeapons Mode On/Off"); + RegAdminCmd("sm_chaosweapons_settings", Cmd_ChaosWeaponsSettings, ADMFLAG_CONVARS, "Open ChaosWeapons Sttings Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CHAOSWEAPONS_CONVAR_TIMER_INTERVAL, + "sm_chaosweapons_timer_interval", "30.0", "Every how many seconds to keep picking a random weapon?", + ("10.0,15.0,20.0,30.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CHAOSWEAPONS_CONVAR_KNOCKBACK, + "sm_chaosweapons_knockback", "0.1", "Knockback to set of other weapons", + ("0.1,0.2,0.5,1.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CHAOSWEAPONS_CONVAR_TOGGLE, + "sm_chaosweapons_enable", "1", "Enable/Disable ChaosWeapons Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = CHAOSWEAPONS_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[CHAOSWEAPONS_CONVAR_TOGGLE].cvar.AddChangeHook(OnChaosWeaponsModeToggle); +} + +void OnChaosWeaponsModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_ChaosWeapons() {} +stock void OnMapEnd_ChaosWeapons() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + g_hChaosWeaponsTimer = null; +} + +stock void OnClientPutInServer_ChaosWeapons(int client) +{ + #pragma unused client +} + +stock void OnClientDisconnect_ChaosWeapons(int client) +{ + #pragma unused client +} + +stock void ZR_OnClientInfected_ChaosWeapons(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_ChaosWeapons() {} +stock void Event_RoundEnd_ChaosWeapons() {} +stock void Event_PlayerSpawn_ChaosWeapons(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_ChaosWeapons(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_ChaosWeapons(int client) +{ + #pragma unused client +} + +public Action Cmd_ChaosWeaponsToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s ChaosWeapons Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s ChaosWeapons Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + if (THIS_MODE_INFO.isOn) + { + float interval = THIS_MODE_INFO.cvarInfo[CHAOSWEAPONS_CONVAR_TIMER_INTERVAL].cvar.FloatValue; + g_hChaosWeaponsTimer = CreateTimer(interval, Timer_ChaosWeapons, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); + + CPrintToChatAll("%s a Random weapon will get normal knockback and the others will get their knockback nerfed every %.2f seconds!", THIS_MODE_INFO.tag, interval); + + SetAllWeaponsKnockback(THIS_MODE_INFO.cvarInfo[CHAOSWEAPONS_CONVAR_KNOCKBACK].cvar.FloatValue, _, true); + + PickRandomWeapon(); + } + else + { + delete g_hChaosWeaponsTimer; + SetAllWeaponsKnockback(_, _, _, true); + } + + return Plugin_Handled; +} + +/* ChaosWeapons Settings */ +public Action Cmd_ChaosWeaponsSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_ChaosWeaponsSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_ChaosWeaponsSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; +} + +Action Timer_ChaosWeapons(Handle timer) +{ + if (!THIS_MODE_INFO.isOn) + { + g_hChaosWeaponsTimer = null; + return Plugin_Handled; + } + + PickRandomWeapon(); + return Plugin_Continue; +} + +void PickRandomWeapon() +{ + int index = GetRandomInt(0, sizeof(g_ChaosWeaponsList) - 1); + + SetAllWeaponsKnockback(THIS_MODE_INFO.cvarInfo[CHAOSWEAPONS_CONVAR_KNOCKBACK].cvar.FloatValue, index); + + char msg[255]; + FormatEx(msg, sizeof(msg), "Only the [%s] will push the zombies for the next %d seconds!", g_ChaosWeaponsList[index], THIS_MODE_INFO.cvarInfo[CHAOSWEAPONS_CONVAR_TIMER_INTERVAL].cvar.IntValue); + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i)) + continue; + + SendHudText(i, msg, _, 1); + CPrintToChat(i, "%s %s", THIS_MODE_INFO.tag, msg); + } +} + +void SetAllWeaponsKnockback(float kb = 0.0, int index = -1, bool firstTime = false, bool turnOff = false) +{ + for (int i = 0; i < sizeof(g_ChaosWeaponsList); i++) + { + int len = strlen(g_ChaosWeaponsList[i]); + char[] lower = new char[len + 1]; + + for (int j = 0; j < len; j++) + { + char c = g_ChaosWeaponsList[i][j]; + if (c >= 'A' && c <= 'Z') + c |= 0x20; + + lower[j] = c; + } + + if (turnOff || (index >= 0 && i == index)) + { + ZR_SetWeaponKnockback(lower, g_fOriginalWeaponsKB[i]); + continue; + } + + if (firstTime) + g_fOriginalWeaponsKB[i] = ZR_GetWeaponKnockback(lower); + + ZR_SetWeaponKnockback(lower, kb); + } +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/Core.sp b/addons/sourcemod/scripting/Fun_Modes/Core.sp new file mode 100644 index 0000000..004a8c9 --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/Core.sp @@ -0,0 +1,215 @@ +/* + (). FunModes V2: + + @file Core.sp + @Usage Global variables, and modes definition, add the mode names in the end of the file +*/ + +/* Important Variables */ + +/* Event Hooks Booleans */ +bool g_bEvent_RoundStart; +bool g_bEvent_RoundEnd; +bool g_bEvent_PlayerDeath; +bool g_bEvent_PlayerTeam; +bool g_bEvent_PlayerSpawn; +bool g_bEvent_WeaponFire; + +/* Client SDKHook Boolens */ +bool g_bSDKHook_OnTakeDamagePost[MAXPLAYERS + 1] = { false, ... }; +bool g_bSDKHook_WeaponEquip[MAXPLAYERS + 1] = { false, ... }; +bool g_bSDKHook_OnTakeDamage[MAXPLAYERS + 1] = { false, ... }; + +/* Round Checking Booleans */ +bool g_bRoundEnd; + +/* COLORS VARIABLES */ +int g_ColorCyan[4] = {0, 255, 255, 255}; // cyan +int g_ColorDefault[4] = {255, 215, 55, 255}; // default color + +/* Sprites Indexes Integers */ +int g_LaserSprite = -1; +int g_HaloSprite = -1; +int g_iLaserBeam = -1; + +/* Library Checking Booleans */ +bool g_bPlugin_DynamicChannels = false; +bool g_bMotherZombie = false; + +/* HUD HANDLER */ +Handle g_hHudMsg = null; + +/* NORMAL VARIABLES */ +int g_iCounter = 0; + +/* GLOBAL CONVARS */ +ConVar g_cvHUDChannel; +int g_iPreviousModeIndex[MAXPLAYERS+1]; + +/* SDKCall Handles */ +Handle g_hSwitchSDKCall; + +#define Beacon_Sound "buttons/blip1.wav" + +#define FFADE_IN (0x0001) // Fade in +#define FFADE_OUT (0x0002) // Fade out +#define FFADE_MODULATE (0x0004) // Modulate (Don't blend) +#define FFADE_STAYOUT (0x0008) // Ignores the duration, stays faded out until a new fade message is received +#define FFADE_PURGE (0x0010) // Purges all other fades, replacing them with this one + +/* Mode Management structs */ +#define MAX_MODES_NUM 32 +#define MAX_CVARS_NUM 10 + +enum struct ConVarInfo +{ + ConVar cvar; + char values[32]; + char type[10]; +} + +enum struct ModeInfo +{ + int index; + char name[32]; + char tag[64]; + ConVarInfo cvarInfo[MAX_CVARS_NUM]; + bool isOn; + int enableIndex; +} + +ModeInfo g_ModesInfo[MAX_MODES_NUM]; +int g_iLastModeIndex; + +enum struct FM_Color +{ + char name[10]; + char rgb[14]; +} + +FM_Color g_ColorsList[] = +{ + { "White", "255 255 255" }, + { "Red", "255 0 0" }, + { "Lime", "0 255 0" }, + { "Blue", "0 0 255" }, + { "Yellow", "255 255 0" }, + { "Cyan", "0 255 255" }, + { "Gold", "255 215 0" } +}; + +enum WeaponAmmoGrenadeType +{ + GrenadeType_HEGrenade = 11, /** CSS - HEGrenade slot */ + GrenadeType_Flashbang = 12, /** CSS - Flashbang slot. */ + GrenadeType_Smokegrenade = 13, /** CSS - Smokegrenade slot. */ +}; + +/* +- New FunModes Update + * The plugin will now use macros to define the main functions and forwards + * Macros are the only way possible for this as sourcepawn is too weak + * Do not edit the macros unless you know what you are doing + +- Things that are useful by macros: + * Only add the mode inside the DECLARE_FM_FORWARD macro, and the mode wll be included + * The include files will still need to be included by a macro + * Flexibility and more funcitonality +*/ +/* Edit the macros when you add a new mode */ +#define CALL_MODE_FUNC(%1,%2) %1_%2() +#define DECLARE_FM_FORWARD(%1) \ + CALL_MODE_FUNC(%1, HealBeacon); \ + CALL_MODE_FUNC(%1, VIPMode); \ + CALL_MODE_FUNC(%1, IC); \ + CALL_MODE_FUNC(%1, Fog); \ + CALL_MODE_FUNC(%1, RLGL); \ + CALL_MODE_FUNC(%1, DoubleJump); \ + CALL_MODE_FUNC(%1, DamageGame); \ + CALL_MODE_FUNC(%1, BlindMode); \ + CALL_MODE_FUNC(%1, SlapMode); \ + CALL_MODE_FUNC(%1, ChaosWeapons); \ + CALL_MODE_FUNC(%1, GunGame); \ + CALL_MODE_FUNC(%1, MathGame); \ + CALL_MODE_FUNC(%1, CrazyShop); \ + CALL_MODE_FUNC(%1, RealityShift); \ + CALL_MODE_FUNC(%1, PullGame) + +#define CALL_MODE_FUNC_PARAM(%1,%2,%3) %1_%2(%3) +#define DECLARE_FM_FORWARD_PARAM(%1,%2) \ + CALL_MODE_FUNC_PARAM(%1, HealBeacon, %2); \ + CALL_MODE_FUNC_PARAM(%1, VIPMode, %2); \ + CALL_MODE_FUNC_PARAM(%1, IC, %2); \ + CALL_MODE_FUNC_PARAM(%1, Fog, %2); \ + CALL_MODE_FUNC_PARAM(%1, RLGL, %2); \ + CALL_MODE_FUNC_PARAM(%1, DoubleJump, %2); \ + CALL_MODE_FUNC_PARAM(%1, DamageGame, %2); \ + CALL_MODE_FUNC_PARAM(%1, BlindMode, %2); \ + CALL_MODE_FUNC_PARAM(%1, GunGame, %2); \ + CALL_MODE_FUNC_PARAM(%1, CrazyShop, %2); \ + CALL_MODE_FUNC_PARAM(%1, RealityShift, %2); \ + CALL_MODE_FUNC_PARAM(%1, PullGame, %2) + +/* +these commented macros are not used for now +#define CALL_MODE_FUNC_PARAM2(%1,%2,%3,%4) %1_%2(%3,%4) +#define DECLARE_FM_FORWARD_PARAM2(%1,%2,%3) \ + CALL_MODE_FUNC_PARAM2(%1, HealBeacon, %2, %3); \ + CALL_MODE_FUNC_PARAM2(%1, VIPMode, %2, %3); \ + CALL_MODE_FUNC_PARAM2(%1, RLGL, %2, %3); \ + CALL_MODE_FUNC_PARAM2(%1, IC, %2, %3); \ + CALL_MODE_FUNC_PARAM2(%1, Fog, %2, %3); \ + CALL_MODE_FUNC_PARAM2(%1, DoubleJump, %2, %3); \ + CALL_MODE_FUNC_PARAM2(%1, DamageGame, %2, %3) +*/ +/* for now there are only 4 modes that use 3 params functions */ +#define CALL_MODE_FUNC_PARAM3(%1,%2,%3,%4,%5) %1_%2(%3,%4,%5) +#define DECLARE_FM_FORWARD_PARAM3(%1,%2,%3,%4) \ + CALL_MODE_FUNC_PARAM3(%1, VIPMode, %2, %3, %4); \ + CALL_MODE_FUNC_PARAM3(%1, DamageGame, %2, %3, %4); \ + CALL_MODE_FUNC_PARAM3(%1, GunGame, %2, %3, %4); \ + CALL_MODE_FUNC_PARAM3(%1, CrazyShop, %2, %3, %4) + +/* For 4 params-functions, only crazyshop and vipmode use it for now */ +#define CALL_MODE_FUNC_PARAM4(%1,%2,%3,%4,%5,%6) %1_%2(%3,%4,%5,%6) +#define DECLARE_FM_FORWARD_PARAM4(%1,%2,%3,%4,%5) \ + CALL_MODE_FUNC_PARAM4(%1, VIPMode, %2, %3, %4, %5); \ + CALL_MODE_FUNC_PARAM4(%1, CrazyShop, %2, %3, %4, %5) + +/* OnPlayerRunCmdPost Calls (Since this is called every frame, we gotta watch out for performance :p) */ +#define DECLARE_ONPLAYERRUNCMD_POST(%1,%2,%3,%4) \ + CALL_MODE_FUNC_PARAM3(%1, DoubleJump, %2, %3, %4); \ + CALL_MODE_FUNC_PARAM3(%1, CrazyShop, %2, %3, %4); \ + CALL_MODE_FUNC_PARAM3(%1, PullGame, %2, %3, %4) + +/* %0: ConVarInfo[], %1: index, %2: name, %3: default value, %4: description + %5: cvar values, %6: cvar value type +*/ +#define DECLARE_FM_CVAR(%1,%2,%3,%4,%5,%6,%7) \ + %1[%2].cvar = CreateConVar(%3, %4, %5); \ + %1[%2].values = %6; \ + %1[%2].type = %7 + +/* %1: mode struct, %2: variable, %3: value, %4: index */ +#define CHANGE_MODE_INFO(%1,%2,%3,%4) \ + %1.%2 = %3; \ + g_ModesInfo[%4] = %1 + +#define THIS_MODE_INFO + +/* Add the mode's include file here */ +#include "Fun_Modes/HealBeacon.sp" +#include "Fun_Modes/VIPMode.sp" +#include "Fun_Modes/Fog.sp" +#include "Fun_Modes/RedLightGreenLight.sp" +#include "Fun_Modes/DoubleJump.sp" +#include "Fun_Modes/InvertedControls.sp" +#include "Fun_Modes/DamageGame.sp" +#include "Fun_Modes/BlindMode.sp" +#include "Fun_Modes/SlapMode.sp" +#include "Fun_Modes/ChaosWeapons.sp" +#include "Fun_Modes/GunGame.sp" +#include "Fun_Modes/MathGame.sp" +#include "Fun_Modes/CrazyShop.sp" +#include "Fun_Modes/RealityShift.sp" +#include "Fun_Modes/PullGame.sp" \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/CrazyShop.sp b/addons/sourcemod/scripting/Fun_Modes/CrazyShop.sp new file mode 100644 index 0000000..f85c471 --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/CrazyShop.sp @@ -0,0 +1,2276 @@ +/* + (). FunModes V2: + + @file CrazyShop.sp + @Usage Functions for the CrazyShop Mode. + +*/ + +/* + Super DOLLYS shop: This is a shop where you get rewarded for shooting the zombies. + The shop consists using the credits you earn when shooting zombies to buy upgrades of your liking, + such as more hp, one knife protection (Is like a shield where you get protected from being killed 1 time), + golden weapon (This weapon fires the zombies when you shoot with it), even laser protection for some maps. + Of course the zombies would have some upgrades too, such as more speed, + kevlar (this would protect them from full knockback, being more difficult to push them, 100 bullets), + 700 gravity, poison ball(Got this idea from lardy's limitless map), a laser that damages cts or slows them, + and even a grenade that would burn the humans, or one that flashes them. + + By @kiku-san +*/ + +#define _FM_CrazyShop + +#if !defined _KnockbackRestrict_included_ + #undef REQUIRE_PLUGIN + #tryinclude + #define REQUIRE_PLUGIN +#endif + +#pragma semicolon 1 +#pragma newdecls required + +ModeInfo g_CrazyShopInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_CrazyShopInfo + +#define CRAZYSHOP_CONVAR_DAMAGE 0 +#define CRAZYSHOP_CONVAR_CREDITS 1 +#define CRAZYSHOP_CONVAR_SAVECREDITS 2 +#define CRAZYSHOP_CONVAR_SLOWBEACON_RADIUS 3 +#define CRAZYSHOP_CONVAR_DISABLE_SHOP 4 +#define CRAZYSHOP_CONVAR_TOGGLE 5 + +enum CrazyShop_DataType +{ + DATATYPE_NONE = 0, + DATATYPE_AMOUNT, + DATATYPE_TIME, + DATATYPE_BOTH /* first one is amount and second is time */ +} + +enum struct CrazyShop_Item +{ + char name[32]; + int team; + int price; + float amount; + float time; + CrazyShop_DataType type; + char amountName[32]; +} + +static CrazyShop_Item g_CrazyShopItems[] = +{ + /* Name, Team, Price */ + + /* Humans Items (Team = 1) */ + { + "More HP", 1, 5, 100.0, 0.0, DATATYPE_AMOUNT, "HP Amount to Add" + }, + { + "Infect Protection", 1, 10, 0.0, 15.0, DATATYPE_TIME, "" + }, + { + "Super Weapon", 1, 30, 2.5, 15.0, DATATYPE_BOTH, "Damage Scale" + }, + { + "Laser Protection", 1, 10, 0.0, 20.0, DATATYPE_TIME, "" + }, + { + "Unlimited Ammo", 1, 10, 0.0, 15.0, DATATYPE_TIME, "" + }, + { + "Buy a smokegrenade", 1, 10, 0.0, 0.0, DATATYPE_NONE, "" + }, + { + "Slow Beacon", 1, 30, 0.01, 15.0, DATATYPE_BOTH, "Speed Value (absolute)" + }, + + /* Zombies Items (Team = 0) */ + { + "More Speed", 0, 10, 0.2, 15.0, DATATYPE_BOTH, "Speed Value (+)" + }, + { + "KB Protection", 0, 20, 0.2, 15.0, DATATYPE_BOTH, "Knockback Value (absolute)" + }, + { + "Lower Gravity", 0, 10, -0.2, 15.0, DATATYPE_BOTH, "Gravity Value (-)" + }, + { + "Hurting Machine", 0, 20, 20.0, 15.0, DATATYPE_BOTH, "Damage" + }, + { + "Ignite Immunity", 0, 10, 0.0, 20.0, DATATYPE_TIME, "" + }, + { + "Invisibility", 0, 30, 0.0, 15.0, DATATYPE_TIME, "" + }, + { + "Human Pull", 0, 30, 0.0, 15.0, DATATYPE_TIME, "" + } +}; + +#define ITEMS_COUNT 14 + +enum struct CrazyShop_PlayerData +{ + int credits; + int itemsCount[ITEMS_COUNT]; + int originalItemsCount[ITEMS_COUNT]; + bool isItemActive[ITEMS_COUNT]; + + int dealtDamage; + bool isInDB; + + /* Temp Vars, Basically the vars that the item activations use */ + bool infectionProtect; + bool superWeapon; + char superWeaponName[32]; + char originalWeapon[32]; + bool laserProtect; + bool kbProtect; + bool igniteImmunity; + bool protectLaser; + bool unlimitedAmmo; + Handle slowBeaconTimer; + float originalSpeed; + bool gotSlowed; + int grabbedTarget; + float originalTargetMaxSpeed; + float lastUse; + + void Reset(bool tempVarsOnly = false) + { + if (!tempVarsOnly) + { + this.credits = 0; + this.dealtDamage = 0; + this.isInDB = false; + for (int i = 0; i < sizeof(CrazyShop_PlayerData::itemsCount); i++) + { + this.itemsCount[i] = 0; + this.originalItemsCount[i] = 0; + } + } + + this.infectionProtect = false; + this.superWeapon = false; + this.superWeaponName[0] = '\0'; + this.laserProtect = false; + this.kbProtect = false; + this.igniteImmunity = false; + this.protectLaser = false; + this.unlimitedAmmo = false; + delete this.slowBeaconTimer; + this.originalSpeed = 0.0; + this.gotSlowed = false; + this.grabbedTarget = -1; + this.lastUse = 0.0; + } +} + +CrazyShop_PlayerData g_CrazyShopPlayerData[MAXPLAYERS + 1]; + +int g_iCrazyShopPreviousItem[MAXPLAYERS + 1]; +int g_iCrazyShopProps; + +Database g_hCrazyShop_DB; + +/* Macros */ +/***************************************************************/ +#define THIS_MODE_DB g_hCrazyShop_DB +#define CRAZYSHOP_DB_NAME "FM_CrazyShop" // Only SQLITE is supported +#define CRAZYSHOP_DB_DATA_COLUMN "clients_data" +#define CRAZYSHOP_DB_ITEMS_DATA_COLUMN "shop_items_data" +/***************************************************************/ +#define PLAYER_CREDITS(%1) g_CrazyShopPlayerData[%1].credits +#define PLAYER_ITEM_COUNT(%1,%2) g_CrazyShopPlayerData[%1].itemsCount[%2] +#define PLAYER_ITEM_COUNT_OG(%1,%2) g_CrazyShopPlayerData[%1].originalItemsCount[%2] +#define PLAYER_ITEM_ACTIVE(%1,%2) g_CrazyShopPlayerData[%1].isItemActive[%2] +#define DAMAGE_DEALT(%1) g_CrazyShopPlayerData[%1].dealtDamage +#define PLAYER_IN_DB(%1) g_CrazyShopPlayerData[%1].isInDB +#define PLAYER_RESET(%1) g_CrazyShopPlayerData[%1].Reset() +#define PLAYER_RESET_TEMP_VARS(%1) g_CrazyShopPlayerData[%1].Reset(true) +#define PLAYER_TEMP_VAR(%1,%2) g_CrazyShopPlayerData[%1].%2 +/***************************************************************/ +#define PROP_MODEL "models/props/cs_office/vending_machine.mdl" + +stock void OnPluginStart_CrazyShop() +{ + THIS_MODE_INFO.name = "CrazyShop"; + THIS_MODE_INFO.tag = "{gold}[FunModes-CrazyShop]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_crazyshop", Cmd_CrazyShopToggle, ADMFLAG_CONVARS, "Turn CrazyShop Mode On/Off"); + RegAdminCmd("sm_crazyshop_settings", Cmd_CrazyShopSettings, ADMFLAG_CONVARS, "Open CrazyShop Sttings Menu"); + RegConsoleCmd("sm_crazyshop", Cmd_CrazyShopMenu, "Open the CrazyShop Menu"); + RegConsoleCmd("sm_myitems", Cmd_CrazyShopMyItems, "Open the Available Items Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CRAZYSHOP_CONVAR_DAMAGE, + "sm_crazyshop_damage", "5000", "The needed damage for humans to be rewarded with credits", + ("200,500,1000,1500,2000"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CRAZYSHOP_CONVAR_CREDITS, + "sm_crazyshop_credits", "1", "How many credits to reward the human when they reach the needed damage?", + ("1,2,3,4,5"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CRAZYSHOP_CONVAR_SAVECREDITS, + "sm_crazyshop_savecredits", "1", "Save credits to a database or not", + ("0,1"), "bool" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CRAZYSHOP_CONVAR_SLOWBEACON_RADIUS, + "sm_crazyshop_slowbeacon_radius", "400.0", "Slow Beacon Radius", + ("300.0,400.0,500.0,600.0,700.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CRAZYSHOP_CONVAR_DISABLE_SHOP, + "sm_crazyshop_disable_shop", "0", "Enable/Disable the !crazyshop command", + ("0,1"), "bool" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, CRAZYSHOP_CONVAR_TOGGLE, + "sm_crazyshop_enable", "1", "Enable/Disable CrazyShop Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = CRAZYSHOP_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[CRAZYSHOP_CONVAR_TOGGLE].cvar.AddChangeHook(OnCrazyShopModeToggle); +} + +void OnCrazyShopModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_CrazyShop() +{ + PrecacheModel(PROP_MODEL); +} + +stock void OnMapEnd_CrazyShop() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + g_iCrazyShopProps = 0; +} + +stock void OnClientPutInServer_CrazyShop(int client) +{ + if (!THIS_MODE_INFO.isOn) + return; + + if (!g_bSDKHook_OnTakeDamagePost[client]) + { + SDKHook(client, SDKHook_OnTakeDamagePost, OnTakeDamagePost); + g_bSDKHook_OnTakeDamagePost[client] = true; + } + + if (!g_bSDKHook_OnTakeDamage[client]) + { + SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); + g_bSDKHook_OnTakeDamage[client] = true; + } +} + +stock void OnClientDisconnect_CrazyShop(int client) +{ + for (int i = 1; i <= MaxClients; i++) + { + if (PLAYER_TEMP_VAR(i, grabbedTarget) == client) + PLAYER_TEMP_VAR(i, grabbedTarget) = -1; + } + + if (!THIS_MODE_INFO.isOn || THIS_MODE_DB == null) + return; + + if (!PLAYER_IN_DB(client)) + CrazyShop_DB_AddPlayer(client); + else + CrazyShop_DB_SaveCredits(client); + + CrazyShop_DB_CheckItems(client); + + PLAYER_RESET(client); +} + +stock void ZR_OnClientInfected_CrazyShop(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_CrazyShop() +{ + g_iCrazyShopProps = 0; + + for (int i = 1; i <= MaxClients; i++) + PLAYER_RESET_TEMP_VARS(i); +} + +stock void Event_RoundEnd_CrazyShop() {} +stock void Event_PlayerSpawn_CrazyShop(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_CrazyShop(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_CrazyShop(int client) +{ + #pragma unused client +} + +// CrazyShop is the only mode that hooks this event, so it's fine +stock void Event_WeaponFire_CrazyShop(Event event, const char[] name, bool dontBroadcast) +{ + if (!THIS_MODE_INFO.isOn) + return; + + int client = GetClientOfUserId(event.GetInt("userid")); + if (!PLAYER_TEMP_VAR(client, superWeapon) && !PLAYER_TEMP_VAR(client, unlimitedAmmo)) + return; + + int weapon = GetEntPropEnt(client, Prop_Data, "m_hActiveWeapon"); + if (!IsValidEntity(weapon)) + return; + + if (weapon != GetPlayerWeaponSlot(client, CS_SLOT_PRIMARY) && weapon != GetPlayerWeaponSlot(client, CS_SLOT_SECONDARY)) + return; + + int clip1 = GetEntProp(weapon, Prop_Send, "m_iClip1"); + if (GetEntProp(weapon, Prop_Send, "m_iState", 4, 0) != 2 || !clip1) + return; + + int toAdd = 1; + char weaponClassname[32]; + GetEntityClassname(weapon, weaponClassname, sizeof(weaponClassname)); + + if (strcmp(weaponClassname, "weapon_glock") == 0 || strcmp(weaponClassname, "weapon_famas") == 0) + { + if (GetEntProp(weapon, Prop_Send, "m_bBurstMode")) + toAdd = clip1; + } + + SetEntProp(weapon, Prop_Send, "m_iClip1", clip1 + toAdd); +} + +stock void OnTakeDamagePost_CrazyShop(int victim, int attacker, float damage) +{ + if (!THIS_MODE_INFO.isOn) + return; + + if (!(1<=attacker<=MaxClients) || !IsPlayerAlive(victim) || !IsPlayerAlive(attacker) || !ZR_IsClientZombie(victim) || !ZR_IsClientHuman(attacker)) + return; + + if (PLAYER_TEMP_VAR(attacker, superWeapon)) + return; + + DAMAGE_DEALT(attacker) += RoundToNearest(damage); + + if (DAMAGE_DEALT(attacker) >= THIS_MODE_INFO.cvarInfo[CRAZYSHOP_CONVAR_DAMAGE].cvar.IntValue) + { + int credits = THIS_MODE_INFO.cvarInfo[CRAZYSHOP_CONVAR_CREDITS].cvar.IntValue; + if (credits <= 0) + return; + + CPrintToChat(attacker, "%s You have been given {olive}%d credits {lightgreen}for damaging the zombies!", THIS_MODE_INFO.tag, credits); + + PLAYER_CREDITS(attacker) += credits; + DAMAGE_DEALT(attacker) = 0; + } +} + +stock void OnWeaponEquip_CrazyShop(int client, int weapon, Action &result) +{ + #pragma unused client + #pragma unused weapon + #pragma unused result +} + +stock void OnTakeDamage_CrazyShop(int victim, int &attacker, float &damage, Action &result) +{ + if (!THIS_MODE_INFO.isOn) + return; + + bool isVictimAlive = IsPlayerAlive(victim); + bool isAttackerAlive = (1 <= attacker <= MaxClients) && IsPlayerAlive(attacker); + + bool isVictimZombie = ZR_IsClientZombie(victim); + bool isAttackerZombie = (1 <= attacker <= MaxClients) && ZR_IsClientZombie(attacker); + + // victim is for sure gonna be a real player, so no need to check + + // check if victim is a human and has laser protect + if (PLAYER_TEMP_VAR(victim, laserProtect) && !isVictimAlive && !isVictimZombie) + { + if (!IsValidEntity(attacker)) + return; + + char classname[32]; + if (!GetEntityClassname(attacker, classname, sizeof(classname))) + return; + + /* if attacker entity is not trigger_hurt */ + if (strcmp(classname, "trigger_hurt") != 0) + return; + + /* we should now check if trigger_hurt is from a laser */ + int parent = GetEntPropEnt(attacker, Prop_Data, "m_hParent"); + if (!IsValidEntity(parent)) + return; + + bool isFromLaser = false; + char parentClassName[64]; + if (!GetEntityClassname(parent, parentClassName, sizeof(parentClassName))) + return; + + if (strcmp(parentClassName, "func_movelinear") == 0 || strcmp(parentClassName, "func_door") == 0) + isFromLaser = true; + + if (!isFromLaser) + return; + + damage = 0.0; + result = Plugin_Changed; + return; + } + + // check if victim is a zombie and attacker is human for ignite immunity and kb protection + if ((PLAYER_TEMP_VAR(victim, igniteImmunity) || PLAYER_TEMP_VAR(victim, kbProtect)) && isVictimAlive && isVictimZombie) + { + if (isAttackerZombie) + return; + + if (PLAYER_TEMP_VAR(victim, kbProtect)) + { + damage -= damage * 0.9; + result = Plugin_Changed; + return; + } + + RequestFrame(CrazyShop_CheckIgnite, GetClientUserId(victim)); + } + + if (isAttackerAlive && !isAttackerZombie && PLAYER_TEMP_VAR(attacker, superWeapon)) + { + if (!isVictimAlive || !isVictimZombie) + return; + + char weaponName[32]; + GetClientWeapon(attacker, weaponName, sizeof(weaponName)); + if (strcmp(weaponName, PLAYER_TEMP_VAR(attacker, superWeaponName)) != 0) + return; + + damage *= g_CrazyShopItems[2].amount; + int flags = GetEntityFlags(victim); + + if (!(flags & FL_ONFIRE)) + IgniteEntity(victim, 5.0); + + result = Plugin_Changed; + } +} + +void CrazyShop_CheckIgnite(int userid) +{ + int victim = GetClientOfUserId(userid); + if (!victim) + return; + + int flags = GetEntityFlags(victim); + + if (flags & FL_ONFIRE) + { + flags &= ~FL_ONFIRE; + int effect = GetEntPropEnt(victim, Prop_Send, "m_hEffectEntity"); + if (IsValidEntity(effect)) + { + char className[12]; + GetEntityClassname(effect, className, sizeof(className)); + + if (strcmp(className, "entityflame") == 0) + RemoveEntity(effect); + } + } +} + +stock void OnPlayerRunCmdPost_CrazyShop(int client, int buttons, int impulse) +{ + #pragma unused buttons + + if (!THIS_MODE_INFO.isOn) + return; + + if (!IsPlayerAlive(client)) + return; + + float currentTime = GetGameTime(); + if (currentTime <= PLAYER_TEMP_VAR(client, lastUse)) + return; + + // https://github.com/ValveSoftware/source-sdk-2013/blob/7191ecc418e28974de8be3a863eebb16b974a7ef/src/game/server/player.cpp#L6073 + if (impulse == 100) + { + PLAYER_TEMP_VAR(client, lastUse) = currentTime + 2; + CrazyShop_OpenAvailableItems(client); + } +} + +/* TODO: Handle this in FunModes.sp */ +/* This should be in FunModes.sp, but crazyshop is the only mode that's using it for now */ +public void OnClientPostAdminCheck(int client) +{ + if (!THIS_MODE_INFO.isOn || THIS_MODE_DB == null) + return; + + if (IsFakeClient(client)) + return; + + CrazyShop_DB_GetData(client, CRAZYSHOP_DB_DATA_COLUMN, "credits"); + CrazyShop_DB_GetData(client, CRAZYSHOP_DB_ITEMS_DATA_COLUMN, "item,count"); +} + +void CrazyShop_DB_OnConnect(Database db, const char[] error, any data) +{ + // We are not bothered to reconnect + if (db == null || error[0]) + { + LogError("[FM-%s] Couldn't connect to database, error: %s", THIS_MODE_INFO.name, error); + return; + } + + THIS_MODE_DB = db; + THIS_MODE_DB.SetCharset("utf8mb4"); + + CrazyShop_DB_CreateTables(); +} + +void CrazyShop_DB_CreateTables() +{ + char driver[10]; + THIS_MODE_DB.Driver.GetIdentifier(driver, sizeof(driver)); + + if (strcmp(driver, "sqlite", false) != 0) + { + delete THIS_MODE_DB; + LogError("[FM-%s] Only SQLITE is supported", THIS_MODE_INFO.name); + return; + } + + Transaction tr = SQL_CreateTransaction(); + + char query[1024]; + THIS_MODE_DB.Format(query, sizeof(query), + "CREATE TABLE IF NOT EXISTS `%s` (" + ... "`client_steamid` INTEGER PRIMARY KEY NOT NULL," + ... "`credits` INTEGER NOT NULL)", CRAZYSHOP_DB_DATA_COLUMN); + + tr.AddQuery(query); + + THIS_MODE_DB.Format(query, sizeof(query), + "CREATE TABLE IF NOT EXISTS `%s` (" + ... "`client_steamid` INTEGER NOT NULL," + ... "`item` INTEGER NOT NULL," + ... "`count` INTEGER NOT NULL," + ... "UNIQUE(`client_steamid`, `item`))", CRAZYSHOP_DB_ITEMS_DATA_COLUMN); + + tr.AddQuery(query); + + THIS_MODE_DB.Execute(tr, DB_CrazyShop_TablesOnSuccess, DB_CrazyShop_TablesOnError, _, DBPrio_High); +} + +void DB_CrazyShop_TablesOnSuccess(Database database, any data, int queries, Handle[] results, any[] queryData) +{ + LogMessage("[FM-%s] Successfully created tables (SQLITE)", THIS_MODE_INFO.name); + + // here is where we get players' credits and items: + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i)) + continue; + + CrazyShop_DB_GetData(i, CRAZYSHOP_DB_DATA_COLUMN, "credits"); + CrazyShop_DB_GetData(i, CRAZYSHOP_DB_ITEMS_DATA_COLUMN, "item,count"); + } +} + +void DB_CrazyShop_TablesOnError(Database database, any data, int queries, const char[] error, int failIndex, any[] queryData) +{ + LogError("[FM-%s] Error while creating tables (SQLITE): %s", error); +} + +void CrazyShop_DB_GetData(int client, const char[] table, const char[] column) +{ + int steamID = GetSteamAccountID(client); + if (!steamID) + return; + + char query[1024]; + THIS_MODE_DB.Format(query, sizeof(query), "SELECT %s FROM `%s` WHERE `client_steamid`=%d", column, table, steamID); + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(column[0]); + + THIS_MODE_DB.Query(DB_CrazyShop_OnGetData, query, pack, DBPrio_Normal); +} + +void DB_CrazyShop_OnGetData(Database db, DBResultSet results, const char[] error, DataPack pack) +{ + if (error[0]) + { + LogError("[FM-%s] Error getting client data: %s", THIS_MODE_INFO.name, error); + delete pack; + return; + } + + if (results == null || !results.RowCount) + { + delete pack; + return; + } + + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return; + } + + bool isCredits = pack.ReadCell() == 'c'; + delete pack; + + if (!results.FetchRow()) + return; + + if (isCredits) + { + PLAYER_IN_DB(client) = true; + PLAYER_CREDITS(client) = results.FetchInt(0); + } + else + { + // 2 fields here (item and count) + results.Rewind(); + while (results.FetchRow()) + { + int item = results.FetchInt(0); + int count = results.FetchInt(1); + + PLAYER_ITEM_COUNT(client, item) = count; + PLAYER_ITEM_COUNT_OG(client, item) = count; + } + } +} + +void CrazyShop_DB_AddPlayer(int client) +{ + int steamID = GetSteamAccountID(client); + if (!steamID) + return; + + char query[1024]; + THIS_MODE_DB.Format(query, sizeof(query), "INSERT INTO `%s` (`client_steamid`, `credits`) VALUES (%d, %d) " + ... "ON CONFLICT(`client_steamid`) DO UPDATE SET `credits`=excluded.credits", + CRAZYSHOP_DB_DATA_COLUMN, steamID, PLAYER_CREDITS(client)); + + THIS_MODE_DB.Query(DB_CrazyShop_OnAddPlayer, query, _, DBPrio_High); +} + +void DB_CrazyShop_OnAddPlayer(Database db, DBResultSet results, const char[] error, DataPack pack) +{ + if (error[0]) + LogError("[FM-%s] Error while inserting data: %s", THIS_MODE_INFO.name, error); +} + +void CrazyShop_DB_SaveCredits(int client) +{ + int steamID = GetSteamAccountID(client); + if (!steamID) + return; + + char query[1024]; + THIS_MODE_DB.Format(query, sizeof(query), "UPDATE `%s` SET `credits`=%d WHERE `client_steamid`=%d", + CRAZYSHOP_DB_DATA_COLUMN, PLAYER_CREDITS(client), steamID); + + THIS_MODE_DB.Query(DB_CrazyShop_OnSaveCredits, query, _, DBPrio_High); +} + +void DB_CrazyShop_OnSaveCredits(Database db, DBResultSet results, const char[] error, DataPack pack) +{ + if (error[0]) + LogError("[FM-%s] Error while saving player credits: %s", THIS_MODE_INFO.name, error); +} + +void CrazyShop_DB_CheckItems(int client) +{ + int steamID = GetSteamAccountID(client); + if (!steamID) + return; + + char query[1024]; + bool hasItems = false; + for (int i = 0; i < sizeof(CrazyShop_PlayerData::itemsCount); i++) + { + if (PLAYER_ITEM_COUNT(client, i) > 0) + { + hasItems = true; + break; + } + } + + if (!hasItems) + { + THIS_MODE_DB.Format(query, sizeof(query), "DELETE FROM `%s` WHERE `client_steamid`=%d", + CRAZYSHOP_DB_ITEMS_DATA_COLUMN, steamID); + + THIS_MODE_DB.Query(DB_CrazyShop_OnCheckItems, query, _, DBPrio_High); + } + else + { + for (int i = 0; i < sizeof(CrazyShop_PlayerData::itemsCount); i++) + { + THIS_MODE_DB.Format(query, sizeof(query), "INSERT INTO `%s` (`client_steamid`, `item`, `count`) VALUES " + ... "(%d, %d, %d) ON CONFLICT(`client_steamid`, `item`) DO UPDATE SET " + ... "`count` = excluded.count WHERE `count` != excluded.count", + CRAZYSHOP_DB_ITEMS_DATA_COLUMN, steamID, i, PLAYER_ITEM_COUNT(client, i)); + + THIS_MODE_DB.Query(DB_CrazyShop_OnCheckItems, query, _, DBPrio_High); + } + } +} + +void DB_CrazyShop_OnCheckItems(Database db, DBResultSet results, const char[] error, DataPack pack) +{ + if (error[0]) + LogError("[FM-%s] Error while checking player credits: %s", THIS_MODE_INFO.name, error); +} + +public Action Cmd_CrazyShopToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s CrazyShop Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s CrazyShop Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + if (THIS_MODE_INFO.isOn) + { + FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); + FunModes_HookEvent(g_bEvent_RoundEnd, "round_end", Event_RoundEnd); + + CPrintToChatAll("%s Earn credits by defending and shooting the zombies!", THIS_MODE_INFO.tag); + CPrintToChatAll("%s Type {olive}!crazyshop {lightgreen}to open the Shop Menu and buy powerful items!", THIS_MODE_INFO.tag); + + if (THIS_MODE_INFO.cvarInfo[CRAZYSHOP_CONVAR_SAVECREDITS].cvar.BoolValue && THIS_MODE_DB == null) + Database.Connect(CrazyShop_DB_OnConnect, CRAZYSHOP_DB_NAME); + + CrazyShop_GetItems(); + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || IsClientSourceTV(i)) + continue; + + SDKHook(i, SDKHook_OnTakeDamage, OnTakeDamage); + SDKHook(i, SDKHook_OnTakeDamagePost, OnTakeDamagePost); + g_bSDKHook_OnTakeDamagePost[i] = true; + g_bSDKHook_OnTakeDamage[i] = true; + } + + // Restart the round + CS_TerminateRound(2.0, CSRoundEnd_Draw); + } + else + delete THIS_MODE_DB; + + return Plugin_Handled; +} + +/* CrazyShop Settings */ +void CrazyShop_GetItems() +{ + char filePath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, filePath, sizeof(filePath), "configs/FM_CrazyShop.cfg"); + + KeyValues kv = new KeyValues("Items"); + + if (!kv.ImportFromFile(filePath)) + { + delete kv; + return; + } + + if (!kv.GotoFirstSubKey()) + { + delete kv; + return; + } + + int i = 0; + do + { + char name[sizeof(CrazyShop_Item::name)]; + kv.GetString("name", name, sizeof(name)); + + int price = kv.GetNum("price"); + g_CrazyShopItems[i].name = name; + g_CrazyShopItems[i].price = price; + + CrazyShop_DataType type = view_as(kv.GetNum("type", g_CrazyShopItems[i].type)); + switch (type) + { + case DATATYPE_AMOUNT: g_CrazyShopItems[i].amount = kv.GetFloat("amount", g_CrazyShopItems[i].amount); + case DATATYPE_TIME: g_CrazyShopItems[i].time = kv.GetFloat("time", g_CrazyShopItems[i].time); + case DATATYPE_BOTH: + { + g_CrazyShopItems[i].amount = kv.GetFloat("amount", g_CrazyShopItems[i].amount); + g_CrazyShopItems[i].time = kv.GetFloat("time", g_CrazyShopItems[i].time); + } + } + + i++; + } while (kv.GotoNextKey()); + + delete kv; +} + +void CrazyShop_AdminPanel(int client) +{ + Menu menu = new Menu(Menu_CrazyShop_AdminPanel); + + menu.SetTitle("[CrazyShop] Admin Panel (The secret place, shhh!)"); + + for (int i = 0; i < sizeof(g_CrazyShopItems); i++) + { + char item[128]; + FormatEx(item, sizeof(item), "%s - Edit", g_CrazyShopItems[i].name); + + menu.AddItem(NULL_STRING, item); + } + + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_CrazyShop_AdminPanel(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Select: + CrazyShop_OpenItemSettings(param1, param2); + } + + return 0; +} + +void CrazyShop_OpenItemSettings(int client, int item) +{ + g_iCrazyShopPreviousItem[client] = item; + + Menu menu = new Menu(Menu_CrazyShop_ItemSettings); + + CrazyShop_DataType type = g_CrazyShopItems[item].type; + char valuesString[sizeof(CrazyShop_Item::amountName)+32]; + switch (type) + { + case DATATYPE_AMOUNT: FormatEx(valuesString, sizeof(valuesString), "%s: %.2f", g_CrazyShopItems[item].amountName, g_CrazyShopItems[item].amount); + case DATATYPE_TIME: FormatEx(valuesString, sizeof(valuesString), "Time: %.2fs", g_CrazyShopItems[item].time); + case DATATYPE_BOTH: FormatEx(valuesString, sizeof(valuesString), "%s: %.2f\nTime: %.2fs", g_CrazyShopItems[item].amountName, g_CrazyShopItems[item].amount, g_CrazyShopItems[item].time); + } + + menu.SetTitle("[CrazyShop] %s - Settings\nPrice: %d\n%s", g_CrazyShopItems[item].name, g_CrazyShopItems[item].price, valuesString); + + menu.AddItem(NULL_STRING, "Change Price"); + + if (type == DATATYPE_AMOUNT || type == DATATYPE_BOTH) + { + char itemText[sizeof(CrazyShop_Item::amountName) + 20]; + FormatEx(itemText, sizeof(itemText), "Change %s", g_CrazyShopItems[item].amountName); + + menu.AddItem(NULL_STRING, itemText); + } + + if (type == DATATYPE_TIME || type == DATATYPE_BOTH) + menu.AddItem(NULL_STRING, "Change Time"); + + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_CrazyShop_ItemSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + CrazyShop_AdminPanel(param1); + } + + case MenuAction_Select: + CrazyShop_OpenItemAction(param1, param2); + } + + return 0; +} + +void CrazyShop_OpenItemAction(int client, int action) +{ + CrazyShop_Item item; + item = g_CrazyShopItems[g_iCrazyShopPreviousItem[client]]; + + /* 0 = price, 1 = amount (if type is amount or all), time (if type is time), 2 = time (if found) */ + Menu menu = new Menu(Menu_CrazyShop_ItemAction); + + if (action == 0) + { + menu.SetTitle("[CrazyShop] %s - Price\nCurrent Price: %d", item.name, item.price); + + for (int i = item.price, count; i <= item.price * 2; i += item.price / 4) + { + if (count <= 1) + i = item.price - item.price / 4; + + count++; + + if (i <= 0) + { + i += 2*(item.price / 4); + count--; + continue; + } + + char thisVal[3]; + IntToString(i, thisVal, sizeof(thisVal)); + + char data[sizeof(thisVal) + 2]; + FormatEx(data, sizeof(data), "0|%s", thisVal); + + menu.AddItem(data, thisVal); + } + } + + /* this is 100% time */ + if (action == 2) + { + menu.SetTitle("[CrazyShop] %s - Time\nCurrent Time: %.2f", item.name, item.time); + + for (float f = item.time, count; f <= item.time * 2.0; f += item.time / 4.0) + { + if (count <= 1.0) + f = item.time - (item.time / 4.0); + + count++; + + if (f <= 0.0) + { + f += 2*(item.time / 4.0); + count--; + continue; + } + + char thisVal[6]; + FloatToString(f, thisVal, sizeof(thisVal)); + + char data[sizeof(thisVal) + 2]; + FormatEx(data, sizeof(data), "2|%s", thisVal); + + menu.AddItem(data, thisVal); + } + } + + if (action == 1) + { + if (item.type == DATATYPE_TIME) + { + menu.SetTitle("[CrazyShop] %s - Time\nCurrent Time: %.2f", item.name, item.time); + + for (float f = item.time, count; f <= item.time * 2.0; f += item.time / 4.0) + { + if (count <= 1.0) + f = item.time - (item.time / 4.0); + + count++; + + if (f <= 0.0) + { + f += 2*(item.time / 4.0); + count--; + continue; + } + + char thisVal[6]; + FloatToString(f, thisVal, sizeof(thisVal)); + + char data[sizeof(thisVal) + 2]; + FormatEx(data, sizeof(data), "2|%s", thisVal); + + menu.AddItem(data, thisVal); + } + } + else + { + menu.SetTitle("[CrazyShop] %s - %s\nCurrent %s: %.2f", item.name, item.amountName, item.amountName, item.amount); + + for (float f = item.amount, count; f <= item.amount * 2; f += item.amount / 4.0) + { + if (count <= 1.0) + f = item.amount - (item.amount / 4.0); + + if (f <= 0.0) + { + f += 2*(item.amount / 4.0); + count--; + continue; + } + + count++; + char thisVal[6]; + FloatToString(f, thisVal, sizeof(thisVal)); + + char data[sizeof(thisVal) + 2]; + FormatEx(data, sizeof(data), "1|%s", thisVal); + + menu.AddItem(data, thisVal); + } + } + } + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_CrazyShop_ItemAction(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + CrazyShop_OpenItemSettings(param1, g_iCrazyShopPreviousItem[param1]); + } + + case MenuAction_Select: + { + char info[15]; + menu.GetItem(param2, info, sizeof(info)); + + char data[2][10]; + ExplodeString(info, "|", data, sizeof(data), sizeof(data[])); + + int itemAction = StringToInt(data[0]); + + switch (itemAction) + { + case 0: CrazyShop_UpdateItemData(param1, g_iCrazyShopPreviousItem[param1], "price", data[1]); + case 1: CrazyShop_UpdateItemData(param1, g_iCrazyShopPreviousItem[param1], "amount", data[1]); + case 2: CrazyShop_UpdateItemData(param1, g_iCrazyShopPreviousItem[param1], "time", data[1]); + } + } + } + + return 0; +} + +void CrazyShop_UpdateItemData(int client, int item, const char[] key, const char[] value) +{ + char filePath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, filePath, sizeof(filePath), "configs/FM_CrazyShop.cfg"); + + KeyValues kv = new KeyValues("Items"); + + if (!kv.ImportFromFile(filePath)) + { + CPrintToChat(client, "%s Sorry, no settings file was found, Changes will not be saved (Report this to the server manager).", THIS_MODE_INFO.tag); + delete kv; + } + + if (kv != null) + { + char keyNum[3]; + IntToString(item, keyNum, sizeof(keyNum)); + + if (kv.JumpToKey(keyNum)) + { + kv.SetString(key, value); + kv.Rewind(); + kv.ExportToFile(filePath); + } + else + CPrintToChat(client, "%s Sorry, the item is not in the settings file, changes will not be saved, (Report this to the server manager)", THIS_MODE_INFO.tag); + } + + delete kv; + + if (key[0] == 'p') + g_CrazyShopItems[item].price = StringToInt(value); + else if (key[0] == 'a') + g_CrazyShopItems[item].amount = StringToFloat(value); + else + g_CrazyShopItems[item].time = StringToFloat(value); + + CPrintToChat(client, "%s You have successfully changed {olive}%s {lightgreen}of %s {olive}to %s", THIS_MODE_INFO.tag, key, g_CrazyShopItems[item].name, value); +} + +public Action Cmd_CrazyShopSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_CrazyShopSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n "); + menu.AddItem(NULL_STRING, "Manage Shop Items"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_CrazyShopSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + if (param2 == 0) + ShowCvarsInfo(param1, THIS_MODE_INFO); + else + CrazyShop_AdminPanel(param1); + } + } + + return 0; +} + +Action Cmd_CrazyShopMenu(int client, int args) +{ + if (!THIS_MODE_INFO.isOn) + { + CReplyToCommand(client, "%s The CrazyShop Mode is currently OFF!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + if (!client) + return Plugin_Handled; + + if (THIS_MODE_INFO.cvarInfo[CRAZYSHOP_CONVAR_DISABLE_SHOP].cvar.BoolValue) + { + CReplyToCommand(client, "%s The shop is currently disabled!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + CrazyShop_OpenMenu(client); + return Plugin_Handled; +} + +Action Cmd_CrazyShopMyItems(int client, int args) +{ + if (!THIS_MODE_INFO.isOn) + { + CReplyToCommand(client, "%s The CrazyShop Mode is currently OFF!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + if (!client) + return Plugin_Handled; + + CrazyShop_OpenAvailableItems(client); + return Plugin_Handled; +} + +void CrazyShop_OpenMenu(int client) +{ + if (!THIS_MODE_INFO.isOn) + return; + + Menu menu = new Menu(Menu_CrazyShop); + + menu.SetTitle("[CrazyShop] Items List\nYour credits: %d$", PLAYER_CREDITS(client)); + + for (int i = 0; i < sizeof(g_CrazyShopItems); i++) + { + char team[10]; + team = (g_CrazyShopItems[i].team == 0) ? "Zombies" : "Humans"; + + char[] item = new char[sizeof(CrazyShop_Item::name) + strlen(team)]; + FormatEx(item, sizeof(CrazyShop_Item::name) + strlen(team), "%s - %d$ [%s]%s", g_CrazyShopItems[i].name, g_CrazyShopItems[i].price, team, i == (sizeof(g_CrazyShopItems)-1) ? "\n ":""); + + menu.AddItem(NULL_STRING, item, PLAYER_CREDITS(client) >= g_CrazyShopItems[i].price ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED); + } + + menu.AddItem(NULL_STRING, "Gift 5 credits", PLAYER_CREDITS(client) >= 5 ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED); + + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_CrazyShop(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Select: + { + if (!THIS_MODE_INFO.isOn) + return -1; + + // Gift 5 credits + if (param2 == sizeof(g_CrazyShopItems)) + { + CrazyShop_OpenGiftMenu(param1); + return -1; + } + + if (PLAYER_CREDITS(param1) < g_CrazyShopItems[param2].price) + { + CPrintToChat(param1, "%s You have insufficent credits to buy this item.", THIS_MODE_INFO.tag); + return -1; + } + + PLAYER_CREDITS(param1) -= g_CrazyShopItems[param2].price; + PLAYER_ITEM_COUNT(param1, param2) += 1; + CPrintToChat(param1, "%s You have successfully bought {olive}%s, {lightgreen}Type !myitems to activate it!", THIS_MODE_INFO.tag, g_CrazyShopItems[param2].name); + CPrintToChat(param1, "{lightgreen}You can also press the {olive}FlashLight {lightgreen}button to see your inventory!"); + CrazyShop_OpenMenu(param1); + } + } + + return -1; +} + +void CrazyShop_OpenGiftMenu(int client) +{ + Menu menu = new Menu(Menu_CrazyShop_Gift); + + menu.SetTitle("[CrazyShop] Select Player to gift 5 credits"); + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i) || i == client) + continue; + + char userId[10]; + IntToString(GetClientUserId(i), userId, sizeof(userId)); + + char item[64]; + FormatEx(item, sizeof(item), "%N - [%d$]", i, PLAYER_CREDITS(i)); + + menu.AddItem(userId, item); + } + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_CrazyShop_Gift(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + CrazyShop_OpenMenu(param1); + } + + case MenuAction_Select: + { + if (!THIS_MODE_INFO.isOn) + return -1; + + if (PLAYER_CREDITS(param1) < 5) + { + CPrintToChat(param1, "%s You do not have 5 credits to gift.", THIS_MODE_INFO.tag); + return -1; + } + + char userId[10]; + menu.GetItem(param2, userId, sizeof(userId)); + + int target = GetClientOfUserId(StringToInt(userId)); + if (!target) + { + CPrintToChat(param1, "%s Player is no longer available!", THIS_MODE_INFO.tag); + return -1; + } + + PLAYER_CREDITS(target) += 5; + PLAYER_CREDITS(param1) -= 5; + CPrintToChat(param1, "%s You have gifted {olive}%N {lightgreen}5 credits, you are so generous!", THIS_MODE_INFO.tag, target); + CPrintToChat(target, "%s %N {olive}has gifted you 5 credits! What a generous man!", THIS_MODE_INFO.tag, param1); + } + } + + return -1; +} + +void CrazyShop_OpenAvailableItems(int client) +{ + if (!g_bMotherZombie || g_bRoundEnd) + return; + + bool found = false; + + Menu menu; + + if (!IsPlayerAlive(client)) + { + CPrintToChat(client, "%s you have to be alive to use this command!", THIS_MODE_INFO.tag); + return; + } + + for (int i = 0; i < sizeof(CrazyShop_PlayerData::itemsCount); i++) + { + if (((g_CrazyShopItems[i].team == 0 && ZR_IsClientZombie(client)) || + (g_CrazyShopItems[i].team == 1 && ZR_IsClientHuman(client))) && PLAYER_ITEM_COUNT(client, i)) + { + found = true; + + if (menu == null) + { + menu = new Menu(Menu_AvailableItems); + menu.SetTitle("[CrazyShop] Your Available Items!"); + } + + if (menu) + { + char item[64]; + FormatEx(item, sizeof(item), "%s - Activate", g_CrazyShopItems[i].name); + + char data[3]; + IntToString(i, data, sizeof(data)); + menu.AddItem(data, item); + } + } + } + + if (!found) + { + CPrintToChat(client, "%s You have no available items!", THIS_MODE_INFO.tag); + return; + } + + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_AvailableItems(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Select: + { + if (!THIS_MODE_INFO.isOn) + return -1; + + char data[3]; + menu.GetItem(param2, data, sizeof(data)); + + int itemNum = StringToInt(data); + + if (PLAYER_ITEM_COUNT(param1, itemNum) <= 0) + { + CPrintToChat(param1, "%s You do not have this item in your inventory", THIS_MODE_INFO.tag); + return 0; + } + + if (!IsPlayerAlive(param1)) + { + CPrintToChat(param1, "%s You have to be alive to activate items!", THIS_MODE_INFO.tag); + return -1; + } + + CrazyShop_Item item; + item = g_CrazyShopItems[itemNum]; + bool isZombie = ZR_IsClientZombie(param1); + if (item.team == 0 && !isZombie) + { + CPrintToChat(param1, "%s This item is for zombies only!", THIS_MODE_INFO.tag); + return -1; + } + + if (item.team == 1 && isZombie) + { + CPrintToChat(param1, "%s This item is for humans only!", THIS_MODE_INFO.tag); + return -1; + } + + CrazyShop_Activate(param1, itemNum); + CrazyShop_OpenAvailableItems(param1); + } + } + + return -1; +} + +void CrazyShop_Activate(int client, int itemNum) +{ + if (!IsPlayerAlive(client)) + { + CPrintToChat(client, "%s You are not alive to activate this item.", THIS_MODE_INFO.tag); + return; + } + + CrazyShop_Item item; + item = g_CrazyShopItems[itemNum]; + + if (item.team == 1 && !ZR_IsClientHuman(client)) + { + CPrintToChat(client, "%s This is a human item, you cannot use it right now!", THIS_MODE_INFO.tag); + return; + } + + if (item.team == 0 && !ZR_IsClientZombie(client)) + { + CPrintToChat(client, "%s This is a zombie item, you cannot use it right now!", THIS_MODE_INFO.tag); + return; + } + + if (PLAYER_ITEM_ACTIVE(client, itemNum)) + { + CPrintToChat(client, "%s You cannot activate the same item again unless the old ones' effect ended", THIS_MODE_INFO.tag); + return; + } + + switch (itemNum) + { + // HP - Humans + case 0: + { + int maxHealth = GetEntProp(client, Prop_Data, "m_iMaxHealth"); + SetEntProp(client, Prop_Data, "m_iMaxHealth", maxHealth + RoundToNearest(item.amount)); + + int health = RoundToNearest(item.amount); + SetEntityHealth(client, GetClientHealth(client) + health); + + CPrintToChat(client, "%s You have given yourself {olive}%d {lightgreen}more HP", THIS_MODE_INFO.tag, health); + } + + // Infection Protection - Humans + case 1: + { + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + PLAYER_TEMP_VAR(client, infectionProtect) = true; + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_InfectionProtection, pack, TIMER_FLAG_NO_MAPCHANGE); + } + + // Super Weapon - Humans + case 2: + { + #if defined _KnockbackRestrict_included_ + if (KR_ClientStatus(client)) + { + CPrintToChat(client, "%s You cannot use this item while you are kbanned!", THIS_MODE_INFO.tag); + return; + } + #endif + + static const char weaponsList[][] = + { + "weapon_mac10", "weapon_tmp", "weapon_mp5navy", "weapon_ump45", "weapon_p90", + "weapon_galil", "weapon_famas", "weapon_ak47", "weapon_m4a1", "weapon_sg552", "weapon_aug", + "weapon_m249" + }; + + strcopy(PLAYER_TEMP_VAR(client, superWeaponName), sizeof(CrazyShop_PlayerData::superWeaponName), + weaponsList[GetRandomInt(0, sizeof(weaponsList) - 1)]); + + int wp = GetPlayerWeaponSlot(client, CS_SLOT_PRIMARY); + if (IsValidEntity(wp)) + GetEntityClassname(wp, PLAYER_TEMP_VAR(client, originalWeapon), sizeof(CrazyShop_PlayerData::originalWeapon)); + + if (strcmp(PLAYER_TEMP_VAR(client, originalWeapon), PLAYER_TEMP_VAR(client, superWeaponName)) == 0) + PLAYER_TEMP_VAR(client, originalWeapon)[0] = '\0'; + else + { + #if defined _FM_GunGame + GunGame_EquipWeapon(client, PLAYER_TEMP_VAR(client, superWeaponName), true); + #endif + } + + FunModes_HookEvent(g_bEvent_WeaponFire, "weapon_fire", Event_WeaponFire_CrazyShop); + + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + PLAYER_TEMP_VAR(client, superWeapon) = true; + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_SuperWeapon, pack, TIMER_FLAG_NO_MAPCHANGE); + } + + // Laser Protection - Humans + case 3: + { + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + PLAYER_TEMP_VAR(client, laserProtect) = true; + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_LaserProtection, pack, TIMER_FLAG_NO_MAPCHANGE); + } + + // Unlimited Ammo - Humans + case 4: + { + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + + PLAYER_TEMP_VAR(client, unlimitedAmmo) = true; + + FunModes_HookEvent(g_bEvent_WeaponFire, "weapon_fire", Event_WeaponFire_CrazyShop); + + DataPack pack = new DataPack(); + + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_UnlimitedAmmo, pack, TIMER_FLAG_NO_MAPCHANGE); + + CPrintToChat(client, "%s You have activated unlimited Ammo, Go Hunt the Zombies!", THIS_MODE_INFO.tag); + } + + // Buy a smokegrenade + case 5: + { + GiveGrenadesToClient(client, GrenadeType_Smokegrenade, 1); + + int wp = GivePlayerItem(client, "weapon_smokegrenade"); + EquipPlayerWeapon(client, wp); + + CPrintToChat(client, "%s You have given yourself a smokegrenade! {olive}Freeze the zombies now!", THIS_MODE_INFO.tag); + } + + // Slow Beacon + case 6: + { + int userid = GetClientUserId(client); + + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + + delete PLAYER_TEMP_VAR(client, slowBeaconTimer); + PLAYER_TEMP_VAR(client, slowBeaconTimer) = CreateTimer(0.1, Timer_SlowBeaconRepeat, userid, TIMER_REPEAT); + + CreateTimer(item.time, Timer_CrazyShop_SlowBeacon, userid, TIMER_FLAG_NO_MAPCHANGE); + + CPrintToChat(client, "%s You have activated slow beacon, you can slow down the zombies if they got close to your beacon!", THIS_MODE_INFO.tag); + } + + // More Speed - Zombies + case 7: + { + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + + float originalSpeed = GetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue"); + + SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", originalSpeed + item.amount); + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + pack.WriteFloat(originalSpeed); + + CreateTimer(item.time, Timer_CrazyShop_MoreSpeed, pack, TIMER_FLAG_NO_MAPCHANGE); + } + + // KB Protection - Zombies + case 8: + { + PLAYER_TEMP_VAR(client, kbProtect) = true; + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_KBProtection, pack, TIMER_FLAG_NO_MAPCHANGE); + + CPrintToChat(client, "%s You have activated KB protection, your knockback will be much less now!", THIS_MODE_INFO.tag); + } + + // Lower Gravity - Zombies + case 9: + { + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + + SetEntityGravity(client, 1.0 + item.amount); + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_LowerGravity, pack, TIMER_FLAG_NO_MAPCHANGE); + + CPrintToChat(client, "%s You have been given lower gravity, use it wisely!", THIS_MODE_INFO.tag); + } + + // Hurting Machine - Zombies + case 10: + { + if (g_iCrazyShopProps >= 2) + { + CPrintToChat(client, "%s Please wait until the older hurting machines die!", THIS_MODE_INFO.tag); + return; + } + + int userid = GetClientOfUserId(client); + char propName[64]; + FormatEx(propName, sizeof(propName), "%d_FM_PROP_%d_%d", RoundToNearest(item.amount), userid, GetGameTime()); + + int prop = CrazyShop_CreateProp(propName); + if (prop == -1) + { + CPrintToChat(client, "%s Failed to activate this item, try again later", THIS_MODE_INFO.tag); + return; + } + + CrazyShop_ThrowProp(client, prop); + + DataPack pack = new DataPack(); + pack.WriteCell(userid); + pack.WriteCell(EntIndexToEntRef(prop)); + + CreateTimer(item.time, Timer_CrazyShop_HurtingMachine, pack, TIMER_FLAG_NO_MAPCHANGE); + } + + // Ignite Immunity - Zombies + case 11: + { + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + PLAYER_TEMP_VAR(client, igniteImmunity) = true; + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_IgniteImmunity, pack, TIMER_FLAG_NO_MAPCHANGE); + + CPrintToChat(client, "%s You have activated ignite immunity, you won't be on fire for now!", THIS_MODE_INFO.tag); + } + + // Invisibility - Zombies + case 12: + { + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + + int nodraw = 0x20; + + SetEntProp(client, Prop_Send, "m_fEffects", GetEntProp(client, Prop_Send, "m_fEffects") | nodraw); + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_Invisibility, pack, TIMER_FLAG_NO_MAPCHANGE); + + CPrintToChat(client, "%s You are invisibile now, shhh!", THIS_MODE_INFO.tag); + } + + // Human Pull - Zombies + case 13: + { + int target = GetClientAimTarget(client); + if (target == -1 || !IsPlayerAlive(target) || !ZR_IsClientHuman(target)) + { + CPrintToChat(client, "%s Canceling the activation of this item, please aim at a human!", THIS_MODE_INFO.tag); + return; + } + + PLAYER_ITEM_ACTIVE(client, itemNum) = true; + + CrazyShop_StartGrab(client, target); + + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(itemNum); + + CreateTimer(item.time, Timer_CrazyShop_Pull, pack, TIMER_FLAG_NO_MAPCHANGE); + + CPrintToChat(client, "%s You are now pulling a human xD", THIS_MODE_INFO.tag); + } + } + + if (item.time > 0.0) + { + SetEntPropFloat(client, Prop_Send, "m_flProgressBarStartTime", GetGameTime()); + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", RoundToNearest(item.time)); + } + + PLAYER_ITEM_COUNT(client, itemNum)--; +} + +Action Timer_CrazyShop_InfectionProtection(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + + PLAYER_TEMP_VAR(client, infectionProtect) = false; + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +Action Timer_CrazyShop_SuperWeapon(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + + PLAYER_TEMP_VAR(client, superWeaponName)[0] = '\0'; + PLAYER_TEMP_VAR(client, superWeapon) = false; + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + + if (!THIS_MODE_INFO.isOn || g_bRoundEnd) + return Plugin_Stop; + + if (IsPlayerAlive(client) && ZR_IsClientHuman(client) && PLAYER_TEMP_VAR(client, originalWeapon)[0]) + { + #if defined _FM_GunGame + GunGame_EquipWeapon(client, PLAYER_TEMP_VAR(client, originalWeapon), true); + #endif + + PLAYER_TEMP_VAR(client, originalWeapon)[0] = '\0'; + } + + return Plugin_Stop; +} + +Action Timer_CrazyShop_LaserProtection(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + + PLAYER_TEMP_VAR(client, laserProtect) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +Action Timer_CrazyShop_UnlimitedAmmo(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + PLAYER_TEMP_VAR(client, unlimitedAmmo) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +Action Timer_CrazyShop_SlowBeacon(Handle timer, int userid) +{ + int client = GetClientOfUserId(userid); + if (!client) + { + CrazyShop_ResetSpeed(); + return Plugin_Stop; + } + + PLAYER_TEMP_VAR(client, slowBeaconTimer) = null; + PLAYER_ITEM_ACTIVE(client, 6) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +Action Timer_SlowBeaconRepeat(Handle timer, int userid) +{ + int client = GetClientOfUserId(userid); + if (!client) + { + CrazyShop_ResetSpeed(); + return Plugin_Stop; + } + + int itemNum = 6; + + if (!THIS_MODE_INFO.isOn || g_bRoundEnd) + { + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + CrazyShop_ResetSpeed(); + PLAYER_TEMP_VAR(client, slowBeaconTimer) = null; + return Plugin_Stop; + } + + if (!IsPlayerAlive(client) || ZR_IsClientZombie(client)) + { + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + CrazyShop_ResetSpeed(); + PLAYER_TEMP_VAR(client, slowBeaconTimer) = null; + return Plugin_Stop; + } + + if (!PLAYER_ITEM_ACTIVE(client, itemNum)) + { + CrazyShop_ResetSpeed(); + PLAYER_TEMP_VAR(client, slowBeaconTimer) = null; + return Plugin_Stop; + } + + float beaconRadius = THIS_MODE_INFO.cvarInfo[CRAZYSHOP_CONVAR_SLOWBEACON_RADIUS].cvar.FloatValue; + BeaconPlayer(client, 0, beaconRadius, { 255, 255, 255, 255 } ); + + // check for distance + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || !IsPlayerAlive(i) || !ZR_IsClientZombie(i)) + continue; + + float squarredDistance = GetDistanceBetween(client, i, true); + if (!PLAYER_TEMP_VAR(i, gotSlowed) && squarredDistance <= ((beaconRadius/2.0)*(beaconRadius/2.0))) + { + PLAYER_TEMP_VAR(i, gotSlowed) = true; + PLAYER_TEMP_VAR(i, originalSpeed) = GetEntPropFloat(i, Prop_Data, "m_flLaggedMovementValue"); + SetEntPropFloat(i, Prop_Data, "m_flLaggedMovementValue", g_CrazyShopItems[itemNum].amount); + } + else + { + if (PLAYER_TEMP_VAR(i, gotSlowed) && PLAYER_TEMP_VAR(i, originalSpeed) > 0.0) + { + // More Speed - 4 + if (PLAYER_ITEM_ACTIVE(i, 4)) + continue; + + PLAYER_TEMP_VAR(i, gotSlowed) = false; + SetEntPropFloat(i, Prop_Data, "m_flLaggedMovementValue", PLAYER_TEMP_VAR(i, originalSpeed)); + } + } + } + + return Plugin_Continue; +} + +void CrazyShop_ResetSpeed() +{ + for (int i = 1; i <= MaxClients; i++) + { + if (PLAYER_TEMP_VAR(i, gotSlowed) && PLAYER_TEMP_VAR(i, originalSpeed) > 0.0) + { + // More Speed - 4 + if (PLAYER_ITEM_ACTIVE(i, 4)) + continue; + + PLAYER_TEMP_VAR(i, gotSlowed) = false; + SetEntPropFloat(i, Prop_Data, "m_flLaggedMovementValue", PLAYER_TEMP_VAR(i, originalSpeed)); + } + } +} + +Action Timer_CrazyShop_MoreSpeed(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + float speed = pack.ReadFloat(); + + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + + delete pack; + + if (!THIS_MODE_INFO.isOn || g_bRoundEnd) + return Plugin_Stop; + + SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", speed); + return Plugin_Stop; +} + +Action Timer_CrazyShop_KBProtection(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + + PLAYER_TEMP_VAR(client, kbProtect) = false; + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +Action Timer_CrazyShop_LowerGravity(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + + SetEntityGravity(client, 1.0); + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +Action Timer_CrazyShop_IgniteImmunity(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + PLAYER_TEMP_VAR(client, igniteImmunity) = false; + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +Action Timer_CrazyShop_Invisibility(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + + int nodraw = 0x20; + SetEntProp(client, Prop_Send, "m_fEffects", GetEntProp(client, Prop_Send, "m_fEffects") & ~nodraw); + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +Action Timer_CrazyShop_Pull(Handle timer, DataPack pack) +{ + pack.Reset(); + int client = GetClientOfUserId(pack.ReadCell()); + if (!client) + { + delete pack; + return Plugin_Stop; + } + + int itemNum = pack.ReadCell(); + delete pack; + + PLAYER_ITEM_ACTIVE(client, itemNum) = false; + int target = PLAYER_TEMP_VAR(client, grabbedTarget); + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + + if (target == -1) + return Plugin_Stop; + + PLAYER_TEMP_VAR(client, grabbedTarget) = -1; + + PLAYER_ITEM_ACTIVE(target, 1) = false; + PLAYER_TEMP_VAR(target, infectionProtect) = false; + + SetEntPropFloat(target, Prop_Send, "m_flMaxspeed", PLAYER_TEMP_VAR(client, originalTargetMaxSpeed)); + + return Plugin_Stop; +} + +void CrazyShop_StartGrab(int client, int target) +{ + PLAYER_ITEM_ACTIVE(target, 1) = true; + PLAYER_TEMP_VAR(target, infectionProtect) = true; + + PLAYER_TEMP_VAR(client, grabbedTarget) = target; + + PLAYER_TEMP_VAR(client, originalTargetMaxSpeed) = GetEntPropFloat(target, Prop_Send, "m_flMaxspeed"); + SetEntPropFloat(target, Prop_Send, "m_flMaxspeed", 0.01); + + CreateTimer(0.05, CrazyShop_Timer_Grabbing, client, TIMER_REPEAT); +} + +Action CrazyShop_Timer_Grabbing(Handle timer, int client) +{ + int itemNum = 13; + if (!PLAYER_ITEM_ACTIVE(client, itemNum)) + return Plugin_Stop; + + int target = PLAYER_TEMP_VAR(client, grabbedTarget); + if (target == -1 || !IsPlayerAlive(target) || !ZR_IsClientHuman(target) || !IsPlayerAlive(client) || ZR_IsClientHuman(client)) + return Plugin_Stop; + + float clientEyePos[3], targetEyePos[3]; + GetClientEyePosition(client, clientEyePos); + GetClientEyePosition(target, targetEyePos); + + float distance = GetVectorDistance(clientEyePos, targetEyePos, true); + if (distance > 40000.0) + { + float velocity[3]; + SubtractVectors(clientEyePos, targetEyePos, velocity); + NormalizeVector(velocity, velocity); + ScaleVector(velocity, 300.0); + TeleportEntity(target, _, _, velocity); + } + + TE_SetupBeamPoints(clientEyePos, targetEyePos, g_iLaserBeam, 0, 0, 66, 0.2, 1.0, 10.0, 0, 0.0, {255,255,255,255}, 0); + TE_SendToAll(); + + return Plugin_Continue; +} + +stock bool TraceRayTryToHit(int entity, int mask) +{ + #pragma unused mask + if (entity > 0 && entity <= MaxClients) + return false; + + return true; +} + +/*******************************************************************/ +Action Timer_CrazyShop_HurtingMachine(Handle timer, DataPack pack) +{ + pack.Reset(); + + int client = GetClientOfUserId(pack.ReadCell()); + int prop = EntRefToEntIndex(pack.ReadCell()); + + delete pack; + + g_iCrazyShopProps--; + + if (prop == INVALID_ENT_REFERENCE) + return Plugin_Stop; + + RemoveEntity(prop); + + if (!client) + return Plugin_Stop; + + SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); + return Plugin_Stop; +} + +void CrazyShop_ThrowProp(int client, int prop) +{ + float vecEyeAngles[3]; + float vecEyePos[3]; + + GetClientEyeAngles(client, vecEyeAngles); + GetClientEyePosition(client, vecEyePos); + + float vecForward[3]; + GetAngleVectors(vecEyeAngles, vecForward, NULL_VECTOR, NULL_VECTOR); + + ScaleVector(vecForward, 100.0); + + float spawnOrigin[3]; + AddVectors(vecEyePos, vecForward, spawnOrigin); + + TeleportEntity(prop, spawnOrigin, vecEyeAngles, vecEyeAngles); + + DispatchSpawn(prop); + + g_iCrazyShopProps++; +} + +stock int CrazyShop_CreateProp(const char[] name) +{ + int ent = CreateEntityByName("prop_physics_override"); + if (ent == -1) + return -1; + + DispatchKeyValue(ent, "targetname", name); + DispatchKeyValue(ent, "solid", "0"); + DispatchKeyValue(ent, "model", PROP_MODEL); + DispatchKeyValue(ent, "disableshadows", "1"); + DispatchKeyValue(ent, "disablereceiveshadows", "1"); + + SDKHook(ent, SDKHook_SpawnPost, Prop_Spawn); + + return ent; +} + +void Prop_Spawn(int entity) +{ + SDKHook(entity, SDKHook_StartTouch, Hook_PropHit); + SDKHook(entity, SDKHook_OnTakeDamage, Hook_PropDamage); +} + +public Action Hook_PropDamage(int entity, int& attacker, int& inflictor, float& damage, int& damagetype) +{ + return Plugin_Handled; +} + +Action Hook_PropHit(int entity, int other) +{ + if (!(1<=other<=MaxClients)) + return Plugin_Continue; + + if (!IsPlayerAlive(other) || ZR_IsClientZombie(other)) + return Plugin_Continue; + + if (PLAYER_TEMP_VAR(other, protectLaser)) + return Plugin_Continue; + + char name[64]; + GetEntPropString(entity, Prop_Data, "m_iName", name, sizeof(name)); + + char vals[5][10]; + ExplodeString(name, "_", vals, sizeof(vals), sizeof(vals[])); + + int damage = StringToInt(vals[0]); + if (damage == 0) + return Plugin_Continue; + + // Decide what to do: + if (damage > 100) + { + ForcePlayerSuicide(other); + return Plugin_Continue; + } + + SDKHooks_TakeDamage(other, 0, 0, float(damage)); + + return Plugin_Continue; +} + +/****************************************************************/ +/* TODO: Maybe move this to FunModes.sp? */ +public Action ZR_OnClientInfect(int &client, int &attacker, bool &motherInfect) +{ + if (!THIS_MODE_INFO.isOn) + return Plugin_Continue; + + if (!PLAYER_TEMP_VAR(client, infectionProtect)) + return Plugin_Continue; + + return Plugin_Handled; +} + +#undef THIS_MODE_DB +#undef CRAZYSHOP_DB_NAME +#undef PLAYER_CREDITS +#undef PLAYER_ITEM_COUNT +#undef PLAYER_ITEM_ACTIVE +#undef DAMAGE_DEALT +#undef PLAYER_IN_DB +#undef PLAYER_RESET \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/DamageGame.sp b/addons/sourcemod/scripting/Fun_Modes/DamageGame.sp index 043346e..4451a15 100644 --- a/addons/sourcemod/scripting/Fun_Modes/DamageGame.sp +++ b/addons/sourcemod/scripting/Fun_Modes/DamageGame.sp @@ -1,45 +1,179 @@ #pragma semicolon 1 #pragma newdecls required +ModeInfo g_DamageGameInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_DamageGameInfo + int g_iDealtDamage[MAXPLAYERS + 1] = {-1, ...}; +Handle g_hDamageGameTimer; +bool g_bDamageGameDisable; -ConVarInfo g_cvInfoDamageGame[2] = -{ - {null, "15.0,20.0,30.0,40.0", "float"}, - {null, "5.0,10.0,15.0,20.0", "float"} -}; +#define DAMAGEGAME_CONVAR_TIME_INTERVAL 0 +#define DAMAGEGAME_CONVAR_DAMAGE 1 +#define DAMAGEGAME_CONVAR_MODE 2 +#define DAMAGEGAME_CONVAR_TOGGLE 3 /* CALLED on Plugin Start */ -stock void PluginStart_DamageGame() +stock void OnPluginStart_DamageGame() { + THIS_MODE_INFO.name = "DamageGame"; + THIS_MODE_INFO.tag = "{gold}[FunModes-DamageGame]{lightgreen}"; + /* ADMIN COMMANDS */ - RegAdminCmd("sm_fm_damage", Cmd_DamageGame, ADMFLAG_CONVARS, "Enable/Disable Damage Game mode."); - RegAdminCmd("sm_fm_damagegame", Cmd_DamageGame, ADMFLAG_CONVARS, "Enable/Disable Damage Game mode."); - RegAdminCmd("sm_fm_dg", Cmd_DamageGame, ADMFLAG_CONVARS, "Enable/Disable Damage Game mode."); + RegAdminCmd("sm_fm_damage", Cmd_DamageGameToggle, ADMFLAG_CONVARS, "Enable/Disable Damage Game mode."); + RegAdminCmd("sm_fm_damagegame", Cmd_DamageGameToggle, ADMFLAG_CONVARS, "Enable/Disable Damage Game mode."); + RegAdminCmd("sm_fm_dg", Cmd_DamageGameToggle, ADMFLAG_CONVARS, "Enable/Disable Damage Game mode."); /* CONVARS */ - g_cvDamageGameTimer = CreateConVar("sm_damagegame_time_interval", "15.0", "Damage Game Timer Interval"); - g_cvDamageGameDamage = CreateConVar("sm_damagegame_damage", "15.0", "The amount of damage to apply to players who don't shoot zombies"); + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DAMAGEGAME_CONVAR_TIME_INTERVAL, + "sm_damagegame_time_interval", "15.0", "Damage Game Timer Interval", + ("15.0,20.0,30.0,40.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DAMAGEGAME_CONVAR_DAMAGE, + "sm_damagegame_damage", "15.0", "The amount of damage to apply to players who don't shoot zombies", + ("5.0,10.0,15.0,20.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DAMAGEGAME_CONVAR_MODE, + "sm_damagegame_mode", "0", "DamageGame Mode (0 = Worst defenders, 1 = Doesn't defend for x time, 2 = Both)", + ("0,1,2"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DAMAGEGAME_CONVAR_TOGGLE, + "sm_damagegame_enable", "1", "Enable/Disable Damage Game", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = DAMAGEGAME_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[DAMAGEGAME_CONVAR_TOGGLE].cvar.AddChangeHook(OnDamageGameModeToggle); + + THIS_MODE_INFO.cvarInfo[DAMAGEGAME_CONVAR_MODE].cvar.AddChangeHook(OnDamageGameModeChange); +} + +void OnDamageGameModeToggle(ConVar cvar, const char[] oldValue, const char[] newValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +void OnDamageGameModeChange(ConVar cvar, const char[] oldValue, const char[] newValue) +{ + for (int i = 1; i <= MaxClients; i++) + g_iDealtDamage[i] = -1; + + DamageGame_StartTimers(); +} + +stock void OnMapStart_DamageGame() {} +stock void OnMapEnd_DamageGame() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + g_hDamageGameTimer = null; +} + +stock void OnClientPutInServer_DamageGame(int client) +{ + if (g_bSDKHook_OnTakeDamagePost[client]) + return; + + SDKHook(client, SDKHook_OnTakeDamagePost, OnTakeDamagePost); + g_bSDKHook_OnTakeDamagePost[client] = true; +} + +stock void OnClientDisconnect_DamageGame(int client) +{ + if (!THIS_MODE_INFO.isOn) + return; + + g_iDealtDamage[client] = -1; +} + +stock void ZR_OnClientInfected_DamageGame(int client) +{ + #pragma unused client + if (!THIS_MODE_INFO.isOn) + return; + + if (!g_bMotherZombie && g_hDamageGameTimer == null) + DamageGame_StartTimers(); +} + +stock void Event_RoundStart_DamageGame() +{ + if (!THIS_MODE_INFO.isOn) + return; + + for (int i = 1; i <= MaxClients; i++) + g_iDealtDamage[i] = -1; + + delete g_hDamageGameTimer; +} + +stock void Event_RoundEnd_DamageGame() {} +stock void Event_PlayerSpawn_DamageGame(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_DamageGame(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_DamageGame(int client) +{ + if (!THIS_MODE_INFO.isOn) + return; - DamageGame_SetCvarsInfo(); + g_iDealtDamage[client] = -1; } -void DamageGame_SetCvarsInfo() +stock void OnTakeDamagePost_DamageGame(int victim, int attacker, float damage) { - ConVar cvars[sizeof(g_cvInfoDamageGame)]; - cvars[0] = g_cvDamageGameTimer; - cvars[1] = g_cvDamageGameDamage; + if (!THIS_MODE_INFO.isOn) + return; + + if (!(IsPlayerAlive(victim) && ZR_IsClientZombie(victim))) + return; + + if (!(0 < attacker <= MaxClients && IsPlayerAlive(attacker) && ZR_IsClientHuman(attacker))) + return; - for (int i = 0; i < sizeof(g_cvInfoDamageGame); i++) - g_cvInfoDamageGame[i].cvar = cvars[i]; + g_iDealtDamage[attacker] += RoundToNearest(damage); } -Action Cmd_DamageGame(int client, int args) +stock void OnWeaponEquip_DamageGame(int client, int weapon, Action &result) { - g_bIsDamageGameOn = !g_bIsDamageGameOn; - CPrintToChatAll("%s Damage Game is now {olive}%s.", DamageGame_Tag, (g_bIsDamageGameOn) ? "Enabled" : "Disabled"); + #pragma unused client + #pragma unused weapon + #pragma unused result +} - if (g_bIsDamageGameOn) +public Action Cmd_DamageGameToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s Damage Game mode is currently disabled!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s Damage Game is now {olive}%s.", THIS_MODE_INFO.tag, (THIS_MODE_INFO.isOn) ? "Enabled" : "Disabled"); + + if (THIS_MODE_INFO.isOn) { /* Events Hooks */ FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); @@ -48,15 +182,15 @@ Action Cmd_DamageGame(int client, int args) for (int i = 1; i <= MaxClients; i++) { - if (!IsClientConnected(i)) + g_iDealtDamage[i] = -1; + + if (!IsClientInGame(i)) continue; - OnClientPutInServer(i); + OnClientPutInServer_DamageGame(i); } - DamageGame_StartTimers(); - - CPrintToChatAll("%s Humans with lowest damage dealt to zombies will get damaged every %.2f seconds!", DamageGame_Tag, g_cvDamageGameTimer.FloatValue); + CS_TerminateRound(3.0, CSRoundEnd_Draw); } else { @@ -68,24 +202,50 @@ Action Cmd_DamageGame(int client, int args) void DamageGame_StartTimers() { + int interval = THIS_MODE_INFO.cvarInfo[DAMAGEGAME_CONVAR_TIME_INTERVAL].cvar.IntValue; + delete g_hDamageGameTimer; - g_hDamageGameTimer = CreateTimer(g_cvDamageGameTimer.FloatValue, Timer_DamageGame, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); + g_hDamageGameTimer = CreateTimer(float(interval), Timer_DamageGame, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); + switch (THIS_MODE_INFO.cvarInfo[DAMAGEGAME_CONVAR_MODE].cvar.IntValue) + { + case 0: CPrintToChatAll("%s Humans with lowest damage dealt to zombies will get damaged every %d seconds!", THIS_MODE_INFO.tag, interval); + case 1: CPrintToChatAll("%s Humans who don't shoot zombies for {olive}%d seconds {lightgreen}(repeated) will be damaged", THIS_MODE_INFO.tag, interval); + default: + { + CPrintToChatAll("%s Humans with lowest damage dealt to zombies will get damaged every %d seconds! (This doesn't include humans who don't defend at all)", THIS_MODE_INFO.tag, interval); + CPrintToChatAll("%s Humans who don't shoot zombies for {olive}%d seconds {lightgreen}(repeated) will be damaged", THIS_MODE_INFO.tag, interval); + } + } } Action Timer_DamageGame(Handle timer) { - if (!g_bMotherZombie || g_bRoundEnd) + if (!THIS_MODE_INFO.isOn) + { + g_hDamageGameTimer = null; + return Plugin_Stop; + } + + if (g_bDamageGameDisable) return Plugin_Handled; + if (!g_bMotherZombie || g_bRoundEnd) + return Plugin_Handled; + int lowestDamage = 999999, count, clients[MAXPLAYERS + 1]; + int mode = THIS_MODE_INFO.cvarInfo[DAMAGEGAME_CONVAR_MODE].cvar.IntValue; + for (int i = 1; i <= MaxClients; i++) { int thisDamage = 0; if (g_iDealtDamage[i] < 0) { if (!IsClientInGame(i) || !IsPlayerAlive(i) || ZR_IsClientZombie(i)) + { + g_iDealtDamage[i] = -1; continue; + } g_iDealtDamage[i] = 0; } @@ -94,77 +254,108 @@ Action Timer_DamageGame(Handle timer) thisDamage = g_iDealtDamage[i]; } - if (thisDamage >= 0 && thisDamage < lowestDamage) + if ((mode > 0 && thisDamage == 0) || (mode != 1 && (thisDamage == 0 || thisDamage < lowestDamage))) { + clients[count++] = i; lowestDamage = thisDamage; } } - if (lowestDamage == 999999) + if (mode == 0 && lowestDamage == 999999) return Plugin_Continue; - - for (int i = 1; i <= MaxClients; i++) + + if (!count) + return Plugin_Continue; + + /* Depending on the damagegame mode, we will specify which clients to damage */ + for (int i = 0; i < count; i++) { - if (lowestDamage == g_iDealtDamage[i]) + int client = clients[i]; + switch (mode) { - clients[count] = i; - count++; + case 0: + { + if (lowestDamage == g_iDealtDamage[client]) + DamageGame_DamagePlayer(client); + } + + case 1: + { + if (g_iDealtDamage[client] == 0) + DamageGame_DamagePlayer(client); + } + + default: + { + if (g_iDealtDamage[client] == 0 || (lowestDamage != 0 && lowestDamage == g_iDealtDamage[client])) + DamageGame_DamagePlayer(client); + } } } - - // We got the players who dealt the lowest damage, Lets damage THEM! - for (int i = 0; i < count; i++) + + if (mode > 0) { - int client = clients[i]; - int health = GetClientHealth(client); - int newHealth = health - g_cvDamageGameDamage.IntValue; - if (newHealth <= 0) - ForcePlayerSuicide(client); - else - SetEntityHealth(client, newHealth); - - CPrintToChat(client, "%s You have been damaged for being a bad defender", DamageGame_Tag); - CPrintToChatAll("%s %N {olive}got damaged for being a bad defender!", DamageGame_Tag, client); + for (int i = 1; i <= MaxClients; i++) + g_iDealtDamage[i] = -1; } - + return Plugin_Continue; } -stock void RoundStart_DamageGame() +void DamageGame_DamagePlayer(int client) { - if (!g_bIsDamageGameOn) - return; + int health = GetClientHealth(client); + int newHealth = health - THIS_MODE_INFO.cvarInfo[DAMAGEGAME_CONVAR_DAMAGE].cvar.IntValue; + if (newHealth <= 0) + ForcePlayerSuicide(client); + else + SetEntityHealth(client, newHealth); - for (int i = 1; i <= MaxClients; i++) - g_iDealtDamage[i] = -1; - - DamageGame_StartTimers(); + CPrintToChat(client, "%s You have been damaged for being a bad defender", THIS_MODE_INFO.tag); + CPrintToChatAll("%s %N {olive}got damaged for being a bad defender!", THIS_MODE_INFO.tag, client); } -stock void PlayerDeath_DamageGame(int userid) +/* DamageGame Settings */ +public void Cmd_DamageGameSettings(int client) { - if (!g_bIsDamageGameOn) - return; + Menu menu = new Menu(Menu_DamageGameSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n "); - int client = GetClientOfUserId(userid); - if (!client) - return; - - g_iDealtDamage[client] = -1; + char item[20]; + FormatEx(item, sizeof(item), "%s Damage", g_bDamageGameDisable ? "Enable" : "Disable"); + menu.AddItem(NULL_STRING, item); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); } -stock void ClientDisconnect_DamageGame(int client) +int Menu_DamageGameSettings(Menu menu, MenuAction action, int param1, int param2) { - g_iDealtDamage[client] = -1; -} + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } -stock void DamageGame_OnTakeDamagePost(int victim, int attacker, float damage) -{ - if (!(IsPlayerAlive(victim) && ZR_IsClientZombie(victim))) - return; - - if (!(0 < attacker <= MaxClients && IsPlayerAlive(attacker) && ZR_IsClientHuman(attacker))) - return; - - g_iDealtDamage[attacker] += RoundToNearest(damage); + case MenuAction_Select: + { + if (param2 == 0) + ShowCvarsInfo(param1, THIS_MODE_INFO); + else + { + g_bDamageGameDisable = !g_bDamageGameDisable; + Cmd_DamageGameSettings(param1); + } + } + } + + return 0; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/DoubleJump.sp b/addons/sourcemod/scripting/Fun_Modes/DoubleJump.sp index 9e40b84..d1fab9a 100644 --- a/addons/sourcemod/scripting/Fun_Modes/DoubleJump.sp +++ b/addons/sourcemod/scripting/Fun_Modes/DoubleJump.sp @@ -1,67 +1,150 @@ +/* + (). FunModes V2: + + @file DoubleJump.sp + @Usage Functions for the DoubleJump mode. +*/ + #pragma semicolon 1 #pragma newdecls required -#include +ModeInfo g_DoubleJumpInfo; -ConVarInfo g_cvInfoDoubleJump[4] = -{ - {null, "150.0,260.0,300.0,320.0", "float"}, - {null, "1,2,3,4,5", "int"}, - {null, "0,1", "bool"}, - {null, "0,1", "bool"} -}; +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_DoubleJumpInfo + +#define DOUBLEJUMP_CONVAR_BOOST 0 +#define DOUBLEJUMP_CONVAR_MAX_JUMPS 1 +#define DOUBLEJUMP_CONVAR_HUMANS 2 +#define DOUBLEJUMP_CONVAR_ZOMBIES 3 +#define DOUBLEJUMP_CONVAR_TOGGLE 4 /* CALLED on Plugin Start */ -stock void PluginStart_DoubleJump() +stock void OnPluginStart_DoubleJump() { - /* ADMIN COMMANDS */ - RegAdminCmd("sm_fm_doublejump", Cmd_DoubleJump, ADMFLAG_CONVARS, "Enable/Disable Double Jump mode."); + THIS_MODE_INFO.name = "DoubleJump"; + THIS_MODE_INFO.tag = "{gold}[FunModes-DoubleJump]{lightgreen}"; - /* CONVARS HANDLES */ - g_cvDoubleJumpBoost = CreateConVar("sm_doublejump_boost", "260", "The amount of vertical boost to apply to double jumps.", _, true, 260.0, true, 4095.0); - g_cvDoubleJumpMaxJumps = CreateConVar("sm_doublejump_max_jumps", "1", "How many re-jumps the player can do while he is in the air."); - g_cvDoubleJumpHumansEnable = CreateConVar("sm_doublejump_humans", "1", "Enable/Disable Double jump for humans."); - g_cvDoubleJumpZombiesEnable = CreateConVar("sm_doublejump_zombies", "0", "Enable/Disable Double jump for Zombies."); + /* ADMIN COMMANDS */ + RegAdminCmd("sm_fm_doublejump", Cmd_DoubleJumpToggle, ADMFLAG_CONVARS, "Enable/Disable Double Jump mode."); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DOUBLEJUMP_CONVAR_BOOST, + "sm_doublejump_boost", "260.0", "The amount of vertical boost to apply to double jumps.", + ("150.0,260.0,300.0,320.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DOUBLEJUMP_CONVAR_MAX_JUMPS, + "sm_doublejump_max_jumps", "1", "How many re-jumps the player can do while he is in the air.", + ("1,2,3,4,5"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DOUBLEJUMP_CONVAR_HUMANS, + "sm_doublejump_humans", "1", "Enable/Disable Double jump for humans.", + ("0,1"), "bool" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DOUBLEJUMP_CONVAR_ZOMBIES, + "sm_doublejump_zombies", "0", "Enable/Disable Double jump zombies.", + ("0,1"), "bool" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, DOUBLEJUMP_CONVAR_TOGGLE, + "sm_doublejump_enable", "1", "Enable/Disable Double Jump mode", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = DOUBLEJUMP_CONVAR_TOGGLE; - DoubleJump_SetCvarsInfo(); + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[DOUBLEJUMP_CONVAR_TOGGLE].cvar.AddChangeHook(OnDoubleJumpModeToggle); } -void DoubleJump_SetCvarsInfo() +void OnDoubleJumpModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) { - ConVar cvars[sizeof(g_cvInfoDoubleJump)]; - cvars[0] = g_cvDoubleJumpBoost; - cvars[1] = g_cvDoubleJumpMaxJumps; - cvars[2] = g_cvDoubleJumpHumansEnable; - cvars[3] = g_cvDoubleJumpZombiesEnable; - - for (int i = 0; i < sizeof(g_cvInfoDoubleJump); i++) - g_cvInfoDoubleJump[i].cvar = cvars[i]; + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_DoubleJump() {} +stock void OnMapEnd_DoubleJump() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); +} + +stock void OnClientPutInServer_DoubleJump(int client) +{ + #pragma unused client +} + +stock void OnClientDisconnect_DoubleJump(int client) +{ + #pragma unused client +} + +stock void ZR_OnClientInfected_DoubleJump(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_DoubleJump() {} +stock void Event_RoundEnd_DoubleJump() {} +stock void Event_PlayerSpawn_DoubleJump(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_DoubleJump(Event event) +{ + #pragma unused event } -Action Cmd_DoubleJump(int client, int args) +stock void Event_PlayerDeath_DoubleJump(int client) { - g_bIsDoubleJumpOn = !g_bIsDoubleJumpOn; - CPrintToChatAll("%s Double Jump is now {olive}%s. %s", DoubleJump_Tag, (g_bIsDoubleJumpOn) ? "Enabled" : "Disabled", - (g_bIsDoubleJumpOn) ? "You can re-jump while you are in the air." : ""); + #pragma unused client +} + +public Action Cmd_DoubleJumpToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s Double Jump mode is currently disabled!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s Double Jump is now {olive}%s. %s", THIS_MODE_INFO.tag, (THIS_MODE_INFO.isOn) ? "Enabled" : "Disabled", + (THIS_MODE_INFO.isOn) ? "You can re-jump while you are in the air." : ""); - if(g_bIsDoubleJumpOn) + if(THIS_MODE_INFO.isOn) { CPrintToChatAll("%s Humans Double Jump: {olive}%s\n%s Zombies Double Jump: {olive}%s.", - DoubleJump_Tag, (g_cvDoubleJumpHumansEnable.BoolValue) ? "Enabled" : "Disabled", - DoubleJump_Tag, (g_cvDoubleJumpZombiesEnable.BoolValue) ? "Enabled" : "Disabled"); + THIS_MODE_INFO.tag, (THIS_MODE_INFO.cvarInfo[DOUBLEJUMP_CONVAR_HUMANS].cvar.BoolValue) ? "Enabled" : "Disabled", + THIS_MODE_INFO.tag, (THIS_MODE_INFO.cvarInfo[DOUBLEJUMP_CONVAR_ZOMBIES].cvar.BoolValue) ? "Enabled" : "Disabled"); } return Plugin_Handled; } /* SM DOUBLEJUMP 1.1.0, ALL CREDITS GO TO - https://forums.alliedmods.net/showpost.php?p=2759524&postcount=37 */ -public Action OnPlayerRunCmd(int client, int& buttons) +void OnPlayerRunCmdPost_DoubleJump(int client, int buttons, int impulse) { - if(!g_bIsDoubleJumpOn || !IsClientInGame(client) || !IsPlayerAlive(client)) - return Plugin_Continue; + #pragma unused buttons + #pragma unused impulse + + if(!THIS_MODE_INFO.isOn || !IsClientInGame(client) || !IsPlayerAlive(client)) + return; - if((!g_cvDoubleJumpHumansEnable.BoolValue && GetClientTeam(client) == CS_TEAM_CT) || (!g_cvDoubleJumpZombiesEnable.BoolValue && GetClientTeam(client) == CS_TEAM_T)) - return Plugin_Continue; + if((!THIS_MODE_INFO.cvarInfo[DOUBLEJUMP_CONVAR_HUMANS].cvar.BoolValue && GetClientTeam(client) == CS_TEAM_CT) || (!THIS_MODE_INFO.cvarInfo[DOUBLEJUMP_CONVAR_ZOMBIES].cvar.BoolValue && GetClientTeam(client) == CS_TEAM_T)) + return; static bool inGround; static bool inJump; @@ -73,12 +156,12 @@ public Action OnPlayerRunCmd(int client, int& buttons) if(!landed[client]) { - if(g_cvDoubleJumpMaxJumps.IntValue) + if(THIS_MODE_INFO.cvarInfo[DOUBLEJUMP_CONVAR_MAX_JUMPS].cvar.IntValue) { static int jumps[MAXPLAYERS+1]; if(inGround) jumps[client] = 0; - else if(!wasJump[client] && inJump && jumps[client]++ <= g_cvDoubleJumpMaxJumps.IntValue) + else if(!wasJump[client] && inJump && jumps[client]++ <= THIS_MODE_INFO.cvarInfo[DOUBLEJUMP_CONVAR_MAX_JUMPS].cvar.IntValue) ApplyNewJump(client); } else if(!inGround && !wasJump[client] && inJump) @@ -90,14 +173,49 @@ public Action OnPlayerRunCmd(int client, int& buttons) landed[client] = inGround; wasJump[client] = inJump; - return Plugin_Continue; + return; } stock void ApplyNewJump(int client) { static float vel[3]; GetEntPropVector(client, Prop_Data, "m_vecVelocity", vel); - vel[2] = g_cvDoubleJumpBoost.FloatValue; + vel[2] = THIS_MODE_INFO.cvarInfo[DOUBLEJUMP_CONVAR_BOOST].cvar.FloatValue; TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, vel); +} + +/* DoubleJump Settings */ +public void Cmd_DoubleJumpSettings(int client) +{ + Menu menu = new Menu(Menu_DoubleJumpSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_DoubleJumpSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/Fog.sp b/addons/sourcemod/scripting/Fun_Modes/Fog.sp index a2e9893..72a9395 100644 --- a/addons/sourcemod/scripting/Fun_Modes/Fog.sp +++ b/addons/sourcemod/scripting/Fun_Modes/Fog.sp @@ -1,35 +1,106 @@ +/* + (). FunModes V2: + + @file Fog.sp + @Usage Functions for the Fog mode. +*/ + #pragma semicolon 1 #pragma newdecls required +ModeInfo g_FogInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_FogInfo + +#define FOGInput_Color 0 +#define FOGInput_Start 1 +#define FOGInput_End 2 +#define FOGInput_Toggle 3 + +enum struct fogData +{ + float fogStart; + float fogEnd; + int fogColor[4]; + + void SetColor(int setColor[4]) + { + this.fogColor[0] = setColor[0]; + this.fogColor[1] = setColor[1]; + this.fogColor[2] = setColor[2]; + this.fogColor[3] = setColor[3]; + } +} + +fogData g_FogData; + +int g_iFogEntity = -1; + +#define FOG_CONVAR_TOGGLE 0 /* CALLED ON PLUGIN START */ -stock void PluginStart_Fog() +stock void OnPluginStart_Fog() { - RegAdminCmd("sm_fm_fog", Cmd_FogEnable, ADMFLAG_CONVARS, "Enable/Disable fog"); + THIS_MODE_INFO.name = "Fog"; + THIS_MODE_INFO.tag = "{gold}[FunModes-FOG]{lightgreen}"; + + RegAdminCmd("sm_fm_fog", Cmd_FogToggle, ADMFLAG_CONVARS, "Toggle fog on/off"); RegAdminCmd("sm_fogmode", Cmd_FogSettings, ADMFLAG_CONVARS, "Fog Settings"); RegAdminCmd("sm_fog_start", Cmd_FogStart, ADMFLAG_CONVARS, "Fog Start"); RegAdminCmd("sm_fog_end", Cmd_FogEnd, ADMFLAG_CONVARS, "Fog End"); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, FOG_CONVAR_TOGGLE, + "sm_fog_enable", "1", "Enable/Disable Fog Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = FOG_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[FOG_CONVAR_TOGGLE].cvar.AddChangeHook(OnFogModeToggle); } -stock void PlayerSpawn_Fog(int userid) +void OnFogModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) { - CreateTimer(1.0, PlayerSpawn_Timer, userid, TIMER_FLAG_NO_MAPCHANGE); + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); } -Action PlayerSpawn_Timer(Handle timer, int userid) +stock void OnMapStart_Fog() { - int client = GetClientOfUserId(userid); - if(client < 1 || !g_FogData.fogEnable) - return Plugin_Stop; + g_FogData.fogStart = 50.0; + g_FogData.fogEnd = 250.0; + g_iFogEntity = -1; +} - SetVariantString("fog_mode_aaa34124n"); - AcceptEntityInput(client, "SetFogController"); - return Plugin_Continue; +stock void OnMapEnd_Fog() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + g_iFogEntity = -1; +} + +stock void OnClientPutInServer_Fog(int client) +{ + #pragma unused client +} + +stock void OnClientDisconnect_Fog(int client) +{ + #pragma unused client +} + +stock void ZR_OnClientInfected_Fog(int client) +{ + #pragma unused client } -stock void RoundStart_Fog() +stock void Event_RoundStart_Fog() { - if(!g_FogData.fogEnable) + if (!THIS_MODE_INFO.isOn) return; if(IsValidEntity(g_iFogEntity)) @@ -49,6 +120,33 @@ stock void RoundStart_Fog() CreateFogEntity(); } +stock void Event_RoundEnd_Fog() {} +stock void Event_PlayerSpawn_Fog(int client) +{ + CreateTimer(1.0, PlayerSpawn_Timer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); +} + +stock void Event_PlayerTeam_Fog(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_Fog(int client) +{ + #pragma unused client +} + +Action PlayerSpawn_Timer(Handle timer, int userid) +{ + int client = GetClientOfUserId(userid); + if(client < 1 || !THIS_MODE_INFO.isOn) + return Plugin_Stop; + + SetVariantString("fog_mode_aaa34124n"); + AcceptEntityInput(client, "SetFogController"); + return Plugin_Continue; +} + stock void CreateFogEntity() { /* CHECK FOR ANY FOG MAP HAS */ @@ -120,7 +218,7 @@ stock void AcceptFogInput(int mode) } case FOGInput_Toggle: { - bool isOn = g_FogData.fogEnable; + bool isOn = THIS_MODE_INFO.isOn; if(isOn) AcceptEntityInput(g_iFogEntity, "TurnOn"); else @@ -140,7 +238,7 @@ stock void Fog_DisplaySettingsMenu(int client) menu.AddItem("0", "Change FOG Color"); char buffer[92]; - Format(buffer, sizeof(buffer), "%s FOG", g_FogData.fogEnable ? "TurnOff" : "TurnOn"); + Format(buffer, sizeof(buffer), "%s FOG", THIS_MODE_INFO.isOn ? "TurnOff" : "TurnOn"); menu.AddItem("3", buffer); menu.ExitButton = true; @@ -165,16 +263,16 @@ public int FogSettings_Handler(Menu menu, MenuAction action, int param1, int par } case 1: { - bool isOn = g_FogData.fogEnable; + bool isOn = THIS_MODE_INFO.isOn; if(isOn) { - CPrintToChat(param1, "%s %T", Fog_Tag, "Fog_Disabled", param1); - g_FogData.fogEnable = false; + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "Fog_Disabled", param1); + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); } else { - CPrintToChat(param1, "%s %T", Fog_Tag, "Fog_Enabled", param1); - g_FogData.fogEnable = true; + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "Fog_Enabled", param1); + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, true, THIS_MODE_INFO.index); } AcceptFogInput(FOGInput_Toggle); @@ -193,15 +291,16 @@ stock void Fog_DisplayColorsMenu(int client) /* TO GET FOG COLOR */ char colorName[64]; - for(int i = 0; i < sizeof(colorsList); i++) + for(int i = 0; i < sizeof(g_ColorsList); i++) { - char buffers[5][64]; - ExplodeString(colorsList[i], " ", buffers, 5, sizeof(buffers[])); + char buffers[3][5]; + ExplodeString(g_ColorsList[i].rgb, " ", buffers, 3, sizeof(buffers[])); + int color[4]; color[0] = StringToInt(buffers[0]); color[1] = StringToInt(buffers[1]); color[2] = StringToInt(buffers[2]); - color[3] = StringToInt(buffers[3]); + color[3] = 255; int fogColor[4]; fogColor[0] = g_FogData.fogColor[0]; @@ -211,7 +310,7 @@ stock void Fog_DisplayColorsMenu(int client) if(fogColor[0] == color[0] && fogColor[1] == color[1] && fogColor[2] == color[2] && fogColor[3] == color[3]) { - Format(colorName, sizeof(colorName), buffers[4]); + Format(colorName, sizeof(colorName), g_ColorsList[i].name); break; } } @@ -221,11 +320,11 @@ stock void Fog_DisplayColorsMenu(int client) menu.SetTitle(title); /* TO ADD ITEMS */ - for(int i = 0; i < sizeof(colorsList); i++) + for(int i = 0; i < sizeof(g_ColorsList); i++) { - char buffers[5][64]; - ExplodeString(colorsList[i], " ", buffers, 5, sizeof(buffers[])); - menu.AddItem(colorsList[i], buffers[4]); + char index[3]; + IntToString(i, index, sizeof(index)); + menu.AddItem(index, g_ColorsList[i].name); } menu.ExitBackButton = true; @@ -247,29 +346,34 @@ public int FogColorsMenu_Handler(Menu menu, MenuAction action, int param1, int p } case MenuAction_Select: { - if(!IsValidEntity(g_iFogEntity)) + if (!IsValidEntity(g_iFogEntity)) { - CPrintToChat(param1, "%s %T", Fog_Tag, "Fog_EntityInvalid", param1); + CPrintToChat(param1, "%s %t", THIS_MODE_INFO.tag, "Fog_EntityInvalid"); return 0; } - char info[128]; + char info[3]; menu.GetItem(param2, info, sizeof(info)); - - char buffers[5][64]; - ExplodeString(info, " ", buffers, 5, sizeof(buffers[])); + + int index = StringToInt(info); + FM_Color myColor; + myColor = g_ColorsList[index]; + + char buffers[3][5]; + ExplodeString(myColor.rgb, " ", buffers, 3, sizeof(buffers[])); + int color[4]; color[0] = StringToInt(buffers[0]); color[1] = StringToInt(buffers[1]); color[2] = StringToInt(buffers[2]); - color[3] = StringToInt(buffers[3]); + color[3] = 255; g_FogData.SetColor(color); AcceptFogInput(FOGInput_Color); - CPrintToChat(param1, "%s %T", Fog_Tag, "Fog_ColorChange", param1, buffers[4], buffers[4]); - LogAction(param1, -1, "[FunModes-FOG] \"%L\" changed FOG color to \"%s\"", param1, buffers[4]); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "Fog_ColorChange", param1, myColor.name, myColor.name); + LogAction(param1, -1, "[FunModes-FOG] \"%L\" changed FOG color to \"%s\"", param1, myColor.name); Fog_DisplayColorsMenu(param1); } } @@ -277,21 +381,27 @@ public int FogColorsMenu_Handler(Menu menu, MenuAction action, int param1, int p return 0; } -Action Cmd_FogEnable(int client, int args) +public Action Cmd_FogToggle(int client, int args) { - if(g_FogData.fogEnable) + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) { - g_FogData.fogEnable = false; + CReplyToCommand(client, "%s Fog mode is currently disabled!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + if(THIS_MODE_INFO.isOn) + { + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); AcceptFogInput(FOGInput_Toggle); - CReplyToCommand(client, "%s FOG Mode is now {olive}OFF!", Fog_Tag); + CReplyToCommand(client, "%s FOG Mode is now {olive}OFF!", THIS_MODE_INFO.tag); return Plugin_Handled; } else { - g_FogData.fogEnable = true; + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, true, THIS_MODE_INFO.index); FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); FunModes_HookEvent(g_bEvent_PlayerSpawn, "player_spawn", Event_PlayerSpawn); - CReplyToCommand(client, "%s FOG Mode is now {olive}ON!", Fog_Tag); + CReplyToCommand(client, "%s FOG Mode is now {olive}ON!", THIS_MODE_INFO.tag); CreateFogEntity(); return Plugin_Handled; } @@ -306,11 +416,11 @@ Action Cmd_FogSettings(int client, int args) return Plugin_Handled; } -Action Cmd_FogStart(int client, int args) +public Action Cmd_FogStart(int client, int args) { if(args < 1) { - CReplyToCommand(client, "%s Usage: sm_fog_start ", Fog_Tag); + CReplyToCommand(client, "%s Usage: sm_fog_start ", THIS_MODE_INFO.tag); return Plugin_Handled; } @@ -320,26 +430,27 @@ Action Cmd_FogStart(int client, int args) int distance; if(!StringToIntEx(arg, distance)) { - CReplyToCommand(client, "%s Invalid distance.", Fog_Tag); + CReplyToCommand(client, "%s Invalid distance.", THIS_MODE_INFO.tag); return Plugin_Handled; } if(distance == 0) { - CReplyToCommand(client, "%s Distance cannot be 0", Fog_Tag); + CReplyToCommand(client, "%s Distance cannot be 0", THIS_MODE_INFO.tag); return Plugin_Handled; } g_FogData.fogStart = float(distance); AcceptFogInput(FOGInput_Start); - CReplyToCommand(client, "%s You have changed FOG Start Distance to %d", Fog_Tag, distance); + CReplyToCommand(client, "%s You have changed FOG Start Distance to %d", THIS_MODE_INFO.tag, distance); return Plugin_Handled; } Action Cmd_FogEnd(int client, int args) { - if(args < 1) { - CReplyToCommand(client, "%s Usage: sm_fog_end ", Fog_Tag); + if(args < 1) + { + CReplyToCommand(client, "%s Usage: sm_fog_end ", THIS_MODE_INFO.tag); return Plugin_Handled; } @@ -349,24 +460,24 @@ Action Cmd_FogEnd(int client, int args) int distance; if(!StringToIntEx(arg, distance)) { - CReplyToCommand(client, "%s Invalid distance.", Fog_Tag); + CReplyToCommand(client, "%s Invalid distance.", THIS_MODE_INFO.tag); return Plugin_Handled; } if(distance == 0) { - CReplyToCommand(client, "%s Distance cannot be 0", Fog_Tag); + CReplyToCommand(client, "%s Distance cannot be 0", THIS_MODE_INFO.tag); return Plugin_Handled; } if(distance < g_FogData.fogStart) { - CReplyToCommand(client, "%s End Distance has to be higher than Start one.", Fog_Tag); + CReplyToCommand(client, "%s End Distance has to be higher than Start one.", THIS_MODE_INFO.tag); return Plugin_Handled; } g_FogData.fogEnd = float(distance); AcceptFogInput(FOGInput_End); - CReplyToCommand(client, "%s You have changed FOG End Distance to %d", Fog_Tag, distance); + CReplyToCommand(client, "%s You have changed FOG End Distance to %d", THIS_MODE_INFO.tag, distance); return Plugin_Handled; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/GunGame.sp b/addons/sourcemod/scripting/Fun_Modes/GunGame.sp new file mode 100644 index 0000000..5a794b7 --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/GunGame.sp @@ -0,0 +1,719 @@ +/* + (). FunModes V2: + + @file GunGame.sp + @Usage Functions for the GunGame Mode. + +*/ + +/* + GunGame Escape: Humans start with pistols like in a gg game, and every 1 thousand damage, + the gun automatically upgrades to the next one, making it into pistols, smgs, rifles and ending in m249. + After 1 complete cycle (If the map is long enough to cycle), + the human will get a random advantage such as 3 extra grenades, more speed, more grav... etc + + By @kiku-san +*/ + +#pragma semicolon 1 +#pragma newdecls required + +#undef REQUIRE_PLUGIN +#tryinclude +#define REQUIRE_PLUGIN + +#define _FM_GunGame + +ModeInfo g_GunGameInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_GunGameInfo + +#define GUNGAME_CONVAR_PISTOLS_DAMAGE 0 +#define GUNGAME_CONVAR_SHOTGUNS_DAMAGE 1 +#define GUNGAME_CONVAR_SMGS_DAMAGE 2 +#define GUNGAME_CONVAR_RIFLES_DAMAGE 3 +#define GUNGAME_CONVAR_M249_DAMAGE 4 +#define GUNGAME_CONVAR_ENTWATCH 5 +#define GUNGAME_CONVAR_HEGRENADES_COUNT 6 +#define GUNGAME_CONVAR_REWARD_GRAVITY 7 +#define GUNGAME_CONVAR_REWARD_SPEED 8 +#define GUNGAME_CONVAR_TOGGLE 9 + +static const char g_GunGameWeaponsList[][][] = +{ + { "weapon_glock", "weapon_usp", "weapon_p228", "weapon_deagle", "weapon_elite", "weapon_fiveseven" }, /* Pistols */ + { "weapon_m3", "weapon_xm1014", "", "", "", "" }, /* Shotguns */ + { "weapon_mac10", "weapon_ump45", "weapon_tmp", "weapon_mp5navy", "weapon_p90", "" }, /* SMGs */ + { "weapon_galil", "weapon_famas", "weapon_sg552", "weapon_aug", "weapon_ak47", "weapon_m4a1" }, /* Rifles */ + { "weapon_m249", "", "", "", "", "" } /* The one and only :) */ +}; + +enum GunGame_Reward +{ + REWARD_SPEED = 0, + REWARD_GRAVITY, + REWARD_HEGRENADES, + REWARD_NONE +}; + +enum struct GunGame_Data +{ + int level[2]; // [0] = weapon type, [1] = weapon index + int dealtDamage; + + bool completedCycle; + bool allowEquip; + + float originalSpeed; + float originalGravity; + + GunGame_Reward reward; + Handle rewardTimer; + + void ResetLevel() + { + this.level[0] = 0; + this.level[1] = 0; + } +} + +GunGame_Data g_GunGameData[MAXPLAYERS + 1]; + +stock void OnPluginStart_GunGame() +{ + THIS_MODE_INFO.name = "GunGame"; + THIS_MODE_INFO.tag = "{gold}[FunModes-GunGame]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_gungame", Cmd_GunGameToggle, ADMFLAG_CONVARS, "Turn GunGame Mode On/Off"); + RegAdminCmd("sm_gungame_settings", Cmd_GunGameSettings, ADMFLAG_CONVARS, "Open GunGame Sttings Menu"); + + RegConsoleCmd("sm_gungame", Cmd_GunGame, "Get your original weapons"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_PISTOLS_DAMAGE, + "sm_gungame_pistols_damage", "1200", "The required damage needed for pistols to upgrade", + ("800,1000,1500,2000,2500"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_SHOTGUNS_DAMAGE, + "sm_gungame_shotguns_damage", "2200", "The required damage needed for shotguns to upgrade", + ("800,1000,1500,2000,2500"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_SMGS_DAMAGE, + "sm_gungame_smgs_damage", "4200", "The required damage needed for smgs to upgrade", + ("800,1000,1500,2000,2500"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_RIFLES_DAMAGE, + "sm_gungame_rifles_damage", "3800", "The required damage needed for rifles to upgrade", + ("800,1000,1500,2000,2500"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_M249_DAMAGE, + "sm_gungame_m249_damage", "8000", "The required damage needed for m249 to finish the gungame cycle", + ("800,1000,1500,2000,2500"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_ENTWATCH, + "sm_gungame_allow_entwatch", "0", "Allow entwatch items to be picked up (1 = Enabled, 0 = Disabled)", + ("0,1"), "bool" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_HEGRENADES_COUNT, + "sm_gungame_hegrenades_reward", "3", "How many hegrenades to give to the player when completing a cycle", + ("1,3,5,10,15"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_REWARD_GRAVITY, + "sm_gungame_gravity_reward", "100.0", "How many seconds can the player keep their low gravity hold", + ("20.0,30.0,40.0,60.0,80.0,100.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_REWARD_SPEED, + "sm_gungame_speed_reward", "100.0", "How many seconds can the player keep their high speed hold", + ("20.0,30.0,40.0,60.0,80.0,100.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, GUNGAME_CONVAR_TOGGLE, + "sm_gungame_enable", "1", "Enable/Disable GunGame Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = GUNGAME_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_TOGGLE].cvar.AddChangeHook(OnGunGameModeToggle); +} + +void OnGunGameModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_GunGame() {} +stock void OnMapEnd_GunGame() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + for (int i = 1; i <= MaxClients; i++) + g_GunGameData[i].rewardTimer = null; +} + +stock void OnClientPutInServer_GunGame(int client) +{ + if (!THIS_MODE_INFO.isOn) + return; + + g_GunGameData[client].allowEquip = true; + g_GunGameData[client].ResetLevel(); + + if (!g_bSDKHook_WeaponEquip[client]) + { + SDKHook(client, SDKHook_WeaponEquip, OnWeaponEquip); + g_bSDKHook_WeaponEquip[client] = true; + } + + if (!g_bSDKHook_OnTakeDamagePost[client]) + { + SDKHook(client, SDKHook_OnTakeDamagePost, OnTakeDamagePost); + g_bSDKHook_OnTakeDamagePost[client] = true; + } +} + +stock void OnClientDisconnect_GunGame(int client) +{ + delete g_GunGameData[client].rewardTimer; +} + +stock void ZR_OnClientInfected_GunGame(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_GunGame() {} +stock void Event_RoundEnd_GunGame() +{ + for (int i = 1; i <= MaxClients; i++) + g_GunGameData[i].allowEquip = true; +} + +stock void Event_PlayerSpawn_GunGame(int client) +{ + if (!THIS_MODE_INFO.isOn) + return; + + CreateTimer(2.0, Timer_GunGame_CheckPlayerSpawn, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); +} + +Action Timer_GunGame_CheckPlayerSpawn(Handle timer, int userid) +{ + int client = GetClientOfUserId(userid); + if (!client) + return Plugin_Stop; + + GunGame_GiveReward(client, REWARD_NONE); + g_GunGameData[client].ResetLevel(); + + if (!IsPlayerAlive(client) || !ZR_IsClientHuman(client)) + return Plugin_Stop; + + GunGame_EquipWeapon(client, g_GunGameWeaponsList[0][GetRandomInt(0, 1)]); + return Plugin_Stop; +} + +stock void Event_PlayerTeam_GunGame(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_GunGame(int client) +{ + if (!THIS_MODE_INFO.isOn) + return; + + GunGame_GiveReward(client, REWARD_NONE); +} + +stock void OnTakeDamagePost_GunGame(int victim, int attacker, float damage) +{ + if (!THIS_MODE_INFO.isOn) + return; + + if (!(1<=attacker<=MaxClients) || !IsPlayerAlive(attacker) || !IsPlayerAlive(victim) || !ZR_IsClientZombie(victim) || !ZR_IsClientHuman(attacker)) + return; + + if (THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_ENTWATCH].cvar.BoolValue && EntWatch_HasSpecialItem(attacker)) + return; + + int neededDamage = THIS_MODE_INFO.cvarInfo[g_GunGameData[attacker].level[0]].cvar.IntValue; + + if (g_GunGameData[attacker].dealtDamage >= neededDamage) + { + g_GunGameData[attacker].dealtDamage = 0; + GunGame_GiveWeapon(attacker); + return; + } + + g_GunGameData[attacker].dealtDamage += RoundToNearest(damage); +} + +stock void OnWeaponEquip_GunGame(int client, int weapon, Action &result) +{ + if (!THIS_MODE_INFO.isOn) + return; + + if (!IsPlayerAlive(client) || ZR_IsClientZombie(client)) + return; + + if (THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_ENTWATCH].cvar.BoolValue) + { + #if !defined _EntWatch_include + THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_ENTWATCH].cvar.BoolValue = false; + return; + #else + if (EntWatch_IsSpecialItem(weapon)) + return; + #endif + } + + if (!g_GunGameData[client].allowEquip) + { + result = Plugin_Handled; + return; + } +} + +public Action CS_OnBuyCommand(int client, const char[] weapon) +{ + if (!THIS_MODE_INFO.isOn) + return Plugin_Continue; + + if (THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_ENTWATCH].cvar.BoolValue) + { + #if !defined _EntWatch_include + THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_ENTWATCH].cvar.BoolValue = false; + return Plugin_Continue; + #else + if (!EntWatch_HasSpecialItem(client)) + return Plugin_Continue; + #endif + } + + if (!g_GunGameData[client].allowEquip) + { + CPrintToChat(client, "%s You cannot buy/equip weapons during GunGame Escape Mode", THIS_MODE_INFO.tag); + return Plugin_Stop; + } + + return Plugin_Continue; +} + +public Action Cmd_GunGameToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s GunGame Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s GunGame Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + static bool cvarsValues[2]; + + if (THIS_MODE_INFO.isOn) + { + FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); + FunModes_HookEvent(g_bEvent_RoundEnd, "round_end", Event_RoundEnd); + FunModes_HookEvent(g_bEvent_PlayerSpawn, "player_spawn", Event_PlayerSpawn); + FunModes_HookEvent(g_bEvent_PlayerDeath, "player_death", Event_PlayerDeath); + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i)) + continue; + + OnClientPutInServer_GunGame(i); + if (view_as(g_GunGameData[i].reward) < view_as(REWARD_HEGRENADES)) + GunGame_GiveReward(i, REWARD_NONE); + } + + CPrintToChatAll("%s Your weapon will be upgraded when you reach the required damage for each weapon type!", THIS_MODE_INFO.tag); + CS_TerminateRound(3.0, CSRoundEnd_Draw); + + ConVar cvar = FindConVar("zr_weapons_zmarket_rebuy"); + if (cvar != null) + { + cvarsValues[0] = cvar.BoolValue; + cvar.BoolValue = false; + delete cvar; + } + + cvar = FindConVar("zr_weapons_zmarket"); + if (cvar != null) + { + cvarsValues[1] = cvar.BoolValue; + cvar.BoolValue = false; + delete cvar; + } + } + else + { + ConVar cvar = FindConVar("zr_weapons_zmarket_rebuy"); + if (cvar != null) + { + cvar.BoolValue = cvarsValues[0]; + delete cvar; + } + + cvar = FindConVar("zr_weapons_zmarket"); + if (cvar != null) + { + cvar.BoolValue = cvarsValues[1]; + delete cvar; + } + } + + return Plugin_Handled; +} + +/* GunGame Settings */ +public Action Cmd_GunGameSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_GunGameSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_GunGameSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; +} + +Action Cmd_GunGame(int client, int args) +{ + if (!client) + return Plugin_Handled; + + if (!THIS_MODE_INFO.isOn) + { + CReplyToCommand(client, "%s GunGame is currently Off!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + if (!IsPlayerAlive(client) || !ZR_IsClientHuman(client)) + { + CReplyToCommand(client, "%s You have to be an alive human to use this command!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + if (THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_ENTWATCH].cvar.BoolValue) + { + #if defined _EntWatch_include + if (EntWatch_HasSpecialItem(client)) + { + static const char weapons[][] = { "weapon_p90", "weapon_tmp", "weapon_ak47", "weapon_m4a1" }; + GunGame_EquipWeapon(client, weapons[GetRandomInt(0, sizeof(weapons)-1)], true); + return Plugin_Handled; + } + #endif + } + + int weaponType = g_GunGameData[client].level[0]; + int weaponIndex = g_GunGameData[client].level[1]; + if (weaponType > 0) + { + if (GetPlayerWeaponSlot(client, CS_SLOT_SECONDARY) == -1) + GunGame_EquipWeapon(client, g_GunGameWeaponsList[0][0], true); + } + + GunGame_EquipWeapon(client, g_GunGameWeaponsList[weaponType][weaponIndex], true); + + return Plugin_Handled; +} + +void GunGame_GiveWeapon(int client) +{ + int weaponType = g_GunGameData[client].level[0]; + int weaponIndex = g_GunGameData[client].level[1]; + + /* If weapon type is still pistols */ + if (weaponType == 0) + { + int secondary = GetPlayerWeaponSlot(client, CS_SLOT_SECONDARY); + if (!IsValidEntity(secondary)) + { + GunGame_EquipWeapon(client, g_GunGameWeaponsList[0][0]); + g_GunGameData[client].level[0] = 0; g_GunGameData[client].level[1] = 0; + return; + } + + char weaponName[32]; + GetEntityClassname(secondary, weaponName, sizeof(weaponName)); + + bool hasGlock = !strcmp(weaponName, "weapon_glock"); + + if (hasGlock || strcmp(weaponName, "weapon_usp") == 0) + { + if (weaponIndex == 0) + { + GunGame_EquipWeapon(client, hasGlock ? "weapon_usp" : "weapon_glock"); + g_GunGameData[client].level[1] = 1; + return; + } + } + } + + if (weaponType == sizeof(g_GunGameWeaponsList) - 1) + { + weaponType = 0; + weaponIndex = 0; + + /* Reward player with shits */ + g_GunGameData[client].completedCycle = true; + GunGame_ShowRewardsMenu(client); + } + else if (++weaponIndex >= sizeof(g_GunGameWeaponsList[]) || g_GunGameWeaponsList[weaponType][weaponIndex][0] == '\0') + { + weaponType++; + weaponIndex = 0; + } + + g_GunGameData[client].level[0] = weaponType; + g_GunGameData[client].level[1] = weaponIndex; + + GunGame_EquipWeapon(client, g_GunGameWeaponsList[weaponType][weaponIndex], weaponType > 0); +} + +void GunGame_EquipWeapon(int client, const char[] weaponName, bool keepSecondary = false) +{ + int weapon = GivePlayerItem(client, weaponName); + if (!IsValidEntity(weapon)) + return; + + GunGame_StripPlayer(client, keepSecondary); + + g_GunGameData[client].allowEquip = true; + EquipPlayerWeapon(client, weapon); + + if (g_hSwitchSDKCall != null) + SDKCall(g_hSwitchSDKCall, client, weapon, 0); + + g_GunGameData[client].allowEquip = false; +} + +void GunGame_StripPlayer(int client, bool keepSecondary = false, bool giveSecondary = false) +{ + for (int i = 0; i <= 5; i++) + { + if (i == CS_SLOT_KNIFE || i == CS_SLOT_GRENADE) + continue; + + if (keepSecondary && i == CS_SLOT_SECONDARY) + continue; + + int wp = GetPlayerWeaponSlot(client, i); + if (!IsValidEntity(wp)) + { + if (i == CS_SLOT_SECONDARY && giveSecondary) + GunGame_EquipWeapon(client, g_GunGameWeaponsList[0][0], true); + + continue; + } + + SDKHooks_DropWeapon(client, wp); + RemoveEntity(wp); + } +} + +void GunGame_ShowRewardsMenu(int client) +{ + GunGame_GiveReward(client, REWARD_SPEED); + + Menu menu = new Menu(Menu_GunGame_ShowRewards); + menu.SetTitle("[GunGame Escape] You have completed a gungame cycle! Choose your reward!\nYou only have 60s to switch your rewards"); + + menu.AddItem("0", "More Speed", g_GunGameData[client].reward == REWARD_SPEED ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT); + menu.AddItem("1", "Lower Gravity", g_GunGameData[client].reward == REWARD_GRAVITY ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT); + menu.AddItem("2", "More hegrenades", g_GunGameData[client].reward == REWARD_HEGRENADES ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT); + + menu.ExitBackButton = true; + menu.Display(client, 60); +} + +int Menu_GunGame_ShowRewards(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Select: + { + char data[3]; + menu.GetItem(param2, data, sizeof(data)); + + GunGame_Reward reward = view_as(StringToInt(data)); + GunGame_GiveReward(param1, reward); + } + } + + return 0; +} + +void GunGame_GiveReward(int client, GunGame_Reward reward) +{ + g_GunGameData[client].reward = reward; + + /* Delete Timer */ + delete g_GunGameData[client].rewardTimer; + + switch (reward) + { + case REWARD_SPEED: + { + /* Reset Gravity */ + if (g_GunGameData[client].originalGravity != 0.0) + { + SetEntityGravity(client, g_GunGameData[client].originalGravity); + g_GunGameData[client].originalGravity = 0.0; + } + + if (!IsPlayerAlive(client) || !ZR_IsClientHuman(client)) + return; + + g_GunGameData[client].originalSpeed = GetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue"); + SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", g_GunGameData[client].originalSpeed + 0.3); + + CPrintToChat(client, "%s You have been granted an extra speed for finishing a gungame cycle!", THIS_MODE_INFO.tag); + + delete g_GunGameData[client].rewardTimer; + g_GunGameData[client].rewardTimer = CreateTimer(THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_REWARD_SPEED].cvar.FloatValue, Timer_GunGameReward, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); + } + + case REWARD_GRAVITY: + { + /* Reset Speed */ + if (g_GunGameData[client].originalSpeed != 0.0) + { + SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", g_GunGameData[client].originalSpeed); + g_GunGameData[client].originalSpeed = 0.0; + } + + if (!IsPlayerAlive(client) || !ZR_IsClientHuman(client)) + return; + + g_GunGameData[client].originalGravity = GetEntityGravity(client); + SetEntityGravity(client, 0.5); + + CPrintToChat(client, "%s You have been granted a lower gravity for finishing a gungame cycle!", THIS_MODE_INFO.tag); + + delete g_GunGameData[client].rewardTimer; + g_GunGameData[client].rewardTimer = CreateTimer(THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_REWARD_GRAVITY].cvar.FloatValue, Timer_GunGameReward, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE); + } + + case REWARD_HEGRENADES: + { + /* Reset Gravity */ + if (g_GunGameData[client].originalGravity != 0.0) + { + SetEntityGravity(client, g_GunGameData[client].originalGravity); + g_GunGameData[client].originalGravity = 0.0; + } + + /* Reset Speed */ + if (g_GunGameData[client].originalSpeed != 0.0) + { + SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", g_GunGameData[client].originalSpeed); + g_GunGameData[client].originalSpeed = 0.0; + } + + if (!IsPlayerAlive(client) || !ZR_IsClientHuman(client)) + return; + + g_GunGameData[client].allowEquip = true; + GivePlayerItem(client, "weapon_hegrenade"); + int count = THIS_MODE_INFO.cvarInfo[GUNGAME_CONVAR_HEGRENADES_COUNT].cvar.IntValue; + GiveGrenadesToClient(client, GrenadeType_HEGrenade, count-1); + g_GunGameData[client].allowEquip = false; + + CPrintToChat(client, "%s You have been granted {olive}%d extra hegrenades {lightgreen}for finishing a gungame cycle!", THIS_MODE_INFO.tag, count); + } + + default: + { + /* Reset Gravity */ + if (g_GunGameData[client].originalGravity != 0.0) + { + SetEntityGravity(client, g_GunGameData[client].originalGravity); + g_GunGameData[client].originalGravity = 0.0; + } + + /* Reset Speed */ + if (g_GunGameData[client].originalSpeed != 0.0) + { + SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", g_GunGameData[client].originalSpeed); + g_GunGameData[client].originalSpeed = 0.0; + } + } + } +} + +Action Timer_GunGameReward(Handle timer, int userid) +{ + int client = GetClientOfUserId(userid); + if (!client) + return Plugin_Stop; + + g_GunGameData[client].rewardTimer = null; + + CPrintToChat(client, "%s Sorry, your reward has ended!", THIS_MODE_INFO.tag); + GunGame_GiveReward(client, REWARD_NONE); + return Plugin_Stop; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/HealBeacon.sp b/addons/sourcemod/scripting/Fun_Modes/HealBeacon.sp index 6dff560..7794c8e 100644 --- a/addons/sourcemod/scripting/Fun_Modes/HealBeacon.sp +++ b/addons/sourcemod/scripting/Fun_Modes/HealBeacon.sp @@ -1,116 +1,247 @@ +/* + (). FunModes V2: + + @file HealBeacon.sp + @Usage Functions for the HealBeacon mode. +*/ + #pragma semicolon 1 #pragma newdecls required -ConVarInfo g_cvInfoHealBeacon[6] = +ModeInfo g_HBInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_HBInfo + +bool g_bIsBetterDamageModeOn; + +/* Arraylist to save client indexes of the heal beaconed players */ +ArrayList g_aHBPlayers; + +/* Timers */ +Handle g_hRoundStart_Timer[2] = { null, ... }; +Handle g_hDamageTimer = null; +Handle g_hHealTimer = null; +Handle g_hBeaconTimer[MAXPLAYERS + 1] = { null, ... }; + +#define HB_CONVAR_BEACON_TIMER 0 +#define HB_CONVAR_ALERT_TIMER 1 +#define HB_CONVAR_BEACON_DAMAGE 2 +#define HB_CONVAR_BEACON_HEAL 3 +#define HB_CONVAR_RANDOMS 4 +#define HB_CONVAR_DEFAULT_DISTANCE 5 +#define HB_CONVAR_TOGGLE 6 + +enum struct BeaconPlayers { - {null, "20.0,30.0,40.0,60.0", "float"}, - {null, "5.0,8.0,10.0,15.0", "float"}, - {null, "2.0,5.0,10.0,15.0", "float"}, - {null, "1,2,3,4,5", "int"}, - {null, "1,2,3,4,5", "int"}, - {null, "100.0,200.0,400.0,500.0", "float"} -}; + bool hasHealBeacon; + bool hasNeon; + int color[4]; + float distance; + int neonEntity; + + void SetColor(int setColor[4]) + { + this.color[0] = setColor[0]; + this.color[1] = setColor[1]; + this.color[2] = setColor[2]; + this.color[3] = setColor[3]; + } + + void ResetColor() + { + this.color[0] = g_ColorDefault[0]; + this.color[1] = g_ColorDefault[1]; + this.color[2] = g_ColorDefault[2]; + this.color[3] = g_ColorDefault[3]; + } + + void ResetValues() + { + this.hasHealBeacon = false; + this.ResetColor(); + this.distance = THIS_MODE_INFO.cvarInfo[HB_CONVAR_DEFAULT_DISTANCE].cvar.FloatValue; + this.neonEntity = -1; + } +} + +BeaconPlayers g_BeaconPlayersData[MAXPLAYERS + 1]; /* Called in OnPluginStart */ -stock void PluginStart_HealBeacon() +stock void OnPluginStart_HealBeacon() { + THIS_MODE_INFO.name = "HealBeacon"; + THIS_MODE_INFO.tag = "{gold}[FunModes-HealBeacon]{lightgreen}"; + /* ADMIN COMMANDS */ - RegAdminCmd("sm_fm_healbeacon", Cmd_HealBeacon, ADMFLAG_CONVARS, "Enable/Disable Healbeacon"); - RegAdminCmd("sm_healbeacon", Cmd_HealBeaconMenu, ADMFLAG_CONVARS, "Shows healbeacon menu"); + RegAdminCmd("sm_fm_healbeacon", Cmd_HealBeaconToggle, ADMFLAG_CONVARS, "Enable/Disable Healbeacon"); + RegAdminCmd("sm_healbeacon", Cmd_HealBeaconSettings, ADMFLAG_CONVARS, "Shows healbeacon menu"); RegAdminCmd("sm_beacon_distance", Cmd_HealBeaconDistance, ADMFLAG_CONVARS, "Change beacon distance"); RegAdminCmd("sm_replacebeacon", Cmd_HealBeaconReplace, ADMFLAG_BAN, "Replace an already heal beaconed player with another one"); RegAdminCmd("sm_addnewbeacon", Cmd_HealBeaconAddNew, ADMFLAG_BAN, "Add a new heal beaconed player"); RegAdminCmd("sm_removebeacon", Cmd_HealBeaconRemove, ADMFLAG_BAN, "Remove heal beacon player"); RegConsoleCmd("sm_checkdistance", Cmd_HealBeaconCheckDistance, "..."); - /* CONVARS HANDLES */ - g_cvHealBeaconTimer = CreateConVar("sm_beacon_timer", "20.0", "The time that will start picking random players at round start"); - g_cvAlertTimer = CreateConVar("sm_beacon_alert_timer", "10", "How much time in seconds the damage will start being applied from heal beacon as an alert for the other humans"); - g_cvHealBeaconDamage = CreateConVar("sm_beacon_damage", "5", "The damage that the heal beacon will give"); - g_cvHealBeaconHeal = CreateConVar("sm_beacon_heal", "1", "How much heal beacon should heal the players in 1 second"); - g_cvRandoms = CreateConVar("sm_healbeacon_randoms", "2", "How many random players should get the heal beacon"); - g_cvDefaultDistance = CreateConVar("sm_healbeacon_distance", "400.0", "Default distance of beacon to give"); - - HealBeacon_SetCvarsInfo(); + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, HB_CONVAR_BEACON_TIMER, + "sm_beacon_timer", "20.0", "The time that will start picking random players at round start", + ("20.0,30.0,40.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, HB_CONVAR_ALERT_TIMER, + "sm_beacon_alert_timer", "10.0", "How much time in seconds the damage will start being applied from heal beacon as an alert for the other humans", + ("5.0,8.0,10.0,15.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, HB_CONVAR_BEACON_DAMAGE, + "sm_beacon_damage", "5.0", "The damage that the heal beacon will give", + ("2.0,5.0,8.0,10.0,15.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, HB_CONVAR_BEACON_HEAL, + "sm_beacon_heal", "1", "How much heal beacon should heal the players in 1 second", + ("1,2,3,4,5,10"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, HB_CONVAR_RANDOMS, + "sm_healbeacon_randoms", "2", "How many random players should get the heal beacon", + ("1,2,3,4,5,10"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, HB_CONVAR_DEFAULT_DISTANCE, + "sm_healbeacon_distance", "400.0", "Default distance of beacon to give", + ("100.0,200.0,400.0,500.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, HB_CONVAR_TOGGLE, + "sm_healbeacon_enable", "1", "Enable/Disable HealBeacon mode.", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = HB_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[HB_CONVAR_TOGGLE].cvar.AddChangeHook(OnHBModeToggle); +} + +void OnHBModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_HealBeacon() {} +stock void OnMapEnd_HealBeacon() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + for (int i = 1; i <= MaxClients; i++) + { + g_hBeaconTimer[i] = null; + } + g_hRoundStart_Timer[0] = null; + g_hRoundStart_Timer[1] = null; + g_hDamageTimer = null; + g_hHealTimer = null; } -void HealBeacon_SetCvarsInfo() +stock void OnClientPutInServer_HealBeacon(int client) { - ConVar cvars[sizeof(g_cvInfoHealBeacon)]; - cvars[0] = g_cvHealBeaconTimer; - cvars[1] = g_cvAlertTimer; - cvars[2] = g_cvHealBeaconDamage; - cvars[3] = g_cvHealBeaconHeal; - cvars[4] = g_cvRandoms; - cvars[5] = g_cvDefaultDistance; + #pragma unused client +} + +stock void OnClientDisconnect_HealBeacon(int client) +{ + if (!THIS_MODE_INFO.isOn) + return; + + if (!g_BeaconPlayersData[client].hasHealBeacon) + { + delete g_hBeaconTimer[client]; + g_BeaconPlayersData[client].ResetValues(); + return; + } - for (int i = 0; i < sizeof(g_cvInfoHealBeacon); i++) - g_cvInfoHealBeacon[i].cvar = cvars[i]; + RemoveBeacon(-1, client); + CPrintToChatAll("%s {olive}%N {lightgreen}disconnected with HealBeacon.", THIS_MODE_INFO.tag, client); +} + +stock void ZR_OnClientInfected_HealBeacon(int client) +{ + #pragma unused client } -stock void RoundStart_HealBeacon() +stock void Event_RoundStart_HealBeacon() { /* DELETE TIMER HANDLES SO WE DONT GET ERRORS */ HealBeacon_DeleteAllTimers(); /* CHECK IF ARRAYLIST IS NOT NULL AND THEN ERASE ALL CLIENTS INDEXES IN ARRAYLIST */ - if(g_aHBPlayers == null) + if (g_aHBPlayers == null) return; g_aHBPlayers.Clear(); - if(!g_bIsHealBeaconOn) + if (!THIS_MODE_INFO.isOn) return; /* RESET COUNTER */ g_iCounter = 0; /* LETS CREATE THE FIRST ROUND START TIMER */ - g_hRoundStart_Timer[0] = CreateTimer(g_cvHealBeaconTimer.FloatValue, RoundStart_Timer, _, TIMER_FLAG_NO_MAPCHANGE); + g_hRoundStart_Timer[0] = CreateTimer(THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_TIMER].cvar.FloatValue, RoundStart_Timer, _, TIMER_FLAG_NO_MAPCHANGE); } -stock void PlayerDeath_HealBeacon(int userid) +stock void Event_RoundEnd_HealBeacon() {} +stock void Event_PlayerSpawn_HealBeacon(int client) { - int client = GetClientOfUserId(userid); - if(!IsValidClient(client) || !g_BeaconPlayersData[client].hasHealBeacon) + #pragma unused client +} + +stock void Event_PlayerDeath_HealBeacon(int client) +{ + if (!THIS_MODE_INFO.isOn || !g_BeaconPlayersData[client].hasHealBeacon) return; RemoveBeacon(-1, client); - CPrintToChatAll("%s {olive}%N {lightgreen}died with HealBeacon.", HealBeacon_Tag, client); + CPrintToChatAll("%s {olive}%N {lightgreen}died with HealBeacon.", THIS_MODE_INFO.tag, client); } -stock void PlayerTeam_HealBeacon(int userid, int team) +stock void Event_PlayerTeam_HealBeacon(Event event) { - int client = GetClientOfUserId(userid); - if(!IsValidClient(client) || !g_BeaconPlayersData[client].hasHealBeacon) + if (!THIS_MODE_INFO.isOn) + return; + + int client = GetClientOfUserId(event.GetInt("userid")); + if (!client || !g_BeaconPlayersData[client].hasHealBeacon) return; - if(team == CS_TEAM_SPECTATOR || team == CS_TEAM_NONE) + int team = event.GetInt("team"); + if (team == CS_TEAM_SPECTATOR || team == CS_TEAM_NONE) { RemoveBeacon(-1, client); - CPrintToChatAll("%s {olive}%N {lightgreen}moved to spectator team with HealBeacon.", HealBeacon_Tag, client); + CPrintToChatAll("%s {olive}%N {lightgreen}moved to spectator team with HealBeacon.", THIS_MODE_INFO.tag, client); } } -stock void ClientDisconnect_HealBeacon(int client) -{ - if(!g_BeaconPlayersData[client].hasHealBeacon) - { - delete g_hBeaconTimer[client]; - g_BeaconPlayersData[client].ResetValues(); - return; - } - - RemoveBeacon(-1, client); - CPrintToChatAll("%s {olive}%N {lightgreen}disconnected with HealBeacon.", HealBeacon_Tag, client); -} - Action RoundStart_Timer(Handle timer) { g_hRoundStart_Timer[0] = null; - + + if (!THIS_MODE_INFO.isOn) + return Plugin_Stop; + /* Let's now pick the random players */ - for(int i = 0; i < g_cvRandoms.IntValue; i++) + for (int i = 0; i < THIS_MODE_INFO.cvarInfo[HB_CONVAR_RANDOMS].cvar.IntValue; i++) { GetRandomPlayer(); } @@ -123,9 +254,15 @@ Action RoundStart_Timer(Handle timer) Action RoundStart_CountTimer(Handle timer) { - int alertTime = g_cvAlertTimer.IntValue; + if (!THIS_MODE_INFO.isOn) + { + g_hRoundStart_Timer[1] = null; + return Plugin_Stop; + } + + int alertTime = THIS_MODE_INFO.cvarInfo[HB_CONVAR_ALERT_TIMER].cvar.IntValue; - if(g_iCounter >= alertTime) + if (g_iCounter >= alertTime) { HealBeacon_Setup(); g_hRoundStart_Timer[1] = null; @@ -133,14 +270,14 @@ Action RoundStart_CountTimer(Handle timer) } /* Lets send the hud message to all clients */ - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsClientInGame(i)) + if (!IsClientInGame(i)) continue; - char sMessage[256]; - FormatEx(sMessage, sizeof(sMessage), "%T", "HealBeacon_Alert", i, (alertTime - g_iCounter)); - SendHudText(i, sMessage); + char message[256]; + FormatEx(message, sizeof(message), "%T", "HealBeacon_Alert", i, (alertTime - g_iCounter)); + SendHudText(i, message); } g_iCounter++; @@ -152,35 +289,35 @@ stock void GetRandomPlayer() int clientsCount[MAXPLAYERS + 1]; int humansCount; - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) + if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) continue; /* if client is already heal beaconed then dont include them in */ - if(g_BeaconPlayersData[i].hasHealBeacon) + if (g_BeaconPlayersData[i].hasHealBeacon) continue; clientsCount[humansCount++] = i; } - if(humansCount <= 0 || humansCount < g_cvRandoms.IntValue) + if (humansCount <= 0 || humansCount < THIS_MODE_INFO.cvarInfo[HB_CONVAR_RANDOMS].cvar.IntValue) return; int random = clientsCount[GetRandomInt(0, (humansCount - 1))]; - if(random < 1) + if (random < 1) return; /* Lets now apply healbeacon to the choosen one */ SetHealBeaconToClient(random); - CPrintToChatAll("%s %T", HealBeacon_Tag, "HealBeacon_AddAnnounce", random, random); + CPrintToChatAll("%s %T", THIS_MODE_INFO.tag, "HealBeacon_AddAnnounce", random, random); } stock void SetHealBeaconToClient(int client) { /* Lets save the healbeacon player data they are needed */ g_BeaconPlayersData[client].hasHealBeacon = true; - g_BeaconPlayersData[client].distance = g_cvDefaultDistance.FloatValue; + g_BeaconPlayersData[client].distance = THIS_MODE_INFO.cvarInfo[HB_CONVAR_DEFAULT_DISTANCE].cvar.FloatValue; g_BeaconPlayersData[client].ResetColor(); /* BEACON THE PLAYER */ @@ -205,49 +342,60 @@ stock void HealBeacon_Setup() Action HealBeacon_BeaconTimer(Handle timer, int userid) { int client = GetClientOfUserId(userid); - if(!IsValidClient(client)) + if (!client) + { + return Plugin_Stop; + } + + if (!THIS_MODE_INFO.isOn) { g_hBeaconTimer[client] = null; return Plugin_Stop; } - - if(!IsPlayerAlive(client) || GetClientTeam(client) != CS_TEAM_CT || !g_BeaconPlayersData[client].hasHealBeacon) + + if (!IsPlayerAlive(client) || GetClientTeam(client) != CS_TEAM_CT || !g_BeaconPlayersData[client].hasHealBeacon) { g_hBeaconTimer[client] = null; return Plugin_Stop; } - BeaconPlayer(client, BeaconMode_HealBeacon); + BeaconPlayer(client, 0, g_BeaconPlayersData[client].distance, g_BeaconPlayersData[client].color); return Plugin_Continue; } Action HealBeacon_DamageTimer(Handle timer) { + if (!THIS_MODE_INFO.isOn) + { + g_hDamageTimer = null; + return Plugin_Stop; + } + /* if round is ending */ - if(g_bRoundEnd) + if (g_bRoundEnd) return Plugin_Handled; /* if all healbeacon players died */ - if(g_aHBPlayers.Length == 0) + if (g_aHBPlayers.Length == 0) { - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) + if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) continue; - SDKHooks_TakeDamage(i, 0, 0, g_cvHealBeaconDamage.FloatValue); + SDKHooks_TakeDamage(i, 0, 0, THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_DAMAGE].cvar.FloatValue); } return Plugin_Handled; } - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) + if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) continue; /* if client is healbeaconed then continue the loop and ignore that client */ - if(g_BeaconPlayersData[i].hasHealBeacon) + if (g_BeaconPlayersData[i].hasHealBeacon) continue; HealBeacon_DealDamage(i); @@ -260,27 +408,29 @@ stock void HealBeacon_DealDamage(int client) { bool isFar = false; - for(int i = 0; i < g_aHBPlayers.Length; i++) + for (int i = 0; i < g_aHBPlayers.Length; i++) { int random = g_aHBPlayers.Get(i); - float distance = GetDistanceBetween(random, client); + + // squarred distance, better for performance + float distance = GetDistanceBetween(random, client, true); /* if player is not far from any heal beacon player then we need to stop the loop */ - if(distance < (g_BeaconPlayersData[random].distance / 2.0)) + float beaconRadiusHalf = g_BeaconPlayersData[random].distance / 2.0; + if (distance < (beaconRadiusHalf * beaconRadiusHalf)) { isFar = false; break; } /* else */ - if(distance > (g_BeaconPlayersData[random].distance / 2.0)) - isFar = true; + isFar = true; } /* if player is far then do damage and warn them */ - if(isFar) + if (isFar) { - SDKHooks_TakeDamage(client, 0, 0, g_cvHealBeaconDamage.FloatValue); + SDKHooks_TakeDamage(client, 0, 0, THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_DAMAGE].cvar.FloatValue); char sMessage[256]; FormatEx(sMessage, sizeof(sMessage), "%T", "HealBeacon_Damage", client); SendHudText(client, sMessage, true); @@ -289,14 +439,20 @@ stock void HealBeacon_DealDamage(int client) Action HealBeacon_HealTimer(Handle timer) { + if (!THIS_MODE_INFO.isOn) + { + g_hHealTimer = null; + return Plugin_Stop; + } + /* IF BETTER DAMAGE MODE IS ON THEN stop the timer for a while until its off */ /* BETTER DAMAGE mode means that the players will get hurt but they wont get heal */ - if(g_bIsBetterDamageModeOn) + if (g_bIsBetterDamageModeOn) return Plugin_Handled; - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) + if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) continue; HealBeacon_DealHeal(i); @@ -308,19 +464,19 @@ Action HealBeacon_HealTimer(Handle timer) stock void HealBeacon_DealHeal(int client) { /* if client has healbeacon then give heal to them */ - if(g_BeaconPlayersData[client].hasHealBeacon) + if (g_BeaconPlayersData[client].hasHealBeacon) { int health = GetEntProp(client, Prop_Send, "m_iHealth"); int maxHealth = GetEntProp(client, Prop_Data, "m_iMaxHealth"); /* WE SHOULD ALWAYS CHECK IF MAXHEALTH IS MORE THAN PLAYERS HEALTH summing with the extra health */ - if((health) < maxHealth) + if ((health) < maxHealth) { - int newHealth = (health + g_cvHealBeaconHeal.IntValue); + int newHealth = (health + THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_HEAL].cvar.IntValue); - if(newHealth == maxHealth) + if (newHealth == maxHealth) newHealth = maxHealth; - else if(newHealth > maxHealth) + else if (newHealth > maxHealth) newHealth = (health + 1); SetEntProp(client, Prop_Data, "m_iHealth", newHealth); @@ -329,25 +485,25 @@ stock void HealBeacon_DealHeal(int client) return; } - for(int i = 0; i < g_aHBPlayers.Length; i++) + for (int i = 0; i < g_aHBPlayers.Length; i++) { int random = g_aHBPlayers.Get(i); float distance = GetDistanceBetween(random, client); /* if distance between both of them is less than or equal the healbeacon distance */ - if(distance <= (g_BeaconPlayersData[random].distance / 2.0)) + if (distance <= (g_BeaconPlayersData[random].distance / 2.0)) { int health = GetEntProp(client, Prop_Send, "m_iHealth"); int maxHealth = GetEntProp(client, Prop_Data, "m_iMaxHealth"); /* WE SHOULD ALWAYS CHECK IF MAXHEALTH IS MORE THAN PLAYERS HEALTH summing with the extra health */ - if((health) < maxHealth) + if ((health) < maxHealth) { - int newHealth = (health + g_cvHealBeaconHeal.IntValue); + int newHealth = (health + THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_HEAL].cvar.IntValue); - if(newHealth == maxHealth) + if (newHealth == maxHealth) newHealth = maxHealth; - else if(newHealth > maxHealth) + else if (newHealth > maxHealth) newHealth = (health + 1); SetEntProp(client, Prop_Data, "m_iHealth", newHealth); @@ -360,18 +516,15 @@ stock void HealBeacon_DealHeal(int client) stock void HealBeacon_DeleteAllTimers() { - for(int i = 0; i <= 1; i++) { + for (int i = 0; i <= 1; i++) { delete g_hRoundStart_Timer[i]; } delete g_hDamageTimer; delete g_hHealTimer; - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i)) - continue; - delete g_hBeaconTimer[i]; } } @@ -382,7 +535,7 @@ stock void SetClientNeon(int client) int entity = CreateEntityByName("light_dynamic"); - if(!IsValidEntity(entity)) + if (!IsValidEntity(entity)) return; g_BeaconPlayersData[client].hasNeon = true; @@ -417,7 +570,7 @@ stock void SetClientNeon(int client) stock void RemoveNeon(int client) { - if(g_BeaconPlayersData[client].neonEntity && IsValidEntity(g_BeaconPlayersData[client].neonEntity)) + if (g_BeaconPlayersData[client].neonEntity && IsValidEntity(g_BeaconPlayersData[client].neonEntity)) AcceptEntityInput(g_BeaconPlayersData[client].neonEntity, "KillHierarchy"); g_BeaconPlayersData[client].hasNeon = false; @@ -429,7 +582,7 @@ stock void AddNewBeacon(int client, int target) SetHealBeaconToClient(target); /* ANNOUNCE THAT THIS TARGET IS NOW A HEALBEACON! */ - CPrintToChatAll("%s %T", HealBeacon_Tag, "HealBeacon_AddAnnounce", client, target); + CPrintToChatAll("%s %T", THIS_MODE_INFO.tag, "HealBeacon_AddAnnounce", client, target); } stock void RemoveBeacon(int client, int target) @@ -441,10 +594,10 @@ stock void RemoveBeacon(int client, int target) g_BeaconPlayersData[target].ResetValues(); /* ERASE THE TARGET INDEX FROM ARRAYLIST */ - for(int i = 0; i < g_aHBPlayers.Length; i++) + for (int i = 0; i < g_aHBPlayers.Length; i++) { int random = g_aHBPlayers.Get(i); - if(random == target) + if (random == target) { g_aHBPlayers.Erase(i); break; @@ -455,9 +608,9 @@ stock void RemoveBeacon(int client, int target) delete g_hBeaconTimer[target]; /* ANNOUNCE THAT THIS DUDE HEALBEACON IS REMOVED */ - if(client > 0) + if (client > 0) { - CPrintToChatAll("%s %T", HealBeacon_Tag, "HealBeacon_RemoveAnnounce", client, client, target); + CPrintToChatAll("%s %T", THIS_MODE_INFO.tag, "HealBeacon_RemoveAnnounce", client, client, target); LogAction(client, target, "[FunModes-HealBeacon] \"%L\" removed HealBeacon from \"%L\"", client, target); } } @@ -465,24 +618,24 @@ stock void RemoveBeacon(int client, int target) stock void ReplaceBeacon(int client, int random, int target) { /* if is Repick */ - if(target == -1) + if (target == -1) { /* WE GOTTA REPICK a RANDOM HUMAN FOR HEALBEACON */ int clientsCount[MAXPLAYERS + 1]; int humansCount; - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) + if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) continue; - if(g_BeaconPlayersData[i].hasHealBeacon) + if (g_BeaconPlayersData[i].hasHealBeacon) continue; clientsCount[humansCount++] = i; } - if(humansCount <= 0) + if (humansCount <= 0) return; /* REMOVE BEACON FROM PREVIOUS HEALBEACON */ @@ -493,7 +646,7 @@ stock void ReplaceBeacon(int client, int random, int target) SetHealBeaconToClient(newRandom); /* ANNOUNCE THAT THIS DUDE IS A HEALBEACON */ - CPrintToChatAll("%s %T", HealBeacon_Tag, "HealBeacon_RepickAnnounce", client, client, newRandom, random); + CPrintToChatAll("%s %T", THIS_MODE_INFO.tag, "HealBeacon_RepickAnnounce", client, client, newRandom, random); return; } @@ -502,33 +655,34 @@ stock void ReplaceBeacon(int client, int random, int target) SetHealBeaconToClient(target); /* ANNOUNCE THAT THIS DUDE IS A HEALBEACON */ - CPrintToChatAll("%s %T", HealBeacon_Tag, "HealBeacon_ReplaceAnnounce", client, client, target, random); + CPrintToChatAll("%s %T", THIS_MODE_INFO.tag, "HealBeacon_ReplaceAnnounce", client, client, target, random); } /*---------------------*/ /* COMMANDS CALLBACKS */ /*---------------------*/ -Action Cmd_HealBeacon(int client, int args) +public Action Cmd_HealBeaconToggle(int client, int args) { - if(g_bIsHealBeaconOn) + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s Healbeacon is currently disabled!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + if (THIS_MODE_INFO.isOn) { - g_bIsHealBeaconOn = false; delete g_aHBPlayers; HealBeacon_DeleteAllTimers(); - if(!client) - ReplyToCommand(client, "%s HealBeacon Mode is now OFF!", HealBeacon_Tag); + if (!client) + ReplyToCommand(client, "%s HealBeacon Mode is now OFF!", THIS_MODE_INFO.tag); else - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_Disabled", client); - - return Plugin_Handled; + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_Disabled", client); } else { - g_bIsHealBeaconOn = true; - /* Event hooks */ FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); FunModes_HookEvent(g_bEvent_RoundEnd, "round_end", Event_RoundEnd); @@ -537,23 +691,24 @@ Action Cmd_HealBeacon(int client, int args) delete g_aHBPlayers; g_aHBPlayers = new ArrayList(ByteCountToCells(32)); - if(!client) - ReplyToCommand(client, "%s HealBeacon Mode is now ON!", HealBeacon_Tag); + if (!client) + ReplyToCommand(client, "%s HealBeacon Mode is now ON!", THIS_MODE_INFO.tag); else - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_Enabled", client); - - return Plugin_Handled; + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_Enabled", client); } + + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + return Plugin_Handled; } -Action Cmd_HealBeaconMenu(int client, int args) +public Action Cmd_HealBeaconSettings(int client, int args) { - if(!client) + if (!client) return Plugin_Handled; - if(!g_bIsHealBeaconOn) + if (!THIS_MODE_INFO.isOn) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_Disabled", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_Disabled", client); return Plugin_Handled; } @@ -563,15 +718,15 @@ Action Cmd_HealBeaconMenu(int client, int args) Action Cmd_HealBeaconDistance(int client, int args) { - if(!g_bIsHealBeaconOn) + if (!THIS_MODE_INFO.isOn) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_Disabled", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_Disabled", client); return Plugin_Handled; } - if(args < 2) + if (args < 2) { - CReplyToCommand(client, "%s Usage: sm_beacon_distance ", HealBeacon_Tag); + CReplyToCommand(client, "%s Usage: sm_beacon_distance ", THIS_MODE_INFO.tag); return Plugin_Handled; } @@ -580,42 +735,42 @@ Action Cmd_HealBeaconDistance(int client, int args) GetCmdArg(2, arg2, sizeof(arg2)); int target = FindTarget(client, arg1, false, false); - if(target < 1) + if (target < 1) { ReplyToTargetError(client, COMMAND_TARGET_NOT_IN_GAME); return Plugin_Handled; } - if(!g_BeaconPlayersData[target].hasHealBeacon) + if (!g_BeaconPlayersData[target].hasHealBeacon) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_PlayerIsNot", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_PlayerIsNot", client); return Plugin_Handled; } float distance; - if(!StringToFloatEx(arg2, distance)) + if (!StringToFloatEx(arg2, distance)) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_InvalidDistnace", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_InvalidDistnace", client); return Plugin_Handled; } g_BeaconPlayersData[target].distance = distance; - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_DistanceChange", client, target, distance); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_DistanceChange", client, target, distance); LogAction(client, target, "[FunModes-HealBeacon] \"%L\" changed Beacon Distance of \"%L\" to \"%d\"", client, target, distance); return Plugin_Handled; } Action Cmd_HealBeaconReplace(int client, int args) { - if(!g_bIsHealBeaconOn) + if (!THIS_MODE_INFO.isOn) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_Disabled", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_Disabled", client); return Plugin_Handled; } - if(args < 2) + if (args < 2) { - CReplyToCommand(client, "%s Usage: sm_replacebeacon ", HealBeacon_Tag); + CReplyToCommand(client, "%s Usage: sm_replacebeacon ", THIS_MODE_INFO.tag); return Plugin_Handled; } @@ -626,21 +781,21 @@ Action Cmd_HealBeaconReplace(int client, int args) int healBeaconTarget = FindTarget(client, arg1, false, false); int target = FindTarget(client, arg2, false, false); - if(healBeaconTarget < 1 || target < 1) + if (healBeaconTarget < 1 || target < 1) { ReplyToTargetError(client, COMMAND_TARGET_NOT_IN_GAME); return Plugin_Handled; } - if(!g_BeaconPlayersData[healBeaconTarget].hasHealBeacon) + if (!g_BeaconPlayersData[healBeaconTarget].hasHealBeacon) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_PlayerIsNot", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_PlayerIsNot", client); return Plugin_Handled; } - if(g_BeaconPlayersData[target].hasHealBeacon) + if (g_BeaconPlayersData[target].hasHealBeacon) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_PlayerIs", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_PlayerIs", client); return Plugin_Handled; } @@ -650,15 +805,15 @@ Action Cmd_HealBeaconReplace(int client, int args) Action Cmd_HealBeaconAddNew(int client, int args) { - if(!g_bIsHealBeaconOn) + if (!THIS_MODE_INFO.isOn) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_Disabled", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_Disabled", client); return Plugin_Handled; } - if(args < 1) + if (args < 1) { - CReplyToCommand(client, "%s Usage: sm_addnewbeacon ", HealBeacon_Tag); + CReplyToCommand(client, "%s Usage: sm_addnewbeacon ", THIS_MODE_INFO.tag); return Plugin_Handled; } @@ -666,15 +821,15 @@ Action Cmd_HealBeaconAddNew(int client, int args) GetCmdArg(1, arg, sizeof(arg)); int target = FindTarget(client, arg, false, false); - if(target < 1) + if (target < 1) { ReplyToTargetError(client, COMMAND_TARGET_NOT_IN_GAME); return Plugin_Handled; } - if(g_BeaconPlayersData[target].hasHealBeacon) + if (g_BeaconPlayersData[target].hasHealBeacon) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_PlayerIs", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_PlayerIs", client); return Plugin_Handled; } @@ -685,15 +840,15 @@ Action Cmd_HealBeaconAddNew(int client, int args) Action Cmd_HealBeaconRemove(int client, int args) { - if(!g_bIsHealBeaconOn) + if (!THIS_MODE_INFO.isOn) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_Disabled", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_Disabled", client); return Plugin_Handled; } - if(args < 1) + if (args < 1) { - CReplyToCommand(client, "%s Usage: sm_removebeacon ", HealBeacon_Tag); + CReplyToCommand(client, "%s Usage: sm_removebeacon ", THIS_MODE_INFO.tag); return Plugin_Handled; } @@ -701,15 +856,15 @@ Action Cmd_HealBeaconRemove(int client, int args) GetCmdArg(1, arg, sizeof(arg)); int target = FindTarget(client, arg, false, false); - if(target < 1) + if (target < 1) { ReplyToTargetError(client, COMMAND_TARGET_NOT_IN_GAME); return Plugin_Handled; } - if(!g_BeaconPlayersData[target].hasHealBeacon) + if (!g_BeaconPlayersData[target].hasHealBeacon) { - CReplyToCommand(client, "%s %T", HealBeacon_Tag, "HealBeacon_PlayerIsNot", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_PlayerIsNot", client); return Plugin_Handled; } @@ -719,14 +874,14 @@ Action Cmd_HealBeaconRemove(int client, int args) Action Cmd_HealBeaconCheckDistance(int client, int args) { - if(!client) + if (!client) { return Plugin_Handled; } - if(args < 1) + if (args < 1) { - CReplyToCommand(client, "%s Usage: sm_checkdistance ", HealBeacon_Tag); + CReplyToCommand(client, "%s Usage: sm_checkdistance ", THIS_MODE_INFO.tag); return Plugin_Handled; } @@ -734,19 +889,21 @@ Action Cmd_HealBeaconCheckDistance(int client, int args) GetCmdArg(1, arg, sizeof(arg)); int target = FindTarget(client, arg, false, false); - if(target < 1) + if (target < 1) { ReplyToTargetError(client, COMMAND_TARGET_NOT_IN_GAME); return Plugin_Handled; } - if(!IsPlayerAlive(target)) + if (!IsPlayerAlive(target)) { ReplyToTargetError(client, COMMAND_TARGET_NOT_ALIVE); return Plugin_Handled; } float distance = GetDistanceBetween(client, target); - CReplyToCommand(client, "%s Distance between you and %N is: {olive}%.2f.", HealBeacon_Tag, target, distance); + CReplyToCommand(client, "%s Distance between you and %N is: {olive}%.2f.", THIS_MODE_INFO.tag, target, distance); return Plugin_Handled; -} \ No newline at end of file +} + +#include "Fun_Modes/HealBeacon_Menus.sp" \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/HealBeacon_Menus.sp b/addons/sourcemod/scripting/Fun_Modes/HealBeacon_Menus.sp index 35d79bc..9d6ab35 100644 --- a/addons/sourcemod/scripting/Fun_Modes/HealBeacon_Menus.sp +++ b/addons/sourcemod/scripting/Fun_Modes/HealBeacon_Menus.sp @@ -1,6 +1,15 @@ +/* + (). FunModes V2: + + @file HealBeacon_Menus.sp + @Usage Menu Functions for the HealBeacon mode. +*/ + #pragma semicolon 1 #pragma newdecls required +int g_iClientMenuUserId[MAXPLAYERS + 1] = { -1, ... }; + stock void HealBeacon_DisplayMainMenu(int client) { Menu menu = new Menu(MainMenu_Handler); @@ -10,7 +19,7 @@ stock void HealBeacon_DisplayMainMenu(int client) for(int i = 0; i < g_aHBPlayers.Length; i++) { int random = g_aHBPlayers.Get(i); - if(!IsValidClient(random)) + if (!IsClientInGame(random) || !IsPlayerAlive(random)) continue; char info[32], buffer[64]; @@ -42,7 +51,7 @@ public int MainMenu_Handler(Menu menu, MenuAction action, int param1, int param2 { char buffer[64]; menu.GetItem(param2, buffer, sizeof(buffer)); - if(StrEqual(buffer, "option2")) + if(strcmp(buffer, "option2") == 0) { HealBeacon_DisplaySettingsMenu(param1); return 0; @@ -50,15 +59,15 @@ public int MainMenu_Handler(Menu menu, MenuAction action, int param1, int param2 int userid = StringToInt(buffer); int random = GetClientOfUserId(userid); - if(!IsValidClient(random)) + if (!random) { - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "PlayerNotValid", param1); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "PlayerNotValid", param1); return 0; } if(!g_BeaconPlayersData[random].hasHealBeacon) { - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_PlayerIsNot", param1); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_PlayerIsNot", param1); return 0; } @@ -123,12 +132,12 @@ public int SettingsMenu_Handler(Menu menu, MenuAction action, int param1, int pa if(g_bIsBetterDamageModeOn) { g_bIsBetterDamageModeOn = false; - CPrintToChat(param1, "%s Better Damage Mode is now {olive}OFF!", HealBeacon_Tag); + CPrintToChat(param1, "%s Better Damage Mode is now {olive}OFF!", THIS_MODE_INFO.tag); } else { g_bIsBetterDamageModeOn = true; - CPrintToChat(param1, "%s Better Damage Mode is now {olive}ON!", HealBeacon_Tag); + CPrintToChat(param1, "%s Better Damage Mode is now {olive}ON!", THIS_MODE_INFO.tag); } } case 4: @@ -147,7 +156,7 @@ stock void HealBeacon_DisplayBeaconDamageMenu(int client) { Menu menu = new Menu(BeaconDamageMenu_Handler); char title[256]; - Format(title, sizeof(title), "Change Heal Beacon Damage\nYou can also change the cvar sm_beacon_damage\nincase you didnt find the good\ndamage in the list\nCurrent HealBeacon Damage: %.2f", g_cvHealBeaconDamage.FloatValue); + Format(title, sizeof(title), "Change Heal Beacon Damage\nYou can also change the cvar sm_beacon_damage\nincase you didnt find the good\ndamage in the list\nCurrent HealBeacon Damage: %.2f", THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_DAMAGE].cvar.FloatValue); menu.SetTitle(title); menu.AddItem("1", "1"); @@ -180,8 +189,8 @@ public int BeaconDamageMenu_Handler(Menu menu, MenuAction action, int param1, in menu.GetItem(param2, buffer, sizeof(buffer)); int num = StringToInt(buffer); - g_cvHealBeaconDamage.FloatValue = float(num); - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_DamageChange", param1, num); + THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_DAMAGE].cvar.FloatValue = float(num); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_DamageChange", param1, num); HealBeacon_DisplayBeaconDamageMenu(param1); } } @@ -194,7 +203,7 @@ stock void HealBeacon_DisplayBeaconHealMenu(int client) { Menu menu = new Menu(BeaconHealMenu_Handler); char title[256]; - Format(title, sizeof(title), "Change Heal Beacon Heal per second\nYou can also change the cvar sm_beacon_heal\nincase you didnt find the good\nheal in the list\nCurrent HealBeacon Heal: %d", g_cvHealBeaconHeal.IntValue); + Format(title, sizeof(title), "Change Heal Beacon Heal per second\nYou can also change the cvar sm_beacon_heal\nincase you didnt find the good\nheal in the list\nCurrent HealBeacon Heal: %d", THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_HEAL].cvar.IntValue); menu.SetTitle(title); for(int i = 1; i <= 7; i++) @@ -227,8 +236,8 @@ public int BeaconHealMenu_Handler(Menu menu, MenuAction action, int param1, int menu.GetItem(param2, buffer, sizeof(buffer)); int num = StringToInt(buffer); - g_cvHealBeaconHeal.IntValue = num; - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_HealChange", param1, num); + THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_HEAL].cvar.IntValue = num; + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_HealChange", param1, num); HealBeacon_DisplayBeaconHealMenu(param1); } } @@ -274,8 +283,8 @@ public int BeaconTimerMenu_Handler(Menu menu, MenuAction action, int param1, int menu.GetItem(param2, buffer, sizeof(buffer)); int num = StringToInt(buffer); - g_cvHealBeaconTimer.FloatValue = float(num); - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_TimerChange", param1, num); + THIS_MODE_INFO.cvarInfo[HB_CONVAR_BEACON_TIMER].cvar.FloatValue = float(num); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_TimerChange", param1, num); HealBeacon_DisplaySettingsMenu(param1); } } @@ -290,14 +299,14 @@ stock void HealBeacon_DisplayBeaconDefaultColorMenu(int client) /* CHECK DEFAULT COLOR NAME */ char colorName[32]; - for(int i = 0; i < sizeof(colorsList); i++) + for(int i = 0; i < sizeof(g_ColorsList); i++) { - char buffers[5][64]; - ExplodeString(colorsList[i], " ", buffers, 5, sizeof(buffers[])); + char buffers[3][5]; + ExplodeString(g_ColorsList[i].rgb, " ", buffers, 3, sizeof(buffers[])); if(StringToInt(buffers[0]) == g_ColorDefault[0] && StringToInt(buffers[1]) == g_ColorDefault[1] - && StringToInt(buffers[2]) == g_ColorDefault[2] && StringToInt(buffers[3]) == g_ColorDefault[3]) { - Format(colorName, sizeof(colorName), buffers[4]); + && StringToInt(buffers[2]) == g_ColorDefault[2] && 255 == g_ColorDefault[3]) { + Format(colorName, sizeof(colorName), g_ColorsList[i].name); break; } } @@ -306,11 +315,11 @@ stock void HealBeacon_DisplayBeaconDefaultColorMenu(int client) Format(title, sizeof(title), "Change Heal Beacon Default Color\nDefault Color: %s", colorName); menu.SetTitle(title); - for(int i = 0; i < sizeof(colorsList); i++) + for(int i = 0; i < sizeof(g_ColorsList); i++) { - char buffers[5][64]; - ExplodeString(colorsList[i], " ", buffers, 5, sizeof(buffers[])); - menu.AddItem(colorsList[i], buffers[4]); + char index[3]; + IntToString(i, index, sizeof(index)); + menu.AddItem(index, g_ColorsList[i].name); } menu.ExitBackButton = true; @@ -333,16 +342,20 @@ public int BeaconDefaultColorMenu_Handler(Menu menu, MenuAction action, int para { char info[128]; menu.GetItem(param2, info, sizeof(info)); - - char buffers[5][64]; - ExplodeString(info, " ", buffers, 5, sizeof(buffers[])); - + + int index = StringToInt(info); + FM_Color myColor; + myColor = g_ColorsList[index]; + + char buffers[3][5]; // the splitted buffers from menu item + ExplodeString(myColor.rgb, " ", buffers, 3, sizeof(buffers[])); + g_ColorDefault[0] = StringToInt(buffers[0]); g_ColorDefault[1] = StringToInt(buffers[1]); g_ColorDefault[2] = StringToInt(buffers[2]); - g_ColorDefault[3] = StringToInt(buffers[3]); + g_ColorDefault[3] = 255; - CPrintToChat(param1, "%s You have changed the Default Beacon Color to {%s}%s.", HealBeacon_Tag, buffers[4], buffers[4]); + CPrintToChat(param1, "%s You have changed the Default Beacon Color to {%s}%s.", THIS_MODE_INFO.tag, myColor.name, myColor.name); HealBeacon_DisplayBeaconDefaultColorMenu(param1); } } @@ -354,8 +367,6 @@ public int BeaconDefaultColorMenu_Handler(Menu menu, MenuAction action, int para stock void HealBeacon_DisplayActionsMenu(int client, int random) { Menu menu = new Menu(ActionsMenu_Handler); - if(!IsValidClient(random)) - return; g_iClientMenuUserId[client] = GetClientUserId(random); char title[64], buffer[32]; @@ -397,16 +408,16 @@ public int ActionsMenu_Handler(Menu menu, MenuAction action, int param1, int par case MenuAction_Select: { int random = GetClientOfUserId(g_iClientMenuUserId[param1]); - if(!IsValidClient(random)) + if(!random) { - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "PlayerNotValid", param1); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "PlayerNotValid", param1); HealBeacon_DisplayMainMenu(param1); return 0; } if(!g_BeaconPlayersData[random].hasHealBeacon) { - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_PlayerIsNot", param1); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_PlayerIsNot", param1); HealBeacon_DisplayMainMenu(param1); return 0; } @@ -431,12 +442,12 @@ public int ActionsMenu_Handler(Menu menu, MenuAction action, int param1, int par if(g_BeaconPlayersData[random].hasNeon) { RemoveNeon(random); - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_NeonRemove", param1, random); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_NeonRemove", param1, random); } else { SetClientNeon(random); - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_NeonAdd", param1, random); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_NeonAdd", param1, random); } HealBeacon_DisplayActionsMenu(param1, random); @@ -471,7 +482,7 @@ public int ActionsMenu_Handler(Menu menu, MenuAction action, int param1, int par { ForcePlayerSuicide(random); LogAction(param1, random, "[FunModes-HealBeacon] \"%L\" slayed \"%L\"(HealBeacon Player)", param1, random); - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_Slay", param1, random); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_Slay", param1, random); HealBeacon_DisplayMainMenu(param1); } } @@ -485,18 +496,18 @@ stock void HealBeacon_DisplayColorsMenu(int client) { Menu menu = new Menu(ColorsMenu_Handler); int random = GetClientOfUserId(g_iClientMenuUserId[client]); - if(!IsValidClient(random)) + if (!random) return; char title[64]; Format(title, sizeof(title), "Change beacon and neon color on %N", random); menu.SetTitle(title); - for(int i = 0; i < sizeof(colorsList); i++) + for(int i = 0; i < sizeof(g_ColorsList); i++) { - char buffers[5][64]; - ExplodeString(colorsList[i], " ", buffers, 5, sizeof(buffers[])); - menu.AddItem(colorsList[i], buffers[4]); + char index[3]; + IntToString(i, index, sizeof(index)); + menu.AddItem(index, g_ColorsList[i].name); } menu.ExitBackButton = true; @@ -516,10 +527,10 @@ public int ColorsMenu_Handler(Menu menu, MenuAction action, int param1, int para if(param2 == MenuCancel_ExitBack) { int random = GetClientOfUserId(g_iClientMenuUserId[param1]); - if(!IsValidClient(random)) + if (!random) { HealBeacon_DisplayMainMenu(param1); - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "PlayerNotValid", param1); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "PlayerNotValid", param1); return 0; } @@ -529,30 +540,33 @@ public int ColorsMenu_Handler(Menu menu, MenuAction action, int param1, int para case MenuAction_Select: { int random = GetClientOfUserId(g_iClientMenuUserId[param1]); - if(!IsValidClient(random)) + if (!random) { - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "PlayerNotValid", param1); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "PlayerNotValid", param1); return 0; } - char info[128]; // The menu item + char info[3]; // The menu item menu.GetItem(param2, info, sizeof(info)); - - char buffers[5][64]; // the splitted buffers from menu item - ExplodeString(info, " ", buffers, 5, sizeof(buffers[])); + + int index = StringToInt(info); + FM_Color myColor; + myColor = g_ColorsList[index]; + + char buffers[3][5]; // the splitted buffers from menu item + ExplodeString(myColor.rgb, " ", buffers, 3, sizeof(buffers[])); + int color[4]; color[0] = StringToInt(buffers[0]); color[1] = StringToInt(buffers[1]); color[2] = StringToInt(buffers[2]); - color[3] = StringToInt(buffers[3]); + color[3] = 255; - char colorName[64]; - FormatEx(colorName, sizeof(colorName), buffers[4]); // the name of the color g_BeaconPlayersData[random].SetColor(color); // we gotta save the new color in the enum struct /* TELL THE CLIENT THAT THIS CHANGE IS APPLIED */ - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_ColorChange", param1, random, colorName, colorName); - LogAction(param1, random, "[FunModes-HealBeacon] \"%L\" changed Beacon and Neon colors of \"%L\" to \"%s\"", param1, random, colorName); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_ColorChange", param1, random, myColor.name, myColor.name); + LogAction(param1, random, "[FunModes-HealBeacon] \"%L\" changed Beacon and Neon colors of \"%L\" to \"%s\"", param1, random, myColor.name); HealBeacon_DisplayColorsMenu(param1); } } @@ -564,7 +578,7 @@ stock void HealBeacon_DisplayBeaconDistanceMenu(int client) { Menu menu = new Menu(BeaconDistanceMenu_Handler); int random = GetClientOfUserId(g_iClientMenuUserId[client]); - if(!IsValidClient(random)) + if (!random) return; char title[64]; @@ -597,10 +611,10 @@ public int BeaconDistanceMenu_Handler(Menu menu, MenuAction action, int param1, if(param2 == MenuCancel_ExitBack) { int random = GetClientOfUserId(g_iClientMenuUserId[param1]); - if(!IsValidClient(random)) + if (!random) { HealBeacon_DisplayMainMenu(param1); - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "PlayerNotValid", param1); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "PlayerNotValid", param1); return 0; } @@ -610,10 +624,10 @@ public int BeaconDistanceMenu_Handler(Menu menu, MenuAction action, int param1, case MenuAction_Select: { int random = GetClientOfUserId(g_iClientMenuUserId[param1]); - if(!IsValidClient(random)) + if(!random) { HealBeacon_DisplayMainMenu(param1); - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "PlayerNotValid", param1); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "PlayerNotValid", param1); return 0; } @@ -624,7 +638,7 @@ public int BeaconDistanceMenu_Handler(Menu menu, MenuAction action, int param1, g_BeaconPlayersData[random].distance = float(distance); /* TELL THE CLIENT THAT THIS CHANGE IS APPLIED */ - CPrintToChat(param1, "%s %T", HealBeacon_Tag, "HealBeacon_DistanceChange", param1, random, distance); + CPrintToChat(param1, "%s %T", THIS_MODE_INFO.tag, "HealBeacon_DistanceChange", param1, random, distance); LogAction(param1, random, "[FunModes-HealBeacon] \"%L\" changed Beacon Distance of \"%L\" to \"%d\"", param1, random, distance); HealBeacon_DisplayBeaconDistanceMenu(param1); } diff --git a/addons/sourcemod/scripting/Fun_Modes/InvertedControls.sp b/addons/sourcemod/scripting/Fun_Modes/InvertedControls.sp index 1c551f1..a019ee9 100644 --- a/addons/sourcemod/scripting/Fun_Modes/InvertedControls.sp +++ b/addons/sourcemod/scripting/Fun_Modes/InvertedControls.sp @@ -1,9 +1,27 @@ +/* + (). FunModes V2: + + @file InvertedControls.sp + @Usage Functions for the IC mode. +*/ + #pragma semicolon 1 #pragma newdecls required +ModeInfo g_ICInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_ICInfo + +#define IC_CONVAR_TOGGLE 0 + /* CALLED ON PLUGIN START */ -stock void PluginStart_IC() +stock void OnPluginStart_IC() { + THIS_MODE_INFO.name = "IC"; + THIS_MODE_INFO.tag = "{gold}[FunModes-InvertedControls]{lightgreen}"; + + /* Admin Commands */ static const char commands[][] = { "sm_invertedcon", @@ -14,12 +32,78 @@ stock void PluginStart_IC() for(int i = 0; i < sizeof(commands); i++) { - RegAdminCmd(commands[i], Cmd_IC, ADMFLAG_CONVARS, "Enable/Disable Inverted controls"); + RegAdminCmd(commands[i], Cmd_ICToggle, ADMFLAG_CONVARS, "Enable/Disable Inverted controls"); } + + RegAdminCmd("sm_ic_settings", Cmd_ICSettings, ADMFLAG_CONVARS, "Open IC Settings Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, IC_CONVAR_TOGGLE, + "sm_ic_enable", "1", "Enable/Disable Inverted Controls mode.", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = IC_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[IC_CONVAR_TOGGLE].cvar.AddChangeHook(OnICModeToggle); +} + +void OnICModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_IC() {} +stock void OnMapEnd_IC() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); +} + +stock void OnClientPutInServer_IC(int client) +{ + #pragma unused client +} + +stock void OnClientDisconnect_IC(int client) +{ + #pragma unused client +} + +stock void ZR_OnClientInfected_IC(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_IC() {} +stock void Event_RoundEnd_IC() {} +stock void Event_PlayerSpawn_IC(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_IC(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_IC(int client) +{ + #pragma unused client } -Action Cmd_IC(int client, int args) +public Action Cmd_ICToggle(int client, int args) { + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s Inverted Controls is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + ConVar cvar = FindConVar("sv_accelerate"); if(cvar == null) { @@ -29,14 +113,54 @@ Action Cmd_IC(int client, int args) if(cvar.IntValue == -5) { - CPrintToChatAll("%s Inverted Controls is now {olive}Disabled!", IC_TAG); + CPrintToChatAll("%s Inverted Controls is now {olive}Off!", THIS_MODE_INFO.tag); cvar.IntValue = 5; delete cvar; return Plugin_Handled; } - CPrintToChatAll("%s Inverted Controls is now {olive}Enabled!", IC_TAG); + CPrintToChatAll("%s Inverted Controls is now {olive}On!", THIS_MODE_INFO.tag); cvar.IntValue = -5; delete cvar; return Plugin_Handled; +} + +/* IC Settings */ +public Action Cmd_ICSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_ICSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_ICSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/MathGame.sp b/addons/sourcemod/scripting/Fun_Modes/MathGame.sp new file mode 100644 index 0000000..0e2f597 --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/MathGame.sp @@ -0,0 +1,467 @@ +/* + (). FunModes V2: + + @file MathGame.sp + @Usage Functions for the MathGame Mode. + +*/ + +#pragma semicolon 1 +#pragma newdecls required + +ModeInfo g_MathGameInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_MathGameInfo + +#define MATHGAME_CONVAR_TIMER_INTERVAL_EASY 0 +#define MATHGAME_CONVAR_TIMER_INTERVAL_MEDIUM 1 +#define MATHGAME_CONVAR_TIMER_INTERVAL_HARD 2 +#define MATHGAME_CONVAR_EASY_DAMAGE 3 +#define MATHGAME_CONVAR_MEDIUM_DAMAGE 4 +#define MATHGAME_CONVAR_HARD_DAMAGE 5 +#define MATHGAME_CONVAR_INCLUDE_ZOMBIE 6 +#define MATHGAME_CONVAR_MAX_TRIES 7 +#define MATHGAME_CONVAR_TIME_DELAY 8 +#define MATHGAME_CONVAR_TOGGLE 9 + +Handle g_hMathGameTimer; +Handle g_hMathGameTimerRepeat; +Handle g_hMathGameTimerDelay; + +bool g_bMathGameHasQuestion[MAXPLAYERS + 1]; +int g_iMathGameAnswer[MAXPLAYERS + 1]; +int g_iMathGameFailedAnswers[MAXPLAYERS + 1]; +bool g_bMathGameDisableRespawn[MAXPLAYERS + 1]; +char g_sMathGameQuestion[MAXPLAYERS + 1][32]; +int g_iMathGameTime; + +stock void OnPluginStart_MathGame() +{ + THIS_MODE_INFO.name = "MathGame"; + THIS_MODE_INFO.tag = "{gold}[FunModes-MathGame]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_mathgame", Cmd_MathGameToggle, ADMFLAG_CONVARS, "Turn MathGame Mode On/Off"); + RegAdminCmd("sm_mathgame_settings", Cmd_MathGameSettings, ADMFLAG_CONVARS, "Open MathGame Sttings Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_TIMER_INTERVAL_EASY, + "sm_mathgame_easy_time", "15.0", "The time needed to answer easy math questions", + ("20.0,30.0,50.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_TIMER_INTERVAL_MEDIUM, + "sm_mathgame_medium_time", "30.0", "The time needed to answer medium math questions", + ("20.0,30.0,50.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_TIMER_INTERVAL_HARD, + "sm_mathgame_hard_time", "60.0", "The time needed to answer hard math questions", + ("20.0,30.0,50.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_EASY_DAMAGE, + "sm_mathgame_easy_damage", "50.0", "The amount of damage to apply to those who can't answer easy questions", + ("10.0,20.0,25.0,35.0,50.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_MEDIUM_DAMAGE, + "sm_mathgame_medium_damage", "35.0", "The amount of damage to apply to those who can't answer medium questions", + ("10.0,20.0,25.0,35.0,50.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_HARD_DAMAGE, + "sm_mathgame_hard_damage", "20.0", "The amount of damage to apply to those who can't answer hard questions", + ("10.0,20.0,25.0,35.0,50.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_INCLUDE_ZOMBIE, + "sm_mathgame_include_zombies", "0", "Include zombies to the math game (1 = Enabled, 0 = Disabled)", + ("0,1"), "bool" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_MAX_TRIES, + "sm_mathgame_max_tries", "3", "How many failed tries for zombies to answer question until they can never respawn again?", + ("1,2,3,4,5"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_TIME_DELAY, + "sm_mathgame_time_delay", "15.0", "The delayed time after each math question", + ("15.0,20.0,30.0,35.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, MATHGAME_CONVAR_TOGGLE, + "sm_mathgame_enable", "1", "Enable/Disable MathGame Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = MATHGAME_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[MATHGAME_CONVAR_TOGGLE].cvar.AddChangeHook(OnMathGameModeToggle); +} + +void OnMathGameModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_MathGame() {} +stock void OnMapEnd_MathGame() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + g_hMathGameTimer = null; + g_hMathGameTimerRepeat = null; +} + +stock void OnClientPutInServer_MathGame(int client) +{ + g_bMathGameHasQuestion[client] = false; + g_iMathGameFailedAnswers[client] = 0; + g_bMathGameDisableRespawn[client] = false; +} + +stock void OnClientDisconnect_MathGame(int client) +{ + #pragma unused client +} + +stock void ZR_OnClientInfected_MathGame(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_MathGame() +{ + if (!THIS_MODE_INFO.isOn) + return; + + delete g_hMathGameTimer; + delete g_hMathGameTimerRepeat; + delete g_hMathGameTimerDelay; + + MathGame_ResetPlayers(); + CreateTimer(30.0, Timer_StartMathGame, _, TIMER_FLAG_NO_MAPCHANGE); +} + +Action Timer_StartMathGame(Handle timer) +{ + if (!THIS_MODE_INFO.isOn) + return Plugin_Stop; + + MathGame_Ask(); + return Plugin_Stop; +} + +stock void Event_RoundEnd_MathGame() {} +stock void Event_PlayerSpawn_MathGame(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_MathGame(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_MathGame(int client) +{ + #pragma unused client +} + +public Action ZR_OnClientRespawn(int &client, ZR_RespawnCondition &condition) +{ + if (!THIS_MODE_INFO.isOn) + return Plugin_Continue; + + if (condition != ZR_Respawn_Zombie) + return Plugin_Continue; + + if (!g_bMathGameDisableRespawn[client]) + return Plugin_Continue; + + return Plugin_Handled; +} + +public Action Cmd_MathGameToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s MathGame Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s MathGame Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + if (THIS_MODE_INFO.isOn) + { + MathGame_ResetPlayers(); + FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); + FunModes_HookEvent(g_bEvent_RoundEnd, "round_end", Event_RoundEnd); + MathGame_Ask(); + } + else + { + MathGame_ResetPlayers(); + delete g_hMathGameTimer; + delete g_hMathGameTimerRepeat; + delete g_hMathGameTimerDelay; + } + + return Plugin_Handled; +} + +public Action OnClientSayCommand(int client, const char[] command, const char[] args) +{ + if (!THIS_MODE_INFO.isOn) + return Plugin_Continue; + + if (!g_bMathGameHasQuestion[client]) + return Plugin_Continue; + + if (!IsCharNumeric(args[0]) && args[0] != '-' && args[0] != '+') + return Plugin_Continue; + + int num; + if (!StringToIntEx(args, num)) + return Plugin_Continue; + + if (num == g_iMathGameAnswer[client]) + { + CPrintToChat(client, "%s Congratuations, you have answered the math question, nothing bad will hurt you now!", THIS_MODE_INFO.tag); + CPrintToChatAll("%s {olive}%N {lightgreen}turns to be a smart boy and answered their question!", THIS_MODE_INFO.tag, client); + g_bMathGameHasQuestion[client] = false; + g_iMathGameAnswer[client] = 0; + return Plugin_Stop; + } + + return Plugin_Continue; +} + +void MathGame_Ask() +{ + int level = GetRandomInt(0, 2); + + static const char levels[][] = { "Easy", "Medium", "Hard" }; + + int time = THIS_MODE_INFO.cvarInfo[level].cvar.IntValue; + CPrintToChatAll("%s Alright gentlemen, Each player will now receive a math question to answer, You have got only {olive}%d seconds", THIS_MODE_INFO.tag, time); + CPrintToChatAll("%s Question Level: {olive}%s", THIS_MODE_INFO.tag, levels[level]); + + bool includeZombies = THIS_MODE_INFO.cvarInfo[MATHGAME_CONVAR_INCLUDE_ZOMBIE].cvar.BoolValue; + int maxTries = THIS_MODE_INFO.cvarInfo[MATHGAME_CONVAR_MAX_TRIES].cvar.IntValue; + + if (includeZombies) + CPrintToChatAll("%s Zombies will have {olive}%d maximum tries {lightgreen}to survive or they will be stuck on spec!", THIS_MODE_INFO.tag, maxTries); + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i) || !IsPlayerAlive(i)) + continue; + + if (ZR_IsClientHuman(i) || (includeZombies && ZR_IsClientZombie(i))) + MathGame_SendQuestion(i, level); + } + + delete g_hMathGameTimer; + g_hMathGameTimer = CreateTimer(float(time), MathGame_Timer, level, TIMER_FLAG_NO_MAPCHANGE); + + g_iMathGameTime = 0; + + delete g_hMathGameTimerRepeat; + g_hMathGameTimerRepeat = CreateTimer(1.0, MathGame_TimerRepeat, time, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); +} + +void MathGame_SendQuestion(int client, int level) +{ + g_bMathGameHasQuestion[client] = true; + + char oper[2]; + int numbers[2]; + + int min, max; + + if (level == 0 || level == 1) + { + min = 1; + max = (level == 0) ? 99 : 299; + oper = (GetRandomInt(0,1) == 0)?"+":"-"; + + numbers[0] = GetRandomInt(min, max); + numbers[1] = GetRandomInt(min, max); + } + else + { + numbers[0] = GetRandomInt(11, 44); + numbers[1] = GetRandomInt(0, 9); + oper = "*"; + } + + int answer; + switch (oper[0]) + { + case '+': answer = numbers[0] + numbers[1]; + case '-': answer = numbers[0] - numbers[1]; + default: answer = numbers[0] * numbers[1]; + } + + g_iMathGameAnswer[client] = answer; + FormatEx(g_sMathGameQuestion[client], sizeof(g_sMathGameQuestion[]), "%d %s %d", numbers[0], oper, numbers[1]); + + CPrintToChat(client, "%s What is [ {white}%d {olive}%s {white}%d {lightgreen}]?", THIS_MODE_INFO.tag, numbers[0], oper, numbers[1]); +} + +Action MathGame_Timer(Handle timer, int level) +{ + g_hMathGameTimer = null; + + if (!THIS_MODE_INFO.isOn) + { + delete g_hMathGameTimerRepeat; + return Plugin_Stop; + } + + delete g_hMathGameTimerRepeat; + + CPrintToChatAll("%s Time is Up! Players who failed to answer will now be punished!", THIS_MODE_INFO.tag); + + float damage = THIS_MODE_INFO.cvarInfo[level + 3].cvar.FloatValue; + bool includeZombies = THIS_MODE_INFO.cvarInfo[MATHGAME_CONVAR_INCLUDE_ZOMBIE].cvar.BoolValue; + int maxTries = THIS_MODE_INFO.cvarInfo[MATHGAME_CONVAR_MAX_TRIES].cvar.IntValue; + + for (int i = 1; i <= MaxClients; i++) + { + if (g_bMathGameHasQuestion[i]) + { + if (ZR_IsClientHuman(i)) + { + CPrintToChatAll("%s {olive}%N {lightgreen}has been damaged for not answering their math question!", THIS_MODE_INFO.tag, i); + SDKHooks_TakeDamage(i, 0, 0, damage); + } + else + { + if (!includeZombies) + continue; + + g_iMathGameFailedAnswers[i]++; + if (g_iMathGameFailedAnswers[i] >= maxTries) + { + ForcePlayerSuicide(i); + CPrintToChat(i, "%s You will not be able to respawn for failing to answer math questions {olive}%d in a row", THIS_MODE_INFO.tag, maxTries); + g_bMathGameDisableRespawn[i] = true; + g_iMathGameFailedAnswers[i] = 0; + } + } + } + } + + MathGame_ResetPlayers(); + + delete g_hMathGameTimerDelay; + g_hMathGameTimerDelay = CreateTimer(THIS_MODE_INFO.cvarInfo[MATHGAME_CONVAR_TIME_DELAY].cvar.FloatValue, MathGame_TimerDelay, _, TIMER_FLAG_NO_MAPCHANGE); + return Plugin_Stop; +} + +Action MathGame_TimerDelay(Handle timer) +{ + g_hMathGameTimerDelay = null; + + if (!THIS_MODE_INFO.isOn) + return Plugin_Stop; + + MathGame_Ask(); + return Plugin_Continue; +} + +Action MathGame_TimerRepeat(Handle timer, int time) +{ + char message[128]; + FormatEx(message, sizeof(message), "[MathGame] Time Left: %ds\n", time - g_iMathGameTime - 2); + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || IsFakeClient(i)) + continue; + + char thisMsg[256]; + strcopy(thisMsg, sizeof(thisMsg), message); + + if (g_bMathGameHasQuestion[i]) + FormatEx(thisMsg, sizeof(thisMsg), "%s\n[ %s ]", thisMsg, g_sMathGameQuestion[i]); + + SendHudText(i, thisMsg); + } + + g_iMathGameTime++; + return Plugin_Continue; +} + +/* MathGame Settings */ +public Action Cmd_MathGameSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_MathGameSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_MathGameSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; +} + +void MathGame_ResetPlayers() +{ + for (int i = 1; i <= MaxClients; i++) + { + g_bMathGameHasQuestion[i] = false; + g_iMathGameAnswer[i] = 0; + g_iMathGameFailedAnswers[i] = 0; + g_bMathGameDisableRespawn[i] = false; + } +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/PullGame.sp b/addons/sourcemod/scripting/Fun_Modes/PullGame.sp new file mode 100644 index 0000000..427239c --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/PullGame.sp @@ -0,0 +1,477 @@ +/* + (). FunModes V2: + + @file PullGame.sp + @Usage Functions for the PullGame Mode. + +*/ + +#pragma semicolon 1 +#pragma newdecls required + +ModeInfo g_PullGameInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_PullGameInfo + +#define PULLGAME_CONVAR_TIMER_INTERVAL 0 +#define PULLGAME_CONVAR_SPEED 1 +#define PULLGAME_CONVAR_PULL_TIME 2 +#define PULLGAME_CONVAR_RANDOMS_ZOMBIES 3 +#define PULLGAME_CONVAR_RANDOMS_HUMANS 4 +#define PULLGAME_CONVAR_TOGGLE 5 + +float g_fPullLastUseTime[MAXPLAYERS + 1]; +bool g_bPullState[MAXPLAYERS + 1]; +float g_fPullOriginalSpeed[MAXPLAYERS + 1]; +float g_fPullOriginalDistance[MAXPLAYERS + 1]; +int g_iPullClientTarget[MAXPLAYERS + 1]; +bool g_bPullGameHas[MAXPLAYERS + 1]; + +float g_fPullGameSpeed; + +Handle g_hPullGameTimer; + +stock void OnPluginStart_PullGame() +{ + THIS_MODE_INFO.name = "PullGame"; + THIS_MODE_INFO.tag = "{gold}[FunModes-PullGame]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_pullgame", Cmd_PullGameToggle, ADMFLAG_CONVARS, "Turn PullGame Mode On/Off"); + RegAdminCmd("sm_pullgame_settings", Cmd_PullGameSettings, ADMFLAG_CONVARS, "Open PullGame Sttings Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, PULLGAME_CONVAR_TIMER_INTERVAL, + "sm_pullgame_timer_interval", "30.0", "After how many seconds to keep giving pull access to a random zm?", + ("15.0,30.0,40.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, PULLGAME_CONVAR_SPEED, + "sm_pullgame_speed", "300.0", "Pulling Speed Value", + ("100.0,300.0,500.0,700.0,1000.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, PULLGAME_CONVAR_PULL_TIME, + "sm_pullgame_pull_time", "15.0", "Pulling Time", + ("10.0,15.0,30.0,40.0,55.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, PULLGAME_CONVAR_RANDOMS_HUMANS, + "sm_pullgame_humans_count", "3", "Pulling Time", + ("1,2,3,4,5,6,7"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, PULLGAME_CONVAR_RANDOMS_ZOMBIES, + "sm_pullgame_zombies_count", "3", "Pulling Time", + ("1,2,3,4,5,6,7"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, PULLGAME_CONVAR_TOGGLE, + "sm_pullgame_enable", "1", "Enable/Disable PullGame Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = PULLGAME_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_TOGGLE].cvar.AddChangeHook(OnPullGameModeToggle); + + g_fPullGameSpeed = THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_SPEED].cvar.FloatValue; + THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_SPEED].cvar.AddChangeHook(OnPullGameSpeedChange); +} + +void OnPullGameModeToggle(ConVar cvar, const char[] oldValue, const char[] newValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +void OnPullGameSpeedChange(ConVar cvar, const char[] oldValue, const char[] newValue) +{ + g_fPullGameSpeed = cvar.FloatValue; +} + +stock void OnMapStart_PullGame() {} +stock void OnMapEnd_PullGame() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); +} + +stock void OnClientPutInServer_PullGame(int client) +{ + PullGame_ResetVariablesClient(client); +} + +stock void OnClientDisconnect_PullGame(int client) +{ + for (int i = 1; i <= MaxClients; i++) + { + if (g_iPullClientTarget[i] == client) + g_iPullClientTarget[i] = -1; + } + + PullGame_ResetVariablesClient(client); +} + +stock void ZR_OnClientInfected_PullGame(int client) +{ + #pragma unused client + + if (!THIS_MODE_INFO.isOn) + return; + + if (!g_bMotherZombie) + PullGame_ToggleTimer(true); +} + +stock void Event_RoundStart_PullGame() +{ + PullGame_ResetVariables(); +} + +stock void Event_RoundEnd_PullGame() {} +stock void Event_PlayerSpawn_PullGame(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_PullGame(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_PullGame(int client) +{ + #pragma unused client +} + +public Action Cmd_PullGameToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s PullGame Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s PullGame Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + if (THIS_MODE_INFO.isOn) + { + FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); + FunModes_HookEvent(g_bEvent_RoundEnd, "round_end", Event_RoundEnd); + + CPrintToChatAll("%s Press (F) {olive} | Flashlight {lightgreen}to use pull, only when you get selected!", THIS_MODE_INFO.tag); + + int humansCount = THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_RANDOMS_HUMANS].cvar.IntValue; + int zombiesCount = THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_RANDOMS_ZOMBIES].cvar.IntValue; + int interval = THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_TIMER_INTERVAL].cvar.IntValue; + + CPrintToChatAll("%s {olive}%d Random Humans {lightgreen}and {olive}%d Random Zombies {lightgreen}will be selected for the pullgame every %d seconds", THIS_MODE_INFO.tag, humansCount, zombiesCount, interval); + + CS_TerminateRound(3.0, CSRoundEnd_Draw); + } + else + PullGame_ToggleTimer(false); + + return Plugin_Handled; +} + +/* PullGame Settings */ +public Action Cmd_PullGameSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_PullGameSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_PullGameSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; +} + +void PullGame_ResetVariablesClient(int client) +{ + g_bPullGameHas[client] = false; + g_bPullState[client] = false; + g_fPullOriginalSpeed[client] = 0.0; + g_fPullOriginalDistance[client] = 0.0; + g_iPullClientTarget[client] = -1; + g_fPullLastUseTime[client] = 0.0; +} + +void PullGame_ResetVariables() +{ + for (int i = 1; i <= MaxClients; i++) + PullGame_ResetVariablesClient(i); +} + +void PullGame_ToggleTimer(bool toggle) +{ + PullGame_ResetVariables(); + + delete g_hPullGameTimer; + + if (toggle) + g_hPullGameTimer = CreateTimer(THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_TIMER_INTERVAL].cvar.FloatValue, Timer_PullGame, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); +} + +Action Timer_PullGame(Handle timer) +{ + if (g_bRoundEnd || !g_bMotherZombie) + { + g_hPullGameTimer = null; + return Plugin_Stop; + } + + int humansMaxCount = THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_RANDOMS_HUMANS].cvar.IntValue; + int zombiesMaxCount = THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_RANDOMS_ZOMBIES].cvar.IntValue; + + int zombies[MAXPLAYERS + 1]; + int humans[MAXPLAYERS + 1]; + + int zombiesCount, humansCount; + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || !IsPlayerAlive(i)) + continue; + + if (ZR_IsClientZombie(i)) + zombies[zombiesCount++] = i; + else + humans[humansCount++] = i; + } + + if (zombiesCount) + PullGame_PickTeamRandoms(zombies, zombiesCount, 0, zombiesMaxCount); + + if (humansCount) + PullGame_PickTeamRandoms(humans, humansCount, 0, humansMaxCount); + + return Plugin_Continue; +} + +void PullGame_PickTeamRandoms(int[] arr, int len, int min, int max) +{ + for (int i = 0; i < len; i++) + { + if (len == max) + g_bPullGameHas[arr[i]] = true; + else + { + if (++min > max) + break; + + int random; + int index = PullGame_GetRandomFromArray(arr, len, random); + if (index == -1) + continue; + + arr[index] = 0; + g_bPullGameHas[random] = true; + + CPrintToChat(random, "%s You have been selected to use pull! Press FlashLight button (F) Now!", THIS_MODE_INFO.tag); + SendHudText(random, "[FunModes-PullGame] You have been selected to use pull! Press FlashLight button (F) Now!"); + } + } +} + +int PullGame_GetRandomFromArray(int[] arr, int len, int &client) +{ + int count; + int[] newArr = new int[len]; + + for (int i = 0; i < len; i++) + { + if (arr[i] == 0) + continue; + + if (g_bPullGameHas[arr[i]]) + continue; + + newArr[count++] = arr[i]; + } + + if (!count) + return -1; + + int index = GetRandomInt(0, count - 1); + client = newArr[index]; + return index; +} + +stock void OnPlayerRunCmdPost_PullGame(int client, int buttons, int impulse) +{ + #pragma unused buttons + if (!THIS_MODE_INFO.isOn) + return; + + float time = GetGameTime(); + if (g_fPullLastUseTime[client] > time) + return; + + if (impulse == 100) + { + Cmd_Pull(client); + g_fPullLastUseTime[client] = GetGameTime() + 2.0; + } +} + +void Cmd_Pull(int client) +{ + if (!g_bPullGameHas[client]) + { + CPrintToChat(client, "%s You cannot use this command unless you were randomly chosen for it!", THIS_MODE_INFO.tag); + return; + } + + if (!IsPlayerAlive(client)) + { + CPrintToChat(client, "%s You have to be alive to use this command.", THIS_MODE_INFO.tag); + return; + } + + if (g_iPullClientTarget[client] != -1) + { + CPrintToChat(client, "%s You cannot use this command more than once while you are activating it.", THIS_MODE_INFO.tag); + return; + } + + int target = GetClientAimTarget(client); + if (target == -1) + { + CPrintToChat(client, "%s You have to aim at a player!", THIS_MODE_INFO.tag); + return; + } + + bool isClientHuman = ZR_IsClientHuman(client); + bool isTargetHuman = ZR_IsClientHuman(target); + + if (isClientHuman) + { + if (!isTargetHuman) + { + CPrintToChat(client, "%s You cannot target a zombie!", THIS_MODE_INFO.tag); + return; + } + + if (!g_bPullState[target]) + { + CPrintToChat(client, "%s You cannot pull a human that's not being pulled from the zombies!", THIS_MODE_INFO.tag); + return; + } + } + + PullGame_StartGrab(client, target); +} + +void PullGame_StartGrab(int client, int target) +{ + g_iPullClientTarget[client] = target; + + if (!g_bPullState[target]) + { + g_bPullState[target] = true; + g_fPullOriginalSpeed[target] = GetEntPropFloat(target, Prop_Send, "m_flMaxspeed"); + SetEntPropFloat(target, Prop_Send, "m_flMaxspeed", 0.01); + } + + CreateTimer(THIS_MODE_INFO.cvarInfo[PULLGAME_CONVAR_PULL_TIME].cvar.FloatValue, Timer_PullGameFinish, client, TIMER_FLAG_NO_MAPCHANGE); + CreateTimer(0.05, PullGame_Pull_Timer, client, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); +} + +Action Timer_PullGameFinish(Handle timer, int client) +{ + int target = g_iPullClientTarget[client]; + if (target == -1) + return Plugin_Stop; + + bool reset = true; + for (int i = 1; i <= MaxClients; i++) + { + if (i == client || !IsClientInGame(i) || !IsPlayerAlive(i) || !ZR_IsClientHuman(i)) + continue; + + if (g_iPullClientTarget[i] == target) + { + reset = false; + break; + } + } + + if (reset) + { + SetEntPropFloat(target, Prop_Send, "m_flMaxspeed", g_fPullOriginalSpeed[target]); + g_bPullState[target] = false; + } + + g_iPullClientTarget[client] = -1; + g_bPullGameHas[client] = false; + return Plugin_Stop; +} + +Action PullGame_Pull_Timer(Handle timer, int client) +{ + int target = g_iPullClientTarget[client]; + if (target == -1 || !IsPlayerAlive(target) || !IsPlayerAlive(client)) + return Plugin_Stop; + + float clientEyePos[3], targetEyePos[3]; + GetClientEyePosition(client, clientEyePos); + GetClientEyePosition(target, targetEyePos); + + float distance = GetVectorDistance(clientEyePos, targetEyePos, true); + if (distance > 40000.0) + { + float velocity[3]; + SubtractVectors(clientEyePos, targetEyePos, velocity); + NormalizeVector(velocity, velocity); + ScaleVector(velocity, g_fPullGameSpeed); + TeleportEntity(target, _, _, velocity); + } + + TE_SetupBeamPoints(clientEyePos, targetEyePos, g_iLaserBeam, 0, 0, 66, 0.2, 1.0, 10.0, 0, 0.0, {255,255,255,255}, 0); + TE_SendToAll(); + + return Plugin_Continue; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/RealityShift.sp b/addons/sourcemod/scripting/Fun_Modes/RealityShift.sp new file mode 100644 index 0000000..f374abf --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/RealityShift.sp @@ -0,0 +1,351 @@ +/* + (). FunModes V2: + + @file RealityShift.sp + @Usage Functions for the RealityShift Mode. + +*/ + +#pragma semicolon 1 +#pragma newdecls required + +ModeInfo g_RealityShiftInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_RealityShiftInfo + +#define REALITYSHIFT_CONVAR_TIMER_INTERVAL 0 +#define REALITYSHIFT_CONVAR_MODE 1 +#define REALITYSHIFT_CONVAR_TOGGLE 2 + +Handle g_hRealityShiftTimer; + +int g_iRealityShiftAssigned[MAXPLAYERS + 1]; +bool g_bRealityShiftSwapped[MAXPLAYERS + 1]; + +stock void OnPluginStart_RealityShift() +{ + THIS_MODE_INFO.name = "RealityShift"; + THIS_MODE_INFO.tag = "{gold}[FunModes-RealityShift]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_rs", Cmd_RealityShiftToggle, ADMFLAG_CONVARS, "Turn RealityShift Mode On/Off"); + RegAdminCmd("sm_realityshift_settings", Cmd_RealityShiftSettings, ADMFLAG_CONVARS, "Open RealityShift Sttings Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, REALITYSHIFT_CONVAR_TIMER_INTERVAL, + "sm_realityshift_timer_interval", "30.0", "After how many seconds to keep swapping positions", + ("15.0,30.0,45.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, REALITYSHIFT_CONVAR_MODE, + "sm_realityshift_mode", "0", ("RealityShift Mode [0 = Random Swaps, 1 = Assigned Swaps [At round start]]"), + ("0,1"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, REALITYSHIFT_CONVAR_TOGGLE, + "sm_realityshift_enable", "1", "Enable/Disable RealityShift Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = REALITYSHIFT_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_TOGGLE].cvar.AddChangeHook(OnRealityShiftModeToggle); + + THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_TIMER_INTERVAL].cvar.AddChangeHook(OnRealityShiftConVarChange); + THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_MODE].cvar.AddChangeHook(OnRealityShiftConVarChange); +} + +void OnRealityShiftModeToggle(ConVar cvar, const char[] oldValue, const char[] newValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +void OnRealityShiftConVarChange(ConVar cvar, const char[] oldValue, const char[] newValue) +{ + if (!THIS_MODE_INFO.isOn) + return; + + if (cvar == THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_TIMER_INTERVAL].cvar) + { + RealityShift_StartTimer(cvar.FloatValue); + return; + } + + if (cvar.IntValue == 1) + RealityShift_AssignPlayers(true); +} + +stock void OnMapStart_RealityShift() {} +stock void OnMapEnd_RealityShift() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + g_hRealityShiftTimer = null; +} + +stock void OnClientPutInServer_RealityShift(int client) +{ + g_iRealityShiftAssigned[client] = 0; + g_bRealityShiftSwapped[client] = false; +} + +stock void OnClientDisconnect_RealityShift(int client) +{ + g_iRealityShiftAssigned[client] = 0; + g_bRealityShiftSwapped[client] = false; +} + +stock void ZR_OnClientInfected_RealityShift(int client) +{ + #pragma unused client + if (!THIS_MODE_INFO.isOn) + return; + + if (!g_bMotherZombie && g_hRealityShiftTimer == null) + { + RealityShift_StartTimer(THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_TIMER_INTERVAL].cvar.FloatValue); + if (THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_MODE].cvar.IntValue == 1) + RealityShift_AssignPlayers(true); + } +} + +stock void Event_RoundStart_RealityShift() {} +stock void Event_RoundEnd_RealityShift() {} +stock void Event_PlayerSpawn_RealityShift(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_RealityShift(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_RealityShift(int client) +{ + #pragma unused client +} + +public Action Cmd_RealityShiftToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s RealityShift Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s RealityShift Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + if (THIS_MODE_INFO.isOn) + { + FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); + FunModes_HookEvent(g_bEvent_RoundEnd, "round_end", Event_RoundEnd); + + CPrintToChatAll("%s Each human will be swappaed their position with another one!", THIS_MODE_INFO.tag); + + int mode = THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_MODE].cvar.IntValue; + if (mode == 0) + CPrintToChatAll("%s The positions will be swapped randomly.", THIS_MODE_INFO.tag); + + int interval = THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_TIMER_INTERVAL].cvar.IntValue; + CPrintToChatAll("%s Positions will be swapped every {olive}%d seconds!", THIS_MODE_INFO.tag, interval); + + CS_TerminateRound(3.0, CSRoundEnd_Draw); + } + else + delete g_hRealityShiftTimer; + + return Plugin_Handled; +} + +/* RealityShift Settings */ +public Action Cmd_RealityShiftSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_RealityShiftSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_RealityShiftSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; +} + +void RealityShift_StartTimer(float interval) +{ + for (int i = 1; i <= MaxClients; i++) + g_iRealityShiftAssigned[i] = 0; + + delete g_hRealityShiftTimer; + g_hRealityShiftTimer = CreateTimer(interval, RealityShift_Timer, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); +} + +Action RealityShift_Timer(Handle timer) +{ + if (g_bRoundEnd || !g_bMotherZombie) + { + g_hRealityShiftTimer = null; + return Plugin_Stop; + } + + int mode = THIS_MODE_INFO.cvarInfo[REALITYSHIFT_CONVAR_MODE].cvar.IntValue; + RealityShift_AssignPlayers(_, mode == 0); + + return Plugin_Continue; +} + +int GetRandomClientFromArray(int[] arr, int len, int &client) +{ + int count; + int[] newArr = new int[len]; + + for (int i = 0; i < len; i++) + { + if (arr[i] == 0) + continue; + + if (g_bRealityShiftSwapped[arr[i]]) + continue; + + newArr[count++] = arr[i]; + } + + if (!count) + return -1; + + int index = GetRandomInt(0, count - 1); + client = newArr[index]; + return index; +} + +void RealityShift_AssignPlayers(bool saveOnly = false, bool random = true) +{ + int clients[MAXPLAYERS + 1], count; + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || !IsPlayerAlive(i) || !ZR_IsClientHuman(i)) + continue; + + g_bRealityShiftSwapped[i] = false; + clients[count++] = i; + + if (!random) + { + int assignedTo = GetClientOfUserId(g_iRealityShiftAssigned[i]); + if (!assignedTo || !IsClientInGame(assignedTo) || !IsPlayerAlive(assignedTo) || !ZR_IsClientHuman(assignedTo)) + { + g_bRealityShiftSwapped[i] = false; + g_iRealityShiftAssigned[i] = 0; + continue; + } + + RealityShift_SwapPositions(i, assignedTo); + } + } + + if (!saveOnly && !random) + return; + + int assignmentsCount = count / 2; + if (assignmentsCount <= 1) + return; + + for (int i = 0; i < assignmentsCount; i++) + { + int client, assignedTo; + + int index = GetRandomClientFromArray(clients, count, client); + if (index == -1) + continue; + + clients[index] = 0; + + index = GetRandomClientFromArray(clients, count, assignedTo); + if (index == -1) + continue; + + clients[index] = 0; + + if (saveOnly) + { + g_iRealityShiftAssigned[client] = GetClientUserId(assignedTo); + g_iRealityShiftAssigned[assignedTo] = GetClientUserId(client); + CPrintToChat(client, "%s You will be swapping positions with {olive}%N {lightgreen}the whole round!", THIS_MODE_INFO.tag, assignedTo); + CPrintToChat(assignedTo, "%s You will be swapping positions with {olive}%N {lightgreen}the whole round!", THIS_MODE_INFO.tag, client); + } + else + { + if (!random) + continue; + + if (g_bRealityShiftSwapped[client] || g_bRealityShiftSwapped[assignedTo]) + continue; + + RealityShift_SwapPositions(client, assignedTo); + } + } +} + +void RealityShift_SwapPositions(int client, int assignedTo) +{ + if (client == assignedTo) + return; + + if (g_bRealityShiftSwapped[client] || g_bRealityShiftSwapped[assignedTo]) + return; + + float clientOrigin[3], assignedToOrigin[3], clientEyeAngles[3], assignedToEyeAngles[3]; + GetClientAbsOrigin(client, clientOrigin); + GetClientAbsOrigin(assignedTo, assignedToOrigin); + GetClientEyeAngles(client, clientEyeAngles); + GetClientEyeAngles(assignedTo, assignedToEyeAngles); + + TeleportEntity(client, assignedToOrigin, assignedToEyeAngles); + TeleportEntity(assignedTo, clientOrigin, clientEyeAngles); + + CPrintToChat(client, "%s You have swapped positions with {olive}%N", THIS_MODE_INFO.tag, assignedTo); + CPrintToChat(assignedTo, "%s You have swapped position with {olive}%N", THIS_MODE_INFO.tag, client); + + g_bRealityShiftSwapped[client] = true; + g_bRealityShiftSwapped[assignedTo] = true; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/RedLightGreenLight.sp b/addons/sourcemod/scripting/Fun_Modes/RedLightGreenLight.sp index 9ad44d5..33d645d 100644 --- a/addons/sourcemod/scripting/Fun_Modes/RedLightGreenLight.sp +++ b/addons/sourcemod/scripting/Fun_Modes/RedLightGreenLight.sp @@ -1,65 +1,115 @@ #pragma semicolon 1 #pragma newdecls required -#define FFADE_IN (0x0001) // Fade in -#define FFADE_OUT (0x0002) // Fade out -#define FFADE_MODULATE (0x0004) // Modulate (Don't blend) -#define FFADE_STAYOUT (0x0008) // Ignores the duration, stays faded out until a new fade message is received -#define FFADE_PURGE (0x0010) // Purges all other fades, replacing them with this one +ModeInfo g_RLGLInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_RLGLInfo + +bool g_bEnableDetecting; char countDownPath[PLATFORM_MAX_PATH]; float g_fOriginalSpeed[MAXPLAYERS + 1]; -ConVarInfo g_cvInfoRLGL[7] = -{ - {null, "0.1,0.3,0.5,0.8", "float"}, - {null, "2.0,5.0,10.0,15.0", "float"}, - {null, "20.0,30.0,40.0,60.0", "float"}, - {null, "25.0,35.0,55.0,65.0", "float"}, - {null, "1.0,2.0,3.0,4.0,5.0", "float"}, - {null, "3.0,5.0,8.0,10.0", "float"}, - {null, "0.0,0.2,0.5,1.2,1.5,2.0", "float"} -}; +/* Timers */ +Handle g_hRLGLTimer; +Handle g_hRLGLDetectTimer; +Handle g_hRLGLWarningTimer; + +#define RLGL_CONVAR_TIME_BETWEEN_DAMAGE 0 +#define RLGL_CONVAR_FREEZE_TIME 1 +#define RLGL_CONVAR_TIME_BETWEEN_REDLIGHTS_MIN 2 +#define RLGL_CONVAR_TIME_BETWEEN_REDLIGHTS_MAX 3 +#define RLGL_CONVAR_DAMAGE 4 +#define RLGL_CONVAR_WARNING_TIME 5 +#define RLGL_CONVAR_ZOMBIES_SPEED 6 +#define RLGL_CONVAR_COUNTDOWN_FOLDER 7 +#define RLGL_CONVAR_TOGGLE 8 /* CALLED on Plugin Start */ -stock void PluginStart_RLGL() +stock void OnPluginStart_RLGL() { + THIS_MODE_INFO.name = "RLGL"; + THIS_MODE_INFO.tag = "{gold}[FunModes-RedLightGreenLight]{lightgreen}"; + /* ADMIN COMMANDS */ - RegAdminCmd("sm_fm_rlgl", Cmd_RLGL, ADMFLAG_CONVARS, "Enable/Disable RedLightGreenLight mode."); - - /* CONVARS HANDLES */ - g_cvRLGLDetectTimer = CreateConVar("sm_rlgl_time_between_damage", "0.1", "The timer interval for player to detect their movement"); - g_cvRLGLFinishDetectTime = CreateConVar("sm_rlgl_freeze_time", "5", "How many seconds the movement detection should be disabled after"); - g_cvRLGLDetectTimerRepeatMin = CreateConVar("sm_rlgl_time_between_redlights_min", "20.0", "After how many seconds to keep repeating the redlights (MIN VALUE)"); - g_cvRLGLDetectTimerRepeatMax = CreateConVar("sm_rlgl_time_between_redlights_max", "30.0", "After how many seconds to keep repeating the redlights (MAX VALUE, SET TO 0 to disable min/max)"); - g_cvRLGLDamage = CreateConVar("sm_rlgl_damage", "5.0", "Damage to apply to the player that is moving while its a red light"); - g_cvRLGLWarningTime = CreateConVar("sm_rlgl_warning_time", "8", "Time in seconds to warn the players before red light is on"); - g_cvRLGLZombiesSpeed = CreateConVar("sm_rlgl_zombies_speed", "0.5", "Zombies speed during red light, if set to 0 then it is disabled"); - g_cvCountdownFolder = CreateConVar("sm_rlgl_countdown_folder", "zr/countdown/$.mp3", "Countdown folder and the files that can be used for sound"); + RegAdminCmd("sm_fm_rlgl", Cmd_RLGLToggle, ADMFLAG_CONVARS, "Enable/Disable RedLightGreenLight mode."); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_TIME_BETWEEN_DAMAGE, + "sm_rlgl_time_between_damage", "0.1", "The timer interval for player to detect their movement", + ("0.1,0.3,0.5,0.8"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_FREEZE_TIME, + "sm_rlgl_freeze_time", "5.0", "How many seconds the movement detection should be disabled after", + ("2.0,5.0,10.0,15.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_TIME_BETWEEN_REDLIGHTS_MIN, + "sm_rlgl_time_between_redlights_min", "20.0", "After how many seconds to keep repeating the redlights (MIN VALUE)", + ("20.0,30.0,40.0,60.0"), "float" + ); - RLGL_SetCvarsInfo(); + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_TIME_BETWEEN_REDLIGHTS_MAX, + "sm_rlgl_time_between_redlights_max", "30.0", "After how many seconds to keep repeating the redlights (MAX VALUE, SET TO 0 to disable min/max)", + ("25.0,35.0,45.0,65.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_DAMAGE, + "sm_rlgl_damage", "5.0", "Damage to apply to the player that is moving while its a red light", + ("1.0,2.0,3.0,4.0,5.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_WARNING_TIME, + "sm_rlgl_warning_time", "8.0", "Time in seconds to warn the players before red light is on", + ("5.0,8.0,10.0,15.0,20.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_ZOMBIES_SPEED, + "sm_rlgl_zombies_speed", "0.5", ("Zombies speed during red light, if set to 0 then it is disabled"), + ("0.0,0.2,0.5,0.8,1.5,2.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_COUNTDOWN_FOLDER, + "sm_rlgl_countdown_folder", "zr/countdown/$.mp3", "Countdown folder and the files that can be used for sound", + "", "" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, RLGL_CONVAR_TOGGLE, + "sm_rlgl_enable", "1", "Enable/Disable the RLGL Mode (This differes from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = RLGL_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_TOGGLE].cvar.AddChangeHook(OnRLGLModeToggle); } -void RLGL_SetCvarsInfo() +void OnRLGLModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) { - ConVar cvars[sizeof(g_cvInfoRLGL)]; - cvars[0] = g_cvRLGLDetectTimer; - cvars[1] = g_cvRLGLFinishDetectTime; - cvars[2] = g_cvRLGLDetectTimerRepeatMin; - cvars[3] = g_cvRLGLDetectTimerRepeatMax; - cvars[4] = g_cvRLGLDamage; - cvars[5] = g_cvRLGLWarningTime; - cvars[6] = g_cvRLGLZombiesSpeed; - - for (int i = 0; i < sizeof(g_cvInfoRLGL); i++) - g_cvInfoRLGL[i].cvar = cvars[i]; + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); } -stock void MapStart_RLGL() { - g_cvCountdownFolder.GetString(countDownPath, sizeof(countDownPath)); +stock void OnMapStart_RLGL() +{ + THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_COUNTDOWN_FOLDER].cvar.GetString(countDownPath, sizeof(countDownPath)); - for (int i = 1; i <= g_cvRLGLWarningTime.IntValue; i++) + for (int i = 1; i <= THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_WARNING_TIME].cvar.IntValue; i++) { char sndPath[PLATFORM_MAX_PATH]; strcopy(sndPath, sizeof(sndPath), countDownPath); @@ -74,19 +124,31 @@ stock void MapStart_RLGL() { } } -stock void RoundStart_RLGL() +stock void OnMapEnd_RLGL() { - delete g_hRLGLWarningTime; - delete g_hRLGLTimer; - delete g_hRLGLDetectTimer; - - if (g_bIsRLGLEnabled) - StartRLGLTimer(); + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + g_hRLGLTimer = null; + g_hRLGLDetectTimer = null; + g_hRLGLWarningTimer = null; +} + +stock void OnClientPutInServer_RLGL(int client) +{ + #pragma unused client } -stock void RLGL_OnClientInfected(int client) +stock void OnClientDisconnect_RLGL(int client) { - float speed = g_cvRLGLZombiesSpeed.FloatValue; + g_fOriginalSpeed[client] = 0.0; +} + +stock void ZR_OnClientInfected_RLGL(int client) +{ + if (!(THIS_MODE_INFO.isOn && g_bEnableDetecting)) + return; + + float speed = THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_ZOMBIES_SPEED].cvar.FloatValue; if (speed <= 0.0) return; @@ -94,9 +156,30 @@ stock void RLGL_OnClientInfected(int client) SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", speed); } -stock void ClientDisconnect_RLGL(int client) +stock void Event_RoundStart_RLGL() { - g_fOriginalSpeed[client] = 0.0; + delete g_hRLGLWarningTimer; + delete g_hRLGLTimer; + delete g_hRLGLDetectTimer; + + if (THIS_MODE_INFO.isOn) + StartRLGLTimer(); +} + +stock void Event_RoundEnd_RLGL() {} +stock void Event_PlayerSpawn_RLGL(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_RLGL(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_RLGL(int client) +{ + #pragma unused client } void ApplyFade(const char[] sColor) @@ -157,15 +240,21 @@ void ApplyFade(const char[] sColor) EndMessage(); } -Action Cmd_RLGL(int client, int args) +public Action Cmd_RLGLToggle(int client, int args) { - g_bIsRLGLEnabled = !g_bIsRLGLEnabled; - CPrintToChatAll("%s Red Light Green Light is now {olive}%s{lightgreen}.", RLGL_Tag, (g_bIsRLGLEnabled) ? "Enabled" : "Disabled"); + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s RLGL mode is currently disabled!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + CPrintToChatAll("%s Red Light Green Light is now {olive}%s{lightgreen}.", THIS_MODE_INFO.tag, (THIS_MODE_INFO.isOn) ? "Enabled" : "Disabled"); delete g_hRLGLTimer; delete g_hRLGLDetectTimer; - if (g_bIsRLGLEnabled) + if (THIS_MODE_INFO.isOn) { FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); StartRLGLTimer(); @@ -176,10 +265,13 @@ Action Cmd_RLGL(int client, int args) Action RLGL_Timer(Handle timer) { - if (!g_bIsRLGLEnabled) + g_hRLGLTimer = null; + + if (!THIS_MODE_INFO.isOn) return Plugin_Stop; - g_hRLGLWarningTime = CreateTimer(1.0, RLGL_Warning_Timer, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); + delete g_hRLGLWarningTimer; + g_hRLGLWarningTimer = CreateTimer(1.0, RLGL_Warning_Timer, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); StartRLGLTimer(); @@ -188,12 +280,20 @@ Action RLGL_Timer(Handle timer) Action RLGL_Warning_Timer(Handle timer) { + if (!THIS_MODE_INFO.isOn) + { + g_hRLGLWarningTimer = null; + return Plugin_Stop; + } + static int timePassed; char sMessage[256]; - FormatEx(sMessage, sizeof(sMessage), "Warning: Red Light is coming in %d seconds, Do not move after that", (g_cvRLGLWarningTime.IntValue - timePassed)); + FormatEx(sMessage, sizeof(sMessage), "Warning: Red Light is coming in %d seconds, Do not move after that", (THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_WARNING_TIME].cvar.IntValue - timePassed)); + int warningTime = THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_WARNING_TIME].cvar.IntValue; + char numStr[3]; - IntToString(g_cvRLGLWarningTime.IntValue - timePassed, numStr, sizeof(numStr)); + IntToString(warningTime - timePassed, numStr, sizeof(numStr)); char sndPath[PLATFORM_MAX_PATH]; strcopy(sndPath, sizeof(sndPath), countDownPath); @@ -217,21 +317,21 @@ Action RLGL_Warning_Timer(Handle timer) timePassed++; - if (timePassed > g_cvRLGLWarningTime.IntValue) + if (timePassed > warningTime) { ApplyFade("Red"); g_bEnableDetecting = true; - float speed = g_cvRLGLZombiesSpeed.FloatValue; + float speed = THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_ZOMBIES_SPEED].cvar.FloatValue; if (speed > 0.0) { SetZombiesSpeed(speed); } - CreateTimer(g_cvRLGLFinishDetectTime.FloatValue, RLGL_Detect_Time_Timer, _, TIMER_FLAG_NO_MAPCHANGE); + CreateTimer(THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_FREEZE_TIME].cvar.FloatValue, RLGL_Detect_Time_Timer, _, TIMER_FLAG_NO_MAPCHANGE); timePassed = 0; - g_hRLGLWarningTime = null; + g_hRLGLWarningTimer = null; delete g_hRLGLDetectTimer; - g_hRLGLDetectTimer = CreateTimer(g_cvRLGLDetectTimer.FloatValue, RLGL_Detect_Timer, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); + g_hRLGLDetectTimer = CreateTimer(THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_TIME_BETWEEN_DAMAGE].cvar.FloatValue, RLGL_Detect_Timer, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); return Plugin_Stop; } @@ -241,14 +341,13 @@ Action RLGL_Warning_Timer(Handle timer) Action RLGL_Detect_Timer(Handle timer) { - if (!g_bIsRLGLEnabled || !g_bEnableDetecting) + if (!THIS_MODE_INFO.isOn || !g_bEnableDetecting) { g_hRLGLDetectTimer = null; return Plugin_Stop; } - char sMessage[256]; - FormatEx(sMessage, sizeof(sMessage), "STOP MOVING ITS A RED LIGHT!!!"); + float damage = THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_DAMAGE].cvar.FloatValue; for (int i = 1; i <= MaxClients; i++) { if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) @@ -261,8 +360,8 @@ Action RLGL_Detect_Timer(Handle timer) int buttons = GetClientButtons(i); if (buttons & (IN_WALK | IN_BACK | IN_FORWARD | IN_RIGHT | IN_LEFT | IN_JUMP)) { - SDKHooks_TakeDamage(i, 0, 0, g_cvRLGLDamage.FloatValue); - SendHudText(i, sMessage, _, 1); + SDKHooks_TakeDamage(i, 0, 0, damage); + SendHudText(i, "STOP MOVING ITS A RED LIGHT!!!", _, 1); } continue; @@ -273,20 +372,21 @@ Action RLGL_Detect_Timer(Handle timer) Action RLGL_Detect_Time_Timer(Handle timer) { + if (!THIS_MODE_INFO.isOn) + return Plugin_Stop; + ApplyFade("Green"); g_bEnableDetecting = false; SetZombiesSpeed(1.0); delete g_hRLGLDetectTimer; - char sMessage[256]; - FormatEx(sMessage, sizeof(sMessage), "YOU CAN MOVE NOW, ITS A GREEN LIGHT!"); for (int i = 1; i <= MaxClients; i++) { if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) continue; - SendHudText(i, sMessage, _, 2); + SendHudText(i, "YOU CAN MOVE NOW, ITS A GREEN LIGHT!", _, 2); } return Plugin_Continue; @@ -305,20 +405,59 @@ stock void SetZombiesSpeed(float val) { thisVal = 1.0; SetEntPropFloat(i, Prop_Data, "m_flLaggedMovementValue", thisVal); - CPrintToChat(i, RLGL_Tag ... " Your speed has been changed to {olive}%.2f", thisVal); - CPrintToChat(i, RLGL_Tag ... " This is a part of {olive}Red Light Green Light.{white} An admin decided to have this kicker."); + CPrintToChat(i, "%s Your speed has been changed to {olive}%.2f", THIS_MODE_INFO.tag, thisVal); + CPrintToChat(i, "%s This is a part of {olive}Red Light Green Light.{white} An admin decided to have this kicker.", THIS_MODE_INFO.tag); } } stock void StartRLGLTimer() { float time = 10.0; - float timeMax = g_cvRLGLDetectTimerRepeatMax.FloatValue; - float timeMin = g_cvRLGLDetectTimerRepeatMin.FloatValue; + float timeMax = THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_TIME_BETWEEN_REDLIGHTS_MAX].cvar.FloatValue; + float timeMin = THIS_MODE_INFO.cvarInfo[RLGL_CONVAR_TIME_BETWEEN_REDLIGHTS_MIN].cvar.FloatValue; if (timeMax <= 0.0) time = timeMin; else time = GetRandomFloat(timeMin, timeMax); - g_hRLGLTimer = CreateTimer(time, RLGL_Timer, _, TIMER_FLAG_NO_MAPCHANGE); + g_hRLGLTimer = CreateTimer(time, RLGL_Timer, _, TIMER_FLAG_NO_MAPCHANGE); +} + +/* RLGL Settings */ +public Action Cmd_RLGLSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_RLGLSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + return Plugin_Handled; +} + +int Menu_RLGLSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/Sample.sp b/addons/sourcemod/scripting/Fun_Modes/Sample.sp new file mode 100644 index 0000000..d0c4a2d --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/Sample.sp @@ -0,0 +1,142 @@ +/* + (). FunModes V2: + + @file Sample.sp + @Usage Functions for the Sample Mode. + +*/ + +#pragma semicolon 1 +#pragma newdecls required + +ModeInfo g_SampleInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_SampleInfo + +#define SAMPLE_CONVAR_TOGGLE 0 + +stock void OnPluginStart_Sample() +{ + THIS_MODE_INFO.name = "Sample"; + THIS_MODE_INFO.tag = "{gold}[FunModes-Sample]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_sample", Cmd_SampleToggle, ADMFLAG_CONVARS, "Turn Sample Mode On/Off"); + RegAdminCmd("sm_sample_settings", Cmd_SampleSettings, ADMFLAG_CONVARS, "Open Sample Sttings Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, SAMPLE_CONVAR_TOGGLE, + "sm_sample_enable", "1", "Enable/Disable Sample Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = SAMPLE_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[SAMPLE_CONVAR_TOGGLE].cvar.AddChangeHook(OnSampleModeToggle); +} + +void OnSampleModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_Sample() {} +stock void OnMapEnd_Sample() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); +} + +stock void OnClientPutInServer_Sample(int client) +{ + #pragma unused client +} + +stock void OnClientDisconnect_Sample(int client) +{ + #pragma unused client +} + +stock void ZR_OnClientInfected_Sample(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_Sample() {} +stock void Event_RoundEnd_Sample() {} +stock void Event_PlayerSpawn_Sample(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_Sample(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_Sample(int client) +{ + #pragma unused client +} + +public Action Cmd_SampleToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s Sample Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s Sample Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + return Plugin_Handled; +} + +/* Sample Settings */ +public Action Cmd_SampleSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_SampleSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_SampleSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/SlapMode.sp b/addons/sourcemod/scripting/Fun_Modes/SlapMode.sp new file mode 100644 index 0000000..9a3a5bd --- /dev/null +++ b/addons/sourcemod/scripting/Fun_Modes/SlapMode.sp @@ -0,0 +1,215 @@ +/* + (). FunModes V2: + + @file SlapMode.sp + @Usage Functions for the Slap mode. + +*/ + +/* + Slapmode : + Like all 3 or 5 seconds (not sure about the time) a random ct gets slapped, i think it can make certain maps really fun + + By @Kamisama Kaneki +*/ + +#pragma semicolon 1 +#pragma newdecls required + +ModeInfo g_SlapModeInfo; + +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_SlapModeInfo + +#define SLAPMODE_CONVAR_TIMER_INTERVAL 0 +#define SLAPMODE_CONVAR_RANDOMS_COUNT 1 +#define SLAPMODE_CONVAR_TOGGLE 2 + +Handle g_hSlapModeTimer; + +stock void OnPluginStart_SlapMode() +{ + THIS_MODE_INFO.name = "SlapMode"; + THIS_MODE_INFO.tag = "{gold}[FunModes-SlapMode]{lightgreen}"; + + /* COMMANDS */ + /* THESE ARE THE STANDARD COMMANDS THAT ALL MODES SHOULD HAVE */ + RegAdminCmd("sm_fm_slapmode", Cmd_SlapModeToggle, ADMFLAG_CONVARS, "Turn SlapMode Mode On/Off"); + RegAdminCmd("sm_slapmode_settings", Cmd_SlapModeSettings, ADMFLAG_CONVARS, "Open SlapMode Sttings Menu"); + + /* CONVARS */ + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, SLAPMODE_CONVAR_TIMER_INTERVAL, + "sm_slapmode_time_interval", "20.0", "Every how many seconds to keep slapping a random human?", + ("15.0,20.0,30.0,40.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, SLAPMODE_CONVAR_RANDOMS_COUNT, + "sm_slapmode_randoms_count", "1", "How many random humans to keep slapping?", + ("1,2,3,4,5"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, SLAPMODE_CONVAR_TOGGLE, + "sm_slapmode_enable", "1", "Enable/Disable SlapMode Mode (This differs from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = SLAPMODE_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[SLAPMODE_CONVAR_TOGGLE].cvar.AddChangeHook(OnSlapModeModeToggle); +} + +void OnSlapModeModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) +{ + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); +} + +stock void OnMapStart_SlapMode() {} +stock void OnMapEnd_SlapMode() +{ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); + + g_hSlapModeTimer = null; +} + +stock void OnClientPutInServer_SlapMode(int client) +{ + #pragma unused client +} + +stock void OnClientDisconnect_SlapMode(int client) +{ + #pragma unused client +} + +stock void ZR_OnClientInfected_SlapMode(int client) +{ + #pragma unused client +} + +stock void Event_RoundStart_SlapMode() {} +stock void Event_RoundEnd_SlapMode() {} +stock void Event_PlayerSpawn_SlapMode(int client) +{ + #pragma unused client +} + +stock void Event_PlayerTeam_SlapMode(Event event) +{ + #pragma unused event +} + +stock void Event_PlayerDeath_SlapMode(int client) +{ + #pragma unused client +} + +public Action Cmd_SlapModeToggle(int client, int args) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s SlapMode Mode is currently Disabled", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + /* You can change whatever you want here */ + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, !THIS_MODE_INFO.isOn, THIS_MODE_INFO.index); + + CPrintToChatAll("%s SlapMode Mode is now %s!", THIS_MODE_INFO.tag, THIS_MODE_INFO.isOn ? "On" : "Off"); + + if (THIS_MODE_INFO.isOn) + { + float interval = THIS_MODE_INFO.cvarInfo[SLAPMODE_CONVAR_TIMER_INTERVAL].cvar.FloatValue; + + CPrintToChatAll("%s A random human will get slapped every %.2f seconds", THIS_MODE_INFO.tag, interval); + g_hSlapModeTimer = CreateTimer(interval, Timer_SlapMode, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT); + } + else + { + delete g_hSlapModeTimer; + } + + return Plugin_Handled; +} + +/* SlapMode Settings */ +public Action Cmd_SlapModeSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_SlapModeSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +int Menu_SlapModeSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + } + + return 0; +} + +Action Timer_SlapMode(Handle timer) +{ + if (!THIS_MODE_INFO.isOn) + { + g_hBlindModeTimer = null; + return Plugin_Stop; + } + + int humansCount = 0; + int humans[MAXPLAYERS + 1]; + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) + continue; + + humans[humansCount++] = i; + } + + if (humansCount == 0) + return Plugin_Handled; + + int neededHumans = THIS_MODE_INFO.cvarInfo[SLAPMODE_CONVAR_RANDOMS_COUNT].cvar.IntValue; + int enough = 1; + do + { + int human = humans[GetRandomInt(0, humansCount - 1)]; + SlapPlayer(human); + SlapPlayer(human); + CPrintToChatAll("%s %N {olive}has been slapped for being a bad boy (Bruh, It's totally random...)", THIS_MODE_INFO.tag, human); + enough++; + } while (enough <= neededHumans); + + return Plugin_Continue; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/Fun_Modes/VIPMode.sp b/addons/sourcemod/scripting/Fun_Modes/VIPMode.sp index 509a90c..05a7bb7 100644 --- a/addons/sourcemod/scripting/Fun_Modes/VIPMode.sp +++ b/addons/sourcemod/scripting/Fun_Modes/VIPMode.sp @@ -1,157 +1,260 @@ +/* + (). FunModes V2: + + @file VIPMode.sp + @Usage Functions for the VIP mode. +*/ + #pragma semicolon 1 #pragma newdecls required -bool g_bDiedFromLaser[MAXPLAYERS + 1]; +ModeInfo g_VIPModeInfo; -ConVarInfo g_cvInfoVIP[4] = -{ - {null, "15.0,25.0,40.0,60.0", "float"}, - {null, "2.0,3.0,5.0,10.0", "float"}, - {null, "0,1", "bool"}, - {null, "1,2,3,4,5", "int"} -}; +#undef THIS_MODE_INFO +#define THIS_MODE_INFO g_VIPModeInfo + +#define VIPMODE_CONVAR_TIMER 0 +#define VIPMODE_CONVAR_COUNT 1 +#define VIPMODE_CONVAR_LASER 2 +#define VIPMODE_CONVAR_VIP_MAX 3 +#define VIPMODE_CONVAR_TOGGLE 4 + +bool g_bDiedFromLaser[MAXPLAYERS+1]; +bool g_bIsVIP[MAXPLAYERS + 1]; + +/* Timers */ +Handle g_hKillAllTimer = null; +Handle g_hVIPRoundStartTimer = null; +Handle g_hVIPBeaconTimer[MAXPLAYERS + 1] = { null, ... }; /* CALLED ON PLUGIN START */ -stock void PluginStart_VIPMode() +stock void OnPluginStart_VIPMode() { - RegAdminCmd("sm_fm_vipmode", Cmd_VIPModeEnable, ADMFLAG_CONVARS, "Enable/Disable VIP Mode"); + THIS_MODE_INFO.name = "VIPMode"; + THIS_MODE_INFO.tag = "{gold}[FunModes-VIPMode]{lightgreen}"; + + /* Commands */ + RegAdminCmd("sm_fm_vipmode", Cmd_VIPModeToggle, ADMFLAG_CONVARS, "Enable/Disable VIP Mode"); RegAdminCmd("sm_vipmode_setvip", Cmd_SetVIP, ADMFLAG_CONVARS); RegConsoleCmd("sm_checkvip", Cmd_CheckVIP); + RegAdminCmd("sm_vipmode_settings", Cmd_VIPModeSettings, ADMFLAG_CONVARS, "Open VIPMode Settings Menu"); /* CONVARS */ - g_cvVIPModeTimer = CreateConVar("sm_vipmode_timer", "15", "After how many seconds from round start to pick VIP"); - g_cvVIPModeCount = CreateConVar("sm_vipmode_counter", "3", "After how many seconds all the other humans will be slayed after the VIP dies"); - g_cvVIPModeLaser = CreateConVar("sm_vipmode_laser", "1", "Don't Kill all humans when vip dies to a laser, 1 = Enabled, 0 = Disabled"); - g_cvVIPMax = CreateConVar("sm_vipmode_max_vips", "1", "How many VIPs to be picked"); - - VIPMode_SetCvarsInfo(); + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, VIPMODE_CONVAR_TIMER, + "sm_vipmode_timer", "15", "After how many seconds from round start to pick VIP", + ("15.0,25.0,40.0,60.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, VIPMODE_CONVAR_COUNT, + "sm_vipmode_counter", "3", "After how many seconds all the other humans will be slayed after the vip dies", + ("2.0,3.0,5.0,10.0"), "float" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, VIPMODE_CONVAR_LASER, + "sm_vipmode_laser", "1", ("Don't Kill all humans when vip dies to a laser, 1 = Enabled, 0 = Disabled"), + ("0,1"), "bool" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, VIPMODE_CONVAR_VIP_MAX, + "sm_vipmode_max_vips", "1", "How many VIPs to be picked", + ("1,2,3,4,5"), "int" + ); + + DECLARE_FM_CVAR( + THIS_MODE_INFO.cvarInfo, VIPMODE_CONVAR_TOGGLE, + "sm_vipmode_enable", "1", "Enable/Disable the VIP Mode (This differes from turning it on/off)", + ("0,1"), "bool" + ); + + THIS_MODE_INFO.enableIndex = VIPMODE_CONVAR_TOGGLE; + + THIS_MODE_INFO.index = g_iLastModeIndex++; + g_ModesInfo[THIS_MODE_INFO.index] = THIS_MODE_INFO; + + THIS_MODE_INFO.cvarInfo[VIPMODE_CONVAR_TOGGLE].cvar.AddChangeHook(OnVIPModeToggle); } -void VIPMode_SetCvarsInfo() +void OnVIPModeToggle(ConVar cvar, const char[] newValue, const char[] oldValue) { - ConVar cvars[sizeof(g_cvInfoVIP)]; - cvars[0] = g_cvVIPModeTimer; - cvars[1] = g_cvVIPModeCount; - cvars[2] = g_cvVIPModeLaser; - cvars[3] = g_cvVIPMax; - - for (int i = 0; i < sizeof(g_cvInfoVIP); i++) - g_cvInfoVIP[i].cvar = cvars[i]; + if (THIS_MODE_INFO.isOn) + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, cvar.BoolValue, THIS_MODE_INFO.index); } -stock Action VIPMode_OnTakeDamage(int victim, int attacker, float damage) +stock void OnMapStart_VIPMode() {} +stock void OnMapEnd_VIPMode() { - if (!g_cvVIPModeLaser.BoolValue) - return Plugin_Continue; - - if (!g_bIsVIP[victim]) - return Plugin_Continue; + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, false, THIS_MODE_INFO.index); - if (!IsValidEntity(attacker)) - return Plugin_Continue; + g_hKillAllTimer = null; + g_hVIPRoundStartTimer = null; + for (int i = 1; i <= MaxClients; i++) + { + g_hVIPBeaconTimer[i] = null; + g_bDiedFromLaser[i] = false; + } +} - char classname[64]; - if (!GetEntityClassname(attacker, classname, sizeof(classname))) - return Plugin_Continue; +stock void OnClientPutInServer_VIPMode(int client) +{ + if (g_bSDKHook_OnTakeDamage[client]) + return; + + SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); + g_bSDKHook_OnTakeDamage[client] = true; +} - /* if attacker entity is not trigger_hurt */ - if (strcmp(classname, "trigger_hurt") != 0) - return Plugin_Continue; +stock void OnClientDisconnect_VIPMode(int client) +{ + delete g_hVIPBeaconTimer[client]; + + if (!THIS_MODE_INFO.isOn) + return; + + if (!g_bIsVIP[client]) + return; + + RemoveClientVIP(client, true, "VIPMode_VIPDeathDisconnect"); +} - /* we should now check if trigger_hurt is from a laser */ - int parent = GetEntPropEnt(attacker, Prop_Data, "m_hParent"); - if (!IsValidEntity(parent)) - return Plugin_Continue; +stock void ZR_OnClientInfected_VIPMode(int client) +{ + #pragma unused client +} - bool isFromLaser = false; - char parentClassName[64]; - if(!GetEntityClassname(parent, parentClassName, sizeof(parentClassName))) - return Plugin_Continue; +stock void Event_RoundStart_VIPMode() +{ + if (!THIS_MODE_INFO.isOn) + return; - if (strcmp(parentClassName, "func_movelinear") == 0 || strcmp(parentClassName, "func_door") == 0) - isFromLaser = true; - - if (!isFromLaser) - return Plugin_Continue; - - g_bDiedFromLaser[victim] = false; - if (damage >= GetClientHealth(victim)) - g_bDiedFromLaser[victim] = true; + delete g_hKillAllTimer; - return Plugin_Continue; + /* DELETE VIP BEACON TIMER */ + for (int i = 1; i <= MaxClients; i++) + { + g_bIsVIP[i] = false; + g_bDiedFromLaser[i] = false; + delete g_hVIPBeaconTimer[i]; + } + + delete g_hVIPRoundStartTimer; + g_hVIPRoundStartTimer = CreateTimer(THIS_MODE_INFO.cvarInfo[VIPMODE_CONVAR_TIMER].cvar.FloatValue, VIPRoundStart_Timer, _, TIMER_FLAG_NO_MAPCHANGE); } -stock void PlayerDeath_VIPMode(int userid) +stock void Event_RoundEnd_VIPMode() {} +stock void Event_PlayerSpawn_VIPMode(int client) { - if(!g_bIsVIPModeOn) + #pragma unused client +} + +stock void Event_PlayerTeam_VIPMode(Event event) +{ + if (!!THIS_MODE_INFO.isOn) + return; + + int client = GetClientOfUserId(event.GetInt("userid")); + if (!client || !g_bIsVIP[client]) return; - int client = GetClientOfUserId(userid); - if(!IsValidClient(client)) + int team = event.GetInt("team"); + if (team == CS_TEAM_SPECTATOR || team == CS_TEAM_NONE) + RemoveClientVIP(client, true, "VIPMode_VIPDeathSpec"); +} + +stock void Event_PlayerDeath_VIPMode(int client) +{ + if (!THIS_MODE_INFO.isOn) return; - if(!g_bIsVIP[client]) + if (!g_bIsVIP[client]) return; if (g_bDiedFromLaser[client]) { - CPrintToChatAll("%s %T", VIPMode_Tag, "VIPMode_VIPDeathLaser", client, client); + CPrintToChatAll("%s %T", THIS_MODE_INFO.tag, "VIPMode_VIPDeathLaser", client, client); RemoveClientVIP(client, false); g_bDiedFromLaser[client] = false; return; } - + RemoveClientVIP(client, true, "VIPMode_VIPDeath"); } -stock void PlayerTeam_VIPMode(int userid, int team) +stock void OnTakeDamagePost_VIPMode(int victim, int attacker, float damage) { - if(!g_bIsVIPModeOn) { + #pragma unused victim + #pragma unused attacker + #pragma unused damage +} + +stock void OnTakeDamage_VIPMode(int victim, int attacker, float damage, Action &result) +{ + #pragma unused result + + if (!THIS_MODE_INFO.cvarInfo[VIPMODE_CONVAR_LASER].cvar.BoolValue) return; - } - int client = GetClientOfUserId(userid); - if(!IsValidClient(client)) + if (!g_bIsVIP[victim]) return; - if(!g_bIsVIP[client]) + if (!IsValidEntity(attacker)) return; - if(team == CS_TEAM_SPECTATOR || team == CS_TEAM_NONE) - RemoveClientVIP(client, true, "VIPMode_VIPDeathSpec"); -} + char classname[64]; + if (!GetEntityClassname(attacker, classname, sizeof(classname))) + return; -stock void ClientDisconnect_VIPMode(int client) -{ - delete g_hVIPBeaconTimer[client]; - - if(!g_bIsVIPModeOn) { + /* if attacker entity is not trigger_hurt */ + if (strcmp(classname, "trigger_hurt") != 0) return; - } + + /* we should now check if trigger_hurt is from a laser */ + int parent = GetEntPropEnt(attacker, Prop_Data, "m_hParent"); + if (!IsValidEntity(parent)) + return; + + bool isFromLaser = false; + char parentClassName[64]; + if (!GetEntityClassname(parent, parentClassName, sizeof(parentClassName))) + return; + + if (strcmp(parentClassName, "func_movelinear") == 0 || strcmp(parentClassName, "func_door") == 0) + isFromLaser = true; - if(!g_bIsVIP[client]) { + if (!isFromLaser) return; - } - RemoveClientVIP(client, true, "VIPMode_VIPDeathDisconnect"); + g_bDiedFromLaser[victim] = false; + if (damage > GetClientHealth(victim)) + g_bDiedFromLaser[victim] = true; +} - delete g_hKillAllTimer; - g_hKillAllTimer = CreateTimer(g_cvVIPModeCount.FloatValue, VIPMode_KillAllTimer, _, TIMER_FLAG_NO_MAPCHANGE); +stock void OnWeaponEquip_VIPMode(int client, int weapon, Action &result) +{ + #pragma unused client + #pragma unused weapon + #pragma unused result } Action VIPMode_KillAllTimer(Handle timer) { g_hKillAllTimer = null; - - if(GetCurrentVIPsCount() > 0) + + if (!THIS_MODE_INFO.isOn) + return Plugin_Stop; + + if (GetCurrentVIPsCount() > 0) { - CPrintToChatAll("%s Found a VIP player, {olive}Cancelling The kills...", VIPMode_Tag); + CPrintToChatAll("%s Found a VIP player, {olive}Cancelling The kills...", THIS_MODE_INFO.tag); return Plugin_Stop; } - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) + if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT) continue; ForcePlayerSuicide(i); @@ -160,35 +263,19 @@ Action VIPMode_KillAllTimer(Handle timer) return Plugin_Continue; } -stock void RoundStart_VIPMode() -{ - if(!g_bIsVIPModeOn) - return; - - delete g_hKillAllTimer; - - /* DELETE VIP BEACON TIMER */ - for(int i = 1; i <= MaxClients; i++) - { - g_bIsVIP[i] = false; - g_bDiedFromLaser[i] = false; - delete g_hVIPBeaconTimer[i]; - } - - delete g_hVIPRoundStartTimer; - g_hVIPRoundStartTimer = CreateTimer(g_cvVIPModeTimer.FloatValue, VIPRoundStart_Timer, _, TIMER_FLAG_NO_MAPCHANGE); -} - Action VIPRoundStart_Timer(Handle timer) { g_hVIPRoundStartTimer = null; + if (THIS_MODE_INFO.isOn) + return Plugin_Stop; + /* CHECK IF THERE IS ALREADY VIP SET BY ADMIN */ - if(GetCurrentVIPsCount() > 0) + if (GetCurrentVIPsCount() > 0) return Plugin_Stop; /* Lets pick a random human */ - for (int i = 0; i < g_cvVIPMax.IntValue; i++) + for (int i = 0; i < THIS_MODE_INFO.cvarInfo[VIPMODE_CONVAR_VIP_MAX].cvar.IntValue; i++) VIP_PickRandom(); return Plugin_Stop; @@ -197,51 +284,59 @@ Action VIPRoundStart_Timer(Handle timer) Action VIP_BeaconTimer(Handle timer, int userid) { int client = GetClientOfUserId(userid); - if(!IsValidClient(client)) + if (!client) { - g_hVIPBeaconTimer[client] = null; return Plugin_Stop; } - if(!IsPlayerAlive(client) || GetClientTeam(client) != CS_TEAM_CT) + + if (!THIS_MODE_INFO.isOn) + { + g_hVIPBeaconTimer[client] = null; + return Plugin_Stop; + } + + if (!IsPlayerAlive(client) || GetClientTeam(client) != CS_TEAM_CT) { g_hVIPBeaconTimer[client] = null; return Plugin_Stop; } - if(g_bRoundEnd) + if (g_bRoundEnd) { g_hVIPBeaconTimer[client] = null; return Plugin_Stop; } - BeaconPlayer(client, BeaconMode_VIP); + BeaconPlayer(client, 1); return Plugin_Continue; } -Action Cmd_VIPModeEnable(int client, int args) +public Action Cmd_VIPModeToggle(int client, int args) { - if(g_bIsVIPModeOn) + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + { + CReplyToCommand(client, "%s VIPmode is currently disabled!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + bool isOn = THIS_MODE_INFO.isOn; + if (isOn) { - g_bIsVIPModeOn = false; - if(!client) - CReplyToCommand(client, "%s VIP Mode is now OFF!", VIPMode_Tag); + isOn = false; + if (!client) + CReplyToCommand(client, "%s VIP Mode is now OFF!", THIS_MODE_INFO.tag); else - CReplyToCommand(client, "%s %T", VIPMode_Tag, "VIPMode_Disabled", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "VIPMode_Disabled", client); for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !g_bIsVIP[i]) - continue; - g_bIsVIP[i] = false; delete g_hVIPBeaconTimer[i]; } - - return Plugin_Handled; } else { - g_bIsVIPModeOn = true; + isOn = true; /* Events Hooks */ FunModes_HookEvent(g_bEvent_RoundStart, "round_start", Event_RoundStart); @@ -249,28 +344,35 @@ Action Cmd_VIPModeEnable(int client, int args) FunModes_HookEvent(g_bEvent_PlayerTeam, "player_team", Event_PlayerTeam); FunModes_HookEvent(g_bEvent_PlayerDeath, "player_death", Event_PlayerDeath); - if(!client) - CReplyToCommand(client, "%s VIP Mode is now ON!", VIPMode_Tag); + if (!client) + CReplyToCommand(client, "%s VIP Mode is now ON!", THIS_MODE_INFO.tag); else - CReplyToCommand(client, "%s %T", VIPMode_Tag, "VIPMode_Enabled", client); + CReplyToCommand(client, "%s %T", THIS_MODE_INFO.tag, "VIPMode_Enabled", client); - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsClientInGame(i) || IsFakeClient(i) || !IsClientConnected(i)) + if (!IsClientInGame(i) || IsFakeClient(i)) continue; SDKHook(i, SDKHook_OnTakeDamage, OnTakeDamage); } - - return Plugin_Handled; } + + CHANGE_MODE_INFO(THIS_MODE_INFO, isOn, isOn, THIS_MODE_INFO.index); + return Plugin_Handled; } Action Cmd_SetVIP(int client, int args) { - if(args < 1) + if (!THIS_MODE_INFO.isOn) { - CReplyToCommand(client, "%s Usage: sm_setvip ", VIPMode_Tag); + CReplyToCommand(client, "%s VIP Mode is currently OFF!", THIS_MODE_INFO.tag); + return Plugin_Handled; + } + + if (args < 1) + { + CReplyToCommand(client, "%s Usage: sm_vipmode_setvip ", THIS_MODE_INFO.tag); return Plugin_Handled; } @@ -278,26 +380,26 @@ Action Cmd_SetVIP(int client, int args) GetCmdArg(1, arg, sizeof(arg)); int target = FindTarget(client, arg, false, false); - if(target < 1) + if (target < 1) { ReplyToTargetError(client, COMMAND_TARGET_NOT_IN_GAME); return Plugin_Handled; } - if(g_bIsVIP[target]) + if (g_bIsVIP[target]) { - CReplyToCommand(client, "%s The specified target is already VIP!", VIPMode_Tag); + CReplyToCommand(client, "%s The specified target is already VIP!", THIS_MODE_INFO.tag); return Plugin_Handled; } - if(!IsPlayerAlive(target) || GetClientTeam(target) != CS_TEAM_CT) + if (!IsPlayerAlive(target) || GetClientTeam(target) != CS_TEAM_CT) { - CReplyToCommand(client, "%s Cannot set VIP to a player that is not human.", VIPMode_Tag); + CReplyToCommand(client, "%s Cannot set VIP to a player that is not human.", THIS_MODE_INFO.tag); return Plugin_Handled; } g_bIsVIP[target] = true; - CPrintToChatAll("%s {olive}%N {lightgreen}is a VIP!", VIPMode_Tag, target); + CPrintToChatAll("%s {olive}%N {lightgreen}is a VIP!", THIS_MODE_INFO.tag, target); delete g_hVIPBeaconTimer[target]; g_hVIPBeaconTimer[target] = CreateTimer(1.0, VIP_BeaconTimer, GetClientUserId(target), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); @@ -306,28 +408,28 @@ Action Cmd_SetVIP(int client, int args) Action Cmd_CheckVIP(int client, int args) { - if(!g_bIsVIPModeOn) + if (!THIS_MODE_INFO.isOn) { - CReplyToCommand(client, "%s VIP Mode is currently OFF", VIPMode_Tag); + CReplyToCommand(client, "%s VIP Mode is currently OFF", THIS_MODE_INFO.tag); return Plugin_Handled; } - if(GetCurrentVIPsCount() == 0) + if (GetCurrentVIPsCount() == 0) { - CReplyToCommand(client, "%s No VIP was found!", VIPMode_Tag); + CReplyToCommand(client, "%s No VIP was found!", THIS_MODE_INFO.tag); return Plugin_Handled; } char vipPlayers[200]; for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !g_bIsVIP[i]) + if (!g_bIsVIP[i]) continue; Format(vipPlayers, sizeof(vipPlayers), "%s%N, ", vipPlayers, i); } - CReplyToCommand(client, "%s The current {purple}VIPs {olive}are: {purple}%s", VIPMode_Tag, vipPlayers); + CReplyToCommand(client, "%s The current {purple}VIPs {olive}are: {purple}%s", THIS_MODE_INFO.tag, vipPlayers); return Plugin_Handled; } @@ -336,7 +438,7 @@ stock int GetCurrentVIPsCount() int count; for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !g_bIsVIP[i]) + if (!g_bIsVIP[i]) continue; count++; @@ -350,14 +452,15 @@ stock void RemoveClientVIP(int client, bool kill, const char[] translation = "") g_bIsVIP[client] = false; delete g_hVIPBeaconTimer[client]; - CPrintToChatAll("%s %t", VIPMode_Tag, translation, client); + CPrintToChatAll("%s %t", THIS_MODE_INFO.tag, translation, client); - if(kill && GetCurrentVIPsCount() == 0) + if (kill && GetCurrentVIPsCount() == 0) { - CPrintToChatAll("%s %t", VIPMode_Tag, "VIPMode_KillAll", g_cvVIPModeCount.IntValue); + int counter = THIS_MODE_INFO.cvarInfo[VIPMODE_CONVAR_COUNT].cvar.IntValue; + CPrintToChatAll("%s %t", THIS_MODE_INFO.tag, "VIPMode_KillAll", counter); delete g_hKillAllTimer; - g_hKillAllTimer = CreateTimer(g_cvVIPModeCount.FloatValue, VIPMode_KillAllTimer, _, TIMER_FLAG_NO_MAPCHANGE); + g_hKillAllTimer = CreateTimer(float(counter), VIPMode_KillAllTimer, _, TIMER_FLAG_NO_MAPCHANGE); } } @@ -367,24 +470,235 @@ stock void VIP_PickRandom() int clientsCount[MAXPLAYERS + 1]; int humansCount; - for(int i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(!IsValidClient(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT || g_bIsVIP[i]) + if (!IsClientInGame(i) || !IsPlayerAlive(i) || GetClientTeam(i) != CS_TEAM_CT || g_bIsVIP[i]) continue; clientsCount[humansCount++] = i; } - if(humansCount <= 0) + if (humansCount <= 0) return; int random = clientsCount[GetRandomInt(0, (humansCount - 1))]; - if(random < 1) + if (random < 1) return; g_bIsVIP[random] = true; - CPrintToChatAll("%s {olive}%N {lightgreen}is a VIP!", VIPMode_Tag, random); + CPrintToChatAll("%s {olive}%N {lightgreen}is a VIP!", THIS_MODE_INFO.tag, random); delete g_hVIPBeaconTimer[random]; g_hVIPBeaconTimer[random] = CreateTimer(1.0, VIP_BeaconTimer, GetClientUserId(random), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); +} + +/* VIPMode Settings */ +public Action Cmd_VIPModeSettings(int client, int args) +{ + if (!client) + return Plugin_Handled; + + Menu menu = new Menu(Menu_VIPModeSettings); + + menu.SetTitle("%s - Settings", THIS_MODE_INFO.name); + + menu.AddItem(NULL_STRING, "Show Cvars\n"); + menu.AddItem(NULL_STRING, "Check current VIPs", THIS_MODE_INFO.isOn ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED); + menu.AddItem(NULL_STRING, "Set Player VIP", THIS_MODE_INFO.isOn ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED); + + menu.ExitBackButton = true; + menu.Display(client, MENU_TIME_FOREVER); + return Plugin_Handled; +} + +int Menu_VIPModeSettings(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + DisplayModeInfo(param1, g_iPreviousModeIndex[param1]); + } + + case MenuAction_Select: + { + switch (param2) + { + case 0: + { + ShowCvarsInfo(param1, THIS_MODE_INFO); + } + + case 1: + { + ShowCurrentVIPs(param1); + } + + case 2: + { + ShowSetPlayerVIP(param1); + } + } + } + } + + return 0; +} + +void ShowCurrentVIPs(int client) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + return; + + Menu menu = new Menu(Menu_VIPCurrentVIPs); + + menu.SetTitle("%s - Current VIPs List", THIS_MODE_INFO.name); + + if (!THIS_MODE_INFO.isOn) + menu.AddItem(NULL_STRING, "The VIPMode is currently Off!", ITEMDRAW_DISABLED); + else + { + bool found = false; + for (int i = 1; i <= MaxClients; i++) + { + if (!g_bIsVIP[i]) + continue; + + found = true; + int userid = GetClientUserId(i); + + char useridStr[10]; + IntToString(userid, useridStr, sizeof(useridStr)); + + char menuItem[70]; + FormatEx(menuItem, sizeof(menuItem), "[#%d] %N - Remove", userid, i); + + menu.AddItem(useridStr, menuItem); + } + + if (!found) + menu.AddItem(NULL_STRING, "There's no VIP player yet!", ITEMDRAW_DISABLED); + } + + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_VIPCurrentVIPs(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + Cmd_VIPModeSettings(param1, 0); + } + + case MenuAction_Select: + { + char useridStr[10]; + menu.GetItem(param2, useridStr, sizeof(useridStr)); + + int userid = StringToInt(useridStr); + int client = GetClientOfUserId(userid); + if (!client || !g_bIsVIP[client]) + { + CPrintToChat(param1, "%s The selected player either left or is no longer {purple]VIP!", THIS_MODE_INFO.tag); + ShowCurrentVIPs(param1); + return 0; + } + + RemoveClientVIP(client, false, "VIPMode_AdminRemove"); + ShowCurrentVIPs(param1); + } + } + + return 0; +} + +void ShowSetPlayerVIP(int client) +{ + if (!THIS_MODE_INFO.cvarInfo[THIS_MODE_INFO.enableIndex].cvar.BoolValue) + return; + + Menu menu = new Menu(Menu_VIPSetPlayerVIP); + + menu.SetTitle("%s - Players List - Select a player to set them to a VIP", THIS_MODE_INFO.name); + + if (!THIS_MODE_INFO.isOn) + menu.AddItem(NULL_STRING, "The VIPMode is currently Off!", ITEMDRAW_DISABLED); + else + { + bool found = false; + for (int i = 1; i <= MaxClients; i++) + { + if (g_bIsVIP[i] || !IsClientInGame(i) || IsFakeClient(i) || !IsPlayerAlive(i)) + continue; + + if (ZR_IsClientZombie(i)) + continue; + + found = true; + int userid = GetClientUserId(i); + + char useridStr[10]; + IntToString(userid, useridStr, sizeof(useridStr)); + + char menuItem[70]; + FormatEx(menuItem, sizeof(menuItem), "[#%d] %N - Set VIP", userid, i); + + menu.AddItem(useridStr, menuItem); + } + + if (!found) + menu.AddItem(NULL_STRING, "No player was found!", ITEMDRAW_DISABLED); + } + + menu.Display(client, MENU_TIME_FOREVER); +} + +int Menu_VIPSetPlayerVIP(Menu menu, MenuAction action, int param1, int param2) +{ + switch (action) + { + case MenuAction_End: + delete menu; + + case MenuAction_Cancel: + { + if (param2 == MenuCancel_ExitBack) + Cmd_VIPModeSettings(param1, 0); + } + + case MenuAction_Select: + { + char useridStr[10]; + menu.GetItem(param2, useridStr, sizeof(useridStr)); + + int userid = StringToInt(useridStr); + int client = GetClientOfUserId(userid); + if (!client || g_bIsVIP[client] || ZR_IsClientZombie(client)) + { + CPrintToChat(param1, "%s The selected player either left, died or is currently a {purple]VIP!", THIS_MODE_INFO.tag); + ShowCurrentVIPs(param1); + return 0; + } + + g_bIsVIP[client] = true; + CPrintToChatAll("%s {olive}%N {lightgreen}is a VIP!", THIS_MODE_INFO.tag, client); + + delete g_hVIPBeaconTimer[client]; + g_hVIPBeaconTimer[client] = CreateTimer(1.0, VIP_BeaconTimer, userid, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); + + ShowCurrentVIPs(param1); + } + } + + return 0; } \ No newline at end of file