v1.2.3.b2 - Part 2

## GENERAL
- Added a css_entity admin command to check whether an entity with a given index/handle exists (prints the designer name to chat or console).
- Added a TakeDamage post-hook (OnTakeDamagePost) alongside the existing pre-hook, so skills can now react after damage has actually been applied, not just before.
- Added CreateMolotovProjectile (new CMolotovProjectile_CreateFunc signature) and CreateTrackedChicken entity helpers.
- Added a weapon_mp7 → weapon_mp5sd fallback mapping.
- Added class for KillfeedIcons

## SKILL IMPROVEMENTS
- Aimbot:
  -- Only forces a headshot hitgroup once (skips if it's already a head or an invalid hitgroup), and now restores the original hitgroup value in the new post-damage hook instead of leaving it overwritten.
- Tripwire:
  -- Reduced the default wire width from 1.5 to 0.7.

## NEW SKILLS:
- Berserker: You deal more damage and move faster as your health gets lower.
- Blast Shot: Press Attack2 with the MP5 to fire an HE grenade.
- Demon Eye: You deal damage to every enemy you are looking at.
- Fire Rain: Throw a decoy to call down a rain of Molotovs.
- Flashlight: Click [css_useSkill] to turn the flashlight on or off; its light can blind enemies.
- Healing Chicken: Your chickens heal you while you are nearby.
- Jetkick: Select a player to jetkick - every shot they fire knocks them backwards until disabled.
- Last Gasp: After you die, you deal damage to the enemy who killed you.
- Take Ammo: Click [css_useSkill] to take the active weapon's magazine from a random enemy.
- Team Teleport: Press [css_useSkill] to teleport to the teammate you're looking at.
This commit is contained in:
Juzlus 2026-07-31 20:28:02 +02:00
parent 203a0c3986
commit 8038a4d646
57 changed files with 3663 additions and 553 deletions

View file

@ -1,20 +1,12 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Cvars;
using CounterStrikeSharp.API.Modules.Events;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.UserMessages;
using CounterStrikeSharp.API.Modules.Utils;
using RayTraceAPI;
using src.player.skills;
using src.utils;
using System.Collections.Concurrent;
using static CounterStrikeSharp.API.Core.Listeners;
using static src.jRandomSkills;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
namespace src.player
{
@ -106,6 +98,15 @@ namespace src.player
}
}
private static HookResult OnTakeDamagePost(DynamicHook h)
{
lock (setLock)
{
DispatchOnTakeDamage(h, true);
return HookResult.Continue;
}
}
private static HookResult OnTriggerEnter(DynamicHook hook)
{
lock (setLock)
@ -172,33 +173,6 @@ namespace src.player
}
}
private static HookResult WeaponDrop(DynamicHook hook)
{
lock (setLock)
{
CCSPlayerController player = hook.GetParam<CCSPlayerController>(0);
if (player == null || !player.IsValid)
return HookResult.Continue;
var activeSkills = Instance.SkillPlayer
.Where(p => !p.IsDrawing)
.Select(p => p.Skill.ToString())
.Distinct();
bool block = false;
foreach (string skillName in activeSkills)
{
bool? result = (bool?)Instance.SkillAction(skillName, "WeaponDrop", [hook, player]);
if (result == true)
{
block = true;
break;
}
}
return block ? HookResult.Handled : HookResult.Continue;
}
}
private static void EntitySpawned(CEntityInstance entity)
{
lock (setLock)

View file

@ -14,6 +14,7 @@ public interface ISkill
public static void TypeSkill(CCSPlayerController _, string[] __) { }
public static void OnTakeDamage(DynamicHook _) { }
public static void OnTakeDamagePost(DynamicHook _) { }
public static void OnEntitySpawned(CEntityInstance _) { }
public static void OnTick() { }
public static void CheckTransmit([CastFrom(typeof(nint))] CCheckTransmitInfoList _) { }
@ -70,8 +71,10 @@ public enum Skills
Bankrupt,
Baseball,
Behind,
Berserker,
BladeMaster,
BunnyHop,
BlastShot,
C4Camouflage,
CarefulBullets,
Catapult,
@ -83,6 +86,7 @@ public enum Skills
Deactivator,
Deaf,
DeathBomb,
DemonEye,
Disarmament,
Distancer,
Dash,
@ -95,7 +99,9 @@ public enum Skills
ExplosiveShot,
FalconEye,
FastReload,
FireRain,
Flash,
Flashlight,
Fortnite,
FragileBomb,
FriendlyFire,
@ -108,6 +114,7 @@ public enum Skills
Glue,
GodMode,
Grenadier,
HealingChicken,
HealingSmoke,
Hermit,
HolyHandGrenade,
@ -121,11 +128,13 @@ public enum Skills
Jackal,
Jammer,
Jester,
JetKick,
JumpBan,
JumpCurse,
JumpingJack,
KillerFlash,
Knockback,
LastGasp,
LifeSwap,
LongKnife,
LongZeus,
@ -176,6 +185,8 @@ public enum Skills
SoundMaker,
Spectator,
SwapPosition,
TakeAmmo,
TeamTeleport,
Teleporter,
Thief,
ThirdEye,

View file

@ -79,6 +79,7 @@ namespace src.player
Instance.HookUserMessage(208, PlayerMakeSound);
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre);
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamagePost, HookMode.Post);
Instance.RegisterEventHandler<EventBulletImpact>(BulletImpact);
@ -94,6 +95,7 @@ namespace src.player
public static void Unload()
{
TryUnhook(() => VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamage, HookMode.Pre));
TryUnhook(() => VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamagePost, HookMode.Post));
TryUnhook(() => VirtualFunctions.CBaseTrigger_StartTouchFunc.Unhook(OnTriggerEnter, HookMode.Post));
TryUnhook(() => VirtualFunctions.CBaseTrigger_EndTouchFunc.Unhook(OnTriggerExit, HookMode.Pre));
TryUnhook(() => VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Unhook(OnWeaponCanAcquire, HookMode.Pre));
@ -133,7 +135,7 @@ namespace src.player
}
}
private static void DispatchOnTakeDamage(DynamicHook h)
private static void DispatchOnTakeDamage(DynamicHook h, bool post = false)
{
object[] args = [h];
var seen = new HashSet<Skills>();
@ -149,26 +151,26 @@ namespace src.player
continue;
}
InvokeOnTakeDamage(p.Skill, h, args);
InvokeOnTakeDamage(p.Skill, h, args, post);
}
if (deferred == null) return;
foreach (var skill in deferred)
InvokeOnTakeDamage(skill, h, args);
InvokeOnTakeDamage(skill, h, args, post);
}
private static void InvokeOnTakeDamage(Skills skill, DynamicHook h, object[] args)
private static void InvokeOnTakeDamage(Skills skill, DynamicHook h, object[] args, bool post)
{
if (Config.LoadedConfig.DebugMode != true)
{
InvokeSkill(skill, "OnTakeDamage", args);
InvokeSkill(skill, post ? "OnTakeDamagePost" : "OnTakeDamage", args);
return;
}
var info = h.GetParam<CTakeDamageInfo>(1);
float before = info == null ? 0f : info.Damage;
InvokeSkill(skill, "OnTakeDamage", args);
InvokeSkill(skill, post ? "OnTakeDamagePost" : "OnTakeDamage", args);
float after = info == null ? 0f : info.Damage;
if (Math.Abs(before - after) > 0.01f)
@ -345,6 +347,33 @@ namespace src.player
}
}
private static HookResult WeaponDrop(DynamicHook hook)
{
lock (setLock)
{
CCSPlayerController player = hook.GetParam<CCSPlayerController>(0);
if (player == null || !player.IsValid)
return HookResult.Continue;
var activeSkills = Instance.SkillPlayer
.Where(p => !p.IsDrawing)
.Select(p => p.Skill.ToString())
.Distinct();
bool block = false;
foreach (string skillName in activeSkills)
{
bool? result = (bool?)Instance.SkillAction(skillName, "WeaponDrop", [hook, player]);
if (result == true)
{
block = true;
break;
}
}
return block ? HookResult.Handled : HookResult.Continue;
}
}
private static readonly Dictionary<Skills, string> _skillNames =
Enum.GetValues<Skills>().ToDictionary(s => s, s => s.ToString());
private static readonly HashSet<Skills> _activeSkillsSet = [];

View file

@ -10,6 +10,7 @@ namespace src.player.skills
public class Aimbot : ISkill
{
private const Skills skillName = Skills.Aimbot;
private static readonly ThreadLocal<Stack<(nint Address, HitGroup_t OldValue)>> _restoreStack = new(() => new Stack<(nint, HitGroup_t)>());
public static void LoadSkill()
{
@ -50,7 +51,33 @@ namespace src.player.skills
nint hitGroupData = Marshal.ReadIntPtr(hitGroupPointer, 16);
if (hitGroupData == nint.Zero) return;
Marshal.WriteInt32(hitGroupData, 56, (int)HitGroup_t.HITGROUP_HEAD);
nint address = hitGroupData + 56;
HitGroup_t oldValue = (HitGroup_t)Marshal.ReadInt32(address);
if (oldValue == HitGroup_t.HITGROUP_HEAD || oldValue == HitGroup_t.HITGROUP_INVALID) return;
_restoreStack.Value!.Push((address, oldValue));
Marshal.WriteInt32(address, (int)HitGroup_t.HITGROUP_HEAD);
}
public static void OnTakeDamagePost(DynamicHook h)
{
var info = h.GetParam<CTakeDamageInfo>(1);
if (info == null || info.Handle == nint.Zero)
return;
if (!SkillUtils.IsBulletDamage(info)) return;
if (_restoreStack.Value!.Count > 0)
{
var (address, oldValue) = _restoreStack.Value.Pop();
if (address == nint.Zero)
return;
Marshal.WriteInt32(address, (int)oldValue);
}
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff0000", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)

View file

@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
@ -57,7 +58,7 @@ namespace src.player.skills
var attackerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(attacker)?.Index ?? attacker.Index));
if (attackerInfo?.Skill != skillName) return;
SkillUtils.TakeHealth(victim!.PlayerPawn.Value, SkillsInfo.GetValue<int>(skillName, "damageDeal"), attacker, "decoy");
SkillUtils.TakeHealth(victim!.PlayerPawn.Value, SkillsInfo.GetValue<int>(skillName, "damageDeal"), attacker, KillfeedIcons.Decoy);
}
public static void OnEntitySpawned(CEntityInstance entity)

