(CURRENTYLY BROKEN) Add new skills, signatures and fixes

Introduce multiple new skill implementations and related updates: add AimLock, HealingChicken, HomingNades, HotBomb, Illusionist, MagneticDecoy, ThrowingKnife, Weightless and WildThrow; register skills and HUD/cooldown handling. Update ISkill enum to include new skills. Add SnapViewAngles signature to gamedata. Improve existing skills to handle bayonet (BladeMaster, Cutter, Disarmament, LongKnife) and fix iteration/null-check issues in FrozenDecoy. Make HealingSmoke tick interval configurable and extend its config. Update English and Polish language files with new skill strings and tweaks. Also sync server-side gamedata and language files.
This commit is contained in:
Juzlus 2026-03-17 05:53:41 +01:00
parent 4e4458ad38
commit 97887118bf
31 changed files with 1625 additions and 73 deletions

View file

@ -3,7 +3,7 @@
"signatures": { "signatures": {
"library": "server", "library": "server",
"windows": "48 8B C4 48 89 58 ? 48 89 68 ? 48 89 70 ? 57 41 56 41 57 48 81 EC ? ? ? ? 48 8B B4 24 ? ? ? ? 4D 8B F8", "windows": "48 8B C4 48 89 58 ? 48 89 68 ? 48 89 70 ? 57 41 56 41 57 48 81 EC ? ? ? ? 48 8B B4 24 ? ? ? ? 4D 8B F8",
"linux": "55 4C 89 C1 48 89 E5 41 57 49 89 FF 41 56 45 89 CE" "linux": "55 4C 89 C1 48 89 E5 41 57 45 89 CF 41 56 49 89 FE"
} }
}, },
"HEGrenadeProjectile_CreateFunc": { "HEGrenadeProjectile_CreateFunc": {
@ -19,5 +19,12 @@
"windows": "48 89 5C 24 ? 57 48 83 EC 20 44 0F BF C2", "windows": "48 89 5C 24 ? 57 48 83 EC 20 44 0F BF C2",
"linux": "55 48 89 E5 41 54 53 48 89 FB 66 83 FE 65" "linux": "55 48 89 E5 41 54 53 48 89 FB 66 83 FE 65"
} }
},
"SnapViewAngles": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B DA 48 8B F1 48 8D 55",
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 89 F7 48 81 EC ? ? ? ? E8 ? ? ? ? 48 8B 93"
}
} }
} }

View file

@ -285,7 +285,7 @@
"psychicdefusing_hud_info": "{0} seconds remaining to defuse", "psychicdefusing_hud_info": "{0} seconds remaining to defuse",
"pilot": "Pilot", "pilot": "Pilot",
"pilot_desc": "Fly for a limited time. Hold [USE - E] to fly", "pilot_desc": "Fly for a limited time. Double-click the jump to fly",
"pilot_hud_info": "Fuel", "pilot_hud_info": "Fuel",
"planter": "Free Planter", "planter": "Free Planter",
@ -369,6 +369,9 @@
"silent": "Silent", "silent": "Silent",
"silent_desc": "Your footsteps and jumps are silent to OTHER players", "silent_desc": "Your footsteps and jumps are silent to OTHER players",
"smoker": "Smoker",
"smoker_desc": "Your smoke grenades never run out",
"sniperelite": "Sniper Elite", "sniperelite": "Sniper Elite",
"sniperelite_customname": "Sniper Elite Skill", "sniperelite_customname": "Sniper Elite Skill",
"sniperelite_desc": "Click [css_useSkill] to swap your current weapon for an AWP", "sniperelite_desc": "Click [css_useSkill] to swap your current weapon for an AWP",
@ -378,7 +381,7 @@
"soldier_desc2": "Your damage multiplier is: {0}x", "soldier_desc2": "Your damage multiplier is: {0}x",
"soundmaker": "Soundmaker", "soundmaker": "Soundmaker",
"soundmaker_desc": "Click [css_useSkill] to trigger a sound for every enemy", "soundmaker_desc": "Every now and then, you hear player screams",
"spectator": "Spectator", "spectator": "Spectator",
"spectator_desc": "Click [css_useSkill] to spectate a random enemy", "spectator_desc": "Click [css_useSkill] to spectate a random enemy",
@ -473,5 +476,52 @@
"menu_controlls_scroll": "W/S - Scroll", "menu_controlls_scroll": "W/S - Scroll",
"menu_controlls_padding": " | ", "menu_controlls_padding": " | ",
"menu_controlls_select": "E - Select" "menu_controlls_select": "E - Select",
"aimlock": "Aim Lock",
"aimlock_desc": "Click [css_useSkill] to lock your aim on the nearest enemy",
"homingnades": "Homing Grenades",
"homingnades_desc": "Your grenades (except smokes) are attracted to enemies",
"hotbomb": "Hot Bomb",
"hotbomb_desc": "As long as you are alive, the bomb deals damage to its carrier",
"hotbomb_hint": "Careful, the bomb is hot!",
"illiterate": "Illiterate",
"illiterate_desc": "As long as you are alive, your enemies cannot read",
"illusionist": "Illusionist",
"illusionist_desc": "Click [css_useSkill] to deploy a replica that walks straight ahead",
"magneticdecoy": "Magnetic Decoy",
"magneticdecoy_desc": "Your decoy attracts nearby players towards itself",
"magneto": "Magneto",
"magneto_desc": "All enemy grenades are repelled away from you",
"weightless": "Weightlessness",
"weightless_desc": "Your grenades are not affected by gravity and fly faster",
"wildthrow": "Wild Throws",
"wildthrow_desc": "Choose a player who will have trouble throwing grenades",
"wildthrow_player_info": "Player '{0}' has forgotten all their lineups",
"wildthrow_select_info": "Select a player:",
"throwingknife": "Throwing Knife",
"throwingknife_desc": "Click [css_useSkill] to throw a knife. But watch out for others"
} }

View file

@ -5,6 +5,9 @@
"aimbot": "Aimbot", "aimbot": "Aimbot",
"aimbot_desc": "Każdy twój trafiony pocisk liczy się jako strzał w głowę", "aimbot_desc": "Każdy twój trafiony pocisk liczy się jako strzał w głowę",
"aimlock": "Aim Lock",
"aimlock_desc": "Kliknij [css_useSkill], aby wycelować na najbliższego wroga",
"anomaly": "Anomalia", "anomaly": "Anomalia",
"anomaly_desc": "Cofasz się o kilka sekund do tyłu", "anomaly_desc": "Cofasz się o kilka sekund do tyłu",
@ -77,7 +80,7 @@
"cypher": "Kamera", "cypher": "Kamera",
"cypher_desc": "Kliknij [css_useSkill], aby utworzyć/przełączyć się na kamerę", "cypher_desc": "Kliknij [css_useSkill], aby utworzyć/przełączyć się na kamerę",
"cypher_nospace": "Kamera musi być ustawiona pod kątem prostym do ściany", "cypher_nospace": "Kamera musi być ustawiona pod kątem prostym do ściany",
"darkness": "Mrok", "darkness": "Mrok",
"darkness_desc": "Nadaje efekt ciemności wybranemu przeciwnikowi", "darkness_desc": "Nadaje efekt ciemności wybranemu przeciwnikowi",
"darkness_enemy_info": "Niech zgasną światła.", "darkness_enemy_info": "Niech zgasną światła.",
@ -186,9 +189,18 @@
"holyhandgrenade": "Święty Granat Ręczny", "holyhandgrenade": "Święty Granat Ręczny",
"holyhandgrenade_desc": "Twoje granaty uderzeniowe zadają podwójne obrażenia i mają podwójny zasięg", "holyhandgrenade_desc": "Twoje granaty uderzeniowe zadają podwójne obrażenia i mają podwójny zasięg",
"homingnades": "Namierzające Granaty",
"homingnades_desc": "Twoje granaty (oprócz dymnych) są przyciągane do wrogów",
"hotbomb": "Gorąca Bomba",
"hotbomb_desc": "Póki żyjesz, bomba zadaje obrażenia nosicielowi",
"iana": "Hologram", "iana": "Hologram",
"iana_desc": "Kliknij [css_useSkill], aby sterować hologramem przez kilka sekund", "iana_desc": "Kliknij [css_useSkill], aby sterować hologramem przez kilka sekund",
"illiterate": "Analfabeta",
"illiterate_desc": "Dopóki żyjesz, twoi wrogowie nie potrafią czytać",
"impostor": "Szpieg", "impostor": "Szpieg",
"impostor_desc": "Na początku rundy otrzymujesz model postaci przeciwnika", "impostor_desc": "Na początku rundy otrzymujesz model postaci przeciwnika",
@ -234,6 +246,12 @@
"longzeus": "Długi Zeus", "longzeus": "Długi Zeus",
"longzeus_desc": "Zeus zadaje obrażenia niezależnie od odległości", "longzeus_desc": "Zeus zadaje obrażenia niezależnie od odległości",
"magneticdecoy": "Magnetyczny Decoy",
"magneticdecoy_desc": "Twój wabik przyciąga graczy wokół siebie",
"magneto": "Magneto",
"magneto_desc": "Wszystkie granaty przeciwnika są odpychane od ciebie",
"magnifier": "Lupa", "magnifier": "Lupa",
"magnifier_desc": "Przybiżasz ekran wybranemu przeciwnikowi", "magnifier_desc": "Przybiżasz ekran wybranemu przeciwnikowi",
"magnifier_enemy_info": "Twoje pole widzenia zostało zniekształcone!", "magnifier_enemy_info": "Twoje pole widzenia zostało zniekształcone!",
@ -285,7 +303,7 @@
"psychicdefusing_hud_info": "Pozostało {0} sekund do rozbrojenia", "psychicdefusing_hud_info": "Pozostało {0} sekund do rozbrojenia",
"pilot": "Pilot", "pilot": "Pilot",
"pilot_desc": "Latanie przez określony czas. Przytrzymaj [USE - E], aby latać", "pilot_desc": "Latanie przez określony czas. Kliknij dwukrotnie skok, aby latać",
"pilot_hud_info": "Paliwo", "pilot_hud_info": "Paliwo",
"planter": "Samowolka", "planter": "Samowolka",
@ -369,7 +387,10 @@
"silent": "Cichociemny", "silent": "Cichociemny",
"silent_desc": "Twoje kroki i skoki są niesłyszalne dla INNYCH graczy", "silent_desc": "Twoje kroki i skoki są niesłyszalne dla INNYCH graczy",
"sniperelite": "SzeliS", "smoker": "Zadymiarz",
"smoker_desc": "Twoje granaty dymne nigdy się nie kończą",
"sniperelite": "Papito",
"sniperelite_customname": "Mityczna AWP", "sniperelite_customname": "Mityczna AWP",
"sniperelite_desc": "Kliknij [css_useSkill], aby zamienić aktualną broń na AWP", "sniperelite_desc": "Kliknij [css_useSkill], aby zamienić aktualną broń na AWP",
@ -378,7 +399,7 @@
"soldier_desc2": "Twój mnożnik obrażeń wynosi: {0}x", "soldier_desc2": "Twój mnożnik obrażeń wynosi: {0}x",
"soundmaker": "Dźwiękowiec", "soundmaker": "Dźwiękowiec",
"soundmaker_desc": "Kliknij [css_useSkill], aby wywołać dzwięk u każdego przeciwnika", "soundmaker_desc": "Co jakiś czas szłyszysz krzyki graczy",
"spectator": "Obserwator", "spectator": "Obserwator",
"spectator_desc": "Kliknij [css_useSkill], aby obserwować losowego przeciwnika", "spectator_desc": "Kliknij [css_useSkill], aby obserwować losowego przeciwnika",
@ -402,6 +423,9 @@
"thorns": "Ciernie", "thorns": "Ciernie",
"thorns_desc": "Twój przeciwnik otrzymuje część obrażeń, które zadał ci", "thorns_desc": "Twój przeciwnik otrzymuje część obrażeń, które zadał ci",
"throwingknife": "Nóż do Rzucania",
"throwingknife_desc": "Kliknij [css_useSkill], aby rzucić nożem. Ale uważaj na innych",
"toxicsmoke": "Toksyczny Dym", "toxicsmoke": "Toksyczny Dym",
"toxicsmoke_desc": "Twoje granaty dymny zadają obrażenia", "toxicsmoke_desc": "Twoje granaty dymny zadają obrażenia",
@ -417,6 +441,14 @@
"weaponsswap_desc": "Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem", "weaponsswap_desc": "Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem",
"weaponsswap_hud_info2": "Nie posiadasz broni na zamiane", "weaponsswap_hud_info2": "Nie posiadasz broni na zamiane",
"weightless": "Stan Nieważkości",
"weightless_desc": "Twoje granaty nie podlegają grawitacji i lecą szybciej",
"wildthrow": "Dzikie rzuty",
"wildthrow_desc": "Wybierz gracza, który będzie miał trudności z rzucaniem granatami",
"wildthrow_player_info": "Gracz '{0}' zapomniał wszystkie lineup'y",
"wildthrow_select_info": "Wybierz gracza:",
"zeus": "Zeus", "zeus": "Zeus",
"zeus_desc": "Zeus x27 natychmiastowo się odnawia", "zeus_desc": "Zeus x27 natychmiastowo się odnawia",

