From f2ce13c81ed73d3c748a3f8c0b369c8bd91f0fbb Mon Sep 17 00:00:00 2001 From: moltard Date: Tue, 6 Jul 2021 15:06:48 +0100 Subject: [PATCH] Stackmode plugin --- StackMode/scripting/StackMode.sp | 859 +++++++++++++++++++++++++++++++ 1 file changed, 859 insertions(+) create mode 100644 StackMode/scripting/StackMode.sp diff --git a/StackMode/scripting/StackMode.sp b/StackMode/scripting/StackMode.sp new file mode 100644 index 00000000..70b5be46 --- /dev/null +++ b/StackMode/scripting/StackMode.sp @@ -0,0 +1,859 @@ +#pragma semicolon 1 + +#include +#include +#include +#include +#include + +int g_iVIPClient = -1; +int g_iVIPClientTwo = -1; +bool g_bDoubleVIP = false; +bool g_bmotherInfect = false; + +int g_BeaconSerial[MAXPLAYERS + 1] = { 0, ... }; +int g_Serial_Gen = 0; +int g_BeamSprite = -1; +int g_HaloSprite = -1; +int greyColor[4] = {128, 128, 128, 255}; +int spriteEntities[MAXPLAYERS + 1]; + +int g_iDamageTick; +int g_iHealTick; +float g_fAuraRange; + +public Plugin myinfo = +{ + name = "Stack Mode", + author = "Dogan", + description = "Stack Mode for ZE Events", + version = "2.2.0", + url = "" +}; + +public void OnPluginStart() +{ + HookEvent("player_death", OnPlayerDeath); + HookEvent("round_end", OnRoundEnd); + HookEvent("player_team", OnPlayerTeam); + + RegConsoleCmd("sm_stackmaster", WhoIsVIP); + RegAdminCmd("sm_fsm", PerformAdminVIPSelection, ADMFLAG_GENERIC, "Randomly chooses another alive human as Stack Master (putting a target force picks your target)"); + RegAdminCmd("sm_fsm2", PerformAdmin2ndVIPSelection, ADMFLAG_GENERIC, "Randomly chooses another alive human as 2nd Stack Master (putting a target force picks your target)"); + + CreateTimer(1.0, Timer_AuraAroundVIP, _, TIMER_REPEAT); + + ConVar cvar; + HookConVarChange((cvar = CreateConVar("sm_stackmode_damage", "2", "how much damage shall be dealt to clients that are not in the aura of the stackmaster", FCVAR_NONE, true, 1.0, true, 20.0)), g_cvDamageTick); + g_iDamageTick = cvar.IntValue; + HookConVarChange((cvar = CreateConVar("sm_stackmode_heal", "1", "how much shall the clients heal in the aura of the stackmaster", FCVAR_NONE, true, 0.0, true, 20.0)), g_cvHealTick); + g_iHealTick = cvar.IntValue; + HookConVarChange((cvar = CreateConVar("sm_stackmode_aura", "150.0", "aura range of the stackmaster", FCVAR_NONE, true, 50.0, true, 500.0)), g_cvAuraRange); + g_fAuraRange = cvar.FloatValue; + HookConVarChange((cvar = CreateConVar("sm_stackmode_doublemaster", "0", "0 = only one stack master mode, 1 = two stack masters mode", FCVAR_NONE, true, 0.0, true, 1.0)), g_cvDoubleVIP); + g_bDoubleVIP = cvar.BoolValue; + delete cvar; + + AutoExecConfig(true, "plugin.StackMode"); + + /*for (int client = 1; client <= MaxClients; client++) + { + if (IsClientInGame(client)) + OpenInformationPanel(client); + }*/ +} + +public void OnPluginEnd() +{ + KillAllBeacons(); +} + +public void g_cvDamageTick(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_iDamageTick = convar.IntValue; +} + +public void g_cvHealTick(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_iHealTick = convar.IntValue; +} + +public void g_cvAuraRange(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_fAuraRange = convar.FloatValue; +} + +public void g_cvDoubleVIP(ConVar convar, const char[] oldValue, const char[] newValue) +{ + g_bDoubleVIP = convar.BoolValue; +} + +public void OnMapStart() +{ + Handle gameConfig = LoadGameConfigFile("funcommands.games"); + if (gameConfig == null) + { + SetFailState("Unable to load game config funcommands.games"); + return; + } + + char buffer[PLATFORM_MAX_PATH]; + if (GameConfGetKeyValue(gameConfig, "SpriteBeam", buffer, sizeof(buffer)) && buffer[0]) + { + g_BeamSprite = PrecacheModel(buffer); + } + if (GameConfGetKeyValue(gameConfig, "SpriteHalo", buffer, sizeof(buffer)) && buffer[0]) + { + g_HaloSprite = PrecacheModel(buffer); + } +} + +/*public void OnClientPostAdminCheck(int client) +{ + OpenInformationPanel(client); +} + +public void OpenInformationPanel(int client) +{ + char sBuffer[256]; + Panel hNotifyPanel = new Panel(GetMenuStyleHandle(MenuStyle_Radio)); + + hNotifyPanel.SetTitle("*** Welcome to Unloze Stack Mode Event ***"); + hNotifyPanel.DrawItem("", ITEMDRAW_SPACER); + + Format(sBuffer, sizeof(sBuffer), "A random player is chosen as Stack Master couple seconds after Zombies spawn."); + hNotifyPanel.DrawItem(sBuffer, ITEMDRAW_RAWLINE); + + Format(sBuffer, sizeof(sBuffer), "You will constantly lose HP if you get too far away from the Stack Master!"); + hNotifyPanel.DrawItem(sBuffer, ITEMDRAW_RAWLINE); + + Format(sBuffer, sizeof(sBuffer), "But you also regenerate some HP if you stay close to him."); + hNotifyPanel.DrawItem(sBuffer, ITEMDRAW_RAWLINE); + + Format(sBuffer, sizeof(sBuffer), "The round does NOT end if the Stack Master dies! Another player is randomly chosen to replace him instead."); + hNotifyPanel.DrawItem(sBuffer, ITEMDRAW_RAWLINE); + hNotifyPanel.DrawItem("", ITEMDRAW_SPACER); + + Format(sBuffer, sizeof(sBuffer), "So make sure to stack with Stack Master as long as you can!"); + hNotifyPanel.DrawItem(sBuffer, ITEMDRAW_RAWLINE); + + hNotifyPanel.DrawItem("", ITEMDRAW_SPACER); + hNotifyPanel.DrawItem("", ITEMDRAW_SPACER); + hNotifyPanel.DrawItem("1. Got it!", ITEMDRAW_RAWLINE); + + hNotifyPanel.SetKeys(1023); + hNotifyPanel.Send(client, MenuHandler_NotifyPanel, 0); + delete hNotifyPanel; +} + +public int MenuHandler_NotifyPanel(Handle menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_Select, MenuAction_Cancel: + delete menu; + } +}*/ + +public Action WhoIsVIP(int client, int args) +{ + if(g_iVIPClient == -1) + CReplyToCommand(client, "{cyan}[UNLOZE StackMode]{lightgreen} There currently is no Stack Master!"); + else + CReplyToCommand(client, "{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the current Stack Master! Stay near him or you will lose HP.", g_iVIPClient); + + if(g_iVIPClientTwo != -1) + CReplyToCommand(client, "{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the 2nd Stack Master! Stay near him or you will lose HP.", g_iVIPClientTwo); + + return Plugin_Handled; +} + +public void ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn) +{ + if(motherInfect && g_bmotherInfect == false) + { + g_bmotherInfect = true; + CreateTimer(5.0, SelectVIP, _, TIMER_FLAG_NO_MAPCHANGE); + } +} + +public Action OnRoundEnd(Event event, const char[] name, bool dontBroadcast) +{ + g_iVIPClient = -1; + g_iVIPClientTwo = -1; + g_bmotherInfect = false; + KillAllBeacons(); +} + +public Action SelectVIP(Handle timer) +{ + PerformVIPSelection(false); +} + +public void CreateBeacon(int client) +{ + g_BeaconSerial[client] = ++g_Serial_Gen; + CreateTimer(1.0, Timer_Beacon, client | (g_Serial_Gen << 7), TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); +} + +public void KillBeacon(int client) +{ + g_BeaconSerial[client] = 0; + + if(IsClientInGame(client)) + SetEntityRenderColor(client, 255, 255, 255, 255); +} + +public void KillAllBeacons() +{ + for(int i = 1; i <= MaxClients; i++) + KillBeacon(i); +} + +public void PerformBeacon(int client) +{ + CreateBeacon(client); +} + +public Action Timer_Beacon(Handle timer, any value) +{ + int client = value & 0x7f; + int serial = value >> 7; + + if(!IsClientInGame(client) || !IsPlayerAlive(client) || g_BeaconSerial[client] != serial) + { + KillBeacon(client); + return Plugin_Stop; + } + + float vec[3]; + GetClientAbsOrigin(client, vec); + vec[2] += 10; + + TE_SetupBeamRingPoint(vec, 10.0, g_fAuraRange - 10.0, g_BeamSprite, g_HaloSprite, 0, 15, 0.5, 5.0, 0.0, greyColor, 10, 0); + TE_SendToAll(); + + int rainbowColor[4]; + float i = GetGameTime(); + float Frequency = 2.5; + rainbowColor[0] = RoundFloat(Sine(Frequency * i + 0.0) * 127.0 + 128.0); + rainbowColor[1] = RoundFloat(Sine(Frequency * i + 2.0943951) * 127.0 + 128.0); + rainbowColor[2] = RoundFloat(Sine(Frequency * i + 4.1887902) * 127.0 + 128.0); + rainbowColor[3] = 255; + + TE_SetupBeamRingPoint(vec, 10.0, g_fAuraRange - 10.0, g_BeamSprite, g_HaloSprite, 0, 10, 0.6, 10.0, 0.5, rainbowColor, 10, 0); + + TE_SendToAll(); + + GetClientEyePosition(client, vec); + + return Plugin_Continue; +} + +public int AttachSprite(int client) +{ + if(!IsPlayerAlive(client)) + { + return -1; + } + + char iTarget[16], sTargetname[64]; + GetEntPropString(client, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname)); + + Format(iTarget, sizeof(iTarget), "Client%d", client); + DispatchKeyValue(client, "targetname", iTarget); + + float Origin[3]; + GetClientEyePosition(client, Origin); + Origin[2] += 45.0; + + int Ent = CreateEntityByName("env_sprite"); + if(!Ent) return -1; + + DispatchKeyValue(Ent, "model", "materials/nide/follow.vmt"); + DispatchKeyValue(Ent, "classname", "env_sprite"); + DispatchKeyValue(Ent, "spawnflags", "1"); + DispatchKeyValue(Ent, "scale", "0.1"); + DispatchKeyValue(Ent, "rendermode", "1"); + DispatchKeyValue(Ent, "rendercolor", "255 255 255"); + DispatchSpawn(Ent); + TeleportEntity(Ent, Origin, NULL_VECTOR, NULL_VECTOR); + SetVariantString(iTarget); + AcceptEntityInput(Ent, "SetParent", Ent, Ent, 0); + + DispatchKeyValue(client, "targetname", sTargetname); + + return Ent; +} + +public void RemoveSprite(int client) +{ + if (spriteEntities[client] != -1 && IsValidEdict(spriteEntities[client])) + { + char m_szClassname[64]; + GetEdictClassname(spriteEntities[client], m_szClassname, sizeof(m_szClassname)); + if(strcmp("env_sprite", m_szClassname)==0) + AcceptEntityInput(spriteEntities[client], "Kill"); + } + + spriteEntities[client] = -1; +} + +public Action Timer_AuraAroundVIP(Handle timer, any value) +{ + if(g_iVIPClient == -1) + return Plugin_Continue; + + new Float:fVec1[3]; + new Float:fVec2[3]; + GetClientAbsOrigin(g_iVIPClient, fVec1); + + if(g_iVIPClientTwo == -1) + { + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client) && IsPlayerAlive(client) && ZR_IsClientHuman(client)) + { + GetClientAbsOrigin(client, fVec2); + + if(GetVectorDistance(fVec1, fVec2, false) <= g_fAuraRange) + { + if(GetClientHealth(client) < 125) + { + int health = GetClientHealth(client); + SetEntityHealth(client, health + g_iHealTick); + + if(GetClientHealth(client) > 125) //prevent hp over 125 + SetEntityHealth(client, 125); + } + } + else + { + int health = GetClientHealth(client); + SetEntityHealth(client, health - g_iDamageTick); + + //CPrintToChat(client, "{cyan}UNLOZE StackMode: {lightgreen} Warning! You are losing HP for not being close to the Stack Master."); + PrintCenterText(client, "UNLOZE StackMode: Warning! You are losing HP for not being close to the Stack Master."); + + if(GetClientHealth(client) < 1) + { + ForcePlayerSuicide(client); + CPrintToChat(client, "{cyan}[UNLOZE StackMode] {lightgreen} You died being far away from the Stack Master for too long!"); + } + } + } + } + } + else + { + new Float:fVec3[3]; + GetClientAbsOrigin(g_iVIPClientTwo, fVec3); + + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client) && IsPlayerAlive(client) && ZR_IsClientHuman(client)) + { + GetClientAbsOrigin(client, fVec2); + + if(GetVectorDistance(fVec1, fVec2, false) <= g_fAuraRange || GetVectorDistance(fVec3, fVec2, false) <= g_fAuraRange) + { + if(GetClientHealth(client) < 125) + { + int health = GetClientHealth(client); + SetEntityHealth(client, health + g_iHealTick); + + if(GetClientHealth(client) > 125) //prevent hp over 125 + SetEntityHealth(client, 125); + } + } + else + { + int health = GetClientHealth(client); + SetEntityHealth(client, health - g_iDamageTick); + + //CPrintToChat(client, "{cyan}UNLOZE StackMode: {lightgreen} Warning! You are losing HP for not being close to the Stack Master."); + PrintCenterText(client, "UNLOZE StackMode: Warning! You are losing HP for not being close to one the Stack Masters."); + + if(GetClientHealth(client) < 1) + { + ForcePlayerSuicide(client); + CPrintToChat(client, "{cyan}[UNLOZE StackMode] {lightgreen} You died being far away from the Stack Masters for too long!"); + } + } + } + } + } + + return Plugin_Continue; +} + +public void PerformVIPSelection(bool reselect) +{ + int PotentialVIPCount; + int PotentialVIPClient[64]; + + for (int client = 1; client <= MaxClients; client++) + { + if (IsClientInGame(client) && IsPlayerAlive(client) && ZR_IsClientHuman(client)) + { + if(IsFakeClient(client)) + continue; + + if(g_iVIPClientTwo == client) //prevent 2nd vip to be chosen twice + continue; + + PotentialVIPClient[PotentialVIPCount] = client; + PotentialVIPCount++; + } + } + + if(PotentialVIPCount < 1) + { + CPrintToChatAll("{cyan}[UNLOZE StackMode]{lightgreen} Couldn't find a valid client to set as Stack Master. Aborting on this round."); + + if(g_iVIPClientTwo != -1) + { + KillBeacon(g_iVIPClientTwo); + RemoveSprite(g_iVIPClientTwo); + g_iVIPClientTwo = -1; + } + + return; + } + + g_iVIPClient = PotentialVIPClient[GetRandomInt(0, PotentialVIPCount - 1)]; + + PerformBeacon(g_iVIPClient); + spriteEntities[g_iVIPClient] = AttachSprite(g_iVIPClient); + + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the current Stack Master! Stay near him or you will lose HP.", g_iVIPClient); + + if (!reselect) + { + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the current Stack Master! Stay near him or you will lose HP.", g_iVIPClient); + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the current Stack Master! Stay near him or you will lose HP.", g_iVIPClient); + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the current Stack Master! Stay near him or you will lose HP.", g_iVIPClient); + } + + if(g_bDoubleVIP == true && !reselect) + CreateTimer(5.0, Select2ndVIP, _, TIMER_FLAG_NO_MAPCHANGE); +} + +public Action Select2ndVIP(Handle timer) +{ + Perform2ndVIPSelection(false); +} + +public void Perform2ndVIPSelection(bool reselect) +{ + int PotentialVIPCount; + int PotentialVIPClient[64]; + + for (int client = 1; client <= MaxClients; client++) + { + if (IsClientInGame(client) && IsPlayerAlive(client) && ZR_IsClientHuman(client)) + { + if(IsFakeClient(client)) + continue; + + if(g_iVIPClient == client) //prevent 1st vip to be chosen twice + continue; + + PotentialVIPClient[PotentialVIPCount] = client; + PotentialVIPCount++; + } + } + + if(PotentialVIPCount < 1) + { + CPrintToChatAll("{cyan}[UNLOZE StackMode]{lightgreen} Couldn't find a valid client to set as 2nd Stack Master. Sticking with only one Stack Master for this round."); + return; + } + + g_iVIPClientTwo = PotentialVIPClient[GetRandomInt(0, PotentialVIPCount - 1)]; + + PerformBeacon(g_iVIPClientTwo); + spriteEntities[g_iVIPClientTwo] = AttachSprite(g_iVIPClientTwo); + + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the 2nd Stack Master! Stay near him or you will lose HP.", g_iVIPClientTwo); + + if (!reselect) + { + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the 2nd Stack Master! Stay near him or you will lose HP.", g_iVIPClientTwo); + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the 2nd Stack Master! Stay near him or you will lose HP.", g_iVIPClientTwo); + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the 2nd Stack Master! Stay near him or you will lose HP.", g_iVIPClientTwo); + } +} + +public Action PerformAdminVIPSelection(int client, int args) +{ + if(g_iVIPClient == -1) + { + CReplyToCommand(client, "{cyan}[UNLOZE StackMode]{lightgreen} You can't choose a Stack Master yet."); + return Plugin_Handled; + } + + int iOldVIP = g_iVIPClient; + + if(args < 1) + { + int PotentialVIPCount; + int PotentialVIPClient[64]; + + for (int player = 1; player <= MaxClients; player++) + { + if (IsClientInGame(player) && IsPlayerAlive(player) && ZR_IsClientHuman(player)) + { + if(IsFakeClient(player)) + continue; + + if(iOldVIP == player) //prevent same dude to be chosen again + continue; + + if(g_iVIPClientTwo == player) //prevent 2nd vip to be chosen twice + continue; + + PotentialVIPClient[PotentialVIPCount] = player; + PotentialVIPCount++; + } + } + + KillBeacon(g_iVIPClient); + RemoveSprite(g_iVIPClient); + + g_iVIPClient = -1; + + if(PotentialVIPCount < 1) + { + CPrintToChatAll("{cyan}[UNLOZE StackMode]{lightgreen} Couldn't find a valid client to set as Stack Master. Aborting on this round."); + + if(g_iVIPClientTwo != -1) + { + KillBeacon(g_iVIPClientTwo); + RemoveSprite(g_iVIPClientTwo); + g_iVIPClientTwo = -1; + } + + return Plugin_Handled; + } + + g_iVIPClient = PotentialVIPClient[GetRandomInt(0, PotentialVIPCount - 1)]; + + PerformBeacon(g_iVIPClient); + spriteEntities[g_iVIPClient] = AttachSprite(g_iVIPClient); + + ReplyToCommand(client, "[SM] You have randomly chosen another Stack Master."); + PrintToChatAll("[SM] %N randomly chose another Stack Master!", client); + + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the current Stack Master! Stay near him or you will lose HP.", g_iVIPClient); + } + else + { + int target; + char sArguments[64]; + GetCmdArg(1, sArguments, sizeof(sArguments)); + if((target = FindTarget(client, sArguments, true)) == -1) + return Plugin_Handled; + + if(!IsPlayerAlive(target)) + { + ReplyToCommand(client, "[SM] The target has to be alive!"); + return Plugin_Handled; + } + + if(!ZR_IsClientHuman(target)) + { + ReplyToCommand(client, "[SM] The target has to be a Human!"); + return Plugin_Handled; + } + + if(target == iOldVIP) + { + ReplyToCommand(client, "[SM] Don't be silly. You can't choose the same Stack Master again!"); + return Plugin_Handled; + } + + KillBeacon(g_iVIPClient); + RemoveSprite(g_iVIPClient); + + g_iVIPClient = -1; //kinda obsolete to set -1 here o.O + + g_iVIPClient = target; + + PerformBeacon(g_iVIPClient); + spriteEntities[g_iVIPClient] = AttachSprite(g_iVIPClient); + + ReplyToCommand(client, "[SM] You have chosen %N as Stack Master.", g_iVIPClient); + PrintToChatAll("[SM] %N chose %N as Stack Master!", client, g_iVIPClient); + + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the current Stack Master! Stay near him or you will lose HP.", g_iVIPClient); + } + + return Plugin_Handled; +} + +public Action PerformAdmin2ndVIPSelection(int client, int args) +{ + if(g_bDoubleVIP == false) + { + CReplyToCommand(client, "{cyan}[UNLOZE StackMode]{lightgreen} Two Stack Masters Mode is disabled on this round."); + return Plugin_Handled; + } + + if(g_iVIPClientTwo == -1) + { + CReplyToCommand(client, "{cyan}[UNLOZE StackMode]{lightgreen} You can't choose a 2nd Stack Master yet."); + return Plugin_Handled; + } + + int iOldVIP = g_iVIPClientTwo; + + if(args < 1) + { + int PotentialVIPCount; + int PotentialVIPClient[64]; + + for (int player = 1; player <= MaxClients; player++) + { + if (IsClientInGame(player) && IsPlayerAlive(player) && ZR_IsClientHuman(player)) + { + if(IsFakeClient(player)) + continue; + + if(iOldVIP == player) //prevent same dude to be chosen again + continue; + + if(g_iVIPClient == player) //prevent 1st vip to be chosen twice + continue; + + PotentialVIPClient[PotentialVIPCount] = player; + PotentialVIPCount++; + } + } + + KillBeacon(g_iVIPClientTwo); + RemoveSprite(g_iVIPClientTwo); + + g_iVIPClientTwo = -1; + + if(PotentialVIPCount < 1) + { + CPrintToChatAll("{cyan}[UNLOZE StackMode]{lightgreen} Couldn't find a valid client to set as 2nd Stack Master. Sticking with only one Stack Master for this round."); + return Plugin_Handled; + } + + g_iVIPClientTwo = PotentialVIPClient[GetRandomInt(0, PotentialVIPCount - 1)]; + + PerformBeacon(g_iVIPClientTwo); + spriteEntities[g_iVIPClientTwo] = AttachSprite(g_iVIPClientTwo); + + ReplyToCommand(client, "[SM] You have randomly chosen another 2nd Stack Master."); + PrintToChatAll("[SM] %N randomly chose another 2nd Stack Master!", client); + + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the 2nd Stack Master! Stay near him or you will lose HP.", g_iVIPClientTwo); + } + else + { + int target; + char sArguments[64]; + GetCmdArg(1, sArguments, sizeof(sArguments)); + if((target = FindTarget(client, sArguments, true)) == -1) + return Plugin_Handled; + + if(!IsPlayerAlive(target)) + { + ReplyToCommand(client, "[SM] The target has to be alive!"); + return Plugin_Handled; + } + + if(!ZR_IsClientHuman(target)) + { + ReplyToCommand(client, "[SM] The target has to be a Human!"); + return Plugin_Handled; + } + + if(target == iOldVIP) + { + ReplyToCommand(client, "[SM] Don't be silly. You can't choose the same 2nd Stack Master again!"); + return Plugin_Handled; + } + + KillBeacon(g_iVIPClientTwo); + RemoveSprite(g_iVIPClientTwo); + + g_iVIPClientTwo = -1; //kinda obsolete to set -1 here o.O + + g_iVIPClientTwo = target; + + PerformBeacon(g_iVIPClientTwo); + spriteEntities[g_iVIPClientTwo] = AttachSprite(g_iVIPClientTwo); + + ReplyToCommand(client, "[SM] You have chosen %N as 2nd Stack Master.", g_iVIPClientTwo); + PrintToChatAll("[SM] %N chose %N as 2nd Stack Master!", client, g_iVIPClientTwo); + + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the 2nd Stack Master! Stay near him or you will lose HP.", g_iVIPClientTwo); + } + + return Plugin_Handled; +} + +public Action OnPlayerDeath(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(GetEventInt(event, "userid")); + + if(client == g_iVIPClient) + { + KillBeacon(g_iVIPClient); + RemoveSprite(g_iVIPClient); + + g_iVIPClient = -1; + + int PotentialVIPCount; + int PotentialVIPClient[64]; + + for (int player = 1; player <= MaxClients; player++) + { + if (IsClientInGame(player) && IsPlayerAlive(player) && ZR_IsClientHuman(player)) + { + if(IsFakeClient(player)) + continue; + + if(g_iVIPClientTwo == player) //prevent 2nd vip to be chosen twice + continue; + + PotentialVIPClient[PotentialVIPCount] = player; + PotentialVIPCount++; + } + } + + if(PotentialVIPCount < 1) + { + CPrintToChatAll("{cyan}[UNLOZE StackMode]{lightgreen} Couldn't find a valid client to set as Stack Master. Aborting on this round."); + + if(g_iVIPClientTwo != -1) + { + KillBeacon(g_iVIPClientTwo); + g_iVIPClientTwo = -1; + } + + return Plugin_Handled; + } + + g_iVIPClient = PotentialVIPClient[GetRandomInt(0, PotentialVIPCount - 1)]; + + PerformBeacon(g_iVIPClient); + spriteEntities[g_iVIPClient] = AttachSprite(g_iVIPClient); + + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the current Stack Master! Stay near him or you will lose HP.", g_iVIPClient); + } + + if(client == g_iVIPClientTwo) + { + KillBeacon(g_iVIPClientTwo); + RemoveSprite(g_iVIPClientTwo); + + g_iVIPClientTwo = -1; + + int PotentialVIPCount; + int PotentialVIPClient[64]; + + for (int player = 1; player <= MaxClients; player++) + { + if (IsClientInGame(player) && IsPlayerAlive(player) && ZR_IsClientHuman(player)) + { + if(IsFakeClient(player)) + continue; + + if(g_iVIPClient == player) //prevent 1st vip to be chosen twice + continue; + + PotentialVIPClient[PotentialVIPCount] = player; + PotentialVIPCount++; + } + } + + if(PotentialVIPCount < 1) + { + CPrintToChatAll("{cyan}[UNLOZE StackMode]{lightgreen} Couldn't find a valid client to set as 2nd Stack Master. Sticking with only one Stack Master for this round."); + return Plugin_Handled; + } + + g_iVIPClientTwo = PotentialVIPClient[GetRandomInt(0, PotentialVIPCount - 1)]; + + PerformBeacon(g_iVIPClientTwo); + spriteEntities[g_iVIPClientTwo] = AttachSprite(g_iVIPClientTwo); + + CPrintToChatAll("{cyan}[UNLOZE StackMode] {white}%N{lightgreen} is the 2nd Stack Master! Stay near him or you will lose HP.", g_iVIPClientTwo); + } + + return Plugin_Handled; +} + +public void OnClientDisconnect(int client) +{ + if(client == g_iVIPClient) + { + KillBeacon(g_iVIPClient); + RemoveSprite(g_iVIPClient); + g_iVIPClient = -1; + PerformVIPSelection(true); + } + + if(client == g_iVIPClientTwo) + { + KillBeacon(g_iVIPClientTwo); + RemoveSprite(g_iVIPClientTwo); + g_iVIPClientTwo = -1; + Perform2ndVIPSelection(true); + } +} + +public Action OnPlayerTeam(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(GetEventInt(event, "userid")); + + if(client == g_iVIPClient) + { + KillBeacon(g_iVIPClient); + RemoveSprite(g_iVIPClient); + g_iVIPClient = -1; + RequestFrame(RequestFrame_Callback); + } + + if(client == g_iVIPClientTwo) + { + KillBeacon(g_iVIPClientTwo); + RemoveSprite(g_iVIPClientTwo); + g_iVIPClientTwo = -1; + RequestFrame(RequestFrame_Callback2); + } +} + +public void OnPlayerSwitchedToSpectateByCommand(int client) +{ + if(client == g_iVIPClient) + { + KillBeacon(g_iVIPClient); + RemoveSprite(g_iVIPClient); + g_iVIPClient = -1; + RequestFrame(RequestFrame_Callback); + } + + if(client == g_iVIPClientTwo) + { + KillBeacon(g_iVIPClientTwo); + RemoveSprite(g_iVIPClientTwo); + g_iVIPClientTwo = -1; + RequestFrame(RequestFrame_Callback2); + } +} + +public void RequestFrame_Callback(int iPacked) +{ + PerformVIPSelection(true); +} + +public void RequestFrame_Callback2(int iPacked) +{ + Perform2ndVIPSelection(true); +} \ No newline at end of file