View file

@ -0,0 +1,123 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
namespace src.player.skills
{
public class Berserker : ISkill
{
private const Skills skillName = Skills.Berserker;
public static readonly ConcurrentDictionary<uint, int> jumpedPlayers = [];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"), false);
}
public static void NewRound()
{
jumpedPlayers.Clear();
}
private static float CalculateNewVelocity(CCSPlayerPawn pawn, float maxValue)
{
if (pawn!.Health <= 0) return 1f;
float healthPercentage = pawn.MaxHealth > 0
? Math.Clamp((float)pawn.Health / pawn.MaxHealth, 0f, 1f)
: 0f;
float newValue = 1f + (maxValue - 1f) * (1f - healthPercentage);
return Math.Max(1, Math.Min(maxValue, newValue));
}
public static void OnTakeDamage(DynamicHook h)
{
CEntityInstance param = h.GetParam<CEntityInstance>(0);
CTakeDamageInfo param2 = h.GetParam<CTakeDamageInfo>(1);
if (param == null || param.Entity == null || param2 == null || param2.Attacker == null || param2.Attacker.Value == null)
return;
CCSPlayerPawn attackerPawn = new(param2.Attacker.Value.Handle);
CCSPlayerPawn victimPawn = new(param.Handle);
if (attackerPawn.DesignerName != "player" || victimPawn.DesignerName != "player")
return;
if (attackerPawn == null || attackerPawn.Controller?.Value == null || victimPawn == null || victimPawn.Controller?.Value == null)
return;
CCSPlayerController attacker = PlayerManager.GetPlayerEvent(attackerPawn.Controller.Value.As<CCSPlayerController>())!;
var playerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
if (playerInfo == null) return;
if (playerInfo.Skill == skillName)
{
float damageMultiplier = CalculateNewVelocity(attackerPawn, SkillsInfo.GetValue<float>(skillName, "maxDamageVelocity"));
param2.Damage *= damageMultiplier;
}
}
public static void PlayerJump(EventPlayerJump @event)
{
var player = PlayerManager.GetPlayerEvent(@event.Userid);
if (player == null || !player.IsValid) return;
if (!jumpedPlayers.TryGetValue(player.Index, out _)) return;
jumpedPlayers.AddOrUpdate(player.Index, Server.TickCount + 20, (k, v) => Server.TickCount + 20);
}
public static void EnableSkill(CCSPlayerController player)
{
var playerPawn = player.PlayerPawn.Value;
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerPawn == null || playerInfo == null) return;
jumpedPlayers.TryAdd(player.Index, 0);
}
public static void DisableSkill(CCSPlayerController player)
{
var playerPawn = player.PlayerPawn.Value;
if (playerPawn == null) return;
playerPawn.VelocityModifier = 1;
jumpedPlayers.TryRemove(player.Index, out _);
}
public static void OnTick()
{
foreach (var player in PlayerManager.GetTickPlayers())
{
if (!Instance.IsPlayerValid(player)) continue;
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo?.Skill != skillName) continue;
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null || playerPawn.VelocityModifier == 0) continue;
var buttons = player.Buttons;
float newSpeedVelocity = CalculateNewVelocity(playerPawn, SkillsInfo.GetValue<float>(skillName, "maxSpeedVelocity"));
if (buttons.HasFlag(PlayerButtons.Moveleft) || buttons.HasFlag(PlayerButtons.Moveright) || buttons.HasFlag(PlayerButtons.Forward) || buttons.HasFlag(PlayerButtons.Back))
playerPawn.VelocityModifier = newSpeedVelocity;
if (jumpedPlayers.TryGetValue(player.Index, out var time) && time > Server.TickCount)
continue;
if (!((PlayerFlags)player.Flags).HasFlag(PlayerFlags.FL_ONGROUND))
playerPawn.AbsVelocity.Z = Math.Min(playerPawn.AbsVelocity.Z, 10);
}
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#cc2929", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float maxSpeedVelocity = 2f, float maxDamageVelocity = 2f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public float MaxSpeedVelocity { get; set; } = maxSpeedVelocity;
public float MaxDamageVelocity { get; set; } = maxDamageVelocity;
}
}
}

View file

@ -0,0 +1,217 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Cvars;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
namespace src.player.skills
{
public class BlastShot : ISkill
{
private const Skills skillName = Skills.BlastShot;
private static readonly QAngle angle = new(13, -5, 5);
private static readonly ConcurrentDictionary<int, (byte Team, uint Owner)> nades = [];
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
private static readonly string[] allowedWeapons = ["weapon_mp5sd"];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
SkillPlayerInfo.Clear();
nades.Clear();
}
public static void EnableSkill(CCSPlayerController player)
{
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
{
SteamID = player.Index,
CanUse = true,
Cooldown = DateTime.MinValue,
});
SkillUtils.TryGiveWeapon(player, CsItem.MP5SD);
}
public static void DisableSkill(CCSPlayerController player)
{
if (player == null || !player.IsValid) return;
SkillPlayerInfo.TryRemove(player.Index, out _);
}
public static void OnTick()
{
float cooldown = SkillsInfo.GetValue<float>(skillName, "cooldown");
foreach (var player in PlayerManager.GetTickPlayers())
{
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo?.Skill != skillName) continue;
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null || !playerPawn.IsValid) continue;
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) continue;
var buttons = player.Buttons;
bool isAttack2 = (buttons & PlayerButtons.Attack2) != 0;
if (skillInfo.CanUse && isAttack2)
{
var weapon = playerPawn.WeaponServices?.ActiveWeapon?.Value;
if (weapon == null || !weapon.IsValid) continue;
if (!allowedWeapons.Contains(SkillUtils.GetDesignerName(weapon))) continue;
skillInfo.CanUse = false;
skillInfo.Cooldown = DateTime.Now;
SpawnExplosion(player);
}
UpdateHUD(player, skillInfo, cooldown);
}
}
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo, float cooldownSkill)
{
float cooldown = 0;
if (skillInfo != null)
{
float time = (int)Math.Ceiling((skillInfo.Cooldown.AddSeconds(cooldownSkill) - DateTime.Now).TotalSeconds);
cooldown = Math.Max(time, 0);
if (cooldown == 0 && skillInfo?.CanUse == false)
skillInfo.CanUse = true;
}
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo == null) return;
if (cooldown == 0)
playerInfo.PrintHTML = null;
else
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
}
private static void SpawnExplosion(CCSPlayerController player)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
float force = SkillsInfo.GetValue<float>(skillName, "force");
Vector pos = new(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z + pawn.ViewOffset.Z);
Vector vel = SkillUtils.GetForwardVector(pawn.EyeAngles) * force;
SkillUtils.CreateHEGrenadeProjectile(pos, angle, vel, player.TeamNum);
nades.AddOrUpdate(Server.TickCount, (player.TeamNum, player.Index), (_, _) => (player.TeamNum, player.Index));
}
public static void OnEntitySpawned(CEntityInstance entity)
{
if (entity.DesignerName != "hegrenade_projectile") return;
var heProjectile = entity.As<CBaseCSGrenadeProjectile>();
if (heProjectile == null || !heProjectile.IsValid || heProjectile.AbsRotation == null) return;
int lastTick = Server.TickCount;
Server.NextFrame(() =>
{
if (heProjectile == null || !heProjectile.IsValid) return;
if (!(NearlyEquals(angle.X, heProjectile.AbsRotation.X) && NearlyEquals(angle.Y, heProjectile.AbsRotation.Y) && NearlyEquals(angle.Z, heProjectile.AbsRotation.Z)))
return;
heProjectile.TicksAtZeroVelocity = 100;
heProjectile.Damage = SkillsInfo.GetValue<int>(skillName, "explosionDamage");
heProjectile.DmgRadius = SkillsInfo.GetValue<float>(skillName, "explosionRadius");
if (nades.TryRemove(lastTick, out var source))
heProjectile.Globalname = $"deathbomb_team_{source.Team}_{source.Owner}_{heProjectile.Index}";
});
}
public static void OnTakeDamage(DynamicHook h)
{
CEntityInstance param = h.GetParam<CEntityInstance>(0);
CTakeDamageInfo param2 = h.GetParam<CTakeDamageInfo>(1);
if (param == null || param.Entity == null || param2 == null) return;
var nade = param2.Attacker.Value;
if (nade == null || !nade.IsValid) return;
if (nade.DesignerName != "hegrenade_projectile") return;
if (string.IsNullOrEmpty(nade.Globalname) || !nade.Globalname.StartsWith("deathbomb_team_")) return;
var parts = nade.Globalname.Split('_');
if (parts.Length < 4) return;
if (!int.TryParse(parts[2], out int nadeTeam)) return;
if (!uint.TryParse(parts[3], out uint ownerIndex)) return;
CCSPlayerPawn victimPawn = new(param.Handle);
if (victimPawn.DesignerName != "player") return;
if (victimPawn.Controller?.Value == null) return;
var victim = victimPawn.Controller.Value.As<CCSPlayerController>();
if (victim == null || !victim.IsValid || victim.Index == ownerIndex) return;
var owner = Utilities.GetPlayerFromIndex((int)ownerIndex);
if (owner != null && !owner.IsValid) owner = null;
if (victimPawn.TeamNum == nadeTeam)
{
float reduction = SkillsInfo.GetValue<float>(skillName, "dmgReductionForTeamates");
param2.Damage *= 1f - Math.Clamp(reduction, 0f, 1f);
if (IsFriendlyFireOff())
{
int teamDamage = (int)param2.Damage;
param2.Damage = 0;
if (teamDamage > 0)
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, KillfeedIcons.Explosion);
return;
}
}
if (owner != null && param2.Damage >= victimPawn.Health)
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, KillfeedIcons.Explosion);
}
private static bool IsFriendlyFireOff()
{
bool ff = ConVar.Find("mp_friendlyfire")?.GetPrimitiveValue<bool>() ?? false;
bool tae = ConVar.Find("mp_teammates_are_enemies")?.GetPrimitiveValue<bool>() ?? false;
return !ff && !tae;
}
private static bool NearlyEquals(float a, float b, float epsilon = 0.001f) => Math.Abs(a - b) < epsilon;
public class PlayerSkillInfo
{
public ulong SteamID { get; set; }
public bool CanUse { get; set; }
public DateTime Cooldown { get; set; }
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#7740c9", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float explosionRadius = 400.0f, int explosionDamage = 60, float dmgReductionForTeamates = 0.5f, float cooldown = 10f, float force = 1000f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public float ExplosionRadius { get; set; } = explosionRadius;
public int ExplosionDamage { get; set; } = explosionDamage;
public float DmgReductionForTeamates { get; set; } = dmgReductionForTeamates;
public float Cooldown { get; set; } = cooldown;
public float Force { get; set; } = force;
}
}
}