View file

@ -51,6 +51,7 @@ public enum Skills
{ {
None, None,
Aimbot, Aimbot,
AimLock, // <-
Anomaly, Anomaly,
AntyFlash, AntyFlash,
AntyHead, AntyHead,
@ -79,7 +80,7 @@ public enum Skills
Dracula, Dracula,
Duplicator, Duplicator,
Dwarf, Dwarf,
Earthquake, Earthquake, // <-
EnemySpawn, EnemySpawn,
ExplosiveShot, ExplosiveShot,
FalconEye, FalconEye,
@ -96,11 +97,15 @@ public enum Skills
Glue, Glue,
GodMode, GodMode,
Grenadier, Grenadier,
HealingChicken, // <-
HealingSmoke, HealingSmoke,
Hermit, Hermit,
HolyHandGrenade, HolyHandGrenade,
HomingNades, // <-
HotBomb,
Iana, Iana,
Illiterate, Illiterate,
Illusionist,
Impostor, Impostor,
InfiniteAmmo, InfiniteAmmo,
Jackal, Jackal,
@ -112,6 +117,8 @@ public enum Skills
LifeSwap, LifeSwap,
LongKnife, LongKnife,
LongZeus, LongZeus,
MagneticDecoy,
Magneto,
Magnifier, Magnifier,
Medic, Medic,
MoneySwap, MoneySwap,
@ -125,7 +132,7 @@ public enum Skills
PawelJumper, PawelJumper,
Phoenix, Phoenix,
PsychicDefusing, PsychicDefusing,
Pilot, Pilot, // <-
Planter, Planter,
Poison, Poison,
PrimaryBan, PrimaryBan,
@ -136,7 +143,7 @@ public enum Skills
RadarHack, RadarHack,
Rambo, Rambo,
RandomWeapon, RandomWeapon,
RCMelon, RCMelon, // <-
ReZombie, ReZombie,
ReactiveArmor, ReactiveArmor,
Regeneration, Regeneration,
@ -149,10 +156,10 @@ public enum Skills
Saper, Saper,
SecondLife, SecondLife,
Shade, Shade,
ShortBomb, ShortBomb, // <- short
Silent, Silent,
Smoker, Smoker, // <- nie dziala
SniperElite, SniperElite, // <- nie dziala
Soldier, Soldier,
SoundMaker, SoundMaker,
Spectator, Spectator,
@ -161,9 +168,12 @@ public enum Skills
Thief, Thief,
ThirdEye, ThirdEye,
Thorns, Thorns,
ThrowingKnife,
ToxicSmoke, ToxicSmoke,
Wallhack, Wallhack,
Watchmaker, Watchmaker,
WeaponsSwap, WeaponsSwap,
Weightless,
WildThrow,
Zeus, Zeus,
} }

View file

@ -0,0 +1,146 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using static src.jRandomSkills;
using System.Collections.Concurrent;
using src.utils;
namespace src.player.skills
{
public class AimLock : ISkill
{
private const Skills skillName = Skills.AimLock;
private static readonly ConcurrentDictionary<ulong, PlayerSkillInfo> SkillPlayerInfo = [];
private static readonly object setLock = new();
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
lock (setLock)
SkillPlayerInfo.Clear();
}
public static void OnTick()
{
foreach (var player in Utilities.GetPlayers())
{
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill == skillName)
if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo))
UpdateHUD(player, skillInfo);
}
}
public static void EnableSkill(CCSPlayerController player)
{
SkillPlayerInfo.TryAdd(player.SteamID, new PlayerSkillInfo
{
SteamID = player.SteamID,
CanUse = true,
Cooldown = DateTime.MinValue,
});
}
public static void DisableSkill(CCSPlayerController player)
{
SkillPlayerInfo.TryRemove(player.SteamID, out _);
SkillUtils.ResetPrintHTML(player);
}
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo)
{
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 = Instance.SkillPlayer.FirstOrDefault(s => s.SteamID == player?.SteamID);
if (playerInfo == null) return;
if (cooldown == 0)
playerInfo.PrintHTML = null;
else
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.SteamID, out var skillInfo))
{
if (!player.IsValid || !player.PawnIsAlive) return;
if (skillInfo.CanUse)
{
skillInfo.CanUse = false;
skillInfo.Cooldown = DateTime.Now;
LookAtEnemey(player);
}
}
}
private static void LookAtEnemey(CCSPlayerController player)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
CCSPlayerController? closetEnemy = null;
double minDist = double.MaxValue;
foreach (var enemy in Utilities.GetPlayers().Where(p => p.IsValid && p.PawnIsAlive && p.Team != player.Team))
{
var enemyPawn = enemy.PlayerPawn.Value;
if (enemyPawn == null || !enemyPawn.IsValid || enemyPawn.AbsOrigin == null) return;
double dist = SkillUtils.GetDistance(enemyPawn.AbsOrigin, pawn.AbsOrigin);
if (dist < minDist)
{
minDist = dist;
closetEnemy = enemy;
}
}
if (closetEnemy != null)
{
Vector enemyPos = closetEnemy.PlayerPawn.Value!.AbsOrigin!;
Vector myPos = pawn.AbsOrigin;
Vector direction = enemyPos - myPos;
QAngle angle = VectorToAngle(direction);
pawn.Look(angle);
}
}
private static QAngle VectorToAngle(Vector direction)
{
float pitch = (float)(-Math.Atan2(direction.Z, Math.Sqrt(direction.X * direction.X + direction.Y * direction.Y)) * 180 / Math.PI);
float yaw = (float)(Math.Atan2(direction.Y, direction.X) * 180 / Math.PI);
return new QAngle(pitch, yaw, 0);
}
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 = "#fa7b48", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float cooldown = 5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public float Cooldown { get; set; } = cooldown;
}
}
}

View file

@ -9,7 +9,7 @@ namespace src.player.skills
public class BladeMaster : ISkill public class BladeMaster : ISkill
{ {
private const Skills skillName = Skills.BladeMaster; private const Skills skillName = Skills.BladeMaster;
private static readonly string[] noReflectionWeapon = ["inferno", "flashbang", "smokegrenade", "decoy", "hegrenade", "knife", "taser"]; private static readonly string[] noReflectionWeapon = ["inferno", "flashbang", "smokegrenade", "decoy", "hegrenade", "knife", "taser", "bayonet"];
public static void LoadSkill() public static void LoadSkill()
{ {
@ -30,7 +30,7 @@ namespace src.player.skills
var weaponServices = playerPawn.WeaponServices; var weaponServices = playerPawn.WeaponServices;
if (weaponServices == null) return; if (weaponServices == null) return;
if (weaponServices.ActiveWeapon == null || !weaponServices.ActiveWeapon.IsValid || weaponServices.ActiveWeapon.Value == null || !weaponServices.ActiveWeapon.Value.IsValid || weaponServices.ActiveWeapon.Value.DesignerName != "weapon_knife") if (weaponServices.ActiveWeapon == null || !weaponServices.ActiveWeapon.IsValid || weaponServices.ActiveWeapon.Value == null || !weaponServices.ActiveWeapon.Value.IsValid || (weaponServices.ActiveWeapon.Value.DesignerName != "weapon_knife" && weaponServices.ActiveWeapon.Value.DesignerName != "weapon_bayonet"))
return; return;
playerPawn.VelocityModifier = SkillsInfo.GetValue<float>(skillName, "velocityModifier"); playerPawn.VelocityModifier = SkillsInfo.GetValue<float>(skillName, "velocityModifier");
@ -63,7 +63,7 @@ namespace src.player.skills
var weaponServices = pawn.WeaponServices; var weaponServices = pawn.WeaponServices;
if (weaponServices == null) return; if (weaponServices == null) return;
if (weaponServices.ActiveWeapon == null || !weaponServices.ActiveWeapon.IsValid || weaponServices.ActiveWeapon.Value == null || !weaponServices.ActiveWeapon.Value.IsValid || weaponServices.ActiveWeapon.Value.DesignerName != "weapon_knife") if (weaponServices.ActiveWeapon == null || !weaponServices.ActiveWeapon.IsValid || weaponServices.ActiveWeapon.Value == null || !weaponServices.ActiveWeapon.Value.IsValid || (weaponServices.ActiveWeapon.Value.DesignerName != "weapon_knife" && weaponServices.ActiveWeapon.Value.DesignerName != "weapon_bayonet"))
return; return;
SkillUtils.RestoreHealth(victim); SkillUtils.RestoreHealth(victim);

View file

@ -25,7 +25,7 @@ namespace src.player.skills
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == attacker?.SteamID); var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == attacker?.SteamID);
if (playerInfo?.Skill != skillName) return; if (playerInfo?.Skill != skillName) return;
if (weapon == "knife") if (weapon == "knife" || weapon == "bayonet")
SkillUtils.TakeHealth(victim!.PlayerPawn.Value, 9999); SkillUtils.TakeHealth(victim!.PlayerPawn.Value, 9999);
} }

