diff --git a/jRandomSkills - SRC Files/jRandomSkills.csproj b/jRandomSkills - SRC Files/jRandomSkills.csproj index 4e71fe3..2fc4f87 100644 --- a/jRandomSkills - SRC Files/jRandomSkills.csproj +++ b/jRandomSkills - SRC Files/jRandomSkills.csproj @@ -1,70 +1,86 @@  - - net8.0 - enable - enable - true - + + net8.0 + enable + enable + true + true + - - - - - - - - - - - - - - - - - - - - - True - True - Resources.resx - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - $(MSBuildProjectDirectory)\src\lang - $(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\plugins\jRandomSkills\languages - $(MSBuildProjectDirectory)\bin\Debug\net8.0 - $(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\plugins\jRandomSkills - - - - - - + + + - - - - - - - - + + + + + - - - + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + $(MSBuildProjectDirectory)\src\lang + $(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\plugins\jRandomSkills\languages + $(MSBuildProjectDirectory)\bin\Debug\net8.0 + $(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\plugins\jRandomSkills + $(MSBuildProjectDirectory)\src\gamedata + $(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\gamedata + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jRandomSkills - SRC Files/src/command/VoteSystem.cs b/jRandomSkills - SRC Files/src/command/VoteSystem.cs index fc8b944..801b7c0 100644 --- a/jRandomSkills - SRC Files/src/command/VoteSystem.cs +++ b/jRandomSkills - SRC Files/src/command/VoteSystem.cs @@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using src.utils; using System.Collections.Concurrent; +using Timer = CounterStrikeSharp.API.Modules.Timers.Timer; namespace src.command { @@ -10,6 +11,20 @@ namespace src.command { private static readonly ConcurrentDictionary votes = []; + private static void StartVoteTimer(VoteData vote, string commandName) + { + vote.ActiveTimer?.Kill(); + + vote.ActiveTimer = jRandomSkills.Instance.AddTimer(vote.TimeToVote, () => + { + if (!votes.ContainsKey(vote) || !vote.GetActive()) return; + + vote.SetActive(false); + vote.TimeToNextSameVoting = vote.TimeToNextVoting; + Localization.PrintTranslationToChatAll($" {ChatColors.Red}{{0}}", ["vote_timeout"], [commandName]); + }); + } + private static VoteData? CreateVote(VoteType voteType, string? args = null) { var vote = new VoteData(10, @@ -27,21 +42,15 @@ namespace src.command foreach (var player in Utilities.GetPlayers()) player.EmitSound("UIPanorama.tab_mainmenu_news"); - if (vote == null) return vote; - jRandomSkills.Instance.AddTimer(vote.TimeToVote, () => - { - if (!votes.ContainsKey(vote) || !vote.GetActive()) return; - vote.SetActive(false); - vote.TimeToNextSameVoting = vote.TimeToNextVoting; - Localization.PrintTranslationToChatAll($" {ChatColors.Red}{{0}}", ["vote_timeout"], [commandName]); - }); + StartVoteTimer(vote!, commandName); - float[] times = [vote.TimeToVote, vote.TimeToVote + vote.TimeToNextVoting, vote.TimeToVote + vote.TimeToNextSameVoting]; + float[] times = [vote!.TimeToVote, vote.TimeToVote + vote.TimeToNextVoting, vote.TimeToVote + vote.TimeToNextSameVoting]; jRandomSkills.Instance.AddTimer(times.Max(), () => { if (!votes.ContainsKey(vote)) return; votes.TryRemove(vote, out _); }); + return vote; } @@ -78,16 +87,21 @@ namespace src.command private static void CheckVote(VoteData vote) { int voted = vote.PlayersVoted.Count; - int playerCount = Utilities.GetPlayers().Where(p => !p.IsBot).ToArray().Length; + int playerCount = Utilities.GetPlayers().Count(p => !p.IsBot); int playersNeeded = (int)Math.Ceiling(playerCount * (vote.PercentagesToSuccess / 100f)); + string commandName = $"!{VoteTypeCommands.GetCommand(vote.Type)?.Replace("css_", "")}{(!string.IsNullOrEmpty(vote?.Args) ? $" {vote?.Args}" : "")}"; if (voted >= playersNeeded) { + vote!.ActiveTimer?.Kill(); vote.SuccessAction.Invoke(); vote.SetActive(false); } else - Localization.PrintTranslationToChatAll($" {ChatColors.Yellow}{{0}} '!{VoteTypeCommands.GetCommand(vote.Type)?.Replace("css_", "")}{(!string.IsNullOrEmpty(vote?.Args) ? $" {vote?.Args}" : "")}': {ChatColors.Green}{voted}/{playersNeeded}", ["vote_vote"]); + { + StartVoteTimer(vote!, commandName); + Localization.PrintTranslationToChatAll($" {ChatColors.Yellow}{{0}} '': {ChatColors.Green}{voted}/{playersNeeded}", ["vote_vote"]); + } } } @@ -103,7 +117,7 @@ namespace src.command public VoteType Type { get; set; } = type; public string? Args { get; set; } = args; public ConcurrentDictionary PlayersVoted { get; set; } = []; - + public Timer? ActiveTimer { get; set; } private DateTime CreatedTime { get; set; } = DateTime.Now; public void SetActive(bool active) diff --git a/jRandomSkills - SRC Files/src/gamedata/jRandomSkills.gamedata.json b/jRandomSkills - SRC Files/src/gamedata/jRandomSkills.gamedata.json new file mode 100644 index 0000000..b393a45 --- /dev/null +++ b/jRandomSkills - SRC Files/src/gamedata/jRandomSkills.gamedata.json @@ -0,0 +1,23 @@ +{ + "SmokeGrenadeProjectile_CreateFunc": { + "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" + } + }, + "HEGrenadeProjectile_CreateFunc": { + "signatures": { + "library": "server", + "windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 8B AC 24 ? ? ? ? 49 8B F8", + "linux": "55 4C 89 C1 48 89 E5 41 57 49 89 D7" + } + }, + "Shoot_Secondary": { + "signatures": { + "library": "server", + "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" + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/jRandomSkills.cs b/jRandomSkills - SRC Files/src/jRandomSkills.cs index c8aa550..06db794 100644 --- a/jRandomSkills - SRC Files/src/jRandomSkills.cs +++ b/jRandomSkills - SRC Files/src/jRandomSkills.cs @@ -27,7 +27,7 @@ namespace src public override string ModuleName => "[CS2] [ jRandomSkills ]"; public override string ModuleAuthor => "D3X, Juzlus"; public override string ModuleDescription => "Plugin adds random skills every round for CS2 by D3X. Modified by Juzlus."; - public override string ModuleVersion => "1.10.0"; + public override string ModuleVersion => "1.2.1"; public override void Load(bool hotReload) { diff --git a/jRandomSkills - SRC Files/src/player/ISkill.cs b/jRandomSkills - SRC Files/src/player/ISkill.cs index 5911433..8a85a49 100644 --- a/jRandomSkills - SRC Files/src/player/ISkill.cs +++ b/jRandomSkills - SRC Files/src/player/ISkill.cs @@ -100,6 +100,7 @@ public enum Skills Hermit, HolyHandGrenade, Iana, + Illiterate, Impostor, InfiniteAmmo, Jackal, @@ -150,6 +151,7 @@ public enum Skills Shade, ShortBomb, Silent, + Smoker, SniperElite, Soldier, SoundMaker, diff --git a/jRandomSkills - SRC Files/src/player/PlayerEvents.cs b/jRandomSkills - SRC Files/src/player/PlayerEvents.cs index 1050774..2718ecc 100644 --- a/jRandomSkills - SRC Files/src/player/PlayerEvents.cs +++ b/jRandomSkills - SRC Files/src/player/PlayerEvents.cs @@ -8,15 +8,18 @@ using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.UserMessages; using CounterStrikeSharp.API.Modules.Utils; +using src.player.skills; using src.utils; using System.Collections.Concurrent; using static CounterStrikeSharp.API.Core.Listeners; using static src.jRandomSkills; +using Timer = CounterStrikeSharp.API.Modules.Timers.Timer; namespace src.player { public static partial class Event { + private static Timer? setSkillTimer = null; private static DateTime freezeTimeEnd = DateTime.MinValue; private static bool isTransmitRegistered = false; public static readonly jSkill_SkillInfo noneSkill = new(Skills.None, SkillsInfo.GetValue(Skills.None, "color"), false); @@ -39,6 +42,7 @@ namespace src.player Instance.RegisterEventHandler(PlayerConnectFull); Instance.RegisterEventHandler(PlayerDisconnect); // Instance.RegisterEventHandler(PlayerChat); + Instance.RegisterEventHandler(PlayerSpawned); Instance.RegisterEventHandler(RoundStart); Instance.RegisterEventHandler(RoundEnd); @@ -384,6 +388,32 @@ namespace src.player return HookResult.Continue; } + private static HookResult PlayerSpawned(EventPlayerSpawned @event, GameEventInfo info) + { + lock (setLock) + { + var player = @event.Userid; + if (player == null || !player.IsValid) return HookResult.Continue; + + var skillPlayer = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (skillPlayer == null) return HookResult.Continue; + + if (setSkillTimer != null) + { + skillPlayer.IsDrawing = true; + return HookResult.Continue; + } + + skillPlayer.IsDrawing = false; + if (Instance?.GameRules != null && + Instance?.GameRules.WarmupPeriod == false && + skillPlayer.Skill == Skills.None && + skillPlayer.SpecialSkill == Skills.None) + SetRandomSkill(player); + return HookResult.Continue; + } + } + private static HookResult RoundStart(EventRoundStart @event, GameEventInfo info) { lock (setLock) @@ -401,7 +431,11 @@ namespace src.player Instance.RemoveListener(CheckTransmit); int freezetime = ConVar.Find("mp_freezetime")?.GetPrimitiveValue() ?? 0; freezeTimeEnd = DateTime.Now.AddSeconds(freezetime + (Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0)); - Instance?.AddTimer((Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0) + Math.Max(freezetime - Config.LoadedConfig.SkillTimeBeforeStart, 0) + .3f, SetSkill); + + setSkillTimer?.Kill(); + + float timeToDraw = (Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0) + Math.Max(freezetime - Config.LoadedConfig.SkillTimeBeforeStart, 0) + .3f; + setSkillTimer = Instance?.AddTimer(timeToDraw, SetSkill); return HookResult.Continue; } } @@ -447,6 +481,7 @@ namespace src.player private static HookResult RoundEnd(EventRoundEnd @event, GameEventInfo info) { + Illiterate.Disable(); lock (setLock) { foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid)) @@ -567,6 +602,7 @@ namespace src.player private static void SetSkill() { + setSkillTimer = null; lock (setLock) { var validPlayers = Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot && !p.IsHLTV && p.Team is CsTeam.CounterTerrorist or CsTeam.Terrorist).ToList(); @@ -670,14 +706,20 @@ namespace src.player skillPlayer.Skill = randomSkill.Skill; skillPlayer.SpecialSkill = Skills.None; - if (SkillsInfo.GetValue(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime()) - Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () => - { - if (Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID && p.Skill == randomSkill.Skill) == null) return; + if (randomSkill.Skill == Skills.Illiterate) + Illiterate.Enable(); + + Instance?.AddTimer(.2f, () => + { + if (SkillsInfo.GetValue(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime()) + Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () => + { + if (Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID && p.Skill == randomSkill.Skill) == null) return; + Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); + }); + else Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); - }); - else - Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); + }); Debug.WriteToDebug($"Player {skillPlayer.PlayerName} has got the skill \"{player.GetSkillName(randomSkill.Skill)}\"."); skillPlayer.SkillHudExpired = DateTime.Now.AddSeconds(Config.LoadedConfig.SkillHudDuration); @@ -685,7 +727,7 @@ namespace src.player if (Config.LoadedConfig.TeamMateSkillChatInfo) { - Instance?.AddTimer(.5f, () => + Instance?.AddTimer(.6f, () => { foreach (var teammate in teammates) { @@ -732,6 +774,7 @@ namespace src.player var skillPlayer = Instance?.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (skillPlayer == null) return; + skillPlayer.IsDrawing = false; if (player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid) { skillPlayer.Skill = Skills.None; @@ -792,13 +835,20 @@ namespace src.player skillPlayer.Skill = randomSkill.Skill; skillPlayer.SpecialSkill = Skills.None; - if (SkillsInfo.GetValue(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime()) - Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () => { - if (Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID && p.Skill == randomSkill.Skill) == null) return; + if (randomSkill.Skill == Skills.Illiterate) + Illiterate.Enable(); + + Instance?.AddTimer(.2f, () => + { + if (SkillsInfo.GetValue(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime()) + Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () => + { + if (Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID && p.Skill == randomSkill.Skill) == null) return; + Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); + }); + else Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); - }); - else - Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); + }); Debug.WriteToDebug($"Player {skillPlayer.PlayerName} has got the skill \"{player.GetSkillName(randomSkill.Skill)}\"."); skillPlayer.SkillDescriptionHudExpired = DateTime.Now.AddSeconds(Config.LoadedConfig.SkillDescriptionDuration); @@ -820,6 +870,14 @@ namespace src.player lock (setLock) { if (player == null || !player.IsValid) return; + + if (Illiterate.CheckIlliterateSkill(player)) + { + headerLine = Illiterate.GetRandomText(headerLine); + centerLine = Illiterate.GetRandomText(centerLine); + extraLine = Illiterate.GetRandomText(extraLine); + } + var config = Config.LoadedConfig.HtmlHudCustomisation; var emptySymbol = $" "; var emptySymbol2 = $" "; diff --git a/jRandomSkills - SRC Files/src/player/PlayerOnTick.cs b/jRandomSkills - SRC Files/src/player/PlayerOnTick.cs index 94099ae..0412210 100644 --- a/jRandomSkills - SRC Files/src/player/PlayerOnTick.cs +++ b/jRandomSkills - SRC Files/src/player/PlayerOnTick.cs @@ -62,7 +62,7 @@ namespace src.player infoLine = player.GetTranslation("your_skill"); skillLine = player.GetTranslation("none"); } - else if (skillPlayer.IsDrawing) + else if (skillPlayer.IsDrawing && player.PawnIsAlive) { var randomSkill = SkillData.Skills.ToArray()[Instance.Random.Next(SkillData.Skills.Count)]; infoLine = player.GetTranslation("drawing_skill"); diff --git a/jRandomSkills - SRC Files/src/player/skills/Baseball.cs b/jRandomSkills - SRC Files/src/player/skills/Baseball.cs index 21e0a73..595f1aa 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Baseball.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Baseball.cs @@ -51,6 +51,9 @@ namespace src.player.skills var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo?.Skill != skillName) return; decoys.TryAdd(decoy, 0); + + decoy.Collision.CollisionAttribute.InteractsWith = pawn.Collision.CollisionAttribute.InteractsWith; + decoy.Collision.CollisionGroup = pawn.Collision.CollisionGroup; } public static void DecoyStarted(EventDecoyStarted @event) diff --git a/jRandomSkills - SRC Files/src/player/skills/C4Camouflage.cs b/jRandomSkills - SRC Files/src/player/skills/C4Camouflage.cs index 2d2ead8..077dfe3 100644 --- a/jRandomSkills - SRC Files/src/player/skills/C4Camouflage.cs +++ b/jRandomSkills - SRC Files/src/player/skills/C4Camouflage.cs @@ -1,7 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes; -using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Utils; using src.utils; using System.Collections.Concurrent; @@ -62,8 +61,19 @@ namespace src.player.skills foreach (var (info, player) in infoList) { if (player == null || !player.IsValid) continue; + + var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero; + bool isObservingC4Camouflage = false; + + if (targetHandle != nint.Zero) + { + var target = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == targetHandle); + var targetInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == target?.SteamID); + if (targetInfo?.Skill == skillName) isObservingC4Camouflage = true; + } + foreach (var _player in invisiblePlayers.Keys) - if (player.SteamID != _player.SteamID) + if (player.SteamID != _player.SteamID && !isObservingC4Camouflage) { var playerPawn = _player.PlayerPawn.Value; if (playerPawn == null || !playerPawn.IsValid) continue; diff --git a/jRandomSkills - SRC Files/src/player/skills/Cypher.cs b/jRandomSkills - SRC Files/src/player/skills/Cypher.cs index fd8b4bb..59c7e6d 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Cypher.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Cypher.cs @@ -151,12 +151,13 @@ namespace src.player.skills pawn!.CameraServices!.ViewEntity.Raw = player.CameraView.EntityHandle.Raw; SkillUtils.ApplyScreenColor(player.Player, 0, 0, 255, 20, 100, 1020); - Timer? cameraTimer = null; - ulong playerSteamID = player.Player.SteamID; + ulong? playerSteamID = player.Player?.SteamID; + if (playerSteamID == null) return; + Timer? cameraTimer = null; cameraTimer = jRandomSkills.Instance.AddTimer(2f, () => { - var target = Utilities.GetPlayerFromSteamId(playerSteamID); + var target = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == playerSteamID); if (target == null || !target.IsValid || !target.PawnIsAlive) { cameraTimer?.Kill(); diff --git a/jRandomSkills - SRC Files/src/player/skills/Darkness.cs b/jRandomSkills - SRC Files/src/player/skills/Darkness.cs index 9113c0b..4d0af6d 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Darkness.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Darkness.cs @@ -112,24 +112,26 @@ namespace src.player.skills private static void SetUpPostProcessing(CCSPlayerController player, bool turnOff = false) { if (player == null || !player.IsValid) return; - ulong playerSteamID = player.SteamID; + + ulong? playerSteamID = player?.SteamID; + if (playerSteamID == null) return; lock (setLock) { if (!turnOff) { - playersInDark.TryAdd(playerSteamID, 0); + playersInDark.TryAdd((ulong)playerSteamID, 0); ApplyColor(player); Timer? darkTimer = null; darkTimer = Instance.AddTimer(5f, () => { - if (!playersInDark.ContainsKey(playerSteamID)) + if (!playersInDark.ContainsKey((ulong)playerSteamID)) { darkTimer?.Kill(); return; } - var target = Utilities.GetPlayerFromSteamId(playerSteamID); + var target = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == playerSteamID); if (target == null || !target.IsValid) { darkTimer?.Kill(); @@ -137,18 +139,18 @@ namespace src.player.skills } if (target.PawnIsAlive) - ApplyColor(player); + ApplyColor(target); }, TimerFlags.STOP_ON_MAPCHANGE | TimerFlags.REPEAT); } else { SkillUtils.ApplyScreenColor(player, r: 0, g: 0, b: 0, a: 0, duration: 200, holdTime: 0); - playersInDark.TryRemove(player.SteamID, out _); + playersInDark.TryRemove((ulong)playerSteamID, out _); } } } - private static void ApplyColor(CCSPlayerController player) + private static void ApplyColor(CCSPlayerController? player) { SkillUtils.ApplyScreenColor(player, r: SkillsInfo.GetValue(skillName, "R"), diff --git a/jRandomSkills - SRC Files/src/player/skills/Ghost.cs b/jRandomSkills - SRC Files/src/player/skills/Ghost.cs index 010be1b..5d07c97 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Ghost.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Ghost.cs @@ -1,7 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes; -using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Utils; using src.utils; using System.Collections.Concurrent; @@ -65,9 +64,20 @@ namespace src.player.skills { foreach (var (info, player) in infoList) { - if (player == null) continue; + if (player == null || !player.IsValid) continue; + + var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero; + bool isObservingGhost = false; + + if (targetHandle != nint.Zero) + { + var target = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == targetHandle); + var targetInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == target?.SteamID); + if (targetInfo?.Skill == skillName) isObservingGhost = true; + } + foreach (var _player in invisiblePlayers.Keys) - if (player.SteamID != _player.SteamID) + if (player.SteamID != _player.SteamID && !isObservingGhost) { var playerPawn = _player.PlayerPawn.Value; if (playerPawn == null || !playerPawn.IsValid) continue; diff --git a/jRandomSkills - SRC Files/src/player/skills/Iana.cs b/jRandomSkills - SRC Files/src/player/skills/Iana.cs index d88d3f1..d20090d 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Iana.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Iana.cs @@ -154,12 +154,13 @@ namespace src.player.skills KillClone(playerSkill); }); - Timer? cloneTimer = null; - ulong playerSteamID = player.SteamID; + ulong? playerSteamID = player?.SteamID; + if (playerSteamID == null) return; + Timer? cloneTimer = null; cloneTimer = jRandomSkills.Instance.AddTimer(2f, () => { - var target = Utilities.GetPlayerFromSteamId(playerSteamID); + var target = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == playerSteamID); if (target == null || !target.IsValid || !target.PawnIsAlive) { cloneTimer?.Kill(); diff --git a/jRandomSkills - SRC Files/src/player/skills/Illiterate.cs b/jRandomSkills - SRC Files/src/player/skills/Illiterate.cs new file mode 100644 index 0000000..6e672b2 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Illiterate.cs @@ -0,0 +1,77 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using src.utils; + +namespace src.player.skills +{ + public class Illiterate : ISkill + { + private const Skills skillName = Skills.Illiterate; + private static bool isActive = false; + private static int offset = jRandomSkills.Instance.Random.Next(0, 26); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(skillName, "color")); + } + + public static void NewRound() + { + isActive = false; + } + + public static void EnableSkill(CCSPlayerController player) + { + isActive = true; + } + + public static void Enable() + { + isActive = true; + } + + public static void Disable() + { + isActive = false; + } + + public static bool CheckIlliterateSkill(CCSPlayerController? player) + { + if (!isActive || player == null || !player.IsValid) return false; + if (player.Team == CsTeam.Spectator) return false; + + var playersWithSkill = jRandomSkills.Instance.SkillPlayer.Where(p => p.Skill == skillName).Select(p => p.SteamID); + if (!playersWithSkill.Any()) return false; + + return Utilities.GetPlayers().Any( + p => p.IsValid && + p.PawnIsAlive && + p.Team != player.Team + && playersWithSkill.Contains(p.SteamID)); + } + + public static string? GetRandomText(string? input) + { + if (string.IsNullOrEmpty(input)) return null; + if (Server.TickCount % 64 == 0) + offset = jRandomSkills.Instance.Random.Next(1, 26); + + return new string([.. input.Select(c => + { + if (char.IsDigit(c)) return '?'; + if (!char.IsLetter(c)) return c; + + char baseChar = char.IsUpper(c) ? 'A' : 'a'; + return (char)(baseChar + (c - baseChar + offset) % 26); + })]); + } + + public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1466F5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float maximumFuel = 150f, float fuelConsumption = .64f, float refuelling = .1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) + { + public float MaximumFuel { get; set; } = maximumFuel; + public float FuelConsumption { get; set; } = fuelConsumption; + public float Refuelling { get; set; } = refuelling; + } + } +} \ 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 b82ae1a..6aa7556 100644 --- a/jRandomSkills - SRC Files/src/player/skills/LongKnife.cs +++ b/jRandomSkills - SRC Files/src/player/skills/LongKnife.cs @@ -107,9 +107,9 @@ namespace src.player.skills if (Config.LoadedConfig.CS2TraceRayDebug) { - CreateLine(eyePos, endPos, Color.FromArgb(255, 255, 255, 0)); - CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.EndPos.X, trace.EndPos.Y, trace.EndPos.Z), Color.FromArgb(255, 255, 0, 0)); - CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.Position.X, trace.Position.Y, trace.Position.Z), Color.FromArgb(255, 0, 0, 255)); + SkillUtils.CreateLine(eyePos, endPos, Color.FromArgb(255, 255, 255, 0)); + SkillUtils.CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.EndPos.X, trace.EndPos.Y, trace.EndPos.Z), Color.FromArgb(255, 255, 0, 0)); + SkillUtils.CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.Position.X, trace.Position.Y, trace.Position.Z), Color.FromArgb(255, 0, 0, 255)); if (trace.DidHit()) { @@ -133,24 +133,6 @@ namespace src.player.skills SkillUtils.TakeHealth(target.PlayerPawn.Value, heavyHit ? Instance.Random.Next(45, 55) : Instance.Random.Next(21, 34)); } - private static void CreateLine(Vector start, Vector end, Color color) - { - CBeam beam = Utilities.CreateEntityByName("beam")!; - if (beam == null) return; - - beam.Render = color; - beam.Width = 2.0f; - beam.EndWidth = 2.0f; - beam.Teleport(start); - - beam.EndPos.X = end.X; - beam.EndPos.Y = end.Y; - beam.EndPos.Z = end.Z; - - beam.DispatchSpawn(); - beam.AcceptInput("FollowEntity", beam, null!, ""); - } - public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#c9f8ff", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float maxDistance = 4096f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) { public float MaxDistance { get; set; } = maxDistance; diff --git a/jRandomSkills - SRC Files/src/player/skills/LongZeus.cs b/jRandomSkills - SRC Files/src/player/skills/LongZeus.cs index bfc74e4..878114c 100644 --- a/jRandomSkills - SRC Files/src/player/skills/LongZeus.cs +++ b/jRandomSkills - SRC Files/src/player/skills/LongZeus.cs @@ -45,9 +45,9 @@ namespace src.player.skills if (Config.LoadedConfig.CS2TraceRayDebug) { - CreateLine(eyePos, endPos, Color.FromArgb(255, 255, 255, 0)); - CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.EndPos.X, trace.EndPos.Y, trace.EndPos.Z), Color.FromArgb(255, 255, 0, 0)); - CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.Position.X, trace.Position.Y, trace.Position.Z), Color.FromArgb(255, 0, 0, 255)); + SkillUtils.CreateLine(eyePos, endPos, Color.FromArgb(255, 255, 255, 0)); + SkillUtils.CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.EndPos.X, trace.EndPos.Y, trace.EndPos.Z), Color.FromArgb(255, 255, 0, 0)); + SkillUtils.CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.Position.X, trace.Position.Y, trace.Position.Z), Color.FromArgb(255, 0, 0, 255)); if (trace.DidHit()) { @@ -70,24 +70,6 @@ namespace src.player.skills SkillUtils.TryGiveWeapon(player, CsItem.Zeus); } - private static void CreateLine(Vector start, Vector end, Color color) - { - CBeam beam = Utilities.CreateEntityByName("beam")!; - if (beam == null) return; - - beam.Render = color; - beam.Width = 2.0f; - beam.EndWidth = 2.0f; - beam.Teleport(start); - - beam.EndPos.X = end.X; - beam.EndPos.Y = end.Y; - beam.EndPos.Z = end.Z; - - beam.DispatchSpawn(); - beam.AcceptInput("FollowEntity", beam, null!, ""); - } - public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#6effc7", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float maxDistance = 4096f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) { public float MaxDistance { get; set; } = maxDistance; diff --git a/jRandomSkills - SRC Files/src/player/skills/Ninja.cs b/jRandomSkills - SRC Files/src/player/skills/Ninja.cs index 53e95a5..5377b1a 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Ninja.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Ninja.cs @@ -1,7 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes; -using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Utils; using src.utils; using System.Collections.Concurrent; @@ -57,9 +56,20 @@ namespace src.player.skills { foreach (var (info, player) in infoList) { - if (player == null) continue; + if (player == null || !player.IsValid) continue; + + var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero; + bool isObservingNinja = false; + + if (targetHandle != nint.Zero) + { + var target = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == targetHandle); + var targetInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == target?.SteamID); + if (targetInfo?.Skill == skillName) isObservingNinja = true; + } + foreach (var _player in invisiblePlayers.Keys) - if (player.SteamID != _player.SteamID) + if (player.SteamID != _player.SteamID && !isObservingNinja) { var playerPawn = _player.PlayerPawn.Value; if (playerPawn == null || !playerPawn.IsValid) continue; diff --git a/jRandomSkills - SRC Files/src/player/skills/Noclip.cs b/jRandomSkills - SRC Files/src/player/skills/Noclip.cs index 2bd94f2..7c05562 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Noclip.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Noclip.cs @@ -1,9 +1,13 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Utils; -using static src.jRandomSkills; -using System.Collections.Concurrent; +using CS2TraceRay.Class; +using CS2TraceRay.Struct; using src.utils; +using System.Collections.Concurrent; +using static src.jRandomSkills; +using Timer = CounterStrikeSharp.API.Modules.Timers.Timer; namespace src.player.skills { @@ -87,52 +91,139 @@ namespace src.player.skills public static void UseSkill(CCSPlayerController player) { var playerPawn = player.PlayerPawn.Value; - var duration = SkillsInfo.GetValue(skillName, "duration"); if (playerPawn?.CBodyComponent == null) return; if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo)) { - if (!player.IsValid || !player.PawnIsAlive) return; + if (skillInfo.IsFlying) + { + StopFlying(player, skillInfo); + return; + } + if (skillInfo.CanUse) { + var duration = SkillsInfo.GetValue(skillName, "duration"); + skillInfo.CanUse = false; skillInfo.IsFlying = true; skillInfo.Cooldown = DateTime.Now; skillInfo.LastPosition = playerPawn.AbsOrigin == null ? null : new Vector(playerPawn.AbsOrigin.X, playerPawn.AbsOrigin.Y, playerPawn.AbsOrigin.Z); + SetNoclip(player, true); + skillInfo.Timer?.Kill(); - playerPawn.ActualMoveType = MoveType_t.MOVETYPE_NOCLIP; - Instance.AddTimer(duration, () => { - if (playerPawn == null || !playerPawn.IsValid || !skillInfo.IsFlying) return; - skillInfo.IsFlying = false; - playerPawn.ActualMoveType = MoveType_t.MOVETYPE_WALK; - }); - - Instance.AddTimer(duration + 4, () => { - if (playerPawn == null || !playerPawn.IsValid || !player.PawnIsAlive || skillInfo.IsFlying) return; - if (skillInfo.LastPosition == null || playerPawn.AbsOrigin == null) return; - skillInfo.IsFlying = false; - var diff = Math.Abs(playerPawn.AbsOrigin.Z - skillInfo.LastPosition.Z); - if (diff > 3000 && playerPawn.AbsOrigin.Z < skillInfo.LastPosition.Z) - playerPawn.Teleport(skillInfo.LastPosition, null, new Vector(0,0,0)); - }); - } - else if (skillInfo.IsFlying) - { - skillInfo.IsFlying = false; - playerPawn.ActualMoveType = MoveType_t.MOVETYPE_WALK; - - Instance.AddTimer(4, () => { - if (playerPawn == null || !playerPawn.IsValid || !player.PawnIsAlive || skillInfo.IsFlying) return; - if (skillInfo.LastPosition == null || playerPawn.AbsOrigin == null) return; - skillInfo.IsFlying = false; - var diff = Math.Abs(playerPawn.AbsOrigin.Z - skillInfo.LastPosition.Z); - if (diff > 3000 && playerPawn.AbsOrigin.Z < skillInfo.LastPosition.Z) - playerPawn.Teleport(skillInfo.LastPosition, null, new Vector(0, 0, 0)); + skillInfo.Timer = Instance.AddTimer(duration, () => + { + StopFlying(player, skillInfo); }); } } } + private static void SetNoclip(CCSPlayerController player, bool noclip = true) + { + if (player == null || !player.IsValid) return; + + var playerPawn = player.PlayerPawn.Value; + if (playerPawn == null || !playerPawn.IsValid || !player.PawnIsAlive) return; + + playerPawn.MoveType = noclip ? MoveType_t.MOVETYPE_NOCLIP : MoveType_t.MOVETYPE_WALK; + Schema.SetSchemaValue(playerPawn.Handle, "CBaseEntity", "m_nActualMoveType", (int)playerPawn.MoveType); + Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_MoveType"); + } + + private static void StopFlying(CCSPlayerController player, PlayerSkillInfo skillInfo) + { + skillInfo.Timer?.Kill(); + skillInfo.Timer = null; + + if (!skillInfo.IsFlying) return; + skillInfo.IsFlying = false; + + if (player == null || !player.IsValid || !player.PawnIsAlive) return; + SetNoclip(player, false); + + var playerPawn = player.PlayerPawn.Value; + if (playerPawn == null || !playerPawn.IsValid || skillInfo.IsFlying) return; + + Vector? safePoint = GetCorrectPosition(player, skillInfo); + playerPawn.Teleport(safePoint ?? skillInfo.LastPosition, null, new Vector(0, 0, 0)); + } + + private static Vector? GetCorrectPosition(CCSPlayerController player, PlayerSkillInfo skillInfo) + { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null) return null; + + Vector currentPos = playerPawn.AbsOrigin; + float offset = 50; + + Vector[] checkOffsets = + { + currentPos, + currentPos + new Vector(offset, 0, 10), + currentPos + new Vector(-offset, 0, 10), + currentPos + new Vector(0, offset, 10), + currentPos + new Vector(0, -offset, 10), + + currentPos + new Vector(offset, 0, 60), + currentPos + new Vector(-offset, 0, 60), + currentPos + new Vector(0, offset, 60), + currentPos + new Vector(0, -offset, 60), + }; + + ulong mask = playerPawn.Collision.CollisionAttribute.InteractsWith; + ulong contents = playerPawn.Collision.CollisionGroup; + bool hasGround = false; + + foreach (Vector targetPos in checkOffsets) + { + Vector start = new(targetPos.X, targetPos.Y, targetPos.Z + 70); + Vector end = new(targetPos.X, targetPos.Y, targetPos.Z - 1000); + + CGameTrace groundTrace = TraceRay.TraceShape(start, end, mask, contents, player); + if (!groundTrace.DidHit()) continue; + + hasGround = true; + Vector newPos = + groundTrace.EndPos.Z > targetPos.Z + ? new(groundTrace.EndPos.X, groundTrace.EndPos.Y, groundTrace.EndPos.Z) + : targetPos; + + if (IsPositionSafe(newPos, player)) + return newPos; + } + + if (hasGround) + skillInfo.Cooldown = DateTime.Now.AddSeconds(-SkillsInfo.GetValue(skillName, "cooldown") + SkillsInfo.GetValue(skillName, "cooldownWhenStuck")); + return hasGround ? currentPos : null; + } + + private static bool IsPositionSafe(Vector pos, CCSPlayerController player) + { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null) return false; + + float footHeight = 0; + float headHeight = 70; + float innerDist = 12; + + ulong mask = playerPawn.Collision.CollisionAttribute.InteractsWith; + ulong contents = playerPawn.Collision.CollisionGroup; + + Vector s1 = new(pos.X - innerDist, pos.Y - innerDist, pos.Z + footHeight); + Vector e1 = new(pos.X + innerDist, pos.Y + innerDist, pos.Z + headHeight); + CGameTrace t1 = TraceRay.TraceShape(s1, e1, mask, contents, player); + if (t1.DidHit() || t1.AllSolid) return false; + + Vector s2 = new(pos.X + innerDist, pos.Y - innerDist, pos.Z + footHeight); + Vector e2 = new(pos.X - innerDist, pos.Y + innerDist, pos.Z + headHeight); + CGameTrace t2 = TraceRay.TraceShape(s2, e2, mask, contents, player); + if (t2.DidHit() || t2.AllSolid) return false; + + return true; + } + public class PlayerSkillInfo { public ulong SteamID { get; set; } @@ -140,11 +231,13 @@ namespace src.player.skills public bool IsFlying { get; set; } public DateTime Cooldown { get; set; } public Vector? LastPosition { get; set; } + public Timer? Timer { get; set; } } - public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#44ebd4", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float cooldown = 30f, float duration = 2f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) + public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#44ebd4", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float cooldown = 30f, float duration = 2f, float cooldownWhenStuck = 5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) { public float Cooldown { get; set; } = cooldown; + public float CooldownWhenStuck { get; set; } = cooldownWhenStuck; public float Duration { get; set; } = duration; } } diff --git a/jRandomSkills - SRC Files/src/player/skills/PawelJumper.cs b/jRandomSkills - SRC Files/src/player/skills/PawelJumper.cs index 4ae2893..6509f7b 100644 --- a/jRandomSkills - SRC Files/src/player/skills/PawelJumper.cs +++ b/jRandomSkills - SRC Files/src/player/skills/PawelJumper.cs @@ -9,7 +9,6 @@ namespace src.player.skills public class PawelJumper : ISkill { private const Skills skillName = Skills.PawelJumper; - private static readonly PlayerFlags[] LF = new PlayerFlags[64]; private static readonly int?[] J = new int?[64]; private static readonly PlayerButtons[] LB = new PlayerButtons[64]; @@ -71,7 +70,6 @@ namespace src.player.skills playerPawn.AbsVelocity.Z = 300; } - LF[player.Slot] = flags; LB[player.Slot] = buttons; } diff --git a/jRandomSkills - SRC Files/src/player/skills/Pilot.cs b/jRandomSkills - SRC Files/src/player/skills/Pilot.cs index d1dcc9d..ab67d81 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Pilot.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Pilot.cs @@ -38,6 +38,7 @@ namespace src.player.skills { SteamID = player.SteamID, Fuel = SkillsInfo.GetValue(skillName, "maximumFuel"), + LastButtons = 0 }); } @@ -49,16 +50,37 @@ namespace src.player.skills private static void HandlePilot(CCSPlayerController player) { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn == null || !playerPawn.IsValid) return; + + if (!PlayerPilotInfo.TryGetValue(player.SteamID, out var pilotInfo)) return; + + var flags = (PlayerFlags)playerPawn.Flags; var buttons = player.Buttons; + + bool isJumpDown = (playerPawn.MovementServices?.Buttons?.ButtonStates[0] & (ulong)PlayerButtons.Jump) != 0 || (buttons & PlayerButtons.Jump) != 0; + bool wasJumpDown = (pilotInfo.LastButtons & PlayerButtons.Jump) != 0; + + bool jumpPressed = (isJumpDown && !wasJumpDown) + || (playerPawn.MovementServices?.QueuedButtonChangeMask & (ulong)PlayerButtons.Jump) != 0; + + bool isOnGround = (flags & PlayerFlags.FL_ONGROUND) != 0; + bool inUse = jumpPressed && !isOnGround; + var maximumFuel = SkillsInfo.GetValue(skillName, "maximumFuel"); - if (PlayerPilotInfo.TryGetValue(player.SteamID, out var pilotInfo)) - { - pilotInfo.Fuel = Math.Min(Math.Max(0, pilotInfo.Fuel - (buttons.HasFlag(PlayerButtons.Use) ? SkillsInfo.GetValue(skillName, "fuelConsumption") : -SkillsInfo.GetValue(skillName, "refuelling"))), maximumFuel); - if (buttons.HasFlag(PlayerButtons.Use)) - if (pilotInfo.Fuel > 0 && player.PlayerPawn.Value != null && player.PlayerPawn.Value.IsValid && !player.PlayerPawn.Value.IsDefusing) - ApplyPilotEffect(player); - UpdateHUD(player, pilotInfo); - } + pilotInfo.Fuel = Math.Min( + Math.Max( + 0, + pilotInfo.Fuel - (inUse + ? SkillsInfo.GetValue(skillName, "fuelConsumption") + : -SkillsInfo.GetValue(skillName, "refuelling"))), + maximumFuel); + pilotInfo.LastButtons = buttons; + + if (inUse && pilotInfo.Fuel > 0) + ApplyPilotEffect(player); + + UpdateHUD(player, pilotInfo); } private static void UpdateHUD(CCSPlayerController player, Pilot_PlayerInfo pilotInfo) @@ -121,6 +143,7 @@ namespace src.player.skills { public ulong SteamID { get; set; } public float Fuel { get; set; } + public PlayerButtons LastButtons { get; set; } } public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1466F5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float maximumFuel = 150f, float fuelConsumption = .64f, float refuelling = .1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) diff --git a/jRandomSkills - SRC Files/src/player/skills/Replicator.cs b/jRandomSkills - SRC Files/src/player/skills/Replicator.cs index edf539d..82e6df9 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Replicator.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Replicator.cs @@ -99,9 +99,6 @@ namespace src.player.skills float distance = 40; Vector pos = playerPawn.AbsOrigin + SkillUtils.GetForwardVector(playerPawn.AbsRotation) * distance; - - if (((PlayerFlags)playerPawn.Flags).HasFlag(PlayerFlags.FL_DUCKING)) - pos.Z -= 19; replica.Flags = playerPawn.Flags; replica.Flags |= (uint)Flags_t.FL_DUCKING; @@ -109,6 +106,13 @@ namespace src.player.skills 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 = $"Replica_{Server.TickCount}_{(player.Team == CsTeam.CounterTerrorist ? "CT" : "TT")}"; + + replica.UseAnimGraph = false; + string animName = "idle_for_turns_stand_pistol"; + if (((PlayerFlags)playerPawn.Flags).HasFlag(PlayerFlags.FL_DUCKING)) + animName = "idle_for_turns_crouch_pistol"; + + replica.AcceptInput("SetAnimation", value: animName); replica.Teleport(pos, playerPawn.AbsRotation, null); replica.DispatchSpawn(); } diff --git a/jRandomSkills - SRC Files/src/player/skills/Smoker.cs b/jRandomSkills - SRC Files/src/player/skills/Smoker.cs new file mode 100644 index 0000000..fd52500 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Smoker.cs @@ -0,0 +1,75 @@ +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.Utils; +using Microsoft.Extensions.Logging; +using src.utils; +using System.Collections.Concurrent; +using static src.jRandomSkills; + +namespace src.player.skills +{ + public class Smoker : ISkill + { + private const Skills skillName = Skills.Smoker; + private readonly static ConcurrentDictionary smokes = []; + private static readonly object setLock = new(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(skillName, "color")); + } + + public static void NewRound() + { + lock (setLock) + smokes.Clear(); + + + } + + public static void EnableSkill(CCSPlayerController player) + { + SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade); + } + + public static void SmokegrenadeDetonate(EventSmokegrenadeDetonate @event) + { + 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"); + } + + public static void SmokegrenadeExpired(EventSmokegrenadeExpired @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; + + Vector pos = new(@event.X, @event.Y, @event.Z); + SkillUtils.CreateSmokeGrenadeProjectile(pos, new QAngle(0, 0, 0), new Vector(0, 0, 0), player.TeamNum); + } + + 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) + { + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/SoundMaker.cs b/jRandomSkills - SRC Files/src/player/skills/SoundMaker.cs index 5e373c1..f77632d 100644 --- a/jRandomSkills - SRC Files/src/player/skills/SoundMaker.cs +++ b/jRandomSkills - SRC Files/src/player/skills/SoundMaker.cs @@ -1,18 +1,22 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.UserMessages; using CounterStrikeSharp.API.Modules.Utils; -using static src.jRandomSkills; -using System.Collections.Concurrent; using src.utils; +using System.Collections.Concurrent; +using static src.jRandomSkills; namespace src.player.skills { public class SoundMaker : ISkill { private const Skills skillName = Skills.SoundMaker; - private static readonly ConcurrentDictionary SkillPlayerInfo = []; + private static readonly ConcurrentDictionary SkillPlayerInfo = []; private static readonly object setLock = new(); + private const string soundEventName = "Hostage.Pain"; + private const uint soundEventHash = 1876781570; + public static void LoadSkill() { SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(skillName, "color")); @@ -26,12 +30,7 @@ namespace src.player.skills public static void EnableSkill(CCSPlayerController player) { - SkillPlayerInfo.TryAdd(player.SteamID, new PlayerSkillInfo - { - SteamID = player.SteamID, - CanUse = true, - Cooldown = DateTime.MinValue, - }); + SkillPlayerInfo.TryAdd(player.SteamID, 0); } public static void DisableSkill(CCSPlayerController player) @@ -49,78 +48,40 @@ namespace src.player.skills SkillPlayerInfo.TryRemove(player.SteamID, out _); } + public static void PlayerMakeSound(UserMessage um) + { + var soundevent = um.ReadUInt("soundevent_hash"); + if (soundevent != soundEventHash) return; + + var userIndex = um.ReadUInt("source_entity_index"); + if (userIndex == 0) return; + + var sourcePlayer = Utilities.GetPlayers().FirstOrDefault(p => p.Pawn?.Value != null && p.Pawn.Value.IsValid && p.Pawn.Value.Index == userIndex); + if (sourcePlayer == null || !sourcePlayer.IsValid) return; + + var toRemove = um.Recipients.Where(r => + { + if (r.Team == sourcePlayer.Team) return true; + if (SkillPlayerInfo.ContainsKey(r.SteamID)) return false; + return true; + }).ToList(); + + foreach (var player in toRemove) + um.Recipients.Remove(player); + } + 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); - } + if (Server.TickCount % (60 * SkillsInfo.GetValue(skillName, "cooldown")) != 0) return; + + foreach (var player in Utilities.GetPlayers() + .Where(p => p != null && p.IsValid && p.PawnIsAlive && p.PlayerPawn.Value != null && p.PlayerPawn.Value.IsValid)) + player.PlayerPawn.Value!.EmitSound(soundEventName, volume: 1f); } - private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo) + public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#e3ed8c", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int cooldown = 2) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) { - 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; - MakeSound(player); - } - } - } - - private static void MakeSound(CCSPlayerController player) - { - foreach (var enemy in Utilities.GetPlayers().Where(p => p.Team != player.Team)) - if (enemy != null && enemy.IsValid && enemy.PawnIsAlive && enemy.PlayerPawn.Value != null && enemy.PlayerPawn.Value.IsValid) - enemy.PlayerPawn.Value.EmitSound( - enemy.Team == CsTeam.CounterTerrorist - ? SkillsInfo.GetValue(skillName, "CTSoundEvent") - : SkillsInfo.GetValue(skillName, "TSoundEvent") - , volume: 1f); - } - - 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 = "#e3ed8c", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float cooldown = 5f, string ctSoundEvent = "c4.disarmstart", string tSoundEvent = "C4.PlantSoundB") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) - { - public float Cooldown { get; set; } = cooldown; - public string CTSoundEvent { get; set; } = ctSoundEvent; - public string TSoundEvent { get; set; } = tSoundEvent; + public int Cooldown { get; set; } = cooldown; } } } \ 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 e072ed3..4f72e81 100644 --- a/jRandomSkills - SRC Files/src/player/skills/ToxicSmoke.cs +++ b/jRandomSkills - SRC Files/src/player/skills/ToxicSmoke.cs @@ -95,10 +95,6 @@ namespace src.player.skills var trigger = SkillUtils.CreateTrigger(triggerName, SkillsInfo.GetValue(skillName, "smokeRadius"), new Vector(@event.X, @event.Y, @event.Z)); if (trigger == null) return; triggers.TryAdd(trigger, 0); - - new VirtualFunctionVoid(trigger.Handle, 153); - - } public static void SmokegrenadeExpired(EventSmokegrenadeExpired @event) @@ -138,7 +134,7 @@ namespace src.player.skills } } - public class SkillConfig(Skills skill = skillName, bool active = false, string color = "#507529", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int smokeDamage = 2, float smokeRadius = 180) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) + public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#507529", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int smokeDamage = 2, float smokeRadius = 180) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) { public int SmokeDamage { get; set; } = smokeDamage; public float SmokeRadius { get; set; } = smokeRadius; diff --git a/jRandomSkills - SRC Files/src/player/skills/Wallhack.cs b/jRandomSkills - SRC Files/src/player/skills/Wallhack.cs index 27beb40..999899d 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Wallhack.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Wallhack.cs @@ -13,7 +13,7 @@ namespace src.player.skills { private const Skills skillName = Skills.Wallhack; private static readonly ConcurrentDictionary playersInAction = []; - private static readonly ConcurrentBag<(CDynamicProp, CDynamicProp, CsTeam)> glows = []; + private static readonly ConcurrentBag<(CDynamicProp, CDynamicProp, CsTeam, uint)> glows = []; public static void LoadSkill() { @@ -32,8 +32,11 @@ namespace src.player.skills foreach (var glow in glows) { - if (glow.Item3 != player.Team && (playerInfo?.Skill == skillName || (observerInfo != null && observerInfo?.Skill == skillName))) - continue; + var enemy = Utilities.GetPlayers().FirstOrDefault(e => e.IsValid && e.Index == glow.Item4); + + if (enemy != null && enemy.PawnIsAlive) + if (glow.Item3 != player.Team && (playerInfo?.Skill == skillName || (observerInfo != null && observerInfo?.Skill == skillName))) + continue; var glowEntity1 = Utilities.GetEntityFromIndex((int)glow.Item1.Index); if (glowEntity1 == null || !glowEntity1.IsValid) continue; @@ -110,7 +113,7 @@ namespace src.player.skills modelRelay.AcceptInput("FollowEntity", enemyPawn, modelRelay, "!activator"); modelGlow.AcceptInput("FollowEntity", modelRelay, modelGlow, "!activator"); - glows.Add((modelRelay, modelGlow, enemy.Team)); + glows.Add((modelRelay, modelGlow, enemy.Team, enemy.Index)); } } diff --git a/jRandomSkills - SRC Files/src/utils/Config.cs b/jRandomSkills - SRC Files/src/utils/Config.cs index fef56f7..123f3ea 100644 --- a/jRandomSkills - SRC Files/src/utils/Config.cs +++ b/jRandomSkills - SRC Files/src/utils/Config.cs @@ -1,5 +1,7 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; using static src.jRandomSkills; namespace src.utils @@ -69,6 +71,9 @@ namespace src.utils public class SettingsModel { + [DisplayName("Game Mode")] + [Description("TESTfafw..")] + [Range(0, 5)] public int GameMode { get; set; } public bool YourSkillChatInfo { get; set; } public bool KillerSkillChatInfo { get; set; } @@ -120,6 +125,8 @@ namespace src.utils new LanguageInfo("PT-BR, PT, BR, AO, CV, GW, MZ, ST, TL", "pt-br"), new LanguageInfo("FR, MC, HT", "fr"), new LanguageInfo("DE, AT, CH, LI, LU, BE", "de"), + new LanguageInfo("TR", "tr"), + new LanguageInfo("CZ", "cs"), new LanguageInfo("PL", "pl"), new LanguageInfo("EN, GB, US", "en") ] diff --git a/jRandomSkills - SRC Files/src/utils/Localization.cs b/jRandomSkills - SRC Files/src/utils/Localization.cs index d6030bd..0c3cf3d 100644 --- a/jRandomSkills - SRC Files/src/utils/Localization.cs +++ b/jRandomSkills - SRC Files/src/utils/Localization.cs @@ -6,6 +6,7 @@ using Newtonsoft.Json; using System.Net; using System.Collections.Concurrent; using src.player; +using src.player.skills; namespace src.utils { @@ -80,7 +81,7 @@ namespace src.utils } var value = Math.Round((double)(chance ?? 1), 2); - var skillNameText = GetTranslation(skill.ToString().ToLower(), langCode, value); + var skillNameText = GetTranslation(skill.ToString().ToLower(), langCode, player, value); if (skillNameText.Contains('%')) skillNameText = skillNameText.Replace(value.ToString(), Math.Round(value * 100, 0).ToString()); return skillNameText; } @@ -104,7 +105,7 @@ namespace src.utils var skillName = $"{skill.ToString().ToLower()}_desc2"; var value = Math.Round((double)(chance ?? 1), 2); - var desc2 = GetTranslation(skillName, langCode, value); + var desc2 = GetTranslation(skillName, langCode, player, value); var skilLDescription = desc2 == skillName ? player.GetTranslation($"{skill.ToString().ToLower()}_desc") @@ -127,7 +128,7 @@ namespace src.utils for (int i = 0; i < key.Length; i++) { object[] currentArgs = args != null && i < args.Length ? args[i] : []; - string translation = GetTranslation(key[i], langCode, currentArgs); + string translation = GetTranslation(key[i], langCode, null, currentArgs); translations.Add(translation); } player.PrintToChat(string.Format(message, [.. translations])); @@ -137,10 +138,10 @@ namespace src.utils public static string GetTranslation(this CCSPlayerController player, string key, params object[] args) { string langCode = GetLangCode(player); - return GetTranslation(key, langCode, args); + return GetTranslation(key, langCode, player, args); } - public static string GetTranslation(string key, string? langCode = null, params object[] args) + public static string GetTranslation(string key, string? langCode = null, CCSPlayerController? player = null, params object[] args) { langCode ??= defaultLangCode; if (_translations.TryGetValue(langCode, out var langDict) && langDict.TryGetValue(key, out var translation)) @@ -152,9 +153,14 @@ namespace src.utils output = output.Replace("CHATCOLORS.RED", ChatColors.Red.ToString()); if (Config.LoadedConfig.AlternativeSkillButton != null) output = output.Replace("css_useSkill", $"css_useSkill/{Config.LoadedConfig.AlternativeSkillButton}"); + + if (Illiterate.CheckIlliterateSkill(player)) + return Illiterate.GetRandomText(output); return output; } + if (langCode != defaultLangCode) + return GetTranslation(key, null, player, args); return key; } @@ -188,7 +194,10 @@ namespace src.utils if (string.IsNullOrEmpty(playerIP)) return null; if (!File.Exists(geoliteFilePath)) return null; using var reader = new Reader(geoliteFilePath); - var ip = IPAddress.Parse(playerIP); + + if (!IPAddress.TryParse(playerIP, out var ip)) + return null; + var data = reader.Find>(ip); if (data == null || data.IsEmpty) return null; diff --git a/jRandomSkills - SRC Files/src/utils/SkillUtils.cs b/jRandomSkills - SRC Files/src/utils/SkillUtils.cs index 196e07b..36d8781 100644 --- a/jRandomSkills - SRC Files/src/utils/SkillUtils.cs +++ b/jRandomSkills - SRC Files/src/utils/SkillUtils.cs @@ -9,6 +9,7 @@ using CounterStrikeSharp.API.Modules.Utils; using src.player; using src.player.skills; using System.Collections.Concurrent; +using System.Drawing; using System.Globalization; using System.Runtime.InteropServices; using WASDMenuAPI.Classes; @@ -19,15 +20,21 @@ 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 MemoryFunctionVoid TerminateRoundFunc = new(GameData.GetSignature("CCSGameRules_TerminateRound")); public static void PrintToChat(CCSPlayerController player, string msg, string border = "tb", string? title = null) { + if (!player.IsValid) return; + var config = Config.LoadedConfig.ChatMessage; float maxWidth = config.MaxWidth; char symbol = config.LineSymbol; if (string.IsNullOrEmpty(title)) title = player.GetTranslation("jRandomSkills"); + if (Illiterate.CheckIlliterateSkill(player)) + msg = Illiterate.GetRandomText(msg); + if (border.Contains('t') && config.LineShow) player.PrintToChat($" {MeansureString.GetTextDashed($"{(config.TagFormat.Contains("{TAG}") ? config.TagFormat.Replace("{TAG}", title) : $"\u0002◢◆◤ {title} ◥◆◣")}", maxWidth, symbol, config.LineColor)}"); if (!string.IsNullOrEmpty(msg) && config.InfoMessageShow) @@ -86,9 +93,29 @@ namespace src.utils return new Vector(x, y, z); } - - public static void ApplyScreenColor(CCSPlayerController player, int r, int g, int b, int a, int duration, int holdTime, int flags = 1) + public static CBeam? CreateLine(Vector start, Vector end, Color color) { + CBeam beam = Utilities.CreateEntityByName("beam")!; + if (beam == null) return null; + + beam.Render = color; + beam.Width = 2.0f; + beam.EndWidth = 2.0f; + beam.Teleport(start); + + beam.EndPos.X = end.X; + beam.EndPos.Y = end.Y; + beam.EndPos.Z = end.Z; + + beam.DispatchSpawn(); + + return beam; + } + + public static void ApplyScreenColor(CCSPlayerController? player, int r, int g, int b, int a, int duration, int holdTime, int flags = 1) + { + if (player == null || !player.IsValid) return; + using var msg = UserMessage.FromPartialName("Fade"); if (msg == null) return; int packageColor = (a << 24) | (b << 16) | (g << 8) | r; @@ -142,6 +169,11 @@ namespace src.utils HEGrenadeProjectile_CreateFunc.Invoke(pos.Handle, angle.Handle, vel.Handle, vel.Handle, IntPtr.Zero, 44, teamNum); } + public static void CreateSmokeGrenadeProjectile(Vector pos, QAngle angle, Vector vel, int teamNum) + { + SmokeGrenadeProjectile_CreateFunc.Invoke(pos.Handle, angle.Handle, vel.Handle, vel.Handle, IntPtr.Zero, 45, teamNum); + } + public static void TakeHealth(CCSPlayerPawn? pawn, int damage) { if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) @@ -280,9 +312,11 @@ namespace src.utils var playerInfo = jRandomSkills.Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo == null) return; + bool isIlliterate = Illiterate.CheckIlliterateSkill(player); + Dictionary> list = []; foreach (var item in items) - list.TryAdd(item.Item1, (p, option) => + list.TryAdd(isIlliterate ? Illiterate.GetRandomText(item.Item1) : item.Item1, (p, option) => { jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { item.Item2 }]); manager.CloseMenu(p); @@ -329,15 +363,17 @@ namespace src.utils string itemText = $"{{0}}
"; string itemHoverText = $"[ {{0}} ]
"; + bool isIlliterate = Illiterate.CheckIlliterateSkill(player); + IWasdMenu menu = manager.CreateMenu(hudContent, itemText, itemHoverText, controllsLine); foreach (var enemy in enemies) - menu.Add(enemy.Item1, (p, option) => + menu.Add(isIlliterate ? Illiterate.GetRandomText(enemy.Item1) : enemy.Item1, (p, option) => { jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { enemy.Item2 }]); manager.CloseMenu(p); }); if (lastElement != null) - menu.Add(lastElement.Value.Item1, (p, option) => + menu.Add(isIlliterate ? Illiterate.GetRandomText(lastElement.Value.Item1) : lastElement.Value.Item1, (p, option) => { jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { lastElement.Value.Item2 }]); if (lastElement.Value.Item3)