View file

@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
@ -154,7 +155,7 @@ namespace src.player.skills
{
eventPlayer.ExecuteClientCommand($"play player/player_damagebody_0{Instance.Random.Next(4, 8)}");
SkillUtils.TakeHealth(playerPawn, SkillsInfo.GetValue<int>(skillName, "damageAfterMiss"), GetSkillOwner(playerIndex), "planted_c4");
SkillUtils.TakeHealth(playerPawn, SkillsInfo.GetValue<int>(skillName, "damageAfterMiss"), GetSkillOwner(playerIndex), KillfeedIcons.Fist);
}
lastShot.TryRemove(playerIndex, out _);
});

View file

@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Cvars;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
@ -132,14 +133,14 @@ namespace src.player.skills
param2.Damage = 0;
if (teamDamage > 0)
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, "hegrenade");
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, KillfeedIcons.Explosion);
return;
}
}
if (owner != null && param2.Damage >= victimPawn.Health)
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, "hegrenade");
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, KillfeedIcons.Explosion);
}
private static bool IsFriendlyFireOff()

View file

@ -0,0 +1,80 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using static src.jRandomSkills;
namespace src.player.skills
{
public class DemonEye : ISkill
{
private const Skills skillName = Skills.DemonEye;
private static readonly Skills[] hidingSkills = [Skills.Ghost, Skills.Ninja, Skills.C4Camouflage];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void OnTick()
{
int tickCooldown = (int)(64 * SkillsInfo.GetValue<float>(skillName, "SecondCooldown"));
if (Server.TickCount % tickCooldown != 0) return;
int damage = SkillsInfo.GetValue<int>(skillName, "damage");
foreach (var player in PlayerManager.GetTickPlayers())
{
var playerEvent = PlayerManager.GetPlayerEvent(player);
if (!Instance.IsPlayerValid(playerEvent)) continue;
var playerInfo = PlayerManager.GetPlayerByIndex(playerEvent!.Index);
if (playerInfo?.Skill == skillName)
HitEnemies(playerEvent, damage);
}
}
private static void HitEnemies(CCSPlayerController player, int damage)
{
if (player == null || !player.IsValid || player.PlayerPawn?.Value == null) return;
int playerSlot = player.Slot;
int playerBit = playerSlot % 32;
if (playerSlot < 0)
return;
foreach (var enemy in PlayerManager.GetTickPlayers().FindAll(p => p != null && p.IsValid && p.Team != player.Team))
{
var enemyEvent = PlayerManager.GetPlayerEvent(enemy);
if (enemyEvent == null || !enemyEvent.IsValid) continue;
var enemyPawn = enemyEvent.PlayerPawn?.Value;
if (enemyPawn == null || !enemyPawn.IsValid || enemyPawn.Health <= 0) continue;
int enemySlot = enemy.Slot;
if (enemySlot < 0)
return;
int enemyBit = enemySlot % 32;
uint playerMask = 1u << playerBit;
uint enemyMask = 1u << enemyBit;
bool playerSeesEnemy = (enemyPawn.EntitySpottedState.SpottedByMask[0] & playerMask) != 0;
if (playerSeesEnemy)
{
SkillUtils.TakeHealth(enemyPawn, damage, player, KillfeedIcons.Fist);
enemyEvent.EmitSound("Player.DamageBody.Onlooker");
}
}
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#c91243", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float secondCooldown = 1f, int damage = 5) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public float SecondCooldown { get; set; } = secondCooldown;
public int Damage { get; set; } = damage;
}
}
}

View file

@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Cvars;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
@ -238,14 +239,14 @@ namespace src.player.skills
param2.Damage = 0;
if (teamDamage > 0)
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, "planted_c4");
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, KillfeedIcons.Explosion);
return;
}
}
if (owner != null && param2.Damage >= victimPawn.Health)
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, "planted_c4");
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, KillfeedIcons.Explosion);
}
private static bool IsFriendlyFireOff()

View file

@ -0,0 +1,144 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
namespace src.player.skills
{
public class FireRain : ISkill
{
private const Skills skillName = Skills.FireRain;
private static readonly QAngle angle = new(10, -4, 13);
private static readonly ConcurrentDictionary<uint, byte> decoys = [];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
KillAllDecoys();
}
private static void KillAllDecoys()
{
foreach (var decoyIndex in decoys.Keys.ToArray())
{
var decoy = Utilities.GetEntityFromIndex<CDecoyProjectile>((int)decoyIndex);
if (decoy != null && decoy.IsValid && decoy.DesignerName == "decoy_projectile")
decoy.AddEntityIOEvent("Kill", decoy, delay: 0.1f);
}
decoys.Clear();
}
private static void SpawnRain(CCSPlayerController player, Vector targetPos)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null)
return;
const int grenadeCount = 5;
const float spawnHeight = 800.0f;
const float approachDistance = 600.0f;
const float clusterRadius = 130.0f;
const float flightTime = 0.65f;
const float gravity = 800.0f;
float approachAngle = Random.Shared.NextSingle() * MathF.Tau;
float dirX = MathF.Cos(approachAngle);
float dirY = MathF.Sin(approachAngle);
Vector skyCenter = new(
targetPos.X + dirX * approachDistance,
targetPos.Y + dirY * approachDistance,
targetPos.Z + spawnHeight
);
float dx = targetPos.X - skyCenter.X;
float dy = targetPos.Y - skyCenter.Y;
float dz = targetPos.Z - skyCenter.Z;
float vx = dx / flightTime;
float vy = dy / flightTime;
float vz = (dz + 0.5f * gravity * flightTime * flightTime) / flightTime;
Vector velocity = new(vx, vy, vz);
float yaw = MathF.Atan2(vy, vx) * (180.0f / MathF.PI);
float horizontalSpeed = MathF.Sqrt(vx * vx + vy * vy);
float pitch = -MathF.Atan2(vz, horizontalSpeed) * (180.0f / MathF.PI);
QAngle launchAngle = new(pitch, yaw, 0.0f);
for (int i = 0; i < grenadeCount; i++)
{
float offsetAngle = Random.Shared.NextSingle() * MathF.Tau;
float offsetDist = MathF.Sqrt(Random.Shared.NextSingle()) * clusterRadius;
float offsetX = MathF.Cos(offsetAngle) * offsetDist;
float offsetY = MathF.Sin(offsetAngle) * offsetDist;
Vector spawnPos = new(
skyCenter.X + offsetX,
skyCenter.Y + offsetY,
skyCenter.Z
);
SkillUtils.CreateMolotovProjectile(spawnPos, launchAngle, velocity, player.TeamNum);
}
}
public static void OnEntitySpawned(CEntityInstance entity)
{
var name = entity.DesignerName;
if (name != "decoy_projectile")
return;
var decoy = entity.As<CDecoyProjectile>();
if (decoy == null || !decoy.IsValid || decoy.OwnerEntity == null || decoy.OwnerEntity.Value == null || !decoy.OwnerEntity.Value.IsValid) return;
var pawn = decoy.OwnerEntity.Value.As<CCSPlayerPawn>();
if (pawn == null || !pawn.IsValid || pawn.Controller == null || pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
var player = pawn.Controller.Value.As<CCSPlayerController>();
if (player == null || !player.IsValid) return;
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
if (playerInfo?.Skill != skillName) return;
decoys.TryAdd(decoy.Index, 0);
}
public static void DecoyStarted(EventDecoyStarted @event)
{
var player = PlayerManager.GetPlayerEvent(@event.Userid);
if (player == null || !player.IsValid) return;
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo?.Skill != skillName) return;
uint key = (uint)@event.Entityid;
if (decoys.ContainsKey(key))
{
var decoy = Utilities.GetEntityFromIndex<CDecoyProjectile>(@event.Entityid);
if (decoy != null && decoy.IsValid)
decoy.AddEntityIOEvent("Kill", decoy, delay: 0.1f);
decoys.TryRemove(key, out _);
SpawnRain(player, new Vector(@event.X, @event.Y, @event.Z));
}
}
public static void EnableSkill(CCSPlayerController player)
{
if (player == null || !player.IsValid) return;
SkillUtils.TryGiveWeapon(player, CsItem.DecoyGrenade);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffbf47", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Epic) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
}
}
}

View file