View file

@ -31,7 +31,7 @@ namespace src.player.skills
if (weaponServices?.ActiveWeapon == null) return; if (weaponServices?.ActiveWeapon == null) return;
var weaponName = weaponServices?.ActiveWeapon?.Value?.DesignerName; var weaponName = weaponServices?.ActiveWeapon?.Value?.DesignerName;
if (weaponName != null && !weaponName.Contains("weapon_knife") && !weaponName.Contains("weapon_c4")) if (weaponName != null && !weaponName.Contains("weapon_knife") && !weaponName.Contains("weapon_bayonet") && !weaponName.Contains("weapon_c4"))
victim.DropActiveWeapon(); victim.DropActiveWeapon();
} }
} }

View file

@ -27,8 +27,10 @@ namespace src.player.skills
{ {
var player = @event.Userid; var player = @event.Userid;
if (player == null || !player.IsValid) return; if (player == null || !player.IsValid) return;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return; if (playerInfo?.Skill != skillName) return;
decoys.TryAdd(new Vector(@event.X, @event.Y, @event.Z), 0); decoys.TryAdd(new Vector(@event.X, @event.Y, @event.Z), 0);
} }
@ -36,8 +38,10 @@ namespace src.player.skills
{ {
var player = @event.Userid; var player = @event.Userid;
if (player == null || !player.IsValid) return; if (player == null || !player.IsValid) return;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return; if (playerInfo?.Skill != skillName) return;
foreach (var decoy in decoys.Keys.Where(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z)) foreach (var decoy in decoys.Keys.Where(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z))
decoys.TryRemove(decoy, out _); decoys.TryRemove(decoy, out _);
} }
@ -45,11 +49,11 @@ namespace src.player.skills
public static void OnTick() public static void OnTick()
{ {
foreach (Vector decoyPos in decoys.Keys) foreach (Vector decoyPos in decoys.Keys)
foreach (var player in Utilities.GetPlayers().Where(p => p.Team == CsTeam.Terrorist || p.Team == CsTeam.CounterTerrorist)) foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && p.PawnIsAlive && p.Team is CsTeam.CounterTerrorist or CsTeam.Terrorist))
{ {
var decoyRadius = SkillsInfo.GetValue<float>(skillName, "triggerRadius"); var decoyRadius = SkillsInfo.GetValue<float>(skillName, "triggerRadius");
var pawn = player.PlayerPawn.Value; var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return; if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) continue;
double distance = SkillUtils.GetDistance(decoyPos, pawn.AbsOrigin); double distance = SkillUtils.GetDistance(decoyPos, pawn.AbsOrigin);
if (distance <= decoyRadius) if (distance <= decoyRadius)
{ {

View file

@ -0,0 +1,85 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
using System.Drawing;
using static src.jRandomSkills;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
namespace src.player.skills
{
public class HealingChicken : ISkill
{
private const Skills skillName = Skills.HealingChicken;
private readonly static ConcurrentDictionary<ulong, List<Timer>> playerSmokes = [];
private static readonly object setLock = new();
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
}
public static void EnableSkill(CCSPlayerController player)
{
SpawnChicken(player);
}
public static void DisableSkill(CCSPlayerController player)
{
}
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");
for (int i = 0; i < 1; i++)
{
CChicken? chicken = Utilities.CreateEntityByName<CChicken>("chicken");
if (chicken == null || !chicken.IsValid) continue;
chicken.Render = Color.Green;
Vector offset = new (
(float)(100 * Math.Cos(2 * Math.PI * i / amount)),
(float)(100 * Math.Sin(2 * Math.PI * i / amount)),
0
);
chicken.DispatchSpawn();
chicken.Teleport(pawn.AbsOrigin + offset);
// Schema.SetSchemaValue(chicken.Handle, "CChicken", "m_leader", player.PlayerPawn.Raw);
Vector spawn = SkillUtils.GetSpawnPointVector(player);
Schema.SetSchemaValue(chicken.Handle, "CChicken", "m_vecPathGoal", spawn);
float speed = 50;
Instance.AddTickTimer(1, () =>
{
if (chicken == null || !chicken.IsValid) return;
Server.PrintToChatAll($"{chicken.PathGoal}, {chicken.UpdateTimer.Duration}, {chicken.UpdateTimer.Timescale}");
}, TimerFlags.REPEAT | TimerFlags.STOP_ON_MAPCHANGE);
}
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#b5ab8f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int amount = 3, int heal = 2, int tickCooldown = 16) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public int Amount { get; set; } = amount;
public int Heal { get; set; } = heal;
public int TickCooldown { get; set; } = tickCooldown;
}
}
}

View file

@ -70,9 +70,10 @@ namespace src.player.skills
public static void OnTick() public static void OnTick()
{ {
int tick = SkillsInfo.GetValue<int>(skillName, "tickCooldown");
foreach (Vector smokePos in smokes.Keys) foreach (Vector smokePos in smokes.Keys)
foreach (var player in Utilities.GetPlayers()) foreach (var player in Utilities.GetPlayers())
if (Server.TickCount % 16 == 0) if (Server.TickCount % tick == 0)
if (player.PlayerPawn.Value != null && player.PlayerPawn.Value.IsValid && player.PlayerPawn.Value.AbsOrigin != null) if (player.PlayerPawn.Value != null && player.PlayerPawn.Value.IsValid && player.PlayerPawn.Value.AbsOrigin != null)
if (SkillUtils.GetDistance(smokePos, player.PlayerPawn.Value.AbsOrigin) <= SkillsInfo.GetValue<float>(skillName, "smokeRadius")) if (SkillUtils.GetDistance(smokePos, player.PlayerPawn.Value.AbsOrigin) <= SkillsInfo.GetValue<float>(skillName, "smokeRadius"))
AddHealth(player.PlayerPawn.Value, SkillsInfo.GetValue<int>(skillName, "smokeHeal")); AddHealth(player.PlayerPawn.Value, SkillsInfo.GetValue<int>(skillName, "smokeHeal"));
@ -95,10 +96,11 @@ namespace src.player.skills
Utilities.SetStateChanged(player, "CBaseEntity", "m_iHealth"); Utilities.SetStateChanged(player, "CBaseEntity", "m_iHealth");
} }
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1fe070", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int smokeHeal = 1, float smokeRadius = 180) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1fe070", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int smokeHeal = 1, float smokeRadius = 180, int tickCooldown = 16) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{ {
public int SmokeHeal { get; set; } = smokeHeal; public int SmokeHeal { get; set; } = smokeHeal;
public float SmokeRadius { get; set; } = smokeRadius; public float SmokeRadius { get; set; } = smokeRadius;
public int TickCooldown { get; set; } = tickCooldown;
} }
} }
} }

View file

@ -0,0 +1,155 @@
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;
using static src.jRandomSkills;
namespace src.player.skills
{
public class HomingNades : ISkill
{
private const Skills skillName = Skills.HomingNades;
private readonly static ConcurrentDictionary<uint, (Vector, double)> nades = [];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
nades.Clear();
}
public static void OnTick()
{
if (Server.TickCount % 10 != 0) return;
foreach (var index in nades.Keys.ToList())
{
if (!nades.TryGetValue(index, out var data)) continue;
(Vector oldPos, double createdTime) = data;
var nade = Utilities.GetEntityFromIndex<CBaseCSGrenadeProjectile>((int)index);
if (nade == null || !nade.IsValid || nade.AbsOrigin == null)
{
nades.TryRemove(index, out _);
continue;
}
Vector currentPos = new(nade.AbsOrigin.X, nade.AbsOrigin.Y, nade.AbsOrigin.Z);
double distanceMoved = SkillUtils.GetDistance(currentPos, oldPos);
Vector calculatedVelocity = CalculateVelocity(nade, nade.TeamNum);
Server.PrintToChatAll($"Dist: {distanceMoved}, vel: {calculatedVelocity}");
if (distanceMoved < 4 || calculatedVelocity.IsZero())
{
Server.PrintToChatAll($"Short, {Server.TickedTime} -> {createdTime + 3}, {createdTime + 3 - Server.TickedTime}s");
nade.DetonateTime = (float)createdTime + 3;
Utilities.SetStateChanged(nade, "CBaseGrenade", "m_flDetonateTime");
nades.TryRemove(index, out _);
continue;
}
Vector currentVel = new(nade.Velocity.X, nade.Velocity.Y, nade.Velocity.Z);
float maxVelocity = SkillsInfo.GetValue<float>(skillName, "maxVelocity");
Vector newVelocity = currentVel + calculatedVelocity;
float speed = newVelocity.Length();
if (speed > maxVelocity)
newVelocity *= (maxVelocity / speed);
nades[index] = (currentPos, createdTime);
nade.Teleport(null, null, newVelocity);
}
}
private static Vector CalculateVelocity(CBaseCSGrenadeProjectile nade, int team)
{
if (nade.AbsOrigin == null) return Vector.Zero;
Vector? closetEnemyPos = null;
double minDistance = int.MaxValue;
Vector nadePos = nade.AbsOrigin;
foreach (var enemy in Utilities.GetPlayers().Where(p => p.IsValid && p.PawnIsAlive && p.TeamNum != team))
{
var pawn = enemy.PlayerPawn.Value;
if (pawn?.IsValid != true || pawn.AbsOrigin == null) continue;
double dist = SkillUtils.GetDistance(nadePos, pawn.AbsOrigin);
if (dist < SkillsInfo.GetValue<float>(skillName, "detonationRange"))
{
nade.DetonateTime = 0;
Utilities.SetStateChanged(nade, "CBaseGrenade", "m_flDetonateTime");
nades.TryRemove(nade.Index, out _);
return Vector.Zero;
}
if (dist < minDistance)
{
minDistance = dist;
closetEnemyPos = pawn.AbsOrigin;
}
}
if (closetEnemyPos == null)
return Vector.Zero;
Vector direction = closetEnemyPos - nadePos;
float length = direction.Length();
if (length > 0)
{
float strength = SkillsInfo.GetValue<float>(skillName, "strength");
return new Vector(
(direction.X / length) * strength,
(direction.Y / length) * strength,
(direction.Z / length) * strength
);
}
return Vector.Zero;
}
public static void OnEntitySpawned(CEntityInstance @event)
{
var name = @event.DesignerName;
if (!name.EndsWith("_projectile") || name == "smokegrenade_projectile") return;
var grenade = @event.As<CBaseCSGrenadeProjectile>();
if (grenade == null || !grenade.IsValid) return;
if (grenade.OwnerEntity.Value == null || !grenade.OwnerEntity.Value.IsValid) return;
var pawn = grenade.OwnerEntity.Value.As<CCSPlayerPawn>();
if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
var player = pawn.Controller.Value.As<CCSPlayerController>();
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
grenade.DetonateTime = (float)Server.TickedTime + 6;
Vector pos = new(grenade.AbsOrigin?.X, grenade.AbsOrigin?.Y, grenade.AbsOrigin?.Z);
nades.TryAdd(grenade.Index, (pos, Server.TickedTime));
}
public static void EnableSkill(CCSPlayerController player)
{
SkillUtils.TryGiveWeapon(player, CsItem.HEGrenade);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#384728", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float strength = 150, float maxVelocity = 2000, float detonationRange = 130) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public float Strength { get; set; } = strength;
public float MaxVelocity { get; set; } = maxVelocity;
public float DetonationRange { get; set; } = detonationRange;
}
}
}

