feat: add BasePower abstraction
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Cs2SuperPowers.Players;
|
||||
using Cs2SuperPowers.Players.PlayerValidations;
|
||||
using Cs2SuperPowers.Utils;
|
||||
|
||||
namespace Cs2SuperPowers.Powers;
|
||||
|
||||
public class NotSoDecoy(IPlayerHud playerHud) : BasePower(playerHud)
|
||||
{
|
||||
public override int Id => 24;
|
||||
public override string Name => "Not So Decoy";
|
||||
|
||||
public override string Description => "Decoys thrown by you spawn 20 grenades when thrown (5 second cooldown).";
|
||||
|
||||
public override char ChatColor => ChatColors.Red;
|
||||
|
||||
public override string HtmlColor => "#FF0000";
|
||||
|
||||
private readonly Dictionary<CCSPlayerController, DateTime> _lastUse = new();
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
RegisterEventHandler<EventRoundStart>(OnRoundStart);
|
||||
RegisterEventHandler<EventDecoyStarted>(OnDecoyStarted);
|
||||
}
|
||||
|
||||
private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo _)
|
||||
{
|
||||
_lastUse.Clear();
|
||||
|
||||
foreach (var player in Utilities.GetPlayers())
|
||||
{
|
||||
if (!Ensure.Player(player).IsValid().IsAlive().Check() || !IsAssignedTo(player!))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
player.GiveNamedItem("weapon_decoy");
|
||||
});
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private HookResult OnDecoyStarted(EventDecoyStarted @event, GameEventInfo _)
|
||||
{
|
||||
var player = @event.Userid;
|
||||
if (!Ensure.Player(player).IsValid().Check() || !IsAssignedTo(player!))
|
||||
{
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
// Check cooldown (skip if nodelay is enabled)
|
||||
var now = DateTime.UtcNow;
|
||||
DateTime lastUseTime = default;
|
||||
bool isOnCooldown = !GlobalConfig.NoDelayEnabled && _lastUse.TryGetValue(player!, out lastUseTime) && (now - lastUseTime).TotalSeconds < 5;
|
||||
|
||||
// Always give a new decoy, regardless of cooldown!
|
||||
player!.GiveNamedItem("weapon_decoy");
|
||||
|
||||
if (isOnCooldown)
|
||||
{
|
||||
double secondsRemaining = Math.Ceiling(5 - (now - lastUseTime).TotalSeconds);
|
||||
player.PrintToCenterAlert($"Not So Decoy is on cooldown! {ChatColors.DarkRed}{secondsRemaining}{ChatColors.Default}s remaining");
|
||||
return HookResult.Continue;
|
||||
}
|
||||
_lastUse[player!] = now;
|
||||
|
||||
var pos = new Vector(@event.X, @event.Y, @event.Z);
|
||||
|
||||
// Spawn grenades (with boost level) in a loop with random angles and velocities
|
||||
var random = new Random();
|
||||
int grenadeCount = GlobalConfig.GetNotSoDecoyCount(20);
|
||||
for (int i = 0; i < grenadeCount; i++)
|
||||
{
|
||||
// Random pitch between -45 and 45 degrees, yaw between 0 and 360
|
||||
float pitch = (float)(random.NextDouble() * 90.0 - 45.0);
|
||||
float yaw = (float)(random.NextDouble() * 360.0);
|
||||
var ang = new QAngle(pitch, yaw, 0);
|
||||
|
||||
// Random speed between 400 and 900 units
|
||||
float speed = (float)(random.NextDouble() * 500.0 + 400.0);
|
||||
|
||||
// Convert angles to a forward vector
|
||||
float pitchRad = pitch * MathF.PI / 180f;
|
||||
float yawRad = yaw * MathF.PI / 180f;
|
||||
var forward = new Vector(
|
||||
MathF.Cos(yawRad) * MathF.Cos(pitchRad),
|
||||
MathF.Sin(yawRad) * MathF.Cos(pitchRad),
|
||||
-MathF.Sin(pitchRad));
|
||||
|
||||
// Add some random upward velocity for the "jump"
|
||||
float upward = (float)(random.NextDouble() * 200.0 + 200.0);
|
||||
|
||||
var velocity = new Vector(
|
||||
forward.X * speed,
|
||||
forward.Y * speed,
|
||||
forward.Z * speed + upward);
|
||||
|
||||
var createdGrenade = GrenadeSpawner.CreateGrenade(pos, ang, velocity, player.PlayerPawn.Value);
|
||||
}
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user