@ -0,0 +1,466 @@
// https://github.com/creazy231/cs2-css-flashlight
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
using System.Drawing;
namespace src.player.skills
{
public class Flashlight : ISkill
{
private const Skills skillName = Skills.Flashlight;
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
public class PlayerSkillInfo
{
public ulong SteamID { get; set; }
public bool CanUse { get; set; }
public DateTime Cooldown { get; set; }
public uint LightEntityIndex { get; set; }
public bool IsActive { get; set; }
}
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
ClearAllEntities();
SkillPlayerInfo.Clear();
}
public static void RoundEnd()
{
ClearAllEntities();
}
public static void OnTick()
{
foreach (var player in PlayerManager.GetTickPlayers())
{
if (player == null || !player.IsValid)
continue;
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
if (playerInfo?.Skill != skillName)
continue;
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
continue;
UpdateHUD(player, skillInfo);
if (!skillInfo.IsActive || skillInfo.LightEntityIndex == 0)
continue;
var lightEntity = Utilities.GetEntityFromIndex<CBarnLight>((int)skillInfo.LightEntityIndex);
if (lightEntity == null || !lightEntity.IsValid)
{
skillInfo.IsActive = false;
skillInfo.LightEntityIndex = 0;
continue;
}
UpdateLightPosition(player, lightEntity);
if (Server.TickCount % 32 != 0) continue;
CanBlind(player, lightEntity);
}
}
public static void EnableSkill(CCSPlayerController player)
{
if (player == null || !player.IsValid)
return;
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
{
SteamID = player.Index,
CanUse = true,
Cooldown = DateTime.MinValue,
LightEntityIndex = 0,
IsActive = false
});
}
public static void DisableSkill(CCSPlayerController player)
{
if (player == null)
return;
RemovePlayerLight(player.Index);
SkillPlayerInfo.TryRemove(player.Index, out _);
SkillUtils.ResetPrintHTML(player);
}
public static void PlayerDeath(EventPlayerDeath @event)
{
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
if (victim != null && victim.IsValid)
RemovePlayerLight(victim.Index);
}
public static void UseSkill(CCSPlayerController player)
{
if (player == null || !player.IsValid)
return;
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0)
return;
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
return;
if (!skillInfo.CanUse)
return;
skillInfo.CanUse = false;
skillInfo.Cooldown = DateTime.Now;
CBarnLight? lightEntity = null;
if (skillInfo.LightEntityIndex != 0)
lightEntity = Utilities.GetEntityFromIndex<CBarnLight>((int)skillInfo.LightEntityIndex);
if (lightEntity == null || !lightEntity.IsValid)
CreatePlayerFlashlight(player, skillInfo);
else
{
skillInfo.IsActive = !skillInfo.IsActive;
lightEntity.Enabled = skillInfo.IsActive;
if (skillInfo.IsActive)
{
lightEntity.AcceptInput("TurnOn");
UpdateLightPosition(player, lightEntity);
}
else
{
lightEntity.AcceptInput("TurnOff");
lightEntity.Teleport(new Vector(0, 0, -1000));
}
}
}
private static void CreatePlayerFlashlight(CCSPlayerController player, PlayerSkillInfo skillInfo)
{
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null)
return;
RemovePlayerLight(player.Index);
if (EntityManager.OverBudget())
return;
var light = Utilities.CreateEntityByName<CBarnLight>("light_barn");
if (light == null || !light.IsValid)
return;
EntityManager.RegisterEntity(light.Index, player.Index, "light_barn");
int colorR = SkillsInfo.GetValue<int>(skillName, "colorR");
int colorG = SkillsInfo.GetValue<int>(skillName, "colorG");
int colorB = SkillsInfo.GetValue<int>(skillName, "colorB");
float brightness = SkillsInfo.GetValue<float>(skillName, "brightness");
float range = SkillsInfo.GetValue<float>(skillName, "range");
light.Enabled = true;
light.Color = Color.FromArgb(255, Math.Clamp(colorR, 0, 255), Math.Clamp(colorG, 0, 255), Math.Clamp(colorB, 0, 255));
light.ColorTemperature = 6500;
light.Brightness = brightness;
light.Range = range;
light.SoftX = 1f;
light.SoftY = 1f;
light.Skirt = 0.5f;
light.SkirtNear = 1.0f;
light.CastShadows = 0;
light.DirectLight = 3;
light.SizeParams.X = 45;
light.SizeParams.Y = 45;
light.SizeParams.Z = 0.03f;
using (var keyValues = new CEntityKeyValues())
{
light.DispatchSpawn(keyValues);
}
light.AcceptInput("TurnOn");
skillInfo.LightEntityIndex = light.Index;
skillInfo.IsActive = true;
UpdateLightPosition(player, light);
}
private static void UpdateLightPosition(CCSPlayerController player, CBarnLight light)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.V_angle == null)
return;
Vector eyePos = new(
pawn.AbsOrigin.X,
pawn.AbsOrigin.Y,
pawn.AbsOrigin.Z + pawn.ViewOffset.Z
);
Vector forward = SkillUtils.GetForwardVector(pawn.V_angle);
const float distance = 18.0f;
Vector lightPos = new(
eyePos.X + forward.X * distance,
eyePos.Y + forward.Y * distance,
eyePos.Z + forward.Z * distance
);
light.Teleport(lightPos, pawn.V_angle, null);
}
private static void CanBlind(CCSPlayerController owner, CBarnLight light)
{
var ownerPawn = owner.PlayerPawn.Value;
if (ownerPawn == null || !ownerPawn.IsValid || ownerPawn.AbsOrigin == null || ownerPawn.V_angle == null)
return;
if (light == null || !light.IsValid || light.AbsOrigin == null)
return;
float blindDuration = SkillsInfo.GetValue<float>(skillName, "blindDuration");
float blindAlpha = SkillsInfo.GetValue<float>(skillName, "blindAlpha");
float blindAngle = SkillsInfo.GetValue<float>(skillName, "blindAngle");
float range = SkillsInfo.GetValue<float>(skillName, "range");
float rangeSq = range * range;
Vector eyePos = new(
ownerPawn.AbsOrigin.X,
ownerPawn.AbsOrigin.Y,
ownerPawn.AbsOrigin.Z + ownerPawn.ViewOffset.Z
);
Vector ownerForward = SkillUtils.GetForwardVector(ownerPawn.V_angle);
Vector lightPos = new(
eyePos.X + ownerForward.X * 18.0f,
eyePos.Y + ownerForward.Y * 18.0f,
eyePos.Z + ownerForward.Z * 18.0f
);
float minDot = MathF.Cos(blindAngle * MathF.PI / 180.0f);
foreach (var target in PlayerManager.GetTickPlayers())
{
if (target == null || !target.IsValid || target.Index == owner.Index || target.Team == owner.Team)
continue;
var targetInfo = PlayerManager.GetPlayerByIndex(target.Index);
if (targetInfo != null && targetInfo.Skill == Skills.AntyFlash)
continue;
var targetPawn = target.PlayerPawn.Value;
if (targetPawn == null || !targetPawn.IsValid || targetPawn.Health <= 0 || target.TeamNum == owner.TeamNum)
continue;
bool targetBlinded = targetPawn.BlindUntilTime > Server.CurrentTime;
bool ownerBlinded = ownerPawn.BlindUntilTime > Server.CurrentTime;
var (playerSeesEnemy, enemySeesPlayer) = ArePlayersSpottedBothWays(owner, ownerPawn, target, targetPawn);
bool needPlayerSees = !ownerBlinded;
bool needEnemySees = !targetBlinded;
if (ownerBlinded && targetBlinded)
continue;
if (needPlayerSees && !playerSeesEnemy)
continue;
if (needEnemySees && !enemySeesPlayer)
continue;
Vector targetEyePos = new(
targetPawn.AbsOrigin.X,
targetPawn.AbsOrigin.Y,
targetPawn.AbsOrigin.Z + targetPawn.ViewOffset.Z
);
Vector toTarget = new(
targetEyePos.X - lightPos.X,
targetEyePos.Y - lightPos.Y,
targetEyePos.Z - lightPos.Z
);
float distanceSq = toTarget.X * toTarget.X + toTarget.Y * toTarget.Y + toTarget.Z * toTarget.Z;
if (distanceSq <= 0.0001f || distanceSq > rangeSq)
continue;
float distance = MathF.Sqrt(distanceSq);
float invLength = 1.0f / distance;
Vector directionToTarget = new(
toTarget.X * invLength,
toTarget.Y * invLength,
toTarget.Z * invLength
);
float sourceDot = ownerForward.X * directionToTarget.X +
ownerForward.Y * directionToTarget.Y +
ownerForward.Z * directionToTarget.Z;
if (sourceDot < minDot)
continue;
Vector targetForward = SkillUtils.GetForwardVector(targetPawn.V_angle);
Vector fromTargetToLight = new(
lightPos.X - targetEyePos.X,
lightPos.Y - targetEyePos.Y,
lightPos.Z - targetEyePos.Z
);
float targetDistanceSq = fromTargetToLight.X * fromTargetToLight.X +
fromTargetToLight.Y * fromTargetToLight.Y +
fromTargetToLight.Z * fromTargetToLight.Z;
if (targetDistanceSq <= 0.0001f)
continue;
float targetInvLength = 1.0f / MathF.Sqrt(targetDistanceSq);
fromTargetToLight.X *= targetInvLength;
fromTargetToLight.Y *= targetInvLength;
fromTargetToLight.Z *= targetInvLength;
float targetDot = targetForward.X * fromTargetToLight.X +
targetForward.Y * fromTargetToLight.Y +
targetForward.Z * fromTargetToLight.Z;
if (targetDot < minDot)
continue;
BlindPlayers(targetPawn, blindDuration, blindAlpha);
}
}
private static void BlindPlayers(CCSPlayerPawn pawn, float blindDuration, float blindAlpha)
{
var rng = jRandomSkills.Instance.Random;
float now = Server.CurrentTime;
bool alreadyBlinded = pawn.BlindUntilTime > now;
if (!alreadyBlinded)
pawn.BlindStartTime = now;
pawn.BlindUntilTime = now + blindDuration;
pawn.FlashDuration = blindDuration + (float)rng.NextDouble() * 0.05f;
pawn.FlashMaxAlpha = blindAlpha + (float)rng.NextDouble() * 0.5f;
Utilities.SetStateChanged(pawn, "CCSPlayerPawnBase", "m_flFlashDuration");
Utilities.SetStateChanged(pawn, "CCSPlayerPawnBase", "m_flFlashMaxAlpha");
}
private static (bool, bool) ArePlayersSpottedBothWays(CCSPlayerController player, CCSPlayerPawn playerPawn, CCSPlayerController enemy, CCSPlayerPawn enemyPawn)
{
int playerSlot = player.Slot;
int enemySlot = enemy.Slot;
if (playerSlot < 0 || enemySlot < 0)
return (false, false);
int playerBit = playerSlot % 32;
int enemyBit = enemySlot % 32;
uint playerMask = 1u << playerBit;
uint enemyMask = 1u << enemyBit;
bool playerSeesEnemy = (enemyPawn.EntitySpottedState.SpottedByMask[0] & playerMask) != 0;
bool enemySeesPlayer = (playerPawn.EntitySpottedState.SpottedByMask[0] & enemyMask) != 0;
return (playerSeesEnemy, enemySeesPlayer);
}
private static void RemovePlayerLight(uint playerIndex)
{
if (SkillPlayerInfo.TryGetValue(playerIndex, out var info) && info.LightEntityIndex != 0)
{
EntityManager.DestroyEntity(info.LightEntityIndex);
info.LightEntityIndex = 0;
info.IsActive = false;
}
}
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo)
{
float cooldown = 0;
float time = (float)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "cooldown")) - DateTime.Now).TotalSeconds);
cooldown = Math.Max(time, 0);
if (cooldown == 0 && !skillInfo.CanUse)
skillInfo.CanUse = true;
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
if (playerInfo == null)
return;
if (cooldown == 0)
playerInfo.PrintHTML = null;
else
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
}
private static void ClearAllEntities()
{
foreach (var key in SkillPlayerInfo.Keys)
RemovePlayerLight(key);
}
public class SkillConfig(
Skills skill = skillName,
bool active = true,
string color = "#a3000b",
CsTeam onlyTeam = CsTeam.None,
bool disableOnFreezeTime = true,
bool needsTeammates = false,
string requiredPermission = "",
float? hudDuration = null,
float? descriptionHudDuration = null,
int maxPerServer = 2,
Rarity rarity = Rarity.Legendary,
float cooldown = 2f,
int colorR = 255,
int colorG = 255,
int colorB = 255,
float brightness = 1.5f,
float range = 1200.0f,
float blindDuration = 5f,
float blindAngle = 10.0f,
float blindAlpha = 200
) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public float Cooldown { get; set; } = cooldown;
public int ColorR { get; set; } = colorR;
public int ColorG { get; set; } = colorG;
public int ColorB { get; set; } = colorB;
public float Brightness { get; set; } = brightness;
public float Range { get; set; } = range;
public float BlindDuration { get; set; } = blindDuration;
public float BlindAlpha { get; set; } = blindAlpha;
public float BlindAngle { get; set; } = blindAngle;
}
}
}