View file

@ -0,0 +1,102 @@
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 HotBomb : ISkill
{
private const Skills skillName = Skills.HotBomb;
private readonly static ConcurrentDictionary<uint, byte> players = [];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void OnTick()
{
float cooldown = SkillsInfo.GetValue<float>(skillName, "cooldown");
if (Server.TickCount % (int)(cooldown * 64) != 0) return;
if (players.IsEmpty || jRandomSkills.Instance.GameRules?.FreezePeriod == true) return;
int damage = SkillsInfo.GetValue<int>(skillName, "damage");
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && p.Team == CsTeam.Terrorist && p.PawnIsAlive))
{
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.WeaponServices == null) continue;
bool hasC4 = pawn.WeaponServices.MyWeapons.Any(w => w.Value?.DesignerName == "weapon_c4");
if (!hasC4) continue;
SkillUtils.TakeHealth(pawn, damage);
player.ExecuteClientCommand("play sounds/player/burn_damage1");
}
}
public static void WeaponPickup(EventItemPickup @event)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return;
var weapon = @event.Item;
if (string.IsNullOrEmpty(weapon) || weapon != "c4") return;
player.PrintToCenterAlert(player.GetTranslation("hotbomb_hint"));
}
private static void ChangeC4Color()
{
Server.NextFrame(() =>
{
var bombEntities = Utilities.FindAllEntitiesByDesignerName<CC4>("weapon_c4").ToList();
if (bombEntities.Count == 0) return;
var bomb = bombEntities.FirstOrDefault();
if (bomb == null) return;
bomb.Render = Color.Red;
Utilities.SetStateChanged(bomb, "CBaseModelEntity", "m_clrRender");
});
}
public static void PlayerDeath(EventPlayerDeath @event)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return;
players.TryRemove(player.Index, out _);
}
public static void NewRound()
{
players.Clear();
}
public static void EnableSkill(CCSPlayerController player)
{
if (players.IsEmpty)
{
ChangeC4Color();
foreach (var enemy in Utilities.GetPlayers().Where(p => p.IsValid && p.Team == CsTeam.Terrorist && p.PawnIsAlive))
enemy.PrintToCenterAlert(enemy.GetTranslation("hotbomb_hint"));
}
players.TryAdd(player.Index, 0);
}
public static void DisableSkill(CCSPlayerController player)
{
players.TryRemove(player.Index, out _);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#baf081", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float cooldown = 1, int damage = 2) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public float Cooldown { get; set; } = cooldown;
public int Damage { get; set; } = damage;
}
}
}

View file

@ -47,8 +47,8 @@ namespace src.player.skills
return Utilities.GetPlayers().Any( return Utilities.GetPlayers().Any(
p => p.IsValid && p => p.IsValid &&
p.PawnIsAlive && p.PawnIsAlive &&
p.Team != player.Team p.Team != player.Team &&
&& playersWithSkill.Contains(p.SteamID)); playersWithSkill.Contains(p.SteamID));
} }
public static string? GetRandomText(string? input) public static string? GetRandomText(string? input)

View file

@ -0,0 +1,217 @@
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 Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
namespace src.player.skills
{
public class Illusionist : ISkill
{
private const Skills skillName = Skills.Illusionist;
private static readonly ConcurrentDictionary<ulong, PlayerSkillInfo> SkillPlayerInfo = [];
private static readonly ConcurrentDictionary<int, Timer> ActiveTimers = [];
private static readonly object setLock = new();
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
ClearAllReplicas();
lock (setLock)
SkillPlayerInfo.Clear();
}
private static void ClearAllReplicas()
{
foreach (var timer in ActiveTimers.Values) timer?.Kill();
ActiveTimers.Clear();
var entities = Utilities.FindAllEntitiesByDesignerName<CDynamicProp>("prop_dynamic_override");
foreach (var entity in entities)
if (entity != null && entity.IsValid && entity.Entity != null && !string.IsNullOrEmpty(entity.Entity.Name) && (entity.Entity.Name?.StartsWith("Illusionist_") ?? false))
entity.AcceptInput("Kill");
}
public static void OnTick()
{
foreach (var player in Utilities.GetPlayers())
{
if (player == null || !player.IsValid || player.IsBot) continue;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill == skillName)
if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo))
UpdateHUD(player, skillInfo);
}
}
public static void EnableSkill(CCSPlayerController player)
{
SkillPlayerInfo.TryAdd(player.SteamID, new PlayerSkillInfo
{
SteamID = player.SteamID,
CanUse = true,
Cooldown = DateTime.MinValue,
});
}
public static void DisableSkill(CCSPlayerController player)
{
SkillPlayerInfo.TryRemove(player.SteamID, out _);
SkillUtils.ResetPrintHTML(player);
}
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo)
{
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 = Instance.SkillPlayer.FirstOrDefault(s => s.SteamID == player?.SteamID);
if (playerInfo == null) return;
if (cooldown == 0)
playerInfo.PrintHTML = null;
else
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
}
public static void UseSkill(CCSPlayerController player)
{
if (player == null || !player.IsValid || !player.PawnIsAlive) return;
if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo) && skillInfo.CanUse)
{
skillInfo.CanUse = false;
skillInfo.Cooldown = DateTime.Now;
CreateReplica(player);
}
}
private static void CreateReplica(CCSPlayerController player)
{
var playerPawn = player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid) return;
if (playerPawn.AbsOrigin == null || playerPawn.AbsRotation == null) return;
var replica = Utilities.CreateEntityByName<CDynamicProp>("prop_dynamic_override");
if (replica == null || !replica.IsValid) return;
replica.Collision.SolidType = SolidType_t.SOLID_VPHYSICS;
replica.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags = (uint)(replica.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags & ~(1 << 2));
replica.SetModel(playerPawn!.CBodyComponent!.SceneNode!.GetSkeletonInstance().ModelState.ModelName);
replica.Entity!.Name = replica.Globalname = $"Illusionist_{Server.TickCount}_{(player.Team == CsTeam.CounterTerrorist ? "CT" : "TT")}";
replica.UseAnimGraph = false;
replica.DispatchSpawn();
float distance = 40;
Vector startPos = playerPawn.AbsOrigin + SkillUtils.GetForwardVector(playerPawn.AbsRotation) * distance;
QAngle angle = new(0, playerPawn.EyeAngles.Y, 0);
replica.Teleport(startPos, angle, new Vector(0, 0, -100));
bool ducking = ((PlayerFlags)playerPawn.Flags).HasFlag(PlayerFlags.FL_DUCKING);
string animName = ducking ? "crouch_new_knife_n" : "run_new_knife_n";
replica.AcceptInput("SetAnimation", value: animName);
replica.AcceptInput("SetPlaybackRate", value: "1.0");
float speed = ducking ? 1.25f : 3.5f;
Vector forwardVec = SkillUtils.GetForwardVector(angle);
int replicaIndex = (int)replica.Index;
Instance.AddTickTimer(10, () => {
var moveTimer = Instance.AddTickTimer(1, () =>
{
if (replica == null || !replica.IsValid)
{
if (ActiveTimers.TryRemove(replicaIndex, out var timer)) timer?.Kill();
return;
}
if (ducking && Server.TickCount % 50 == 0)
{
replica.AcceptInput("SetAnimation", value: animName);
replica.AcceptInput("SetPlaybackRate", value: "1.0");
}
Vector currentPos = replica.AbsOrigin!;
Vector nexPos = new(
currentPos.X + (forwardVec.X * speed),
currentPos.Y + (forwardVec.Y * speed),
currentPos.Z
);
replica.Teleport(nexPos, null, null);
}, TimerFlags.REPEAT | TimerFlags.STOP_ON_MAPCHANGE);
ActiveTimers.TryAdd(replicaIndex, moveTimer);
});
float duration = SkillsInfo.GetValue<float>(skillName, ducking ? "durationCrouch" : "durationRun");
Instance.AddTimer(duration, () =>
{
if (replica != null && replica.IsValid)
{
replica.AcceptInput("Kill");
if (ActiveTimers.TryRemove(replicaIndex, out var timer)) timer?.Kill();
}
});
}
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;
if (string.IsNullOrEmpty(param.Entity.Name)) return;
if (!param.Entity.Name.StartsWith("Illusionist_")) return;
var replica = param.As<CDynamicProp>();
if (replica == null || !replica.IsValid) return;
replica.EmitSound("GlassBottle.BulletImpact", volume: 1f);
if (ActiveTimers.TryRemove((int)replica.Index, out var timer)) timer?.Kill();
replica.AcceptInput("Kill");
CCSPlayerPawn attackerPawn = new(param2.Attacker.Value.Handle);
if (attackerPawn.DesignerName != "player") return;
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"));
}
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 = "#42f5ef", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float cooldown = 30f, float durationRun = 5, float durationCrouch = 12, int yourTeamDamage = 10, int enemyTeamDamage = 20) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public float Cooldown { get; set; } = cooldown;
public float DurationRun { get; set; } = durationRun;
public float DurationCrouch { get; set; } = durationCrouch;
public int YourTeamDamage { get; set; } = yourTeamDamage;
public int EnemyTeamDamage { get; set; } = enemyTeamDamage;
}
}
}

