feat: add BasePower abstraction

This commit is contained in:
admin
2026-07-26 23:47:38 +02:00
commit 6dbbfc0dde
83 changed files with 7587 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Utils;
using Cs2SuperPowers.Players;
using Cs2SuperPowers.Players.PlayerValidations;
using Microsoft.Extensions.Logging;
namespace Cs2SuperPowers.Powers;
public class BlindingLight(IPlayerHud playerHud) : BasePower(playerHud)
{
public override int Id => 22;
public override string Name => "Blinding Light";
public override string Description => $"Inflict a blinding flash of light that disorients enemies. Press E (Use) to activate the power.";
public override char ChatColor => ChatColors.BlueGrey;
public override string HtmlColor => "#cdcece";
private readonly List<BlindingLightInfo> _registrations = new();
private const int SecondsBetweenActivations = 8;
public override void AssignToPlayer(CCSPlayerController player, bool showMessages)
{
base.AssignToPlayer(player, showMessages);
if (!_registrations.Any(r => r.Player == player))
{
_registrations.Add(new BlindingLightInfo(player, DateTime.MinValue));
}
Plugin!.Logger.LogInformation("BlindingLight assigned to {PlayerName} ({SteamID})", player.PlayerName, player.SteamID);
}
public override void UnassignFromPlayer(CCSPlayerController player)
{
base.UnassignFromPlayer(player);
var registration = _registrations.FirstOrDefault(r => r.Player == player);
if (registration != null)
{
_registrations.Remove(registration);
}
Plugin!.Logger.LogInformation("BlindingLight unassigned from {PlayerName} ({SteamID})", player.PlayerName, player.SteamID);
}
protected override void OnInitialize()
{
RegisterListener<Listeners.OnTick>(OnTick);
RegisterEventHandler<EventRoundStart>(OnRoundStart);
RegisterEventHandler<EventPlayerDeath>(OnPlayerDeath);
Plugin!.Logger.LogInformation("BlindingLight initialized!");
}
private HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
{
var player = @event.Userid;
var registration = _registrations
.FirstOrDefault(r => r.Player == player);
if (registration != null)
{
registration.WasUsePressedLastTick = false;
}
return HookResult.Continue;
}
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info)
{
_registrations.Clear();
foreach (var player in PlayerPowers.Instance.GetPlayersWithPower(this))
{
_registrations.Add(new BlindingLightInfo(player, DateTime.MinValue));
}
Plugin!.Logger.LogInformation("BlindingLight: Round start, registered {Count} players", _registrations.Count);
return HookResult.Continue;
}
private void OnTick()
{
foreach (var registration in _registrations.ToList())
{
if (!Ensure.Player(registration.Player).IsValid().Check())
{
_registrations.Remove(registration);
continue;
}
var usePressed = registration.Player.Buttons.HasFlag(PlayerButtons.Use);
var canUsePower = (DateTime.UtcNow - registration.LastUse).TotalSeconds > SecondsBetweenActivations;
if (usePressed && !registration.WasUsePressedLastTick)
{
Plugin!.Logger.LogInformation("BlindingLight: {PlayerName} pressed use! CanUse: {CanUse}", registration.Player.PlayerName, canUsePower);
if (canUsePower)
{
ActivatePower(registration);
}
else
{
var secondsBeforeNextUse =
SecondsBetweenActivations - (int)(DateTime.UtcNow - registration.LastUse).TotalSeconds;
registration.Player
.PrintToCenterAlert($"You need to wait {ChatColors.DarkRed}{secondsBeforeNextUse} {ChatColors.Default}seconds before using the power.");
}
}
registration.WasUsePressedLastTick = usePressed;
}
}
private void ActivatePower(BlindingLightInfo registration)
{
// Check for at least 1 player in the opposing team
var playerTeam = registration.Player.Team;
var enemyCount = Utilities.GetPlayers().Count(p =>
p.IsValid && p.Team != CsTeam.None && p.Team != CsTeam.Spectator && p.Team != playerTeam);
Plugin!.Logger.LogInformation("BlindingLight: Activating for {PlayerName}, enemy count: {EnemyCount}", registration.Player.PlayerName, enemyCount);
if (enemyCount < 1)
{
return;
}
var flashProjectile = Utilities.CreateEntityByName<CFlashbangProjectile>("flashbang_projectile");
if (flashProjectile == null || !flashProjectile.IsValid)
{
Plugin!.Logger.LogError("BlindingLight: Failed to create flashbang projectile!");
return;
}
var player = registration.Player;
var pos = player.PlayerPawn.Value!.AbsOrigin;
pos!.Z += 10;
flashProjectile.TicksAtZeroVelocity = 100;
flashProjectile.TeamNum = player.TeamNum;
flashProjectile.Teleport(pos, null, new Vector(0, 0, -10));
flashProjectile.DispatchSpawn();
flashProjectile.AcceptInput("InitializeSpawnFromWorld", player.PlayerPawn.Value, player.PlayerPawn.Value);
flashProjectile.DetonateTime = 0;
Plugin!.Logger.LogInformation("BlindingLight: Flashbang created and detonated!");
registration.UpdateUse();
}
}
public record BlindingLightInfo(CCSPlayerController Player, DateTime LastUse)
{
public DateTime LastUse { get; private set; } = LastUse;
public bool WasUsePressedLastTick { get; set; } = false;
public void UpdateUse()
{
LastUse = DateTime.UtcNow;
}
}