diff --git a/jRandomSkills - SRC Files/src/gamedata/jRandomSkills.gamedata.json b/jRandomSkills - SRC Files/src/gamedata/jRandomSkills.gamedata.json index b393a45..713f6f8 100644 --- a/jRandomSkills - SRC Files/src/gamedata/jRandomSkills.gamedata.json +++ b/jRandomSkills - SRC Files/src/gamedata/jRandomSkills.gamedata.json @@ -3,7 +3,7 @@ "signatures": { "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", - "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": { @@ -19,5 +19,12 @@ "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" } + }, + "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" + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/lang/en.json b/jRandomSkills - SRC Files/src/lang/en.json index 32a8e1a..e91eed4 100644 --- a/jRandomSkills - SRC Files/src/lang/en.json +++ b/jRandomSkills - SRC Files/src/lang/en.json @@ -285,7 +285,7 @@ "psychicdefusing_hud_info": "{0} seconds remaining to defuse", "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", "planter": "Free Planter", @@ -369,6 +369,9 @@ "silent": "Silent", "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_customname": "Sniper Elite Skill", "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", "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_desc": "Click [css_useSkill] to spectate a random enemy", @@ -473,5 +476,52 @@ "menu_controlls_scroll": "W/S - Scroll", "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" } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/lang/pl.json b/jRandomSkills - SRC Files/src/lang/pl.json index 0a2f4f9..3063468 100644 --- a/jRandomSkills - SRC Files/src/lang/pl.json +++ b/jRandomSkills - SRC Files/src/lang/pl.json @@ -5,6 +5,9 @@ "aimbot": "Aimbot", "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_desc": "Cofasz się o kilka sekund do tyłu", @@ -77,7 +80,7 @@ "cypher": "Kamera", "cypher_desc": "Kliknij [css_useSkill], aby utworzyć/przełączyć się na kamerę", "cypher_nospace": "Kamera musi być ustawiona pod kątem prostym do ściany", - + "darkness": "Mrok", "darkness_desc": "Nadaje efekt ciemności wybranemu przeciwnikowi", "darkness_enemy_info": "Niech zgasną światła.", @@ -186,9 +189,18 @@ "holyhandgrenade": "Święty Granat Ręczny", "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_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_desc": "Na początku rundy otrzymujesz model postaci przeciwnika", @@ -234,6 +246,12 @@ "longzeus": "Długi Zeus", "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_desc": "Przybiżasz ekran wybranemu przeciwnikowi", "magnifier_enemy_info": "Twoje pole widzenia zostało zniekształcone!", @@ -285,7 +303,7 @@ "psychicdefusing_hud_info": "Pozostało {0} sekund do rozbrojenia", "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", "planter": "Samowolka", @@ -369,7 +387,10 @@ "silent": "Cichociemny", "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_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", "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_desc": "Kliknij [css_useSkill], aby obserwować losowego przeciwnika", @@ -402,6 +423,9 @@ "thorns": "Ciernie", "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_desc": "Twoje granaty dymny zadają obrażenia", @@ -417,6 +441,14 @@ "weaponsswap_desc": "Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem", "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_desc": "Zeus x27 natychmiastowo się odnawia", diff --git a/jRandomSkills - SRC Files/src/player/ISkill.cs b/jRandomSkills - SRC Files/src/player/ISkill.cs index 8a85a49..b6ff606 100644 --- a/jRandomSkills - SRC Files/src/player/ISkill.cs +++ b/jRandomSkills - SRC Files/src/player/ISkill.cs @@ -51,6 +51,7 @@ public enum Skills { None, Aimbot, + AimLock, // <- Anomaly, AntyFlash, AntyHead, @@ -79,7 +80,7 @@ public enum Skills Dracula, Duplicator, Dwarf, - Earthquake, + Earthquake, // <- EnemySpawn, ExplosiveShot, FalconEye, @@ -96,11 +97,15 @@ public enum Skills Glue, GodMode, Grenadier, + HealingChicken, // <- HealingSmoke, Hermit, HolyHandGrenade, + HomingNades, // <- + HotBomb, Iana, Illiterate, + Illusionist, Impostor, InfiniteAmmo, Jackal, @@ -112,6 +117,8 @@ public enum Skills LifeSwap, LongKnife, LongZeus, + MagneticDecoy, + Magneto, Magnifier, Medic, MoneySwap, @@ -125,7 +132,7 @@ public enum Skills PawelJumper, Phoenix, PsychicDefusing, - Pilot, + Pilot, // <- Planter, Poison, PrimaryBan, @@ -136,7 +143,7 @@ public enum Skills RadarHack, Rambo, RandomWeapon, - RCMelon, + RCMelon, // <- ReZombie, ReactiveArmor, Regeneration, @@ -149,10 +156,10 @@ public enum Skills Saper, SecondLife, Shade, - ShortBomb, + ShortBomb, // <- short Silent, - Smoker, - SniperElite, + Smoker, // <- nie dziala + SniperElite, // <- nie dziala Soldier, SoundMaker, Spectator, @@ -161,9 +168,12 @@ public enum Skills Thief, ThirdEye, Thorns, + ThrowingKnife, ToxicSmoke, Wallhack, Watchmaker, WeaponsSwap, + Weightless, + WildThrow, Zeus, } diff --git a/jRandomSkills - SRC Files/src/player/skills/AimLock.cs b/jRandomSkills - SRC Files/src/player/skills/AimLock.cs new file mode 100644 index 0000000..932c7d5 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/AimLock.cs @@ -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 SkillPlayerInfo = []; + private static readonly object setLock = new(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(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(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", $"{cooldown}")}"; + } + + 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; + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/BladeMaster.cs b/jRandomSkills - SRC Files/src/player/skills/BladeMaster.cs index 73c7aad..a30cdc6 100644 --- a/jRandomSkills - SRC Files/src/player/skills/BladeMaster.cs +++ b/jRandomSkills - SRC Files/src/player/skills/BladeMaster.cs @@ -9,7 +9,7 @@ namespace src.player.skills public class BladeMaster : ISkill { 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() { @@ -30,7 +30,7 @@ namespace src.player.skills var weaponServices = playerPawn.WeaponServices; 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; playerPawn.VelocityModifier = SkillsInfo.GetValue(skillName, "velocityModifier"); @@ -63,7 +63,7 @@ namespace src.player.skills var weaponServices = pawn.WeaponServices; 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; SkillUtils.RestoreHealth(victim); diff --git a/jRandomSkills - SRC Files/src/player/skills/Cutter.cs b/jRandomSkills - SRC Files/src/player/skills/Cutter.cs index 29dd087..68c3adf 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Cutter.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Cutter.cs @@ -25,7 +25,7 @@ namespace src.player.skills var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == attacker?.SteamID); if (playerInfo?.Skill != skillName) return; - if (weapon == "knife") + if (weapon == "knife" || weapon == "bayonet") SkillUtils.TakeHealth(victim!.PlayerPawn.Value, 9999); } diff --git a/jRandomSkills - SRC Files/src/player/skills/Disarmament.cs b/jRandomSkills - SRC Files/src/player/skills/Disarmament.cs index c6acdef..0d91901 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Disarmament.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Disarmament.cs @@ -31,7 +31,7 @@ namespace src.player.skills if (weaponServices?.ActiveWeapon == null) return; 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(); } } diff --git a/jRandomSkills - SRC Files/src/player/skills/FrozenDecoy.cs b/jRandomSkills - SRC Files/src/player/skills/FrozenDecoy.cs index cbddeee..911a922 100644 --- a/jRandomSkills - SRC Files/src/player/skills/FrozenDecoy.cs +++ b/jRandomSkills - SRC Files/src/player/skills/FrozenDecoy.cs @@ -27,8 +27,10 @@ namespace src.player.skills { 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); } @@ -36,8 +38,10 @@ namespace src.player.skills { 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 _); } @@ -45,11 +49,11 @@ namespace src.player.skills public static void OnTick() { 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(skillName, "triggerRadius"); 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); if (distance <= decoyRadius) { diff --git a/jRandomSkills - SRC Files/src/player/skills/HealingChicken.cs b/jRandomSkills - SRC Files/src/player/skills/HealingChicken.cs new file mode 100644 index 0000000..832a48e --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/HealingChicken.cs @@ -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> playerSmokes = []; + private static readonly object setLock = new(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(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(skillName, "amount"); + for (int i = 0; i < 1; i++) + { + CChicken? chicken = Utilities.CreateEntityByName("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; + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/HealingSmoke.cs b/jRandomSkills - SRC Files/src/player/skills/HealingSmoke.cs index cf501fd..c01c588 100644 --- a/jRandomSkills - SRC Files/src/player/skills/HealingSmoke.cs +++ b/jRandomSkills - SRC Files/src/player/skills/HealingSmoke.cs @@ -70,9 +70,10 @@ namespace src.player.skills public static void OnTick() { + int tick = SkillsInfo.GetValue(skillName, "tickCooldown"); foreach (Vector smokePos in smokes.Keys) 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 (SkillUtils.GetDistance(smokePos, player.PlayerPawn.Value.AbsOrigin) <= SkillsInfo.GetValue(skillName, "smokeRadius")) AddHealth(player.PlayerPawn.Value, SkillsInfo.GetValue(skillName, "smokeHeal")); @@ -95,10 +96,11 @@ namespace src.player.skills 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 float SmokeRadius { get; set; } = smokeRadius; + public int TickCooldown { get; set; } = tickCooldown; } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/HomingNades.cs b/jRandomSkills - SRC Files/src/player/skills/HomingNades.cs new file mode 100644 index 0000000..e427aff --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/HomingNades.cs @@ -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 nades = []; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(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((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(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(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(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(); + if (grenade == null || !grenade.IsValid) return; + + if (grenade.OwnerEntity.Value == null || !grenade.OwnerEntity.Value.IsValid) return; + var pawn = grenade.OwnerEntity.Value.As(); + + if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return; + var player = pawn.Controller.Value.As(); + + 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; + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/HotBomb.cs b/jRandomSkills - SRC Files/src/player/skills/HotBomb.cs new file mode 100644 index 0000000..aebff28 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/HotBomb.cs @@ -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 players = []; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(skillName, "color")); + } + + public static void OnTick() + { + float cooldown = SkillsInfo.GetValue(skillName, "cooldown"); + if (Server.TickCount % (int)(cooldown * 64) != 0) return; + + if (players.IsEmpty || jRandomSkills.Instance.GameRules?.FreezePeriod == true) return; + int damage = SkillsInfo.GetValue(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("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; + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Illiterate.cs b/jRandomSkills - SRC Files/src/player/skills/Illiterate.cs index 6e672b2..09a169c 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Illiterate.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Illiterate.cs @@ -47,8 +47,8 @@ namespace src.player.skills return Utilities.GetPlayers().Any( p => p.IsValid && p.PawnIsAlive && - p.Team != player.Team - && playersWithSkill.Contains(p.SteamID)); + p.Team != player.Team && + playersWithSkill.Contains(p.SteamID)); } public static string? GetRandomText(string? input) diff --git a/jRandomSkills - SRC Files/src/player/skills/Illusionist.cs b/jRandomSkills - SRC Files/src/player/skills/Illusionist.cs new file mode 100644 index 0000000..8a76adc --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Illusionist.cs @@ -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 SkillPlayerInfo = []; + private static readonly ConcurrentDictionary ActiveTimers = []; + private static readonly object setLock = new(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(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("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(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", $"{cooldown}")}"; + } + + 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("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(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(0); + CTakeDamageInfo param2 = h.GetParam(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(); + 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(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue(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; + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/LongKnife.cs b/jRandomSkills - SRC Files/src/player/skills/LongKnife.cs index 6aa7556..31c5b7b 100644 --- a/jRandomSkills - SRC Files/src/player/skills/LongKnife.cs +++ b/jRandomSkills - SRC Files/src/player/skills/LongKnife.cs @@ -59,7 +59,7 @@ namespace src.player.skills var weapon = hook.GetParam(0); var action = hook.GetParam(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; var pawn = weapon.OwnerEntity.Value.As(); @@ -87,7 +87,7 @@ namespace src.player.skills if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.WeaponServices == null) return; 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); } diff --git a/jRandomSkills - SRC Files/src/player/skills/MagneticDecoy.cs b/jRandomSkills - SRC Files/src/player/skills/MagneticDecoy.cs new file mode 100644 index 0000000..21c22a3 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/MagneticDecoy.cs @@ -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 decoys = []; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(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(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(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; + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Magneto.cs b/jRandomSkills - SRC Files/src/player/skills/Magneto.cs new file mode 100644 index 0000000..6e1ffa3 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Magneto.cs @@ -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 nades = []; + private readonly static ConcurrentDictionary players = []; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(skillName, "color")); + } + + public static void NewRound() + { + nades.Clear(); + players.Clear(); + } + + public static void OnTick() + { + if (Server.TickCount % 5 != 0) return; + float radius = SkillsInfo.GetValue(skillName, "radius"); + + foreach (var nadeIndex in nades.Keys) + { + var nade = Utilities.GetEntityFromIndex((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(); + 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; + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Ninja.cs b/jRandomSkills - SRC Files/src/player/skills/Ninja.cs index 5377b1a..984024f 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Ninja.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Ninja.cs @@ -127,7 +127,7 @@ namespace src.player.skills if (buttons.HasFlag(PlayerButtons.Duck)) percentInvisibility += SkillsInfo.GetValue(skillName, "duckPercentInvisibility"); - if (activeWeapon != null && activeWeapon.DesignerName == "weapon_knife") + if (activeWeapon != null && (activeWeapon.DesignerName == "weapon_knife" || activeWeapon.DesignerName == "weapon_bayonet")) percentInvisibility += SkillsInfo.GetValue(skillName, "knifePercentInvisibility"); 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(skillName, "idlePercentInvisibility"); diff --git a/jRandomSkills - SRC Files/src/player/skills/Replicator.cs b/jRandomSkills - SRC Files/src/player/skills/Replicator.cs index 82e6df9..f96ffa7 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Replicator.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Replicator.cs @@ -21,10 +21,19 @@ namespace src.player.skills public static void NewRound() { + ClearAllReplicas(); lock (setLock) SkillPlayerInfo.Clear(); } + private static void ClearAllReplicas() + { + var entities = Utilities.FindAllEntitiesByDesignerName("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() { foreach (var player in Utilities.GetPlayers()) diff --git a/jRandomSkills - SRC Files/src/player/skills/RichBoy.cs b/jRandomSkills - SRC Files/src/player/skills/RichBoy.cs index 268fd2d..a787966 100644 --- a/jRandomSkills - SRC Files/src/player/skills/RichBoy.cs +++ b/jRandomSkills - SRC Files/src/player/skills/RichBoy.cs @@ -38,7 +38,6 @@ namespace src.player.skills var moneyServices = player.InGameMoneyServices; if (moneyServices == null) return; - player.PrintToChat(moneyServices.CashSpentThisRound.ToString()); int money = Math.Abs((int)playerInfo.SkillChance! - moneyServices.CashSpentThisRound); AddMoney(player, -money, 3000); } diff --git a/jRandomSkills - SRC Files/src/player/skills/Smoker.cs b/jRandomSkills - SRC Files/src/player/skills/Smoker.cs index fd52500..5bc203e 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Smoker.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Smoker.cs @@ -1,20 +1,19 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Core.Attributes; -using CounterStrikeSharp.API.Modules.Entities; using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.Modules.Utils; -using Microsoft.Extensions.Logging; using src.utils; using System.Collections.Concurrent; using static src.jRandomSkills; +using Timer = CounterStrikeSharp.API.Modules.Timers.Timer; namespace src.player.skills { public class Smoker : ISkill { private const Skills skillName = Skills.Smoker; - private readonly static ConcurrentDictionary smokes = []; + private readonly static ConcurrentDictionary> playerSmokes = []; private static readonly object setLock = new(); public static void LoadSkill() @@ -25,9 +24,11 @@ namespace src.player.skills public static void NewRound() { lock (setLock) - smokes.Clear(); - - + { + foreach (var timers in playerSmokes.Values) + timers.ForEach(t => t?.Kill()); + playerSmokes.Clear(); + } } public static void EnableSkill(CCSPlayerController player) @@ -35,28 +36,13 @@ namespace src.player.skills SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade); } - public static void SmokegrenadeDetonate(EventSmokegrenadeDetonate @event) + public static void DisableSkill(CCSPlayerController player) { - Server.PrintToChatAll("BOOM"); - 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; - - var smoke = Utilities.GetEntityFromIndex(@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"); + if (playerSmokes.TryRemove(player.SteamID, out var timers)) + timers.ForEach(t => t?.Kill()); } - public static void SmokegrenadeExpired(EventSmokegrenadeExpired @event) + public static void SmokegrenadeDetonate(EventSmokegrenadeDetonate @event) { var player = @event.Userid; if (player == null || !player.IsValid) return; @@ -65,7 +51,22 @@ namespace src.player.skills if (playerInfo?.Skill != skillName) return; 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) diff --git a/jRandomSkills - SRC Files/src/player/skills/SniperElite.cs b/jRandomSkills - SRC Files/src/player/skills/SniperElite.cs index c31aeb4..b46feaa 100644 --- a/jRandomSkills - SRC Files/src/player/skills/SniperElite.cs +++ b/jRandomSkills - SRC Files/src/player/skills/SniperElite.cs @@ -75,16 +75,33 @@ namespace src.player.skills if (playerAWPIndexes.TryGetValue(player.SteamID, out var AWPs)) foreach (var index in AWPs.ToList()) { - var ent = Utilities.GetEntityFromIndex((int)index); - if (ent != null && ent.IsValid) - ent.AcceptInput("Kill"); + var pawn = player.PlayerPawn.Value; + if (pawn == null || !pawn.IsValid || pawn.WeaponServices == null) continue; + + 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)) - Server.NextFrame(() => - player.PlayerPawn.Value?.ItemServices?.As().GiveNamedItem(savedWeapon)); + Server.NextFrame(() => + { + 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 _); playerAWPIndexes.TryRemove(player.SteamID, out _); @@ -135,7 +152,7 @@ namespace src.player.skills weaponToGive = weapon_awp + "_script"; } - activeRifle.AcceptInput("Kill"); + activeRifle.AddEntityIOEvent("Kill", activeRifle, delay: 0.1f); } else { @@ -200,7 +217,7 @@ namespace src.player.skills { var ent = Utilities.GetEntityFromIndex((int)index); if (ent != null && ent.IsValid) - ent.AcceptInput("Kill"); + ent.AddEntityIOEvent("Kill", ent, delay: 0.1f); AWPs.Remove(index); } diff --git a/jRandomSkills - SRC Files/src/player/skills/ThrowingKnife.cs b/jRandomSkills - SRC Files/src/player/skills/ThrowingKnife.cs new file mode 100644 index 0000000..59340cc --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/ThrowingKnife.cs @@ -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 triggers = []; + private readonly static ConcurrentDictionary glows = []; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(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((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((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("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(); + 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((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) + { + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/ToxicSmoke.cs b/jRandomSkills - SRC Files/src/player/skills/ToxicSmoke.cs index 4f72e81..25d1b5a 100644 --- a/jRandomSkills - SRC Files/src/player/skills/ToxicSmoke.cs +++ b/jRandomSkills - SRC Files/src/player/skills/ToxicSmoke.cs @@ -41,6 +41,7 @@ namespace src.player.skills CCSPlayerPawn playerPawn = new(entity.Handle); if (playerPawn == null || playerPawn.Controller?.Value == null)return; + CCSPlayerController player = playerPawn.Controller.Value.As(); if (player == null) return; diff --git a/jRandomSkills - SRC Files/src/player/skills/Weightless.cs b/jRandomSkills - SRC Files/src/player/skills/Weightless.cs new file mode 100644 index 0000000..f2b77d9 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Weightless.cs @@ -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 nades = []; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(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((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(); + if (grenade == null || !grenade.IsValid) return; + + if (grenade.OwnerEntity.Value == null || !grenade.OwnerEntity.Value.IsValid) return; + var pawn = grenade.OwnerEntity.Value.As(); + + if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return; + var player = pawn.Controller.Value.As(); + + 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) + { + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/WildThrow.cs b/jRandomSkills - SRC Files/src/player/skills/WildThrow.cs new file mode 100644 index 0000000..edc7e5c --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/WildThrow.cs @@ -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 infectedPlayers = []; + private static readonly object setLock = new(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(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(); + if (grenade == null || !grenade.IsValid) return; + + if (grenade.OwnerEntity.Value == null || !grenade.OwnerEntity.Value.IsValid) return; + var pawn = grenade.OwnerEntity.Value.As(); + + if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return; + var player = pawn.Controller.Value.As(); + + 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) + { + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/utils/SkillUtils.cs b/jRandomSkills - SRC Files/src/utils/SkillUtils.cs index 36d8781..36f1788 100644 --- a/jRandomSkills - SRC Files/src/utils/SkillUtils.cs +++ b/jRandomSkills - SRC Files/src/utils/SkillUtils.cs @@ -20,10 +20,11 @@ namespace src.utils public static class SkillUtils { private static readonly MemoryFunctionWithReturn HEGrenadeProjectile_CreateFunc = new(GameData.GetSignature("HEGrenadeProjectile_CreateFunc")); - private static readonly MemoryFunctionWithReturn SmokeGrenadeProjectile_CreateFunc = new(GameData.GetSignature("SmokeGrenadeProjectile_CreateFunc")); + private static readonly MemoryFunctionWithReturn SmokeGrenadeProjectile_CreateFunc = new(GameData.GetSignature("SmokeGrenadeProjectile_CreateFunc")); private static readonly MemoryFunctionVoid TerminateRoundFunc = new(GameData.GetSignature("CCSGameRules_TerminateRound")); + private static readonly MemoryFunctionVoid 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; @@ -93,6 +94,13 @@ namespace src.utils 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) { CBeam beam = Utilities.CreateEntityByName("beam")!; diff --git a/jRandomSkills - Server Files/gamedata/jRandomSkills.gamedata.json b/jRandomSkills - Server Files/gamedata/jRandomSkills.gamedata.json index b393a45..669a62b 100644 --- a/jRandomSkills - Server Files/gamedata/jRandomSkills.gamedata.json +++ b/jRandomSkills - Server Files/gamedata/jRandomSkills.gamedata.json @@ -19,5 +19,12 @@ "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" } + }, + "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" + } } } \ No newline at end of file diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/languages/en.json b/jRandomSkills - Server Files/plugins/jRandomSkills/languages/en.json index 32a8e1a..e91eed4 100644 --- a/jRandomSkills - Server Files/plugins/jRandomSkills/languages/en.json +++ b/jRandomSkills - Server Files/plugins/jRandomSkills/languages/en.json @@ -285,7 +285,7 @@ "psychicdefusing_hud_info": "{0} seconds remaining to defuse", "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", "planter": "Free Planter", @@ -369,6 +369,9 @@ "silent": "Silent", "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_customname": "Sniper Elite Skill", "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", "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_desc": "Click [css_useSkill] to spectate a random enemy", @@ -473,5 +476,52 @@ "menu_controlls_scroll": "W/S - Scroll", "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" } \ No newline at end of file diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/languages/pl.json b/jRandomSkills - Server Files/plugins/jRandomSkills/languages/pl.json index 0a2f4f9..3063468 100644 --- a/jRandomSkills - Server Files/plugins/jRandomSkills/languages/pl.json +++ b/jRandomSkills - Server Files/plugins/jRandomSkills/languages/pl.json @@ -5,6 +5,9 @@ "aimbot": "Aimbot", "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_desc": "Cofasz się o kilka sekund do tyłu", @@ -77,7 +80,7 @@ "cypher": "Kamera", "cypher_desc": "Kliknij [css_useSkill], aby utworzyć/przełączyć się na kamerę", "cypher_nospace": "Kamera musi być ustawiona pod kątem prostym do ściany", - + "darkness": "Mrok", "darkness_desc": "Nadaje efekt ciemności wybranemu przeciwnikowi", "darkness_enemy_info": "Niech zgasną światła.", @@ -186,9 +189,18 @@ "holyhandgrenade": "Święty Granat Ręczny", "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_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_desc": "Na początku rundy otrzymujesz model postaci przeciwnika", @@ -234,6 +246,12 @@ "longzeus": "Długi Zeus", "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_desc": "Przybiżasz ekran wybranemu przeciwnikowi", "magnifier_enemy_info": "Twoje pole widzenia zostało zniekształcone!", @@ -285,7 +303,7 @@ "psychicdefusing_hud_info": "Pozostało {0} sekund do rozbrojenia", "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", "planter": "Samowolka", @@ -369,7 +387,10 @@ "silent": "Cichociemny", "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_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", "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_desc": "Kliknij [css_useSkill], aby obserwować losowego przeciwnika", @@ -402,6 +423,9 @@ "thorns": "Ciernie", "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_desc": "Twoje granaty dymny zadają obrażenia", @@ -417,6 +441,14 @@ "weaponsswap_desc": "Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem", "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_desc": "Zeus x27 natychmiastowo się odnawia",