using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using Cs2SuperPowers.Players; namespace Cs2SuperPowers.Powers; public class Jetpack(IPlayerHud playerHud) : BasePower(playerHud) { private const float MaxFuel = 180.0f; private const float FuelBurnPerTick = 0.8f; private const float FuelRechargePerTick = 0.9f; private const float LiftPerTick = 14.0f; private const float MaxVerticalSpeed = 260.0f; private static readonly TimeSpan HudRefreshInterval = TimeSpan.FromMilliseconds(125); public override int Id => 33; public override string Name => "Jetpack"; public override string Description => "Hold Jump (Space) to fly with a fuel-based jetpack."; public override char ChatColor => ChatColors.Orange; public override string HtmlColor => "#FF8C00"; private readonly Dictionary _fuelByPlayer = new(); private readonly Dictionary _lastHudUpdate = new(); protected override void OnInitialize() { RegisterListener(OnTick); RegisterEventHandler(OnRoundStart); } private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) { _fuelByPlayer.Clear(); _lastHudUpdate.Clear(); return HookResult.Continue; } public override void AssignToPlayer(CCSPlayerController player, bool showMessages) { base.AssignToPlayer(player, showMessages); _fuelByPlayer[player] = MaxFuel; _lastHudUpdate.Remove(player); } public override void UnassignFromPlayer(CCSPlayerController player) { base.UnassignFromPlayer(player); _fuelByPlayer.Remove(player); _lastHudUpdate.Remove(player); } private void OnTick() { foreach (var player in Utilities.GetPlayers()) { if (!player.IsValid || !player.PawnIsAlive) continue; if (!IsAssignedTo(player)) continue; var pawn = player.PlayerPawn.Value; if (pawn == null || !pawn.IsValid) continue; float fuel = _fuelByPlayer.GetValueOrDefault(player, MaxFuel); bool isJumpPressed = player.Buttons.HasFlag(PlayerButtons.Jump); if (isJumpPressed && fuel > 0.0f) { var currentVelocity = pawn.AbsVelocity; currentVelocity.Z = Math.Min(currentVelocity.Z + LiftPerTick, MaxVerticalSpeed); pawn.Teleport(pawn.AbsOrigin, null, currentVelocity); fuel = Math.Max(0.0f, fuel - FuelBurnPerTick); } else { fuel = Math.Min(MaxFuel, fuel + FuelRechargePerTick); } _fuelByPlayer[player] = fuel; if (isJumpPressed) { var now = DateTime.UtcNow; if (!_lastHudUpdate.TryGetValue(player, out var lastHudUpdate) || now - lastHudUpdate >= HudRefreshInterval) { _lastHudUpdate[player] = now; player.PrintToCenterHtml(BuildFuelMessage(fuel)); } } } } private static string BuildFuelMessage(float fuel) { int percent = (int)MathF.Round((fuel / MaxFuel) * 100.0f); int filledBars = (int)MathF.Round((fuel / MaxFuel) * 10.0f); filledBars = Math.Clamp(filledBars, 0, 10); string bar = new string('|', filledBars).PadRight(10, '.'); string color = percent > 60 ? "#4CAF50" : percent > 30 ? "#FFC107" : "#F44336"; return $"Jetpack Fuel: {percent}%
{bar}"; } }