View file

@ -0,0 +1,167 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
using System.Drawing;
namespace src.player.skills
{
public class HealingChicken : ISkill
{
private const Skills skillName = Skills.HealingChicken;
private class ChickenState
{
public CChicken? Chicken { get; set; }
public Vector? LastOrigin { get; set; }
public int TickCounter { get; set; }
}
private static readonly ConcurrentDictionary<uint, List<ChickenState>> activeChickens = new();
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
activeChickens.Clear();
}
public static void EnableSkill(CCSPlayerController player)
{
SpawnChicken(player);
}
public static void DisableSkill(CCSPlayerController player)
{
if (activeChickens.TryRemove(player.Index, out var chickens))
foreach (var state in chickens)
if (state.Chicken != null && state.Chicken.IsValid)
state.Chicken.Remove();
}
private static void SpawnChicken(CCSPlayerController player)
{
if (player == null || !player.IsValid) return;
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
int amount = SkillsInfo.GetValue<int>(skillName, "amount");
var list = new List<ChickenState>();
for (int i = 0; i < amount; i++)
{
CChicken? chicken = EntityManager.CreateTrackedChicken(player.Index);
if (chicken == null || !chicken.IsValid) continue;
chicken.Render = Color.LightGreen;
Vector offset = new(
(float)(100 * Math.Cos(2 * Math.PI * i / amount)),
(float)(100 * Math.Sin(2 * Math.PI * i / amount)),
0
);
chicken.Teleport(new Vector(pawn.AbsOrigin.X + offset.X, pawn.AbsOrigin.Y + offset.Y, pawn.AbsOrigin.Z + offset.Z));
chicken.Leader.Raw = pawn.Index;
list.Add(new ChickenState { Chicken = chicken, LastOrigin = null, TickCounter = 0 });
}
activeChickens[player.Index] = list;
}
public static void OnTick()
{
int tickCooldown = SkillsInfo.GetValue<int>(skillName, "tickCooldown");
if (Server.TickCount % tickCooldown == 0) return;
var players = PlayerManager.GetTickPlayers().ToArray();
int healAmount = SkillsInfo.GetValue<int>(skillName, "heal");
float healRadius = SkillsInfo.GetValue<float>(skillName, "healRadius");
foreach (var player in players)
{
if (player == null || !player.IsValid) continue;
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
if (playerInfo?.Skill != skillName) continue;
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) continue;
if (!activeChickens.TryGetValue(player.Index, out var chickens)) continue;
for (int i = chickens.Count - 1; i >= 0; i--)
{
var state = chickens[i];
if (state.Chicken == null || !state.Chicken.IsValid || state.Chicken.AbsOrigin == null)
{
chickens.RemoveAt(i);
continue;
}
var chicken = state.Chicken;
if (chicken.Leader.Raw != player.Pawn.Raw)
chicken.Leader.Raw = player.Pawn.Raw;
Vector currentOrigin = new(chicken.AbsOrigin.X, chicken.AbsOrigin.Y, chicken.AbsOrigin.Z);
if (state.LastOrigin != null)
{
float dx = currentOrigin.X - state.LastOrigin.X;
float dy = currentOrigin.Y - state.LastOrigin.Y;
float dist2D = MathF.Sqrt(dx * dx + dy * dy);
if (dist2D > 0.05f && dist2D < 20.0f)
{
float boostFactor = 2.5f;
Vector newPos = new(
currentOrigin.X + (dx * boostFactor),
currentOrigin.Y + (dy * boostFactor),
currentOrigin.Z
);
chicken.Teleport(newPos, chicken.AbsRotation, chicken.AbsVelocity);
state.LastOrigin = newPos;
}
else
state.LastOrigin = currentOrigin;
}
else
state.LastOrigin = currentOrigin;
float pdx = pawn.AbsOrigin.X - state.LastOrigin.X;
float pdy = pawn.AbsOrigin.Y - state.LastOrigin.Y;
float pdz = pawn.AbsOrigin.Z - state.LastOrigin.Z;
float distToPlayer = MathF.Sqrt(pdx * pdx + pdy * pdy + pdz * pdz);
if (distToPlayer <= healRadius)
{
state.TickCounter++;
if (state.TickCounter >= tickCooldown)
{
SkillUtils.AddHealth(pawn, healAmount);
state.TickCounter = 0;
}
}
else
state.TickCounter = 0;
}
}
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#b5ab8f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 1, Rarity rarity = Rarity.Legendary, int amount = 3, int heal = 2, int tickCooldown = 16, float healRadius = 150.0f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public int Amount { get; set; } = amount;
public int Heal { get; set; } = heal;
public int TickCooldown { get; set; } = tickCooldown;
public float HealRadius { get; set; } = healRadius;
}
}
}

View file

@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands.Targeting;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using System.Drawing;
@ -39,7 +40,7 @@ namespace src.player.skills
bool hasC4 = pawn.WeaponServices.MyWeapons.Any(w => w.Value?.DesignerName == "weapon_c4");
if (!hasC4) continue;
SkillUtils.TakeHealth(pawn, damage, owner, "planted_c4");
SkillUtils.TakeHealth(pawn, damage, owner, KillfeedIcons.C4);
playerEvent?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");
}
}

View file

@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
@ -353,7 +354,10 @@ namespace src.player.skills
var playerPawn = player.PlayerPawn.Value;
if (playerPawn != null)
SkillUtils.TakeHealth(playerPawn, (int)dealDamage, GetShooter(param2), param2.Ability?.Value?.DesignerName);
{
KillfeedIcons? killfeed = KillfeedIconsExtensions.FromWeaponName(param2.Ability?.Value?.DesignerName);
SkillUtils.TakeHealth(playerPawn, (int)dealDamage, GetShooter(param2), killfeed ?? KillfeedIcons.Leg);
}
}
}

View file