View file

@ -59,7 +59,7 @@ namespace src.player.skills
var weapon = hook.GetParam<CBasePlayerWeapon>(0); var weapon = hook.GetParam<CBasePlayerWeapon>(0);
var action = hook.GetParam<short>(1); var action = hook.GetParam<short>(1);
if (action != actionCode || weapon?.DesignerName != "weapon_knife") return HookResult.Continue; if (action != actionCode || (weapon?.DesignerName != "weapon_knife" && weapon?.DesignerName != "weapon_bayonet")) return HookResult.Continue;
if (weapon.OwnerEntity.Value == null || !weapon.OwnerEntity.Value.IsValid) return HookResult.Continue; if (weapon.OwnerEntity.Value == null || !weapon.OwnerEntity.Value.IsValid) return HookResult.Continue;
var pawn = weapon.OwnerEntity.Value.As<CCSPlayerPawn>(); var pawn = weapon.OwnerEntity.Value.As<CCSPlayerPawn>();
@ -87,7 +87,7 @@ namespace src.player.skills
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.WeaponServices == null) return; if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.WeaponServices == null) return;
var activeWeapon = pawn.WeaponServices.ActiveWeapon.Value; var activeWeapon = pawn.WeaponServices.ActiveWeapon.Value;
if (activeWeapon == null || !activeWeapon.IsValid || activeWeapon.DesignerName != "weapon_knife") return; if (activeWeapon == null || !activeWeapon.IsValid || (activeWeapon.DesignerName != "weapon_knife" && activeWeapon.DesignerName != "weapon_bayonet")) return;
KnifeHit(player, false); KnifeHit(player, false);
} }

View file

@ -0,0 +1,86 @@
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;
using static src.jRandomSkills;
namespace src.player.skills
{
public class MagneticDecoy : ISkill
{
private const Skills skillName = Skills.MagneticDecoy;
private static readonly ConcurrentDictionary<Vector, byte> decoys = [];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
decoys.Clear();
}
public static void DecoyStarted(EventDecoyStarted @event)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
decoys.TryAdd(new Vector(@event.X, @event.Y, @event.Z), 0);
}
public static void DecoyDetonate(EventDecoyDetonate @event)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
foreach (var decoy in decoys.Keys.Where(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z))
decoys.TryRemove(decoy, out _);
}
public static void OnTick()
{
foreach (Vector decoyPos in decoys.Keys)
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && p.PawnIsAlive && p.Team is CsTeam.CounterTerrorist or CsTeam.Terrorist))
{
var decoyRadius = SkillsInfo.GetValue<float>(skillName, "triggerRadius");
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) continue;
double distance = SkillUtils.GetDistance(decoyPos, pawn.AbsOrigin);
if (distance <= decoyRadius && distance > 10)
{
Vector direction = new(decoyPos.X - pawn.AbsOrigin.X, decoyPos.Y - pawn.AbsOrigin.Y, 0);
float length = direction.Length();
Vector normalized = direction / length;
float ratio = 1 - (float)(distance / decoyRadius);
float strenght = SkillsInfo.GetValue<float>(skillName, "strenght") * ratio;
pawn.AbsVelocity.X += normalized.X * strenght;
pawn.AbsVelocity.Y += normalized.Y * strenght;
}
}
}
public static void EnableSkill(CCSPlayerController player)
{
SkillUtils.TryGiveWeapon(player, CsItem.DecoyGrenade);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#81f0c4", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float triggerRadius = 180, float strenght = 30) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public float TriggerRadius { get; set; } = triggerRadius;
public float Strenght { get; set; } = strenght;
}
}
}

View file

@ -0,0 +1,87 @@
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 Magneto : ISkill
{
private const Skills skillName = Skills.Magneto;
private readonly static ConcurrentDictionary<uint, byte> nades = [];
private readonly static ConcurrentDictionary<uint, byte> players = [];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
nades.Clear();
players.Clear();
}
public static void OnTick()
{
if (Server.TickCount % 5 != 0) return;
float radius = SkillsInfo.GetValue<float>(skillName, "radius");
foreach (var nadeIndex in nades.Keys)
{
var nade = Utilities.GetEntityFromIndex<CBaseCSGrenadeProjectile>((int)nadeIndex);
if (nade == null || !nade.IsValid)
{
nades.TryRemove(nadeIndex, out _);
continue;
}
foreach (var playerIndex in players.Keys)
{
var player = Utilities.GetPlayerFromIndex((int)playerIndex);
if (player == null || !player.IsValid || !player.PawnIsAlive || player.PlayerPawn.Value == null || !player.PlayerPawn.Value.IsValid)
{
players.TryRemove(playerIndex, out _);
continue;
}
var pawn = player.PlayerPawn.Value;
double distanceMoved = SkillUtils.GetDistance(nade.AbsOrigin ?? Vector.Zero, pawn.AbsOrigin ?? Vector.Zero);
if (distanceMoved < radius && nade.TeamNum != player.TeamNum)
{
nade.Teleport(null, null, -nade.AbsVelocity);
nades.TryRemove(nadeIndex, out _);
}
}
}
}
public static void OnEntitySpawned(CEntityInstance @event)
{
var name = @event.DesignerName;
if (!name.EndsWith("_projectile")) return;
var grenade = @event.As<CBaseCSGrenadeProjectile>();
if (grenade == null || !grenade.IsValid) return;
nades.TryAdd(grenade.Index, 0);
}
public static void EnableSkill(CCSPlayerController player)
{
players.TryAdd(player.Index, 0);
}
public static void DisableSkill(CCSPlayerController player)
{
players.TryRemove(player.Index, out _);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#f081ec", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float radius = 100) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public float Radius { get; set; } = radius;
}
}
}

View file

@ -127,7 +127,7 @@ namespace src.player.skills
if (buttons.HasFlag(PlayerButtons.Duck)) if (buttons.HasFlag(PlayerButtons.Duck))
percentInvisibility += SkillsInfo.GetValue<float>(skillName, "duckPercentInvisibility"); percentInvisibility += SkillsInfo.GetValue<float>(skillName, "duckPercentInvisibility");
if (activeWeapon != null && activeWeapon.DesignerName == "weapon_knife") if (activeWeapon != null && (activeWeapon.DesignerName == "weapon_knife" || activeWeapon.DesignerName == "weapon_bayonet"))
percentInvisibility += SkillsInfo.GetValue<float>(skillName, "knifePercentInvisibility"); percentInvisibility += SkillsInfo.GetValue<float>(skillName, "knifePercentInvisibility");
if (!buttons.HasFlag(PlayerButtons.Moveleft) && !buttons.HasFlag(PlayerButtons.Moveright) && !buttons.HasFlag(PlayerButtons.Forward) && !buttons.HasFlag(PlayerButtons.Back) && flags.HasFlag(PlayerFlags.FL_ONGROUND)) if (!buttons.HasFlag(PlayerButtons.Moveleft) && !buttons.HasFlag(PlayerButtons.Moveright) && !buttons.HasFlag(PlayerButtons.Forward) && !buttons.HasFlag(PlayerButtons.Back) && flags.HasFlag(PlayerFlags.FL_ONGROUND))
percentInvisibility += SkillsInfo.GetValue<float>(skillName, "idlePercentInvisibility"); percentInvisibility += SkillsInfo.GetValue<float>(skillName, "idlePercentInvisibility");

View file

@ -21,10 +21,19 @@ namespace src.player.skills
public static void NewRound() public static void NewRound()
{ {
ClearAllReplicas();
lock (setLock) lock (setLock)
SkillPlayerInfo.Clear(); SkillPlayerInfo.Clear();
} }
private static void ClearAllReplicas()
{
var entities = Utilities.FindAllEntitiesByDesignerName<CDynamicProp>("prop_dynamic_override");
foreach (var entity in entities)
if (entity != null && entity.IsValid && entity.Entity != null && !string.IsNullOrEmpty(entity.Entity.Name) && (entity.Entity.Name?.StartsWith("Replica_") ?? false))
entity.AcceptInput("Kill");
}
public static void OnTick() public static void OnTick()
{ {
foreach (var player in Utilities.GetPlayers()) foreach (var player in Utilities.GetPlayers())

View file

@ -38,7 +38,6 @@ namespace src.player.skills
var moneyServices = player.InGameMoneyServices; var moneyServices = player.InGameMoneyServices;
if (moneyServices == null) return; if (moneyServices == null) return;
player.PrintToChat(moneyServices.CashSpentThisRound.ToString());
int money = Math.Abs((int)playerInfo.SkillChance! - moneyServices.CashSpentThisRound); int money = Math.Abs((int)playerInfo.SkillChance! - moneyServices.CashSpentThisRound);
AddMoney(player, -money, 3000); AddMoney(player, -money, 3000);
} }

View file

