using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using Cs2SuperPowers.Players; using Cs2SuperPowers.Players.PlayerValidations; namespace Cs2SuperPowers.Powers; public class DoubleJump(IPlayerHud playerHud) : BasePower(playerHud) { public override int Id => 28; public override string Name => "Double Jump"; public override string Description => "Jump again in mid-air! A classic double jump ability."; public override char ChatColor => ChatColors.Blue; public override string HtmlColor => "#0000FF"; private readonly Dictionary _canDoubleJump = new(); private readonly Dictionary _wasOnGround = new(); private readonly Dictionary _requireJumpRelease = new(); protected override void OnInitialize() { RegisterListener(OnTick); RegisterEventHandler(OnRoundStart); RegisterEventHandler(OnPlayerHurt); } private HookResult OnRoundStart(EventRoundStart @event, GameEventInfo _) { _canDoubleJump.Clear(); _wasOnGround.Clear(); _requireJumpRelease.Clear(); return HookResult.Continue; } public override void AssignToPlayer(CCSPlayerController player, bool showMessages) { base.AssignToPlayer(player, showMessages); _canDoubleJump[player] = true; _wasOnGround[player] = true; _requireJumpRelease[player] = false; } public override void UnassignFromPlayer(CCSPlayerController player) { base.UnassignFromPlayer(player); _canDoubleJump.Remove(player); _wasOnGround.Remove(player); _requireJumpRelease.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; var isOnGround = pawn.GroundEntity.IsValid; var jumpPressed = player.Buttons.HasFlag(PlayerButtons.Jump); var wasOnGroundLastTick = _wasOnGround.GetValueOrDefault(player, true); if (isOnGround) { _canDoubleJump[player] = true; _requireJumpRelease[player] = false; } else if (wasOnGroundLastTick) { _canDoubleJump[player] = true; _requireJumpRelease[player] = jumpPressed; } if (!isOnGround && !jumpPressed) { _requireJumpRelease[player] = false; } if (!isOnGround && jumpPressed && !_requireJumpRelease.GetValueOrDefault(player, false) && _canDoubleJump.GetValueOrDefault(player, false)) { var velocity = pawn.AbsVelocity; velocity.Z = Math.Max(velocity.Z, 300.0f); pawn.Teleport(pawn.AbsOrigin, null, velocity); _canDoubleJump[player] = false; _requireJumpRelease[player] = true; } _wasOnGround[player] = isOnGround; } } private HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) { var victim = @event.Userid; if (!Ensure.Player(victim).IsValid().Check() || !IsAssignedTo(victim!)) { return HookResult.Continue; } bool isWorldDamage = !Ensure.Player(@event.Attacker).IsValid().Check(); bool hasNoWeapon = string.IsNullOrEmpty(@event.Weapon); if (!isWorldDamage || !hasNoWeapon) { return HookResult.Continue; } var pawn = victim!.PlayerPawn.Value; if (pawn == null || !pawn.IsValid) { return HookResult.Continue; } pawn.Health = Math.Min(pawn.MaxHealth, pawn.Health + @event.DmgHealth); return HookResult.Stop; } }