@ -1,11 +1,12 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
using static src.jRandomSkills;
using System.Collections.Concurrent;
using src.utils;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
namespace src.player.skills
@ -209,7 +210,7 @@ namespace src.player.skills
var attackerTeam = attackerPawn.TeamNum;
var replicaTeam = replica.Globalname.EndsWith("CT") ? 3 : 2;
SkillUtils.TakeHealth(attackerPawn, attackerTeam != replicaTeam ? SkillsInfo.GetValue<int>(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue<int>(skillName, "YourTeamDamage"), owner, "planted_c4");
SkillUtils.TakeHealth(attackerPawn, attackerTeam != replicaTeam ? SkillsInfo.GetValue<int>(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue<int>(skillName, "YourTeamDamage"), owner, KillfeedIcons.Player);
}
private static CCSPlayerController? GetReplicaOwner(uint replicaIndex)

View file

@ -0,0 +1,166 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
namespace src.player.skills
{
public class JetKick : ISkill
{
private const Skills skillName = Skills.JetKick;
private static readonly ConcurrentDictionary<uint, byte> targetedPlayers = [];
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
private static readonly object setLock = new();
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
lock (setLock)
{
foreach (var player in PlayerManager.GetTickPlayers())
{
DisableSkill(player);
SkillUtils.CloseMenu(player);
}
targetedPlayers.Clear();
playersToTarget.Clear();
}
}
public static void OnTick()
{
if (Server.TickCount % 32 != 0) return;
foreach (var player in PlayerManager.GetTickPlayers())
{
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo == null || playerInfo.Skill != skillName) continue;
if (!SkillUtils.HasMenu(player)) continue;
var enemies = PlayerManager.GetTickPlayers().Where(p => p != null && p.IsValid).Select(p => PlayerManager.GetPlayerEvent(p)).Where(p => p != null && p.IsValid && p.Team != player.Team && p.PlayerPawn?.Value != null && p.PlayerPawn.Value.IsValid && p.PlayerPawn.Value.Health > 0 && !p.IsHLTV && p.Team != CsTeam.Spectator && p.Team != CsTeam.None).ToArray();
ConcurrentBag<(string, string)> menuItems = new(enemies.Select(e => (e.PlayerName, e.Index.ToString())));
SkillUtils.UpdateMenu(player, menuItems);
}
}
public static void TypeSkill(CCSPlayerController player, string[] commands)
{
if (player == null || !player.IsValid || player.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo?.Skill != skillName) return;
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
if (playerEvent == null || !playerEvent.IsValid) return;
if (playerInfo.SkillUsed)
{
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("areareaper_used_info")}");
return;
}
string enemyId = commands[0];
if (!uint.TryParse(enemyId, out uint enemyIndex))
{
playerEvent.PrintToChat($" {ChatColors.Red}" + playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index"));
return;
}
var enemy = Utilities.GetPlayerFromIndex((int)enemyIndex);
if (enemy == null)
{
playerEvent.PrintToChat($" {ChatColors.Red}" + playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index"));
return;
}
targetedPlayers.TryAdd(enemy.Index, 0);
playersToTarget[player.Index] = enemy.Index;
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
if (enemyEvent == null || !enemyEvent.IsValid) return;
playerInfo.SkillUsed = true;
playerEvent.PrintToChat($" {ChatColors.Green}" + playerEvent.GetTranslation("jetkick_player_info", enemy.PlayerName));
enemyEvent.PrintToChat($" {ChatColors.Red}" + enemyEvent.GetTranslation("jetkick_enemy_info"));
}
public static void EnableSkill(CCSPlayerController player)
{
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo == null) return;
playerInfo.SkillUsed = false;
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
if (playerEvent == null || !playerEvent.IsValid) return;
var enemies = PlayerManager.GetTickPlayers().Where(p => p != null && p.IsValid).Select(p => PlayerManager.GetPlayerEvent(p)).Where(p => p != null && p.IsValid && p.Team != player.Team && p.PlayerPawn?.Value != null && p.PlayerPawn.Value.IsValid && p.PlayerPawn.Value.Health > 0 && !p.IsHLTV && p.Team != CsTeam.Spectator && p.Team != CsTeam.None).ToArray();
if (enemies.Length > 0)
{
ConcurrentBag<(string, string)> menuItems = new(enemies.Select(e => (e.PlayerName, e.Index.ToString())));
SkillUtils.CreateMenu(player, menuItems);
}
else
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
}
public static void DisableSkill(CCSPlayerController player)
{
if (playersToTarget.TryRemove(player.Index, out uint targetIndex))
{
var target = PlayerManager.GetPlayerFromEvent(Utilities.GetPlayerFromIndex((int)targetIndex));
if (target != null && target.IsValid)
{
if (target.PawnIsAlive && !SkillUtils.IsFreezeTime())
target.PrintToChat($" {ChatColors.Green}" + target.GetTranslation("jetkick_disable_info"));
}
targetedPlayers.TryRemove(targetIndex, out _);
}
SkillUtils.CloseMenu(player);
}
public static void PlayerDeath(EventPlayerDeath @event)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return;
targetedPlayers.TryRemove(player.Index, out _);
SkillUtils.CloseMenu(player);
}
public static void WeaponFire(EventWeaponFire @event)
{
var player = PlayerManager.GetPlayerEvent(@event.Userid);
if (player == null || !player.IsValid) return;
if (!targetedPlayers.ContainsKey(player.Index)) return;
if (!SkillUtils.FiresBullets(@event.Weapon)) return;
PushPlayer(player);
}
private static void PushPlayer(CCSPlayerController player)
{
var playerPawn = player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0) return;
Vector newVelocity = -SkillUtils.GetForwardVector(playerPawn.V_angle) * SkillsInfo.GetValue<float>(skillName, "pushVelocity");
playerPawn.Teleport(null, null, newVelocity);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#5a4fd1", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float pushVelocity = 400f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public float PushVelocity { get; set; } = pushVelocity;
}
}
}

View file

@ -2,6 +2,7 @@ using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Cvars;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
@ -30,7 +31,7 @@ namespace src.player.skills
if (!SkillsInfo.GetValue<bool>(skillName, "friendlyFire") && player!.Team == attacker!.Team) return;
if (attackerInfo?.Skill == skillName && playerInfo?.Skill != Skills.AntyFlash && player!.PlayerPawn.Value!.FlashDuration >= SkillsInfo.GetValue<float>(skillName, "flashDuration"))
SkillUtils.TakeHealth(player.PlayerPawn.Value, 9999, attacker, "weapon_flashbang");
SkillUtils.TakeHealth(player.PlayerPawn.Value, 9999, attacker, KillfeedIcons.Flashbang);
}
public static void GrenadeThrown(EventGrenadeThrown @event)

View file

@ -0,0 +1,58 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using static System.Net.Mime.MediaTypeNames;
namespace src.player.skills
{
public class LastGasp : ISkill
{
private const Skills skillName = Skills.LastGasp;
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void PlayerDeath(EventPlayerDeath @event)
{
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
var attacker = PlayerManager.GetPlayerEvent(@event.Attacker);
if (victim == null || !victim.IsValid || attacker == null || !attacker.IsValid)
return;
var victimPawn = victim.PlayerPawn?.Value;
var attackerPawn = attacker.PlayerPawn?.Value;
if (victimPawn == null || !victimPawn.IsValid || attackerPawn == null || !attackerPawn.IsValid)
return;
var victimInfo = PlayerManager.GetPlayerByIndex(victim!.Index);
if (victimInfo?.Skill != skillName)
return;
int damageAfterDeath = SkillsInfo.GetValue<int>(skillName, "DamageAfterDeath");
bool canKill = SkillsInfo.GetValue<bool>(skillName, "CanKill");
if (!canKill)
{
int newHealth = (int)(attackerPawn.Health - damageAfterDeath);
if (newHealth <= 0)
damageAfterDeath = damageAfterDeath - 1 + newHealth;
}
SkillUtils.TakeHealth(attackerPawn, damageAfterDeath, victim, KillfeedIcons.Fist);
PlayerManager.GetPlayerFromEvent(attacker)?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#88bdba", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, int damageAfterDeath = 30, bool canKill = true) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public int DamageAfterDeath { get; set; } = damageAfterDeath;
public bool CanKill { get; set; } = canKill;
}
}
}

View file

@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
@ -76,7 +77,8 @@ namespace src.player.skills
var playerInfo = PlayerManager.GetPlayerByIndex(eventPlayer.Index);
if (playerInfo == null || playerInfo.Skill != skillName) return HookResult.Continue;
KnifeHit(eventPlayer, true);
KillfeedIcons? killfeedIcon = KillfeedIconsExtensions.FromWeapon(weapon);
KnifeHit(eventPlayer, true, killfeedIcon);
return HookResult.Continue;
}
@ -94,10 +96,11 @@ namespace src.player.skills
var activeWeapon = pawn.WeaponServices.ActiveWeapon.Value;
if (activeWeapon == null || !activeWeapon.IsValid || (activeWeapon.DesignerName != "weapon_knife" && activeWeapon.DesignerName != "weapon_bayonet")) return;
KnifeHit(player, false);
KillfeedIcons? killfeedIcon = KillfeedIconsExtensions.FromWeapon(activeWeapon);
KnifeHit(player, false, killfeedIcon);
}
private unsafe static void KnifeHit(CCSPlayerController player, bool heavyHit)
private unsafe static void KnifeHit(CCSPlayerController player, bool heavyHit, KillfeedIcons? killfeedIcon)
{
var pawn = player!.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null)
@ -119,7 +122,7 @@ namespace src.player.skills
if (!SkillsInfo.GetValue<bool>(skillName, "friendlyFire") && player.Team == target.Team) return;
target.PlayerPawn.Value.EmitSound("Player.DamageBody.Onlooker");
SkillUtils.TakeHealth(target.PlayerPawn.Value, heavyHit ? Instance.Random.Next(45, 55) : Instance.Random.Next(21, 34), player, "weapon_knife");
SkillUtils.TakeHealth(target.PlayerPawn.Value, heavyHit ? Instance.Random.Next(45, 55) : Instance.Random.Next(21, 34), player, killfeedIcon ?? KillfeedIcons.Knife);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#c9f8ff", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float maxDistance = 4096f, bool friendlyFire = true) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)

View file

@ -1,6 +1,7 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using static src.jRandomSkills;
@ -39,7 +40,7 @@ namespace src.player.skills
if (target.Handle == player.Handle) return;
if (!SkillsInfo.GetValue<bool>(skillName, "friendlyFire") && player.Team == target.Team) return;
SkillUtils.TakeHealth(target.PlayerPawn.Value, 9999, player, "weapon_taser");
SkillUtils.TakeHealth(target.PlayerPawn.Value, 9999, player, KillfeedIcons.Taser);
}
public static void EnableSkill(CCSPlayerController player)

View file