@ -1,20 +1,19 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Timers;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using Microsoft.Extensions.Logging;
using src.utils; using src.utils;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using static src.jRandomSkills; using static src.jRandomSkills;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
namespace src.player.skills namespace src.player.skills
{ {
public class Smoker : ISkill public class Smoker : ISkill
{ {
private const Skills skillName = Skills.Smoker; private const Skills skillName = Skills.Smoker;
private readonly static ConcurrentDictionary<uint, int> smokes = []; private readonly static ConcurrentDictionary<ulong, List<Timer>> playerSmokes = [];
private static readonly object setLock = new(); private static readonly object setLock = new();
public static void LoadSkill() public static void LoadSkill()
@ -25,9 +24,11 @@ namespace src.player.skills
public static void NewRound() public static void NewRound()
{ {
lock (setLock) lock (setLock)
smokes.Clear(); {
foreach (var timers in playerSmokes.Values)
timers.ForEach(t => t?.Kill());
playerSmokes.Clear();
}
} }
public static void EnableSkill(CCSPlayerController player) public static void EnableSkill(CCSPlayerController player)
@ -35,28 +36,13 @@ namespace src.player.skills
SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade); SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade);
} }
public static void SmokegrenadeDetonate(EventSmokegrenadeDetonate @event) public static void DisableSkill(CCSPlayerController player)
{ {
Server.PrintToChatAll("BOOM"); if (playerSmokes.TryRemove(player.SteamID, out var timers))
var player = @event.Userid; timers.ForEach(t => t?.Kill());
if (player == null || !player.IsValid) return;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
var smoke = Utilities.GetEntityFromIndex<CSmokeGrenadeProjectile>(@event.Entityid);
if (smoke == null || !smoke.IsValid) return;
smokes.TryAdd(smoke.Index, Server.TickCount);
// smoke.SmokeEffectTickBegin = Server.TickCount - ((19 - 15) * 64);
smoke.NextThinkTick = 0;
// Utilities.SetStateChanged(smoke, "CSmokeGrenadeProjectile", "m_nSmokeEffectTickBegin");
Utilities.SetStateChanged(smoke, "CBaseEntity", "m_nNextThinkTick");
} }
public static void SmokegrenadeExpired(EventSmokegrenadeExpired @event) public static void SmokegrenadeDetonate(EventSmokegrenadeDetonate @event)
{ {
var player = @event.Userid; var player = @event.Userid;
if (player == null || !player.IsValid) return; if (player == null || !player.IsValid) return;
@ -65,7 +51,22 @@ namespace src.player.skills
if (playerInfo?.Skill != skillName) return; if (playerInfo?.Skill != skillName) return;
Vector pos = new(@event.X, @event.Y, @event.Z); Vector pos = new(@event.X, @event.Y, @event.Z);
SkillUtils.CreateSmokeGrenadeProjectile(pos, new QAngle(0, 0, 0), new Vector(0, 0, 0), player.TeamNum); float refillInterval = 15.5f;
Timer? smokeTimer = null;
smokeTimer = Instance.AddTimer(refillInterval, () =>
{
if (player == null || !player.IsValid)
{
smokeTimer?.Kill();
return;
}
Server.PrintToChatAll("Create Smoke");
SkillUtils.CreateSmokeGrenadeProjectile(pos, QAngle.Zero, Vector.Zero, player.TeamNum);
}, TimerFlags.REPEAT | TimerFlags.STOP_ON_MAPCHANGE);
playerSmokes.AddOrUpdate(player.SteamID, [smokeTimer], (_, list) => { list.Add(smokeTimer); return list; });
} }
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#b5ab8f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#b5ab8f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)

View file

@ -75,16 +75,33 @@ namespace src.player.skills
if (playerAWPIndexes.TryGetValue(player.SteamID, out var AWPs)) if (playerAWPIndexes.TryGetValue(player.SteamID, out var AWPs))
foreach (var index in AWPs.ToList()) foreach (var index in AWPs.ToList())
{ {
var ent = Utilities.GetEntityFromIndex<CBaseEntity>((int)index); var pawn = player.PlayerPawn.Value;
if (ent != null && ent.IsValid) if (pawn == null || !pawn.IsValid || pawn.WeaponServices == null) continue;
ent.AcceptInput("Kill");
var weapon = pawn.WeaponServices.MyWeapons.FirstOrDefault(w => w != null && w.IsValid && w.Value != null && w.Value.IsValid && AWPs.Contains(w.Value.Index));
if (weapon == null) continue;
weapon.Value?.AddEntityIOEvent("Kill", weapon.Value, delay: 0.1f);
} }
if (savedWeapons.TryGetValue(player.SteamID, out string? savedWeapon) && !string.IsNullOrWhiteSpace(savedWeapon)) if (savedWeapons.TryGetValue(player.SteamID, out string? savedWeapon) && !string.IsNullOrWhiteSpace(savedWeapon))
Server.NextFrame(() => Server.NextFrame(() =>
player.PlayerPawn.Value?.ItemServices?.As<CCSPlayer_ItemServices>().GiveNamedItem<CEntityInstance>(savedWeapon)); {
if (player == null || !player.IsValid || !player.PawnIsAlive) return;
Server.NextFrame(() => player.ExecuteClientCommand("lastinv")); var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid) return;
var itemServices = pawn.ItemServices;
if (itemServices != null && itemServices.Handle != IntPtr.Zero)
player.GiveNamedItem(savedWeapon);
});
Server.NextFrame(() =>
{
if (player != null && player.IsValid && player.PawnIsAlive)
player.ExecuteClientCommand("lastinv");
});
savedWeapons.TryRemove(player.SteamID, out _); savedWeapons.TryRemove(player.SteamID, out _);
playerAWPIndexes.TryRemove(player.SteamID, out _); playerAWPIndexes.TryRemove(player.SteamID, out _);
@ -135,7 +152,7 @@ namespace src.player.skills
weaponToGive = weapon_awp + "_script"; weaponToGive = weapon_awp + "_script";
} }
activeRifle.AcceptInput("Kill"); activeRifle.AddEntityIOEvent("Kill", activeRifle, delay: 0.1f);
} }
else else
{ {
@ -200,7 +217,7 @@ namespace src.player.skills
{ {
var ent = Utilities.GetEntityFromIndex<CBaseEntity>((int)index); var ent = Utilities.GetEntityFromIndex<CBaseEntity>((int)index);
if (ent != null && ent.IsValid) if (ent != null && ent.IsValid)
ent.AcceptInput("Kill"); ent.AddEntityIOEvent("Kill", ent, delay: 0.1f);
AWPs.Remove(index); AWPs.Remove(index);
} }

View file

@ -0,0 +1,204 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
using System.Drawing;
using static src.jRandomSkills;
namespace src.player.skills
{
public class ThrowingKnife : ISkill
{
private const Skills skillName = Skills.ThrowingKnife;
private readonly static ConcurrentDictionary<uint, uint> triggers = [];
private readonly static ConcurrentDictionary<uint, uint> glows = [];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
foreach (var player in Utilities.GetPlayers())
DisableSkill(player);
triggers.Clear();
glows.Clear();
}
public static void EnableSkill(CCSPlayerController player)
{
Event.EnableTransmit();
}
public static void DisableSkill(CCSPlayerController player)
{
var playersTriggers = triggers.Where(t => t.Value == player.Index).Select(t => t.Key).ToList();
foreach (var triggerIndex in playersTriggers)
if (triggers.TryRemove(triggerIndex, out _))
{
var entity = Utilities.GetEntityFromIndex<CTriggerMultiple>((int)triggerIndex);
if (entity != null && entity.IsValid)
Server.NextFrame(() =>
{
if (entity.IsValid)
entity.AcceptInput("Kill");
});
}
if (glows.TryRemove(player.Index, out uint glowIndex))
{
var entity = Utilities.GetEntityFromIndex<CTriggerMultiple>((int)glowIndex);
if (entity != null && entity.IsValid)
Server.NextFrame(() =>
{
if (entity.IsValid)
entity.AcceptInput("Kill");
});
}
}
public static void UseSkill(CCSPlayerController player)
{
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
DropKnife(player);
}
private static void DropKnife(CCSPlayerController player)
{
player.ExecuteClientCommand("slot3");
Instance.AddTickTimer(8, () =>
{
if (player == null || !player.IsValid) return;
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.WeaponServices == null) return;
var weapon = pawn.WeaponServices.ActiveWeapon.Value;
if (weapon == null || !weapon.IsValid || (!weapon.DesignerName.Contains("knife") && !weapon.DesignerName.Contains("bayonet"))) return;
player.DropActiveWeapon();
Server.NextFrame(() => ThrowKnife(player, weapon) );
});
}
private static void ThrowKnife(CCSPlayerController player, CBasePlayerWeapon knife)
{
if (player == null || !player.IsValid) return;
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
if (knife == null || !knife.IsValid || knife.AbsOrigin == null) return;
float force = 2000;
Vector pos = new(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z + pawn.ViewOffset.Z);
QAngle angle = new(0, 0, 0);
Vector vel = SkillUtils.GetForwardVector(pawn.EyeAngles) * force;
knife.Collision.CollisionAttribute.InteractsWith = pawn.Collision.CollisionAttribute.InteractsWith;
knife.Teleport(pos, angle, vel);
CreateTrigger(player, knife);
CreateGlow(player, knife);
}
private static void CreateTrigger(CCSPlayerController player, CBaseEntity knife)
{
if (player == null || !player.IsValid) return;
if (triggers.Any(t => t.Value == player.Index)) return;
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
if (knife == null || !knife.IsValid || knife.AbsOrigin == null) return;
var trigger = SkillUtils.CreateTrigger($"trowingknife", 10, knife.AbsOrigin);
if (trigger == null || !trigger.IsValid) return;
trigger.AcceptInput("SetParent", knife, knife, "!activator");
triggers.TryAdd(trigger.Index, player.Index);
}
private static void CreateGlow(CCSPlayerController player, CBaseEntity knife)
{
if (player == null || !player.IsValid) return;
if (glows.ContainsKey(player.Index)) return;
if (knife == null || !knife.IsValid || knife.AbsOrigin == null) return;
var modelGlow = Utilities.CreateEntityByName<CPhysicsPropMultiplayer>("prop_physics_multiplayer");
if (modelGlow == null) return;
modelGlow.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags = (uint)(modelGlow.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags & ~(1 << 2));
modelGlow.SetModel(knife.CBodyComponent!.SceneNode!.GetSkeletonInstance().ModelState.ModelName);
modelGlow.DispatchSpawn();
modelGlow.Glow.GlowColorOverride = Color.GreenYellow;
modelGlow.Glow.GlowRange = 5000;
modelGlow.Glow.GlowTeam = -1;
modelGlow.Glow.GlowType = 3;
modelGlow.Glow.GlowRangeMin = 10;
modelGlow.Teleport(knife.AbsOrigin, knife.AbsRotation, knife.AbsVelocity);
modelGlow.AcceptInput("SetParent", knife, modelGlow, "!activator");
glows.TryAdd(player.Index, modelGlow.Index);
}
public static void OnTriggerEnter(CBaseTrigger trigger, CBaseEntity entity)
{
if (entity == null || !entity.IsValid || trigger == null || !trigger.IsValid) return;
string triggerName = trigger.Globalname;
if (entity.DesignerName != "player" || string.IsNullOrEmpty(triggerName) || !triggerName.StartsWith("trowingknife")) return;
if (triggers.TryGetValue(trigger.Index, out var throwerIndex))
{
var thrower = Utilities.GetPlayerFromIndex((int)throwerIndex);
if (thrower == null || !thrower.IsValid) return;
CCSPlayerPawn victimPawn = entity.As<CCSPlayerPawn>();
if (victimPawn == null || !victimPawn.IsValid || victimPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
if (thrower != null && thrower.Pawn.Value != null && victimPawn.Index == thrower.Pawn.Index) return;
if (CheckHasKnife(thrower!)) return;
SkillUtils.TakeHealth(victimPawn, 99999);
Server.PrintToChatAll($"HIT");
}
}
private static bool CheckHasKnife(CCSPlayerController player)
{
var pawn = player.PlayerPawn.Value;
if (pawn == null || !pawn.IsValid || pawn.WeaponServices == null) return false;
return pawn.WeaponServices.MyWeapons.Any(w => w.IsValid && w != null && w.Value != null && w.Value.IsValid && (w.Value.DesignerName.Contains("knife") || w.Value.DesignerName.Contains("bayonet")));
}
public static void CheckTransmit([CastFrom(typeof(nint))] CCheckTransmitInfoList infoList)
{
foreach (var (info, player) in infoList)
{
if (player == null || !player.IsValid) continue;
var observedPlayer = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == player?.Pawn?.Value?.ObserverServices?.ObserverTarget?.Value?.Handle);
foreach (var glow in glows)
{
if (glow.Key == player.Index || (observedPlayer != null && observedPlayer.IsValid && glow.Key == observedPlayer.Index)) continue;
var glowEntity = Utilities.GetEntityFromIndex<CBaseEntity>((int)glow.Value);
if (glowEntity == null || !glowEntity.IsValid) continue;
info.TransmitEntities.Remove(glowEntity.Index);
}
}
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#8f108f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
}
}
}

