feat: add BasePower abstraction
This commit is contained in:
+192
@@ -0,0 +1,192 @@
|
||||
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<ulong, int> _visibilityTokens = new();
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
RegisterEventHandler<EventRoundStart>(OnRoundStart);
|
||||
RegisterEventHandler<EventPlayerHurt>(OnPlayerHurt);
|
||||
RegisterEventHandler<EventRoundEnd>(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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user