@ -1,8 +1,9 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using System.Collections.Concurrent;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
namespace src.player.skills
{
@ -65,7 +66,7 @@ namespace src.player.skills
if (pawn.Health <= SkillsInfo.GetValue<int>(skillName, "MinHealth")) continue;
SkillUtils.TakeHealth(pawn, SkillsInfo.GetValue<int>(skillName, "Damage"), GetSkillOwner(playerIndex), "planted_c4");
SkillUtils.TakeHealth(pawn, SkillsInfo.GetValue<int>(skillName, "Damage"), GetSkillOwner(playerIndex), KillfeedIcons.Spray);
if (Server.TickCount % cooldown2 == 0)
PlayerManager.GetPlayerFromEvent(player)?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");

View file

@ -2,10 +2,9 @@ using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
using static src.jRandomSkills;
using System.Collections.Concurrent;
using jRandomSkills.src.utils;
using src.utils;
using CounterStrikeSharp.API.Modules.Memory;
using System.Collections.Concurrent;
namespace src.player.skills
{
@ -62,7 +61,7 @@ namespace src.player.skills
public static void DisableSkill(CCSPlayerController player)
{
if (player == null) return;
if (player == null || !player.IsValid) return;
SkillPlayerInfo.TryRemove(player.Index, out _);
EntityManager.DestroyPlayerEntities(player.Index);
SkillUtils.ResetPrintHTML(player);
@ -164,7 +163,7 @@ namespace src.player.skills
var attackerTeam = attackerPawn.TeamNum;
var replicaTeam = replica.Globalname.EndsWith("CT") ? 3 : 2;
SkillUtils.TakeHealth(attackerPawn, attackerTeam != replicaTeam ? SkillsInfo.GetValue<int>(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue<int>(skillName, "YourTeamDamage"), owner, "planted_c4");
SkillUtils.TakeHealth(attackerPawn, attackerTeam != replicaTeam ? SkillsInfo.GetValue<int>(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue<int>(skillName, "YourTeamDamage"), owner, KillfeedIcons.Player);
}
private static CCSPlayerController? GetReplicaOwner(uint replicaIndex)

View file

@ -0,0 +1,300 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
namespace src.player.skills
{
public class TakeAmmo : ISkill
{
private const Skills skillName = Skills.TakeAmmo;
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
private static readonly object setLock = new();
private static readonly ConcurrentDictionary<string, (int, string)> OriginalWeaponMaxAmmo = new();
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
lock (setLock)
{
SkillPlayerInfo.Clear();
}
foreach (var kvp in OriginalWeaponMaxAmmo)
{
var vdata = VirtualFunctions.GetCSWeaponDataFromKey(-1, kvp.Value.Item2);
if (vdata != null)
vdata.PrimaryReserveAmmoMax = kvp.Value.Item1;
}
OriginalWeaponMaxAmmo.Clear();
}
public static void EnableSkill(CCSPlayerController player)
{
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
{
SteamID = player.Index,
CanUse = true,
Cooldown = DateTime.MinValue,
LastClick = DateTime.MinValue,
FindedEnemy = true,
EnemyHaveAmmo = true,
MaxWeaponAmmo = new ConcurrentDictionary<string, int>()
});
}
public static void DisableSkill(CCSPlayerController player)
{
if (SkillPlayerInfo.TryRemove(player.Index, out var _))
SkillUtils.ResetPrintHTML(player);
var weaponServices = player.PlayerPawn?.Value?.WeaponServices;
if (weaponServices == null) return;
foreach (var _weapon in weaponServices.MyWeapons.ToArray())
{
if (_weapon == null || !_weapon.IsValid) continue;
var weapon = _weapon?.Value;
if (weapon == null || string.IsNullOrEmpty(weapon.DesignerName)) continue;
OriginalWeaponMaxAmmo.TryGetValue(weapon.DesignerName, out var items);
weapon.ReserveAmmo.Fill(items.Item1);
Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_pReserveAmmo");
}
}
public static void OnTick()
{
var players = PlayerManager.GetTickPlayers().ToArray();
foreach (var player in players)
{
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo?.Skill != skillName) continue;
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
{
bool recentClick = skillInfo.LastClick.AddSeconds(4) >= DateTime.Now;
UpdateHUD(player, skillInfo, recentClick);
}
}
}
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo, bool showInfo)
{
float cooldown = 0;
if (skillInfo != null)
{
float time = (int)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "cooldown")) - DateTime.Now).TotalSeconds);
cooldown = Math.Max(time, 0);
if (cooldown == 0 && skillInfo?.CanUse == false)
skillInfo.CanUse = true;
}
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
if (playerInfo == null) return;
if (cooldown == 0)
{
if (showInfo)
playerInfo.PrintHTML =
skillInfo != null && !skillInfo.FindedEnemy
? $"<font color='#FF0000'>{player.GetTranslation("takeammo_hud_info1")}</font>"
: skillInfo != null && !skillInfo.EnemyHaveAmmo ? $"<font color='#FF0000'>{player.GetTranslation("takeammo_hud_info2")}</font>" : null;
else
SkillUtils.ResetPrintHTML(player);
return;
}
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
}
public static void UseSkill(CCSPlayerController player)
{
var playerPawn = player.PlayerPawn.Value;
if (playerPawn?.CBodyComponent == null) return;
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
{
if (!player.IsValid || playerPawn.Health <= 0) return;
if (skillInfo.CanUse)
{
CCSPlayerController? enemy = GetRandomEnemy(player);
if (enemy == null)
{
skillInfo.FindedEnemy = false;
skillInfo.LastClick = DateTime.Now;
return;
}
int playerMagazines = GetMagazinesCount(player);
int enemyMagazines = GetMagazinesCount(enemy);
if (enemyMagazines == 0)
{
skillInfo.FindedEnemy = true;
skillInfo.EnemyHaveAmmo = false;
skillInfo.LastClick = DateTime.Now;
return;
}
skillInfo.EnemyHaveAmmo = true;
skillInfo.FindedEnemy = true;
skillInfo.CanUse = false;
skillInfo.Cooldown = DateTime.Now;
Server.NextFrame(() =>
{
if (player == null || !player.IsValid) return;
if (enemy == null || !enemy.IsValid) return;
SetMagazines(player, playerMagazines + enemyMagazines);
SetMagazines(enemy, 0);
PlayerManager.GetPlayerFromEvent(enemy)?.ExecuteClientCommand($"play sounds/weapons/g3sg1/g3sg1_clipout");
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
if (enemyEvent == null || !enemyEvent.IsValid) return;
enemyEvent.PrintToChat($" {ChatColors.Red}" + enemyEvent.GetTranslation("takeammo_enemy_info"));
});
}
else
skillInfo.LastClick = DateTime.Now;
}
}
private static int GetMagazinesCount(CCSPlayerController player)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.Health <= 0) return 0;
var ws = pawn.WeaponServices;
if (ws == null) return 0;
var activeWeapon = ws.ActiveWeapon?.Value;
if (activeWeapon == null || !activeWeapon.IsValid || activeWeapon.VData == null || string.IsNullOrEmpty(activeWeapon.DesignerName)) return 0;
if (activeWeapon.VData.PrimaryAmmoType == 7 && activeWeapon.ReserveAmmo.Length >= 1)
return (int)(activeWeapon.ReserveAmmo[0] / activeWeapon.VData.MaxClip1);
int magazines = activeWeapon.VData.ReserveAmmoAsClips && activeWeapon.ReserveAmmo.Length >= 1 ? activeWeapon.ReserveAmmo[0] : 0;
return magazines;
}
private static void SetMagazines(CCSPlayerController player, int magazines)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.Health <= 0) return;
var ws = pawn.WeaponServices;
if (ws == null) return;
var activeWeapon = ws.ActiveWeapon?.Value;
if (activeWeapon == null || !activeWeapon.IsValid || activeWeapon.VData == null || string.IsNullOrEmpty(activeWeapon.DesignerName)) return;
if (activeWeapon.VData.PrimaryAmmoType == 7)
magazines = (int)(magazines * activeWeapon.VData.MaxClip1);
activeWeapon.ReserveAmmo.Fill(magazines);
Utilities.SetStateChanged(activeWeapon, "CBasePlayerWeapon", "m_pReserveAmmo");
string weaponName = activeWeapon.DesignerName;
string weaponIndex = activeWeapon.AttributeManager.Item.ItemDefinitionIndex.ToString();
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
{
if (skillInfo.MaxWeaponAmmo.TryGetValue(weaponName, out int currentMax))
skillInfo.MaxWeaponAmmo[weaponName] = Math.Max(currentMax, magazines);
else
skillInfo.MaxWeaponAmmo.TryAdd(weaponName, magazines);
}
var vdata = VirtualFunctions.GetCSWeaponDataFromKey(-1, weaponIndex);
if (vdata == null) return;
if (!OriginalWeaponMaxAmmo.ContainsKey(weaponName))
OriginalWeaponMaxAmmo.TryAdd(weaponName, (vdata.PrimaryReserveAmmoMax, weaponIndex));
vdata.PrimaryReserveAmmoMax = Math.Max(vdata.PrimaryReserveAmmoMax, magazines);
}
public static void WeaponEquip(EventItemEquip @event)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return;
string weaponName = @event.Item;
if (string.IsNullOrEmpty(weaponName)) return;
if (OriginalWeaponMaxAmmo.TryGetValue("weapon_" + weaponName, out var items))
{
var pawn = player.PlayerPawn?.Value;
if (pawn == null) return;
var ws = pawn.WeaponServices;
if (ws == null) return;
var activeWeapon = ws.ActiveWeapon?.Value;
if (activeWeapon == null || !activeWeapon.IsValid || string.IsNullOrEmpty(activeWeapon.DesignerName)) return;
int ammoLimit = items.Item1;
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
{
if (skillInfo.MaxWeaponAmmo.TryGetValue("weapon_" + weaponName, out int personalMax))
ammoLimit = Math.Max(ammoLimit, personalMax);
}
if (activeWeapon.ReserveAmmo.Length > 0 && activeWeapon.ReserveAmmo[0] > ammoLimit)
{
activeWeapon.ReserveAmmo.Fill(ammoLimit);
Utilities.SetStateChanged(activeWeapon, "CBasePlayerWeapon", "m_pReserveAmmo");
}
}
}
private static CCSPlayerController? GetRandomEnemy(CCSPlayerController player)
{
CCSPlayerController[] enemies = [.. PlayerManager.GetTickPlayers().FindAll(e =>
e.Team != player.Team &&
e.PlayerPawn?.Value?.Health > 0 &&
e.PlayerPawn?.Value?.WeaponServices?.ActiveWeapon?.Value?.ReserveAmmo.Length > 0
)];
if (enemies.Length == 0) return null;
return enemies[Instance.Random.Next(enemies.Length)];
}
public class PlayerSkillInfo
{
public ulong SteamID { get; set; }
public bool CanUse { get; set; }
public DateTime Cooldown { get; set; }
public DateTime LastClick { get; set; }
public bool FindedEnemy { get; set; }
public bool EnemyHaveAmmo { get; set; }
public ConcurrentDictionary<string, int> MaxWeaponAmmo { get; set; } = new();
}
public class WeaponInfo
{
public required string Name { get; set; }
public required int Clip1 { get; set; }
public required int Clip2 { get; set; }
public required int Reserve { get; set; }
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#5eb8b0", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 30f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public float Cooldown { get; set; } = cooldown;
}
}
}

View file