View file

@ -41,6 +41,7 @@ namespace src.player.skills
CCSPlayerPawn playerPawn = new(entity.Handle); CCSPlayerPawn playerPawn = new(entity.Handle);
if (playerPawn == null || playerPawn.Controller?.Value == null)return; if (playerPawn == null || playerPawn.Controller?.Value == null)return;
CCSPlayerController player = playerPawn.Controller.Value.As<CCSPlayerController>(); CCSPlayerController player = playerPawn.Controller.Value.As<CCSPlayerController>();
if (player == null) return; if (player == null) return;

View file

@ -0,0 +1,92 @@
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;
using static src.jRandomSkills;
namespace src.player.skills
{
public class Weightless : ISkill
{
private const Skills skillName = Skills.Weightless;
private readonly static ConcurrentDictionary<uint, byte> nades = [];
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
nades.Clear();
}
public static void OnTick()
{
if (Server.TickCount % 10 != 0) return;
foreach ((var index, _) in nades)
{
var nade = Utilities.GetEntityFromIndex<CBaseCSGrenadeProjectile>((int)index);
if (nade == null || !nade.IsValid)
{
nades.TryRemove(index, out _);
continue;
}
if (nade.Bounces != 0)
{
nade.ActualGravityScale = 2;
nade.DetonateTime = 0;
Utilities.SetStateChanged(nade, "CBaseGrenade", "m_flDetonateTime");
nades.TryRemove(index, out _);
}
}
}
public static void OnEntitySpawned(CEntityInstance @event)
{
var name = @event.DesignerName;
if (!name.EndsWith("_projectile")) return;
var grenade = @event.As<CBaseCSGrenadeProjectile>();
if (grenade == null || !grenade.IsValid) return;
if (grenade.OwnerEntity.Value == null || !grenade.OwnerEntity.Value.IsValid) return;
var pawn = grenade.OwnerEntity.Value.As<CCSPlayerPawn>();
if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
var player = pawn.Controller.Value.As<CCSPlayerController>();
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
Server.NextFrame(() => {
if (grenade == null || !grenade.IsValid) return;
grenade.ActualGravityScale = .0001f;
Vector currentVelocity = new(grenade.AbsVelocity.X, grenade.AbsVelocity.Y, grenade.AbsVelocity.Z);
float speed = currentVelocity.Length() * 2;
Vector forward = SkillUtils.GetForwardVector(pawn.EyeAngles);
Vector newVelocity = forward * speed;
grenade.Teleport(null, null, newVelocity);
nades.TryAdd(grenade.Index, 0);
});
}
public static void EnableSkill(CCSPlayerController player)
{
SkillUtils.TryGiveWeapon(player, CsItem.HEGrenade);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#8f6dc9", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
}
}
}

View file

@ -0,0 +1,149 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
namespace src.player.skills
{
public class WildThrow : ISkill
{
private const Skills skillName = Skills.WildThrow;
private readonly static ConcurrentDictionary<ulong, byte> infectedPlayers = [];
private static readonly object setLock = new();
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
lock (setLock)
infectedPlayers.Clear();
foreach (var player in Utilities.GetPlayers())
DisableSkill(player);
}
public static void PlayerDeath(EventPlayerDeath @event)
{
var player = @event.Userid;
if (player == null) return;
DisableSkill(player);
}
public static void EnableSkill(CCSPlayerController player)
{
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo == null) return;
playerInfo.SkillUsed = false;
var enemies = Utilities.GetPlayers().Where(p => p.PawnIsAlive && p.Team != player.Team && p.IsValid && !p.IsBot && !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
player.PrintToChat($" {ChatColors.Red}{player.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
}
public static void DisableSkill(CCSPlayerController player)
{
infectedPlayers.TryRemove(player.SteamID, out _);
SkillUtils.CloseMenu(player);
}
public static void OnTick()
{
if (Server.TickCount % 32 != 0) return;
foreach (var player in Utilities.GetPlayers())
{
if (!SkillUtils.HasMenu(player)) continue;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo == null || playerInfo.Skill != skillName) continue;
var enemies = Utilities.GetPlayers().Where(p => p.PawnIsAlive && p.Team != player.Team && p.IsValid && !p.IsBot && !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.PawnIsAlive) return;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
if (playerInfo.SkillUsed)
{
player.PrintToChat($" {ChatColors.Red}{player.GetTranslation("areareaper_used_info")}");
return;
}
string enemyId = commands[0];
var enemy = Utilities.GetPlayers().FirstOrDefault(p => p.Team != player.Team && p.Index.ToString() == enemyId);
if (enemy == null)
{
player.PrintToChat($" {ChatColors.Red}" + player.GetTranslation("selectplayerskill_incorrect_enemy_index"));
return;
}
infectedPlayers.TryAdd(enemy.SteamID, 0);
playerInfo.SkillUsed = true;
player.PrintToChat($" {ChatColors.Green}" + player.GetTranslation("wildthrow_player_info", enemy.PlayerName));
}
public static void OnEntitySpawned(CEntityInstance @event)
{
var name = @event.DesignerName;
if (!name.EndsWith("_projectile")) return;
var grenade = @event.As<CBaseCSGrenadeProjectile>();
if (grenade == null || !grenade.IsValid) return;
if (grenade.OwnerEntity.Value == null || !grenade.OwnerEntity.Value.IsValid) return;
var pawn = grenade.OwnerEntity.Value.As<CCSPlayerPawn>();
if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
var player = pawn.Controller.Value.As<CCSPlayerController>();
if (!infectedPlayers.ContainsKey(player.SteamID)) return;
Server.NextFrame(() => {
if (grenade == null || !grenade.IsValid) return;
float forceMultiplier = (float)(Instance.Random.NextDouble() * .6 + .7);
float min = 150;
float max = 450;
float devX = GetRandom(min, max);
float devY = GetRandom(min, max);
float devZ = GetRandom(min, max);
Vector randomDev = new(devX, devY, devZ);
Vector newVelocity = new(
(grenade.Velocity.X + randomDev.X) * forceMultiplier,
(grenade.Velocity.Y + randomDev.Y) * forceMultiplier,
(grenade.Velocity.Z + randomDev.Z) * forceMultiplier
);
grenade.Teleport(null, null, newVelocity);
});
}
private static float GetRandom(float min, float max)
{
float val = (float)(Instance.Random.NextDouble() * (max - min) + min);
return Instance.Random.Next(0, 2) == 0 ? val : -val;
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#384728", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
}
}
}

View file

@ -20,10 +20,11 @@ namespace src.utils
public static class SkillUtils public static class SkillUtils
{ {
private static readonly MemoryFunctionWithReturn<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, int> HEGrenadeProjectile_CreateFunc = new(GameData.GetSignature("HEGrenadeProjectile_CreateFunc")); private static readonly MemoryFunctionWithReturn<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, int> HEGrenadeProjectile_CreateFunc = new(GameData.GetSignature("HEGrenadeProjectile_CreateFunc"));
private static readonly MemoryFunctionWithReturn<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, int> SmokeGrenadeProjectile_CreateFunc = new(GameData.GetSignature("SmokeGrenadeProjectile_CreateFunc")); private static readonly MemoryFunctionWithReturn<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, int, int, CSmokeGrenadeProjectile> SmokeGrenadeProjectile_CreateFunc = new(GameData.GetSignature("SmokeGrenadeProjectile_CreateFunc"));
private static readonly MemoryFunctionVoid<nint, float, RoundEndReason, nint, nint> TerminateRoundFunc = new(GameData.GetSignature("CCSGameRules_TerminateRound")); private static readonly MemoryFunctionVoid<nint, float, RoundEndReason, nint, nint> TerminateRoundFunc = new(GameData.GetSignature("CCSGameRules_TerminateRound"));
private static readonly MemoryFunctionVoid<CBasePlayerPawn, QAngle> SnapViewAngles = new(GameData.GetSignature("SnapViewAngles"));
public static void PrintToChat(CCSPlayerController player, string msg, string border = "tb", string? title = null) public static void PrintToChat(CCSPlayerController player, string? msg, string border = "tb", string? title = null)
{ {
if (!player.IsValid) return; if (!player.IsValid) return;
@ -93,6 +94,13 @@ namespace src.utils
return new Vector(x, y, z); return new Vector(x, y, z);
} }
public static void Look(this CBasePlayerPawn pawn, QAngle angle)
{
if (pawn == null || !pawn.IsValid) return;
SnapViewAngles.Invoke(pawn, angle);
}
public static CBeam? CreateLine(Vector start, Vector end, Color color) public static CBeam? CreateLine(Vector start, Vector end, Color color)
{ {
CBeam beam = Utilities.CreateEntityByName<CBeam>("beam")!; CBeam beam = Utilities.CreateEntityByName<CBeam>("beam")!;

View file

@ -19,5 +19,12 @@
"windows": "48 89 5C 24 ? 57 48 83 EC 20 44 0F BF C2", "windows": "48 89 5C 24 ? 57 48 83 EC 20 44 0F BF C2",
"linux": "55 48 89 E5 41 54 53 48 89 FB 66 83 FE 65" "linux": "55 48 89 E5 41 54 53 48 89 FB 66 83 FE 65"
} }
},
"SnapViewAngles": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B DA 48 8B F1 48 8D 55",
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 48 89 FB 48 89 F7 48 81 EC ? ? ? ? E8 ? ? ? ? 48 8B 93"
}
} }
} }

View file

