using System.Drawing; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using Cs2SuperPowers.Players; using Cs2SuperPowers.Players.PlayerValidations; namespace Cs2SuperPowers.Powers; public class Ghost(IPlayerHud playerHud) : BasePower(playerHud) { public override int Id => 7; public override string Name => "The Ghost"; public override string Description => $"You are invisible to other players - but will show up for few seconds after you will take/give damage."; public override char ChatColor => ChatColors.White; private readonly Random _random = new Random(); public override string HtmlColor => "#FFFFFF"; public override int MinimumPlayersRequired => 4; private readonly Dictionary _visibilityTokens = new(); protected override void OnInitialize() { RegisterEventHandler(OnRoundStart); RegisterEventHandler(OnPlayerHurt); RegisterEventHandler(OnRoundEnd); } private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) { foreach (var player in PlayerPowers.Instance.GetPlayersWithPower(this)) { _visibilityTokens[player.SteamID] = _visibilityTokens.GetValueOrDefault(player.SteamID) + 1; NextFrame(() => { SetPlayerVisibility(player, true); }); } return HookResult.Continue; } private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) { var validPlayersWithPower = PlayerPowers.Instance .GetPlayersWithPower(this) .Where(player => Ensure.Player(player).IsValid().Check()); foreach (var player in validPlayersWithPower) { NextFrame(() => { SetPlayerVisibility(player, false); }); } return HookResult.Continue; } public override void UnassignFromPlayer(CCSPlayerController player) { base.UnassignFromPlayer(player); NextFrame(() => { SetPlayerVisibility(player, true); }); } private HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) { var attacker = @event.Attacker; var victim = @event.Userid; if (!Ensure.Player(victim).IsValid().IsAlive().Check() || !Ensure.Player(attacker).IsValid().Check()) { return HookResult.Continue; } // Check for at least 4 valid (non-spectator, non-none) players total var validPlayerCount = Utilities.GetPlayers().Count(p => p.IsValid && p.Team != CsTeam.None && p.Team != CsTeam.Spectator); if (validPlayerCount < 4) { return HookResult.Continue; } if (IsAssignedTo(victim!)) { RevealGhostTemporarily(victim!); } else if (IsAssignedTo(attacker!)) { RevealGhostTemporarily(attacker!); } return HookResult.Continue; } private void RevealGhostTemporarily(CCSPlayerController player) { if (!Ensure.Player(player).IsValid().IsAlive().Check()) { return; } var token = _visibilityTokens.GetValueOrDefault(player.SteamID) + 1; _visibilityTokens[player.SteamID] = token; SetPlayerVisibility(player, true); AddTimer(_random.Next(1, 5), () => { if (!IsAssignedTo(player) || _visibilityTokens.GetValueOrDefault(player.SteamID) != token) { return; } SetPlayerVisibility(player, false); }); } private void SetPlayerVisibility(CCSPlayerController player, bool visible) { if (!IsAssignedTo(player) && !visible) { return; } var playerPawn = player.PlayerPawn.Value; if (playerPawn != null) { var color = visible ? Color.FromArgb(255, 255, 255, 255) : Color.FromArgb(0, 255, 255, 255); var shadowStrength = visible ? 1.0f : 0.0f; playerPawn.Render = color; playerPawn.ShadowStrength = shadowStrength; Utilities.SetStateChanged(playerPawn, "CBaseModelEntity", "m_clrRender"); var activeWeapon = playerPawn.WeaponServices?.ActiveWeapon.Value; if (activeWeapon != null && activeWeapon.IsValid) { activeWeapon.Render = color; activeWeapon.ShadowStrength = shadowStrength; Utilities.SetStateChanged(activeWeapon, "CBaseModelEntity", "m_clrRender"); } var skeleton = playerPawn.CBodyComponent?.SceneNode?.GetSkeletonInstance(); if (skeleton != null) { skeleton.MaterialGroup.Value = visible ? (uint)0 : 1; } var myWeapons = playerPawn.WeaponServices?.MyWeapons; if (myWeapons != null) { foreach (var gun in myWeapons) { var weapon = gun.Value; if (weapon != null) { weapon.Render = color; weapon.ShadowStrength = shadowStrength; Utilities.SetStateChanged(weapon, "CBaseModelEntity", "m_clrRender"); } } } var myWearables = playerPawn.MyWearables; if (myWearables != null) { foreach (var wearableHandle in myWearables) { var wearable = wearableHandle.Value; if (wearable == null || !wearable.IsValid) { continue; } wearable.Render = color; wearable.ShadowStrength = shadowStrength; Utilities.SetStateChanged(wearable, "CBaseModelEntity", "m_clrRender"); } } } } }