@ -0,0 +1,257 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
namespace src.player.skills
{
public class TeamTeleport : ISkill
{
private const Skills skillName = Skills.TeamTeleport;
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
public class PlayerSkillInfo
{
public ulong SteamID { get; set; }
public bool CanUse { get; set; }
public DateTime Cooldown { get; set; }
public string? TeamateName { get; set; }
public uint? TeamateIndex { get; set; }
public Vector? TeamatePosition { get; set; }
public int NoSpace { get; set; }
public int NoEnemy { get; set; }
}
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
SkillPlayerInfo.Clear();
}
public static void OnTick()
{
foreach (var player in PlayerManager.GetTickPlayers())
{
if (player == null || !player.IsValid) continue;
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
if (playerInfo?.Skill != skillName) continue;
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) continue;
GetTeamate(player, skillInfo);
UpdateHUD(player, skillInfo);
}
}
public static void EnableSkill(CCSPlayerController player)
{
if (player == null || !player.IsValid) return;
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
{
SteamID = player.Index,
CanUse = true,
Cooldown = DateTime.MinValue,
TeamateName = null,
TeamateIndex = null,
TeamatePosition = null,
NoSpace = int.MinValue,
NoEnemy = int.MinValue
});
}
public static void DisableSkill(CCSPlayerController player)
{
if (player == null) return;
SkillPlayerInfo.TryRemove(player.Index, out _);
SkillUtils.ResetPrintHTML(player);
}
public static void UseSkill(CCSPlayerController player)
{
if (player == null || !player.IsValid) return;
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0) return;
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) return;
if (!skillInfo.CanUse) return;
skillInfo.NoEnemy = int.MinValue;
skillInfo.NoSpace = int.MinValue;
if (skillInfo.TeamateIndex == null || skillInfo.TeamatePosition == null)
{
skillInfo.NoEnemy = Server.TickCount + (64 * 2);
return;
}
var victim = PlayerManager.GetTickPlayers().FirstOrDefault(p => p.Index == skillInfo.TeamateIndex.Value);
if (victim == null || !victim.IsValid)
{
skillInfo.NoEnemy = Server.TickCount + (64 * 2);
return;
}
TeleportToTeamate(player, victim, skillInfo.TeamatePosition, skillInfo);
}
private static void GetTeamate(CCSPlayerController player, PlayerSkillInfo skillInfo)
{
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null || playerPawn.V_angle == null || playerPawn.ViewOffset == null)
return;
Vector eyePos = new(playerPawn.AbsOrigin.X, playerPawn.AbsOrigin.Y, playerPawn.AbsOrigin.Z + playerPawn.ViewOffset.Z);
Vector playerForward = SkillUtils.GetForwardVector(playerPawn.V_angle);
float teleportAngle = SkillsInfo.GetValue<float>(skillName, "teleportAngle");
float minDot = MathF.Cos(teleportAngle * MathF.PI / 180.0f);
skillInfo.TeamateIndex = null;
skillInfo.TeamateName = null;
skillInfo.TeamatePosition = null;
foreach (var teammate in PlayerManager.GetTickPlayers())
{
if (teammate == null || !teammate.IsValid || teammate.Index == player.Index || teammate.Team != player.Team)
continue;
var teammatePawn = teammate.PlayerPawn?.Value;
if (teammatePawn == null || !teammatePawn.IsValid || teammatePawn.Health <= 0 || teammatePawn.AbsOrigin == null)
continue;
Vector targetPos = new(teammatePawn.AbsOrigin.X, teammatePawn.AbsOrigin.Y, teammatePawn.AbsOrigin.Z + (teammatePawn.ViewOffset.Z * 0.5f));
Vector toTarget = new(targetPos.X - eyePos.X, targetPos.Y - eyePos.Y, targetPos.Z - eyePos.Z);
float distanceSq = toTarget.X * toTarget.X + toTarget.Y * toTarget.Y + toTarget.Z * toTarget.Z;
if (distanceSq <= 0.0001f)
continue;
float distance = MathF.Sqrt(distanceSq);
float invLength = 1.0f / distance;
toTarget.X *= invLength;
toTarget.Y *= invLength;
toTarget.Z *= invLength;
float dot = playerForward.X * toTarget.X + playerForward.Y * toTarget.Y + playerForward.Z * toTarget.Z;
if (distance > 30.0f && dot < minDot)
continue;
skillInfo.TeamateIndex = teammate.Index;
skillInfo.TeamateName = teammate.PlayerName;
skillInfo.TeamatePosition = new Vector(teammatePawn.AbsOrigin.X, teammatePawn.AbsOrigin.Y, teammatePawn.AbsOrigin.Z);
}
}
private unsafe static bool CheckTeleport(CCSPlayerController attacker, CCSPlayerController victim, Vector startPos, Vector endPos, QAngle angle)
{
var attackerPawn = attacker.PlayerPawn.Value;
if (attackerPawn == null || !attackerPawn.IsValid) return false;
var victimPawn = victim.PlayerPawn.Value;
if (victimPawn == null || !victimPawn.IsValid) return false;
var result = RayTrace.TraceHullShape(
startPos,
endPos,
victim,
attackerPawn.Collision.Mins,
attackerPawn.Collision.Maxs,
null,
null,
angle
);
if (!result.HasValue)
return false;
return !result.Value.DidHit;
}
private static void TeleportToTeamate(CCSPlayerController player, CCSPlayerController victim, Vector position, PlayerSkillInfo skillInfo)
{
var playerPawn = player.PlayerPawn?.Value;
if (playerPawn == null || !playerPawn.IsValid || player.AbsRotation == null) return;
QAngle playerAngles = new(player.AbsRotation.X, player.AbsRotation.Y, player.AbsRotation.Z);
float distance = SkillsInfo.GetValue<float>(skillName, "teleportDistance");
int[] angles = [0, 90, -90, 179];
bool teleported = false;
foreach (int extraAngle in angles)
{
QAngle targetAngle = new(0, playerAngles.Y + extraAngle, 0);
Vector direction = SkillUtils.GetForwardVector(targetAngle);
Vector targetPos = position - (direction * distance);
Vector traceStart = position - (direction * 20f);
if (CheckTeleport(player, victim, traceStart, targetPos, targetAngle))
{
playerPawn.Teleport(targetPos, targetAngle, Vector.Zero);
teleported = true;
break;
}
}
if (!teleported)
skillInfo.NoSpace = Server.TickCount + (64 * 2);
else
{
skillInfo.NoSpace = int.MinValue;
skillInfo.NoEnemy = int.MinValue;
skillInfo.CanUse = false;
skillInfo.Cooldown = DateTime.Now;
}
}
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo)
{
float cooldown = 0;
float time = (float)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "cooldown")) - DateTime.Now).TotalSeconds);
cooldown = Math.Max(time, 0);
if (cooldown == 0 && !skillInfo.CanUse)
skillInfo.CanUse = true;
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
if (playerInfo == null) return;
if (cooldown != 0)
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
else if (skillInfo.NoSpace >= Server.TickCount)
playerInfo.PrintHTML = $"<font color='#FF0000'>{player.GetTranslation("shade_nospace")}</font>";
else if (skillInfo.NoEnemy >= Server.TickCount)
playerInfo.PrintHTML = $"<font color='#FF0000'>{player.GetTranslation("teamteleport_noenemy")}</font>";
else
{
if (skillInfo.TeamateName == null)
playerInfo.PrintHTML = null;
else
{
string color = player.Team == CsTeam.Terrorist ? "#FFA500" : "#ADD8E6";
playerInfo.PrintHTML = $"{player.GetTranslation("teamteleport_hud_info", $"<font color='{color}'>{System.Net.WebUtility.HtmlEncode(skillInfo.TeamateName)}</font>")}";
}
}
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#bcf542", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = true, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = 15f, float teleportAngle = 10.0f, float teleportDistance = 100f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public float Cooldown { get; set; } = cooldown;
public float TeleportAngle { get; set; } = teleportAngle;
public float TeleportDistance { get; set; } = teleportDistance;
}
}
}

View file

@ -1,5 +1,6 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
namespace src.player.skills
@ -38,7 +39,7 @@ namespace src.player.skills
int damage = (int)(@event.DmgHealth * SkillsInfo.GetValue<float>(skillName, "healthTakenScale"));
damage = Math.Min(damage, SkillsInfo.GetValue<int>(skillName, "maxTakenDamagePerShot"));
SkillUtils.TakeHealth(attackerEvent.PlayerPawn.Value, damage, victimEvent, "planted_c4");
SkillUtils.TakeHealth(attackerEvent.PlayerPawn.Value, damage, victimEvent, KillfeedIcons.Armor);
attackerEvent.EmitSound("Player.DamageBody.Onlooker");
}
}

View file

@ -6,6 +6,7 @@ using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.UserMessages;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
using System.Drawing;
@ -360,7 +361,7 @@ namespace src.player.skills
if (CheckHasKnife(thrower!)) return;
SkillUtils.TakeHealth(victimPawn, SkillsInfo.GetValue<int>(skillName, "damage"), thrower, "weapon_knife");
SkillUtils.TakeHealth(victimPawn, SkillsInfo.GetValue<int>(skillName, "damage"), thrower, KillfeedIcons.Knife);
}
}

View file

@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Utils;
using jRandomSkills.src.utils;
using src.utils;
using System.Collections.Concurrent;
@ -95,7 +96,7 @@ namespace src.player.skills
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) continue;
if (SkillUtils.GetDistance(smoke.Key, pawn.AbsOrigin) <= smokeRadius)
if (SkillUtils.TakeHealth(pawn, smokeDamage, thrower, "smokegrenade"))
if (SkillUtils.TakeHealth(pawn, smokeDamage, thrower, KillfeedIcons.Smokegrenade))
player.EmitSound("Player.DamageBody.Onlooker");
}
}

View file

@ -314,7 +314,7 @@ namespace src.player.skills
public DateTime LastAttempt { get; set; }
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff3b3b", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, float radarDuration = 5f, float triggerRadius = 24f, float wireHeight = 30f, float wireWidth = 1.5f, float maxWallDistance = 400f, float cooldown = 20f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff3b3b", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, float radarDuration = 5f, float triggerRadius = 24f, float wireHeight = 30f, float wireWidth = 0.7f, float maxWallDistance = 400f, float cooldown = 20f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
{
public float RadarDuration { get; set; } = radarDuration;
public float TriggerRadius { get; set; } = triggerRadius;

View file

@ -195,7 +195,6 @@ namespace src.player.skills
itemServices.HasHelmet = gear.HasHelmet;
itemServices.HasDefuser = gear.HasDefuser;
Utilities.SetStateChanged(pawn, "CCSPlayerPawn", "m_pItemServices");
}
private static (WeaponInfo[]?, bool) GetWeapons(CCSPlayerController player)
@ -272,7 +271,7 @@ namespace src.player.skills
private static CCSPlayerController? GetRandomEnemy(CCSPlayerController player)
{
CCSPlayerController[] enemies = [.. PlayerManager.GetTickPlayers().FindAll(e => e.Team != player.Team && e.PawnIsAlive)];
CCSPlayerController[] enemies = [.. PlayerManager.GetTickPlayers().FindAll(e => e.Team != player.Team && e.PlayerPawn?.Value?.Health > 0)];
if (enemies.Length == 0) return null;
return enemies[Instance.Random.Next(enemies.Length)];
}