@ -285,7 +285,7 @@
"psychicdefusing_hud_info": "{0} seconds remaining to defuse", "psychicdefusing_hud_info": "{0} seconds remaining to defuse",
"pilot": "Pilot", "pilot": "Pilot",
"pilot_desc": "Fly for a limited time. Hold [USE - E] to fly", "pilot_desc": "Fly for a limited time. Double-click the jump to fly",
"pilot_hud_info": "Fuel", "pilot_hud_info": "Fuel",
"planter": "Free Planter", "planter": "Free Planter",
@ -369,6 +369,9 @@
"silent": "Silent", "silent": "Silent",
"silent_desc": "Your footsteps and jumps are silent to OTHER players", "silent_desc": "Your footsteps and jumps are silent to OTHER players",
"smoker": "Smoker",
"smoker_desc": "Your smoke grenades never run out",
"sniperelite": "Sniper Elite", "sniperelite": "Sniper Elite",
"sniperelite_customname": "Sniper Elite Skill", "sniperelite_customname": "Sniper Elite Skill",
"sniperelite_desc": "Click [css_useSkill] to swap your current weapon for an AWP", "sniperelite_desc": "Click [css_useSkill] to swap your current weapon for an AWP",
@ -378,7 +381,7 @@
"soldier_desc2": "Your damage multiplier is: {0}x", "soldier_desc2": "Your damage multiplier is: {0}x",
"soundmaker": "Soundmaker", "soundmaker": "Soundmaker",
"soundmaker_desc": "Click [css_useSkill] to trigger a sound for every enemy", "soundmaker_desc": "Every now and then, you hear player screams",
"spectator": "Spectator", "spectator": "Spectator",
"spectator_desc": "Click [css_useSkill] to spectate a random enemy", "spectator_desc": "Click [css_useSkill] to spectate a random enemy",
@ -473,5 +476,52 @@
"menu_controlls_scroll": "W/S - Scroll", "menu_controlls_scroll": "W/S - Scroll",
"menu_controlls_padding": " | ", "menu_controlls_padding": " | ",
"menu_controlls_select": "E - Select" "menu_controlls_select": "E - Select",
"aimlock": "Aim Lock",
"aimlock_desc": "Click [css_useSkill] to lock your aim on the nearest enemy",
"homingnades": "Homing Grenades",
"homingnades_desc": "Your grenades (except smokes) are attracted to enemies",
"hotbomb": "Hot Bomb",
"hotbomb_desc": "As long as you are alive, the bomb deals damage to its carrier",
"hotbomb_hint": "Careful, the bomb is hot!",
"illiterate": "Illiterate",
"illiterate_desc": "As long as you are alive, your enemies cannot read",
"illusionist": "Illusionist",
"illusionist_desc": "Click [css_useSkill] to deploy a replica that walks straight ahead",
"magneticdecoy": "Magnetic Decoy",
"magneticdecoy_desc": "Your decoy attracts nearby players towards itself",
"magneto": "Magneto",
"magneto_desc": "All enemy grenades are repelled away from you",
"weightless": "Weightlessness",
"weightless_desc": "Your grenades are not affected by gravity and fly faster",
"wildthrow": "Wild Throws",
"wildthrow_desc": "Choose a player who will have trouble throwing grenades",
"wildthrow_player_info": "Player '{0}' has forgotten all their lineups",
"wildthrow_select_info": "Select a player:",
"throwingknife": "Throwing Knife",
"throwingknife_desc": "Click [css_useSkill] to throw a knife. But watch out for others"
} }

View file

@ -5,6 +5,9 @@
"aimbot": "Aimbot", "aimbot": "Aimbot",
"aimbot_desc": "Każdy twój trafiony pocisk liczy się jako strzał w głowę", "aimbot_desc": "Każdy twój trafiony pocisk liczy się jako strzał w głowę",
"aimlock": "Aim Lock",
"aimlock_desc": "Kliknij [css_useSkill], aby wycelować na najbliższego wroga",
"anomaly": "Anomalia", "anomaly": "Anomalia",
"anomaly_desc": "Cofasz się o kilka sekund do tyłu", "anomaly_desc": "Cofasz się o kilka sekund do tyłu",
@ -77,7 +80,7 @@
"cypher": "Kamera", "cypher": "Kamera",
"cypher_desc": "Kliknij [css_useSkill], aby utworzyć/przełączyć się na kamerę", "cypher_desc": "Kliknij [css_useSkill], aby utworzyć/przełączyć się na kamerę",
"cypher_nospace": "Kamera musi być ustawiona pod kątem prostym do ściany", "cypher_nospace": "Kamera musi być ustawiona pod kątem prostym do ściany",
"darkness": "Mrok", "darkness": "Mrok",
"darkness_desc": "Nadaje efekt ciemności wybranemu przeciwnikowi", "darkness_desc": "Nadaje efekt ciemności wybranemu przeciwnikowi",
"darkness_enemy_info": "Niech zgasną światła.", "darkness_enemy_info": "Niech zgasną światła.",
@ -186,9 +189,18 @@
"holyhandgrenade": "Święty Granat Ręczny", "holyhandgrenade": "Święty Granat Ręczny",
"holyhandgrenade_desc": "Twoje granaty uderzeniowe zadają podwójne obrażenia i mają podwójny zasięg", "holyhandgrenade_desc": "Twoje granaty uderzeniowe zadają podwójne obrażenia i mają podwójny zasięg",
"homingnades": "Namierzające Granaty",
"homingnades_desc": "Twoje granaty (oprócz dymnych) są przyciągane do wrogów",
"hotbomb": "Gorąca Bomba",
"hotbomb_desc": "Póki żyjesz, bomba zadaje obrażenia nosicielowi",
"iana": "Hologram", "iana": "Hologram",
"iana_desc": "Kliknij [css_useSkill], aby sterować hologramem przez kilka sekund", "iana_desc": "Kliknij [css_useSkill], aby sterować hologramem przez kilka sekund",
"illiterate": "Analfabeta",
"illiterate_desc": "Dopóki żyjesz, twoi wrogowie nie potrafią czytać",
"impostor": "Szpieg", "impostor": "Szpieg",
"impostor_desc": "Na początku rundy otrzymujesz model postaci przeciwnika", "impostor_desc": "Na początku rundy otrzymujesz model postaci przeciwnika",
@ -234,6 +246,12 @@
"longzeus": "Długi Zeus", "longzeus": "Długi Zeus",
"longzeus_desc": "Zeus zadaje obrażenia niezależnie od odległości", "longzeus_desc": "Zeus zadaje obrażenia niezależnie od odległości",
"magneticdecoy": "Magnetyczny Decoy",
"magneticdecoy_desc": "Twój wabik przyciąga graczy wokół siebie",
"magneto": "Magneto",
"magneto_desc": "Wszystkie granaty przeciwnika są odpychane od ciebie",
"magnifier": "Lupa", "magnifier": "Lupa",
"magnifier_desc": "Przybiżasz ekran wybranemu przeciwnikowi", "magnifier_desc": "Przybiżasz ekran wybranemu przeciwnikowi",
"magnifier_enemy_info": "Twoje pole widzenia zostało zniekształcone!", "magnifier_enemy_info": "Twoje pole widzenia zostało zniekształcone!",
@ -285,7 +303,7 @@
"psychicdefusing_hud_info": "Pozostało {0} sekund do rozbrojenia", "psychicdefusing_hud_info": "Pozostało {0} sekund do rozbrojenia",
"pilot": "Pilot", "pilot": "Pilot",
"pilot_desc": "Latanie przez określony czas. Przytrzymaj [USE - E], aby latać", "pilot_desc": "Latanie przez określony czas. Kliknij dwukrotnie skok, aby latać",
"pilot_hud_info": "Paliwo", "pilot_hud_info": "Paliwo",
"planter": "Samowolka", "planter": "Samowolka",
@ -369,7 +387,10 @@
"silent": "Cichociemny", "silent": "Cichociemny",
"silent_desc": "Twoje kroki i skoki są niesłyszalne dla INNYCH graczy", "silent_desc": "Twoje kroki i skoki są niesłyszalne dla INNYCH graczy",
"sniperelite": "SzeliS", "smoker": "Zadymiarz",
"smoker_desc": "Twoje granaty dymne nigdy się nie kończą",
"sniperelite": "Papito",
"sniperelite_customname": "Mityczna AWP", "sniperelite_customname": "Mityczna AWP",
"sniperelite_desc": "Kliknij [css_useSkill], aby zamienić aktualną broń na AWP", "sniperelite_desc": "Kliknij [css_useSkill], aby zamienić aktualną broń na AWP",
@ -378,7 +399,7 @@
"soldier_desc2": "Twój mnożnik obrażeń wynosi: {0}x", "soldier_desc2": "Twój mnożnik obrażeń wynosi: {0}x",
"soundmaker": "Dźwiękowiec", "soundmaker": "Dźwiękowiec",
"soundmaker_desc": "Kliknij [css_useSkill], aby wywołać dzwięk u każdego przeciwnika", "soundmaker_desc": "Co jakiś czas szłyszysz krzyki graczy",
"spectator": "Obserwator", "spectator": "Obserwator",
"spectator_desc": "Kliknij [css_useSkill], aby obserwować losowego przeciwnika", "spectator_desc": "Kliknij [css_useSkill], aby obserwować losowego przeciwnika",
@ -402,6 +423,9 @@
"thorns": "Ciernie", "thorns": "Ciernie",
"thorns_desc": "Twój przeciwnik otrzymuje część obrażeń, które zadał ci", "thorns_desc": "Twój przeciwnik otrzymuje część obrażeń, które zadał ci",
"throwingknife": "Nóż do Rzucania",
"throwingknife_desc": "Kliknij [css_useSkill], aby rzucić nożem. Ale uważaj na innych",
"toxicsmoke": "Toksyczny Dym", "toxicsmoke": "Toksyczny Dym",
"toxicsmoke_desc": "Twoje granaty dymny zadają obrażenia", "toxicsmoke_desc": "Twoje granaty dymny zadają obrażenia",
@ -417,6 +441,14 @@
"weaponsswap_desc": "Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem", "weaponsswap_desc": "Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem",
"weaponsswap_hud_info2": "Nie posiadasz broni na zamiane", "weaponsswap_hud_info2": "Nie posiadasz broni na zamiane",
"weightless": "Stan Nieważkości",
"weightless_desc": "Twoje granaty nie podlegają grawitacji i lecą szybciej",
"wildthrow": "Dzikie rzuty",
"wildthrow_desc": "Wybierz gracza, który będzie miał trudności z rzucaniem granatami",
"wildthrow_player_info": "Gracz '{0}' zapomniał wszystkie lineup'y",
"wildthrow_select_info": "Wybierz gracza:",
"zeus": "Zeus", "zeus": "Zeus",
"zeus_desc": "Zeus x27 natychmiastowo się odnawia", "zeus_desc": "Zeus x27 natychmiastowo się odnawia",