From 26cb787b57c8560b8a6b687c9fdcbde2bbc377df Mon Sep 17 00:00:00 2001 From: Juzlus Date: Fri, 29 Aug 2025 02:41:39 +0200 Subject: [PATCH] v1.1.0 --- .../jRandomSkills.csproj | 3 +- .../src/command/Command.cs | 85 +-- .../src/icons/jRandomSkills.png | Bin 0 -> 40227 bytes .../src/jRandomSkills.cs | 48 +- jRandomSkills - SRC Files/src/lang/en.json | 485 +++++++++++++---- jRandomSkills - SRC Files/src/lang/pl.json | 501 ++++++++++++------ jRandomSkills - SRC Files/src/lang/pt-br.json | 410 ++++++++++++++ jRandomSkills - SRC Files/src/lang/zh.json | 410 ++++++++++++++ jRandomSkills - SRC Files/src/player/Debug.cs | 7 +- .../src/player/ISkill.cs | 161 +++--- .../src/player/PlayerEvents.cs | 75 ++- .../src/player/PlayerOnTick.cs | 28 +- .../src/player/skills/Aimbot.cs | 18 +- .../src/player/skills/Anomaly.cs | 163 ++++++ .../src/player/skills/AntyFlash.cs | 38 +- .../src/player/skills/AntyHead.cs | 15 +- .../src/player/skills/AreaReaper.cs | 11 +- .../src/player/skills/Armored.cs | 29 +- .../src/player/skills/Assassin.cs | 78 +++ .../src/player/skills/Astronaut.cs | 34 +- .../src/player/skills/Baseball.cs | 130 +++++ .../src/player/skills/Behind.cs | 23 +- .../src/player/skills/BladeMaster.cs | 75 +++ .../src/player/skills/BunnyHop.cs | 62 ++- .../src/player/skills/C4Camouflage.cs | 25 +- .../src/player/skills/Catapult.cs | 28 +- .../src/player/skills/Chicken.cs | 31 +- .../src/player/skills/ChillOut.cs | 50 ++ .../src/player/skills/Cutter.cs | 41 ++ .../src/player/skills/Darkness.cs | 136 +++++ .../src/player/skills/Deactivator.cs | 17 +- .../src/player/skills/Deaf.cs | 119 +++++ .../src/player/skills/Disarmament.cs | 31 +- .../src/player/skills/Distancer.cs | 98 ++++ .../src/player/skills/Dracula.cs | 22 +- .../src/player/skills/Duplicator.cs | 14 +- .../src/player/skills/Dwarf.cs | 29 +- .../src/player/skills/EnemySpawn.cs | 26 +- .../src/player/skills/ExplosiveShot.cs | 106 ++++ .../src/player/skills/FalconEye.cs | 147 +++++ .../src/player/skills/FastReload.cs | 46 ++ .../src/player/skills/Flash.cs | 27 +- .../src/player/skills/Fortnite.cs | 191 +++++++ .../src/player/skills/FragileBomb.cs | 131 +++++ .../src/player/skills/FriendlyFire.cs | 54 ++ .../src/player/skills/FrozenDecoy.cs | 126 +---- .../src/player/skills/Ghost.cs | 19 +- .../src/player/skills/Glaz.cs | 89 ++++ .../src/player/skills/Glitch.cs | 13 +- .../src/player/skills/Glue.cs | 41 ++ .../src/player/skills/GodMode.cs | 29 +- .../src/player/skills/HealingSmoke.cs | 121 +++++ .../src/player/skills/Hermit.cs | 21 +- .../src/player/skills/HolyHandGrenade.cs | 26 +- .../src/player/skills/Impostor.cs | 14 +- .../src/player/skills/InfiniteAmmo.cs | 15 +- .../src/player/skills/Jackal.cs | 184 +++++++ .../src/player/skills/Jammer.cs | 13 +- .../src/player/skills/JumpBan.cs | 121 +++++ .../src/player/skills/JumpingJack.cs | 37 ++ .../src/player/skills/KillerFlash.cs | 20 +- .../src/player/skills/LifeSwap.cs | 103 ++++ .../src/player/skills/LongKnife.cs | 74 +++ .../src/player/skills/LongZeus.cs | 94 ++++ .../src/player/skills/Medic.cs | 128 ++++- .../src/player/skills/MoneySwap.cs | 102 ++++ .../src/player/skills/Muhammed.cs | 27 +- .../src/player/skills/Mute.cs | 30 +- .../src/player/skills/Ninja.cs | 40 +- .../src/player/skills/NoNades.cs | 43 ++ .../src/player/skills/NoRecoil.cs | 16 +- .../skills/{TimeManipulator.cs => Noclip.cs} | 44 +- .../src/player/skills/None.cs | 14 +- .../src/player/skills/OneShot.cs | 18 +- .../src/player/skills/OnlyHead.cs | 15 +- .../src/player/skills/PawelJumper.cs | 14 +- .../src/player/skills/Phoenix.cs | 25 +- .../src/player/skills/Pilot.cs | 25 +- .../src/player/skills/Planter.cs | 40 +- .../src/player/skills/Poison.cs | 120 +++++ .../src/player/skills/PrimaryBan.cs | 126 +++++ .../src/player/skills/Prosthesis.cs | 17 +- .../src/player/skills/PsychicDefusing.cs | 153 ++++++ .../src/player/skills/Push.cs | 96 ++++ .../src/player/skills/Pyro.cs | 76 +++ .../src/player/skills/QuickShot.cs | 15 +- .../src/player/skills/RadarHack.cs | 15 +- .../src/player/skills/Rambo.cs | 23 +- .../src/player/skills/RandomWeapon.cs | 19 +- .../src/player/skills/ReZombie.cs | 91 ++++ .../src/player/skills/ReactiveArmor.cs | 22 +- .../src/player/skills/Regeneration.cs | 46 ++ .../src/player/skills/Replicator.cs | 19 +- .../src/player/skills/Retreat.cs | 18 +- .../src/player/skills/ReturnToSender.cs | 18 +- .../src/player/skills/RichBoy.cs | 25 +- .../src/player/skills/RobinHood.cs | 23 +- .../src/player/skills/Rubber.cs | 74 +++ .../src/player/skills/Saper.cs | 13 +- .../src/player/skills/SecondLife.cs | 25 +- .../src/player/skills/Shade.cs | 94 +++- .../src/player/skills/ShortBomb.cs | 43 ++ .../src/player/skills/Silent.cs | 15 +- .../src/player/skills/SniperElite.cs | 117 ++++ .../src/player/skills/Soldier.cs | 24 +- .../src/player/skills/SoundMaker.cs | 22 +- .../src/player/skills/Spectator.cs | 153 ++++++ .../src/player/skills/SwapPosition.cs | 18 +- .../src/player/skills/Teleporter.cs | 14 +- .../src/player/skills/Thief.cs | 15 +- .../src/player/skills/ThirdEye.cs | 122 +++++ .../src/player/skills/ToxicSmoke.cs | 157 +++--- .../src/player/skills/Wallhack.cs | 74 +-- .../src/player/skills/Watchmaker.cs | 93 ++++ .../src/player/skills/WeaponsSwap.cs | 27 +- .../src/player/skills/Zeus.cs | 15 +- jRandomSkills - SRC Files/src/utils/Config.cs | 207 ++++---- .../src/utils/SkillUtils.cs | 174 +++++- .../plugins/jRandomSkills/Config.json | 408 -------------- .../plugins/jRandomSkills/jRandomSkills.dll | Bin 150528 -> 340480 bytes .../plugins/jRandomSkills/lang/en.json | 485 +++++++++++++---- .../plugins/jRandomSkills/lang/pl.json | 491 +++++++++++++---- .../plugins/jRandomSkills/lang/pt-br.json | 410 ++++++++++++++ .../plugins/jRandomSkills/lang/zh.json | 410 ++++++++++++++ readme-pl.md | 476 +++++++++++++---- 125 files changed, 9157 insertions(+), 1940 deletions(-) create mode 100644 jRandomSkills - SRC Files/src/icons/jRandomSkills.png create mode 100644 jRandomSkills - SRC Files/src/lang/pt-br.json create mode 100644 jRandomSkills - SRC Files/src/lang/zh.json create mode 100644 jRandomSkills - SRC Files/src/player/skills/Anomaly.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Assassin.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Baseball.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/BladeMaster.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/ChillOut.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Cutter.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Darkness.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Deaf.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Distancer.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/ExplosiveShot.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/FalconEye.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/FastReload.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Fortnite.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/FragileBomb.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/FriendlyFire.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Glaz.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Glue.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/HealingSmoke.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Jackal.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/JumpBan.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/JumpingJack.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/LifeSwap.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/LongKnife.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/LongZeus.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/MoneySwap.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/NoNades.cs rename jRandomSkills - SRC Files/src/player/skills/{TimeManipulator.cs => Noclip.cs} (71%) create mode 100644 jRandomSkills - SRC Files/src/player/skills/Poison.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/PrimaryBan.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/PsychicDefusing.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Push.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Pyro.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/ReZombie.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Regeneration.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Rubber.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/ShortBomb.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/SniperElite.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Spectator.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/ThirdEye.cs create mode 100644 jRandomSkills - SRC Files/src/player/skills/Watchmaker.cs delete mode 100644 jRandomSkills - Server Files/plugins/jRandomSkills/Config.json create mode 100644 jRandomSkills - Server Files/plugins/jRandomSkills/lang/pt-br.json create mode 100644 jRandomSkills - Server Files/plugins/jRandomSkills/lang/zh.json diff --git a/jRandomSkills - SRC Files/jRandomSkills.csproj b/jRandomSkills - SRC Files/jRandomSkills.csproj index 41aa672..b07a38b 100644 --- a/jRandomSkills - SRC Files/jRandomSkills.csproj +++ b/jRandomSkills - SRC Files/jRandomSkills.csproj @@ -12,7 +12,8 @@ - + + diff --git a/jRandomSkills - SRC Files/src/command/Command.cs b/jRandomSkills - SRC Files/src/command/Command.cs index 8c775ee..5dea68f 100644 --- a/jRandomSkills - SRC Files/src/command/Command.cs +++ b/jRandomSkills - SRC Files/src/command/Command.cs @@ -2,9 +2,11 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.utils; -using System; +using System.Runtime.InteropServices; using static jRandomSkills.jRandomSkills; namespace jRandomSkills @@ -20,25 +22,22 @@ namespace jRandomSkills var commands = new Dictionary, (string description, CommandInfo.CommandCallback handler)> { - { SplitCommands(config.Set_Skill), ("Delete record", Command_SetSkill) }, - { SplitCommands(config.SkillsList_Menu), ("Delete all records", Command_SkillsListMenu) }, - { SplitCommands("t, useSkill"), ("Use/Type Skill", Command_UseTypeSkill) } + { SplitCommands(config.SetSkillCommands), ("Delete record", Command_SetSkill) }, + { SplitCommands(config.SkillsListCommands), ("Delete all records", Command_SkillsListMenu) }, + { SplitCommands(config.UseSkillCommands), ("Use/Type skill", Command_UseTypeSkill) }, + { SplitCommands(config.ChangeMapCommands), ("Change map", Command_ChangeMap) }, + { SplitCommands(config.ConsoleCommands), ("Console command", Command_CustomCommand) }, + { SplitCommands(config.StartGameCommands), ("Start game", Command_StartGame) }, + { SplitCommands(config.SwapCommands), ("Swap team", Command_Swap) }, + { SplitCommands(config.ShuffleCommands), ("Shuffle team", Command_Shuffle) }, + { SplitCommands(config.PauseCommands), ("Pause game", Command_Pause) }, + { SplitCommands(config.HealCommands), ("Heal", Command_Heal) }, + { SplitCommands(config.SetScoreCommands), ("Set teams score", Command_SetScore) }, }; foreach (var commandPair in commands) - { foreach (var command in commandPair.Key) - { Instance.AddCommand($"css_{command}", commandPair.Value.description, commandPair.Value.handler); - } - } - - Instance.AddCommand($"css_map", "", Command_ChangeMap); - Instance.AddCommand($"css_console", "", Command_CustomCommand); - Instance.AddCommand($"css_start", "", Command_StartGame); - Instance.AddCommand($"css_swap", "", Command_Swap); - Instance.AddCommand($"css_shuffle", "", Command_Shuffle); - Instance.AddCommand($"css_pause", "", Command_Pause); } private static IEnumerable SplitCommands(string commands) @@ -46,7 +45,7 @@ namespace jRandomSkills return commands.Split(',').Select(c => c.Trim()); } - public static void AddCommands(IEnumerable commands, string description, CommandInfo.CommandCallback commandAction) + private static void AddCommands(IEnumerable commands, string description, CommandInfo.CommandCallback commandAction) { foreach (var command in commands) { @@ -55,7 +54,7 @@ namespace jRandomSkills } [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_ONLY)] - public static void Command_UseTypeSkill(CCSPlayerController? player, CommandInfo _) + private static void Command_UseTypeSkill(CCSPlayerController? player, CommandInfo _) { if (player == null) return; var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); @@ -65,15 +64,16 @@ namespace jRandomSkills if (!player.IsValid || !player.PawnIsAlive) return; string[] commands = _.ArgString.Trim().Split(" ", StringSplitOptions.RemoveEmptyEntries); + Debug.WriteToDebug($"Player {player.PlayerName} used the skill: {playerInfo.Skill}"); if (commands == null || commands.Length == 0) Instance.SkillAction(playerInfo!.Skill.ToString(), "UseSkill", new object[] { player }); else Instance.SkillAction(playerInfo!.Skill.ToString(), "TypeSkill", new object[] { player, commands }); } - [RequiresPermissions("@css/root")] + [RequiresPermissions("@jRandmosSkills/admin")] [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_ONLY)] - public static void Command_SetSkill(CCSPlayerController? player, CommandInfo command) + private static void Command_SetSkill(CCSPlayerController? player, CommandInfo command) { if (player == null) return; @@ -131,15 +131,15 @@ namespace jRandomSkills } [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_ONLY)] - public static void Command_SkillsListMenu(CCSPlayerController? player, CommandInfo command) + private static void Command_SkillsListMenu(CCSPlayerController? player, CommandInfo command) { if (player == null) return; Menu.DisplaySkillsList(player); } - [RequiresPermissions("@css/root")] + [RequiresPermissions("@jRandmosSkills/admin")] [CommandHelper(minArgs: 1, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] - public static void Command_ChangeMap(CCSPlayerController? player, CommandInfo command) + private static void Command_ChangeMap(CCSPlayerController? player, CommandInfo command) { if (player == null) return; string map = command.GetArg(1); @@ -160,9 +160,9 @@ namespace jRandomSkills Server.ExecuteCommand($"changelevel {map}"); } - [RequiresPermissions("@css/root")] + [RequiresPermissions("@jRandmosSkills/admin")] [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] - public static void Command_StartGame(CCSPlayerController? player, CommandInfo command) + private static void Command_StartGame(CCSPlayerController? player, CommandInfo command) { if (player == null) return; int cheats = command.GetArg(1) == "sv" ? 1 : 0; @@ -180,18 +180,18 @@ namespace jRandomSkills }); } - [RequiresPermissions("@css/root")] + [RequiresPermissions("@jRandmosSkills/root")] [CommandHelper(minArgs: 1, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] - public static void Command_CustomCommand(CCSPlayerController? player, CommandInfo command) + private static void Command_CustomCommand(CCSPlayerController? player, CommandInfo command) { if (player == null) return; string param = command.GetArg(1); Server.ExecuteCommand(param); } - [RequiresPermissions("@css/root")] + [RequiresPermissions("@jRandmosSkills/admin")] [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] - public static void Command_Swap(CCSPlayerController? _player, CommandInfo command) + private static void Command_Swap(CCSPlayerController? _player, CommandInfo command) { foreach (var player in Utilities.GetPlayers()) if (Instance.IsPlayerValid(player) && new CsTeam[] { CsTeam.CounterTerrorist, CsTeam.Terrorist }.Contains(player.Team)) @@ -199,9 +199,9 @@ namespace jRandomSkills Server.ExecuteCommand($"mp_restartgame 1"); } - [RequiresPermissions("@css/root")] + [RequiresPermissions("@jRandmosSkills/admin")] [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] - public static void Command_Shuffle(CCSPlayerController? _player, CommandInfo command) + private static void Command_Shuffle(CCSPlayerController? _player, CommandInfo command) { var players = Utilities.GetPlayers().FindAll(p => (Instance.IsPlayerValid(p) && new CsTeam[] { CsTeam.CounterTerrorist, CsTeam.Terrorist }.Contains(p.Team))); double CTlimit = Instance.Random.Next(0, 2) == 0 ? Math.Floor(players.Count / 2.0) : Math.Ceiling(players.Count / 2.0); @@ -214,13 +214,34 @@ namespace jRandomSkills Server.ExecuteCommand($"mp_restartgame 1"); } - [RequiresPermissions("@css/root")] + [RequiresPermissions("@jRandmosSkills/admin")] [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] - public static void Command_Pause(CCSPlayerController? player, CommandInfo command) + private static void Command_Pause(CCSPlayerController? player, CommandInfo command) { Server.PrintToChatAll($" {(gamePaused ? ChatColors.Green : ChatColors.Red)}{Localization.GetTranslation(gamePaused ? "unpause" : "pause")}"); Server.ExecuteCommand( gamePaused ? "mp_unpause_match" : "mp_pause_match"); gamePaused = !gamePaused; } + + [RequiresPermissions("@jRandmosSkills/root")] + [CommandHelper(minArgs: 0, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] + private static void Command_Heal(CCSPlayerController? player, CommandInfo command) + { + SkillUtils.AddHealth(player.PlayerPawn.Value, 100); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("healed")}"); + } + + [RequiresPermissions("@jRandmosSkills/root")] + [CommandHelper(minArgs: 2, whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] + private static void Command_SetScore(CCSPlayerController? player, CommandInfo command) + { + if (!int.TryParse(command.GetArg(1), out int ctScore) || !int.TryParse(command.GetArg(2), out int tScore)) + { + SkillUtils.PrintToChat(player, Localization.GetTranslation("correct_form_setscore"), true); + return; + } + + SkillUtils.SetTeamScores((short)ctScore, (short)tScore, RoundEndReason.RoundDraw); + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/icons/jRandomSkills.png b/jRandomSkills - SRC Files/src/icons/jRandomSkills.png new file mode 100644 index 0000000000000000000000000000000000000000..d23db6a30344981ea5f4cac16b0977bae5c50a21 GIT binary patch literal 40227 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 literal 0 HcmV?d00001 diff --git a/jRandomSkills - SRC Files/src/jRandomSkills.cs b/jRandomSkills - SRC Files/src/jRandomSkills.cs index dd70414..81a6e1e 100644 --- a/jRandomSkills - SRC Files/src/jRandomSkills.cs +++ b/jRandomSkills - SRC Files/src/jRandomSkills.cs @@ -12,13 +12,14 @@ namespace jRandomSkills { public static jRandomSkills Instance { get; private set; } - public List skillPlayer { get; } = new List(); + public List skillPlayer { get; } = new List(); public Random Random { get; } = new Random(); + public CCSGameRules GameRules { get; set; } 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.0.4"; + public override string ModuleVersion => "1.1.0"; public override void Load(bool hotReload) { @@ -26,25 +27,23 @@ namespace jRandomSkills Config.Initialize(); Localization.Load(); - // Debug.Load(); + Debug.Load(); Event.Load(); PlayerOnTick.Load(); Command.Load(); + LoadAllSkills(); + } - - None.LoadSkill(); - // -> Mute.LoadSkill();; - // -> ToxicSmoke.LoadSkill(); - - // Shade.LoadSkill(); - // FrozenDecoy.LoadSkill(); - // Medic.LoadSkill(); - - - return; - + internal void LoadAllSkills() + { foreach (var skill in Enum.GetValues(typeof(Skills))) - SkillAction(skill.ToString(), "LoadSkill"); + if (Config.GetValue(skill, "active")) + SkillAction(skill.ToString()!, "LoadSkill"); + + Debug.WriteToDebug($"jRandomSkills v{Instance.ModuleVersion} ({SkillData.Skills.Count - 1}/{Config.config.SkillsInfo.Length - 1} Skills) loaded!"); + Debug.WriteToDebug($"GameModes: {(Config.GameModes)Config.config.Settings.GameMode}, Lang: {Config.config.Settings.LangCode}"); + foreach (var skill in SkillData.Skills) + Debug.WriteToDebug($"Loaded: {skill.Skill}"); } internal void SkillAction(string skill, string methodName, object[] param = null) @@ -83,11 +82,11 @@ namespace jRandomSkills return player != null && player.IsValid && player.PlayerPawn?.Value != null && player.PlayerPawn.Value.LifeState == (byte)LifeState_t.LIFE_ALIVE; } - public uint[] footstepSoundEvents = { 2026488395, 2745524735, 2684452812, 2265091453, 1269567645, 520432428, 3266483468, 1346129716, 2061955732, 2240518199, 2829617974, 1194677450, 1803111098, 3749333696, 29217150, 1692050905, 2207486967, 2633527058, 3342414459, 988265811, 540697918, 1763490157, 3755338324, 3161194970, 3753692454, 3166948458, 3997353267, 3161194970, 3753692454, 3166948458, 3997353267, 809738584, 3368720745, 3295206520, 3184465677, 123085364, 3123711576, 737696412, 1403457606, 1770765328, 892882552, 3023174225, 4163677892, 3952104171, 4082928848, 1019414932, 1485322532, 1161855519, 1557420499, 1163426340, 809738584, 3368720745, 2708661994, 2479376962, 3295206520, 1404198078, 1194093029, 1253503839, 2189706910, 1218015996, 96240187, 1116700262, 84876002, 1598540856, 2231399653 }; - public uint[] silentSoundEvents = { 117596568, 117596568, 740474905, 1661204257, 3009312615, 1506215040, 115843229, 3299941720, 1016523349, 2684452812, 2067683805, 2067683805, 1016523349, 4160462271, 1543118744, 585390608, 3802757032, 2302139631, 2546391140, 144629619, 4152012084, 4113422219, 1627020521, 2899365092, 819435812, 3218103073, 961838155, 1535891875, 1826799645, 3460445620, 1818046345, 3666896632, 3099536373, 1440734007, 1409986305, 1939055066, 782454593, 4074593561, 1540837791, 3257325156 }; + public uint[] footstepSoundEvents = { 3109879199, 70939233, 1342713723, 2722081556, 1909915699, 3193435079, 2300993891, 3847761506, 4084367249, 1342713723, 3847761506, 2026488395, 2745524735, 2684452812, 2265091453, 1269567645, 520432428, 3266483468, 1346129716, 2061955732, 2240518199, 2829617974, 1194677450, 1803111098, 3749333696, 29217150, 1692050905, 2207486967, 2633527058, 3342414459, 988265811, 540697918, 1763490157, 3755338324, 3161194970, 3753692454, 3166948458, 3997353267, 3161194970, 3753692454, 3166948458, 3997353267, 809738584, 3368720745, 3295206520, 3184465677, 123085364, 3123711576, 737696412, 1403457606, 1770765328, 892882552, 3023174225, 4163677892, 3952104171, 4082928848, 1019414932, 1485322532, 1161855519, 1557420499, 1163426340, 809738584, 3368720745, 2708661994, 2479376962, 3295206520, 1404198078, 1194093029, 1253503839, 2189706910, 1218015996, 96240187, 1116700262, 84876002, 1598540856, 2231399653 }; + public uint[] silentSoundEvents = { 2551626319, 765706800, 765706800, 2860219006, 2162652424, 2551626319, 2162652424, 117596568, 117596568, 740474905, 1661204257, 3009312615, 1506215040, 115843229, 3299941720, 1016523349, 2684452812, 2067683805, 2067683805, 1016523349, 4160462271, 1543118744, 585390608, 3802757032, 2302139631, 2546391140, 144629619, 4152012084, 4113422219, 1627020521, 2899365092, 819435812, 3218103073, 961838155, 1535891875, 1826799645, 3460445620, 1818046345, 3666896632, 3099536373, 1440734007, 1409986305, 1939055066, 782454593, 4074593561, 1540837791, 3257325156 }; } - public class dSkill_PlayerInfo + public class jSkill_PlayerInfo { public required ulong SteamID { get; set; } public required string PlayerName { get; set; } @@ -97,7 +96,7 @@ namespace jRandomSkills public bool IsDrawing { get; set; } } - public class dSkill_SkillInfo + public class jSkill_SkillInfo { public Skills Skill { get; } public string Name { get; } @@ -106,7 +105,7 @@ namespace jRandomSkills public bool Display { get; } - public dSkill_SkillInfo(Skills skill, string color, bool display) + public jSkill_SkillInfo(Skills skill, string color, bool display) { Skill = skill; Name = Localization.GetTranslation(skill.ToString().ToLower()); @@ -114,10 +113,15 @@ namespace jRandomSkills Color = color; Display = display; } + + public static implicit operator Skills(jSkill_SkillInfo v) + { + throw new NotImplementedException(); + } } public static class SkillData { - public static List Skills { get; } = new List(); + public static List Skills { get; } = new List(); } } \ 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 5c08d9e..4f947c2 100644 --- a/jRandomSkills - SRC Files/src/lang/en.json +++ b/jRandomSkills - SRC Files/src/lang/en.json @@ -1,127 +1,410 @@ { - "none_desc": "You have no skills", + "none": "None", + "none_desc": "You have no skill", + + "aimbot": "Aimbot", "aimbot_desc": "Every bullet you hit counts as a headshot", - "antyflash_desc": "You are immune to flashes, and your flashes last 7 seconds", - "astronaut_desc": "You receive a random gravity value at the start of the round", - "astronaut_desc2": "Your random gravity is: {0}x", - "richboy_desc": "You receive a random amount of money at the start of the round", - "bunnyhop_desc": "You get auto \"BunnyHop\"", - "silent_desc": "Your footsteps and jumps are silent to OTHER players", - "shade_desc": "You teleport behind the back of a hit enemy", - "dracula_desc": "Hitting an enemy restores a percentage of the damage dealt as health", - "ghost_desc": "You are completely invisible", - "flash_desc": "Random player speed at the beginning of the round", - "flash_desc2": "Your speed multiplier is {0}x", - "godmode_desc": "You are immortal for 2 seconds. Press [css_useSkill], cooldown 30s", - "godmode_on": "Immortality enabled", - "godmode_off": "Immortality disabled", + + "anomaly": "Anomaly", + "anomaly_desc": "You rewind a few seconds back in time", + + "antyflash": "Anti-Flash", + "antyflash_desc": "You are immune to flashbangs, and your flashbangs last 7 seconds", + + "antyhead": "Iron Head", + "antyhead_desc": "You take no damage from headshots", + + "areareaper": "Zone Reaper", + "areareaper_desc": "You can choose a bomb site to deactivate", + "areareaper_incorrect_site": "No such bomb site found.", + "areareaper_no_site": "No bomb sites found.", + "areareaper_select_info": "Choose the bomb site you want to deactivate:", + "areareaper_site_disabled": "Bomb site {0} has been deactivated - no bombs can be planted there!", + "areareaper_used_info": "Your skill has already been used.", + + "armored": "Armored", "armored_desc": "You have a random damage taken multiplier", "armored_desc2": "Your damage taken multiplier is: {0}x", - "muhammed_desc": "You explode upon death, killing nearby players", - "dwarf_desc": "Random character size at the start of the round", - "dwarf_desc2": "Your size multiplier is {0}x", - "medic_desc": "You receive a random number of medkits at the start of the round", - "randomweapon_desc": "You get a random weapon. Press [css_useSkill], cooldown 15s", - "chicken_desc": "You get a chicken model + 10% faster movement - 50 HP", - "impostor_desc": "You start the round with an enemy player model", + + "assassin": "Assassin", + "assassin_desc": "You deal increased damage to enemies from behind", + + "astronaut": "Astronaut", + "astronaut_desc": "You receive a random gravity value at the start of the round", + "astronaut_desc2": "Your random gravity is: {0}x", + + "baseball": "Baseball Player", + "baseball_desc": "Your decoy bounces off walls and instantly kills an enemy on impact", + + "behind": "Enemy Spin", + "behind_desc": "You have a random chance to turn an enemy 180 degrees when hitting them", + "behind_desc2": "Your chance to turn an enemy on hit is: {0}%", + + "blademaster": "Blademaster", + "blademaster_desc": "While holding a knife, you have a high chance to deflect a shot", + + "bunnyhop": "Bunny", + "bunnyhop_desc": "You get auto \"BunnyHop\"", + + "c4camouflage": "C4 Camouflage", + "c4camouflage_desc": "You are invisible while holding the bomb", + + "catapult": "Catapult", "catapult_desc": "You have a random chance to launch an enemy upwards", "catapult_desc2": "Your chance to launch an enemy on hit is: {0}%", + + "chicken": "Chicken", + "chicken_desc": "You get a chicken model + 10% faster movement - 50 HP", + + "chillout": "Chillout", + "chillout_desc": "Planting the bomb takes significantly longer", + + "cutter": "Cutter", + "cutter_desc": "Instant kill with a knife", + + "darkness": "Darkness", + "darkness_desc": "Applies a darkness effect to a chosen enemy", + "darkness_enemy_info": "Let the lights go out.", + "darkness_player_info": "Darkness has overtaken player '{0}'.", + "darkness_select_info": "Choose the player you want to apply the darkness effect to:", + + "deactivator": "Deactivator", + "deactivator_desc": "Choose a player whose skill you want to disable", + "deactivator_enemy_info": "Your skill has been disabled.", + "deactivator_player_info": "Player '{0}'s skill has been disabled.", + "deactivator_select_info": "Choose the player whose skill you want to disable:", + + "deaf": "Deaf", + "deaf_desc": "Choose a player to mute all sounds for", + "deaf_enemy_info": "Your headphones have left the game.", + "deaf_player_info": "Sound has been disabled for player '{0}'.", + "deaf_select_info": "Choose the player for whom you want to mute all sounds:", + + "disarmament": "Disarmament", + "disarmament_desc": "You have a random chance to make an enemy drop their weapon on hit", + "disarmament_desc2": "Your chance to disarm an enemy is: {0}%", + + "distancer": "Rangefinder", + "distancer_desc": "You can see the distance to the nearest enemy", + + "dracula": "Dracula", + "dracula_desc": "Hitting an enemy restores health equal to a percentage of the damage dealt", + + "duplicator": "Duplicator", + "duplicator_desc": "Choose a player to copy their skill", + "duplicator_player_info": "Player '{0}'s skill has been copied.", + "duplicator_select_info": "Choose the player whose skill you want to copy:", + + "dwarf": "Dwarf", + "dwarf_desc": "Random character size at the start of the round", + "dwarf_desc2": "Your size multiplier is: {0}x", + + "enemyspawn": "Enemy Spawn", + "enemyspawn_desc": "Click [css_useSkill] to teleport to the enemy spawn", + + "explosiveshot": "Explosive Shot", + "explosiveshot_desc": "Random chance to fire an explosive bullet while shooting", + "explosiveshot_desc2": "Your chance to fire an explosive bullet: {0}%", + + "falconeye": "Falcon Eye", + "falconeye_desc": "Click [css_useSkill] to activate a bird's-eye view camera", + + "fastreload": "Fastreload", + "fastreload_desc": "Click [css_useSkill] to reload the weapon you are currently holding", + + "flash": "Flash", + "flash_desc": "Random player speed at the beginning of the round", + "flash_desc2": "Your speed multiplier is: {0}x", + + "fortnite": "Fortnite", + "fortnite_desc": "Click [css_useSkill] to create a destructible barricade", + + "fragilebomb": "Fragile Bomb", + "fragilebomb_desc": "Shooting the bomb damages it", + "fragilebomb_bomb_health": "Bomb health", + + "friendlyfire": "Friendly Fire", + "friendlyfire_desc": "Shooting teammates heals them", + + "frozendecoy": "Freezing Decoy", + "frozendecoy_desc": "Your decoy freezes all nearby players", + + "ghost": "Ghost", + "ghost_desc": "You are completely invisible", + + "glaz": "Glaz", + "glaz_desc": "You can see through smoke grenades", + + "glitch": "Glitch", + "glitch_desc": "Disables the radar for a chosen enemy", + "glitch_enemy_info": "Your radar has been disabled.", + "glitch_player_info": "Player '{0}'s radar has been disabled.", + "glitch_select_info": "Choose the player whose radar you want to disable:", + + "glue": "Glue", + "glue_desc": "Your grenades stick to walls", + + "godmode": "God Mode", + "godmode_desc": "Click [css_useSkill] to become immortal for a short time", + "godmode_off": "Immortality disabled", + "godmode_on": "Immortality enabled", + + "healingsmoke": "Healing Smoke", + "healingsmoke_desc": "Your smoke grenades heal", + + "hermit": "Hermit", + "hermit_desc": "Killing restores ammo and a portion of health", + + "holyhandgrenade": "Holy Hand Grenade", + "holyhandgrenade_desc": "Your HE grenades deal double damage and have double range", + + "impostor": "Impostor", + "impostor_desc": "You start the round with an enemy player model", + + "infiniteammo": "Infinite Ammo", "infiniteammo_desc": "You receive infinite ammo for all your weapons", - "behind_desc": "You have a random chance to turn an enemy 180 degrees on hit", - "behind_desc2": "Your chance to turn an enemy on hit is: {0}%", - "retreat_desc": "Return to spawn. Press [css_useSkill], cooldown 15s", + + "jackal": "Tracker", + "jackal_desc": "Choose a player who will leave a trail behind them", + "jackal_player_info": "Player '{0}' will start leaving a trail.", + "jackal_select_info": "Choose the player who will leave a trail:", + + "jammer": "Jammer", + "jammer_desc": "Choose a player to disable their crosshair", + "jammer_enemy_info": "Your crosshair has been disabled.", + "jammer_player_info": "Player '{0}'s crosshair has been disabled.", + "jammer_select_info": "Choose the player whose crosshair you want to disable:", + + "jumpban": "Legless", + "jumpban_desc": "Choose a player who cannot jump", + "jumpban_enemy_info": "Someone cut off your legs.", + "jumpban_player_info": "Player '{0}' can no longer jump.", + "jumpban_select_info": "Choose the player who cannot jump:", + + "jumpingjack": "Jumping Jack", + "jumpingjack_desc": "Jumping restores health", + + "killerflash": "Killer Flash", + "killerflash_desc": "Anyone fully blinded by your flashbang dies (including you)", + + "lifeswap": "Life Swap", + "lifeswap_desc": "Choose a player to swap health with", + "lifeswap_enemy_info": "Someone borrowed your health.", + "lifeswap_player_info": "You swapped health with player '{0}'.", + "lifeswap_select_info": "Choose the player to swap health with:", + + "longknife": "Long Knife", + "longknife_desc": "A primary knife attack deals damage regardless of distance", + + "longzeus": "Long Zeus", + "longzeus_desc": "Zeus deals damage regardless of distance", + + "medic": "Medic", + "medic_desc": "Click [css_useSkill] to use a healing charge that restores 50 health", + + "moneyswap": "Taxman", + "moneyswap_desc": "Choose a player to swap money with", + "moneyswap_enemy_info": "The tax office got you.", + "moneyswap_player_info": "You swapped money with player '{0}'.", + "moneyswap_select_info": "Choose the player to swap money with:", + + "muhammed": "Muhammed", + "muhammed_desc": "You explode upon death, killing nearby players", + + "ninja": "Ninja", + "ninja_desc": "Standing still increases your invisibility by 33%, crouching by 33%, and holding a knife by 33%", + + "nonades": "No-Nades", + "nonades_desc": "Grenades deal no damage to you", + + "norecoil": "Focus", + "norecoil_desc": "No recoil while shooting", + + "noclip": "NoClip", + "noclip_desc": "Click [css_useSkill] to enable noclip for a short time", + + "oneshot": "One-Shot", "oneshot_desc": "Hitting an enemy instantly kills them", + + "onlyhead": "Head Only", + "onlyhead_desc": "You only take damage to the head", + + "paweljumper": "Pawel Jumper", "paweljumper_desc": "You get an extra jump", + + "phoenix": "Phoenix", "phoenix_desc": "You have a random chance to respawn after death", "phoenix_desc2": "Your chance to respawn after death: {0}%", "phoenix_respawn": "You have been resurrected from the ashes thanks to the power of: CHATCOLORS.REDPhoenix", + + "psychicdefusing": "Psychic Defusing", + "psychicdefusing_desc": "When you are near the bomb, you start defusing it", + "psychicdefusing_hud_info": "{0} seconds remaining to defuse", + + "pilot": "Pilot", "pilot_desc": "Fly for a limited time. Hold [USE - E] to fly", "pilot_hud_info": "Recharging", - "radarhack_desc": "You can see enemies on the radar", + + "planter": "Free Planter", + "planter_desc": "You can plant the bomb anywhere, with a detonation time of 60 seconds.", + + "poison": "Poison", + "poison_desc": "Choose a player who will take damage every few seconds", + "poison_enemy_info": "You have been poisoned.", + "poison_player_info": "Player '{0}' has been poisoned.", + "poison_select_info": "Choose the player who will take damage every few seconds:", + + "primaryban": "No Rifles", + "primaryban_desc": "Choose a player who cannot use rifles", + "primaryban_enemy_info": "You can no longer use rifles.", + "primaryban_player_info": "Player '{0}' can no longer use rifles.", + "primaryban_select_info": "Choose the player to ban from using rifles:", + + "prosthesis": "Prosthesis", + "prosthesis_desc": "Arms and legs are bulletproof", + + "push": "Pusher", + "push_desc": "You have a random chance to push an enemy back when hitting them", + "push_desc2": "Your chances of pushing back the enemy are: {0}%", + + "pyro": "Pyro", + "pyro_desc": "Molotov restores health", + + "quickshot": "Rapid Fire", + "quickshot_desc": "All bullets are fired very quickly", + + "radarhack": "Radar Hack", + "radarhack_desc": "Enemies are visible on the radar", + + "rambo": "Rambo", "rambo_desc": "You receive a random amount of health at the start of the round", - "enemyspawn_desc": "Teleport to enemy spawn. Press [css_useSkill], cooldown 15s", - "disarmament_desc": "You have a random chance to make an enemy drop their weapon on hit", - "disarmament_desc2": "Your chance to disarm an enemy is: {0}%", - "planter_desc": "You can plant the bomb anywhere; bomb detonation time is 60s", + + "randomweapon": "Random Weapon", + "randomweapon_desc": "Click [css_useSkill] to receive a random weapon", + + "rezombie": "Re-Zombie", + "rezombie_desc": "After death, you respawn as a zombie with increased health and no weapons", + + "reactivearmor": "Reactive Armor", + "reactivearmor_desc": "Armor absorbs the first damage taken", + + "regeneration": "Regeneration", + "regeneration_desc": "You restore health every few seconds", + + "replicator": "Replicator", + "replicator_desc": "Click [css_useSkill] to create a replica that deals damage on hit", + + "retreat": "Retreat", + "retreat_desc": "Click [css_useSkill] to return to spawn", + + "returntosender": "Return to Sender", + "returntosender_desc": "The first hit on an enemy sends them back to their spawn", + + "richboy": "Rich Boy", + "richboy_desc": "You receive a random amount of money at the start of the round", + + "robinhood": "Robin Hood", + "robinhood_desc": "Dealing damage to an enemy steals their money", + + "rubber": "Rubber Bullets", + "rubber_desc": "Your bullets significantly slow down players", + + "saper": "Sapper", "saper_desc": "You can plant and defuse bombs faster", - "timemanipulator_desc": "Slows down time for everyone for 6 seconds. Press [css_useSkill], cooldown 30s", - "quickshot_desc": "No cooldown when shooting", - "teleporter_desc": "You swap places with the hit enemy", - "wallhack_desc": "You can see enemies through walls", - "killerflash_desc": "Every enemy fully blinded by your flashbang dies (including you)", - "weaponsswap_desc": "Swap weapons with a random enemy. Press [css_useSkill], cooldown 30s", - "weaponsswap_hud_info2": "You have no weapon to swap", - "hud_info_no_enemy": "No enemy found", - "zeus_desc": "Zeus x27 instantly recharges", - "frozendecoy_desc": "Your decoy grenade freezes all nearby players", - "antyhead_desc": "You receive no headshot damage", + + "secondlife": "Second Chance", + "secondlife_desc": "After death, you respawn with the same amount of health", + + "shade": "Shade", + "shade_desc": "You teleport behind the back of a hit enemy", + "shade_nospace": "No space available", + + "shortbomb": "Short Fuse", + "shortbomb_desc": "The bomb explodes much faster", + + "silent": "Silent", + "silent_desc": "Your footsteps and jumps are silent to OTHER players", + + "sniperelite": "Sniper Elite", + "sniperelite_desc": "Click [css_useSkill] to swap your current weapon for an AWP", + + "soldier": "Soldier", "soldier_desc": "You have a random damage multiplier", "soldier_desc2": "Your damage multiplier is: {0}x", - "swapposition_desc": "Swap places with a random enemy. Press [css_useSkill], cooldown 30s", - "welcome_message": "Welcome {PLAYER} to {SERVER_NAME}!\nCurrent jRandomSkills version: {VERSION} ({SKILLS_COUNT} skills).\n\nOriginally created by:\n{AUTHOR1}\nModified and improved by:\n{AUTHOR2}", - "hud_info": "Wait {0} seconds", - "no_player": "No player found.", - "duplicate_player": "More than one player found with the same name.", - "drawing_skill": "Drawing a skill", + "soundmaker": "Soundmaker", + "soundmaker_desc": "Click [css_useSkill] to trigger a sound for every enemy", + + "spectator": "Spectator", + "spectator_desc": "Click [css_useSkill] to spectate a random enemy", + + "swapposition": "Position Swap", + "swapposition_desc": "Click [css_useSkill] to swap places with a random enemy", + + "teleporter": "Teleporter", + "teleporter_desc": "You swap places with the hit enemy", + + "thief": "Thief", + "thief_desc": "You can steal a skill from a chosen player", + "thief_enemy_info": "Your skill has been stolen.", + "thief_player_info": "Player '{0}'s skill has been stolen.", + "thief_select_info": "Choose the player whose skill you want to steal:", + + "thirdeye": "Third Eye", + "thirdeye_desc": "Click [css_useSkill] to activate third-person view", + + "toxicsmoke": "Toxic Smoke", + "toxicsmoke_desc": "Your smoke grenades deal damage", + + "wallhack": "Wallhack", + "wallhack_desc": "You can see enemies through walls", + + "watchmaker": "Watchmaker", + "watchmaker_desc": "Every grenade throw alters the round time", + "watchmaker_ct": "Round time shortened by {0} seconds.", + "watchmaker_tt": "Round time extended by {0} seconds.", + + "weaponsswap": "Weapon Swap", + "weaponsswap_desc": "Click [css_useSkill] to swap weapons with a random enemy", + "weaponsswap_hud_info2": "You have no weapon to swap", + + "zeus": "Zeus", + "zeus_desc": "Zeus x27 instantly recharges", + "your_skill": "Your current skill", - "summary_start": "======SUMMARY=OF=THE=LAST=ROUND======", - "summary_end": "=======================================", "enemy_skill": "Enemy's skill", - "teammate_skills": "Your teammates' skills", - "observer_skill": "Player's power", - "game_start": "Game started!", - "invalid_map": "Invalid map name!", - "loading_map": "Loading a new map", - "skills_menu": "Skill List", + "observer_skill": "Player's skill", + "welcome_message": "Welcome {PLAYER} to {SERVER_NAME}!\nCurrent jRandomSkills version: {VERSION} ({SKILLS_COUNT} skills).\n\nOriginally created by:\n{AUTHOR1}\nModified and improved by:\n{AUTHOR2}\nOfficial Discord: https://discord.gg/72nzFguNtd", + "drawing_skill": "Drawing a skill", + "disabled_weapon": "You cannot use this weapon", + + "hud_info": "Wait another {0} seconds", + "hud_info_no_enemy": "No enemy found", + "active_hud_info": "Active for another {0} milliseconds", + + "skills_menu": "skill List", + "no_player": "No matching player found.", + "duplicate_player": "More than one player found with the same name.", + "selectplayerskill_command": "Type /t", + "selectplayerskill_incorrect_enemy_index": "No player found with that index.", + + "skill_not_found_setskill": "No such CHATCOLORS.REDskill found", + "player_not_found_setskill": "No such CHATCOLORS.REDplayer found", "correct_form_setskill": "Correct usage: CHATCOLORS.RED!setskill ", - "skill_not_found_setskill": "Skill CHATCOLORS.REDnot found", + "correct_form_setskill": "Correct usage: CHATCOLORS.RED!setscore ", + "done_setskill": "skill set", "error_setskill": "Failed to set CHATCOLORS.REDskill", - "done_setskill": "Skill set", "for_setskill": "for", - "none": "None", - "dwarf": "Dwarf", - "swapposition": "Swapper", - "killerflash": "Deadly Flash", - "soldier": "Soldier", - "armored": "Tank", - "aimbot": "Aimbot", - "retreat": "Retreat", - "enemyspawn": "Enemy Spawn", - "zeus": "Zeus", - "radarhack": "Radar Hack", - "quickshot": "Quick-Shot", - "planter": "Planter", - "silent": "Silent", - "frozendecoy": "Freezing Decoy", - "timemanipulator": "Time Slow", - "godmode": "God Mode", - "randomweapon": "Random Weapon", - "weaponsswap": "Weapon Swap", - "wallhack": "Wallhack", - "flash": "Flash", - "paweljumper": "Paweł Jumper", - "bunnyhop": "Bunnyhop", - "impostor": "Spy", - "oneshot": "One-Shot", - "muhammed": "Muhammed", - "richboy": "Rich Boy", - "rambo": "Rambo", - "medic": "Medic", - "ghost": "Ghost", - "chicken": "Chicken", - "astronaut": "Astronaut", - "disarmament": "Disarmament", - "antyflash": "Anti-Flash", - "behind": "Enemy Rotation", - "infiniteammo": "Infinite Ammo", - "catapult": "Catapult", - "dracula": "Dracula", - "teleporter": "Teleporter", - "saper": "Sapper", - "phoenix": "Phoenix", - "pilot": "Pilot", - "shade": "Shade", - "antyhead": "Anty Head" + "invalid_map": "Map name entered incorrectly!", + "loading_map": "Loading a new map", + + "pause": "Match has been paused.", + "unpause": "Match has been resumed.", + "healed": "You have been healed.", + "game_start": "Game started!", + + "teammate_skills": "Your teammates' skills", + "summary_start": "======SUMMARY=OF=THE=LAST=ROUND======", + "summary_end": "=======================================" } \ 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 20578ec..6efaa23 100644 --- a/jRandomSkills - SRC Files/src/lang/pl.json +++ b/jRandomSkills - SRC Files/src/lang/pl.json @@ -3,215 +3,408 @@ "none_desc": "Nie posiadasz żadnej supermocy", "aimbot": "Aimbot", - "aimbot_desc": "Każdy twój trafiony pocisk jest liczony jako głowa", + "aimbot_desc": "Każdy twój trafiony pocisk liczy się jako strzał w głowę", + + "anomaly": "Anomalia", + "anomaly_desc": "Cofasz się o kilka sekund do tyłu", "antyflash": "Anty Flash", - "antyflash_desc": "Posiadasz odporność na flashe i 7 sekund trwają twoje flash'e", + "antyflash_desc": "Posiadasz odporność na flash'e, a twoje flash'e trwają 7 sekund", - "astronaut": "Astronauta", - "astronaut_desc": "Otrzymujesz losową ilość grawitacji na start rundy", - "astronaut_desc2": "Twoja losowa grawitacja wynosi: {0}x", + "antyhead": "Żelazna Głowa", + "antyhead_desc": "Nie otrzymujesz obrażeń w głowę", - "richboy": "Bogacz", - "richboy_desc": "Otrzymujesz losową ilość kasy na start rundy", - - "bunnyhop": "Królik", - "bunnyhop_desc": "Otrzymujesz auto \"BunnyHopa\"", - - "silent": "Cichociemny", - "silent_desc": "Twoje kroki i skoki są niesłyszalne dla INNYCH graczy", - - "shade": "Cień", - "shade_desc": "Teleportujesz się za plecy trafionego wroga", - - "dracula": "Drakula", - "dracula_desc": "Po trafieniu ofiary otrzymujesz zwrot zdrowia w postaci danego procentu zadanych obrażeń", - - "ghost": "Duszek", - "ghost_desc": "Jesteś całkowicie niewidzialny", - - "flash": "Flash", - "flash_desc": "Losowa prędkośc postaci na początku rundy", - "flash_desc2": "Twój mnożnik prędkości to {0}x", - - "godmode": "Nieśmiertelność", - "godmode_desc": "Jesteś nieśmiertelny przez 2 sekundy. Kliknij [css_useSkill], cooldown 30s", - "godmode_on": "Nieśmiertelność włączona", - "godmode_off": "Nieśmiertelność wyłączona", + "areareaper": "Niszczyciel Stref", + "areareaper_desc": "Możesz wybrać strefę detonacji, którą chcesz dezaktywować", + "areareaper_incorrect_site": "Nie znaleziono takiej strefy detonacji.", + "areareaper_no_site": "Nie znaleziono żadnej strefy detonacji.", + "areareaper_select_info": "Wybierz strefę detonacji, którą chcesz dezaktywować:", + "areareaper_site_disabled": "Strefa detonacji {0} została dezaktywowana - nie można na niej podłożyć bomby!", + "areareaper_used_info": "Twoja moc została już wykorzystana.", "armored": "Gruby", "armored_desc": "Masz losowy mnożnik otrzymywanych obrażeń", "armored_desc2": "Twój mnożnik otrzymywanych obrażeń wynosi: {0}x", - "muhammed": "Muhammed", - "muhammed_desc": "Po śmierci wybucha i zabija graczy w obrębie", + "assassin": "Skrytobójca", + "assassin_desc": "Zadajesz większe obrażenia przeciwnikowi od tyłu", - "dwarf": "MiniMajk", - "dwarf_desc": "Losowa wielkość postaci na początku rundy", - "dwarf_desc2": "Twój mnożnik wielkości to {0}x", + "astronaut": "Astronauta", + "astronaut_desc": "Na początku rundy otrzymujesz losową wartość grawitacji", + "astronaut_desc2": "Twoja losowa grawitacja wynosi: {0}x", - "medic": "Medyk", - "medic_desc": "Otrzymujesz losową ilość apteczek na start rundy", + "baseball": "Bejsbolista", + "baseball_desc": "Twój wabik odbija się od ścian i natychmiastowo zabija wroga po trafieniu", - "randomweapon": "Losowa Broń", - "randomweapon_desc": "Dostajesz losową broń. Kliknij [css_useSkill], cooldown 15s", + "behind": "Obrót Wroga", + "behind_desc": "Masz losową szansę na obrócenie wroga o 180 stopni po trafieniu go", + "behind_desc2": "Twoje szanse na obrócenie wroga po trafieniu to: {0}%", - "chicken": "Kurczak", - "chicken_desc": "Otrzymujesz model kurczaka + jesteś o 10% szybszy - 50hp", + "blademaster": "Mistrz Ostrza", + "blademaster_desc": "Trzymając nóż, masz duże szanse na odparcie strzału", - "impostor": "Szpieg", - "impostor_desc": "Otrzymujesz na start rundy model postaci wroga", + "bunnyhop": "Królik", + "bunnyhop_desc": "Otrzymujesz auto \"BunnyHopa\"", + + "c4camouflage": "C4 Kamuflaż", + "c4camouflage_desc": "Kiedy trzymasz bombę, jesteś niewidzialny", "catapult": "Katapulta", "catapult_desc": "Masz losową szanse na podrzucenie wroga", "catapult_desc2": "Twoje szanse na podrzucenie wroga po trafieniu to: {0}%", - "infiniteammo": "Nieskończone Ammo", - "infiniteammo_desc": "Otrzymujesz nieskończoną ilość ammo do wszystkich swoich broni", + "chicken": "Kurczak", + "chicken_desc": "Otrzymujesz model kurczaka + jesteś o 10% szybszy - 50hp", - "behind": "Obrót Wroga", - "behind_desc": "Masz losową szanse na obrócenie wroga o 180 stopni po trafieniu", - "behind_desc2": "Twoje szanse na obrócenie wroga po trafieniu to: {0}%", + "chillout": "Wyluzowany", + "chillout_desc": "Podłożenie bomby zajmuje znacznie więcej czasu", - "retreat": "Odwrót", - "retreat_desc": "Powrót na spawna. Kliknij [css_useSkill], cooldown 15s", + "cutter": "Scyzoryk", + "cutter_desc": "Natychmiastowe zabójstwo nożem", - "oneshot": "Jednostrzałowiec", - "oneshot_desc": "Po trafieniu od razu zabija przeciwnika", + "darkness": "Mrok", + "darkness_desc": "Nadaje efekt ciemności wybranemu przeciwnikowi", + "darkness_enemy_info": "Niech zgasną światła.", + "darkness_player_info": "Ciemność opanowała gracza '{0}'.", + "darkness_select_info": "Wybierz gracza, któremu chcesz nadać efekt ciemności:", - "paweljumper": "Pawel Jumper", - "paweljumper_desc": "Otrzymujesz dodatkowy skok", + "deactivator": "Deaktywator", + "deactivator_desc": "Wybierasz gracza, którego supermoc chcesz wyłączyć", + "deactivator_enemy_info": "Twoja supermoc została wyłączona.", + "deactivator_player_info": "Moc gracza '{0}' została wyłączona.", + "deactivator_select_info": "Wybierz gracza, którego supermoc chcesz wyłączyć:", - "phoenix": "Phoenix", - "phoenix_desc": "Masz losową szans na odrodzenie się po śmierci", - "phoenix_desc2": "Twoje szanse na odrodzenie się po śmierci: {0}%", - "phoenix_respawn": "Zostałeś odrodzony z popiołów dzięki mocy: CHATCOLORS.REDPhoenix", - - "pilot": "Pilot", - "pilot_desc": "Latanie przez określony czas. Przytrzymaj [USE - E], aby latać", - "pilot_hud_info": "W trakcie odnawiania", - - "radarhack": "Radarowiec", - "radarhack_desc": "Widzisz wrogów na radarze", - - "rambo": "Rambo", - "rambo_desc": "Otrzymujesz losową ilość zdrowia na start rundy", - - "enemyspawn": "Resp Wroga", - "enemyspawn_desc": "Teleportacja na spawn wroga. Kliknij [css_useSkill], cooldown 15s", + "deaf": "Głuchy", + "deaf_desc": "Wybierasz gracza, dla którego chcesz wyłączyć wszystkie dźwięki", + "deaf_enemy_info": "Słuchawki opuściły grę.", + "deaf_player_info": "Dźwięk został wyłączony dla gracza '{0}'.", + "deaf_select_info": "Wybierz gracza, dla którego chcesz wyłączyć wszystkie dźwięki:", "disarmament": "Rozbrojenie", "disarmament_desc": "Masz losową szanse na wyrzucenie broni wroga po trafieniu", "disarmament_desc2": "Twoje szanse na wyrzucenie broni wroga to: {0}%", - "planter": "Samowolka", - "planter_desc": "Możesz podłożyć bombę w dowolnym miejscu, czas detonacji bomby trwa 60s", + "distancer": "Odległościomierz", + "distancer_desc": "Możesz zobaczyć odległość do najbliższego przeciwnika", - "saper": "Saper", - "saper_desc": "Możesz szybciej podłożyć bombę oraz ją zdefować", + "dracula": "Drakula", + "dracula_desc": "Po trafieniu ofiary odzyskujesz zdrowie równe pewnemu procentowi zadanych obrażeń", - "timemanipulator": "Spowlnienie Czasu", - "timemanipulator_desc": "Spowolnienie czasu dla wszystkich na 6 sekundy. Kliknij [css_useSkill], cooldown 30s", + "duplicator": "Duplikator", + "duplicator_desc": "Wybierasz gracza, od którego chcesz skopiować supermoc", + "duplicator_player_info": "Moc gracza '{0}' została skopiowana.", + "duplicator_select_info": "Wybierz gracza, od którego chcesz skopiować supermoc:", - "quickshot": "Szybkostrzelność", - "quickshot_desc": "Brak cooldown przy strzelaniu", + "dwarf": "Mini Majk", + "dwarf_desc": "Losowa wielkość postaci na początku rundy", + "dwarf_desc2": "Twój mnożnik wielkości to {0}x", - "teleporter": "Teleporter", - "teleporter_desc": "Zamieniasz się miejscami z trafionym wrogiem", + "enemyspawn": "Resp Wroga", + "enemyspawn_desc": "Kliknij [css_useSkill], aby teleportować się na resp wroga", - "wallhack": "Wallhack", - "wallhack_desc": "Widzisz wrogów przez ściany", + "explosiveshot": "Strzał Wybuchowy", + "explosiveshot_desc": "Losowa szansa wystrzelenia pocisku wybuchowego podczas strzelania", + "explosiveshot_desc2": "Twoja szansa na wystrzelenie pocisku wybuchowego: {0}%", + + "falconeye": "Oko Sokoła", + "falconeye_desc": "Kliknij [css_useSkill], aby aktywować kamerę z lotu ptaka", + + "fastreload": "Szybkie Rączki", + "fastreload_desc": "Kliknij [css_useSkill], aby przeładować broń, którą obecnie trzymasz", + + "flash": "Flash", + "flash_desc": "Losowa prędkośc postaci na początku rundy", + "flash_desc2": "Twój mnożnik prędkości to {0}x", + + "fortnite": "Fortnite", + "fortnite_desc": "Kliknij [css_useSkill], aby stworzyć barykadę, którą można zniszczyć", + + "fragilebomb": "Krucha Bomba", + "fragilebomb_desc": "Strzelanie do bomby powoduje jej uszkodzenie", + "fragilebomb_bomb_health": "Zdrowie bomby", + + "friendlyfire": "Ogień Przyjacielski", + "friendlyfire_desc": "Strzelanie do członków drużyny leczy ich", + + "frozendecoy": "Zamrażający Wabik", + "frozendecoy_desc": "Twój decoy zamraża wszystkich graczy w pobliżu", + + "ghost": "Duszek", + "ghost_desc": "Jesteś całkowicie niewidzialny", + + "glaz": "Glaz", + "glaz_desc": "Nie widzisz granatów dymnych", + + "glitch": "Glitch", + "glitch_desc": "Wyłączasz radar wybranemu przeciwnikowi", + "glitch_enemy_info": "Twój radar został wyłączony.", + "glitch_player_info": "Radar gracza '{0}' został wyłączony.", + "glitch_select_info": "Wybierz gracza, dla którego chcesz wyłączyć radar:", + + "glue": "Klej", + "glue_desc": "Twoje granaty przyklejają się do ścian", + + "godmode": "Nieśmiertelność", + "godmode_desc": "Kliknij [css_useSkill], aby stać się nieśmiertelnym na krótką chwilę", + "godmode_off": "Nieśmiertelność wyłączona", + "godmode_on": "Nieśmiertelność włączona", + + "healingsmoke": "Leczący Dym", + "healingsmoke_desc": "Twoje granaty dymne leczą", + + "hermit": "Pustelnik", + "hermit_desc": "Zabijanie przywraca amunicję i część zdrowia", + + "holyhandgrenade": "Święty Granat Ręczny", + "holyhandgrenade_desc": "Twoje granaty uderzeniowe zadają podwójne obrażenia i mają podwójny zasięg", + + "impostor": "Szpieg", + "impostor_desc": "Na początku rundy otrzymujesz model postaci przeciwnika", + + "infiniteammo": "Nieskończone Ammo", + "infiniteammo_desc": "Otrzymujesz nieskończoną ilość amunicji do wszystkich broni", + + "jackal": "Stópkarz", + "jackal_desc": "Wybierasz gracza, który pozostawi za sobą ślad", + "jackal_player_info": "Gracz '{0}' zacznie zostawiać za sobą ślad.", + "jackal_select_info": "Wybierz gracza, który pozostawi za sobą ślad:", + + "jammer": "Zakłócacz", + "jammer_desc": "Wybierasz gracza, dla którego chcesz wyłączyć celownik", + "jammer_enemy_info": "Twój celownik został wyłączony.", + "jammer_player_info": "Celownik gracza '{0}' została wyłączona.", + "jammer_select_info": "Wybierz gracza, dla którego chcesz wyłączyć celownik:", + + "jumpban": "Beznogi", + "jumpban_desc": "Wybierasz gracza, który nie będzie mógł skakać", + "jumpban_enemy_info": "Ktoś odciął ci nogi.", + "jumpban_player_info": "Gracz '{0}' nie może teraz skakać.", + "jumpban_select_info": "Wybierz gracza, który nie będzie mógł skakać:", + + "jumpingjack": "Pajacyk", + "jumpingjack_desc": "Skakanie przywraca zdrowie", "killerflash": "Zabójczy Flash", "killerflash_desc": "Każdy całkowicie oślepiony twoim granatem umiera (również ty)", - "weaponsswap": "Zamiana Broni", - "weaponsswap_desc": "Zamieniasz się bronią z losowym wrogiem. Kliknij [css_useSkill], cooldown 30s", - "weaponsswap_hud_info2": "Nie posiadasz broni na zamiane", - "hud_info_no_enemy": "Nie znaleziono przeciwnika", + "lifeswap": "Zamiana Żyć", + "lifeswap_desc": "Wybierasz gracza, z którym chcesz wymienić się zdrowiem", + "lifeswap_enemy_info": "Ktoś pożyczył sobie twoje zdrowie.", + "lifeswap_player_info": "Wymieniłeś się zdrowiem z graczem '{0}'.", + "lifeswap_select_info": "Wybierz gracza, z którym chcesz wymienić się zdrowiem:", - "zeus": "Zeus", - "zeus_desc": "Zeus x27 natychmiastowo się odnawia", + "longknife": "Długi Nóż", + "longknife_desc": "Podstawowy atak nożem zadaje obrażenia niezależnie od odległości", - "frozendecoy": "Zamrażający Decoy", - "frozendecoy_desc": "Twój decoy zamraża wszystkich pobliskich graczy", + "longzeus": "Długi Zeus", + "longzeus_desc": "Zeus zadaje obrażenia niezależnie od odległości", - "antyhead": "Żelazna Głowa", - "antyhead_desc": "Nie otrzymujesz obrażeń w głowę", + "medic": "Medyk", + "medic_desc": "Kliknij [css_useSkill], aby użyć ładunku leczniczego, który przywraca 50 punktów zdrowia", + + "moneyswap": "Skarbówka", + "moneyswap_desc": "Wybierasz gracza, z którym chcesz zamienić się pieniędzmi", + "moneyswap_enemy_info": "Urząd skarbowy cię dopadł.", + "moneyswap_player_info": "Wymieniłeś swoje pieniądze z graczem '{0}'.", + "moneyswap_select_info": "Wybierz gracza, z którym chcesz zamienić się pieniędzmi:", + + "muhammed": "Muhammed", + "muhammed_desc": "Po śmierci eksplodujesz i zabijasz graczy znajdujących się w zasięgu", + + "ninja": "Ninja", + "ninja_desc": "Stojąc nieruchomo zwiększasz swoją niewidzialność o 33%, kucając o 33%, a trzymając nóż o 33%", + + "nonades": "Pancernik", + "nonades_desc": "Granaty nie zadają Ci obrażeń", + + "norecoil": "Skupienie", + "norecoil_desc": "Brak odrzutu podczas strzelania", + + "noclip": "NoClip", + "noclip_desc": "Kliknij [css_useSkill], aby włączyć noclip na krótki czas", + + "oneshot": "Jednostrzałowiec", + "oneshot_desc": "Po trafieniu natychmiast zabijasz przeciwnika", + + "onlyhead": "Tylko Głowa", + "onlyhead_desc": "Otrzymujesz obrażenia tylko w głowę", + + "paweljumper": "Pawel Jumper", + "paweljumper_desc": "Otrzymujesz dodatkowy skok", + + "phoenix": "Feniks", + "phoenix_desc": "Masz losową szans na odrodzenie się po śmierci", + "phoenix_desc2": "Twoje szanse na odrodzenie się po śmierci: {0}%", + "phoenix_respawn": "Zostałeś odrodzony z popiołów dzięki mocy: CHATCOLORS.REDPhoenix", + + "psychicdefusing": "Zdalne Rozbrajanie", + "psychicdefusing_desc": "Kiedy jesteś blisko bomby, zaczynasz ją rozbrajać", + "psychicdefusing_hud_info": "Pozostało {0} sekund do rozbrojenia", + + "pilot": "Pilot", + "pilot_desc": "Latanie przez określony czas. Przytrzymaj [USE - E], aby latać", + "pilot_hud_info": "W trakcie odnawiania", + + "planter": "Samowolka", + "planter_desc": "Bombę można podłożyć w dowolnym miejscu, a czas detonacji wynosi 60 sekund.", + + "poison": "Trutka", + "poison_desc": "Wybierasz gracza, który co kilka sekund będzie otrzymywał obrażenia", + "poison_enemy_info": "Zostałeś otruty.", + "poison_player_info": "Gracz '{0}' został otruty.", + "poison_select_info": "Wybierz gracza, który co kilka sekund będzie otrzymywał obrażenia:", + + "primaryban": "Brak Karabinów", + "primaryban_desc": "Wybierasz gracza, który nie może używać karabinów", + "primaryban_enemy_info": "Nie możesz już używać karabinów.", + "primaryban_player_info": "Gracz '{0}' nie może już używać karabinów.", + "primaryban_select_info": "Wybierz gracza, któremu chcesz zabronić używania karabinów:", + + "prosthesis": "Proteza", + "prosthesis_desc": "Ramiona i nogi są kuloodporne", + + "push": "Odpychacz", + "push_desc": "Masz losową szansę na odepchnięcie wroga po trafieniu go", + "push_desc2": "Twoje szanse na odepchnięcie wroga to: {0}%", + + "pyro": "Pyro", + "pyro_desc": "Molotow przywraca zdrowie", + + "quickshot": "Szybkostrzelność", + "quickshot_desc": "Wszystkie pociski są wystrzeliwane bardzo szybko", + + "radarhack": "Radarowiec", + "radarhack_desc": "Na radarze widać wrogów", + + "rambo": "Rambo", + "rambo_desc": "Na początku rundy otrzymujesz losową ilość zdrowia", + + "randomweapon": "Losowa Broń", + "randomweapon_desc": "Kliknij [css_useSkill], aby otrzymać losową broń", + + "rezombie": "Re-Zombie", + "rezombie_desc": "Po śmierci odradzasz się jako zombie z większym zdrowiem i bez broni", + + "reactivearmor": "Pancerz Reaktywny", + "reactivearmor_desc": "Pancerz pochłania pierwsze otrzymane obrażenia", + + "regeneration": "Regeneracja", + "regeneration_desc": "Co kilka sekund odnawiasz zdrowie", + + "replicator": "Replikator", + "replicator_desc": "Kliknij [css_useSkill], aby stworzyć swoją replikę, która zadaje obrażenia po trafieniu", + + "retreat": "Odwrót", + "retreat_desc": "Kliknij [css_useSkill], aby powrócić na resp", + + "returntosender": "Zwrot do Nadawcy", + "returntosender_desc": "Pierwsze trafienie wroga powoduje, że wraca on na swój resp", + + "richboy": "Bogacz", + "richboy_desc": "Na początku rundy otrzymujesz losową kwotę gotówki", + + "robinhood": "Robin Hood", + "robinhood_desc": "Zadanie obrażeń przeciwnikowi powoduje kradzież jego pieniędzy", + + "rubber": "Gumowe Kule", + "rubber_desc": "Twoje pociski znacznie spowalniają graczy", + + "saper": "Saper", + "saper_desc": "Możesz szybciej podłożyć bombę i ją rozbroić", + + "secondlife": "Druga Szansa", + "secondlife_desc": "Po śmierci odradzasz się z taką samą ilością zdrowia", + + "shade": "Cień", + "shade_desc": "Teleportujesz się za plecy trafionego wroga", + "shade_nospace": "Brak miejsca", + + "shortbomb": "Krótka Bomba", + "shortbomb_desc": "Bomba wybucha znacznie szybciej", + + "silent": "Cichociemny", + "silent_desc": "Twoje kroki i skoki są niesłyszalne dla INNYCH graczy", + + "sniperelite": "SzeliS", + "sniperelite_desc": "Kliknij [css_useSkill], aby zamienić aktualną broń na AWP", "soldier": "Żołnierz", "soldier_desc": "Masz losowy mnożnik obrażeń", "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", + + "spectator": "Obserwator", + "spectator_desc": "Kliknij [css_useSkill], aby obserwować losowego przeciwnika", + "swapposition": "Zamiana Miejsc", - "swapposition_desc": "Zamiana miejscami z losowym wrogiem. Kliknij [css_useSkill], cooldown 30s", + "swapposition_desc": "Kliknij [css_useSkill], aby zamienić się miejscami z losowym przeciwnikiem", - "holyhandgrenade": "Święty granat ręczny", - "holyhandgrenade_desc": "Twoje granaty uderzeniowe mają podwójne obrażenia i zasięg", - - "areareaper": "Niszczyciel stref", - "areareaper_desc": "Możesz wybrać strefę detonacji do dezaktywowania", - "areareaper_incorrect_site": "Nie znaleziono takiej strefy detonacji.", - "areareaper_no_site": "Nie znaleziono żadnej strefy detonacji.", - "areareaper_used_info": "Twoja moc została już wykorzystana.", - "areareaper_site_disabled": "Strefa detonacji {0} została dezaktywowana - nie można na nią podłożyć bomby!", - "areareaper_select_info": "Wybierz strefę detonacji, którą chcesz dezaktywować:", - - "deactivator": "Deaktywator", - "deactivator_desc": "", - "deactivator_enemy_info": "Twoja supermoc została wyłączona.", - "deactivator_player_info": "Moc gracza '{0}' została wyłączona.", - "deactivator_select_info": "Wybierz gracza któremu chcesz wyłączyć supermoc:", - - "glitch": "Glitch", - "jammer_enemy_info": "Twój radar został wyłączony.", - "glitch_desc": "Wyłącza radar wybranemu przeciwnikowi", - "glitch_player_info": "Radar gracza '{0}' został wyłączony.", - "glitch_select_info": "Wybierz gracza któremu chcesz wyłączyć radar:", - - "jammer": "Zakłócacz", - "jammer_desc": "", - "jammer_enemy_info": "Twój celownik został wyłączony.", - "jammer_player_info": "Celownik gracza '{0}' została wyłączona.", - "jammer_select_info": "Wybierz gracza któremu chcesz wyłączyć celownik:", - - "duplicator": "Duplikator", - "duplicator_desc": "", - "duplicator_player_info": "Moc gracza '{0}' została skopiowana.", - "duplicator_select_info": "Wybierz gracza od którego chcesz skopiować supermoc:", + "teleporter": "Teleporter", + "teleporter_desc": "Zamieniasz się miejscami z trafionym przeciwnikiem", "thief": "Złodziej", - "thief_desc": "", - "thief_enemy_info": "Twoja supermoc została ukradziona.", - "thief_player_info": "Moc gracza '{0}' została ukradziona.", - "thief_select_info": "Wybierz gracza któremu chcesz ukraść supermoc:", + "thief_desc": "Możesz ukraść supermoc wybranemu graczowi", + "thief_enemy_info": "Twoja supermoc została skradziona.", + "thief_player_info": "Moc gracza '{0}' została skradziona.", + "thief_select_info": "Wybierz gracza, którego supermoc chcesz ukraść:", - "selectplayerskill_incorrect_enemy_index": "Nie znaleziono gracza o takim index'ie.", - "selectplayerskill_not_found": "Nie znaleziono graczy!", - "selectplayerskill_command": "Wpisz /t", + "thirdeye": "Trzecie Oko", + "thirdeye_desc": "Kliknij [css_useSkill], aby aktywować trzecią osobę", - "pause": "Mecz został zapauzowany.", - "unpause": "Mecz został wznowiony.", - "welcome_message": "Witaj {PLAYER} na serwerze {SERVER_NAME}!\nAktualna wersja jRandomSkills: {VERSION} ({SKILLS_COUNT} supermocy).\n\nPierwotnie plugin stworzona przez:\n{AUTHOR1}\nZmodyfikowany i ulepszony przez:\n{AUTHOR2}", - "hud_info": "Poczekaj jeszcze {0} sekund", + "toxicsmoke": "Toksyczny Dym", + "toxicsmoke_desc": "Twoje granaty dymny zadają obrażenia", + + "wallhack": "Wallhack", + "wallhack_desc": "Widzisz wrogów przez ściany", + + "watchmaker": "Zegarmistrz", + "watchmaker_desc": "Każdy rzut granatem zmienia czas rundy", + "watchmaker_ct": "Czas rundy został skrócony o {0} sekund.", + "watchmaker_tt": "Czas rundy został wydłużony o {0} sekund", + + "weaponsswap": "Zamiana Broni", + "weaponsswap_desc": "Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem", + "weaponsswap_hud_info2": "Nie posiadasz broni na zamiane", + + "zeus": "Zeus", + "zeus_desc": "Zeus x27 natychmiastowo się odnawia", + + "your_skill": "Twoja aktualna moc", + "enemy_skill": "Supermoc przeciwnika", + "observer_skill": "Moc gracza", + "welcome_message": "Witaj {PLAYER} na serwerze {SERVER_NAME}!\nAktualna wersja jRandomSkills: {VERSION} ({SKILLS_COUNT} supermocy).\n\nPierwotnie plugin stworzona przez:\n{AUTHOR1}\nZmodyfikowany i ulepszony przez:\n{AUTHOR2}\nOficjalny discord: https://discord.gg/72nzFguNtd", + "drawing_skill": "Losowanie mocy", "disabled_weapon": "Nie możesz używać tej broni", + + "hud_info": "Poczekaj jeszcze {0} sekund", + "hud_info_no_enemy": "Nie znaleziono przeciwnika", + "active_hud_info": "Działa jeszcze przez {0} milisekund", + + "skills_menu": "Lista Super Mocy", "no_player": "Nie znaleziono pasującego gracza.", "duplicate_player": "Znaleziono więcej niż jednego gracza o tej samej nazwie.", - "drawing_skill": "Losowanie mocy", - "your_skill": "Twoja aktualna moc", - "summary_start": "======PODSUMOWANIE=Z=OSTATNIEJ=RUNDY======", - "summary_end": "============================================", - "enemy_skill": "Supermoc przeciwnika", - "teammate_skills": "Supermoce twoich sojuszników", - "observer_skill": "Moc gracza", - "game_start": "Gra rozpoczęta!", - "invalid_map": "Niepoprawnie podano nazwę mapy!", - "loading_map": "Ładowanie nowej mapy", - "skills_menu": "Lista Super Mocy", - "correct_form_setskill": "Poprawne użycie: CHATCOLORS.RED!setskill ", - "player_not_found_setskill": "Nie znaleziono takiego CHATCOLORS.REDgracza", + "selectplayerskill_command": "Wpisz /t", + "selectplayerskill_incorrect_enemy_index": "Nie znaleziono gracza o takim index'ie.", + "skill_not_found_setskill": "Nie znaleziono takiej CHATCOLORS.REDsupermocy", - "error_setskill": "Nie udało się ustawić CHATCOLORS.REDsupermocy", + "player_not_found_setskill": "Nie znaleziono takiego CHATCOLORS.REDgracza", + "correct_form_setskill": "Poprawne użycie: CHATCOLORS.RED!setskill ", + "correct_form_setscore": "Poprawne użycie: CHATCOLORS.RED!setscore ", "done_setskill": "Ustawiono Supermoc", - "for_setskill": "dla" + "error_setskill": "Nie udało się ustawić CHATCOLORS.REDsupermocy", + "for_setskill": "dla", + + "invalid_map": "Nazwa mapy została wprowadzona nieprawidłowo!", + "loading_map": "Ładowanie nowej mapy", + + "pause": "Mecz został wstrzymany.", + "unpause": "Mecz został wznowiony.", + "healed": "Zostałeś uleczony.", + "game_start": "Gra rozpoczęta!", + + "teammate_skills": "Supermoce twoich sojuszników", + "summary_start": "======PODSUMOWANIE=Z=OSTATNIEJ=RUNDY======", + "summary_end": "============================================" } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/lang/pt-br.json b/jRandomSkills - SRC Files/src/lang/pt-br.json new file mode 100644 index 0000000..9993d21 --- /dev/null +++ b/jRandomSkills - SRC Files/src/lang/pt-br.json @@ -0,0 +1,410 @@ +{ + "none": "Nenhum", + "none_desc": "Você não tem nenhuma habilidade", + + "aimbot": "Aimbot", + "aimbot_desc": "Cada bala que você acertar conta como um tiro na cabeça", + + "anomaly": "Anomalia", + "anomaly_desc": "Você retrocede alguns segundos no tempo", + + "antyflash": "Anti-Flash", + "antyflash_desc": "Você é imune a granadas de flash, e suas granadas de flash duram 7 segundos", + + "antyhead": "Cabeça de Ferro", + "antyhead_desc": "Você não recebe dano de tiros na cabeça", + + "areareaper": "Ceifador de Zonas", + "areareaper_desc": "Você pode escolher um local de bomba para desativar", + "areareaper_incorrect_site": "Nenhum local de bomba encontrado.", + "areareaper_no_site": "Nenhum local de bomba encontrado.", + "areareaper_select_info": "Escolha o local de bomba que deseja desativar:", + "areareaper_site_disabled": "Local de bomba {0} foi desativado - nenhuma bomba pode ser plantada lá!", + "areareaper_used_info": "Seu poder já foi usado.", + + "armored": "Blindado", + "armored_desc": "Você tem um multiplicador de dano recebido aleatório", + "armored_desc2": "Seu multiplicador de dano recebido é: {0}x", + + "assassin": "Assassino", + "assassin_desc": "Você causa mais dano aos inimigos por trás", + + "astronaut": "Astronauta", + "astronaut_desc": "Você recebe um valor de gravidade aleatório no início da rodada", + "astronaut_desc2": "Sua gravidade aleatória é: {0}x", + + "baseball": "Jogador de Beisebol", + "baseball_desc": "Seu chamariz ricocheteia nas paredes e mata instantaneamente um inimigo ao acertar", + + "behind": "Giro do Inimigo", + "behind_desc": "Você tem uma chance aleatória de girar um inimigo 180 graus ao acertá-lo", + "behind_desc2": "Sua chance de girar um inimigo ao acertar é: {0}%", + + "blademaster": "Mestre das Lâminas", + "blademaster_desc": "Enquanto segura uma faca, você tem uma alta chance de desviar de um tiro", + + "bunnyhop": "Coelho", + "bunnyhop_desc": "Você ganha \"BunnyHop\" automático", + + "c4camouflage": "Camuflagem C4", + "c4camouflage_desc": "Você fica invisível enquanto segura a bomba", + + "catapult": "Catapulta", + "catapult_desc": "Você tem uma chance aleatória de lançar um inimigo para cima", + "catapult_desc2": "Sua chance de lançar um inimigo ao acertar é: {0}%", + + "chicken": "Galinha", + "chicken_desc": "Você ganha um modelo de galinha + 10% de movimento mais rápido - 50 HP", + + "chillout": "Descontraído", + "chillout_desc": "Plantar a bomba leva significativamente mais tempo", + + "cutter": "Cortador", + "cutter_desc": "Mata instantaneamente com uma faca", + + "darkness": "Escuridão", + "darkness_desc": "Aplica um efeito de escuridão a um inimigo escolhido", + "darkness_enemy_info": "Que as luzes se apaguem.", + "darkness_player_info": "A escuridão tomou conta do jogador '{0}'.", + "darkness_select_info": "Escolha o jogador ao qual deseja aplicar o efeito de escuridão:", + + "deactivator": "Desativador", + "deactivator_desc": "Escolha um jogador cuja habilidade você deseja desativar", + "deactivator_enemy_info": "Sua habilidade foi desativada.", + "deactivator_player_info": "A habilidade do jogador '{0}' foi desativada.", + "deactivator_select_info": "Escolha o jogador cuja habilidade você deseja desativar:", + + "deaf": "Surdo", + "deaf_desc": "Escolha um jogador para silenciar todos os sons", + "deaf_enemy_info": "Seus fones de ouvido saíram do jogo.", + "deaf_player_info": "O som foi desativado para o jogador '{0}'.", + "deaf_select_info": "Escolha o jogador para quem deseja silenciar todos os sons:", + + "disarmament": "Desarmamento", + "disarmament_desc": "Você tem uma chance aleatória de fazer um inimigo largar sua arma ao acertá-lo", + "disarmament_desc2": "Sua chance de desarmar um inimigo é: {0}%", + + "distancer": "Medidor de Distância", + "distancer_desc": "Você pode ver a distância até o inimigo mais próximo", + + "dracula": "Drácula", + "dracula_desc": "Acertar um inimigo restaura saúde igual a uma porcentagem do dano causado", + + "duplicator": "Duplicador", + "duplicator_desc": "Escolha um jogador para copiar sua habilidade", + "duplicator_player_info": "A habilidade do jogador '{0}' foi copiada.", + "duplicator_select_info": "Escolha o jogador cuja habilidade você deseja copiar:", + + "dwarf": "Anão", + "dwarf_desc": "Tamanho de personagem aleatório no início da rodada", + "dwarf_desc2": "Seu multiplicador de tamanho é: {0}x", + + "enemyspawn": "Spawn Inimigo", + "enemyspawn_desc": "Clique em [css_useSkill] para se teletransportar para o spawn inimigo", + + "explosiveshot": "Tiro Explosivo", + "explosiveshot_desc": "Chance aleatória de disparar uma bala explosiva enquanto atira", + "explosiveshot_desc2": "Sua chance de disparar uma bala explosiva: {0}%", + + "falconeye": "Olho de Falcão", + "falconeye_desc": "Clique em [css_useSkill] para ativar uma câmera com visão aérea", + + "fastreload": "Recarga Rápida", + "fastreload_desc": "Clique em [css_useSkill] para recarregar a arma que você está segurando", + + "flash": "Flash", + "flash_desc": "Velocidade de jogador aleatória no início da rodada", + "flash_desc2": "Seu multiplicador de velocidade é: {0}x", + + "fortnite": "Fortnite", + "fortnite_desc": "Clique em [css_useSkill] para criar uma barricada destrutível", + + "fragilebomb": "Bomba Frágil", + "fragilebomb_desc": "Atirar na bomba a danifica", + "fragilebomb_bomb_health": "Vida da bomba", + + "friendlyfire": "Fogo Amigo", + "friendlyfire_desc": "Atirar em companheiros de equipe os cura", + + "frozendecoy": "Chamariz Congelante", + "frozendecoy_desc": "Seu chamariz congela todos os jogadores próximos", + + "ghost": "Fantasma", + "ghost_desc": "Você é completamente invisível", + + "glaz": "Glaz", + "glaz_desc": "Você não pode ver granadas de fumaça", + + "glitch": "Glitch", + "glitch_desc": "Desativa o radar de um inimigo escolhido", + "glitch_enemy_info": "Seu radar foi desativado.", + "glitch_player_info": "O radar do jogador '{0}' foi desativado.", + "glitch_select_info": "Escolha o jogador cujo radar você deseja desativar:", + + "glue": "Cola", + "glue_desc": "Suas granadas grudam nas paredes", + + "godmode": "Modo Deus", + "godmode_desc": "Clique em [css_useSkill] para se tornar imortal por um curto período", + "godmode_off": "Imortalidade desativada", + "godmode_on": "Imortalidade ativada", + + "healingsmoke": "Fumaça Curativa", + "healingsmoke_desc": "Suas granadas de fumaça curam", + + "hermit": "Eremita", + "hermit_desc": "Matar restaura munição e uma porção de saúde", + + "holyhandgrenade": "Granada Sagrada", + "holyhandgrenade_desc": "Suas granadas explosivas causam dano dobrado e têm alcance dobrado", + + "impostor": "Impostor", + "impostor_desc": "Você começa a rodada com um modelo de jogador inimigo", + + "infiniteammo": "Munição Infinita", + "infiniteammo_desc": "Você recebe munição infinita para todas as suas armas", + + "jackal": "Rastreador", + "jackal_desc": "Escolha um jogador que deixará um rastro atrás dele", + "jackal_player_info": "O jogador '{0}' começará a deixar um rastro.", + "jackal_select_info": "Escolha o jogador que deixará um rastro:", + + "jammer": "Jammer", + "jammer_desc": "Escolha um jogador para desativar sua mira", + "jammer_enemy_info": "Sua mira foi desativada.", + "jammer_player_info": "A mira do jogador '{0}' foi desativada.", + "jammer_select_info": "Escolha o jogador cuja mira você deseja desativar:", + + "jumpban": "Sem Pernas", + "jumpban_desc": "Escolha um jogador que não poderá pular", + "jumpban_enemy_info": "Alguém cortou suas pernas.", + "jumpban_player_info": "O jogador '{0}' não pode mais pular.", + "jumpban_select_info": "Escolha o jogador que não poderá pular:", + + "jumpingjack": "Pula-Pula", + "jumpingjack_desc": "Pular restaura saúde", + + "killerflash": "Flash Mortal", + "killerflash_desc": "Qualquer um completamente cego pela sua granada de flash morre (incluindo você)", + + "lifeswap": "Troca de Vida", + "lifeswap_desc": "Escolha um jogador para trocar saúde com ele", + "lifeswap_enemy_info": "Alguém pegou sua saúde emprestada.", + "lifeswap_player_info": "Você trocou saúde com o jogador '{0}'.", + "lifeswap_select_info": "Escolha o jogador com quem deseja trocar saúde:", + + "longknife": "Faca Longa", + "longknife_desc": "Um ataque com faca primária causa dano independentemente da distância", + + "longzeus": "Zeus Longo", + "longzeus_desc": "Zeus causa dano independentemente da distância", + + "medic": "Médico", + "medic_desc": "Clique em [css_useSkill] para usar uma carga de cura que restaura 50 de saúde", + + "moneyswap": "Cobrador de Impostos", + "moneyswap_desc": "Escolha um jogador para trocar dinheiro com ele", + "moneyswap_enemy_info": "A receita federal te pegou.", + "moneyswap_player_info": "Você trocou dinheiro com o jogador '{0}'.", + "moneyswap_select_info": "Escolha o jogador com quem deseja trocar dinheiro:", + + "muhammed": "Muhammed", + "muhammed_desc": "Você explode ao morrer, matando jogadores próximos", + + "ninja": "Ninja", + "ninja_desc": "Ficar parado aumenta sua invisibilidade em 33%, agachar em 33%, e segurar uma faca em 33%", + + "nonades": "Sem Granadas", + "nonades_desc": "Granadas não causam dano a você", + + "norecoil": "Foco", + "norecoil_desc": "Sem recuo ao atirar", + + "noclip": "NoClip", + "noclip_desc": "Clique em [css_useSkill] para ativar noclip por um curto período", + + "oneshot": "Tiro Único", + "oneshot_desc": "Acertar um inimigo o mata instantaneamente", + + "onlyhead": "Apenas Cabeça", + "onlyhead_desc": "Você só recebe dano na cabeça", + + "paweljumper": "Pawel Jumper", + "paweljumper_desc": "Você ganha um pulo extra", + + "phoenix": "Fênix", + "phoenix_desc": "Você tem uma chance aleatória de renascer após a morte", + "phoenix_desc2": "Sua chance de renascer após a morte: {0}%", + "phoenix_respawn": "Você foi ressuscitado das cinzas graças ao poder de: CHATCOLORS.REDPhoenix", + + "psychicdefusing": "Desarme Psíquico", + "psychicdefusing_desc": "Quando você está perto da bomba, começa a desarmá-la", + "psychicdefusing_hud_info": "{0} segundos restantes para desarmar", + + "pilot": "Piloto", + "pilot_desc": "Voe por um tempo limitado. Segure [USE - E] para voar", + "pilot_hud_info": "Recarregando", + + "planter": "Plantador Livre", + "planter_desc": "Você pode plantar a bomba em qualquer lugar, com um tempo de detonação de 60 segundos.", + + "poison": "Veneno", + "poison_desc": "Escolha um jogador que receberá dano a cada poucos segundos", + "poison_enemy_info": "Você foi envenenado.", + "poison_player_info": "O jogador '{0}' foi envenenado.", + "poison_select_info": "Escolha o jogador que receberá dano a cada poucos segundos:", + + "primaryban": "Sem Rifles", + "primaryban_desc": "Escolha um jogador que não poderá usar rifles", + "primaryban_enemy_info": "Você não pode mais usar rifles.", + "primaryban_player_info": "O jogador '{0}' não pode mais usar rifles.", + "primaryban_select_info": "Escolha o jogador para proibir de usar rifles:", + + "prosthesis": "Prótese", + "prosthesis_desc": "Braços e pernas são à prova de balas", + + "push": "Empurrador", + "push_desc": "Você tem uma chance aleatória de empurrar um inimigo para trás ao acertá-lo", + "push_desc2": "Suas chances de repelir o inimigo são: {0}%", + + "pyro": "Piro", + "pyro_desc": "Molotov restaura saúde", + + "quickshot": "Tiro Rápido", + "quickshot_desc": "Todas as balas são disparadas muito rapidamente", + + "radarhack": "Hack de Radar", + "radarhack_desc": "Inimigos são visíveis no radar", + + "rambo": "Rambo", + "rambo_desc": "Você recebe uma quantidade aleatória de saúde no início da rodada", + + "randomweapon": "Arma Aleatória", + "randomweapon_desc": "Clique em [css_useSkill] para receber uma arma aleatória", + + "rezombie": "Re-Zumbi", + "rezombie_desc": "Após a morte, você renasce como um zumbi com mais saúde e sem armas", + + "reactivearmor": "Armadura Reativa", + "reactivearmor_desc": "A armadura absorve o primeiro dano recebido", + + "regeneration": "Regeneração", + "regeneration_desc": "Você restaura saúde a cada poucos segundos", + + "replicator": "Replicador", + "replicator_desc": "Clique em [css_useSkill] para criar uma réplica que causa dano ao acertar", + + "retreat": "Recuo", + "retreat_desc": "Clique em [css_useSkill] para retornar ao spawn", + + "returntosender": "Devolução ao Remetente", + "returntosender_desc": "O primeiro acerto em um inimigo o envia de volta ao seu spawn", + + "richboy": "Garoto Rico", + "richboy_desc": "Você recebe uma quantidade aleatória de dinheiro no início da rodada", + + "robinhood": "Robin Hood", + "robinhood_desc": "Causar dano a um inimigo rouba seu dinheiro", + + "rubber": "Balas de Borracha", + "rubber_desc": "Suas balas retardam significativamente os jogadores", + + "saper": "Sapeador", + "saper_desc": "Você pode plantar e desarmar bombas mais rápido", + + "secondlife": "Segunda Chance", + "secondlife_desc": "Após a morte, você renasce com a mesma quantidade de saúde", + + "shade": "Sombra", + "shade_desc": "Você se teletransporta para trás de um inimigo acertado", + "shade_nospace": "Sem espaço disponível", + + "shortbomb": "Fusível Curto", + "shortbomb_desc": "A bomba explode muito mais rápido", + + "silent": "Silencioso", + "silent_desc": "Seus passos e pulos são silenciosos para OUTROS jogadores", + + "sniperelite": "Atirador de Elite", + "sniperelite_desc": "Clique em [css_useSkill] para trocar sua arma atual por uma AWP", + + "soldier": "Soldado", + "soldier_desc": "Você tem um multiplicador de dano aleatório", + "soldier_desc2": "Seu multiplicador de dano é: {0}x", + + "soundmaker": "Criador de Som", + "soundmaker_desc": "Clique em [css_useSkill] para acionar um som para cada inimigo", + + "spectator": "Espectador", + "spectator_desc": "Clique em [css_useSkill] para observar um inimigo aleatório", + + "swapposition": "Troca de Posição", + "swapposition_desc": "Clique em [css_useSkill] para trocar de lugar com um inimigo aleatório", + + "teleporter": "Teletransportador", + "teleporter_desc": "Você troca de lugar com o inimigo acertado", + + "thief": "Ladrão", + "thief_desc": "Você pode roubar uma habilidade de um jogador escolhido", + "thief_enemy_info": "Sua habilidade foi roubada.", + "thief_player_info": "A habilidade do jogador '{0}' foi roubada.", + "thief_select_info": "Escolha o jogador cuja habilidade você deseja roubar:", + + "thirdeye": "Terceiro Olho", + "thirdeye_desc": "Clique em [css_useSkill] para ativar a visão em terceira pessoa", + + "toxicsmoke": "Fumaça Tóxica", + "toxicsmoke_desc": "Suas granadas de fumaça causam dano", + + "wallhack": "Wallhack", + "wallhack_desc": "Você pode ver inimigos através das paredes", + + "watchmaker": "Relojoeiro", + "watchmaker_desc": "Cada arremesso de granada altera o tempo da rodada", + "watchmaker_ct": "Tempo da rodada reduzido em {0} segundos.", + "watchmaker_tt": "Tempo da rodada estendido em {0} segundos.", + + "weaponsswap": "Troca de Armas", + "weaponsswap_desc": "Clique em [css_useSkill] para trocar armas com um inimigo aleatório", + "weaponsswap_hud_info2": "Você não tem arma para trocar", + + "zeus": "Zeus", + "zeus_desc": "Zeus x27 recarrega instantaneamente", + + "your_skill": "Seu poder atual", + "enemy_skill": "Habilidade do inimigo", + "observer_skill": "Poder do jogador", + "welcome_message": "Bem-vindo {PLAYER} ao {SERVER_NAME}!\nVersão atual do jRandomSkills: {VERSION} ({SKILLS_COUNT} habilidades).\n\nCriado originalmente por:\n{AUTHOR1}\nModificado e aprimorado por:\n{AUTHOR2}", + "drawing_skill": "Sorteando uma habilidade", + "disabled_weapon": "Você não pode usar esta arma", + + "hud_info": "Espere mais {0} segundos", + "hud_info_no_enemy": "Nenhum inimigo encontrado", + "active_hud_info": "Ativo por mais {0} milissegundos", + + "skills_menu": "Lista de Habilidades", + "no_player": "Nenhum jogador correspondente encontrado.", + "duplicate_player": "Mais de um jogador encontrado com o mesmo nome.", + "selectplayerskill_command": "Digite /t", + "selectplayerskill_incorrect_enemy_index": "Nenhum jogador encontrado com esse índice.", + + "skill_not_found_setskill": "Nenhuma habilidade CHATCOLORS.RED encontrada", + "player_not_found_setskill": "Nenhum jogador CHATCOLORS.RED encontrado", + "correct_form_setskill": "Uso correto: CHATCOLORS.RED!setskill ", + "correct_form_setscore": "Uso correto: CHATCOLORS.RED!setscore ", + "done_setskill": "Habilidade definida", + "error_setskill": "Falha ao definir a habilidade CHATCOLORS.RED", + "for_setskill": "para", + + "invalid_map": "Nome do mapa inserido incorretamente!", + "loading_map": "Carregando um novo mapa", + + "pause": "Partida pausada.", + "unpause": "Partida retomada.", + "healed": "Você foi curado.", + "game_start": "Jogo iniciado!", + + "teammate_skills": "Habilidades dos seus companheiros de equipe", + "summary_start": "=======RESUMO=DA=ÚLTIMA=RODADA=======", + "summary_end": "=======================================" +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/lang/zh.json b/jRandomSkills - SRC Files/src/lang/zh.json new file mode 100644 index 0000000..1882963 --- /dev/null +++ b/jRandomSkills - SRC Files/src/lang/zh.json @@ -0,0 +1,410 @@ +{ + "none": "无", + "none_desc": "你没有任何技能", + + "aimbot": "自动瞄准", + "aimbot_desc": "你击中的每颗子弹都算作爆头", + + "anomaly": "异常", + "anomaly_desc": "你会倒退几秒钟的时间", + + "antyflash": "防闪", + "antyflash_desc": "你对闪光弹免疫,你的闪光弹持续7秒", + + "antyhead": "铁头", + "antyhead_desc": "你不会受到爆头伤害", + + "areareaper": "区域收割者", + "areareaper_desc": "你可以选择一个炸弹点进行禁用", + "areareaper_incorrect_site": "未找到此炸弹点。", + "areareaper_no_site": "未找到任何炸弹点。", + "areareaper_select_info": "选择你想禁用的炸弹点:", + "areareaper_site_disabled": "炸弹点 {0} 已被禁用 - 无法在此放置炸弹!", + "areareaper_used_info": "你的能力已被使用。", + + "armored": "装甲", + "armored_desc": "你有随机受到伤害的倍率", + "armored_desc2": "你的受到伤害倍率是:{0}x", + + "assassin": "刺客", + "assassin_desc": "从背后攻击敌人时造成更高的伤害", + + "astronaut": "宇航员", + "astronaut_desc": "回合开始时你会获得随机重力值", + "astronaut_desc2": "你的随机重力是:{0}x", + + "baseball": "棒球手", + "baseball_desc": "你的诱饵弹会在墙壁上反弹并在击中敌人时立即杀死", + + "behind": "敌人旋转", + "behind_desc": "你有随机几率在击中敌人时使其旋转180度", + "behind_desc2": "你击中敌人使其旋转的几率是:{0}%", + + "blademaster": "刀锋大师", + "blademaster_desc": "持刀时,你有很高几率格挡子弹", + + "bunnyhop": "兔子", + "bunnyhop_desc": "你获得自动“兔子跳”", + + "c4camouflage": "C4伪装", + "c4camouflage_desc": "你持有炸弹时隐形", + + "catapult": "弹射", + "catapult_desc": "你有随机几率将敌人向上弹射", + "catapult_desc2": "你击中敌人将其弹射的几率是:{0}%", + + "chicken": "鸡", + "chicken_desc": "你获得鸡模型 + 移动速度提高10% - 50生命值", + + "chillout": "悠闲", + "chillout_desc": "放置炸弹需要显著更长的时间", + + "cutter": "切割者", + "cutter_desc": "用刀可立即杀死敌人", + + "darkness": "黑暗", + "darkness_desc": "对选定的敌人施加黑暗效果", + "darkness_enemy_info": "让灯光熄灭。", + "darkness_player_info": "黑暗笼罩了玩家 '{0}'。", + "darkness_select_info": "选择你想施加黑暗效果的玩家:", + + "deactivator": "禁用者", + "deactivator_desc": "选择一个玩家以禁用其技能", + "deactivator_enemy_info": "你的技能已被禁用。", + "deactivator_player_info": "玩家 '{0}' 的技能已被禁用。", + "deactivator_select_info": "选择你想禁用其技能的玩家:", + + "deaf": "聾病", + "deaf_desc": "选择一个玩家以静音其所有声音", + "deaf_enemy_info": "你的耳机已退出游戏。", + "deaf_player_info": "玩家 '{0}' 的声音已被禁用。", + "deaf_select_info": "选择你想静音其所有声音的玩家:", + + "disarmament": "解除武装", + "disarmament_desc": "你有随机几率在击中敌人时使其丢下武器", + "disarmament_desc2": "你使敌人解除武装的几率是:{0}%", + + "distancer": "测距仪", + "distancer_desc": "你可以看到与最近敌人的距离", + + "dracula": "德古拉", + "dracula_desc": "击中敌人会根据造成的伤害百分比恢复你的生命值", + + "duplicator": "复制者", + "duplicator_desc": "选择一个玩家以复制其技能", + "duplicator_player_info": "玩家 '{0}' 的技能已被复制。", + "duplicator_select_info": "选择你想复制其技能的玩家:", + + "dwarf": "矮人", + "dwarf_desc": "回合开始时获得随机角色大小", + "dwarf_desc2": "你的体型倍率是:{0}x", + + "enemyspawn": "敌人出生点", + "enemyspawn_desc": "点击 [css_useSkill] 传送到敌人出生点", + + "explosiveshot": "爆炸射击", + "explosiveshot_desc": "射击时有随机几率发射爆炸子弹", + "explosiveshot_desc2": "你发射爆炸子弹的几率是:{0}%", + + "falconeye": "鹰眼", + "falconeye_desc": "点击 [css_useSkill] 激活鸟瞰视角摄像头", + + "fastreload": "快速装弹", + "fastreload_desc": "点击 [css_useSkill] 重新装填你当前持有的武器", + + "flash": "闪电", + "flash_desc": "回合开始时获得随机玩家速度", + "flash_desc2": "你的速度倍率是:{0}x", + + "fortnite": "堡垒之夜", + "fortnite_desc": "点击[css_useSkill]创建可破坏路障", + + "fragilebomb": "脆弱炸弹", + "fragilebomb_desc": "射击炸弹会对其造成伤害", + "fragilebomb_bomb_health": "炸弹生命值", + + "friendlyfire": "友军火力", + "friendlyfire_desc": "射击队友会治愈他们", + + "frozendecoy": "冰冻诱饵", + "frozendecoy_desc": "你的诱饵弹会冻结附近的所有玩家", + + "ghost": "幽灵", + "ghost_desc": "你完全隐形", + + "glaz": "格拉兹", + "glaz_desc": "你无法看到烟雾弹", + + "glitch": "故障", + "glitch_desc": "禁用选定敌人的雷达", + "glitch_enemy_info": "你的雷达已被禁用。", + "glitch_player_info": "玩家 '{0}' 的雷达已被禁用。", + "glitch_select_info": "选择你想禁用其雷达的玩家:", + + "glue": "粘胶", + "glue_desc": "你的手榴弹会粘在墙上", + + "godmode": "神模式", + "godmode_desc": "点击 [css_useSkill] 在短时间内变得无敌", + "godmode_off": "无敌状态已禁用", + "godmode_on": "无敌状态已启用", + + "healingsmoke": "治疗烟雾", + "healingsmoke_desc": "你的烟雾弹会治疗", + + "hermit": "隐士", + "hermit_desc": "击杀敌人会恢复弹药和部分生命值", + + "holyhandgrenade": "神圣手榴弹", + "holyhandgrenade_desc": "你的高爆手榴弹造成双倍伤害并拥有双倍范围", + + "impostor": "冒名顶替者", + "impostor_desc": "回合开始时你获得敌方玩家模型", + + "infiniteammo": "无限弹药", + "infiniteammo_desc": "你为所有武器获得无限弹药", + + "jackal": "追踪者", + "jackal_desc": "选择一个玩家,其身后会留下痕迹", + "jackal_player_info": "玩家 '{0}' 将开始留下痕迹。", + "jackal_select_info": "选择将留下痕迹的玩家:", + + "jammer": "干扰器", + "jammer_desc": "选择一个玩家以禁用其准星", + "jammer_enemy_info": "你的准星已被禁用。", + "jammer_player_info": "玩家 '{0}' 的准星已被禁用。", + "jammer_select_info": "选择你想禁用其准星的玩家:", + + "jumpban": "无腿", + "jumpban_desc": "选择一个玩家使其无法跳跃", + "jumpban_enemy_info": "有人切断了你的腿。", + "jumpban_player_info": "玩家 '{0}' 现在无法跳跃。", + "jumpban_select_info": "选择无法跳跃的玩家:", + + "jumpingjack": "跳跃杰克", + "jumpingjack_desc": "跳跃会恢复生命值", + + "killerflash": "致命闪光", + "killerflash_desc": "任何被你的闪光弹完全致盲的人都会死亡(包括你自己)", + + "lifeswap": "生命交换", + "lifeswap_desc": "选择一个玩家以交换生命值", + "lifeswap_enemy_info": "有人借走了你的生命值。", + "lifeswap_player_info": "你与玩家 '{0}' 交换了生命值。", + "lifeswap_select_info": "选择你想与之交换生命值的玩家:", + + "longknife": "长刀", + "longknife_desc": "近战刀具攻击无论距离远近均可造成伤害", + + "longzeus": "长宙斯", + "longzeus_desc": "宙斯电击枪无论距离多远都能造成伤害", + + "medic": "医务兵", + "medic_desc": "点击 [css_useSkill] 使用治疗装置恢复50点生命值", + + "moneyswap": "税务员", + "moneyswap_desc": "选择一个玩家以交换金钱", + "moneyswap_enemy_info": "税务局找上你了。", + "moneyswap_player_info": "你与玩家 '{0}' 交换了金钱。", + "moneyswap_select_info": "选择你想与之交换金钱的玩家:", + + "muhammed": "穆罕默德", + "muhammed_desc": "你死亡时会爆炸,杀死附近的玩家", + + "ninja": "忍者", + "ninja_desc": "站立不动增加33%隐形,蹲下增加33%,持刀增加33%", + + "nonades": "无手榴弹", + "nonades_desc": "手榴弹对你不造成伤害", + + "norecoil": "专注", + "norecoil_desc": "射击时无后坐力", + + "noclip": "无碰撞", + "noclip_desc": "点击 [css_useSkill] 在短时间内启用无碰撞模式", + + "oneshot": "一击必杀", + "oneshot_desc": "击中敌人立即杀死他们", + + "onlyhead": "仅头部", + "onlyhead_desc": "你只会在头部受到伤害", + + "paweljumper": "帕维尔跳跃者", + "paweljumper_desc": "你获得额外的跳跃", + + "phoenix": "凤凰", + "phoenix_desc": "你有随机几率在死亡后复活", + "phoenix_desc2": "你死亡后复活的几率是:{0}%", + "phoenix_respawn": "你因 CHATCOLORS.RED凤凰 的力量从灰烬中重生", + + "psychicdefusing": "心灵拆弹", + "psychicdefusing_desc": "当你靠近炸弹时,你开始拆除它", + "psychicdefusing_hud_info": "拆除还剩 {0} 秒", + + "pilot": "飞行员", + "pilot_desc": "在有限时间内飞行。按住 [USE - E] 飞行", + "pilot_hud_info": "正在充能", + + "planter": "自由种植者", + "planter_desc": "你可以在任何地方放置炸弹,引爆时间为60秒。", + + "poison": "毒药", + "poison_desc": "选择一个玩家,每隔几秒受到伤害", + "poison_enemy_info": "你被毒害了。", + "poison_player_info": "玩家 '{0}' 已被毒害。", + "poison_select_info": "选择每隔几秒将受到伤害的玩家:", + + "primaryban": "无步枪", + "primaryban_desc": "选择一个玩家使其无法使用步枪", + "primaryban_enemy_info": "你无法再使用步枪。", + "primaryban_player_info": "玩家 '{0}' 无法再使用步枪。", + "primaryban_select_info": "选择禁止使用步枪的玩家:", + + "prosthesis": "假肢", + "prosthesis_desc": "手臂和腿部防弹", + + "push": "推力者", + "push_desc": "你有随机几率在击中敌人时将其推回", + "push_desc2": "你击退敌人的几率为:{0}%", + + "pyro": "火焰兵", + "pyro_desc": "燃烧瓶会恢复生命值", + + "quickshot": "快速射击", + "quickshot_desc": "所有子弹射击速度极快", + + "radarhack": "雷达外挂", + "radarhack_desc": "雷达上可以看到敌人", + + "rambo": "兰博", + "rambo_desc": "回合开始时你获得随机数量的生命值", + + "randomweapon": "随机武器", + "randomweapon_desc": "点击 [css_useSkill] 获得随机武器", + + "rezombie": "重生僵尸", + "rezombie_desc": "死亡后你将作为僵尸复活,拥有更多生命值但无武器", + + "reactivearmor": "反应装甲", + "reactivearmor_desc": "装甲吸收首次受到的伤害", + + "regeneration": "再生", + "regeneration_desc": "每隔几秒恢复生命值", + + "replicator": "复制者", + "replicator_desc": "点击 [css_useSkill] 创建一个造成伤害的复制体", + + "retreat": "撤退", + "retreat_desc": "点击 [css_useSkill] 返回出生点", + + "returntosender": "退货", + "returntosender_desc": "首次击中敌人会将其送回出生点", + + "richboy": "富少", + "richboy_desc": "回合开始时你获得随机数量的钱", + + "robinhood": "罗宾汉", + "robinhood_desc": "对敌人造成伤害会偷取他们的钱", + + "rubber": "橡胶子弹", + "rubber_desc": "你的子弹会显著减慢玩家速度", + + "saper": "工兵", + "saper_desc": "你可以更快地放置和拆除炸弹", + + "secondlife": "第二次机会", + "secondlife_desc": "死亡后你会以相同生命值复活", + + "shade": "阴影", + "shade_desc": "你会传送到被击中敌人的背后", + "shade_nospace": "无可用空间", + + "shortbomb": "短引信", + "shortbomb_desc": "炸弹爆炸速度快得多", + + "silent": "无声", + "silent_desc": "你的脚步和跳跃对其他玩家无声", + + "sniperelite": "狙击精英", + "sniperelite_desc": "点击 [css_useSkill] 将当前武器替换为AWP", + + "soldier": "士兵", + "soldier_desc": "你有随机伤害倍率", + "soldier_desc2": "你的伤害倍率是:{0}x", + + "soundmaker": "声音制造者", + "soundmaker_desc": "点击 [css_useSkill] 为每个敌人触发一个声音", + + "spectator": "观察者", + "spectator_desc": "点击 [css_useSkill] 观察一个随机敌人", + + "swapposition": "位置交换", + "swapposition_desc": "点击 [css_useSkill] 与随机敌人交换位置", + + "teleporter": "传送者", + "teleporter_desc": "你与被击中的敌人交换位置", + + "thief": "小偷", + "thief_desc": "你可以从选定玩家那里偷取技能", + "thief_enemy_info": "你的技能被偷走了。", + "thief_player_info": "玩家 '{0}' 的技能被偷走了。", + "thief_select_info": "选择你想偷取其技能的玩家:", + + "thirdeye": "第三只眼", + "thirdeye_desc": "点击 [css_useSkill] 激活第三人称视角", + + "toxicsmoke": "毒烟", + "toxicsmoke_desc": "你的烟雾弹会造成伤害", + + "wallhack": "透视", + "wallhack_desc": "你可以通过墙壁看到敌人", + + "watchmaker": "钟表匠", + "watchmaker_desc": "每次投掷手榴弹都会改变回合时间", + "watchmaker_ct": "回合时间缩短了 {0} 秒。", + "watchmaker_tt": "回合时间延长了 {0} 秒。", + + "weaponsswap": "武器交换", + "weaponsswap_desc": "点击 [css_useSkill] 与随机敌人交换武器", + "weaponsswap_hud_info2": "你没有可交换的武器", + + "zeus": "宙斯", + "zeus_desc": "宙斯x27立即充能", + + "your_skill": "你当前的技能", + "enemy_skill": "敌人的技能", + "observer_skill": "玩家的技能", + "welcome_message": "欢迎 {PLAYER} 来到 {SERVER_NAME}!\n当前 jRandomSkills 版本:{VERSION}({SKILLS_COUNT} 个技能)。\n\n最初由以下人员创建:\n{AUTHOR1}\n由以下人员修改和改进:\n{AUTHOR2}", + "drawing_skill": "抽取技能", + "disabled_weapon": "你无法使用这把武器", + + "hud_info": "再等 {0} 秒", + "hud_info_no_enemy": "未找到敌人", + "active_hud_info": "还剩 {0} 毫秒有效", + + "skills_menu": "技能列表", + "no_player": "未找到匹配的玩家。", + "duplicate_player": "找到多个同名玩家。", + "selectplayerskill_command": "输入 /t", + "selectplayerskill_incorrect_enemy_index": "未找到该索引的玩家。", + + "skill_not_found_setskill": "未找到 CHATCOLORS.RED 技能", + "player_not_found_setskill": "未找到 CHATCOLORS.RED 玩家", + "correct_form_setskill": "正确用法:CHATCOLORS.RED!setskill <昵称> <技能>", + "correct_form_setscore": "正确用法:CHATCOLORS.RED!setscore ", + "done_setskill": "技能已设置", + "error_setskill": "无法设置 CHATCOLORS.RED 技能", + "for_setskill": "为", + + "invalid_map": "地图名称输入错误!", + "loading_map": "正在加载新地图", + + "pause": "比赛已暂停。", + "unpause": "比赛已恢复。", + "healed": "你已被治疗。", + "game_start": "游戏开始!", + + "teammate_skills": "你队友的技能", + "summary_start": "=============上一回合总结==============", + "summary_end": "=======================================" +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/Debug.cs b/jRandomSkills - SRC Files/src/player/Debug.cs index 102ac67..ceddc30 100644 --- a/jRandomSkills - SRC Files/src/player/Debug.cs +++ b/jRandomSkills - SRC Files/src/player/Debug.cs @@ -1,11 +1,8 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Entities; using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Utils; -using System.Numerics; -using System.Runtime.InteropServices; using static jRandomSkills.jRandomSkills; namespace jRandomSkills @@ -17,7 +14,6 @@ namespace jRandomSkills public static void Load() { Debug.sessionId = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}"; - Debug.WriteToDebug($"jRandomSkills v{Instance.ModuleVersion} loaded!"); Instance.RegisterEventHandler((@event, info) => { var player = @event.Userid; @@ -123,6 +119,9 @@ namespace jRandomSkills public static void WriteToDebug(string message) { + if (Config.config.Settings.DebugMode != true) + return; + string filename = $"Debug_{sessionId}.txt"; string pluginFolder = Path.Combine(Server.GameDirectory, "csgo", "addons", "counterstrikesharp", "plugins", "jRandomSkills"); string debugFolder = Path.Combine(pluginFolder, "Debug"); diff --git a/jRandomSkills - SRC Files/src/player/ISkill.cs b/jRandomSkills - SRC Files/src/player/ISkill.cs index e168af3..d8f38c0 100644 --- a/jRandomSkills - SRC Files/src/player/ISkill.cs +++ b/jRandomSkills - SRC Files/src/player/ISkill.cs @@ -14,69 +14,106 @@ public interface ISkill public enum Skills { None, - Dwarf, - SwapPosition, - FrozenDecoy, - Soldier, - Armored, Aimbot, - Retreat, - EnemySpawn, - Zeus, - RadarHack, - QuickShot, - Planter, - Silent, - KillerFlash, - TimeManipulator, - GodMode, - RandomWeapon, - WeaponsSwap, - Wallhack, - Mute, - HolyHandGrenade, - Replicator, - ToxicSmoke, - Deactivator, - Thief, - Duplicator, - AreaReaper, - Hermit, - RobinHood, - Jammer, - Glitch, - ReturnToSender, - ReactiveArmor, - OnlyHead, - Prosthesis, - SoundMaker, - Ninja, - C4Camouflage, - SecondLife, - NoRecoil, - - Flash, - PawelJumper, - BunnyHop, - Impostor, - OneShot, - Muhammed, - RichBoy, - Rambo, - Medic, - Ghost, - Chicken, - Astronaut, - Disarmament, + Anomaly, AntyFlash, - Behind, - InfiniteAmmo, - Catapult, - Dracula, - Teleporter, - Saper, - Phoenix, - Pilot, - Shade, AntyHead, + AreaReaper, + Armored, + Assassin, + Astronaut, + Baseball, + Behind, + BladeMaster, + BunnyHop, + C4Camouflage, + Catapult, + Chicken, + ChillOut, + Cutter, + Darkness, + Deactivator, + Deaf, + Disarmament, + Distancer, + Dracula, + Duplicator, + Dwarf, + EnemySpawn, + ExplosiveShot, + FalconEye, + FastReload, + Flash, + Fortnite, + FragileBomb, + FriendlyFire, + FrozenDecoy, + Ghost, + Glaz, + Glitch, + Glue, + GodMode, + HealingSmoke, + Hermit, + HolyHandGrenade, + Impostor, + InfiniteAmmo, + Jackal, + Jammer, + JumpBan, + JumpingJack, + KillerFlash, + LifeSwap, + LongKnife, + LongZeus, + Medic, + MoneySwap, + Muhammed, + Ninja, + NoNades, + NoRecoil, + Noclip, + OneShot, + OnlyHead, + PawelJumper, + Phoenix, + PsychicDefusing, + Pilot, + Planter, + Poison, + PrimaryBan, + Prosthesis, + Push, + Pyro, + QuickShot, + RadarHack, + Rambo, + RandomWeapon, + ReZombie, + ReactiveArmor, + Regeneration, + Replicator, + Retreat, + ReturnToSender, + RichBoy, + RobinHood, + Rubber, + Saper, + SecondLife, + Shade, + ShortBomb, + Silent, + SniperElite, + Soldier, + SoundMaker, + Spectator, + SwapPosition, + Teleporter, + Thief, + ThirdEye, + ToxicSmoke, + Wallhack, + Watchmaker, + WeaponsSwap, + Zeus, } diff --git a/jRandomSkills - SRC Files/src/player/PlayerEvents.cs b/jRandomSkills - SRC Files/src/player/PlayerEvents.cs index 8e6e59c..5c2e6b4 100644 --- a/jRandomSkills - SRC Files/src/player/PlayerEvents.cs +++ b/jRandomSkills - SRC Files/src/player/PlayerEvents.cs @@ -11,6 +11,11 @@ namespace jRandomSkills { public static class Event { + private static jSkill_SkillInfo ctSkill = new jSkill_SkillInfo(Skills.None, Config.GetValue(Skills.None, "color"), false); + private static jSkill_SkillInfo tSkill = new jSkill_SkillInfo(Skills.None, Config.GetValue(Skills.None, "color"), false); + private static jSkill_SkillInfo allSkill = new jSkill_SkillInfo(Skills.None, Config.GetValue(Skills.None, "color"), false); + private static List debugSkills = new List(SkillData.Skills); + public static void Load() { Instance.RegisterEventHandler((@event, info) => @@ -19,11 +24,11 @@ namespace jRandomSkills if (player == null || !player.IsValid) return HookResult.Continue; - Instance.skillPlayer.Add(new dSkill_PlayerInfo + Instance.skillPlayer.Add(new jSkill_PlayerInfo { SteamID = player.SteamID, PlayerName = player.PlayerName, - Skill = src.player.Skills.None, + Skill = Skills.None, SpecialSkill = Skills.None, IsDrawing = false, SkillChance = 1, @@ -112,6 +117,29 @@ namespace jRandomSkills Instance.RegisterEventHandler((@event, info) => { + Config.DefaultSkillInfo[] terroristSkills = Config.config.SkillsInfo.Where(s => s.OnlyTeam == (int)CsTeam.Terrorist).ToArray(); + Config.DefaultSkillInfo[] counterterroristSkills = Config.config.SkillsInfo.Where(s => s.OnlyTeam == (int)CsTeam.CounterTerrorist).ToArray(); + Config.DefaultSkillInfo[] allTeamsSkills = Config.config.SkillsInfo.Where(s => s.OnlyTeam == 0).ToArray(); + + if (Config.config.Settings.GameMode == (int)Config.GameModes.TeamSkills) + { + List tSkills = new List(SkillData.Skills); + tSkills.RemoveAll(s => s.Skill == tSkill.Skill || s.Skill == Skills.None || counterterroristSkills.Any(s2 => s2.Name == s.Skill.ToString())); + tSkill = tSkills.Count == 0 ? new jSkill_SkillInfo(Skills.None, Config.GetValue(Skills.None, "color"), false) : tSkills[Instance.Random.Next(tSkills.Count)]; + + List ctSkills = new List(SkillData.Skills); + ctSkills.RemoveAll(s => s.Skill == ctSkill.Skill || s.Skill == Skills.None || terroristSkills.Any(s2 => s2.Name == s.Skill.ToString())); + ctSkill = ctSkills.Count == 0 ? new jSkill_SkillInfo(Skills.None, Config.GetValue(Skills.None, "color"), false) : ctSkills[Instance.Random.Next(ctSkills.Count)]; + } + else if (Config.config.Settings.GameMode == (int)Config.GameModes.SameSkills) + { + List allSkills = new List(SkillData.Skills); + allSkills.RemoveAll(s => s.Skill == allSkill.Skill || s.Skill == Skills.None || !allTeamsSkills.Any(s2 => s2.Name == s.Skill.ToString())); + allSkill = allSkills.Count == 0 ? new jSkill_SkillInfo(Skills.None, Config.GetValue(Skills.None, "color"), false) : allSkills[Instance.Random.Next(allSkills.Count)]; + } + else if (Config.config.Settings.GameMode == (int)Config.GameModes.Debug && debugSkills.Count == 0) + debugSkills = new List(SkillData.Skills); + foreach (var player in Utilities.GetPlayers()) { var playerTeam = player.Team; @@ -123,24 +151,39 @@ namespace jRandomSkills if (skillPlayer != null) { skillPlayer.IsDrawing = false; + jSkill_SkillInfo randomSkill = new jSkill_SkillInfo(Skills.None, Config.GetValue(Skills.None, "color"), false); - List skillList = new List(SkillData.Skills); - skillList.RemoveAll(s => s?.Skill == skillPlayer?.Skill || s?.Skill == skillPlayer?.SpecialSkill || s?.Skill == Skills.None); - - if (Utilities.GetPlayers().FindAll(p => p.Team == player.Team && p.IsValid && !p.IsBot).Count != 1) + if (Config.config.Settings.GameMode == (int)Config.GameModes.Normal) { - Config.SkillInfo[] skillsOnly1v1 = Config.config.SkillsInfo.Where(s => s.Only1v1).ToArray(); - skillList.RemoveAll(s => skillsOnly1v1.Any(s2 => s2.Name == s.Skill.ToString())); + List skillList = new List(SkillData.Skills); + skillList.RemoveAll(s => s?.Skill == skillPlayer?.Skill || s?.Skill == skillPlayer?.SpecialSkill || s?.Skill == Skills.None); + + if (Utilities.GetPlayers().FindAll(p => p.Team == player.Team && p.IsValid && !p.IsBot).Count == 1) + { + Config.DefaultSkillInfo[] skillsNeedsTeammates = Config.config.SkillsInfo.Where(s => s.NeedsTeammates).ToArray(); + skillList.RemoveAll(s => skillsNeedsTeammates.Any(s2 => s2.Name == s.Skill.ToString())); + } + + if (player.Team == CsTeam.Terrorist) + skillList.RemoveAll(s => counterterroristSkills.Any(s2 => s2.Name == s.Skill.ToString())); + else + skillList.RemoveAll(s => terroristSkills.Any(s2 => s2.Name == s.Skill.ToString())); + + randomSkill = skillList.Count == 0 ? new jSkill_SkillInfo(Skills.None, Config.GetValue(Skills.None, "color"), false) : skillList[Instance.Random.Next(skillList.Count)]; + } + else if (Config.config.Settings.GameMode == (int)Config.GameModes.TeamSkills) + randomSkill = player.Team == CsTeam.Terrorist ? tSkill : ctSkill; + else if (Config.config.Settings.GameMode == (int)Config.GameModes.SameSkills) + randomSkill = allSkill; + else if (Config.config.Settings.GameMode == (int)Config.GameModes.Debug) + { + if (debugSkills.Count == 0) + debugSkills = new List(SkillData.Skills); + randomSkill = debugSkills[0]; + debugSkills.RemoveAt(0); + player.PrintToChat($"{SkillData.Skills.Count - debugSkills.Count}/{SkillData.Skills.Count}"); } - Config.SkillInfo[] terroristSkills = Config.config.SkillsInfo.Where(s => s.Team == 2).ToArray(); - Config.SkillInfo[] counterterroristSkills = Config.config.SkillsInfo.Where(s => s.Team == 3).ToArray(); - if (player.Team == CsTeam.Terrorist) - skillList.RemoveAll(s => counterterroristSkills.Any(s2 => s2.Name == s.Skill.ToString())); - else - skillList.RemoveAll(s => terroristSkills.Any(s2 => s2.Name == s.Skill.ToString())); - - var randomSkill = skillList.Count == 0 ? new dSkill_SkillInfo(Skills.None, "#ffffff", false) : skillList[Instance.Random.Next(skillList.Count)]; skillPlayer.Skill = randomSkill.Skill; skillPlayer.SpecialSkill = Skills.None; Debug.WriteToDebug($"Player {skillPlayer.PlayerName} has got the skill \"{randomSkill.Name}\"."); diff --git a/jRandomSkills - SRC Files/src/player/PlayerOnTick.cs b/jRandomSkills - SRC Files/src/player/PlayerOnTick.cs index 54494e2..a647392 100644 --- a/jRandomSkills - SRC Files/src/player/PlayerOnTick.cs +++ b/jRandomSkills - SRC Files/src/player/PlayerOnTick.cs @@ -14,14 +14,34 @@ namespace jRandomSkills { Instance.RegisterListener(() => { + UpdateGameRules(); foreach (var player in Utilities.GetPlayers()) - { if (player != null && player.IsValid) - { UpdatePlayerHud(player); - } - } }); + + Instance.RegisterListener(OnMapStart); + } + + private static void OnMapStart(string mapName) + { + Instance.GameRules = null; + } + + private static void InitializeGameRules() + { + if (Instance.GameRules != null) return; + var gameRulesProxy = Utilities.FindAllEntitiesByDesignerName("cs_gamerules").FirstOrDefault(); + if (gameRulesProxy != null) + Instance.GameRules = gameRulesProxy?.GameRules; + } + + private static void UpdateGameRules() + { + if (Instance.GameRules == null) + InitializeGameRules(); + else + Instance.GameRules.GameRestart = Instance.GameRules.RestartRoundTime < Server.CurrentTime; } private static void UpdatePlayerHud(CCSPlayerController player) diff --git a/jRandomSkills - SRC Files/src/player/skills/Aimbot.cs b/jRandomSkills - SRC Files/src/player/skills/Aimbot.cs index 8b75d6e..56cc90c 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Aimbot.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Aimbot.cs @@ -1,7 +1,7 @@ -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using System.Runtime.InteropServices; using static jRandomSkills.jRandomSkills; @@ -10,15 +10,12 @@ namespace jRandomSkills { public class Aimbot : ISkill { - private static Skills skillName = Skills.Aimbot; + private const Skills skillName = Skills.Aimbot; private static Dictionary hitGroups = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#ff0000"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); } @@ -66,5 +63,12 @@ namespace jRandomSkills return HookResult.Continue; } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff0000", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Anomaly.cs b/jRandomSkills - SRC Files/src/player/skills/Anomaly.cs new file mode 100644 index 0000000..5875041 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Anomaly.cs @@ -0,0 +1,163 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static CounterStrikeSharp.API.Core.Listeners; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Anomaly : ISkill + { + private const Skills skillName = Skills.Anomaly; + private static int maxSize = Config.GetValue(skillName, "secondsInBack"); + private static float tickRate = 64; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); + private static readonly Dictionary SkillPlayerInfo = new Dictionary(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + SkillPlayerInfo.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + if (SkillPlayerInfo.ContainsKey(player.SteamID)) + SkillPlayerInfo.Remove(player.SteamID); + + return HookResult.Continue; + }); + + Instance.RegisterListener(() => + { + 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 % tickRate != 0) return; + var pawn = player.PlayerPawn.Value; + if (pawn != null && pawn.IsValid) + { + skillInfo.LastPositions.Add(new Vector(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z)); + skillInfo.LastRotations.Add(new QAngle(pawn.EyeAngles.X, pawn.EyeAngles.Y, pawn.EyeAngles.Z)); + if (skillInfo.LastRotations.Count > maxSize) + { + skillInfo.LastPositions.RemoveAt(0); + skillInfo.LastRotations.RemoveAt(0); + } + } + } + } + }); + } + + public static void EnableSkill(CCSPlayerController player) + { + SkillPlayerInfo[player.SteamID] = new PlayerSkillInfo + { + SteamID = player.SteamID, + CanUse = true, + Cooldown = DateTime.MinValue, + LastPositions = new List(), + LastRotations = new List(), + }; + } + + public static void DisableSkill(CCSPlayerController player) + { + if (SkillPlayerInfo.ContainsKey(player.SteamID)) + SkillPlayerInfo.Remove(player.SteamID); + } + + private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo) + { + float cooldown = 0; + if (skillInfo != null) + { + float time = (int)(skillInfo.Cooldown.AddSeconds(timerCooldown) - DateTime.Now).TotalSeconds; + cooldown = Math.Max(time, 0); + + if (cooldown == 0 && skillInfo?.CanUse == false) + skillInfo.CanUse = true; + } + + var skillData = SkillData.Skills.FirstOrDefault(s => s.Skill == skillName); + if (skillData == null) return; + + string infoLine = $"{Localization.GetTranslation("your_skill")}:
"; + string skillLine = $"{skillData.Name}
"; + string remainingLine = cooldown != 0 ? $"{Localization.GetTranslation("hud_info", $"{cooldown}")}
" : ""; + + var hudContent = infoLine + skillLine + remainingLine; + player.PrintToCenterHtml(hudContent); + } + + 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; + Vector lastPosition = skillInfo.LastPositions.FirstOrDefault(); + QAngle lastRotation = skillInfo.LastRotations.FirstOrDefault(); + if (lastPosition != null && lastRotation != null) + playerPawn.Teleport(lastPosition, lastRotation, null); + } + } + } + + public class PlayerSkillInfo + { + public ulong SteamID { get; set; } + public bool CanUse { get; set; } + public DateTime Cooldown { get; set; } + public List LastPositions { get; set; } + public List LastRotations { get; set; } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int SecondsInBack { get; set; } + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#a86eff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int secondsInBack = 5, float cooldown = 15) : base(skill, active, color, onlyTeam, needsTeammates) + { + SecondsInBack = secondsInBack; + Cooldown = cooldown; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/AntyFlash.cs b/jRandomSkills - SRC Files/src/player/skills/AntyFlash.cs index 693c3b0..9738fac 100644 --- a/jRandomSkills - SRC Files/src/player/skills/AntyFlash.cs +++ b/jRandomSkills - SRC Files/src/player/skills/AntyFlash.cs @@ -1,4 +1,7 @@ +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -6,15 +9,28 @@ namespace jRandomSkills { public class AntyFlash : ISkill { - private static Skills skillName = Skills.AntyFlash; + private const Skills skillName = Skills.AntyFlash; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); - SkillUtils.RegisterSkill(skillName, "#D6E6FF"); - Instance.RegisterEventHandler((@event, info) => { var player = @event.Userid; @@ -35,5 +51,17 @@ namespace jRandomSkills return HookResult.Continue; }); } + + public static void EnableSkill(CCSPlayerController player) + { + SkillUtils.TryGiveWeapon(player, CsItem.FlashbangGrenade); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#D6E6FF", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/AntyHead.cs b/jRandomSkills - SRC Files/src/player/skills/AntyHead.cs index 5c63a84..44b5aa0 100644 --- a/jRandomSkills - SRC Files/src/player/skills/AntyHead.cs +++ b/jRandomSkills - SRC Files/src/player/skills/AntyHead.cs @@ -1,4 +1,5 @@ using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -6,15 +7,12 @@ namespace jRandomSkills { public class AntyHead : ISkill { - private static Skills skillName = Skills.AntyHead; + private const Skills skillName = Skills.AntyHead; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); - SkillUtils.RegisterSkill(skillName, "#8B4513"); - Instance.RegisterEventHandler((@event, info) => { var attacker = @event.Attacker; @@ -45,5 +43,12 @@ namespace jRandomSkills playerPawn.Health = (int)newHealth; } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#8B4513", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/AreaReaper.cs b/jRandomSkills - SRC Files/src/player/skills/AreaReaper.cs index 1908764..5296644 100644 --- a/jRandomSkills - SRC Files/src/player/skills/AreaReaper.cs +++ b/jRandomSkills - SRC Files/src/player/skills/AreaReaper.cs @@ -9,11 +9,11 @@ namespace jRandomSkills { public class AreaReaper : ISkill { - private static Skills skillName = Skills.AreaReaper; + private const Skills skillName = Skills.AreaReaper; public static void LoadSkill() { - SkillUtils.RegisterSkill(skillName, "#edf5b5", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -94,5 +94,12 @@ namespace jRandomSkills foreach (var bombTarget in bombTargets) bombTarget.AcceptInput("Enable"); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#edf5b5", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Armored.cs b/jRandomSkills - SRC Files/src/player/skills/Armored.cs index df89a66..050d39f 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Armored.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Armored.cs @@ -11,14 +11,11 @@ namespace jRandomSkills { public class Armored : ISkill { - private static Skills skillName = Skills.Armored; + private const Skills skillName = Skills.Armored; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#d1430a", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); @@ -44,10 +41,7 @@ namespace jRandomSkills { var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); - if (skillConfig == null) return; - - float newScale = (float)Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom; + float newScale = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "ChanceTo") - Config.GetValue(skillName, "ChanceFrom")) + Config.GetValue(skillName, "ChanceFrom"); playerInfo.SkillChance = newScale; newScale = (float)Math.Round(newScale, 2); SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("armored")}{ChatColors.Lime}: " + Localization.GetTranslation("armored_desc2", newScale), false); @@ -73,15 +67,24 @@ namespace jRandomSkills CCSPlayerController attacker = attackerPawn.Controller.Value.As(); CCSPlayerController victim = victimPawn.Controller.Value.As(); - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == victim.SteamID); if (playerInfo == null) return HookResult.Continue; - if (playerInfo.Skill == skillName && attacker.PawnIsAlive) - { + if (playerInfo.Skill == skillName && victim.PawnIsAlive) param2.Damage *= (float)playerInfo.SkillChance; - } return HookResult.Continue; } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#d1430a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = .65f, float chanceTo = .85f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Assassin.cs b/jRandomSkills - SRC Files/src/player/skills/Assassin.cs new file mode 100644 index 0000000..e0be636 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Assassin.cs @@ -0,0 +1,78 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Assassin : ISkill + { + private const Skills skillName = Skills.Assassin; + private static float damageMultiplier = Config.GetValue(skillName, "damageMultiplier"); + private static float toleranceDeg = Config.GetValue(skillName, "toleranceDeg"); + private static string[] nades = { "inferno", "flashbang", "smokegrenade", "decoy", "hegrenade" }; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var damage = @event.DmgHealth; + var victim = @event.Userid; + var attacker = @event.Attacker; + var weapon = @event.Weapon; + HitGroup_t hitgroup = (HitGroup_t)@event.Hitgroup; + + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; + if (nades.Contains(weapon)) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + if (IsBehind(attacker, victim)) + SkillUtils.TakeHealth(victim.PlayerPawn.Value, (int)(damage * (damageMultiplier - 1f))); + + return HookResult.Continue; + }); + } + + private static bool IsBehind(CCSPlayerController attacker, CCSPlayerController victim) + { + var attackerPawn = attacker.PlayerPawn.Value; + var victimPawn = victim.PlayerPawn.Value; + if (attackerPawn == null || !attackerPawn.IsValid || victimPawn == null || !victimPawn.IsValid) return false; + var angles = GetAngleRange(victimPawn.AbsRotation.Y); + return IsBeetween(angles.Item1, angles.Item2, attackerPawn.AbsRotation.Y); + } + + private static (float, float) GetAngleRange(float angle) + { + float min = angle - toleranceDeg; + float max = angle + toleranceDeg; + + if (min < -180) min += 360f; + if (max > 180f) max -= 360f; + + return (min, max); + } + + private static bool IsBeetween(float a, float b, float target) + { + if (a <= b) + return (target >= a && target <= b); + return (target >= a || target <= b); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float DamageMultiplier { get; set; } + public float ToleranceDeg { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#d9d9d9", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float damageMultiplier = 2f, float toleranceDeg = 45f) : base(skill, active, color, onlyTeam, needsTeammates) + { + DamageMultiplier = damageMultiplier; + ToleranceDeg = toleranceDeg; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Astronaut.cs b/jRandomSkills - SRC Files/src/player/skills/Astronaut.cs index 7ae9cf4..c8a6655 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Astronaut.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Astronaut.cs @@ -9,15 +9,12 @@ namespace jRandomSkills { public class Astronaut : ISkill { - private static Skills skillName = Skills.Astronaut; + private const Skills skillName = Skills.Astronaut; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); - SkillUtils.RegisterSkill(skillName, "#7E10AD", false); - Instance.RegisterEventHandler((@event, info) => { Instance.AddTimer(0.1f, () => @@ -35,6 +32,13 @@ namespace jRandomSkills }); return HookResult.Continue; }); + + Instance.RegisterEventHandler((@event, info) => + { + foreach (var player in Utilities.GetPlayers()) + DisableSkill(player); + return HookResult.Continue; + }); } public static void EnableSkill(CCSPlayerController player) @@ -44,17 +48,25 @@ namespace jRandomSkills public static void DisableSkill(CCSPlayerController player) { - player.Pawn.Value.GravityScale = 1; + player.Pawn.Value.ActualGravityScale = 1; } private static void ApplyGravityModifier(CCSPlayerController player) { - var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); - if (skillConfig == null) return; - - float gravityModifier = (float)Math.Round(Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom, 1); + float gravityModifier = (float)Math.Round(Instance.Random.NextDouble() * (Config.GetValue(skillName, "ChanceTo") - Config.GetValue(skillName, "chanceFrom")) + Config.GetValue(skillName, "chanceFrom"), 1); SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("astronaut")}{ChatColors.Lime}: " + Localization.GetTranslation("astronaut_desc2", gravityModifier), false); - player.Pawn.Value.GravityScale = gravityModifier; + player.Pawn.Value.ActualGravityScale = gravityModifier; + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#7E10AD", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = .1f, float chanceTo = .7f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + } } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Baseball.cs b/jRandomSkills - SRC Files/src/player/skills/Baseball.cs new file mode 100644 index 0000000..afebce6 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Baseball.cs @@ -0,0 +1,130 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Baseball : ISkill + { + private const Skills skillName = Skills.Baseball; + private static float speedMultipier = Config.GetValue(skillName, "speedMultipier"); + private static float maxSpeed = Config.GetValue(skillName, "maxSpeed"); + private static int damageDeal = Config.GetValue(skillName, "damageDeal"); + private static HashSet decoys = new HashSet(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var victim = @event.Userid; + var attacker = @event.Attacker; + var weapon = @event.Weapon; + + if (weapon != "decoy") return HookResult.Continue; + if (!Instance.IsPlayerValid(victim) || !Instance.IsPlayerValid(attacker)) return HookResult.Continue; + + var attackerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + if (attackerInfo?.Skill != skillName) return HookResult.Continue; + + SkillUtils.TakeHealth(victim.PlayerPawn.Value, damageDeal); + return HookResult.Continue; + }); + + Instance.RegisterListener(@event => + { + var name = @event.DesignerName; + if (name != "decoy_projectile") + return; + + var decoy = @event.As(); + var pawn = decoy.OwnerEntity.Value.As(); + var player = pawn.Controller.Value.As(); + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return; + decoys.Add(decoy); + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + var decoy = decoys.FirstOrDefault(d => d.Index == @event.Entityid); + if (decoy != null && decoy.IsValid) + decoy.Remove(); + + return HookResult.Continue; + }); + + Instance.RegisterListener(OnTick); + } + + private static void OnTick() + { + foreach (var decoy in decoys) + { + if (decoy == null || !decoy.IsValid) + { + decoys.Remove(decoy); + continue; + } + decoy.Bounces = 0; + if (Server.TickCount % 8 != 0) continue; + var vel = decoy.AbsVelocity; + float speed = vel.Length(); + float targetSpeed = Math.Min(speed * speedMultipier, maxSpeed); + + if (speed > .01f) + { + var dir = vel / speed; + var newVelocity = dir * targetSpeed; + + decoy.AbsVelocity.X = newVelocity.X; + decoy.AbsVelocity.Y = newVelocity.Y; + decoy.AbsVelocity.Z = newVelocity.Z; + } + } + } + + public static void EnableSkill(CCSPlayerController player) + { + SkillUtils.TryGiveWeapon(player, CsItem.DecoyGrenade); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float SpeedMultipier { get; set; } + public float MaxSpeed { get; set; } + public float DamageDeal { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#2effc7", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float speedMultipier = 2f, float maxSpeed = 900f, int damageDeal = 9999) : base(skill, active, color, onlyTeam, needsTeammates) + { + SpeedMultipier = speedMultipier; + MaxSpeed = maxSpeed; + DamageDeal = damageDeal; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Behind.cs b/jRandomSkills - SRC Files/src/player/skills/Behind.cs index e7aa88a..bc70b14 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Behind.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Behind.cs @@ -9,14 +9,11 @@ namespace jRandomSkills { public class Behind : ISkill { - private static Skills skillName = Skills.Behind; + private const Skills skillName = Skills.Behind; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#00FF00", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -57,11 +54,8 @@ namespace jRandomSkills public static void EnableSkill(CCSPlayerController player) { - var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); - if (skillConfig == null) return; - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - float newChance = (float)Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom; + float newChance = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "ChanceTo") - Config.GetValue(skillName, "ChanceFrom")) + Config.GetValue(skillName, "ChanceFrom"); playerInfo.SkillChance = newChance; newChance = (float)Math.Round(newChance, 2) * 100; newChance = (float)Math.Round(newChance); @@ -84,5 +78,16 @@ namespace jRandomSkills player.PlayerPawn.Value.Teleport(currentPosition, newAngles, new Vector(0, 0, 0)); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#00FF00", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = .2f, float chanceTo = .4f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + } + } } } \ 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 new file mode 100644 index 0000000..857914a --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/BladeMaster.cs @@ -0,0 +1,75 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class BladeMaster : ISkill + { + private const Skills skillName = Skills.BladeMaster; + private static string[] noReflectionWeapon = { "inferno", "flashbang", "smokegrenade", "decoy", "hegrenade", "knife" }; + private static float torseReflectionChance = Config.GetValue(skillName, "torseReflectionChance") * 100; + private static float legReflectionChance = Config.GetValue(skillName, "legReflectionChance") * 100; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var victim = @event.Userid; + int damage = @event.DmgHealth; + HitGroup_t hitGroup = (HitGroup_t)@event.Hitgroup; + string weapon = @event.Weapon; + + if (noReflectionWeapon.Contains(weapon) || !Instance.IsPlayerValid(victim)) return HookResult.Continue; + var victimInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == victim.SteamID); + if (victimInfo == null || victimInfo.Skill != skillName) return HookResult.Continue; + + int chance = Instance.Random.Next(0, 101); + if (hitGroup == HitGroup_t.HITGROUP_LEFTLEG || hitGroup == HitGroup_t.HITGROUP_RIGHTLEG) + { + if (chance > legReflectionChance) + return HookResult.Continue; + } + else + if (chance > torseReflectionChance) + return HookResult.Continue; + + var pawn = victim.PlayerPawn.Value; + if (pawn == null || !pawn.IsValid) return HookResult.Continue; + + var activeWeapon = pawn.WeaponServices.ActiveWeapon.Value; + if (activeWeapon == null || !activeWeapon.IsValid || activeWeapon.DesignerName != "weapon_knife") return HookResult.Continue; + + RestoreHealth(victim, damage); + return HookResult.Stop; + }); + } + + private static void RestoreHealth(CCSPlayerController victim, float damage) + { + var playerPawn = victim.PlayerPawn.Value; + var newHealth = playerPawn.Health + damage; + + if (newHealth > 100) + newHealth = 100; + + playerPawn.Health = (int)newHealth; + Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_iHealth"); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float TorseReflectionChance { get; set; } + public float LegReflectionChance { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#cc7504", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float torseReflectionChance = .95f, float legReflectionChance = .80f) : base(skill, active, color, onlyTeam, needsTeammates) + { + TorseReflectionChance = torseReflectionChance; + LegReflectionChance = legReflectionChance; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/BunnyHop.cs b/jRandomSkills - SRC Files/src/player/skills/BunnyHop.cs index cab0c15..7c35b37 100644 --- a/jRandomSkills - SRC Files/src/player/skills/BunnyHop.cs +++ b/jRandomSkills - SRC Files/src/player/skills/BunnyHop.cs @@ -9,16 +9,14 @@ namespace jRandomSkills { public class BunnyHop : ISkill { - private static Skills skillName = Skills.BunnyHop; - private const float MaxSpeed = 500f; - private const float BunnyHopVelocity = 300f; + private const Skills skillName = Skills.BunnyHop; + private static float maxSpeed = Config.GetValue(skillName, "maxSpeed"); + private static float bunnyHopVelocity = Config.GetValue(skillName, "jumpVelocity"); + private static float jumpBoost = Config.GetValue(skillName, "jumpBoost"); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#EB4034"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterListener(OnTick); } @@ -27,40 +25,52 @@ namespace jRandomSkills foreach (var player in Utilities.GetPlayers()) { var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - if (playerInfo?.Skill == skillName) - { GiveBunnyHop(player); - } } } private static void GiveBunnyHop(CCSPlayerController player) { var playerPawn = player.PlayerPawn.Value; - if (playerPawn != null) + if (playerPawn == null || !playerPawn.IsValid) return; + + var flags = (PlayerFlags)playerPawn.Flags; + var buttons = player.Buttons; + + if (buttons.HasFlag(PlayerButtons.Jump) && flags.HasFlag(PlayerFlags.FL_ONGROUND) && !playerPawn.MoveType.HasFlag(MoveType_t.MOVETYPE_LADDER)) { - if (Math.Round(playerPawn.AbsVelocity.Length2D()) > MaxSpeed && MaxSpeed != 0) - ChangeVelocity(playerPawn, MaxSpeed); + playerPawn.AbsVelocity.Z = bunnyHopVelocity; - var flags = (PlayerFlags)playerPawn.Flags; - var buttons = player.Buttons; + var vX = playerPawn.AbsVelocity.X; + var vY = playerPawn.AbsVelocity.Y; + var speed2D = Math.Sqrt(vX * vX + vY * vY); + var scale = 1d; - if (buttons.HasFlag(PlayerButtons.Jump) && flags.HasFlag(PlayerFlags.FL_ONGROUND) && !playerPawn.MoveType.HasFlag(MoveType_t.MOVETYPE_LADDER)) - playerPawn.AbsVelocity.Z = BunnyHopVelocity; + if (speed2D < maxSpeed) + { + var newSpeed = Math.Min(speed2D * jumpBoost, maxSpeed); + scale = newSpeed / (speed2D == 0 ? 1 : speed2D); + } + else if (speed2D > maxSpeed) + scale = maxSpeed / speed2D; + + playerPawn.AbsVelocity.X = (float)(vX * scale); + playerPawn.AbsVelocity.Y = (float)(vY * scale); } } - private static void ChangeVelocity(CCSPlayerPawn? pawn, float vel) + public class SkillConfig : Config.DefaultSkillInfo { - if (pawn == null) return; - - var currentVelocity = new Vector(pawn.AbsVelocity.X, pawn.AbsVelocity.Y, pawn.AbsVelocity.Z); - var currentSpeed3D = Math.Sqrt(currentVelocity.X * currentVelocity.X + currentVelocity.Y * currentVelocity.Y + currentVelocity.Z * currentVelocity.Z); - - pawn.AbsVelocity.X = (float)(currentVelocity.X / currentSpeed3D) * vel; - pawn.AbsVelocity.Y = (float)(currentVelocity.Y / currentSpeed3D) * vel; - pawn.AbsVelocity.Z = (float)(currentVelocity.Z / currentSpeed3D) * vel; + public float MaxSpeed { get; set; } + public float JumpVelocity { get; set; } + public float JumpBoost { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#d1430a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float maxSpeed = 500f, float jumpVelocity = 300f, float jumpBoost = 2f) : base(skill, active, color, onlyTeam, needsTeammates) + { + MaxSpeed = maxSpeed; + JumpVelocity = jumpVelocity; + JumpBoost = jumpBoost; + } } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/C4Camouflage.cs b/jRandomSkills - SRC Files/src/player/skills/C4Camouflage.cs index bc522dd..53aa562 100644 --- a/jRandomSkills - SRC Files/src/player/skills/C4Camouflage.cs +++ b/jRandomSkills - SRC Files/src/player/skills/C4Camouflage.cs @@ -1,6 +1,7 @@ using System.Drawing; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -8,14 +9,11 @@ namespace jRandomSkills { public class C4Camouflage : ISkill { - private static Skills skillName = Skills.C4Camouflage; + private const Skills skillName = Skills.C4Camouflage; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#00911f"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -23,6 +21,7 @@ namespace jRandomSkills { foreach (var player in Utilities.GetPlayers()) { + DisableSkill(player); if (!Instance.IsPlayerValid(player)) continue; var playerPawn = player.PlayerPawn?.Value; @@ -35,10 +34,15 @@ namespace jRandomSkills return HookResult.Continue; }); - Instance.RegisterEventHandler((@event, info) => + Instance.RegisterEventHandler((@event, info) => { - foreach (var player in Utilities.GetPlayers()) + var player = @event.Userid; + if (!player.IsValid || player.PlayerPawn.Value == null) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) DisableSkill(player); + return HookResult.Continue; }); @@ -117,5 +121,12 @@ namespace jRandomSkills } } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#00911f", CsTeam onlyTeam = CsTeam.Terrorist, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Catapult.cs b/jRandomSkills - SRC Files/src/player/skills/Catapult.cs index 08f24c1..9f4b60b 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Catapult.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Catapult.cs @@ -9,14 +9,11 @@ namespace jRandomSkills { public class Catapult : ISkill { - private static Skills skillName = Skills.Catapult; + private const Skills skillName = Skills.Catapult; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#FF4500", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -40,10 +37,7 @@ namespace jRandomSkills var attacker = @event.Attacker; var victim = @event.Userid; - if (attacker == null || !attacker.IsValid || victim == null || !victim.IsValid) return HookResult.Continue; - - if (attacker == victim) return HookResult.Continue; - + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; var attackerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); if (attackerInfo?.Skill == skillName && victim.PawnIsAlive) @@ -64,15 +58,23 @@ namespace jRandomSkills public static void EnableSkill(CCSPlayerController player) { - var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); - if (skillConfig == null) return; - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - float newChance = (float)Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom; + float newChance = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "chanceTo") - Config.GetValue(skillName, "chanceFrom")) + Config.GetValue(skillName, "chanceFrom"); playerInfo.SkillChance = newChance; newChance = (float)Math.Round(newChance, 2) * 100; newChance = (float)Math.Round(newChance); SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("catapult")}{ChatColors.Lime}: " + Localization.GetTranslation("catapult_desc2", newChance), false); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#FF4500", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = .2f, float chanceTo = .4f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Chicken.cs b/jRandomSkills - SRC Files/src/player/skills/Chicken.cs index 6bb700e..73de410 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Chicken.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Chicken.cs @@ -11,7 +11,7 @@ namespace jRandomSkills { public class Chicken : ISkill { - private static Skills skillName = Skills.Chicken; + private const Skills skillName = Skills.Chicken; private static string[] disabledWeapons = { "weapon_ak47", @@ -44,10 +44,7 @@ namespace jRandomSkills public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#FF8B42"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -82,7 +79,13 @@ namespace jRandomSkills Instance.RegisterEventHandler((@event, info) => { - DisableSkill(@event.Userid); + var player = @event.Userid; + if (!player.IsValid || player.PlayerPawn.Value == null) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + DisableSkill(player); + return HookResult.Continue; }); @@ -95,6 +98,13 @@ namespace jRandomSkills return HookResult.Continue; }); + Instance.RegisterEventHandler((@event, info) => + { + foreach (var player in Utilities.GetPlayers()) + SetWeaponAttack(player, false); + return HookResult.Continue; + }); + Instance.RegisterListener(OnTick); } @@ -104,7 +114,6 @@ namespace jRandomSkills if (playerPawn != null) { playerPawn.VelocityModifier = 1.1f; - Utilities.SetStateChanged(player, "CCSPlayerPawn", "m_flVelocityModifier"); playerPawn.Health = 50; Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_iHealth"); @@ -127,7 +136,6 @@ namespace jRandomSkills if (playerPawn != null) { playerPawn.VelocityModifier = 1f; - Utilities.SetStateChanged(player, "CCSPlayerPawn", "m_flVelocityModifier"); playerPawn.Health += 50; Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_iHealth"); @@ -219,5 +227,12 @@ namespace jRandomSkills var hudContent = infoLine + skillLine + remainingLine; player.PrintToCenterHtml(hudContent); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#FF8B42", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/ChillOut.cs b/jRandomSkills - SRC Files/src/player/skills/ChillOut.cs new file mode 100644 index 0000000..6c8a0e7 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/ChillOut.cs @@ -0,0 +1,50 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class ChillOut : ISkill + { + private const Skills skillName = Skills.ChillOut; + private static float bombArmedTime = Config.GetValue(skillName, "bombArmedTime"); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + + if (!Instance.IsPlayerValid(player)) return HookResult.Continue; + + var anyChillOut = Instance.skillPlayer.FirstOrDefault(p => p.Skill == skillName); + if (anyChillOut != null) + { + var bombEntities = Utilities.FindAllEntitiesByDesignerName("weapon_c4").ToList(); + + if (bombEntities.Any()) + { + var bomb = bombEntities.FirstOrDefault(); + if (bomb != null) + bomb.ArmedTime = Server.CurrentTime + bombArmedTime; + } + } + + return HookResult.Continue; + }); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float BombArmedTime { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#343deb", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool needsTeammates = false, float bombArmedTime = 10f) : base(skill, active, color, onlyTeam, needsTeammates) + { + BombArmedTime = bombArmedTime; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Cutter.cs b/jRandomSkills - SRC Files/src/player/skills/Cutter.cs new file mode 100644 index 0000000..de36510 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Cutter.cs @@ -0,0 +1,41 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Cutter : ISkill + { + private const Skills skillName = Skills.Cutter; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var damage = @event.DmgHealth; + var attacker = @event.Attacker; + var victim = @event.Userid; + var weapon = @event.Weapon; + + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + if (weapon == "knife") + SkillUtils.TakeHealth(victim.PlayerPawn.Value, 9999); + return HookResult.Continue; + }); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#88a31a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Darkness.cs b/jRandomSkills - SRC Files/src/player/skills/Darkness.cs new file mode 100644 index 0000000..4448ee0 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Darkness.cs @@ -0,0 +1,136 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Darkness : ISkill + { + private const Skills skillName = Skills.Darkness; + private static float brightness = Config.GetValue(skillName, "brightness"); + private static Dictionary deafultPostProcessing = new Dictionary(); + private static List newPostProcessing = new List(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + foreach (var player in deafultPostProcessing.Keys) + DisableSkill(player); + foreach (var postProcessing in newPostProcessing) + postProcessing.Remove(); + newPostProcessing.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + SetUpPostProcessing(@event.Userid, true); + return HookResult.Continue; + }); + } + + 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.SkillChance == 1) + { + player.PrintToChat($" {ChatColors.Red}{Localization.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}" + Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")); + return; + } + + SetUpPostProcessing(enemy); + playerInfo.SkillChance = 1; + player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("darkness_player_info", enemy.PlayerName)); + enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("darkness_enemy_info")); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + playerInfo.SkillChance = 0; + + SkillUtils.PrintToChat(player, Localization.GetTranslation("darkness") + ":", false); + + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("darkness_select_info")}"); + var enemies = Utilities.GetPlayers().Where(p => p.Team != player.Team && p.IsValid && !p.IsBot).ToArray(); + if (enemies.Length > 0) + { + foreach (var enemy in enemies) + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + } + else + player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("selectplayerskill_command")} {ChatColors.Red}index"); + } + + public static void DisableSkill(CCSPlayerController player) + { + SetUpPostProcessing(player, true); + } + + private static void SetUpPostProcessing(CCSPlayerController player, bool dontCreateNew = false) + { + if (deafultPostProcessing.TryGetValue(player, out var oldPostProcessing)) + { + player.PlayerPawn.Value.CameraServices.PostProcessingVolumes.FirstOrDefault().Raw = oldPostProcessing.EntityHandle.Raw; + deafultPostProcessing.Remove(player); + Utilities.SetStateChanged(player.PlayerPawn.Value, "CBasePlayerPawn", "m_pCameraServices"); + return; + } + + if (dontCreateNew) + return; + + var postProcessing = Utilities.CreateEntityByName("post_processing_volume"); + postProcessing.ExposureControl = true; + postProcessing.MaxExposure = brightness; + postProcessing.MinExposure = brightness; + deafultPostProcessing.TryAdd(player, player.PlayerPawn.Value.CameraServices.PostProcessingVolumes.FirstOrDefault().Value); + player.PlayerPawn.Value.CameraServices.PostProcessingVolumes.FirstOrDefault().Raw = postProcessing.EntityHandle.Raw; + Utilities.SetStateChanged(player.PlayerPawn.Value, "CBasePlayerPawn", "m_pCameraServices"); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Brightness { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#383838", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float brightness = .01f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Brightness = brightness; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Deactivator.cs b/jRandomSkills - SRC Files/src/player/skills/Deactivator.cs index 4ba0086..eaee80b 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Deactivator.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Deactivator.cs @@ -3,21 +3,17 @@ using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using jRandomSkills.src.utils; -using static CounterStrikeSharp.API.Core.Listeners; using static jRandomSkills.jRandomSkills; namespace jRandomSkills { public class Deactivator : ISkill { - private static Skills skillName = Skills.Deactivator; + private const Skills skillName = Skills.Deactivator; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#919191", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -83,7 +79,7 @@ namespace jRandomSkills var enemyInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == enemy.SteamID); if (enemyInfo == null) continue; var skillData = SkillData.Skills.FirstOrDefault(s => s.Skill == enemyInfo.Skill); - player.PrintToChat($" {ChatColors.Green}⠀⠀⠀{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}: {ChatColors.Red}{skillData.Name}"); + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}: {ChatColors.Red}{skillData.Name}"); } } else @@ -117,5 +113,12 @@ namespace jRandomSkills enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("deactivator_enemy_info")); } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#919191", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Deaf.cs b/jRandomSkills - SRC Files/src/player/skills/Deaf.cs new file mode 100644 index 0000000..9b05858 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Deaf.cs @@ -0,0 +1,119 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Deaf : ISkill + { + private const Skills skillName = Skills.Deaf; + private static HashSet deafPlayers = new HashSet(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + + Instance.RegisterEventHandler((@event, info) => + { + deafPlayers.Clear(); + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + DisableSkill(@event.Userid); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + foreach (var player in deafPlayers) + DisableSkill(player); + return HookResult.Continue; + }); + + Instance.HookUserMessage(208, um => + { + var soundevent = um.ReadUInt("soundevent_hash"); + var userIndex = um.ReadUInt("source_entity_index"); + + foreach (var player in deafPlayers) + um.Recipients.Remove(player); + + return HookResult.Continue; + }, HookMode.Pre); + } + + 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.SkillChance == 1) + { + player.PrintToChat($" {ChatColors.Red}{Localization.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}" + Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")); + return; + } + + deafPlayers.Add(enemy); + playerInfo.SkillChance = 1; + player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("deaf_player_info", enemy.PlayerName)); + enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("deaf_enemy_info")); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + playerInfo.SkillChance = 0; + + SkillUtils.PrintToChat(player, Localization.GetTranslation("deaf") + ":", false); + + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("deaf_select_info")}"); + var enemies = Utilities.GetPlayers().Where(p => p.Team != player.Team && p.IsValid && !p.IsBot).ToArray(); + if (enemies.Length > 0) + { + foreach (var enemy in enemies) + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + } + else + player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("selectplayerskill_command")} {ChatColors.Red}index"); + } + + public static void DisableSkill(CCSPlayerController player) + { + deafPlayers.Remove(player); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#dae01f", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Disarmament.cs b/jRandomSkills - SRC Files/src/player/skills/Disarmament.cs index b09f631..24b140a 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Disarmament.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Disarmament.cs @@ -9,14 +9,11 @@ namespace jRandomSkills { public class Disarmament : ISkill { - private static Skills skillName = Skills.Disarmament; + private const Skills skillName = Skills.Disarmament; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#FF4500", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -40,10 +37,7 @@ namespace jRandomSkills var attacker = @event.Attacker; var victim = @event.Userid; - if (attacker == null || !attacker.IsValid || victim == null || !victim.IsValid) return HookResult.Continue; - - if (attacker == victim) return HookResult.Continue; - + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); if (playerInfo?.Skill == skillName && victim.PawnIsAlive) @@ -55,7 +49,8 @@ namespace jRandomSkills var weaponName = weaponServices?.ActiveWeapon?.Value?.DesignerName; if (weaponName != null && !weaponName.Contains("weapon_knife") && !weaponName.Contains("weapon_c4")) - victim.DropActiveWeapon(); + victim.ExecuteClientCommand("slot3"); + //victim.DropActiveWeapon(); } } return HookResult.Continue; @@ -64,15 +59,23 @@ namespace jRandomSkills public static void EnableSkill(CCSPlayerController player) { - var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); - if (skillConfig == null) return; - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - float newChance = (float)Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom; + float newChance = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "chanceTo") - Config.GetValue(skillName, "chanceFrom")) + Config.GetValue(skillName, "chanceFrom"); playerInfo.SkillChance = newChance; newChance = (float)Math.Round(newChance, 2) * 100; newChance = (float)Math.Round(newChance); SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("disarmament")}{ChatColors.Lime}: " + Localization.GetTranslation("disarmament_desc2", newChance), false); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#FF4500", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = .65f, float chanceTo = .85f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Distancer.cs b/jRandomSkills - SRC Files/src/player/skills/Distancer.cs new file mode 100644 index 0000000..de5839d --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Distancer.cs @@ -0,0 +1,98 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Distancer : ISkill + { + private const Skills skillName = Skills.Distancer; + private static HashSet distancerPlayers = new HashSet(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + foreach (var player in distancerPlayers) + DisableSkill(player); + return HookResult.Continue; + }); + + Instance.RegisterListener(OnTick); + } + + private static void OnTick() + { + foreach (var player in distancerPlayers) + { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn == null || !playerPawn.IsValid) return; + if (playerPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) return; + + var skillData = SkillData.Skills.FirstOrDefault(s => s.Skill == skillName); + if (skillData == null) return; + + string closetEnemy = "Bot"; + double closetDistance = double.MaxValue; + + foreach (var enemy in Utilities.GetPlayers().Where(p => p.Team != player.Team)) + { + var enemyPawn = enemy.PlayerPawn.Value; + if (enemyPawn == null || !enemyPawn.IsValid) continue; + if (enemyPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) continue; + double distance = (int)SkillUtils.GetDistance(playerPawn.AbsOrigin, enemyPawn.AbsOrigin); + if (distance >= closetDistance) continue; + closetDistance = distance; + closetEnemy = enemy.PlayerName; + } + + string distanceColor = closetDistance > 1500 ? "#00FF00" : closetDistance > 600 ? "#FFFF00" : "#FF0000"; + + string infoLine = $"{Localization.GetTranslation("your_skill")}:
"; + string skillLine = $"{skillData.Name}
"; + string remainingLine = $"{closetEnemy}: {closetDistance}
"; + + var hudContent = infoLine + skillLine + remainingLine; + player.PrintToCenterHtml(hudContent); + } + } + + public static void EnableSkill(CCSPlayerController player) + { + distancerPlayers.Add(player); + } + + public static void DisableSkill(CCSPlayerController player) + { + distancerPlayers.Remove(player); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#00f2ff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Dracula.cs b/jRandomSkills - SRC Files/src/player/skills/Dracula.cs index 435f953..078e8ee 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Dracula.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Dracula.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -7,21 +8,19 @@ namespace jRandomSkills { public class Dracula : ISkill { - private static Skills skillName = Skills.Dracula; + private const Skills skillName = Skills.Dracula; + private static float healthRegainScale = Config.GetValue(skillName, "healthRegainScale"); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#FA050D"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { var attacker = @event.Attacker; var victim = @event.Userid; - if (!Instance.IsPlayerValid(attacker) || attacker == victim) return HookResult.Continue; + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); @@ -38,7 +37,7 @@ namespace jRandomSkills var attackerPawn = attacker.PlayerPawn.Value; if (attackerPawn == null) return; - int newHealth = (int)(attackerPawn.Health + (damage * 0.3)); + int newHealth = (int)(attackerPawn.Health + (damage * healthRegainScale)); attackerPawn.MaxHealth = Math.Max(newHealth, 100); Utilities.SetStateChanged(attackerPawn, "CBaseEntity", "m_iMaxHealth"); @@ -46,5 +45,14 @@ namespace jRandomSkills attackerPawn.Health = newHealth; Utilities.SetStateChanged(attackerPawn, "CBaseEntity", "m_iHealth"); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float HealthRegainScale { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#FA050D", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float healthRegainScale = .3f) : base(skill, active, color, onlyTeam, needsTeammates) + { + HealthRegainScale = healthRegainScale; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Duplicator.cs b/jRandomSkills - SRC Files/src/player/skills/Duplicator.cs index a97d0b1..15be89c 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Duplicator.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Duplicator.cs @@ -9,14 +9,11 @@ namespace jRandomSkills { public class Duplicator : ISkill { - private static Skills skillName = Skills.Duplicator; + private const Skills skillName = Skills.Duplicator; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#ffb73b", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -98,5 +95,12 @@ namespace jRandomSkills player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("duplicator_player_info", enemy.PlayerName)); } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffb73b", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Dwarf.cs b/jRandomSkills - SRC Files/src/player/skills/Dwarf.cs index 08bb54c..692a35f 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Dwarf.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Dwarf.cs @@ -9,14 +9,11 @@ namespace jRandomSkills { public class Dwarf : ISkill { - private static Skills skillName = Skills.Dwarf; + private const Skills skillName = Skills.Dwarf; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#ffff00", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -62,16 +59,12 @@ namespace jRandomSkills var playerPawn = player.PlayerPawn?.Value; if (playerPawn != null) { - var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); - if (skillConfig == null) return; - - float newSize = (float)Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom; + float newSize = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "maxScale") - Config.GetValue(skillName, "minScale")) + Config.GetValue(skillName, "minScale"); newSize = (float)Math.Round(newSize, 2); // playerPawn.CBodyComponent.SceneNode.GetSkeletonInstance().Scale = newSize; - player.PlayerPawn.Value.CBodyComponent.SceneNode.Scale = newSize; + playerPawn.CBodyComponent.SceneNode.Scale = newSize; Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_CBodyComponent"); - SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("dwarf")}{ChatColors.Lime}: " + Localization.GetTranslation("dwarf_desc2", newSize), false); } } @@ -82,9 +75,21 @@ namespace jRandomSkills if (playerPawn != null && playerPawn?.CBodyComponent != null) { // playerPawn.CBodyComponent.SceneNode.GetSkeletonInstance().Scale = 1; - player.PlayerPawn.Value.CBodyComponent.SceneNode.Scale = 1; + playerPawn.CBodyComponent.SceneNode.Scale = 1; Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_CBodyComponent"); } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float MinScale { get; set; } + public float MaxScale { get; set; } + + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffff00", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float minScale = .6f, float maxScale = .95f) : base(skill, active, color, onlyTeam, needsTeammates) + { + MinScale = minScale; + MaxScale = maxScale; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/EnemySpawn.cs b/jRandomSkills - SRC Files/src/player/skills/EnemySpawn.cs index f6e9957..6718ec5 100644 --- a/jRandomSkills - SRC Files/src/player/skills/EnemySpawn.cs +++ b/jRandomSkills - SRC Files/src/player/skills/EnemySpawn.cs @@ -10,16 +10,13 @@ namespace jRandomSkills { public class EnemySpawn : ISkill { - private static Skills skillName = Skills.EnemySpawn; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.EnemySpawn; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#ff8c92"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -123,14 +120,6 @@ namespace jRandomSkills player.PrintToCenterHtml(hudContent); } - private static void ActiveUse(CCSPlayerController player) - { - if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo)) - { - skillInfo.CanUse = true; - } - } - public static void UseSkill(CCSPlayerController player) { var playerPawn = player.PlayerPawn.Value; @@ -169,5 +158,14 @@ namespace jRandomSkills public DateTime Cooldown { get; set; } public DateTime LastClick { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff8c92", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 15f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/ExplosiveShot.cs b/jRandomSkills - SRC Files/src/player/skills/ExplosiveShot.cs new file mode 100644 index 0000000..4766f1e --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/ExplosiveShot.cs @@ -0,0 +1,106 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class ExplosiveShot : ISkill + { + private const Skills skillName = Skills.ExplosiveShot; + private static float damage = Config.GetValue(skillName, "damage"); + private static float damageRadius = Config.GetValue(skillName, "damageRadius"); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + float newChance = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "ChanceTo") - Config.GetValue(skillName, "ChanceFrom")) + Config.GetValue(skillName, "ChanceFrom"); + playerInfo.SkillChance = newChance; + newChance = (float)Math.Round(newChance, 2) * 100; + newChance = (float)Math.Round(newChance); + SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("explosiveshot")}{ChatColors.Lime}: " + Localization.GetTranslation("explosiveshot_desc2", newChance), false); + } + + private static void SpawnExplosion(Vector vector) + { + var heProjectile = Utilities.CreateEntityByName("hegrenade_projectile"); + if (heProjectile == null || !heProjectile.IsValid) return; + + Vector pos = vector; + heProjectile.TicksAtZeroVelocity = 100; + heProjectile.TeamNum = (byte)CsTeam.None; + heProjectile.Damage = damage; + heProjectile.DmgRadius = damageRadius; + heProjectile.Teleport(pos, null, new Vector(0, 0, -10)); + heProjectile.DispatchSpawn(); + heProjectile.AcceptInput("InitializeSpawnFromWorld", null, null, ""); + heProjectile.DetonateTime = 0; + } + + private static HookResult 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 HookResult.Continue; + + CCSPlayerPawn attackerPawn = new CCSPlayerPawn(param2.Attacker.Value.Handle); + if (attackerPawn.DesignerName != "player") + return HookResult.Continue; + + if (attackerPawn == null || attackerPawn.Controller?.Value == null) + return HookResult.Continue; + + CCSPlayerController attacker = attackerPawn.Controller.Value.As(); + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + if (playerInfo == null || playerInfo.Skill != skillName) return HookResult.Continue; + + if (Instance.Random.NextDouble() <= playerInfo.SkillChance) + SpawnExplosion(param2.DamagePosition); + return HookResult.Continue; + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Damage { get; set; } + public float DamageRadius { get; set; } + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#9c0000", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float damage = 10f, float damageRadius = 190f, float chanceFrom = .15f, float chanceTo = .3f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Damage = damage; + DamageRadius = damageRadius; + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/FalconEye.cs b/jRandomSkills - SRC Files/src/player/skills/FalconEye.cs new file mode 100644 index 0000000..551ba5b --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/FalconEye.cs @@ -0,0 +1,147 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using System.Drawing; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class FalconEye : ISkill + { + private const Skills skillName = Skills.FalconEye; + private static bool blocked = false; + private static float distance = Config.GetValue(skillName, "distance"); + private static Dictionary cameras = new Dictionary(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + blocked = true; + foreach (var player in Utilities.GetPlayers()) + if (cameras.TryGetValue(player.SteamID, out _)) + DisableSkill(player); + + foreach (var camera in cameras) + camera.Value.Item2.Remove(); + cameras.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + blocked = false; + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + if (!Instance.IsPlayerValid(player)) return HookResult.Continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + if (cameras.TryGetValue(player.SteamID, out var cameraInfo) && cameraInfo.Item1 == player.PlayerPawn.Value.CameraServices!.ViewEntity!.Raw) + BlockWeapon(player, true); + return HookResult.Continue; + }); + + Instance.RegisterListener(OnTick); + } + + public static void UseSkill(CCSPlayerController player) + { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn?.CBodyComponent == null || blocked) return; + ChangeCamera(player); + } + + public static void DisableSkill(CCSPlayerController player) + { + ChangeCamera(player, true); + } + + private static void OnTick() + { + foreach (var player in Utilities.GetPlayers()) + if (cameras.TryGetValue(player.SteamID, out var cameraInfo) && cameraInfo.Item2.IsValid) + { + var pawn = player.PlayerPawn.Value; + if (pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) + { + ChangeCamera(player, true); + continue; + } + Vector pos = new Vector(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z + 1000); + QAngle angle = new QAngle(90, 0, -pawn.V_angle.Y); + cameraInfo.Item2.Teleport(pos, angle); + } + } + + private static void ChangeCamera(CCSPlayerController player, bool forceToDefault = false) + { + uint orginalCameraRaw; + uint newCameraRaw; + var pawn = player.PlayerPawn.Value; + if (cameras.TryGetValue(player.SteamID, out var cameraInfo) && cameraInfo.Item2.IsValid) + { + orginalCameraRaw = cameraInfo.Item1; + newCameraRaw = cameraInfo.Item2.EntityHandle.Raw; + } + else + { + orginalCameraRaw = pawn!.CameraServices!.ViewEntity.Raw; + newCameraRaw = CreateCamera(player); + } + + if (newCameraRaw == 0) + return; + + bool defaultCam = forceToDefault ? true : (pawn.CameraServices!.ViewEntity!.Raw == orginalCameraRaw ? false : true); + pawn!.CameraServices!.ViewEntity.Raw = defaultCam ? orginalCameraRaw : newCameraRaw; + Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_pCameraServices"); + BlockWeapon(player, !defaultCam); + } + + private static uint CreateCamera(CCSPlayerController player) + { + var camera = Utilities.CreateEntityByName("prop_dynamic"); + if (camera == null || !camera.IsValid) return 0; + + var pawn = player.PlayerPawn.Value; + Vector pos = new Vector(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z + distance); + + camera.Render = Color.FromArgb(0, 255, 255, 255); + camera.Teleport(pos, new QAngle(90, 0, 0)); + camera.DispatchSpawn(); + cameras[player.SteamID] = (pawn.CameraServices!.ViewEntity.Raw, camera); + return camera.EntityHandle.Raw; + } + + private static void BlockWeapon(CCSPlayerController player, bool block) + { + foreach (var weapon in player.Pawn.Value.WeaponServices?.MyWeapons) + if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid) + { + weapon.Value.NextPrimaryAttackTick = block ? int.MaxValue : Server.TickCount; + weapon.Value.NextSecondaryAttackTick = block ? int.MaxValue : Server.TickCount; + + Utilities.SetStateChanged(weapon.Value, "CBasePlayerWeapon", "m_nNextPrimaryAttackTick"); + Utilities.SetStateChanged(weapon.Value, "CBasePlayerWeapon", "m_nNextSecondaryAttackTick"); + } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Distance { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#d1f542", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float distance = 1000f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Distance = distance; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/FastReload.cs b/jRandomSkills - SRC Files/src/player/skills/FastReload.cs new file mode 100644 index 0000000..0c767bb --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/FastReload.cs @@ -0,0 +1,46 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class FastReload : ISkill + { + private const Skills skillName = Skills.FastReload; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + } + + public static void UseSkill(CCSPlayerController player) + { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn?.CBodyComponent == null) return; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return; + if (!player.IsValid || !player.PawnIsAlive) return; + + InstaReload(playerPawn); + } + + private static void InstaReload(CCSPlayerPawn pawn) + { + var activeWeapon = pawn.WeaponServices.ActiveWeapon.Value; + if (activeWeapon == null || !activeWeapon.IsValid) return; + + activeWeapon.Clip1 = activeWeapon.VData.MaxClip1; + Utilities.SetStateChanged(activeWeapon, "CBasePlayerWeapon", "m_iClip1"); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffc061", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float distance = 1000f) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Flash.cs b/jRandomSkills - SRC Files/src/player/skills/Flash.cs index 731f539..3b54ca6 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Flash.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Flash.cs @@ -10,14 +10,11 @@ namespace jRandomSkills { public class Flash : ISkill { - private static Skills skillName = Skills.Flash; + private const Skills skillName = Skills.Flash; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#A31912", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterListener(UpdateSpeed); Instance.RegisterEventHandler((@event, info) => @@ -30,8 +27,6 @@ namespace jRandomSkills var playerPawn = player.PlayerPawn?.Value; playerPawn.VelocityModifier = 1; - Utilities.SetStateChanged(playerPawn, "CCSPlayerPawn", "m_flVelocityModifier"); - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo?.Skill != skillName) continue; EnableSkill(player); @@ -74,12 +69,11 @@ namespace jRandomSkills var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); if (skillConfig == null) return; - float newSpeed = (float)Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom; + float newSpeed = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "ChanceTo") - Config.GetValue(skillName, "ChanceFrom")) + Config.GetValue(skillName, "ChanceFrom"); newSpeed = (float)Math.Round(newSpeed, 2); playerInfo.SkillChance = newSpeed; playerPawn.VelocityModifier = newSpeed; - Utilities.SetStateChanged(playerPawn, "CCSPlayerPawn", "m_flVelocityModifier"); SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("flash")}{ChatColors.Lime}: " + Localization.GetTranslation("flash_desc2", newSpeed), false); } @@ -88,7 +82,6 @@ namespace jRandomSkills var playerPawn = player.PlayerPawn.Value; if (playerPawn == null) return; playerPawn.VelocityModifier = 1; - Utilities.SetStateChanged(playerPawn, "CCSPlayerPawn", "m_flVelocityModifier"); } private static void UpdateSpeed() @@ -102,10 +95,18 @@ namespace jRandomSkills var playerPawn = player.PlayerPawn?.Value; if (playerPawn != null && playerPawn.VelocityModifier != 0) - { playerPawn.VelocityModifier = Math.Max((float)playerInfo?.SkillChance, 1); - Utilities.SetStateChanged(playerPawn, "CCSPlayerPawn", "m_flVelocityModifier"); - } + } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#A31912", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = 1.2f, float chanceTo = 3.0f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; } } } diff --git a/jRandomSkills - SRC Files/src/player/skills/Fortnite.cs b/jRandomSkills - SRC Files/src/player/skills/Fortnite.cs new file mode 100644 index 0000000..975b713 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Fortnite.cs @@ -0,0 +1,191 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static CounterStrikeSharp.API.Core.Listeners; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Fortnite : ISkill + { + private const Skills skillName = Skills.Fortnite; + private static float timerCooldown = Config.GetValue(skillName, "Cooldown"); + private const string propModel = "models/props/de_aztec/hr_aztec/aztec_scaffolding/aztec_scaffold_wall_support_128.vmdl"; + private static readonly Dictionary SkillPlayerInfo = new Dictionary(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) return; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + SkillPlayerInfo.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + if (SkillPlayerInfo.ContainsKey(player.SteamID)) + SkillPlayerInfo.Remove(player.SteamID); + return HookResult.Continue; + }); + + Instance.RegisterListener(() => + { + 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); + } + }); + + Instance.RegisterListener((ResourceManifest manifest) => + { + manifest.AddResource(propModel); + }); + + VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); + } + + public static void EnableSkill(CCSPlayerController player) + { + SkillPlayerInfo[player.SteamID] = new PlayerSkillInfo + { + SteamID = player.SteamID, + CanUse = true, + Cooldown = DateTime.MinValue, + LastClick = DateTime.MinValue, + }; + } + + public static void DisableSkill(CCSPlayerController player) + { + if (SkillPlayerInfo.ContainsKey(player.SteamID)) + SkillPlayerInfo.Remove(player.SteamID); + } + + private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo) + { + float cooldown = 0; + if (skillInfo != null) + { + float time = (int)(skillInfo.Cooldown.AddSeconds(timerCooldown) - DateTime.Now).TotalSeconds; + cooldown = Math.Max(time, 0); + + if (cooldown == 0 && skillInfo?.CanUse == false) + skillInfo.CanUse = true; + } + + var skillData = SkillData.Skills.FirstOrDefault(s => s.Skill == skillName); + if (skillData == null) return; + + string infoLine = $"{Localization.GetTranslation("your_skill")}:
"; + string skillLine = $"{skillData.Name}
"; + string remainingLine = cooldown != 0 ? $"{Localization.GetTranslation("hud_info", $"{cooldown}")}
" : ""; + + var hudContent = infoLine + skillLine + remainingLine; + player.PrintToCenterHtml(hudContent); + } + + 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; + CreateBox(player); + } + else + skillInfo.LastClick = DateTime.Now; + } + } + + private static void CreateBox(CCSPlayerController player) + { + var playerPawn = player.PlayerPawn.Value; + var box = Utilities.CreateEntityByName("prop_dynamic_override"); + if (box == null) return; + + float distance = 50; + Vector pos = playerPawn.AbsOrigin + SkillUtils.GetForwardVector(playerPawn.AbsRotation) * distance; + QAngle angle = new QAngle(playerPawn.AbsRotation.X, playerPawn.AbsRotation.Y + 90, playerPawn.AbsRotation.Z); + + box.Entity.Name = box.Globalname = $"FortniteWall_{Server.TickCount}"; + box.Collision.SolidType = SolidType_t.SOLID_VPHYSICS; + box.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags = (uint)(box.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags & ~(1 << 2)); + box.DispatchSpawn(); + Server.NextFrame(() => + { + box.SetModel(propModel); + box.Teleport(pos, angle, null); + }); + } + + private static HookResult 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 HookResult.Continue; + + if (string.IsNullOrEmpty(param.Entity.Name)) return HookResult.Continue; + if (!param.Entity.Name.StartsWith("FortniteWall")) return HookResult.Continue; + + var box = param.As(); + if (box == null || !box.IsValid) return HookResult.Continue; + box.EmitSound("Wood_Plank.BulletImpact", volume: 1f); + box.Remove(); + return HookResult.Continue; + } + + public class PlayerSkillInfo + { + public ulong SteamID { get; set; } + public bool CanUse { get; set; } + public DateTime Cooldown { get; set; } + public DateTime LastClick { get; set; } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#1b04cc", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 2f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/FragileBomb.cs b/jRandomSkills - SRC Files/src/player/skills/FragileBomb.cs new file mode 100644 index 0000000..cd8a1db --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/FragileBomb.cs @@ -0,0 +1,131 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class FragileBomb : ISkill + { + private const Skills skillName = Skills.FragileBomb; + private static int bombHealth = Config.GetValue(skillName, "maxBombHealth"); + private static int maxBombHealth = Config.GetValue(skillName, "maxBombHealth"); + + private static CPlantedC4 plantedC4; + private static CTriggerMultiple triggerC4; + + public static void LoadSkill() + { + if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) + return; + + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + bombHealth = maxBombHealth; + plantedC4 = null; + triggerC4 = null; + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var plantedBomb = Utilities.FindAllEntitiesByDesignerName("planted_c4").FirstOrDefault(); + if (plantedBomb == null) return HookResult.Continue; + plantedC4 = plantedBomb; + CreateTrigger(); + return HookResult.Continue; + }); + + VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); + } + + private static void CreateTrigger() + { + var trigger = Utilities.CreateEntityByName("trigger_multiple"); + if (trigger == null || plantedC4 == null) return; + + trigger.Collision.SolidType = SolidType_t.SOLID_CAPSULE; + trigger.Collision.SolidFlags = 0; + trigger.Spawnflags = 1; + trigger.Globalname = $"planted_bomb_prop_{trigger.Index}"; + trigger.Collision.SolidFlags = 1; + + trigger.AbsOrigin.X = plantedC4.AbsOrigin.X; + trigger.AbsOrigin.Y = plantedC4.AbsOrigin.Y; + trigger.AbsOrigin.Z = plantedC4.AbsOrigin.Z; + + trigger.Collision.CapsuleRadius = 10; + trigger.Collision.BoundingRadius = 10; + + trigger.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_TRIGGER; + trigger.Collision.EnablePhysics = 1; + trigger.Collision.TriggerBloat = 0; + + trigger.Collision.SurroundType = SurroundingBoundsType_t.USE_OBB_COLLISION_BOUNDS; + trigger.Collision.CollisionAttribute.CollisionFunctionMask = 39; + trigger.Collision.CollisionAttribute.CollisionGroup = 2; + + trigger.DispatchSpawn(); + triggerC4 = trigger; + } + + private static void RemoveBomb() + { + if (plantedC4 != null && plantedC4.IsValid) + plantedC4.Remove(); + if (triggerC4 != null && triggerC4.IsValid) + triggerC4.Remove(); + SkillUtils.TerminateRound(CsTeam.CounterTerrorist); + } + + private static HookResult 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 HookResult.Continue; + + CCSPlayerPawn attackerPawn = new CCSPlayerPawn(param2.Attacker.Value.Handle); + + if (attackerPawn.DesignerName != "player" || param.DesignerName != "trigger_multiple") + return HookResult.Continue; + + CTriggerMultiple trigger = new CTriggerMultiple(param.Handle); + + if (attackerPawn == null || attackerPawn.Controller?.Value == null || trigger == null || !trigger.Globalname.StartsWith("planted_bomb_prop_")) + return HookResult.Continue; + + CCSPlayerController attacker = attackerPawn.Controller.Value.As(); + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + if (playerInfo == null || playerInfo.Skill != skillName) return HookResult.Continue; + + bombHealth -= (int)param2.TotalledDamage; + if (bombHealth <= 0) + { + RemoveBomb(); + return HookResult.Continue; + } + + Server.PrintToChatAll($" {ChatColors.Gold}{Localization.GetTranslation("fragilebomb_bomb_health")}: {ChatColors.Red}{bombHealth}{ChatColors.Gold}/{ChatColors.Green}{maxBombHealth}"); + return HookResult.Continue; + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int MaxBombHealth { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#5d00ff", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool needsTeammates = false, int maxBombHealth = 1000) : base(skill, active, color, onlyTeam, needsTeammates) + { + MaxBombHealth = maxBombHealth; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/FriendlyFire.cs b/jRandomSkills - SRC Files/src/player/skills/FriendlyFire.cs new file mode 100644 index 0000000..0080b6f --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/FriendlyFire.cs @@ -0,0 +1,54 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class FriendlyFire : ISkill + { + private const Skills skillName = Skills.FriendlyFire; + private static float healthMultiplier = Config.GetValue(skillName, "healthMultiplier"); + private static string[] nades = { "inferno", "flashbang", "smokegrenade", "decoy", "hegrenade" }; + + public static void LoadSkill() + { + if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) + return; + + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var damage = @event.DmgHealth; + var victim = @event.Userid; + var attacker = @event.Attacker; + var weapon = @event.Weapon; + HitGroup_t hitgroup = (HitGroup_t)@event.Hitgroup; + + if (nades.Contains(weapon)) return HookResult.Continue; + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + if (playerInfo?.Skill != skillName || attacker.Team != victim.Team) return HookResult.Continue; + + Server.ExecuteCommand("mp_autokick 0"); + + var pawn = victim.PlayerPawn.Value; + SkillUtils.AddHealth(pawn, damage + (int)(damage * healthMultiplier), pawn.MaxHealth); + + return HookResult.Continue; + }); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float HealthMultiplier { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff0000", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = true, float healthMultiplier = 1.5f) : base(skill, active, color, onlyTeam, needsTeammates) + { + HealthMultiplier = healthMultiplier; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/FrozenDecoy.cs b/jRandomSkills - SRC Files/src/player/skills/FrozenDecoy.cs index bdbfe73..75f5294 100644 --- a/jRandomSkills - SRC Files/src/player/skills/FrozenDecoy.cs +++ b/jRandomSkills - SRC Files/src/player/skills/FrozenDecoy.cs @@ -1,8 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Entities.Constants; -using CounterStrikeSharp.API.Modules.Memory; -using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static CounterStrikeSharp.API.Core.Listeners; @@ -12,22 +10,21 @@ namespace jRandomSkills { public class FrozenDecoy : ISkill { - private static Skills skillName = Skills.FrozenDecoy; - private static Dictionary gravities = new Dictionary(); - private static List players = new List(); - private static Dictionary triggers = new Dictionary(); + private const Skills skillName = Skills.FrozenDecoy; + private static float decoyRadius = Config.GetValue(skillName, "triggerRadius"); + private static int slownessMultiplier = Config.GetValue(skillName, "slownessMultiplier"); + private static List decoys = new List(); public static void LoadSkill() { if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) return; - SkillUtils.RegisterSkill(skillName, "#00eaff"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { - gravities.Clear(); - players.Clear(); + decoys.Clear(); return HookResult.Continue; }); @@ -47,71 +44,37 @@ namespace jRandomSkills return HookResult.Continue; }); - Instance.RegisterEventHandler((@event, @info) => + Instance.RegisterEventHandler((@event, info) => { var player = @event.Userid; - if (!Instance.IsPlayerValid(player)) return HookResult.Continue; - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo?.Skill != skillName) return HookResult.Continue; - - var trigger = Utilities.CreateEntityByName("trigger_multiple"); - if (trigger == null) return HookResult.Continue; - - trigger.Collision.SolidType = SolidType_t.SOLID_CAPSULE; - trigger.Collision.SolidFlags = 0; - trigger.Spawnflags = 1; - trigger.Globalname = $"frozen_decoy_{trigger.Index}"; - trigger.Collision.SolidFlags = 1; - - trigger.AbsOrigin.X = @event.X; - trigger.AbsOrigin.Y = @event.Y; - trigger.AbsOrigin.Z = @event.Z; - - trigger.Collision.CapsuleRadius = 150; - trigger.Collision.BoundingRadius = 150; - - trigger.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_TRIGGER; - trigger.Collision.EnablePhysics = 1; - trigger.Collision.TriggerBloat = 0; - - trigger.Collision.SurroundType = SurroundingBoundsType_t.USE_OBB_COLLISION_BOUNDS; - trigger.Collision.CollisionAttribute.CollisionFunctionMask = 39; - trigger.Collision.CollisionAttribute.CollisionGroup = 2; - - trigger.DispatchSpawn(); - triggers.Add(@event.Entityid, trigger); + decoys.Add(new Vector(@event.X, @event.Y, @event.Z)); return HookResult.Continue; }); Instance.RegisterEventHandler((@event, @info) => { var player = @event.Userid; - if (!Instance.IsPlayerValid(player)) return HookResult.Continue; - - if (triggers.TryGetValue(@event.Entityid, out var existingTrigger)) - { - existingTrigger.AcceptInput("Kill"); - triggers.Remove(@event.Entityid); - } - + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + decoys.RemoveAll(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z); return HookResult.Continue; }); Instance.RegisterListener(() => { - foreach (CCSPlayerPawn player in players) - { - player.VelocityModifier = 0; - Utilities.SetStateChanged(player, "CCSPlayerPawn", "m_flVelocityModifier"); - - if ((player.Flags & (uint)PlayerFlags.FL_ONGROUND) != 0) - player.GravityScale = float.MaxValue; - } + foreach (Vector decoyPos in decoys) + foreach (var player in Utilities.GetPlayers()) + { + double distance = SkillUtils.GetDistance(decoyPos, player.PlayerPawn.Value.AbsOrigin); + if (distance <= decoyRadius) + { + double modifier = Math.Clamp(distance / decoyRadius, 0f, 1f); + player.PlayerPawn.Value.VelocityModifier = (float)Math.Pow(modifier, slownessMultiplier); + } + } }); - - VirtualFunctions.CBaseTrigger_StartTouchFunc.Hook(StartTouchFun, HookMode.Post); - VirtualFunctions.CBaseTrigger_EndTouchFunc.Hook(EndTouchFunc, HookMode.Post); } public static void EnableSkill(CCSPlayerController player) @@ -119,46 +82,15 @@ namespace jRandomSkills SkillUtils.TryGiveWeapon(player, CsItem.DecoyGrenade); } - private static HookResult StartTouchFun(DynamicHook h) + public class SkillConfig : Config.DefaultSkillInfo { - CBaseTrigger trigger = h.GetParam(0); - CBaseEntity entity = h.GetParam(1); - - if (trigger == null || entity == null) - return HookResult.Continue; -; - CCSPlayerPawn player = new CCSPlayerPawn(entity.Handle); - if (player == null) return HookResult.Continue; - - if (string.IsNullOrEmpty(trigger?.Globalname) || trigger?.Globalname?.StartsWith("frozen_decoy_") == false) - return HookResult.Continue; - - if (!players.Contains(player)) - players.Add(player); - - gravities.TryAdd(player.Index, player.GravityScale); - return HookResult.Continue; - } - - private static HookResult EndTouchFunc(DynamicHook h) - { - var trigger = h.GetParam(0); - var entity = h.GetParam(1); - - if (trigger == null || entity == null) return HookResult.Continue; - - CCSPlayerPawn player = new CCSPlayerPawn(entity.Handle); - if (player == null) return HookResult.Continue; - - if (string.IsNullOrEmpty(trigger?.Globalname) || trigger?.Globalname?.StartsWith("frozen_decoy_") == false) - return HookResult.Continue; - - if (players.Contains(player)) - players.Remove(player); - - float grav = gravities.GetValueOrDefault(player.Index); - player.GravityScale = Math.Min(grav, 1); - return HookResult.Continue; + public float TriggerRadius { get; set; } + public int SlownessMultiplier { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#00eaff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float triggerRadius = 180, int slownessMultiplier = 5) : base(skill, active, color, onlyTeam, needsTeammates) + { + TriggerRadius = triggerRadius; + SlownessMultiplier = slownessMultiplier; + } } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Ghost.cs b/jRandomSkills - SRC Files/src/player/skills/Ghost.cs index 8df0e7b..52677a0 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Ghost.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Ghost.cs @@ -1,6 +1,7 @@ using System.Drawing; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using jRandomSkills.src.utils; using static CounterStrikeSharp.API.Core.Listeners; @@ -10,7 +11,7 @@ namespace jRandomSkills { public class Ghost : ISkill { - private static Skills skillName = Skills.Ghost; + private const Skills skillName = Skills.Ghost; private static string[] disabledWeapons = { "weapon_deagle", @@ -55,7 +56,7 @@ namespace jRandomSkills if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) return; - SkillUtils.RegisterSkill(skillName, "#FFFFFF"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -110,6 +111,13 @@ namespace jRandomSkills return HookResult.Continue; }); + Instance.RegisterEventHandler((@event, info) => + { + foreach (var player in Utilities.GetPlayers()) + SetWeaponAttack(player, false); + return HookResult.Continue; + }); + Instance.RegisterListener(OnTick); } @@ -199,5 +207,12 @@ namespace jRandomSkills var hudContent = infoLine + skillLine + remainingLine; player.PrintToCenterHtml(hudContent); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#FFFFFF", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Glaz.cs b/jRandomSkills - SRC Files/src/player/skills/Glaz.cs new file mode 100644 index 0000000..c568bd7 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Glaz.cs @@ -0,0 +1,89 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Glaz : ISkill + { + private const Skills skillName = Skills.Glaz; + private static bool exists = false; + private static List smokes = new List(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, @info) => + { + smokes.Clear(); + Instance.AddTimer(2f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + EnableSkill(player); + } + + if (exists) + Instance.RegisterListener(CheckTransmit); + }); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, @info) => + { + smokes.Clear(); + if (exists) + Instance.RemoveListener(CheckTransmit); + exists = false; + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, @info) => + { + smokes.Add(@event.Entityid); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, @info) => + { + smokes.Remove(@event.Entityid); + return HookResult.Continue; + }); + } + + public static void CheckTransmit([CastFrom(typeof(nint))] CCheckTransmitInfoList infoList) + { + foreach (var (info, player) in infoList) + { + if (player == null) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + + foreach (var smoke in smokes) + info.TransmitEntities.Remove(smoke); + } + } + + public static void EnableSkill(CCSPlayerController player) + { + exists = true; + SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#5d00ff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Glitch.cs b/jRandomSkills - SRC Files/src/player/skills/Glitch.cs index daa902f..7175200 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Glitch.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Glitch.cs @@ -9,12 +9,12 @@ namespace jRandomSkills { public class Glitch : ISkill { - private static Skills skillName = Skills.Glitch; + private const Skills skillName = Skills.Glitch; private static HashSet glitchedPlayers = new HashSet(); public static void LoadSkill() { - SkillUtils.RegisterSkill(skillName, "#f542ef", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -80,7 +80,7 @@ namespace jRandomSkills if (enemies.Length > 0) { foreach (var enemy in enemies) - player.PrintToChat($" {ChatColors.Green}⠀⠀⠀{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); } else player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); @@ -92,5 +92,12 @@ namespace jRandomSkills player.ReplicateConVar("sv_disable_radar", "0"); glitchedPlayers.Remove(player); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#f542ef", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Glue.cs b/jRandomSkills - SRC Files/src/player/skills/Glue.cs new file mode 100644 index 0000000..8be8517 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Glue.cs @@ -0,0 +1,41 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Glue : ISkill + { + private const Skills skillName = Skills.Glue; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterListener(@event => + { + var name = @event.DesignerName; + if (!name.EndsWith("_projectile")) + return; + + var grenade = @event.As(); + if (grenade.OwnerEntity.Value == null || !grenade.OwnerEntity.Value.IsValid) return; + + var pawn = grenade.OwnerEntity.Value.As(); + var player = pawn.Controller.Value.As(); + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return; + grenade.Bounces = 555; + }); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#fff52e", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/GodMode.cs b/jRandomSkills - SRC Files/src/player/skills/GodMode.cs index dd0a8ab..0221b22 100644 --- a/jRandomSkills - SRC Files/src/player/skills/GodMode.cs +++ b/jRandomSkills - SRC Files/src/player/skills/GodMode.cs @@ -10,16 +10,14 @@ namespace jRandomSkills { public class GodMode : ISkill { - private static Skills skillName = Skills.GodMode; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.GodMode; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); + private static float duration = Config.GetValue(skillName, "duration"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#e0d83a"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -108,12 +106,6 @@ namespace jRandomSkills player.PrintToCenterHtml(hudContent); } - private static void ActiveUse(CCSPlayerController player) - { - if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo)) - skillInfo.CanUse = true; - } - public static void UseSkill(CCSPlayerController player) { var playerPawn = player.PlayerPawn.Value; @@ -130,7 +122,7 @@ namespace jRandomSkills player.PrintToChat($" {ChatColors.Green} {Localization.GetTranslation("godmode_on")}"); player.PlayerPawn.Value.TakesDamage = false; - Instance.AddTimer(2, () => { + Instance.AddTimer(duration, () => { if (player.IsValid && player.PawnIsAlive) { player.PlayerPawn.Value.TakesDamage = true; @@ -150,5 +142,16 @@ namespace jRandomSkills public DateTime Cooldown { get; set; } public DateTime LastClick { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public float Duration { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#e0d83a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 30f, float duration = 2f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + Duration = duration; + } + } } } \ 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 new file mode 100644 index 0000000..314a385 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/HealingSmoke.cs @@ -0,0 +1,121 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static CounterStrikeSharp.API.Core.Listeners; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class HealingSmoke : ISkill + { + private const Skills skillName = Skills.HealingSmoke; + private static int smokeHeal = Config.GetValue(skillName, "smokeHeal"); + private static float smokeRadius = Config.GetValue(skillName, "smokeRadius"); + private static List smokes = new List(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + smokes.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + smokes.Add(new Vector(@event.X, @event.Y, @event.Z)); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, @info) => + { + var player = @event.Userid; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + smokes.RemoveAll(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z); + return HookResult.Continue; + }); + + Instance.RegisterListener(@event => + { + var name = @event.DesignerName; + if (name != "smokegrenade_projectile") return; + + var grenade = @event.As(); + var pawn = grenade.OwnerEntity.Value.As(); + var player = pawn.Controller.Value.As(); + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return; + + Server.NextFrame(() => + { + var smoke = @event.As(); + smoke.SmokeColor.X = 0; + smoke.SmokeColor.Y = 255; + smoke.SmokeColor.Z = 0; + }); + }); + + Instance.RegisterListener(() => + { + foreach (Vector smokePos in smokes) + foreach (var player in Utilities.GetPlayers()) + if (Server.TickCount % 17 == 0) + if (SkillUtils.GetDistance(smokePos, player.PlayerPawn.Value.AbsOrigin) <= smokeRadius) + AddHealth(player.PlayerPawn.Value, smokeHeal); + }); + } + + public static void EnableSkill(CCSPlayerController player) + { + SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade); + } + + private static void AddHealth(CCSPlayerPawn player, int health) + { + if (player.LifeState != (byte)LifeState_t.LIFE_ALIVE) + return; + + if (player.Health != player.MaxHealth) + player.EmitSound("Healthshot.Success"); + + player.Health = Math.Min(player.Health + health, player.MaxHealth); + Utilities.SetStateChanged(player, "CBaseEntity", "m_iHealth"); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int SmokeHeal { get; set; } + public float SmokeRadius { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#1fe070", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int smokeHeal = 1, float smokeRadius = 180) : base(skill, active, color, onlyTeam, needsTeammates) + { + SmokeHeal = smokeHeal; + SmokeRadius = smokeRadius; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Hermit.cs b/jRandomSkills - SRC Files/src/player/skills/Hermit.cs index 6e44800..917a57c 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Hermit.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Hermit.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -7,7 +8,7 @@ namespace jRandomSkills { public class Hermit : ISkill { - private static Skills skillName = Skills.Hermit; + private const Skills skillName = Skills.Hermit; private static readonly Dictionary maxReserveAmmo = new Dictionary { { "weapon_glock", 120 }, @@ -47,12 +48,11 @@ namespace jRandomSkills { "weapon_negev", 300 } }; + private static int healthToAdd = Config.GetValue(skillName, "healthToAdd"); + public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#ded678"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -74,10 +74,19 @@ namespace jRandomSkills Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_iClip1"); Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_pReserveAmmo"); - SkillUtils.AddHealth(pawn, 25); + SkillUtils.AddHealth(pawn, healthToAdd); return HookResult.Continue; }); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int HealthToAdd { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ded678", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int healthToAdd = 25) : base(skill, active, color, onlyTeam, needsTeammates) + { + HealthToAdd = healthToAdd; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/HolyHandGrenade.cs b/jRandomSkills - SRC Files/src/player/skills/HolyHandGrenade.cs index 5d6dd36..6579dcc 100644 --- a/jRandomSkills - SRC Files/src/player/skills/HolyHandGrenade.cs +++ b/jRandomSkills - SRC Files/src/player/skills/HolyHandGrenade.cs @@ -1,6 +1,7 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -8,14 +9,13 @@ namespace jRandomSkills { public class HolyHandGrenade : ISkill { - private static Skills skillName = Skills.HolyHandGrenade; + private const Skills skillName = Skills.HolyHandGrenade; + private static float damageMultiplier = Config.GetValue(skillName, "damageMultiplier"); + private static float damageRadiusMultiplier = Config.GetValue(skillName, "damageRadiusMultiplier"); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#ffdd00"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -44,13 +44,14 @@ namespace jRandomSkills var hegrenade = @event.As(); var playerPawn = hegrenade.Thrower.Value; + if (playerPawn == null || !playerPawn.IsValid) return; var player = Utilities.GetPlayers().FirstOrDefault(p => p.PlayerPawn.Index == playerPawn.Index); var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo?.Skill != skillName) return; - hegrenade.Damage *= 2; - hegrenade.DmgRadius *= 2; + hegrenade.Damage *= damageMultiplier; + hegrenade.DmgRadius *= damageRadiusMultiplier; }); }); } @@ -59,5 +60,16 @@ namespace jRandomSkills { SkillUtils.TryGiveWeapon(player, CsItem.HEGrenade); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float DamageMultiplier { get; set; } + public float DamageRadiusMultiplier { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffdd00", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float damageMultiplier = 2f, float damageRadiusMultiplier = 2f) : base(skill, active, color, onlyTeam, needsTeammates) + { + DamageMultiplier = damageMultiplier; + DamageRadiusMultiplier = damageRadiusMultiplier; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Impostor.cs b/jRandomSkills - SRC Files/src/player/skills/Impostor.cs index f03d92e..005a5fe 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Impostor.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Impostor.cs @@ -9,16 +9,13 @@ namespace jRandomSkills { public class Impostor : ISkill { - private static Skills skillName = Skills.Impostor; + private const Skills skillName = Skills.Impostor; private static readonly string defaultCTModel = "characters/models/ctm_sas/ctm_sas.vmdl"; private static readonly string defaultTModel = "characters/models/tm_phoenix_heavy/tm_phoenix_heavy.vmdl"; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#99140B"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -75,5 +72,12 @@ namespace jRandomSkills pawn.Render = Color.FromArgb(255, originalRender.R, originalRender.G, originalRender.B); }); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#99140B", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/InfiniteAmmo.cs b/jRandomSkills - SRC Files/src/player/skills/InfiniteAmmo.cs index 23e400e..e7f6462 100644 --- a/jRandomSkills - SRC Files/src/player/skills/InfiniteAmmo.cs +++ b/jRandomSkills - SRC Files/src/player/skills/InfiniteAmmo.cs @@ -1,4 +1,5 @@ using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -6,14 +7,11 @@ namespace jRandomSkills { public class InfiniteAmmo : ISkill { - private static Skills skillName = Skills.InfiniteAmmo; + private const Skills skillName = Skills.InfiniteAmmo; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#0000FF"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -70,5 +68,12 @@ namespace jRandomSkills activeWeaponHandle.Value.Clip1 = 100; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#0000FF", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Jackal.cs b/jRandomSkills - SRC Files/src/player/skills/Jackal.cs new file mode 100644 index 0000000..e1ae942 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Jackal.cs @@ -0,0 +1,184 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using System.Drawing; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Jackal : ISkill + { + private const Skills skillName = Skills.Jackal; + private static int maxStepBeam = Config.GetValue(skillName, "maxStepBeam"); + private static bool exists = false; + + private static Dictionary authorBeams = new Dictionary(); + private static Dictionary> stepBeams = new Dictionary>(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + + if (exists) + Instance.RegisterListener(CheckTransmit); + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + foreach (var beams in stepBeams.Values) + foreach (var beam in beams) + if (beam != null && beam.IsValid) + beam.Remove(); + foreach (var player in stepBeams.Keys) + DisableSkill(player); + authorBeams.Clear(); + stepBeams.Clear(); + + if (exists) + Instance.RemoveListener(CheckTransmit); + exists = false; + return HookResult.Continue; + }); + + Instance.RegisterListener(OnTick); + } + + private static void OnTick() + { + foreach (var step in stepBeams) + { + if (Server.TickCount % 8 != 0) continue; + + var pawn = step.Key.PlayerPawn.Value; + var beams = step.Value; + if (pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) continue; + Vector lastBeamVector = beams.LastOrDefault()?.EndPos ?? pawn.AbsOrigin; + + var newBeam = CreateBeamStep(step.Key.Team, lastBeamVector, pawn.AbsOrigin); + if (newBeam != null) + beams.Add(newBeam); + + if (beams.Count >= maxStepBeam) + { + beams[0].Remove(); + beams.RemoveAt(0); + } + } + } + + public static void CheckTransmit([CastFrom(typeof(nint))] CCheckTransmitInfoList infoList) + { + foreach(var (info, player) in infoList) + { + if (player == null) continue; + foreach (var step in stepBeams) + { + var enemy = step.Key; + var beams = step.Value; + foreach (var beam in beams) + if (!authorBeams.TryGetValue(player.Index, out uint enemyIndex) || enemyIndex != enemy.Index) + info.TransmitEntities.Remove(beam); + } + } + } + + public static CBeam CreateBeamStep(CsTeam team, Vector start, Vector stop) + { + CBeam beam = Utilities.CreateEntityByName("beam")!; + if (beam == null) return null; + + beam.Render = team == CsTeam.Terrorist ? Color.FromArgb(100, 255, 165, 0) : Color.FromArgb(100, 173, 216, 230); + beam.Width = 2.0f; + beam.EndWidth = 2.0f; + beam.Teleport(start); + + beam.EndPos.X = stop.X; + beam.EndPos.Y = stop.Y; + beam.EndPos.Z = stop.Z; + + beam.DispatchSpawn(); + beam.AcceptInput("FollowEntity", beam, null!, ""); + return beam; + } + + 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.SkillChance == 1) + { + player.PrintToChat($" {ChatColors.Red}{Localization.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}" + Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")); + return; + } + + authorBeams.Add(player.Index, enemy.Index); + stepBeams.Add(enemy, new List()); + playerInfo.SkillChance = 1; + player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("jackal_player_info", enemy.PlayerName)); + } + + public static void EnableSkill(CCSPlayerController player) + { + exists = true; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + playerInfo.SkillChance = 0; + + SkillUtils.PrintToChat(player, Localization.GetTranslation("jackal") + ":", false); + + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("jackal_select_info")}"); + var enemies = Utilities.GetPlayers().Where(p => p.Team != player.Team && p.IsValid && !p.IsBot).ToArray(); + if (enemies.Length > 0) + { + foreach (var enemy in enemies) + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + } + else + player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("selectplayerskill_command")} {ChatColors.Red}index"); + } + + public static void DisableSkill(CCSPlayerController player) + { + authorBeams.Remove(player.Index); + stepBeams.Remove(player); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int MaxStepBeam { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#f542ef", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int maxStepBeam = 50) : base(skill, active, color, onlyTeam, needsTeammates) + { + MaxStepBeam = maxStepBeam; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Jammer.cs b/jRandomSkills - SRC Files/src/player/skills/Jammer.cs index 2c62807..cd016fc 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Jammer.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Jammer.cs @@ -9,12 +9,12 @@ namespace jRandomSkills { public class Jammer : ISkill { - private static Skills skillName = Skills.Jammer; + private const Skills skillName = Skills.Jammer; private static HashSet jammedPlayers = new HashSet(); public static void LoadSkill() { - SkillUtils.RegisterSkill(skillName, "#42f5a7", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -90,7 +90,7 @@ namespace jRandomSkills if (enemies.Length > 0) { foreach (var enemy in enemies) - player.PrintToChat($" {ChatColors.Green}⠀⠀⠀{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); } else player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); @@ -102,5 +102,12 @@ namespace jRandomSkills SetCrosshair(player, true); jammedPlayers.Remove(player); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#42f5a7", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/JumpBan.cs b/jRandomSkills - SRC Files/src/player/skills/JumpBan.cs new file mode 100644 index 0000000..3af5346 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/JumpBan.cs @@ -0,0 +1,121 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class JumpBan : ISkill + { + private const Skills skillName = Skills.JumpBan; + private static Dictionary bannedPlayers = new Dictionary(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + bannedPlayers.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + if (!bannedPlayers.TryGetValue(player.PlayerPawn.Value, out _)) return HookResult.Continue; + bannedPlayers[player.PlayerPawn.Value] = Server.TickCount + 10; + return HookResult.Stop; + }); + + Instance.RegisterListener(OnTick); + } + + private static void OnTick() + { + foreach (var item in bannedPlayers) + { + var pawn = item.Key; + var time = item.Value; + if (time > Server.TickCount) + pawn.AbsVelocity.Z = -100; + } + } + + 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.SkillChance == 1) + { + player.PrintToChat($" {ChatColors.Red}{Localization.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}" + Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")); + return; + } + + bannedPlayers[enemy.PlayerPawn.Value] = 0; + playerInfo.SkillChance = 1; + player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("jumpban_player_info", enemy.PlayerName)); + enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("jumpban_enemy_info")); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + playerInfo.SkillChance = 0; + + SkillUtils.PrintToChat(player, Localization.GetTranslation("jumpban") + ":", false); + + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("jumpban_select_info")}"); + var enemies = Utilities.GetPlayers().Where(p => p.Team != player.Team && p.IsValid && !p.IsBot).ToArray(); + if (enemies.Length > 0) + { + foreach (var enemy in enemies) + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + } + else + player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("selectplayerskill_command")} {ChatColors.Red}index"); + } + + public static void DisableSkill(CCSPlayerController player) + { + bannedPlayers.Remove(player.PlayerPawn.Value); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#b01e5d", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/JumpingJack.cs b/jRandomSkills - SRC Files/src/player/skills/JumpingJack.cs new file mode 100644 index 0000000..6156ef3 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/JumpingJack.cs @@ -0,0 +1,37 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class JumpingJack : ISkill + { + private const Skills skillName = Skills.JumpingJack; + private static int addHealth = Config.GetValue(skillName, "healthToAdd"); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + SkillUtils.AddHealth(player.PlayerPawn.Value, addHealth); + return HookResult.Continue; + }); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int HealthToAdd { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#a86eff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int healthToAdd = 3) : base(skill, active, color, onlyTeam, needsTeammates) + { + HealthToAdd = healthToAdd; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/KillerFlash.cs b/jRandomSkills - SRC Files/src/player/skills/KillerFlash.cs index e01ed40..1e60400 100644 --- a/jRandomSkills - SRC Files/src/player/skills/KillerFlash.cs +++ b/jRandomSkills - SRC Files/src/player/skills/KillerFlash.cs @@ -1,6 +1,7 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -8,14 +9,12 @@ namespace jRandomSkills { public class KillerFlash : ISkill { - private static Skills skillName = Skills.KillerFlash; + private const Skills skillName = Skills.KillerFlash; + private static float flashDuration = Config.GetValue(skillName, "flashDuration"); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#57bcff"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -42,7 +41,7 @@ namespace jRandomSkills var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); var attackerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); - if (attackerInfo?.Skill == skillName && playerInfo?.Skill != Skills.AntyFlash && player?.PlayerPawn.Value.FlashDuration >= 1) + if (attackerInfo?.Skill == skillName && playerInfo?.Skill != Skills.AntyFlash && player?.PlayerPawn.Value.FlashDuration >= flashDuration) player?.PlayerPawn?.Value?.CommitSuicide(false, true); return HookResult.Continue; @@ -53,5 +52,14 @@ namespace jRandomSkills { SkillUtils.TryGiveWeapon(player, CsItem.FlashbangGrenade); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float FlashDuration { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#57bcff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float flashDuration = 1f) : base(skill, active, color, onlyTeam, needsTeammates) + { + FlashDuration = flashDuration; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/LifeSwap.cs b/jRandomSkills - SRC Files/src/player/skills/LifeSwap.cs new file mode 100644 index 0000000..f497bcf --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/LifeSwap.cs @@ -0,0 +1,103 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class LifeSwap : ISkill + { + private const Skills skillName = Skills.LifeSwap; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + } + + 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.SkillChance == 1) + { + player.PrintToChat($" {ChatColors.Red}{Localization.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}" + Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")); + return; + } + + SwapHealth(player, enemy); + playerInfo.SkillChance = 1; + player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("lifeswap_player_info", enemy.PlayerName)); + enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("lifeswap_enemy_info")); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + playerInfo.SkillChance = 0; + + SkillUtils.PrintToChat(player, Localization.GetTranslation("lifeswap") + ":", false); + + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("lifeswap_select_info")}"); + var enemies = Utilities.GetPlayers().Where(p => p.Team != player.Team && p.IsValid && !p.IsBot).ToArray(); + if (enemies.Length > 0) + { + foreach (var enemy in enemies) + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + } + else + player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("selectplayerskill_command")} {ChatColors.Red}index"); + } + + private static void SwapHealth(CCSPlayerController player, CCSPlayerController enemy) + { + var playerPawn = player.PlayerPawn.Value; + var enemyPawn = enemy.PlayerPawn.Value; + + if (playerPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE || enemyPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) + return; + + int playerHealth = playerPawn.Health; + playerPawn.Health = enemyPawn.Health; + enemyPawn.Health = playerHealth; + Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_iHealth"); + Utilities.SetStateChanged(enemyPawn, "CBaseEntity", "m_iHealth"); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#a3651a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ 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 new file mode 100644 index 0000000..d6c90c6 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/LongKnife.cs @@ -0,0 +1,74 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; +using CS2TraceRay.Class; +using CS2TraceRay.Struct; +using jRandomSkills.src.player; +using System.Numerics; +using static jRandomSkills.jRandomSkills; +using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; + +namespace jRandomSkills +{ + public class LongKnife : ISkill + { + private const Skills skillName = Skills.LongKnife; + private static float maxDistance = Config.GetValue(skillName, "maxDistance"); + + public unsafe static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + if (!Instance.IsPlayerValid(player)) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + var activeWeapon = player.Pawn.Value.WeaponServices.ActiveWeapon.Value; + if (activeWeapon?.DesignerName != "weapon_knife") return HookResult.Continue; + + var pawn = player.PlayerPawn.Value; + Vector eyePos = new Vector(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z + pawn.ViewOffset.Z); + Vector endPos = eyePos + SkillUtils.GetForwardVector(pawn.EyeAngles) * maxDistance; + + Ray ray = new Ray(Vector3.Zero); + CTraceFilter filter = new CTraceFilter(pawn.Index, pawn.Index) + { + m_nObjectSetMask = 0xf, + m_nCollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER_MOVEMENT, + m_nInteractsWith = pawn.GetInteractsWith(), + m_nInteractsExclude = 0, + m_nBits = 11, + m_bIterateEntities = true, + m_bHitTriggers = false, + m_nInteractsAs = 0x40000 + }; + + filter.m_nHierarchyIds[0] = pawn.GetHierarchyId(); + filter.m_nHierarchyIds[1] = 0; + CGameTrace trace = TraceRay.TraceHull(eyePos, endPos, filter, ray); + + if (!trace.HitPlayer(out CCSPlayerController? target) || target == null) + return HookResult.Continue; + + if (target.Handle == player.Handle || trace.Distance() <= 70) return HookResult.Continue; + target.PlayerPawn.Value.EmitSound("Player.DamageBody.Onlooker"); + SkillUtils.TakeHealth(target.PlayerPawn.Value, Instance.Random.Next(21, 34)); + return HookResult.Continue; + }); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float MaxDistance { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#c9f8ff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float maxDistance = 4096f) : base(skill, active, color, onlyTeam, needsTeammates) + { + MaxDistance = maxDistance; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/LongZeus.cs b/jRandomSkills - SRC Files/src/player/skills/LongZeus.cs new file mode 100644 index 0000000..e7de918 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/LongZeus.cs @@ -0,0 +1,94 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; +using CS2TraceRay.Class; +using CS2TraceRay.Struct; +using jRandomSkills.src.player; +using System.Numerics; +using static jRandomSkills.jRandomSkills; +using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; + +namespace jRandomSkills +{ + public class LongZeus : ISkill + { + private const Skills skillName = Skills.LongZeus; + private static float maxDistance = Config.GetValue(skillName, "maxDistance"); + + public unsafe static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + if (!Instance.IsPlayerValid(player)) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + var activeWeapon = player.Pawn.Value.WeaponServices.ActiveWeapon.Value; + if (activeWeapon?.DesignerName != "weapon_taser") return HookResult.Continue; + + var pawn = player.PlayerPawn.Value; + Vector eyePos = new Vector(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z + pawn.ViewOffset.Z); + Vector endPos = eyePos + SkillUtils.GetForwardVector(pawn.EyeAngles) * maxDistance; + + Ray ray = new Ray(Vector3.Zero); + CTraceFilter filter = new CTraceFilter(pawn.Index, pawn.Index) + { + m_nObjectSetMask = 0xf, + m_nCollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER_MOVEMENT, + m_nInteractsWith = pawn.GetInteractsWith(), + m_nInteractsExclude = 0, + m_nBits = 11, + m_bIterateEntities = true, + m_bHitTriggers = false, + m_nInteractsAs = 0x40000 + }; + + filter.m_nHierarchyIds[0] = pawn.GetHierarchyId(); + filter.m_nHierarchyIds[1] = 0; + CGameTrace trace = TraceRay.TraceHull(eyePos, endPos, filter, ray); + + if (!trace.HitPlayer(out CCSPlayerController? target) || target == null) + return HookResult.Continue; + + if (target.Handle == player.Handle) return HookResult.Continue; + SkillUtils.TakeHealth(target.PlayerPawn.Value, 9999); + return HookResult.Continue; + }); + } + + public static void EnableSkill(CCSPlayerController player) + { + SkillUtils.TryGiveWeapon(player, CsItem.Zeus); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float MaxDistance { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#6effc7", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float maxDistance = 4096f) : base(skill, active, color, onlyTeam, needsTeammates) + { + MaxDistance = maxDistance; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Medic.cs b/jRandomSkills - SRC Files/src/player/skills/Medic.cs index 28e08d5..321cd29 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Medic.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Medic.cs @@ -1,60 +1,150 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static CounterStrikeSharp.API.Core.Listeners; using static jRandomSkills.jRandomSkills; namespace jRandomSkills { public class Medic : ISkill { - private static Skills skillName = Skills.Medic; + private const Skills skillName = Skills.Medic; + private static int healthToAdd = Config.GetValue(skillName, "healthToAdd"); + private static int healthShotLimit = Config.GetValue(skillName, "healthShotLimit"); + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); + private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); - SkillUtils.RegisterSkill(skillName, "#42FF5F"); - Instance.RegisterEventHandler((@event, info) => { - Instance.AddTimer(0.1f, () => + Instance.AddTimer(0.1f, () => { foreach (var player in Utilities.GetPlayers()) { - if (!Instance.IsPlayerValid(player)) continue; - player.RemoveItemByDesignerName("weapon_healthshot"); + if (!Instance.IsPlayerValid(player)) return; var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - if (playerInfo?.Skill != skillName) continue; - EnableSkill(player); + if (playerInfo?.Skill == skillName) + EnableSkill(player); } }); return HookResult.Continue; }); - + Instance.RegisterEventHandler((@event, info) => + { + SkillPlayerInfo.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + if (SkillPlayerInfo.ContainsKey(player.SteamID)) + SkillPlayerInfo.Remove(player.SteamID); + return HookResult.Continue; + }); + + Instance.RegisterListener(() => { foreach (var player in Utilities.GetPlayers()) { - if (!Instance.IsPlayerValid(player)) return HookResult.Continue; - DisableSkill(player); + 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); } - - return HookResult.Continue; }); } public static void EnableSkill(CCSPlayerController player) { - int healthshot = Instance.Random.Next(1, 10); - SkillUtils.TryGiveWeapon(player, CsItem.Healthshot, healthshot); + SkillPlayerInfo[player.SteamID] = new PlayerSkillInfo + { + SteamID = player.SteamID, + CanUse = true, + Cooldown = DateTime.MinValue, + Count = healthShotLimit, + }; } public static void DisableSkill(CCSPlayerController player) { - player.RemoveItemByDesignerName("weapon_healthshot"); + if (SkillPlayerInfo.ContainsKey(player.SteamID)) + SkillPlayerInfo.Remove(player.SteamID); + } + + private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo) + { + float cooldown = 0; + if (skillInfo != null) + { + float time = (int)(skillInfo.Cooldown.AddSeconds(timerCooldown) - DateTime.Now).TotalSeconds; + cooldown = Math.Max(time, 0); + + if (cooldown == 0 && skillInfo?.CanUse == false) + skillInfo.CanUse = true; + } + + var skillData = SkillData.Skills.FirstOrDefault(s => s.Skill == skillName); + if (skillData == null) return; + + string infoLine = $"{Localization.GetTranslation("your_skill")}:
"; + string skillLine = $"{skillData.Name}
"; + string remainingLine = cooldown != 0 + ? $"{Localization.GetTranslation("hud_info", $"{cooldown}")}
" + : $"{skillInfo.Count}/{healthShotLimit}
"; + + var hudContent = infoLine + skillLine + remainingLine; + player.PrintToCenterHtml(hudContent); + } + + 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.Count != 0) + { + skillInfo.CanUse = false; + skillInfo.Cooldown = DateTime.Now; + skillInfo.Count -= 1; + SkillUtils.AddHealth(playerPawn, healthToAdd); + player.EmitSound("Healthshot.Success"); + } + } + } + + public class PlayerSkillInfo + { + public ulong SteamID { get; set; } + public bool CanUse { get; set; } + public int Count { get; set; } + public DateTime Cooldown { get; set; } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int HealthToAdd { get; set; } + public int HealthShotLimit { get; set; } + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#10c212", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int healthToAdd = 50, int healthShotLimit = 3, float cooldown = 1f) : base(skill, active, color, onlyTeam, needsTeammates) + { + HealthToAdd = healthToAdd; + HealthShotLimit = healthShotLimit; + Cooldown = cooldown; + } } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/MoneySwap.cs b/jRandomSkills - SRC Files/src/player/skills/MoneySwap.cs new file mode 100644 index 0000000..2cb1c0d --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/MoneySwap.cs @@ -0,0 +1,102 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class MoneySwap : ISkill + { + private const Skills skillName = Skills.MoneySwap; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + } + + 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.SkillChance == 1) + { + player.PrintToChat($" {ChatColors.Red}{Localization.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}" + Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")); + return; + } + + SwapMoney(player, enemy); + playerInfo.SkillChance = 1; + player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("moneyswap_player_info", enemy.PlayerName)); + enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("moneyswap_enemy_info")); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + playerInfo.SkillChance = 0; + + SkillUtils.PrintToChat(player, Localization.GetTranslation("moneyswap") + ":", false); + + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("moneyswap_select_info")}"); + var enemies = Utilities.GetPlayers().Where(p => p.Team != player.Team && p.IsValid && !p.IsBot).ToArray(); + if (enemies.Length > 0) + { + foreach (var enemy in enemies) + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}: ${enemy.InGameMoneyServices.Account}"); + } + else + player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("selectplayerskill_command")} {ChatColors.Red}index"); + } + + private static void SwapMoney(CCSPlayerController player, CCSPlayerController enemy) + { + var playerMoneyServices = player?.InGameMoneyServices; + var enemyMoneyServices = enemy?.InGameMoneyServices; + if (playerMoneyServices == null || enemyMoneyServices == null) return; + + int playerMoney = playerMoneyServices.Account; + playerMoneyServices.Account = enemyMoneyServices.Account; + Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInGameMoneyServices"); + + enemyMoneyServices.Account = playerMoney; + Utilities.SetStateChanged(enemy, "CCSPlayerController", "m_pInGameMoneyServices"); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#52f54c", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Muhammed.cs b/jRandomSkills - SRC Files/src/player/skills/Muhammed.cs index e220905..28b9161 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Muhammed.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Muhammed.cs @@ -8,16 +8,13 @@ namespace jRandomSkills { public class Muhammed : ISkill { - private static Skills skillName = Skills.Muhammed; - private const float ExplosionRadius = 500.0f; - private const int ExplosionDamage = 999; + private const Skills skillName = Skills.Muhammed; + private static float explosionRadius = Config.GetValue(skillName, "explosionRadius"); + private static int explosionDamage = Config.GetValue(skillName, "explosionDamage"); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#F5CB42"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -42,8 +39,8 @@ namespace jRandomSkills heProjectile.TicksAtZeroVelocity = 100; heProjectile.TeamNum = player.TeamNum; - heProjectile.Damage = ExplosionDamage; - heProjectile.DmgRadius = (int)ExplosionRadius; + heProjectile.Damage = explosionDamage; + heProjectile.DmgRadius = (int)explosionRadius; heProjectile.Teleport(pos, null, new Vector(0, 0, -10)); heProjectile.DispatchSpawn(); heProjectile.AcceptInput("InitializeSpawnFromWorld", player.PlayerPawn.Value, player.PlayerPawn.Value, ""); @@ -62,5 +59,17 @@ namespace jRandomSkills { return player != null && player.IsValid && player.PlayerPawn?.Value != null; } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ExplosionRadius { get; set; } + public int ExplosionDamage { get; set; } + + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#F5CB42", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float explosionRadius = 500.0f, int explosionDamage = 999) : base(skill, active, color, onlyTeam, needsTeammates) + { + ExplosionRadius = explosionRadius; + ExplosionDamage = explosionDamage; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Mute.cs b/jRandomSkills - SRC Files/src/player/skills/Mute.cs index f11de56..2af9f17 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Mute.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Mute.cs @@ -1,4 +1,4 @@ -using CounterStrikeSharp.API; +/*using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -7,7 +7,7 @@ namespace jRandomSkills { public class Mute : ISkill { - private static Skills skillName = Skills.AntyHead; + private const Skills skillName = Skills.Mute; public static void LoadSkill() { @@ -19,17 +19,20 @@ namespace jRandomSkills Instance.RegisterListener(@event => { var name = @event.DesignerName; - if (!name.EndsWith("_projectile") && name != "instanced_scripted_scene") + if (!name.EndsWith("_projectile")) return; - if (@event.DesignerName == "instanced_scripted_scene") - { - @event.AcceptInput("Kill"); - @event.Remove(); - return; - } + var grenade = @event.As(); + var pawn = grenade.OwnerEntity.Value.As(); + var player = pawn.Controller.Value.As(); + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return; Server.NextFrame(() => { + var grenade = @event.As(); + grenade.DetonateTime = float.MaxValue; + switch (name) { case "smokegrenade_projectile": @@ -39,6 +42,7 @@ namespace jRandomSkills case "molotov_projectile": var molotov = @event.As(); molotov.Detonated = true; + molotov.StillTimer.Timestamp = float.MaxValue; break; case "decoy_projectile": var decoy = @event.As(); @@ -46,12 +50,8 @@ namespace jRandomSkills decoy.DecoyShotTick = int.MaxValue; decoy.ShotsRemaining = int.MaxValue; break; - default: - var grenade = @event.As(); - grenade.DetonateTime = float.MaxValue; - break; } - + // deoy smoke molo/inter Instance.AddTimer(5f, () => { if (@event != null && @event.IsValid) @@ -61,4 +61,4 @@ namespace jRandomSkills }); } } -} \ No newline at end of file +}*/ \ 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 0867ecf..c9da2d8 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Ninja.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Ninja.cs @@ -10,20 +10,17 @@ namespace jRandomSkills { public class Ninja : ISkill { - private static Skills skillName = Skills.Ninja; - private static float idlePercentInvisibility = 0.3f; - private static float duckPercentInvisibility = 0.3f; - private static float knifePercentInvisibility = 0.3f; + private const Skills skillName = Skills.Ninja; + private static float idlePercentInvisibility = Config.GetValue(skillName, "idlePercentInvisibility"); + private static float duckPercentInvisibility = Config.GetValue(skillName, "duckPercentInvisibility"); + private static float knifePercentInvisibility = Config.GetValue(skillName, "knifePercentInvisibility"); private static Dictionary invisibilityChanged = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); - SkillUtils.RegisterSkill(skillName, "#dedede"); - - Instance.RegisterEventHandler((@event, info) => + Instance.RegisterEventHandler((@event, info) => { foreach (var player in Utilities.GetPlayers()) DisableSkill(player); @@ -31,6 +28,18 @@ namespace jRandomSkills return HookResult.Continue; }); + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + if (!player.IsValid || player.PlayerPawn.Value == null) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + DisableSkill(player); + + return HookResult.Continue; + }); + Instance.RegisterEventHandler((@event, info) => { var player = @event.Userid; @@ -111,5 +120,18 @@ namespace jRandomSkills } } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float IdlePercentInvisibility { get; set; } + public float DuckPercentInvisibility { get; set; } + public float KnifePercentInvisibility { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#dedede", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float idlePercentInvisibility = .3f, float duckPercentInvisibility = .3f, float knifePercentInvisibility = .3f) : base(skill, active, color, onlyTeam, needsTeammates) + { + IdlePercentInvisibility = idlePercentInvisibility; + DuckPercentInvisibility = duckPercentInvisibility; + KnifePercentInvisibility = knifePercentInvisibility; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/NoNades.cs b/jRandomSkills - SRC Files/src/player/skills/NoNades.cs new file mode 100644 index 0000000..a629ff6 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/NoNades.cs @@ -0,0 +1,43 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class NoNades : ISkill + { + private const Skills skillName = Skills.NoNades; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var damage = @event.DmgHealth; + var player = @event.Userid; + var weapon = @event.Weapon; + + if (!Instance.IsPlayerValid(player)) return HookResult.Continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + if (weapon == "hegrenade" || weapon == "inferno") + { + SkillUtils.AddHealth(player.PlayerPawn.Value, damage); + damage = 0; + return HookResult.Stop; + } + return HookResult.Continue; + }); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#a38c1a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/NoRecoil.cs b/jRandomSkills - SRC Files/src/player/skills/NoRecoil.cs index 820f2b3..dc8e1d4 100644 --- a/jRandomSkills - SRC Files/src/player/skills/NoRecoil.cs +++ b/jRandomSkills - SRC Files/src/player/skills/NoRecoil.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static CounterStrikeSharp.API.Core.Listeners; using static jRandomSkills.jRandomSkills; @@ -8,14 +9,11 @@ namespace jRandomSkills { public class NoRecoil : ISkill { - private static Skills skillName = Skills.NoRecoil; + private const Skills skillName = Skills.NoRecoil; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#8a42f5"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -24,7 +22,6 @@ namespace jRandomSkills foreach (var player in Utilities.GetPlayers()) { if (!Instance.IsPlayerValid(player)) continue; - player.RemoveItemByDesignerName("weapon_healthshot"); var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo?.Skill != skillName) continue; EnableSkill(player); @@ -73,5 +70,12 @@ namespace jRandomSkills } } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#8a42f5", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/TimeManipulator.cs b/jRandomSkills - SRC Files/src/player/skills/Noclip.cs similarity index 71% rename from jRandomSkills - SRC Files/src/player/skills/TimeManipulator.cs rename to jRandomSkills - SRC Files/src/player/skills/Noclip.cs index a84126c..146ed0f 100644 --- a/jRandomSkills - SRC Files/src/player/skills/TimeManipulator.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Noclip.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using jRandomSkills.src.utils; using static CounterStrikeSharp.API.Core.Listeners; @@ -7,18 +8,16 @@ using static jRandomSkills.jRandomSkills; namespace jRandomSkills { - public class TimeManipulator : ISkill + public class Noclip : ISkill { - private static Skills skillName = Skills.TimeManipulator; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.Noclip; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); + private static float duration = Config.GetValue(skillName, "duration"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#2ec761"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -87,11 +86,15 @@ namespace jRandomSkills private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo) { float cooldown = 0; + float flying = 0; if (skillInfo != null) { float time = (int)(skillInfo.Cooldown.AddSeconds(timerCooldown) - DateTime.Now).TotalSeconds; cooldown = Math.Max(time, 0); + float flyingTime = (int)(skillInfo.Cooldown.AddSeconds(duration) - DateTime.Now).TotalMilliseconds; + flying = Math.Max(flyingTime, 0); + if (cooldown == 0 && skillInfo?.CanUse == false) skillInfo.CanUse = true; } @@ -101,7 +104,12 @@ namespace jRandomSkills string infoLine = $"{Localization.GetTranslation("your_skill")}:
"; string skillLine = $"{skillData.Name}
"; - string remainingLine = cooldown != 0 ? $"{Localization.GetTranslation("hud_info", $"{cooldown}")}
" : ""; + string remainingLine = cooldown != 0 + ? ( + flying != 0 + ? $"{Localization.GetTranslation("active_hud_info", $"{Math.Round(flying / 100, 2)}")}
" + : $"{Localization.GetTranslation("hud_info", $"{cooldown}")}
" + ) : ""; var hudContent = infoLine + skillLine + remainingLine; player.PrintToCenterHtml(hudContent); @@ -120,13 +128,8 @@ namespace jRandomSkills skillInfo.CanUse = false; skillInfo.Cooldown = DateTime.Now; - Server.ExecuteCommand("sv_cheats 1"); - Server.ExecuteCommand("host_timescale 0.1"); - Instance.AddTimer(.6f, () => - { - Server.ExecuteCommand("host_timescale 1"); - Server.ExecuteCommand("sv_cheats 0"); - }); + playerPawn.ActualMoveType = MoveType_t.MOVETYPE_NOCLIP; + Instance.AddTimer(duration, () => playerPawn.ActualMoveType = MoveType_t.MOVETYPE_WALK); } else skillInfo.LastClick = DateTime.Now; @@ -140,5 +143,16 @@ namespace jRandomSkills public DateTime Cooldown { get; set; } public DateTime LastClick { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public float Duration { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#44ebd4", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 30f, float duration = 2f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + Duration = duration; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/None.cs b/jRandomSkills - SRC Files/src/player/skills/None.cs index fc2376c..6769331 100644 --- a/jRandomSkills - SRC Files/src/player/skills/None.cs +++ b/jRandomSkills - SRC Files/src/player/skills/None.cs @@ -1,14 +1,22 @@ -using jRandomSkills.src.player; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; namespace jRandomSkills { public class None : ISkill { - private static Skills skillName = Skills.None; + private const Skills skillName = Skills.None; public static void LoadSkill() { - SkillUtils.RegisterSkill(skillName, "#FFFFFF", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#FFFFFF", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/OneShot.cs b/jRandomSkills - SRC Files/src/player/skills/OneShot.cs index fb6449d..38ee1b1 100644 --- a/jRandomSkills - SRC Files/src/player/skills/OneShot.cs +++ b/jRandomSkills - SRC Files/src/player/skills/OneShot.cs @@ -1,7 +1,7 @@ -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -9,14 +9,11 @@ namespace jRandomSkills { public class OneShot : ISkill { - private static Skills skillName = Skills.OneShot; + private const Skills skillName = Skills.OneShot; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#ff5CD9"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); } @@ -47,5 +44,12 @@ namespace jRandomSkills param2.Damage = 1000f; return HookResult.Changed; } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff5CD9", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/OnlyHead.cs b/jRandomSkills - SRC Files/src/player/skills/OnlyHead.cs index 2001af7..9b382c4 100644 --- a/jRandomSkills - SRC Files/src/player/skills/OnlyHead.cs +++ b/jRandomSkills - SRC Files/src/player/skills/OnlyHead.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -7,14 +8,11 @@ namespace jRandomSkills { public class OnlyHead : ISkill { - private static Skills skillName = Skills.OnlyHead; + private const Skills skillName = Skills.OnlyHead; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#3c47de"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -45,5 +43,12 @@ namespace jRandomSkills playerPawn.Health = (int)newHealth; Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_iHealth"); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#3c47de", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/PawelJumper.cs b/jRandomSkills - SRC Files/src/player/skills/PawelJumper.cs index c95e49b..0744425 100644 --- a/jRandomSkills - SRC Files/src/player/skills/PawelJumper.cs +++ b/jRandomSkills - SRC Files/src/player/skills/PawelJumper.cs @@ -9,17 +9,14 @@ namespace jRandomSkills { public class PawelJumper : ISkill { - private static Skills skillName = Skills.PawelJumper; + 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]; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#FFA500"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterListener(() => { @@ -58,5 +55,12 @@ namespace jRandomSkills LF[player.Slot] = flags; LB[player.Slot] = buttons; } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#FFA500", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Phoenix.cs b/jRandomSkills - SRC Files/src/player/skills/Phoenix.cs index 01680ba..7fe7aaf 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Phoenix.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Phoenix.cs @@ -9,14 +9,11 @@ namespace jRandomSkills { public class Phoenix : ISkill { - private static Skills skillName = Skills.Phoenix; + private const Skills skillName = Skills.Phoenix; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#ff5C0A", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -39,7 +36,7 @@ namespace jRandomSkills { var player = @event.Userid; - if (!Instance.IsPlayerValid(player)) return HookResult.Continue; + if (player == null || !player.IsValid || !player.PlayerPawn.Value.IsValid) return HookResult.Continue; var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo?.Skill == skillName) @@ -58,11 +55,8 @@ namespace jRandomSkills public static void EnableSkill(CCSPlayerController player) { - var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); - if (skillConfig == null) return; - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - float newChance = (float)Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom; + float newChance = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "ChanceTo") - Config.GetValue(skillName, "ChanceFrom")) + Config.GetValue(skillName, "ChanceFrom"); playerInfo.SkillChance = newChance; newChance = (float)Math.Round(newChance, 2) * 100; newChance = (float)Math.Round(newChance); @@ -73,5 +67,16 @@ namespace jRandomSkills { return player != null && player.IsValid && player.PlayerPawn?.Value != null; } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff5C0A", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = .2f, float chanceTo = .4f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Pilot.cs b/jRandomSkills - SRC Files/src/player/skills/Pilot.cs index 95dda34..b0facbc 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Pilot.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Pilot.cs @@ -10,15 +10,13 @@ namespace jRandomSkills { public class Pilot : ISkill { - private static Skills skillName = Skills.Pilot; + private const Skills skillName = Skills.Pilot; + private static float maximumFuel = Config.GetValue(skillName, "maximumFuel"); private static readonly Dictionary PlayerPilotInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#1466F5"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -107,12 +105,12 @@ namespace jRandomSkills private static void UpdateHUD(CCSPlayerController player, Pilot_PlayerInfo pilotInfo) { var buttons = player.Buttons; - float fuelPercentage = 100.0f; + float fuelPercentage = maximumFuel; if (pilotInfo.PressedUse && pilotInfo.CanUsePilot) { float elapsedTime = (float)(DateTime.Now - pilotInfo.PilotStartTime).TotalSeconds; - fuelPercentage = Math.Max(0, 100.0f * (4.0f - elapsedTime) / 4.0f); + fuelPercentage = Math.Max(0, maximumFuel * (4.0f - elapsedTime) / 4.0f); } string fuelColor = GetFuelColor(fuelPercentage); @@ -129,8 +127,8 @@ namespace jRandomSkills private static string GetFuelColor(float fuelPercentage) { - if (fuelPercentage > 50) return "#00FF00"; - if (fuelPercentage > 25) return "#FFFF00"; + if (fuelPercentage > (maximumFuel/2f)) return "#00FF00"; + if (fuelPercentage > (maximumFuel/4f)) return "#FFFF00"; return "#FF0000"; } @@ -184,5 +182,14 @@ namespace jRandomSkills public bool PressedUse { get; set; } public DateTime PilotStartTime { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float MaximumFuel { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#1466F5", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float maximumFuel = 100f) : base(skill, active, color, onlyTeam, needsTeammates) + { + MaximumFuel = maximumFuel; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Planter.cs b/jRandomSkills - SRC Files/src/player/skills/Planter.cs index 1f18702..fa4757f 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Planter.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Planter.cs @@ -1,8 +1,8 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; -using jRandomSkills.src.utils; using static CounterStrikeSharp.API.Core.Listeners; using static jRandomSkills.jRandomSkills; @@ -10,14 +10,12 @@ namespace jRandomSkills { public class Planter : ISkill { - private static Skills skillName = Skills.Planter; + private const Skills skillName = Skills.Planter; + private static int extraC4BlowTime = Config.GetValue(skillName, "extraC4BlowTime"); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#7d7d7d"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, @info) => { @@ -31,22 +29,15 @@ namespace jRandomSkills Instance.RegisterEventHandler((@event, info) => { - foreach (var player in Utilities.GetPlayers()) - { - if (!Instance.IsPlayerValid(player)) continue; + var player = @event.Userid; + if (!Instance.IsPlayerValid(player)) return HookResult.Continue; - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - if (playerInfo?.Skill != skillName) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; - var plantedBomb = Utilities.FindAllEntitiesByDesignerName("planted_c4").FirstOrDefault(); - if (plantedBomb != null) - { - Server.NextFrame(() => - { - plantedBomb.C4Blow = (float)Server.EngineTime + 60; - }); - } - } + var plantedBomb = Utilities.FindAllEntitiesByDesignerName("planted_c4").FirstOrDefault(); + if (plantedBomb != null) + Server.NextFrame(() => plantedBomb.C4Blow = (float)Server.EngineTime + extraC4BlowTime); return HookResult.Continue; }); @@ -70,5 +61,14 @@ namespace jRandomSkills Schema.SetSchemaValue(player.Pawn.Value.Handle, "CCSPlayerPawn", "m_bInBombZone", true); } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int ExtraC4BlowTime { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#7d7d7d", CsTeam onlyTeam = CsTeam.Terrorist, bool needsTeammates = false, int extraC4BlowTime = 60) : base(skill, active, color, onlyTeam, needsTeammates) + { + ExtraC4BlowTime = extraC4BlowTime; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Poison.cs b/jRandomSkills - SRC Files/src/player/skills/Poison.cs new file mode 100644 index 0000000..d27e1f0 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Poison.cs @@ -0,0 +1,120 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Poison : ISkill + { + private const Skills skillName = Skills.Poison; + private static int cooldown = Config.GetValue(skillName, "Cooldown"); + private static int healthToDamage = Config.GetValue(skillName, "Damage"); + private static HashSet poisonedPlayers = new HashSet(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + foreach (var player in poisonedPlayers) + DisableSkill(player); + return HookResult.Continue; + }); + + Instance.RegisterListener(OnTick); + } + + private static void OnTick() + { + if (Server.TickCount % (64 * cooldown) != 0) return; + foreach (var player in poisonedPlayers) + { + var pawn = player.PlayerPawn.Value; + if (pawn == null || !pawn.IsValid) continue; + SkillUtils.TakeHealth(pawn, healthToDamage); + } + } + + 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.SkillChance == 1) + { + player.PrintToChat($" {ChatColors.Red}{Localization.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}" + Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")); + return; + } + + poisonedPlayers.Add(enemy); + playerInfo.SkillChance = 1; + player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("poison_player_info", enemy.PlayerName)); + enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("poison_enemy_info")); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + playerInfo.SkillChance = 0; + + SkillUtils.PrintToChat(player, Localization.GetTranslation("poison") + ":", false); + + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("poison_select_info")}"); + var enemies = Utilities.GetPlayers().Where(p => p.Team != player.Team && p.IsValid && !p.IsBot).ToArray(); + if (enemies.Length > 0) + { + foreach (var enemy in enemies) + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + } + else + player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("selectplayerskill_command")} {ChatColors.Red}index"); + } + + public static void DisableSkill(CCSPlayerController player) + { + poisonedPlayers.Remove(player); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int Damage { get; set; } + public int Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#902eff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int cooldown = 2, int damage = 1) : base(skill, active, color, onlyTeam, needsTeammates) + { + Damage = damage; + Cooldown = cooldown; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/PrimaryBan.cs b/jRandomSkills - SRC Files/src/player/skills/PrimaryBan.cs new file mode 100644 index 0000000..ec60098 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/PrimaryBan.cs @@ -0,0 +1,126 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class PrimaryBan : ISkill + { + private const Skills skillName = Skills.PrimaryBan; + private static HashSet bannedPlayers = new HashSet(); + private static string[] disabledWeapons = + { + "ak47", "m4a1", "m4a4", "m4a1_silencer", "famas", "galilar", "aug", "sg553", "mp9", "mac10", "bizon", "mp7", "ump45", + "p90", "mp5sd", "ssg08", "awp", "scar20", "g3sg1", "nova", "xm1014", "mag7", "sawedoff", "m249", "negev" + }; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + bannedPlayers.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + var weapon = @event.Item; + + if (!bannedPlayers.Contains(player.SteamID) || !disabledWeapons.Contains(weapon)) return HookResult.Continue; + player.ExecuteClientCommand("slot3"); + return HookResult.Stop; + }); + } + + 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.SkillChance == 1) + { + player.PrintToChat($" {ChatColors.Red}{Localization.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}" + Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")); + return; + } + + bannedPlayers.Add(enemy.SteamID); + CheckWeapon(enemy); + playerInfo.SkillChance = 1; + player.PrintToChat($" {ChatColors.Green}" + Localization.GetTranslation("primaryban_player_info", enemy.PlayerName)); + enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("primaryban_enemy_info")); + } + + private static void CheckWeapon(CCSPlayerController player) + { + var activeWeapon = player.PlayerPawn.Value?.WeaponServices?.ActiveWeapon?.Value; + if (activeWeapon == null || !activeWeapon.IsValid) return; + if (activeWeapon.DesignerName == null || string.IsNullOrEmpty(activeWeapon.DesignerName)) return; + + if (!bannedPlayers.Contains(player.SteamID) || !disabledWeapons.Contains(activeWeapon.DesignerName?.Replace("weapon_", ""))) return; + player.ExecuteClientCommand("slot3"); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + playerInfo.SkillChance = 0; + + SkillUtils.PrintToChat(player, Localization.GetTranslation("primaryban") + ":", false); + + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("primaryban_select_info")}"); + var enemies = Utilities.GetPlayers().Where(p => p.Team != player.Team && p.IsValid && !p.IsBot).ToArray(); + if (enemies.Length > 0) + { + foreach (var enemy in enemies) + player.PrintToChat($" {ChatColors.Green}⠀⠀⠀[{ChatColors.Red}{enemy.Index}{ChatColors.Green}] {enemy.PlayerName}"); + } + else + player.PrintToChat($" {ChatColors.Red}⠀⠀⠀{Localization.GetTranslation("selectplayerskill_incorrect_enemy_index")}"); + player.PrintToChat($" {ChatColors.Green}{Localization.GetTranslation("selectplayerskill_command")} {ChatColors.Red}index"); + } + + public static void DisableSkill(CCSPlayerController player) + { + bannedPlayers.Remove(player.SteamID); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffc061", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Prosthesis.cs b/jRandomSkills - SRC Files/src/player/skills/Prosthesis.cs index d297824..87bcbaf 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Prosthesis.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Prosthesis.cs @@ -1,7 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Memory; -using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -9,14 +8,11 @@ namespace jRandomSkills { public class Prosthesis : ISkill { - private static Skills skillName = Skills.Prosthesis; + private const Skills skillName = Skills.Prosthesis; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#9c9c9c"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -47,5 +43,12 @@ namespace jRandomSkills playerPawn.Health = (int)newHealth; Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_iHealth"); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#9c9c9c", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/PsychicDefusing.cs b/jRandomSkills - SRC Files/src/player/skills/PsychicDefusing.cs new file mode 100644 index 0000000..ed12ec8 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/PsychicDefusing.cs @@ -0,0 +1,153 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static CounterStrikeSharp.API.Core.Listeners; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class PsychicDefusing : ISkill + { + private const Skills skillName = Skills.PsychicDefusing; + private static readonly Dictionary SkillPlayerInfo = new Dictionary(); + private static Vector bombLocation = null; + private static float maxDefusingRange = Config.GetValue(skillName, "maxDefusingRange"); + private static float defusingTime = Config.GetValue(skillName, "defusingTime"); + private static float tickRate = 64f; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + SkillPlayerInfo.Clear(); + bombLocation = null; + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + if (SkillPlayerInfo.ContainsKey(player.PlayerPawn.Value)) + SkillPlayerInfo.Remove(player.PlayerPawn.Value); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var plantedBomb = Utilities.FindAllEntitiesByDesignerName("planted_c4").FirstOrDefault(); + if (plantedBomb != null) + bombLocation = plantedBomb.AbsOrigin; + return HookResult.Continue; + }); + + Instance.RegisterListener(() => + { + if (bombLocation == null) return; + foreach (var skillInfo in SkillPlayerInfo) + { + var player = skillInfo.Key; + var info = skillInfo.Value; + + if (SkillUtils.GetDistance(player.AbsOrigin, bombLocation) > maxDefusingRange) + { + info.Defusing = false; + info.DefusingTime = defusingTime; + continue; + } + + if (!info.Defusing) + player.EmitSound("c4.disarmstart"); + info.Defusing = true; + info.DefusingTime -= (1f / tickRate); + + if (info.DefusingTime <= 0) + { + var plantedBomb = Utilities.FindAllEntitiesByDesignerName("planted_c4").FirstOrDefault(); + if (plantedBomb != null) + { + plantedBomb.Remove(); + SkillUtils.TerminateRound(CsTeam.CounterTerrorist); + } + + SkillPlayerInfo.Clear(); + } + + UpdateHUD(player.Controller.Value.As(), info); + } + }); + } + + public static void EnableSkill(CCSPlayerController player) + { + SkillPlayerInfo[player.PlayerPawn.Value] = new PlayerSkillInfo + { + SteamID = player.SteamID, + Defusing = false, + DefusingTime = defusingTime, + }; + } + + public static void DisableSkill(CCSPlayerController player) + { + if (SkillPlayerInfo.ContainsKey(player.PlayerPawn.Value)) + SkillPlayerInfo.Remove(player.PlayerPawn.Value); + } + + private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo) + { + if (!skillInfo.Defusing) return; + int cooldown = (int)skillInfo.DefusingTime + 1; + + var skillData = SkillData.Skills.FirstOrDefault(s => s.Skill == skillName); + if (skillData == null) return; + + string infoLine = $"{Localization.GetTranslation("your_skill")}:
"; + string skillLine = $"{skillData.Name}
"; + string remainingLine = cooldown != 0 ? $"{Localization.GetTranslation("psychicdefusing_hud_info", $"{cooldown}")}
" : ""; + + var hudContent = infoLine + skillLine + remainingLine; + player.PrintToCenterHtml(hudContent); + } + public class PlayerSkillInfo + { + public ulong SteamID { get; set; } + public bool Defusing { get; set; } + public float DefusingTime { get; set; } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float MaxDefusingRange { get; set; } + public float DefusingTime { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#507529", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool needsTeammates = false, float maxDefusingRange = 80f, float defusingTime = 10f) : base(skill, active, color, onlyTeam, needsTeammates) + { + MaxDefusingRange = maxDefusingRange; + DefusingTime = defusingTime; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Push.cs b/jRandomSkills - SRC Files/src/player/skills/Push.cs new file mode 100644 index 0000000..a0fa096 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Push.cs @@ -0,0 +1,96 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Push : ISkill + { + private const Skills skillName = Skills.Push; + private static float jumpVelocity = Config.GetValue(skillName, "jumpVelocity"); + private static float pushVelocity = Config.GetValue(skillName, "pushVelocity"); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var attacker = @event!.Attacker; + var victim = @event!.Userid; + + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) + return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + + if (playerInfo?.Skill == skillName && victim.PawnIsAlive) + { + if (Instance.Random.NextDouble() <= playerInfo.SkillChance) + PushEnemy(victim, attacker.PlayerPawn.Value.EyeAngles); + } + + return HookResult.Continue; + }); + } + + public static void EnableSkill(CCSPlayerController player) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + float newChance = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "ChanceTo") - Config.GetValue(skillName, "ChanceFrom")) + Config.GetValue(skillName, "ChanceFrom"); + playerInfo.SkillChance = newChance; + newChance = (float)Math.Round(newChance, 2) * 100; + newChance = (float)Math.Round(newChance); + SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("push")}{ChatColors.Lime}: " + Localization.GetTranslation("push_desc2", newChance), false); + } + + private static void PushEnemy(CCSPlayerController player, QAngle attackerAngle) + { + if (player.PlayerPawn.Value.LifeState != (int)LifeState_t.LIFE_ALIVE) + return; + + var currentPosition = player.PlayerPawn.Value.AbsOrigin; + var currentAngles = player.PlayerPawn.Value.EyeAngles; + + Vector newVelocity = SkillUtils.GetForwardVector(attackerAngle) * pushVelocity; + newVelocity.Z = player.PlayerPawn.Value.AbsVelocity.Z + jumpVelocity; + + player.PlayerPawn.Value.Teleport(currentPosition, currentAngles, newVelocity); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public float JumpVelocity { get; set; } + public float PushVelocity { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#1e9ab0", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = 1f, float chanceTo = 1f, float jumpVelocity = 300f, float pushVelocity = 400f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + JumpVelocity = jumpVelocity; + PushVelocity = pushVelocity; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Pyro.cs b/jRandomSkills - SRC Files/src/player/skills/Pyro.cs new file mode 100644 index 0000000..e013d3f --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Pyro.cs @@ -0,0 +1,76 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Pyro : ISkill + { + private const Skills skillName = Skills.Pyro; + private static float regenerationMultiplier = Config.GetValue(skillName, "regenerationMultiplier"); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var victim = @event.Userid; + int damage = @event.DmgHealth; + string weapon = @event.Weapon; + + if (weapon != "inferno" || !Instance.IsPlayerValid(victim)) return HookResult.Continue; + var victimInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == victim.SteamID); + if (victimInfo == null || victimInfo.Skill != skillName) return HookResult.Continue; + + RestoreHealth(victim, damage * regenerationMultiplier); + return HookResult.Stop; + }); + } + + public static void EnableSkill(CCSPlayerController player) + { + SkillUtils.TryGiveWeapon(player, player.Team == CsTeam.CounterTerrorist ? CsItem.IncendiaryGrenade : CsItem.Molotov); + } + + private static void RestoreHealth(CCSPlayerController victim, float damage) + { + var playerPawn = victim.PlayerPawn.Value; + var newHealth = playerPawn.Health + damage; + + if (newHealth > 100) + newHealth = 100; + + playerPawn.Health = (int)newHealth; + Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_iHealth"); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float RegenerationMultiplier { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#3c47de", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float regenerationMultiplier = 1.5f) : base(skill, active, color, onlyTeam, needsTeammates) + { + RegenerationMultiplier = regenerationMultiplier; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/QuickShot.cs b/jRandomSkills - SRC Files/src/player/skills/QuickShot.cs index de3edc8..53a630e 100644 --- a/jRandomSkills - SRC Files/src/player/skills/QuickShot.cs +++ b/jRandomSkills - SRC Files/src/player/skills/QuickShot.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static CounterStrikeSharp.API.Core.Listeners; using static jRandomSkills.jRandomSkills; @@ -8,14 +9,11 @@ namespace jRandomSkills { public class QuickShot : ISkill { - private static Skills skillName = Skills.QuickShot; + private const Skills skillName = Skills.QuickShot; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#8a42f5"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterListener(OnTick); } @@ -42,5 +40,12 @@ namespace jRandomSkills } } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#8a42f5", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/RadarHack.cs b/jRandomSkills - SRC Files/src/player/skills/RadarHack.cs index ac26882..7ebfb32 100644 --- a/jRandomSkills - SRC Files/src/player/skills/RadarHack.cs +++ b/jRandomSkills - SRC Files/src/player/skills/RadarHack.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static CounterStrikeSharp.API.Core.Listeners; using static jRandomSkills.jRandomSkills; @@ -8,14 +9,11 @@ namespace jRandomSkills { public class RadarHack : ISkill { - private static Skills skillName = Skills.RadarHack; + private const Skills skillName = Skills.RadarHack; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#2effcb"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterListener(CheckRadarowiec); } @@ -54,5 +52,12 @@ namespace jRandomSkills bomb.EntitySpottedState.SpottedByMask[0] |= (1u << (int)(playerIndex % 32)); } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#2effcb", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Rambo.cs b/jRandomSkills - SRC Files/src/player/skills/Rambo.cs index 3713795..b0a0b7a 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Rambo.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Rambo.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -7,14 +8,13 @@ namespace jRandomSkills { public class Rambo : ISkill { - private static Skills skillName = Skills.Rambo; + private const Skills skillName = Skills.Rambo; + private static int minExtraHealth = Config.GetValue(skillName, "minExtraHealth"); + private static int maxExtraHealth = Config.GetValue(skillName, "maxExtraHealth"); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#009905"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -34,7 +34,7 @@ namespace jRandomSkills public static void EnableSkill(CCSPlayerController player) { - int healthBonus = Instance.Random.Next(50, 501); + int healthBonus = Instance.Random.Next(minExtraHealth, maxExtraHealth); AddHealth(player, healthBonus); } @@ -66,5 +66,16 @@ namespace jRandomSkills pawn.Health = Math.Min(pawn.Health, 100); Utilities.SetStateChanged(pawn, "CBaseEntity", "m_iHealth"); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int MinExtraHealth { get; set; } + public int MaxExtraHealth { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#009905", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int minExtraHealth = 50, int maxExtraHealth = 501) : base(skill, active, color, onlyTeam, needsTeammates) + { + MinExtraHealth = minExtraHealth; + MaxExtraHealth = maxExtraHealth; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/RandomWeapon.cs b/jRandomSkills - SRC Files/src/player/skills/RandomWeapon.cs index b8839c8..3d8ede4 100644 --- a/jRandomSkills - SRC Files/src/player/skills/RandomWeapon.cs +++ b/jRandomSkills - SRC Files/src/player/skills/RandomWeapon.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using jRandomSkills.src.utils; using System.Collections.Immutable; @@ -10,8 +11,8 @@ namespace jRandomSkills { public class RandomWeapon : ISkill { - private static Skills skillName = Skills.RandomWeapon; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.RandomWeapon; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); private static string[] pistols = { "weapon_deagle", "weapon_revolver", "weapon_glock", "weapon_usp_silencer", @@ -24,10 +25,7 @@ namespace jRandomSkills public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#e0873a"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -179,5 +177,14 @@ namespace jRandomSkills public DateTime Cooldown { get; set; } public DateTime LastClick { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#e0873a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 15f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/ReZombie.cs b/jRandomSkills - SRC Files/src/player/skills/ReZombie.cs new file mode 100644 index 0000000..7fb18a5 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/ReZombie.cs @@ -0,0 +1,91 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using System.Drawing; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class ReZombie : ISkill + { + private const Skills skillName = Skills.ReZombie; + private static int zombieHealth = Config.GetValue(skillName, "zombieHealth"); + private static HashSet zombies = new HashSet(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + var weapon = @event.Item; + + if (!zombies.Contains(player) || weapon == "c4") return HookResult.Continue; + player.ExecuteClientCommand("slot3"); + return HookResult.Stop; + }); + + Instance.RegisterEventHandler((@event, info) => + { + foreach(var player in zombies) + DisableSkill(player); + zombies.Clear(); + return HookResult.Stop; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + if (player == null || !player.IsValid || !player.PlayerPawn.Value.IsValid || zombies.Contains(player)) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + var pawn = player.PlayerPawn.Value; + Vector deadPosition = new Vector(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z); + QAngle deadRotation = new QAngle(pawn.EyeAngles.X, pawn.EyeAngles.Y, pawn.EyeAngles.Z); + + player.Respawn(); + Instance.AddTimer(.2f, () => { + player.Respawn(); + zombies.Add(player); + player.ExecuteClientCommand("slot3"); + SetPlayerColor(pawn, false); + SkillUtils.AddHealth(pawn, zombieHealth - 100, zombieHealth); + pawn.Teleport(deadPosition, deadRotation); + }); + + return HookResult.Continue; + }); + } + + public static void EnableSkill(CCSPlayerController player) + { + zombies.Remove(player); + } + + public static void DisableSkill(CCSPlayerController player) + { + zombies.Remove(player); + SetPlayerColor(player.PlayerPawn.Value, true); + } + + private static void SetPlayerColor(CCSPlayerPawn pawn, bool normal) + { + var color = normal ? Color.FromArgb(255, 255, 255, 255) : Color.FromArgb(255, 255, 0, 0); + pawn.Render = color; + Utilities.SetStateChanged(pawn, "CBaseModelEntity", "m_clrRender"); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int ZombieHealth { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff5C0A", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int zombieHealth = 200) : base(skill, active, color, onlyTeam, needsTeammates) + { + ZombieHealth = zombieHealth; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/ReactiveArmor.cs b/jRandomSkills - SRC Files/src/player/skills/ReactiveArmor.cs index de03dfd..ca2df3e 100644 --- a/jRandomSkills - SRC Files/src/player/skills/ReactiveArmor.cs +++ b/jRandomSkills - SRC Files/src/player/skills/ReactiveArmor.cs @@ -1,7 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Memory; -using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using jRandomSkills.src.utils; using static CounterStrikeSharp.API.Core.Listeners; @@ -11,16 +10,13 @@ namespace jRandomSkills { public class ReactiveArmor : ISkill { - private static Skills skillName = Skills.ReactiveArmor; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.ReactiveArmor; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#3cded3"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -73,7 +69,6 @@ namespace jRandomSkills int damage = @event.DmgHealth; if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim)) return HookResult.Continue; - if (SkillPlayerInfo.TryGetValue(victim.SteamID, out var skillInfo)) { if (!victim.IsValid || !victim.PawnIsAlive || !skillInfo.CanUse) return HookResult.Continue; @@ -146,5 +141,14 @@ namespace jRandomSkills public DateTime Cooldown { get; set; } public DateTime LastClick { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#3cded3", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 15) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Regeneration.cs b/jRandomSkills - SRC Files/src/player/skills/Regeneration.cs new file mode 100644 index 0000000..a64a642 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Regeneration.cs @@ -0,0 +1,46 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Regeneration : ISkill + { + private const Skills skillName = Skills.Regeneration; + private static int cooldown = Config.GetValue(skillName, "cooldown"); + private static int healthToAdd = Config.GetValue(skillName, "healthToAdd"); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + Instance.RegisterListener(OnTick); + } + + private static void OnTick() + { + if (Server.TickCount % (64 * cooldown) != 0) return; + foreach (var player in Utilities.GetPlayers()) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + + var pawn = player.PlayerPawn.Value; + if (pawn == null || !pawn.IsValid) continue; + SkillUtils.AddHealth(pawn, healthToAdd); + } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int HealthToAdd { get; set; } + public int Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff462e", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int healthToAdd = 1, int cooldown = 1) : base(skill, active, color, onlyTeam, needsTeammates) + { + HealthToAdd = healthToAdd; + Cooldown = cooldown; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Replicator.cs b/jRandomSkills - SRC Files/src/player/skills/Replicator.cs index bb5d72e..35af400 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Replicator.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Replicator.cs @@ -12,16 +12,13 @@ namespace jRandomSkills { public class Replicator : ISkill { - private static Skills skillName = Skills.Replicator; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.Replicator; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#a3000b"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -68,7 +65,6 @@ namespace jRandomSkills }); VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); - } public static void EnableSkill(CCSPlayerController player) @@ -183,5 +179,14 @@ namespace jRandomSkills public DateTime Cooldown { get; set; } public DateTime LastClick { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#a3000b", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 15f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Retreat.cs b/jRandomSkills - SRC Files/src/player/skills/Retreat.cs index 43a13c1..4c755ad 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Retreat.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Retreat.cs @@ -10,16 +10,13 @@ namespace jRandomSkills { public class Retreat : ISkill { - private static Skills skillName = Skills.Retreat; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.Retreat; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#a86eff"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -146,5 +143,14 @@ namespace jRandomSkills public DateTime Cooldown { get; set; } public DateTime LastClick { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#a86eff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 15f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/ReturnToSender.cs b/jRandomSkills - SRC Files/src/player/skills/ReturnToSender.cs index 70b94db..3cad616 100644 --- a/jRandomSkills - SRC Files/src/player/skills/ReturnToSender.cs +++ b/jRandomSkills - SRC Files/src/player/skills/ReturnToSender.cs @@ -1,7 +1,5 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Memory; -using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -10,15 +8,12 @@ namespace jRandomSkills { public class ReturnToSender : ISkill { - private static Skills skillName = Skills.ReturnToSender; + private const Skills skillName = Skills.ReturnToSender; private static HashSet playersToSender = new HashSet(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#a68132"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -32,7 +27,7 @@ namespace jRandomSkills var victim = @event.Userid; int damage = @event.DmgHealth; - if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim)) return HookResult.Continue; + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; var attackerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); if (attackerInfo == null || attackerInfo.Skill != skillName) return HookResult.Continue; @@ -61,5 +56,12 @@ namespace jRandomSkills } return new Vector(abs.X, abs.Y, abs.Z); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#a68132", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/RichBoy.cs b/jRandomSkills - SRC Files/src/player/skills/RichBoy.cs index a899e3f..d9409a4 100644 --- a/jRandomSkills - SRC Files/src/player/skills/RichBoy.cs +++ b/jRandomSkills - SRC Files/src/player/skills/RichBoy.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -7,14 +8,13 @@ namespace jRandomSkills { public class RichBoy : ISkill { - private static Skills skillName = Skills.RichBoy; + private const Skills skillName = Skills.RichBoy; + private static int minMoney = Config.GetValue(skillName, "minMoney"); + private static int maxMoney = Config.GetValue(skillName, "maxMoney"); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#D4AF37"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -26,7 +26,7 @@ namespace jRandomSkills if (playerInfo?.Skill == skillName) { - int moneyBonus = Instance.Random.Next(5000, 15000); + int moneyBonus = Instance.Random.Next(minMoney, maxMoney); playerInfo.SkillChance = moneyBonus; AddMoney(player, moneyBonus); } @@ -39,7 +39,7 @@ namespace jRandomSkills public static void EnableSkill(CCSPlayerController player) { var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - int moneyBonus = Instance.Random.Next(5000, 15000); + int moneyBonus = Instance.Random.Next(minMoney, maxMoney); playerInfo.SkillChance = moneyBonus; AddMoney(player, moneyBonus); } @@ -59,5 +59,16 @@ namespace jRandomSkills moneyServices.Account = Math.Max(moneyServices.Account + money, 0); Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInGameMoneyServices"); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int MinMoney { get; set; } + public int MaxMoney { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#D4AF37", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int minMoney = 5000, int maxMoney = 15000) : base(skill, active, color, onlyTeam, needsTeammates) + { + MinMoney = minMoney; + MaxMoney = maxMoney; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/RobinHood.cs b/jRandomSkills - SRC Files/src/player/skills/RobinHood.cs index 3ef046d..0433638 100644 --- a/jRandomSkills - SRC Files/src/player/skills/RobinHood.cs +++ b/jRandomSkills - SRC Files/src/player/skills/RobinHood.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -7,25 +8,24 @@ namespace jRandomSkills { public class RobinHood : ISkill { - private static Skills skillName = Skills.RobinHood; + private const Skills skillName = Skills.RobinHood; + private static int moneyMultiplier = Config.GetValue(skillName, "moneyMultiplier"); + public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#119125"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { var victim = @event.Userid; var attacker = @event.Attacker; var damage = @event.DmgHealth; - if (!Instance.IsPlayerValid(victim) || !Instance.IsPlayerValid(attacker)) return HookResult.Continue; + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; var attackerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); if (attackerInfo?.Skill != skillName) return HookResult.Continue; - int moneyToSteal = damage * 35; + int moneyToSteal = damage * moneyMultiplier; StealMoney(victim, attacker, moneyToSteal); return HookResult.Continue; @@ -45,5 +45,14 @@ namespace jRandomSkills attackerMoneyServices.Account = Math.Min(attackerMoneyServices.Account + moneyToAdd, 16000); Utilities.SetStateChanged(attacker, "CCSPlayerController", "m_pInGameMoneyServices"); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int MoneyMultiplier { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#119125", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int moneyMultiplier = 35) : base(skill, active, color, onlyTeam, needsTeammates) + { + MoneyMultiplier = moneyMultiplier; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Rubber.cs b/jRandomSkills - SRC Files/src/player/skills/Rubber.cs new file mode 100644 index 0000000..945dd73 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Rubber.cs @@ -0,0 +1,74 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Rubber: ISkill + { + private const Skills skillName = Skills.Rubber; + private static float rubberTime = Config.GetValue(skillName, "slownessTime"); + private static float rubberModifier = Config.GetValue(skillName, "slownessModifier"); + + private static Dictionary playersToSlow = new Dictionary(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var attacker = @event.Attacker; + var victim = @event.Userid; + + if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return HookResult.Continue; + var attackerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == attacker.SteamID); + + if (attackerInfo?.Skill == skillName) + playersToSlow.Add(victim.PlayerPawn.Value, Server.TickCount + (64 * rubberTime)); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + playersToSlow.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterListener(OnTick); + } + + private static void OnTick() + { + foreach(var item in playersToSlow) + { + var pawn = item.Key; + var time = item.Value; + if (time >= Server.TickCount) + ChangeVelocity(pawn); + else + playersToSlow.Remove(item.Key); + } + } + + private static void ChangeVelocity(CCSPlayerPawn pawn) + { + if (pawn == null || !pawn.IsValid) return; + pawn.VelocityModifier = rubberModifier; + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float SlownessTime { get; set; } + public float SlownessModifier { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#8B4513", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float slownessTime = 2f, float slownessModifier = .2f) : base(skill, active, color, onlyTeam, needsTeammates) + { + SlownessTime = slownessTime; + SlownessModifier = slownessModifier; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Saper.cs b/jRandomSkills - SRC Files/src/player/skills/Saper.cs index f103c44..acfc79c 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Saper.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Saper.cs @@ -1,18 +1,18 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; -using jRandomSkills.src.utils; using static jRandomSkills.jRandomSkills; namespace jRandomSkills { public class Saper : ISkill { - private static Skills skillName = Skills.Saper; + private const Skills skillName = Skills.Saper; public static void LoadSkill() { - SkillUtils.RegisterSkill(skillName, "#8A2BE2"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -62,5 +62,12 @@ namespace jRandomSkills return HookResult.Continue; }); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#8A2BE2", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/SecondLife.cs b/jRandomSkills - SRC Files/src/player/skills/SecondLife.cs index a2597b3..a1e2b81 100644 --- a/jRandomSkills - SRC Files/src/player/skills/SecondLife.cs +++ b/jRandomSkills - SRC Files/src/player/skills/SecondLife.cs @@ -8,16 +8,13 @@ namespace jRandomSkills { public class SecondLife : ISkill { - private static Skills skillName = Skills.SecondLife; - private static int secondLifeHealth = 50; + private const Skills skillName = Skills.SecondLife; + private static int secondLifeHealth = Config.GetValue(skillName, "startHealth"); private static HashSet secondLifePlayers = new HashSet(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#d41c1c"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -44,21 +41,20 @@ namespace jRandomSkills Instance.RegisterEventHandler((@event, info) => { - var attacker = @event.Attacker; var victim = @event.Userid; int damage = @event.DmgHealth; - if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim)) return HookResult.Continue; + if (!Instance.IsPlayerValid(victim)) return HookResult.Continue; var victimInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == victim.SteamID); if (victimInfo == null || victimInfo.Skill != skillName) return HookResult.Continue; var victimPawn = victim.PlayerPawn.Value; - if (victimPawn.Health - damage >= 0 || secondLifePlayers.TryGetValue(victim.Handle, out _)) + if (victimPawn.Health > 0 || secondLifePlayers.TryGetValue(victim.Handle, out _) == true) return HookResult.Continue; secondLifePlayers.Add(victim.Handle); SetHealth(victim, secondLifeHealth); - victimPawn.Teleport(GetSpawnVector(victim)); + victimPawn.Teleport(GetSpawnVector(victim), victimPawn.AbsRotation, null); return HookResult.Stop; }); } @@ -98,5 +94,14 @@ namespace jRandomSkills } return new Vector(abs.X, abs.Y, abs.Z); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int StartHealth { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#d41c1c", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int startHealth = 50) : base(skill, active, color, onlyTeam, needsTeammates) + { + StartHealth = startHealth; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Shade.cs b/jRandomSkills - SRC Files/src/player/skills/Shade.cs index c5a82f3..43fd3e7 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Shade.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Shade.cs @@ -1,23 +1,27 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Utils; +using CS2TraceRay.Class; +using CS2TraceRay.Struct; using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using System.Numerics; using static CounterStrikeSharp.API.Core.Listeners; using static jRandomSkills.jRandomSkills; +using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; namespace jRandomSkills { public class Shade : ISkill { - private static Skills skillName = Skills.Shade; - private const float TeleportDistance = 100.0f; + private const Skills skillName = Skills.Shade; + private static float teleportDistance = Config.GetValue(skillName, "teleportDistance"); + private static Dictionary noSpace = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#18171A"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -35,14 +39,60 @@ namespace jRandomSkills return HookResult.Continue; }); + Instance.RegisterEventHandler((@event, info) => + { + noSpace.Clear(); + return HookResult.Continue; + }); + Instance.RegisterListener(() => { - var skillInfo = Instance.skillPlayer.FirstOrDefault(p => p.Skill == skillName); - if (skillInfo == null) return; - var player = Utilities.GetPlayerFromSteamId(skillInfo.SteamID); + foreach (var item in noSpace) + if (item.Value >= Server.TickCount) + UpdateHUD(item.Key); }); } + public static void DisableSkill(CCSPlayerController player) + { + if (noSpace.ContainsKey(player)) + noSpace.Remove(player); + } + + private static void UpdateHUD(CCSPlayerController player) + { + var skillData = SkillData.Skills.FirstOrDefault(s => s.Skill == skillName); + if (skillData == null) return; + + string infoLine = $"{Localization.GetTranslation("your_skill")}:
"; + string skillLine = $"{skillData.Name}
"; + string remainingLine = $"{Localization.GetTranslation("shade_nospace")}
"; + var hudContent = infoLine + skillLine + remainingLine; + player.PrintToCenterHtml(hudContent); + } + + private unsafe static bool CheckTeleport(CCSPlayerController player, Vector startPos, Vector endPos) + { + var pawn = player.PlayerPawn.Value; + Ray ray = new Ray(new Vector3(-16, -16, -0), new Vector3(16, 16, 72)); + CTraceFilter filter = new CTraceFilter(pawn.Index, pawn.Index) + { + m_nObjectSetMask = 0xf, + m_nCollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER_MOVEMENT, + m_nInteractsWith = pawn.GetInteractsWith(), + m_nInteractsExclude = 0, + m_nBits = 11, + m_bIterateEntities = true, + m_bHitTriggers = false, + m_nInteractsAs = 0x40000 + }; + + filter.m_nHierarchyIds[0] = pawn.GetHierarchyId(); + filter.m_nHierarchyIds[1] = 0; + CGameTrace trace = TraceRay.TraceHull(startPos, endPos, filter, ray); + return !trace.HitWorld(out _); + } + private static void TeleportAttackerBehindVictim(CCSPlayerController attacker, CCSPlayerController victim) { var victimPawn = victim.PlayerPawn.Value; @@ -50,11 +100,31 @@ namespace jRandomSkills if (victimPawn == null || attackerPawn == null) return; - Vector victimPosition = victimPawn.AbsOrigin; QAngle victimAngles = victimPawn.AbsRotation; + Vector victimEyePos = new Vector(victimPawn.AbsOrigin.X, victimPawn.AbsOrigin.Y, victimPawn.AbsOrigin.Z + victimPawn.ViewOffset.Z); + int[] angles = { 0, 90, -90 }; - Vector behindPosition = victimPosition - SkillUtils.GetForwardVector(victimAngles) * TeleportDistance; - attackerPawn.Teleport(behindPosition, victimAngles, new Vector(0, 0, 0)); + bool teleported = false; + foreach (int extraAngle in angles) + { + QAngle newAngle = new QAngle(victimAngles.X, victimAngles.Y + extraAngle, victimAngles.Z); + Vector behindPosition = victimEyePos - SkillUtils.GetForwardVector(newAngle) * teleportDistance; + if (!CheckTeleport(victim, victimEyePos, behindPosition)) continue; + attackerPawn.Teleport(behindPosition, newAngle, new Vector(0, 0, 0)); + teleported = true; + break; + } + if (!teleported) + noSpace[attacker] = Server.TickCount + (64 * 2); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float TeleportDistance { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#4d4d4d", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float teleportDistance = 100f) : base(skill, active, color, onlyTeam, needsTeammates) + { + TeleportDistance = teleportDistance; + } } } } diff --git a/jRandomSkills - SRC Files/src/player/skills/ShortBomb.cs b/jRandomSkills - SRC Files/src/player/skills/ShortBomb.cs new file mode 100644 index 0000000..17946bf --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/ShortBomb.cs @@ -0,0 +1,43 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class ShortBomb : ISkill + { + private const Skills skillName = Skills.ShortBomb; + private static int detonationTime = Config.GetValue(skillName, "detonationTime"); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + if (!Instance.IsPlayerValid(player)) return HookResult.Continue; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + var plantedBomb = Utilities.FindAllEntitiesByDesignerName("planted_c4").FirstOrDefault(); + if (plantedBomb != null) + Server.NextFrame(() => plantedBomb.C4Blow = (float)Server.EngineTime + detonationTime); + + return HookResult.Continue; + }); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int DetonationTime { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#f5b74c", CsTeam onlyTeam = CsTeam.Terrorist, bool needsTeammates = false, int detonationTime = 20) : base(skill, active, color, onlyTeam, needsTeammates) + { + DetonationTime = detonationTime; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Silent.cs b/jRandomSkills - SRC Files/src/player/skills/Silent.cs index 9269d0b..75b860e 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Silent.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Silent.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -7,14 +8,11 @@ namespace jRandomSkills { public class Silent : ISkill { - private static Skills skillName = Skills.Silent; + private const Skills skillName = Skills.Silent; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#333333"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.HookUserMessage(208, um => { @@ -36,5 +34,12 @@ namespace jRandomSkills return HookResult.Handled; }, HookMode.Pre); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#333333", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/SniperElite.cs b/jRandomSkills - SRC Files/src/player/skills/SniperElite.cs new file mode 100644 index 0000000..d49d013 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/SniperElite.cs @@ -0,0 +1,117 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class SniperElite : ISkill + { + private const Skills skillName = Skills.SniperElite; + private static readonly Dictionary sniperElites = new Dictionary(); + + private static string[] rifles = { "weapon_mp9", "weapon_mac10", "weapon_bizon", "weapon_mp7", "weapon_ump45", "weapon_p90", + "weapon_mp5sd", "weapon_famas", "weapon_galilar", "weapon_m4a1", "weapon_m4a1_silencer", "weapon_ak47", + "weapon_aug", "weapon_sg553", "weapon_ssg08", "weapon_awp", "weapon_scar20", "weapon_g3sg1", + "weapon_nova", "weapon_xm1014", "weapon_mag7", "weapon_sawedoff", "weapon_m249", "weapon_negev" }; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + sniperElites.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + if (sniperElites.ContainsKey(player.SteamID)) + sniperElites.Remove(player.SteamID); + + return HookResult.Continue; + }); + } + + public static void EnableSkill(CCSPlayerController player) + { + sniperElites.Add(player.SteamID, "weapon_awp"); + } + + public static void DisableSkill(CCSPlayerController player) + { + if (sniperElites.ContainsKey(player.SteamID)) + sniperElites.Remove(player.SteamID); + } + + public static void UseSkill(CCSPlayerController player) + { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn?.CBodyComponent == null) return; + + if (sniperElites.ContainsKey(player.SteamID)) + RemoveAndGiveWeapon(player); + } + + private static void RemoveAndGiveWeapon(CCSPlayerController player) + { + string holdedWeapon = "weapon_awp"; + if (sniperElites.TryGetValue(player.SteamID, out string weapon)) + holdedWeapon = weapon; + + try + { + string activeRifle = GetActiveRifle(player); + if (activeRifle != null) + player.RemoveItemByDesignerName(activeRifle, true); + sniperElites[player.SteamID] = activeRifle; + Server.NextFrame(() => + { + player.GiveNamedItem(holdedWeapon ?? "weapon_awp"); + }); + } + catch { } + } + + private static string GetActiveRifle(CCSPlayerController player) + { + string rifle = null; + var weapons = player.PlayerPawn.Value.WeaponServices.MyWeapons; + if (weapons == null) return rifle; + + foreach (var weapon in weapons) + if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid) + if (rifles.Contains(weapon.Value.DesignerName)) + rifle = weapon.Value.DesignerName; + return rifle; + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = false, string color = "#e0873a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Soldier.cs b/jRandomSkills - SRC Files/src/player/skills/Soldier.cs index a72357b..4bbe417 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Soldier.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Soldier.cs @@ -11,14 +11,11 @@ namespace jRandomSkills { public class Soldier : ISkill { - private static Skills skillName = Skills.Soldier; + private const Skills skillName = Skills.Soldier; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#09ba00", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); Instance.RegisterEventHandler((@event, info) => @@ -42,11 +39,7 @@ namespace jRandomSkills public static void EnableSkill(CCSPlayerController player) { var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); - - var skillConfig = Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString()); - if (skillConfig == null) return; - - float newScale = (float)Instance.Random.NextDouble() * (skillConfig.ChanceTo - skillConfig.ChanceFrom) + skillConfig.ChanceFrom; + float newScale = (float)Instance.Random.NextDouble() * (Config.GetValue(skillName, "ChanceTo") - Config.GetValue(skillName, "ChanceFrom")) + Config.GetValue(skillName, "ChanceFrom"); playerInfo.SkillChance = newScale; newScale = (float)Math.Round(newScale, 2); SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{Localization.GetTranslation("soldier")}{ChatColors.Lime}: " + Localization.GetTranslation("soldier_desc2", newScale), false); @@ -82,5 +75,16 @@ namespace jRandomSkills return HookResult.Continue; } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float ChanceFrom { get; set; } + public float ChanceTo { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#09ba00", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float chanceFrom = 1.15f, float chanceTo = 1.35f) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChanceFrom = chanceFrom; + ChanceTo = chanceTo; + } + } } } \ 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 43798f0..3729729 100644 --- a/jRandomSkills - SRC Files/src/player/skills/SoundMaker.cs +++ b/jRandomSkills - SRC Files/src/player/skills/SoundMaker.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using jRandomSkills.src.utils; using static CounterStrikeSharp.API.Core.Listeners; @@ -9,16 +10,13 @@ namespace jRandomSkills { public class SoundMaker : ISkill { - private static Skills skillName = Skills.SoundMaker; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.SoundMaker; + private static float timerCooldown = Config.GetValue(skillName, "Cooldown"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#e3ed8c"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -128,10 +126,7 @@ namespace jRandomSkills { foreach (var enemy in Utilities.GetPlayers().Where(p => p.Team != player.Team)) if (enemy != null && enemy.IsValid && enemy.PawnIsAlive) - { - Server.PrintToChatAll($"Sound event on {enemy.PlayerName}"); enemy.PlayerPawn.Value.EmitSound($"weapon.C4Beep.Impact", volume: 1f); - } } public class PlayerSkillInfo @@ -141,5 +136,14 @@ namespace jRandomSkills public DateTime Cooldown { get; set; } public DateTime LastClick { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#e3ed8c", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 5f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Spectator.cs b/jRandomSkills - SRC Files/src/player/skills/Spectator.cs new file mode 100644 index 0000000..fdbb773 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Spectator.cs @@ -0,0 +1,153 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using System.Drawing; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Spectator : ISkill + { + private const Skills skillName = Skills.Spectator; + private static bool blocked = false; + private static float distance = Config.GetValue(skillName, "distance"); + private static Dictionary cameras = new Dictionary(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + blocked = true; + foreach (var player in Utilities.GetPlayers()) + if (cameras.TryGetValue(player.SteamID, out _)) + DisableSkill(player); + + foreach (var camera in cameras) + camera.Value.Item2.Remove(); + cameras.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + blocked = false; + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + var player = @event.Userid; + if (!Instance.IsPlayerValid(player)) return HookResult.Continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + + if (playerInfo?.Skill != skillName) return HookResult.Continue; + + if (cameras.TryGetValue(player.SteamID, out var cameraInfo) && cameraInfo.Item1 != player.PlayerPawn.Value.CameraServices!.ViewEntity!.Raw) + BlockWeapon(player, true); + return HookResult.Continue; + }); + + Instance.RegisterListener(OnTick); + } + + public static void UseSkill(CCSPlayerController player) + { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn?.CBodyComponent == null || blocked) return; + ChangeCamera(player); + } + + public static void DisableSkill(CCSPlayerController player) + { + ChangeCamera(player, true); + } + + private static void OnTick() + { + foreach (var player in Utilities.GetPlayers()) + if (cameras.TryGetValue(player.SteamID, out var cameraInfo) && cameraInfo.Item2.IsValid) + { + var pawn = cameraInfo.Item3; + if (pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) + { + ChangeCamera(player, true); + continue; + } + var pos = pawn.AbsOrigin - SkillUtils.GetForwardVector(pawn.EyeAngles) * distance; + pos.Z += pawn.ViewOffset.Z; + cameraInfo.Item2.Teleport(pos, pawn.V_angle); + } + } + + private static void ChangeCamera(CCSPlayerController player, bool forceToDefault = false) + { + uint orginalCameraRaw; + uint newCameraRaw; + var pawn = player.PlayerPawn.Value; + if (cameras.TryGetValue(player.SteamID, out var cameraInfo) && cameraInfo.Item2.IsValid) + { + orginalCameraRaw = cameraInfo.Item1; + cameraInfo.Item2.Remove(); + newCameraRaw = CreateCamera(player); + } else + { + orginalCameraRaw = pawn!.CameraServices!.ViewEntity.Raw; + newCameraRaw = CreateCamera(player); + } + + if (newCameraRaw == 0) + return; + + bool defaultCam = forceToDefault ? true : (pawn.CameraServices!.ViewEntity!.Raw == orginalCameraRaw ? false : true); + pawn!.CameraServices!.ViewEntity.Raw = defaultCam ? orginalCameraRaw : newCameraRaw; + Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_pCameraServices"); + BlockWeapon(player, !defaultCam); + } + + private static uint CreateCamera(CCSPlayerController player) + { + var camera = Utilities.CreateEntityByName("prop_dynamic"); + if (camera == null || !camera.IsValid) return 0; + + var enemies = Utilities.GetPlayers().Where(p => p.PawnIsAlive && p.Team != player.Team).ToList(); + if (enemies.Count == 0) + return 0; + var enemy = enemies[Instance.Random.Next(enemies.Count)]; + + var pawn = enemy.PlayerPawn.Value; + camera.Render = Color.FromArgb(0, 255, 255, 255); + camera.Teleport(pawn!.AbsOrigin, pawn.EyeAngles); + camera.DispatchSpawn(); + if (cameras.TryGetValue(player.SteamID, out var cameraInfo)) + cameras[player.SteamID] = (cameraInfo.Item1, camera, pawn); + else + cameras[player.SteamID] = (player.PlayerPawn.Value.CameraServices!.ViewEntity.Raw, camera, pawn); + return camera.EntityHandle.Raw; + } + + private static void BlockWeapon(CCSPlayerController player, bool block) + { + foreach (var weapon in player.Pawn.Value.WeaponServices?.MyWeapons) + if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid) + { + weapon.Value.NextPrimaryAttackTick = block ? int.MaxValue : Server.TickCount; + weapon.Value.NextSecondaryAttackTick = block ? int.MaxValue : Server.TickCount; + + Utilities.SetStateChanged(weapon.Value, "CBasePlayerWeapon", "m_nNextPrimaryAttackTick"); + Utilities.SetStateChanged(weapon.Value, "CBasePlayerWeapon", "m_nNextSecondaryAttackTick"); + } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Distance { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#42f5da", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float distance = 100f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Distance = distance; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/SwapPosition.cs b/jRandomSkills - SRC Files/src/player/skills/SwapPosition.cs index a579f47..4bf6219 100644 --- a/jRandomSkills - SRC Files/src/player/skills/SwapPosition.cs +++ b/jRandomSkills - SRC Files/src/player/skills/SwapPosition.cs @@ -10,16 +10,13 @@ namespace jRandomSkills { public class SwapPosition : ISkill { - private static Skills skillName = Skills.SwapPosition; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.SwapPosition; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#1466F5"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -173,5 +170,14 @@ namespace jRandomSkills public DateTime LastClick { get; set; } public bool FindedEnemy { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#1466F5", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 30f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Teleporter.cs b/jRandomSkills - SRC Files/src/player/skills/Teleporter.cs index c0e02d9..5777541 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Teleporter.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Teleporter.cs @@ -8,14 +8,11 @@ namespace jRandomSkills { public class Teleporter : ISkill { - private static Skills skillName = Skills.Teleporter; + private const Skills skillName = Skills.Teleporter; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#8A2BE2"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -51,5 +48,12 @@ namespace jRandomSkills victimPawn.Teleport(attackerPosition, attackerAngles, attackerVelocity); attackerPawn.Teleport(victimPosition, victimAngles, victimVelocity); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#8A2BE2", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } diff --git a/jRandomSkills - SRC Files/src/player/skills/Thief.cs b/jRandomSkills - SRC Files/src/player/skills/Thief.cs index 4e5fd57..5b8a679 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Thief.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Thief.cs @@ -3,21 +3,17 @@ using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using jRandomSkills.src.utils; -using static CounterStrikeSharp.API.Core.Listeners; using static jRandomSkills.jRandomSkills; namespace jRandomSkills { public class Thief : ISkill { - private static Skills skillName = Skills.Thief; + private const Skills skillName = Skills.Thief; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#adaec7", false); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color"), false); Instance.RegisterEventHandler((@event, info) => { @@ -106,5 +102,12 @@ namespace jRandomSkills enemy.PrintToChat($" {ChatColors.Red}" + Localization.GetTranslation("thief_enemy_info")); } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#adaec7", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/ThirdEye.cs b/jRandomSkills - SRC Files/src/player/skills/ThirdEye.cs new file mode 100644 index 0000000..e0bcffe --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/ThirdEye.cs @@ -0,0 +1,122 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using System.Drawing; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class ThirdEye : ISkill + { + private const Skills skillName = Skills.ThirdEye; + private static bool blocked = false; + private static float distance = Config.GetValue(skillName, "distance"); + private static Dictionary cameras = new Dictionary(); + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + blocked = true; + foreach (var player in Utilities.GetPlayers()) + if (cameras.TryGetValue(player.SteamID, out _)) + DisableSkill(player); + + foreach (var camera in cameras) + camera.Value.Item2.Remove(); + cameras.Clear(); + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + blocked = false; + return HookResult.Continue; + }); + + Instance.RegisterListener(OnTick); + } + + public static void UseSkill(CCSPlayerController player) + { + var playerPawn = player.PlayerPawn.Value; + if (playerPawn?.CBodyComponent == null || blocked) return; + ChangeCamera(player); + } + + public static void DisableSkill(CCSPlayerController player) + { + ChangeCamera(player, true); + } + + private static void OnTick() + { + foreach (var player in Utilities.GetPlayers()) + if (cameras.TryGetValue(player.SteamID, out var cameraInfo) && cameraInfo.Item2.IsValid) + { + var pawn = player.PlayerPawn.Value; + if (pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) + { + ChangeCamera(player, true); + continue; + } + var pos = pawn.AbsOrigin - SkillUtils.GetForwardVector(pawn.EyeAngles) * distance; + pos.Z += pawn.ViewOffset.Z; + cameraInfo.Item2.Teleport(pos, pawn.V_angle); + } + } + + private static void ChangeCamera(CCSPlayerController player, bool forceToDefault = false) + { + uint orginalCameraRaw; + uint newCameraRaw; + var pawn = player.PlayerPawn.Value; + if (cameras.TryGetValue(player.SteamID, out var cameraInfo) && cameraInfo.Item2.IsValid) + { + orginalCameraRaw = cameraInfo.Item1; + newCameraRaw = cameraInfo.Item2.EntityHandle.Raw; + } else + { + orginalCameraRaw = pawn!.CameraServices!.ViewEntity.Raw; + newCameraRaw = CreateCamera(player); + } + + if (newCameraRaw == 0) + return; + + if (forceToDefault) + pawn!.CameraServices!.ViewEntity.Raw = orginalCameraRaw; + else + pawn!.CameraServices!.ViewEntity.Raw = + pawn.CameraServices!.ViewEntity!.Raw == orginalCameraRaw + ? newCameraRaw + : orginalCameraRaw; + Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_pCameraServices"); + } + + private static uint CreateCamera(CCSPlayerController player) + { + var camera = Utilities.CreateEntityByName("prop_dynamic"); + if (camera == null || !camera.IsValid) return 0; + + var pawn = player.PlayerPawn.Value; + camera.Render = Color.FromArgb(0, 255, 255, 255); + camera.Teleport(pawn!.AbsOrigin, pawn.EyeAngles); + camera.DispatchSpawn(); + cameras[player.SteamID] = (pawn.CameraServices!.ViewEntity.Raw, camera); + return camera.EntityHandle.Raw; + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Distance { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#1b04cc", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float distance = 100f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Distance = distance; + } + } + } +} \ 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 2da84b9..16caee9 100644 --- a/jRandomSkills - SRC Files/src/player/skills/ToxicSmoke.cs +++ b/jRandomSkills - SRC Files/src/player/skills/ToxicSmoke.cs @@ -1,9 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Entities; using CounterStrikeSharp.API.Modules.Entities.Constants; -using CounterStrikeSharp.API.Modules.Memory; -using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static CounterStrikeSharp.API.Core.Listeners; @@ -13,85 +10,89 @@ namespace jRandomSkills { public class ToxicSmoke : ISkill { - private static Skills skillName = Skills.ToxicSmoke; - private static List players = new List(); - private static Dictionary triggers = new Dictionary(); + private const Skills skillName = Skills.ToxicSmoke; + private static int smokeDamage = Config.GetValue(skillName, "smokeDamage"); + private static float smokeRadius = Config.GetValue(skillName, "smokeRadius"); + private static List smokes = new List(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#507529"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { - players.Clear(); + smokes.Clear(); return HookResult.Continue; }); - Instance.RegisterEventHandler((@event, @info) => + Instance.RegisterEventHandler((@event, info) => + { + Instance.AddTimer(0.1f, () => + { + foreach (var player in Utilities.GetPlayers()) + { + if (!Instance.IsPlayerValid(player)) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) continue; + EnableSkill(player); + } + }); + + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => { var player = @event.Userid; - if (!Instance.IsPlayerValid(player)) return HookResult.Continue; - var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo?.Skill != skillName) return HookResult.Continue; - - var trigger = Utilities.CreateEntityByName("trigger_multiple"); - if (trigger == null) return HookResult.Continue; - - trigger.Collision.SolidType = SolidType_t.SOLID_CAPSULE; - trigger.Collision.SolidFlags = 0; - trigger.Spawnflags = 1; - trigger.Globalname = $"toxic_smoke_{trigger.Index}"; - trigger.Collision.SolidFlags = 1; - - trigger.AbsOrigin.X = @event.X; - trigger.AbsOrigin.Y = @event.Y; - trigger.AbsOrigin.Z = @event.Z; - - trigger.Collision.CapsuleRadius = 160; - trigger.Collision.BoundingRadius = 160; - - trigger.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_TRIGGER; - trigger.Collision.EnablePhysics = 1; - trigger.Collision.TriggerBloat = 0; - - trigger.Collision.SurroundType = SurroundingBoundsType_t.USE_OBB_COLLISION_BOUNDS; - trigger.Collision.CollisionAttribute.CollisionFunctionMask = 39; - trigger.Collision.CollisionAttribute.CollisionGroup = 2; - - trigger.DispatchSpawn(); - triggers.Add(@event.Entityid, trigger); + smokes.Add(new Vector(@event.X, @event.Y, @event.Z)); return HookResult.Continue; }); Instance.RegisterEventHandler((@event, @info) => { var player = @event.Userid; - if (!Instance.IsPlayerValid(player)) return HookResult.Continue; - - if (triggers.TryGetValue(@event.Entityid, out var existingTrigger)) - { - existingTrigger.AcceptInput("Kill"); - triggers.Remove(@event.Entityid); - } - + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return HookResult.Continue; + smokes.RemoveAll(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z); return HookResult.Continue; }); + Instance.RegisterListener(@event => + { + var name = @event.DesignerName; + if (name != "smokegrenade_projectile") return; + + var grenade = @event.As(); + var pawn = grenade.OwnerEntity.Value.As(); + var player = pawn.Controller.Value.As(); + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return; + + Server.NextFrame(() => + { + var smoke = @event.As(); + smoke.SmokeColor.X = 255; + smoke.SmokeColor.Y = 0; + smoke.SmokeColor.Z = 255; + }); + }); + Instance.RegisterListener(() => { - foreach (CCSPlayerPawn player in players) - { - if (Server.TickCount % 10 == 0) - AddHealth(player, -2); - } + foreach (Vector smokePos in smokes) + foreach (var player in Utilities.GetPlayers()) + if (Server.TickCount % 17 == 0) + if (SkillUtils.GetDistance(smokePos, player.PlayerPawn.Value.AbsOrigin) <= smokeRadius) + AddHealth(player.PlayerPawn.Value, -smokeDamage); }); + } - VirtualFunctions.CBaseTrigger_StartTouchFunc.Hook(StartTouchFun, HookMode.Post); - VirtualFunctions.CBaseTrigger_EndTouchFunc.Hook(EndTouchFunc, HookMode.Post); + public static void EnableSkill(CCSPlayerController player) + { + SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade); } private static void AddHealth(CCSPlayerPawn player, int health) @@ -102,46 +103,20 @@ namespace jRandomSkills player.Health += health; Utilities.SetStateChanged(player, "CBaseEntity", "m_iHealth"); - player.EmitSound(""); + player.EmitSound("Player.DamageBody.Onlooker"); if (player.Health <= 0) player.CommitSuicide(false, true); } - private static HookResult StartTouchFun(DynamicHook h) + public class SkillConfig : Config.DefaultSkillInfo { - CBaseTrigger trigger = h.GetParam(0); - CBaseEntity entity = h.GetParam(1); - - if (trigger == null || entity == null) - return HookResult.Continue; - - CCSPlayerPawn player = new CCSPlayerPawn(entity.Handle); - if (player == null) return HookResult.Continue; - - if (string.IsNullOrEmpty(trigger?.Globalname) || trigger?.Globalname?.StartsWith("toxic_smoke_") == false) - return HookResult.Continue; - - if (!players.Contains(player)) - players.Add(player); - return HookResult.Continue; - } - - private static HookResult EndTouchFunc(DynamicHook h) - { - var trigger = h.GetParam(0); - var entity = h.GetParam(1); - - if (trigger == null || entity == null) return HookResult.Continue; - - CCSPlayerPawn player = new CCSPlayerPawn(entity.Handle); - if (player == null) return HookResult.Continue; - - if (string.IsNullOrEmpty(trigger?.Globalname) || trigger?.Globalname?.StartsWith("toxic_smoke_") == false) - return HookResult.Continue; - - if (players.Contains(player)) - players.Remove(player); - return HookResult.Continue; + public int SmokeDamage { get; set; } + public float SmokeRadius { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#507529", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int smokeDamage = 2, float smokeRadius = 180) : base(skill, active, color, onlyTeam, needsTeammates) + { + SmokeDamage = smokeDamage; + SmokeRadius = smokeRadius; + } } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Wallhack.cs b/jRandomSkills - SRC Files/src/player/skills/Wallhack.cs index c604f1d..307029e 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Wallhack.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Wallhack.cs @@ -1,9 +1,8 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Entities; +using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; -using System.Collections.Generic; using System.Drawing; using static jRandomSkills.jRandomSkills; @@ -11,16 +10,13 @@ namespace jRandomSkills { public class Wallhack : ISkill { - private static Skills skillName = Skills.Wallhack; - private static List glows = new List(); - private static Dictionary orginalTeams = new Dictionary(); + private const Skills skillName = Skills.Wallhack; + private static bool exists = false; + private static List<(CDynamicProp, CDynamicProp)> glows = new List<(CDynamicProp, CDynamicProp)>(); public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#5d00ff"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, @info) => { @@ -33,42 +29,51 @@ namespace jRandomSkills var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); if (playerInfo?.Skill == skillName) - { EnableSkill(player); - } } + + if (exists) + Instance.RegisterListener(CheckTransmit); }); return HookResult.Continue; }); Instance.RegisterEventHandler((@event, @info) => { - DisableSkill(null); + foreach (var glow in glows) + { + glow.Item1.Remove(); + glow.Item2.Remove(); + } + glows.Clear(); + + if (exists) + Instance.RemoveListener(CheckTransmit); + exists = false; return HookResult.Continue; }); } - public static void EnableSkill(CCSPlayerController player) + public static void CheckTransmit([CastFrom(typeof(nint))] CCheckTransmitInfoList infoList) { - SetGlowEffectForEnemies(player); - orginalTeams.TryAdd(player, player.TeamNum); - player.PlayerPawn.Value.TeamNum = 1; + foreach (var (info, player) in infoList) + { + if (player == null) continue; + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) continue; + + foreach (var glow in glows) + { + info.TransmitEntities.Remove(glow.Item1); + info.TransmitEntities.Remove(glow.Item2); + } + } } - public static void DisableSkill(CCSPlayerController player) + public static void EnableSkill(CCSPlayerController player) { - foreach (var glow in glows) - { - glows.Remove(glow); - glow.Remove(); - } - - foreach (var orginalTeam in orginalTeams) - { - if (orginalTeam.Key != null) - orginalTeam.Key.PlayerPawn.Value.TeamNum = orginalTeam.Value; - orginalTeams.Remove(orginalTeam.Key); - } + exists = true; + SetGlowEffectForEnemies(player); } private static async void SetGlowEffectForEnemies(CCSPlayerController player) @@ -101,13 +106,20 @@ namespace jRandomSkills modelGlow.Glow.GlowColorOverride = enemy.Team == CsTeam.Terrorist ? Color.FromArgb(255, 255, 165, 0) : Color.FromArgb(255, 173, 216, 230); modelGlow.Glow.GlowRange = 5000; - modelGlow.Glow.GlowTeam = (int)CsTeam.Spectator; + modelGlow.Glow.GlowTeam = (int)player.Team; modelGlow.Glow.GlowType = 3; modelGlow.Glow.GlowRangeMin = 100; modelRelay.AcceptInput("FollowEntity", enemyPawn, modelRelay, "!activator"); modelGlow.AcceptInput("FollowEntity", modelRelay, modelGlow, "!activator"); - glows.Add(modelRelay); + glows.Add((modelRelay, modelGlow)); + } + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#5d00ff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { } } } diff --git a/jRandomSkills - SRC Files/src/player/skills/Watchmaker.cs b/jRandomSkills - SRC Files/src/player/skills/Watchmaker.cs new file mode 100644 index 0000000..dbc38f0 --- /dev/null +++ b/jRandomSkills - SRC Files/src/player/skills/Watchmaker.cs @@ -0,0 +1,93 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; +using jRandomSkills.src.player; +using jRandomSkills.src.utils; +using static CounterStrikeSharp.API.Core.Listeners; +using static jRandomSkills.jRandomSkills; + +namespace jRandomSkills +{ + public class Watchmaker : ISkill + { + private const Skills skillName = Skills.Watchmaker; + private static int roundTime = Config.GetValue(skillName, "changeRoundTime"); + private static bool bombPlanted = false; + + public static void LoadSkill() + { + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); + + Instance.RegisterEventHandler((@event, info) => + { + bombPlanted = false; + return HookResult.Continue; + }); + + Instance.RegisterEventHandler((@event, info) => + { + bombPlanted = true; + return HookResult.Continue; + }); + + Instance.RegisterListener(@event => + { + var name = @event.DesignerName; + if (!name.EndsWith("_projectile")) + return; + + var grenade = @event.As(); + if (grenade.OwnerEntity.Value == null || !grenade.OwnerEntity.Value.IsValid) return; + + var pawn = grenade.OwnerEntity.Value.As(); + var player = pawn.Controller.Value.As(); + + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill != skillName) return; + + Instance.GameRules.RoundTime += player.Team == CsTeam.Terrorist ? roundTime : -roundTime; + if (player.Team == CsTeam.Terrorist) + Server.PrintToChatAll($" {ChatColors.Orange}{Localization.GetTranslation("watchmaker_tt", roundTime)}"); + else + Server.PrintToChatAll($" {ChatColors.LightBlue}{Localization.GetTranslation("watchmaker_ct", roundTime)}"); + }); + + Instance.RegisterListener(OnTick); + } + + private static void OnTick() + { + if (bombPlanted) return; + foreach (var player in Utilities.GetPlayers()) + { + var playerInfo = Instance.skillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); + if (playerInfo?.Skill == skillName) + UpdateHUD(player); + } + } + + private static void UpdateHUD(CCSPlayerController player) + { + var skillData = SkillData.Skills.FirstOrDefault(s => s.Skill == skillName); + if (skillData == null) return; + + int seconds = 1 + (int)(Instance.GameRules.RoundTime - (Server.CurrentTime - Instance.GameRules.RoundStartTime)); + + string infoLine = $"{Localization.GetTranslation("your_skill")}:
"; + string skillLine = $"{skillData.Name}
"; + string remainingLine = $"{SkillUtils.SecondsToTimer(seconds)}
"; + + var hudContent = infoLine + skillLine + remainingLine; + player.PrintToCenterHtml(hudContent); + } + + public class SkillConfig : Config.DefaultSkillInfo + { + public int ChangeRoundTime { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff462e", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, int changeRoundTime = 10) : base(skill, active, color, onlyTeam, needsTeammates) + { + ChangeRoundTime = changeRoundTime; + } + } + } +} \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/WeaponsSwap.cs b/jRandomSkills - SRC Files/src/player/skills/WeaponsSwap.cs index 0d6754f..fdba592 100644 --- a/jRandomSkills - SRC Files/src/player/skills/WeaponsSwap.cs +++ b/jRandomSkills - SRC Files/src/player/skills/WeaponsSwap.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using jRandomSkills.src.utils; using static CounterStrikeSharp.API.Core.Listeners; @@ -9,8 +10,8 @@ namespace jRandomSkills { public class WeaponsSwap : ISkill { - private static Skills skillName = Skills.WeaponsSwap; - private static float timerCooldown = (float)(Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Cooldown); + private const Skills skillName = Skills.WeaponsSwap; + private static float timerCooldown = Config.GetValue(skillName, "cooldown"); private static readonly Dictionary SkillPlayerInfo = new Dictionary(); private static string[] weapons = { "weapon_deagle", "weapon_revolver", "weapon_glock", "weapon_usp_silencer", @@ -22,10 +23,7 @@ namespace jRandomSkills public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#c7e03a"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -127,14 +125,6 @@ namespace jRandomSkills player.PrintToCenterHtml(hudContent); } - private static void ActiveUse(CCSPlayerController player) - { - if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo)) - { - skillInfo.CanUse = true; - } - } - public static void UseSkill(CCSPlayerController player) { var playerPawn = player.PlayerPawn.Value; @@ -212,5 +202,14 @@ namespace jRandomSkills public bool FindedEnemy { get; set; } public bool HaveWeapon { get; set; } } + + public class SkillConfig : Config.DefaultSkillInfo + { + public float Cooldown { get; set; } + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#c7e03a", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false, float cooldown = 30f) : base(skill, active, color, onlyTeam, needsTeammates) + { + Cooldown = cooldown; + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/player/skills/Zeus.cs b/jRandomSkills - SRC Files/src/player/skills/Zeus.cs index 01b91ee..bce41c1 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Zeus.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Zeus.cs @@ -1,6 +1,7 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using static jRandomSkills.jRandomSkills; @@ -8,14 +9,11 @@ namespace jRandomSkills { public class Zeus : ISkill { - private static Skills skillName = Skills.Zeus; + private const Skills skillName = Skills.Zeus; public static void LoadSkill() { - if (Config.config.SkillsInfo.FirstOrDefault(s => s.Name == skillName.ToString())?.Active != true) - return; - - SkillUtils.RegisterSkill(skillName, "#fbff00"); + SkillUtils.RegisterSkill(skillName, Config.GetValue(skillName, "color")); Instance.RegisterEventHandler((@event, info) => { @@ -63,5 +61,12 @@ namespace jRandomSkills { SkillUtils.TryGiveWeapon(player, CsItem.Zeus); } + + public class SkillConfig : Config.DefaultSkillInfo + { + public SkillConfig(Skills skill = skillName, bool active = true, string color = "#fbff00", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) : base(skill, active, color, onlyTeam, needsTeammates) + { + } + } } } \ No newline at end of file diff --git a/jRandomSkills - SRC Files/src/utils/Config.cs b/jRandomSkills - SRC Files/src/utils/Config.cs index c6606cd..44c8672 100644 --- a/jRandomSkills - SRC Files/src/utils/Config.cs +++ b/jRandomSkills - SRC Files/src/utils/Config.cs @@ -1,6 +1,9 @@ +using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; using Microsoft.Extensions.Logging; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Reflection; using static jRandomSkills.jRandomSkills; namespace jRandomSkills @@ -29,16 +32,30 @@ namespace jRandomSkills return defaultConfig; } + string json = File.ReadAllText(configPath); + var config = new ConfigModel(); + try { - string json = File.ReadAllText(configPath); - return JsonConvert.DeserializeObject(json) ?? new ConfigModel(); + var root = JsonConvert.DeserializeObject(json); + + var settings = root["Settings"]; + if (settings != null) JsonConvert.PopulateObject(settings.ToString(), config.Settings); + + var skillsArray = (JArray)root["SkillsInfo"]; + foreach (var skillObj in skillsArray) + { + string name = skillObj["Name"]?.ToString(); + var instance = config.SkillsInfo.FirstOrDefault(x => x.Name == name); + if (instance != null) JsonConvert.PopulateObject(skillObj.ToString(), instance); + } } catch (Exception ex) { - Instance.Logger.LogError($"Error when loading the config file."); - return new ConfigModel(); + Instance.Logger.LogError($"Error when loading the config file: {ex.Message}"); } + + return config; } public static void SaveConfig(ConfigModel config) @@ -66,110 +83,118 @@ namespace jRandomSkills fileWatcher.EnableRaisingEvents = true; } + public static T GetValue(object skill, string key) + { + var skillConfig = config.SkillsInfo.FirstOrDefault(s => s.Name == skill.ToString()); + + var prop = skillConfig.GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); + if (prop != null) + { + var value = prop.GetValue(skillConfig); + if (value == null) return default!; + else return (T)Convert.ChangeType(value, typeof(T)); + } + + var field = skillConfig.GetType().GetField(key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); + if (field != null) + { + var value = field.GetValue(skillConfig); + if (value == null) return default!; + else return (T)Convert.ChangeType(value, typeof(T)); + } + + return default!; + } + public class ConfigModel { - // Team: 2 - TT, 3 - CT - public Settings Settings { get; set; } = new Settings(); - public SkillInfo[] SkillsInfo = { - new SkillInfo(Skills.None), + public DefaultSkillInfo[] SkillsInfo { get; set; } - new SkillInfo(Skills.NoRecoil), - new SkillInfo(Skills.SecondLife), - new SkillInfo(Skills.C4Camouflage), - new SkillInfo(Skills.Ninja), - new SkillInfo(Skills.SoundMaker, cooldown: 5), - new SkillInfo(Skills.Prosthesis), - new SkillInfo(Skills.OnlyHead), - new SkillInfo(Skills.ReactiveArmor, cooldown: 15), - new SkillInfo(Skills.ReturnToSender), - new SkillInfo(Skills.Jammer), - new SkillInfo(Skills.RobinHood), - new SkillInfo(Skills.Hermit), - new SkillInfo(Skills.AreaReaper, team: 3), - new SkillInfo(Skills.Mute), - new SkillInfo(Skills.HolyHandGrenade), - new SkillInfo(Skills.Replicator, cooldown: 15), - new SkillInfo(Skills.ToxicSmoke), - new SkillInfo(Skills.Duplicator), - new SkillInfo(Skills.Thief), - new SkillInfo(Skills.Deactivator), - new SkillInfo(Skills.Dwarf, chanceFrom: .6f, chanceTo : .95f), - new SkillInfo(Skills.SwapPosition, cooldown: 30), - new SkillInfo(Skills.FrozenDecoy), - new SkillInfo(Skills.Soldier, chanceFrom: 1.15f, chanceTo: 1.35f), - new SkillInfo(Skills.Armored, chanceFrom: .65f, chanceTo : .85f), - new SkillInfo(Skills.Aimbot, only1v1: true), - new SkillInfo(Skills.Retreat, cooldown: 15), - new SkillInfo(Skills.EnemySpawn, cooldown: 15), - new SkillInfo(Skills.Zeus), - new SkillInfo(Skills.RadarHack), - new SkillInfo(Skills.QuickShot), - new SkillInfo(Skills.Planter, team: 2), - new SkillInfo(Skills.Silent), - new SkillInfo(Skills.KillerFlash), - new SkillInfo(Skills.TimeManipulator, cooldown: 30), - new SkillInfo(Skills.GodMode, cooldown: 30), - new SkillInfo(Skills.RandomWeapon, cooldown: 15), - new SkillInfo(Skills.WeaponsSwap, cooldown: 30), - new SkillInfo(Skills.Wallhack), - new SkillInfo(Skills.Flash, chanceFrom: 1.2f, chanceTo: 3.0f), - new SkillInfo(Skills.PawelJumper), - new SkillInfo(Skills.BunnyHop), - new SkillInfo(Skills.Impostor), - new SkillInfo(Skills.OneShot), - new SkillInfo(Skills.Muhammed), - new SkillInfo(Skills.RichBoy), - new SkillInfo(Skills.Rambo), - new SkillInfo(Skills.Medic), - new SkillInfo(Skills.Ghost), - new SkillInfo(Skills.Chicken), - new SkillInfo(Skills.Astronaut, chanceFrom: .1f, chanceTo: .7f), - new SkillInfo(Skills.Disarmament, chanceFrom: .2f, chanceTo: .4f), - new SkillInfo(Skills.AntyFlash), - new SkillInfo(Skills.Behind, chanceFrom: .2f, chanceTo: .4f), - new SkillInfo(Skills.InfiniteAmmo), - new SkillInfo(Skills.Catapult, chanceFrom : .2f, chanceTo : .4f), - new SkillInfo(Skills.Dracula), - new SkillInfo(Skills.Teleporter), - new SkillInfo(Skills.Saper), - new SkillInfo(Skills.Phoenix, chanceFrom: .2f, chanceTo: .4f), - new SkillInfo(Skills.Pilot), - new SkillInfo(Skills.Shade), - new SkillInfo(Skills.AntyHead), - }; + public ConfigModel() + { + SkillsInfo = Assembly.GetExecutingAssembly().GetTypes() + .Where(t => typeof(DefaultSkillInfo).IsAssignableFrom(t) && t.Name == "SkillConfig") + .Select(t => + { + var ctor = t.GetConstructors().FirstOrDefault(c => c.GetParameters().All(p => p.IsOptional)); + if (ctor == null) return null; + var args = ctor.GetParameters().Select(p => Type.Missing).ToArray(); + return ctor.Invoke(args) as DefaultSkillInfo; + }) + .Where(instance => instance != null) + .ToArray()!; + } } public class Settings { - public string LangCode { get; set; } = "en"; - public string Set_Skill { get; set; } = "ustawskill, setskill"; - public string SkillsList_Menu { get; set; } = "supermoc, skille, listamocy, supermoce, losowemoce"; - public bool KillerSkillInfo { get; set; } = true; - public bool TeamMateSkillInfo { get; set; } = true; - public bool SummaryAfterTheRound { get; set; } = true; + public string LangCode { get; set; } + public int GameMode { get; set; } + public bool KillerSkillInfo { get; set; } + public bool TeamMateSkillInfo { get; set; } + public bool SummaryAfterTheRound { get; set; } + public bool DebugMode { get; set; } + public string SetSkillCommands { get; set; } + public string SkillsListCommands { get; set; } + public string UseSkillCommands { get; set; } + public string ChangeMapCommands { get; set; } + public string StartGameCommands { get; set; } + public string ConsoleCommands { get; set; } + public string SwapCommands { get; set; } + public string ShuffleCommands { get; set; } + public string PauseCommands { get; set; } + public string HealCommands { get; set; } + public string SetScoreCommands { get; set; } + + public Settings() + { + LangCode = "en"; + GameMode = (int)GameModes.Normal; + KillerSkillInfo = true; + TeamMateSkillInfo = true; + SummaryAfterTheRound = true; + DebugMode = true; + + SetSkillCommands = "ustawskill, setskill, definirhabilidade, configurarhabilidade, 设置技能, 配置技能"; + SkillsListCommands = "supermoc, skille, listamocy, supermoce, skills, listaHabilidades, habilidades, 技能列表, 超能力列表"; + UseSkillCommands = "t, useSkill, usarHabilidade, 技能使用, 使用技能"; + ChangeMapCommands = "map, mapa, changemap, zmienmape, zmienmape, mudarMapa, trocarMapa, 更换地图, 更改地图"; + StartGameCommands = "start, go, começar, iniciar, 开始, 启动"; + ConsoleCommands = "console, sv, 控制台, 服务器"; + SwapCommands = "swap, zmiana, trocar, 交换, 切换"; + ShuffleCommands = "shuffle, embaralhar, 随机排序, 洗牌"; + PauseCommands = "pause, unpause, pausar, despausar, 暂停, 恢复"; + HealCommands = "heal, ulecz, curar, tratar, 治疗, 治愈"; + SetScoreCommands = "setscore, wynik, definirPontuacao, configurarPontos, 设置分数, 调整分数"; + } + } - public class SkillInfo + public class DefaultSkillInfo { - public string Name { get; set; } + public bool NeedsTeammates { get; set; } + public int OnlyTeam { get; set; } + public string Color { get; set; } public bool Active { get; set; } - public float Cooldown { get; set; } - public float ChanceFrom { get; set; } - public float ChanceTo { get; set; } - public int Team { get; set; } - public bool Only1v1 { get; set; } + public string Name { get; set; } - public SkillInfo(Skills skill, bool active = true, float cooldown = 15f, float chanceFrom = 1, float chanceTo = 1, int team = 1, bool only1v1 = false) + public DefaultSkillInfo(Skills skill, bool active = true, string color = "#ffffff", CsTeam onlyTeam = CsTeam.None, bool needsTeammates = false) { Name = skill.ToString(); Active = active; - Cooldown = cooldown; - ChanceFrom = chanceFrom; - ChanceTo = chanceTo; - Team = team; - Only1v1 = only1v1; + Color = color; + OnlyTeam = (int)onlyTeam; + NeedsTeammates = needsTeammates; } } + + public enum GameModes + { + Normal = 0, + TeamSkills = 1, + SameSkills = 2, + Debug = 3, + } } } \ 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 ec6fda7..62e6b85 100644 --- a/jRandomSkills - SRC Files/src/utils/SkillUtils.cs +++ b/jRandomSkills - SRC Files/src/utils/SkillUtils.cs @@ -1,13 +1,19 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Cvars; using CounterStrikeSharp.API.Modules.Entities.Constants; +using CounterStrikeSharp.API.Modules.Memory; +using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.player; +using System.Runtime.InteropServices; namespace jRandomSkills { public static class SkillUtils { + private static MemoryFunctionVoid TerminateRoundFunc = new(GameData.GetSignature("CCSGameRules_TerminateRound")); + public static void PrintToChat(CCSPlayerController player, string msg, bool isError) { string checkIcon = isError ? $"{ChatColors.DarkRed}✖{ChatColors.LightRed}" : $"{ChatColors.Green}✔{ChatColors.Lime}"; @@ -17,7 +23,7 @@ namespace jRandomSkills public static void RegisterSkill(Skills skill, string color, bool display = true) { if (!SkillData.Skills.Any(s => s.Skill == skill)) - SkillData.Skills.Add(new dSkill_SkillInfo(skill, color, display)); + SkillData.Skills.Add(new jSkill_SkillInfo(skill, color, display)); } public static void TryGiveWeapon(CCSPlayerController player, CsItem item, int count = 1) @@ -31,9 +37,22 @@ namespace jRandomSkills player.GiveNamedItem(item); } + public static double GetDistance(Vector vector1, Vector vector2) + { + return Math.Sqrt(Math.Pow(vector2.X - vector1.X, 2) + Math.Pow(vector2.Y - vector1.Y, 2) + Math.Pow(vector2.Z - vector1.Z, 2)); + } + + public static string SecondsToTimer(int totalSeconds) + { + if (totalSeconds <= 0) return "00:00"; + int minutes = totalSeconds / 60; + int seconds = totalSeconds % 60; + return $"{minutes:D2}:{seconds:D2}"; + } + public static Vector GetForwardVector(QAngle angles) { - float pitch = angles.X * (float)(Math.PI / 180); + float pitch = -angles.X * (float)(Math.PI / 180); float yaw = angles.Y * (float)(Math.PI / 180); float x = (float)(Math.Cos(pitch) * Math.Cos(yaw)); @@ -71,5 +90,156 @@ namespace jRandomSkills pawn.MaxHealth = maxHealth; Utilities.SetStateChanged(pawn, "CBaseEntity", "m_iMaxHealth"); } + + public static void SetTeamScores(short ctScore, short tScore, RoundEndReason roundEndReason) + { + UpdateServerTeamScores(ctScore, tScore); + TerminateRoundFunc.Invoke(jRandomSkills.Instance.GameRules.Handle, 5f, roundEndReason, 0, 0); + } + + public static void TerminateRound(CsTeam winnerTeam) + { + var teams = Utilities.FindAllEntitiesByDesignerName("cs_team_manager"); + var ctTeam = teams.First(t => t.IsValid && (CsTeam)t.TeamNum == CsTeam.CounterTerrorist); + var tTeams = teams.First(t => t.IsValid && (CsTeam)t.TeamNum == CsTeam.Terrorist); + if (ctTeam == null || tTeams == null) return; + + short ctScore = (short)(winnerTeam == CsTeam.CounterTerrorist ? ctTeam.Score + 1 : ctTeam.Score); + short tScore = (short)(winnerTeam == CsTeam.Terrorist ? tTeams.Score + 1 : tTeams.Score); + + UpdateServerTeamScores(ctScore, tScore); + TerminateRoundFunc.Invoke(jRandomSkills.Instance.GameRules.Handle, 5f, winnerTeam == CsTeam.CounterTerrorist ? RoundEndReason.BombDefused : RoundEndReason.TargetBombed, 0, 0); + } + + private static void UpdateServerTeamScores(short ctScore, short tScore) + { + int totalRoundsPlayed = ctScore + tScore; + int maxRounds = ConVar.Find("mp_maxrounds")?.GetPrimitiveValue() ?? 24; + int halfRounds = maxRounds / 2; + int overtimeMaxRounds = ConVar.Find("mp_overtime_maxrounds")?.GetPrimitiveValue() ?? 6; + int overtimeLimit = ConVar.Find("mp_overtime_limit")?.GetPrimitiveValue() ?? 1; + + var gameRulesProxy = jRandomSkills.Instance.GameRules; + gameRulesProxy.TotalRoundsPlayed = totalRoundsPlayed; + gameRulesProxy.ITotalRoundsPlayed = totalRoundsPlayed; + gameRulesProxy.RoundsPlayedThisPhase = totalRoundsPlayed; + + gameRulesProxy.TeamIntroPeriod = false; + if (gameRulesProxy.GamePhase == 1 && totalRoundsPlayed < halfRounds) + { + gameRulesProxy.GamePhase = 0; + gameRulesProxy.SwapTeamsOnRestart = true; + gameRulesProxy.SwitchingTeamsAtRoundReset = true; + gameRulesProxy.RoundsPlayedThisPhase = 0; + gameRulesProxy.TeamIntroPeriod = true; + } + + if (totalRoundsPlayed < halfRounds) + gameRulesProxy.GamePhase = 0; + else if (gameRulesProxy.GamePhase == 0) + { + gameRulesProxy.GamePhase = 1; + gameRulesProxy.SwapTeamsOnRestart = true; + gameRulesProxy.SwitchingTeamsAtRoundReset = true; + gameRulesProxy.RoundsPlayedThisPhase = 0; + gameRulesProxy.TeamIntroPeriod = true; + } + + var structOffset = jRandomSkills.Instance.GameRules.Handle + Schema.GetSchemaOffset("CCSGameRules", "m_bMapHasBombZone") + 0x02; + var matchStruct = Marshal.PtrToStructure(structOffset); + + matchStruct.m_totalScore = (short)totalRoundsPlayed; + matchStruct.m_actualRoundsPlayed = (short)totalRoundsPlayed; + gameRulesProxy.MatchInfoDecidedTime = Server.CurrentTime; + + matchStruct.m_ctScoreTotal = ctScore; + gameRulesProxy.AccountCT = ctScore; + matchStruct.m_terroristScoreTotal = tScore; + gameRulesProxy.AccountTerrorist = tScore; + + if (gameRulesProxy.GamePhase == 0) + { + matchStruct.m_ctScoreFirstHalf = ctScore; + matchStruct.m_terroristScoreFirstHalf = tScore; + } + else + { + matchStruct.m_ctScoreSecondHalf = ctScore; + matchStruct.m_terroristScoreSecondHalf = tScore; + } + + if (totalRoundsPlayed >= maxRounds) + { + if (gameRulesProxy.OvertimePlaying == 0) + { + gameRulesProxy.OvertimePlaying = 1; + gameRulesProxy.SwapTeamsOnRestart = true; + gameRulesProxy.SwitchingTeamsAtRoundReset = true; + } + else + { + int roundsInOvertime = totalRoundsPlayed - maxRounds; + if (roundsInOvertime % overtimeMaxRounds == 0) + { + int currentOvertime = roundsInOvertime / overtimeMaxRounds; + if ( currentOvertime < overtimeLimit) + { + gameRulesProxy.SwapTeamsOnRestart = true; + gameRulesProxy.SwitchingTeamsAtRoundReset = true; + } + } + } + } + gameRulesProxy.OvertimePlaying = 0; + + Marshal.StructureToPtr(matchStruct, structOffset, true); + UpdateClientTeamScores(matchStruct); + } + + private static void UpdateClientTeamScores(MCCSMatch match) + { + var teams = Utilities.FindAllEntitiesByDesignerName("cs_team_manager"); + var ctTeam = teams.First(t => t.IsValid && (CsTeam)t.TeamNum == CsTeam.CounterTerrorist); + var tTeams = teams.First(t => t.IsValid && (CsTeam)t.TeamNum == CsTeam.Terrorist); + + if (ctTeam != null && tTeams != null) + { + ctTeam.Score = match.m_ctScoreTotal; + ctTeam.ScoreFirstHalf = match.m_ctScoreFirstHalf; + ctTeam.ScoreSecondHalf = match.m_ctScoreSecondHalf; + ctTeam.ScoreOvertime = match.m_ctScoreOvertime; + Utilities.SetStateChanged(ctTeam, "CTeam", "m_iScore"); + Utilities.SetStateChanged(ctTeam, "CCSTeam", "m_scoreFirstHalf"); + Utilities.SetStateChanged(ctTeam, "CCSTeam", "m_scoreSecondHalf"); + Utilities.SetStateChanged(ctTeam, "CCSTeam", "m_scoreOvertime"); + + tTeams.Score = match.m_terroristScoreTotal; + tTeams.ScoreFirstHalf = match.m_terroristScoreFirstHalf; + tTeams.ScoreSecondHalf = match.m_terroristScoreSecondHalf; + tTeams.ScoreOvertime = match.m_terroristScoreOvertime; + Utilities.SetStateChanged(tTeams, "CTeam", "m_iScore"); + Utilities.SetStateChanged(tTeams, "CCSTeam", "m_scoreFirstHalf"); + Utilities.SetStateChanged(tTeams, "CCSTeam", "m_scoreSecondHalf"); + Utilities.SetStateChanged(tTeams, "CCSTeam", "m_scoreOvertime"); + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct MCCSMatch + { + public short m_totalScore; + public short m_actualRoundsPlayed; + public short m_nOvertimePlaying; + public short m_ctScoreFirstHalf; + public short m_ctScoreSecondHalf; + public short m_ctScoreOvertime; + public short m_ctScoreTotal; + public short m_terroristScoreFirstHalf; + public short m_terroristScoreSecondHalf; + public short m_terroristScoreOvertime; + public short m_terroristScoreTotal; + public short unknown; + public int m_phase; } } \ No newline at end of file diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/Config.json b/jRandomSkills - Server Files/plugins/jRandomSkills/Config.json deleted file mode 100644 index ccdd79b..0000000 --- a/jRandomSkills - Server Files/plugins/jRandomSkills/Config.json +++ /dev/null @@ -1,408 +0,0 @@ -{ - "SkillsInfo": [ - { - "Name": "None", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Dwarf", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 0.6, - "ChanceTo": 0.95, - "Team": 1, - "Only1v1": false - }, - { - "Name": "SwapPosition", - "Active": true, - "Cooldown": 30.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "FrozenDecoy", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Soldier", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.15, - "ChanceTo": 1.35, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Armored", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 0.65, - "ChanceTo": 0.85, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Aimbot", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": true - }, - { - "Name": "Retreat", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "EnemySpawn", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Zeus", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "RadarHack", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "QuickShot", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Planter", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 2, - "Only1v1": false - }, - { - "Name": "Silent", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "KillerFlash", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "TimeManipulator", - "Active": true, - "Cooldown": 30.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "GodMode", - "Active": true, - "Cooldown": 30.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "RandomWeapon", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "WeaponsSwap", - "Active": true, - "Cooldown": 30.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Wallhack", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Flash", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.2, - "ChanceTo": 3.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "PawelJumper", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "BunnyHop", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Impostor", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "OneShot", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Muhammed", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "RichBoy", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Rambo", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Medic", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Ghost", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Chicken", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Astronaut", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 0.1, - "ChanceTo": 0.7, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Disarmament", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 0.2, - "ChanceTo": 0.4, - "Team": 1, - "Only1v1": false - }, - { - "Name": "AntyFlash", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Behind", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 0.2, - "ChanceTo": 0.4, - "Team": 1, - "Only1v1": false - }, - { - "Name": "InfiniteAmmo", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Catapult", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 0.2, - "ChanceTo": 0.4, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Dracula", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Teleporter", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Saper", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Phoenix", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 0.2, - "ChanceTo": 0.4, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Pilot", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "Shade", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - }, - { - "Name": "AntyHead", - "Active": true, - "Cooldown": 15.0, - "ChanceFrom": 1.0, - "ChanceTo": 1.0, - "Team": 1, - "Only1v1": false - } - ], - "Settings": { - "LangCode": "en", - "Set_Skill": "ustawskill, setskill", - "SkillsList_Menu": "supermoc, skills, listamocy, supermoce, losowemoce", - "KillerSkillInfo": true, - "TeamMateSkillInfo": true, - "SummaryAfterTheRound": true - } -} \ No newline at end of file diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/jRandomSkills.dll b/jRandomSkills - Server Files/plugins/jRandomSkills/jRandomSkills.dll index 76af76eea0d2883d334efda2ad5a42160162f0a4..c82892cc06107c33fed75c180b25b1191793ed89 100644 GIT binary patch literal 340480 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

*dgDV9G>a}#EVR^=G8`nTtIDOGvQoIOfTo~K$ zX-2f4u1t|YnW~Oh_2mZBICS@w5Y6<}^ld8d<0vAc0 zY~3yue)P)IACA9Vv^U)F*`t5|$N%n+eh~iblT%HbUj3t+!_VJY_RlYDef3y=Kq-|U zWB}!^^79#BG%CN4L5M+^0WS8c{2~U$45AE57{nN?Vo=H;&cI?&#-N-*1%pc%R5GYy zP|e_d3|2F!VNlE9QU+@fO#i|EJ&$w2`vt7mGPsPvItJ?*)G>HJgAEKeGT6l6R~T$& zu!X@^2K5Z^kd(^Dv(YLaFT+v!cm`kP?_hvONdTjl>M1H9Wt zk$Wm1zd)h#_c7Sd06)T_@~>pj%-|q{76z>h+87*QaEQTG3=T6m!r*EKA7IeV;93Sp z8FVl>#^4$T#~E}o=wfgkgX#|7Hf=40;&! zGU#KFWYCWw0HAi1_g|U++xMNkQVRB z$0&U#s(Jyu8fNT;Ft{&rdcC|wW!>3((h(m%DX~JJON*WPL zl_n(gC%@<`>-Hg!J(v%Yd?qT19@r_8?5ZEbBbkvrgrPSG1|Yz1-*+EJ!lE9GWd}k# z$t<=+m1>fQ=_U+#4MF6{W6dVLgH(N64a`sD~lk(Q3D4^~+I)WV4Kh2%`!x zAju9KKtUtACoxG_BzFNA;j`=f??TU^-qXZ|nS9(@3cy!V+PuBY794{Dr3P^y_XfuB|K1h-YeZY7(s@VYel2Ue!(9LIy?F68!Lgf{lm91$6OIZA9MlguQysnUijW~NZ)kfaRvq8}1bfa)$uJR}bR z7T*jnT=))1hdezZj!I~-6NQwsK76B;7?8g<29!B743ui>wP4QdVdWjD$e)g|L2=m4 z=+P#Qsmw`+%ABE>6XK5|TvoRp51_qzN7G zKzaUi&?x}Wiu%nM*$%+WU%=9te=pQH3OMDpgzsXq3AMI^A8iPcB+VOz*ut%ylEF-& z21SRn(dOk2KsSGA%R%vpKVk;0^KojOM<_!{)FOAuMUv?N@(c^95|HH6t<(*+4DpK; zv8h2FKoWS^$Rz)!AF2;bFLh2$OeTlx%}=V~OOQHq8l%5(-?jK2}Cda#nwj?@IJ@}z_{4#Ra=-K4R z{+@;%{k!^i_cu27?P}=W(OnVf3YOxRv+={aK|D$}4hgU>0(`XfAO5dR8=_v2y;d-|l zy=b2LNna#Lxj$?G%%0E(d5$;LDR>%4rC(?8hSR>CSOD#?sWsQ9@xmdu^c;z-vN14D zB=#t`-%OJWWA;#-L0ovIpb)N!^Wnl;v3tXkOq&Mt``CcDn(QHQCr-TDO^pQypM~{K z-eD&uIHJA%90@MN*hr;tr&8!B6eK+to8mghv&}JZ76(dEhS9sb22->Y1wKpr5M*w` zongJ?WmpHMw6RU7y)lRI| ziLGT%<&p%{R8TNt4CjERFWh0EXm7#*N=b7ZNXtNO2CK0(L1X*8(G0qrwAe$)1B~rw z&@6rMR@pHYEFhSE*7S>K6Os2xNpc+5G5Ls-JjvweOyyFk{37$d&EQQ0GuV_^>06x^ z#4pWYri#H921Hbo>24=>4+~B)m_(3%kmLL;#x4ElME=* zGfy!fO6eCEdmF(lRm5z90dbh^U~n^oyBK_e!6U&!s19rPc?9WK8IVG=-(~O<1ar#i z@CPhqFvnqK0*p18(oBI9BfPo83^=wq2&pwUiy*^-=^rvlwC5fMOQ#qi>T@qT?Hx(U zIFgc~q|6bixnCf-pk)Tk$}}>$k-<&|tqe{u=won>!ABW9z~FHP9O(rT>H=vrU(SFu zn%}~J0Ot2GAb@!Sm?waF0+@f4!P5+0La?A1h*V;3$Cx0Dg)Rm|45k^d`NF*n9$~=I zEY`V5w-HxVom z!=-Yg7%00-TM%R@)JuSiM?@LBhIwhmPB54>lMk)}6V0UD=#(2x)i|ny-h%>IA$WBU zHbi(lm6J6VtSk$Y+%n;QW62vvL|c{g{62w6>s)i_TW$HJcgcroq3`gRCawz+vCK3sr63a3h}OpN%?X%_U^F-d#62Axlj$$k14wC?0%)u% za8l~@>)5iG6-X}A~0 zPzeZ`W;DI}77q-(2PGr5wIcy>}7C}A@$`OabH_<(w?iZWn7FmiH z0PPs=vtc;3KwLM(tu~|ypa48x+9zXO+82^5K{c^5I9)s!ws1cSCu7nh?#AL<_@qJO zqEr|jrV>p6jt|%imD9(h369{{q_7Y-q}UBFk6^fkg*x#P5x}J)hEE6@SUD5C`i5({ zd<-0fgv=o<9Z#cUCyuk=I*1$BK~oGYo#MDB4(r3o zulB@iJ@K`Ohxi!jCI}wxd4UGF?3CUV6v1xOg54$$1ah9>(I$$v%$an%n|;iaeGCH) zL}Llw__cwBqXyUOJbj-;+*d6cU6lyCt?+D)X@+IU9yK0(^Hp&m-|c~X58@?>LJued z=n0gBFKmHKMwfZ)q7ctGJj1@`(IFQl+CbKr?{6A)uY4R~2acIY&P z2xU_ELd_JsnN~Ei(NTsQsSFDkK9;vp#qcRc3hWG{j_5UH1tVdj$_mhaX&*z#Ji{lX zdRvhJ30ZNX$Iv#6Pm~=1`Hg~nIH1B*-*`U-99mt$OKuqN9=mpQr0ra9a*X?ru7UB< z+b0637ZN?cKcK4WuWjpU868hHkBx0HyPn&y?E!#T`JwUd;pFY3<7Zn3C&q@lr>;dZ z%oYjMumbq8jN{!SeWSzJ=nM@_C{+}|+dY##sWW(f9Gx`k-4lM0H=ybzv3cjthQ96n zeSO`#FW=M9n{3*(bN7y9Z+B1AuBL{D?mfvJy^T9|?%EDFWr?6j*PJsX==}rIsXMg64*Ry39w^`j&ygUhFV8?>jou zh1eB+r%%H}$Jv21X-FtTPzRu+2RYRkH?|yj@yL?Q-ec&$?`XQ^?OC_HGwq--eS*^-;Z+^Yt^7}%`S0_I#u*i8 z?_d?YSrkXnWv0Zc<$o;cf7N;^P3O-XwBc%u4$k9 zVqwQuzjx^>!f4rh>beOK_Ebm9ZQD<^CMV8Lj*gwWz9Tugb+~(Qc=;Hp||_}i#_!xUccwV<3DB@;~)6qm(Klj z_oqMg{D%V%oWDCbe}CyCAK0?FU`_Nl{`iYKkM8UE#E<^|j@|cuWbX2hJpAxqckR0B z^H)!uefsJAvePFXY-t$0@2{Ub_sYOCC6)jA;?B#i51oiLeEyRk ze0%eu(%7EY|m9BBJ5 zCto_X{*DuE2G;lfe*D3MS3mc0!u-OiKkj^eaLZMvfBYY={@p{fnO}_GclcK`PZjk4 z+OHq{*85f!G(CUS>DMRK+|kcpa&N;IKed&gU%TVZKM1G3GtE4H-`gDw@l*ZuWn0$% zG_Uu}?H~G+>HNPsdH)07DLhg8*fZCC?>G06cCVhi;!b{;{!jc;$ab8md|=ThC6X{ zf!as)Z~xnuw-d4J6<;@dJ-ontx3hjF?P+{p3lB1n=ajmb|BwHq*JRFo{?p$)2joA} z&8w1_*NRU7Q2FAvLwIEx->!WGFG!O&u%m3fwCX~seiu34`p6e?@+E5e-=q1T1keC* z;)~k&s=G5eAf1ys+9A$xC)~xL0e;&hhPHfl8ed<_KBh1t`xUb&zh&juqXKufHCVR- zbH2x!IE?vld^Z>kFw0yR*8>LM`R$Ic5$~dGa6Y7$h5Dor-zhqdZ@xOu#dzhu_)bfC z%R63K8w8AN(4KFi9+J_IVchyP!F-9V64iK(^p*YkU^8C!EHC1H7aF;JYC7w8d+Xms zn)G1(?sU%J9i9REz2K&8HlXhHA20faDPtD*BU--w@77l@82}rJ=V=f-#+rRR^0|knA QBqn)E|NsB}KSzQ80Thj}g#Z8m literal 150528 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 ", - "skill_not_found_setskill": "Skill CHATCOLORS.REDnot found", + "correct_form_setskill": "Correct usage: CHATCOLORS.RED!setscore ", + "done_setskill": "skill set", "error_setskill": "Failed to set CHATCOLORS.REDskill", - "done_setskill": "Skill set", "for_setskill": "for", - "none": "None", - "dwarf": "Dwarf", - "swapposition": "Swapper", - "killerflash": "Deadly Flash", - "soldier": "Soldier", - "armored": "Tank", - "aimbot": "Aimbot", - "retreat": "Retreat", - "enemyspawn": "Enemy Spawn", - "zeus": "Zeus", - "radarhack": "Radar Hack", - "quickshot": "Quick-Shot", - "planter": "Planter", - "silent": "Silent", - "frozendecoy": "Freezing Decoy", - "timemanipulator": "Time Slow", - "godmode": "God Mode", - "randomweapon": "Random Weapon", - "weaponsswap": "Weapon Swap", - "wallhack": "Wallhack", - "flash": "Flash", - "paweljumper": "Paweł Jumper", - "bunnyhop": "Bunnyhop", - "impostor": "Spy", - "oneshot": "One-Shot", - "muhammed": "Muhammed", - "richboy": "Rich Boy", - "rambo": "Rambo", - "medic": "Medic", - "ghost": "Ghost", - "chicken": "Chicken", - "astronaut": "Astronaut", - "disarmament": "Disarmament", - "antyflash": "Anti-Flash", - "behind": "Enemy Rotation", - "infiniteammo": "Infinite Ammo", - "catapult": "Catapult", - "dracula": "Dracula", - "teleporter": "Teleporter", - "saper": "Sapper", - "phoenix": "Phoenix", - "pilot": "Pilot", - "shade": "Shade", - "antyhead": "Anty Head" + "invalid_map": "Map name entered incorrectly!", + "loading_map": "Loading a new map", + + "pause": "Match has been paused.", + "unpause": "Match has been resumed.", + "healed": "You have been healed.", + "game_start": "Game started!", + + "teammate_skills": "Your teammates' skills", + "summary_start": "======SUMMARY=OF=THE=LAST=ROUND======", + "summary_end": "=======================================" } \ No newline at end of file diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/lang/pl.json b/jRandomSkills - Server Files/plugins/jRandomSkills/lang/pl.json index dcb9e11..6efaa23 100644 --- a/jRandomSkills - Server Files/plugins/jRandomSkills/lang/pl.json +++ b/jRandomSkills - Server Files/plugins/jRandomSkills/lang/pl.json @@ -1,127 +1,410 @@ { + "none": "Brak", "none_desc": "Nie posiadasz żadnej supermocy", - "aimbot_desc": "Każdy twój trafiony pocisk jest liczony jako głowa", - "antyflash_desc": "Posiadasz odporność na flashe i 7 sekund trwają twoje flash'e", - "astronaut_desc": "Otrzymujesz losową ilość grawitacji na start rundy", - "astronaut_desc2": "Twoja losowa grawitacja wynosi: {0}x", - "richboy_desc": "Otrzymujesz losową ilość kasy na start rundy", - "bunnyhop_desc": "Otrzymujesz auto \"BunnyHopa\"", - "silent_desc": "Twoje kroki i skoki są niesłyszalne dla INNYCH graczy", - "shade_desc": "Teleportujesz się za plecy trafionego wroga", - "dracula_desc": "Po trafieniu ofiary otrzymujesz zwrot zdrowia w postaci danego procentu zadanych obrażeń", - "ghost_desc": "Jesteś całkowicie niewidzialny", - "flash_desc": "Losowa prędkośc postaci na początku rundy", - "flash_desc2": "Twój mnożnik prędkości to {0}x", - "godmode_desc": "Jesteś nieśmiertelny przez 2 sekundy. Kliknij [css_useSkill], cooldown 30s", - "godmode_on": "Nieśmiertelność włączona", - "godmode_off": "Nieśmiertelność wyłączona", + + "aimbot": "Aimbot", + "aimbot_desc": "Każdy twój trafiony pocisk liczy się jako strzał w głowę", + + "anomaly": "Anomalia", + "anomaly_desc": "Cofasz się o kilka sekund do tyłu", + + "antyflash": "Anty Flash", + "antyflash_desc": "Posiadasz odporność na flash'e, a twoje flash'e trwają 7 sekund", + + "antyhead": "Żelazna Głowa", + "antyhead_desc": "Nie otrzymujesz obrażeń w głowę", + + "areareaper": "Niszczyciel Stref", + "areareaper_desc": "Możesz wybrać strefę detonacji, którą chcesz dezaktywować", + "areareaper_incorrect_site": "Nie znaleziono takiej strefy detonacji.", + "areareaper_no_site": "Nie znaleziono żadnej strefy detonacji.", + "areareaper_select_info": "Wybierz strefę detonacji, którą chcesz dezaktywować:", + "areareaper_site_disabled": "Strefa detonacji {0} została dezaktywowana - nie można na niej podłożyć bomby!", + "areareaper_used_info": "Twoja moc została już wykorzystana.", + + "armored": "Gruby", "armored_desc": "Masz losowy mnożnik otrzymywanych obrażeń", "armored_desc2": "Twój mnożnik otrzymywanych obrażeń wynosi: {0}x", - "muhammed_desc": "Po śmierci wybucha i zabija graczy w obrębie", - "dwarf_desc": "Losowa wielkość postaci na początku rundy", - "dwarf_desc2": "Twój mnożnik wielkości to {0}x", - "medic_desc": "Otrzymujesz losową ilość apteczek na start rundy", - "randomweapon_desc": "Dostajesz losową broń. Kliknij [css_useSkill], cooldown 15s", - "chicken_desc": "Otrzymujesz model kurczaka + jesteś o 10% szybszy - 50hp", - "impostor_desc": "Otrzymujesz na start rundy model postaci wroga", + + "assassin": "Skrytobójca", + "assassin_desc": "Zadajesz większe obrażenia przeciwnikowi od tyłu", + + "astronaut": "Astronauta", + "astronaut_desc": "Na początku rundy otrzymujesz losową wartość grawitacji", + "astronaut_desc2": "Twoja losowa grawitacja wynosi: {0}x", + + "baseball": "Bejsbolista", + "baseball_desc": "Twój wabik odbija się od ścian i natychmiastowo zabija wroga po trafieniu", + + "behind": "Obrót Wroga", + "behind_desc": "Masz losową szansę na obrócenie wroga o 180 stopni po trafieniu go", + "behind_desc2": "Twoje szanse na obrócenie wroga po trafieniu to: {0}%", + + "blademaster": "Mistrz Ostrza", + "blademaster_desc": "Trzymając nóż, masz duże szanse na odparcie strzału", + + "bunnyhop": "Królik", + "bunnyhop_desc": "Otrzymujesz auto \"BunnyHopa\"", + + "c4camouflage": "C4 Kamuflaż", + "c4camouflage_desc": "Kiedy trzymasz bombę, jesteś niewidzialny", + + "catapult": "Katapulta", "catapult_desc": "Masz losową szanse na podrzucenie wroga", "catapult_desc2": "Twoje szanse na podrzucenie wroga po trafieniu to: {0}%", - "infiniteammo_desc": "Otrzymujesz nieskończoną ilość ammo do wszystkich swoich broni", - "behind_desc": "Masz losową szanse na obrócenie wroga o 180 stopni po trafieniu", - "behind_desc2": "Twoje szanse na obrócenie wroga po trafieniu to: {0}%", - "retreat_desc": "Powrót na spawna. Kliknij [css_useSkill], cooldown 15s", - "oneshot_desc": "Po trafieniu od razu zabija przeciwnika", + + "chicken": "Kurczak", + "chicken_desc": "Otrzymujesz model kurczaka + jesteś o 10% szybszy - 50hp", + + "chillout": "Wyluzowany", + "chillout_desc": "Podłożenie bomby zajmuje znacznie więcej czasu", + + "cutter": "Scyzoryk", + "cutter_desc": "Natychmiastowe zabójstwo nożem", + + "darkness": "Mrok", + "darkness_desc": "Nadaje efekt ciemności wybranemu przeciwnikowi", + "darkness_enemy_info": "Niech zgasną światła.", + "darkness_player_info": "Ciemność opanowała gracza '{0}'.", + "darkness_select_info": "Wybierz gracza, któremu chcesz nadać efekt ciemności:", + + "deactivator": "Deaktywator", + "deactivator_desc": "Wybierasz gracza, którego supermoc chcesz wyłączyć", + "deactivator_enemy_info": "Twoja supermoc została wyłączona.", + "deactivator_player_info": "Moc gracza '{0}' została wyłączona.", + "deactivator_select_info": "Wybierz gracza, którego supermoc chcesz wyłączyć:", + + "deaf": "Głuchy", + "deaf_desc": "Wybierasz gracza, dla którego chcesz wyłączyć wszystkie dźwięki", + "deaf_enemy_info": "Słuchawki opuściły grę.", + "deaf_player_info": "Dźwięk został wyłączony dla gracza '{0}'.", + "deaf_select_info": "Wybierz gracza, dla którego chcesz wyłączyć wszystkie dźwięki:", + + "disarmament": "Rozbrojenie", + "disarmament_desc": "Masz losową szanse na wyrzucenie broni wroga po trafieniu", + "disarmament_desc2": "Twoje szanse na wyrzucenie broni wroga to: {0}%", + + "distancer": "Odległościomierz", + "distancer_desc": "Możesz zobaczyć odległość do najbliższego przeciwnika", + + "dracula": "Drakula", + "dracula_desc": "Po trafieniu ofiary odzyskujesz zdrowie równe pewnemu procentowi zadanych obrażeń", + + "duplicator": "Duplikator", + "duplicator_desc": "Wybierasz gracza, od którego chcesz skopiować supermoc", + "duplicator_player_info": "Moc gracza '{0}' została skopiowana.", + "duplicator_select_info": "Wybierz gracza, od którego chcesz skopiować supermoc:", + + "dwarf": "Mini Majk", + "dwarf_desc": "Losowa wielkość postaci na początku rundy", + "dwarf_desc2": "Twój mnożnik wielkości to {0}x", + + "enemyspawn": "Resp Wroga", + "enemyspawn_desc": "Kliknij [css_useSkill], aby teleportować się na resp wroga", + + "explosiveshot": "Strzał Wybuchowy", + "explosiveshot_desc": "Losowa szansa wystrzelenia pocisku wybuchowego podczas strzelania", + "explosiveshot_desc2": "Twoja szansa na wystrzelenie pocisku wybuchowego: {0}%", + + "falconeye": "Oko Sokoła", + "falconeye_desc": "Kliknij [css_useSkill], aby aktywować kamerę z lotu ptaka", + + "fastreload": "Szybkie Rączki", + "fastreload_desc": "Kliknij [css_useSkill], aby przeładować broń, którą obecnie trzymasz", + + "flash": "Flash", + "flash_desc": "Losowa prędkośc postaci na początku rundy", + "flash_desc2": "Twój mnożnik prędkości to {0}x", + + "fortnite": "Fortnite", + "fortnite_desc": "Kliknij [css_useSkill], aby stworzyć barykadę, którą można zniszczyć", + + "fragilebomb": "Krucha Bomba", + "fragilebomb_desc": "Strzelanie do bomby powoduje jej uszkodzenie", + "fragilebomb_bomb_health": "Zdrowie bomby", + + "friendlyfire": "Ogień Przyjacielski", + "friendlyfire_desc": "Strzelanie do członków drużyny leczy ich", + + "frozendecoy": "Zamrażający Wabik", + "frozendecoy_desc": "Twój decoy zamraża wszystkich graczy w pobliżu", + + "ghost": "Duszek", + "ghost_desc": "Jesteś całkowicie niewidzialny", + + "glaz": "Glaz", + "glaz_desc": "Nie widzisz granatów dymnych", + + "glitch": "Glitch", + "glitch_desc": "Wyłączasz radar wybranemu przeciwnikowi", + "glitch_enemy_info": "Twój radar został wyłączony.", + "glitch_player_info": "Radar gracza '{0}' został wyłączony.", + "glitch_select_info": "Wybierz gracza, dla którego chcesz wyłączyć radar:", + + "glue": "Klej", + "glue_desc": "Twoje granaty przyklejają się do ścian", + + "godmode": "Nieśmiertelność", + "godmode_desc": "Kliknij [css_useSkill], aby stać się nieśmiertelnym na krótką chwilę", + "godmode_off": "Nieśmiertelność wyłączona", + "godmode_on": "Nieśmiertelność włączona", + + "healingsmoke": "Leczący Dym", + "healingsmoke_desc": "Twoje granaty dymne leczą", + + "hermit": "Pustelnik", + "hermit_desc": "Zabijanie przywraca amunicję i część zdrowia", + + "holyhandgrenade": "Święty Granat Ręczny", + "holyhandgrenade_desc": "Twoje granaty uderzeniowe zadają podwójne obrażenia i mają podwójny zasięg", + + "impostor": "Szpieg", + "impostor_desc": "Na początku rundy otrzymujesz model postaci przeciwnika", + + "infiniteammo": "Nieskończone Ammo", + "infiniteammo_desc": "Otrzymujesz nieskończoną ilość amunicji do wszystkich broni", + + "jackal": "Stópkarz", + "jackal_desc": "Wybierasz gracza, który pozostawi za sobą ślad", + "jackal_player_info": "Gracz '{0}' zacznie zostawiać za sobą ślad.", + "jackal_select_info": "Wybierz gracza, który pozostawi za sobą ślad:", + + "jammer": "Zakłócacz", + "jammer_desc": "Wybierasz gracza, dla którego chcesz wyłączyć celownik", + "jammer_enemy_info": "Twój celownik został wyłączony.", + "jammer_player_info": "Celownik gracza '{0}' została wyłączona.", + "jammer_select_info": "Wybierz gracza, dla którego chcesz wyłączyć celownik:", + + "jumpban": "Beznogi", + "jumpban_desc": "Wybierasz gracza, który nie będzie mógł skakać", + "jumpban_enemy_info": "Ktoś odciął ci nogi.", + "jumpban_player_info": "Gracz '{0}' nie może teraz skakać.", + "jumpban_select_info": "Wybierz gracza, który nie będzie mógł skakać:", + + "jumpingjack": "Pajacyk", + "jumpingjack_desc": "Skakanie przywraca zdrowie", + + "killerflash": "Zabójczy Flash", + "killerflash_desc": "Każdy całkowicie oślepiony twoim granatem umiera (również ty)", + + "lifeswap": "Zamiana Żyć", + "lifeswap_desc": "Wybierasz gracza, z którym chcesz wymienić się zdrowiem", + "lifeswap_enemy_info": "Ktoś pożyczył sobie twoje zdrowie.", + "lifeswap_player_info": "Wymieniłeś się zdrowiem z graczem '{0}'.", + "lifeswap_select_info": "Wybierz gracza, z którym chcesz wymienić się zdrowiem:", + + "longknife": "Długi Nóż", + "longknife_desc": "Podstawowy atak nożem zadaje obrażenia niezależnie od odległości", + + "longzeus": "Długi Zeus", + "longzeus_desc": "Zeus zadaje obrażenia niezależnie od odległości", + + "medic": "Medyk", + "medic_desc": "Kliknij [css_useSkill], aby użyć ładunku leczniczego, który przywraca 50 punktów zdrowia", + + "moneyswap": "Skarbówka", + "moneyswap_desc": "Wybierasz gracza, z którym chcesz zamienić się pieniędzmi", + "moneyswap_enemy_info": "Urząd skarbowy cię dopadł.", + "moneyswap_player_info": "Wymieniłeś swoje pieniądze z graczem '{0}'.", + "moneyswap_select_info": "Wybierz gracza, z którym chcesz zamienić się pieniędzmi:", + + "muhammed": "Muhammed", + "muhammed_desc": "Po śmierci eksplodujesz i zabijasz graczy znajdujących się w zasięgu", + + "ninja": "Ninja", + "ninja_desc": "Stojąc nieruchomo zwiększasz swoją niewidzialność o 33%, kucając o 33%, a trzymając nóż o 33%", + + "nonades": "Pancernik", + "nonades_desc": "Granaty nie zadają Ci obrażeń", + + "norecoil": "Skupienie", + "norecoil_desc": "Brak odrzutu podczas strzelania", + + "noclip": "NoClip", + "noclip_desc": "Kliknij [css_useSkill], aby włączyć noclip na krótki czas", + + "oneshot": "Jednostrzałowiec", + "oneshot_desc": "Po trafieniu natychmiast zabijasz przeciwnika", + + "onlyhead": "Tylko Głowa", + "onlyhead_desc": "Otrzymujesz obrażenia tylko w głowę", + + "paweljumper": "Pawel Jumper", "paweljumper_desc": "Otrzymujesz dodatkowy skok", + + "phoenix": "Feniks", "phoenix_desc": "Masz losową szans na odrodzenie się po śmierci", "phoenix_desc2": "Twoje szanse na odrodzenie się po śmierci: {0}%", "phoenix_respawn": "Zostałeś odrodzony z popiołów dzięki mocy: CHATCOLORS.REDPhoenix", + + "psychicdefusing": "Zdalne Rozbrajanie", + "psychicdefusing_desc": "Kiedy jesteś blisko bomby, zaczynasz ją rozbrajać", + "psychicdefusing_hud_info": "Pozostało {0} sekund do rozbrojenia", + + "pilot": "Pilot", "pilot_desc": "Latanie przez określony czas. Przytrzymaj [USE - E], aby latać", "pilot_hud_info": "W trakcie odnawiania", - "radarhack_desc": "Widzisz wrogów na radarze", - "rambo_desc": "Otrzymujesz losową ilość zdrowia na start rundy", - "enemyspawn_desc": "Teleportacja na spawn wroga. Kliknij [css_useSkill], cooldown 15s", - "disarmament_desc": "Masz losową szanse na wyrzucenie broni wroga po trafieniu", - "disarmament_desc2": "Twoje szanse na wyrzucenie broni wroga to: {0}%", - "planter_desc": "Możesz podłożyć bombę w dowolnym miejscu, czas detonacji bomby trwa 60s", - "saper_desc": "Możesz szybciej podłożyć bombę oraz ją zdefować", - "timemanipulator_desc": "Spowolnienie czasu dla wszystkich na 6 sekundy. Kliknij [css_useSkill], cooldown 30s", - "quickshot_desc": "Brak cooldown przy strzelaniu", - "teleporter_desc": "Zamieniasz się miejscami z trafionym wrogiem", - "wallhack_desc": "Widzisz wrogów przez ściany", - "killerflash_desc": "Każdy całkowicie oślepiony twoim granatem umiera (również ty)", - "weaponsswap_desc": "Zamieniasz się bronią z losowym wrogiem. Kliknij [css_useSkill], cooldown 30s", - "weaponsswap_hud_info2": "Nie posiadasz broni na zamiane", - "hud_info_no_enemy": "Nie znaleziono przeciwnika", - "zeus_desc": "Zeus x27 natychmiastowo się odnawia", - "frozendecoy_desc": "Twój decoy zamraża wszystkich pobliskich graczy", - "antyhead_desc": "Nie otrzymujesz obrażeń w głowę", + + "planter": "Samowolka", + "planter_desc": "Bombę można podłożyć w dowolnym miejscu, a czas detonacji wynosi 60 sekund.", + + "poison": "Trutka", + "poison_desc": "Wybierasz gracza, który co kilka sekund będzie otrzymywał obrażenia", + "poison_enemy_info": "Zostałeś otruty.", + "poison_player_info": "Gracz '{0}' został otruty.", + "poison_select_info": "Wybierz gracza, który co kilka sekund będzie otrzymywał obrażenia:", + + "primaryban": "Brak Karabinów", + "primaryban_desc": "Wybierasz gracza, który nie może używać karabinów", + "primaryban_enemy_info": "Nie możesz już używać karabinów.", + "primaryban_player_info": "Gracz '{0}' nie może już używać karabinów.", + "primaryban_select_info": "Wybierz gracza, któremu chcesz zabronić używania karabinów:", + + "prosthesis": "Proteza", + "prosthesis_desc": "Ramiona i nogi są kuloodporne", + + "push": "Odpychacz", + "push_desc": "Masz losową szansę na odepchnięcie wroga po trafieniu go", + "push_desc2": "Twoje szanse na odepchnięcie wroga to: {0}%", + + "pyro": "Pyro", + "pyro_desc": "Molotow przywraca zdrowie", + + "quickshot": "Szybkostrzelność", + "quickshot_desc": "Wszystkie pociski są wystrzeliwane bardzo szybko", + + "radarhack": "Radarowiec", + "radarhack_desc": "Na radarze widać wrogów", + + "rambo": "Rambo", + "rambo_desc": "Na początku rundy otrzymujesz losową ilość zdrowia", + + "randomweapon": "Losowa Broń", + "randomweapon_desc": "Kliknij [css_useSkill], aby otrzymać losową broń", + + "rezombie": "Re-Zombie", + "rezombie_desc": "Po śmierci odradzasz się jako zombie z większym zdrowiem i bez broni", + + "reactivearmor": "Pancerz Reaktywny", + "reactivearmor_desc": "Pancerz pochłania pierwsze otrzymane obrażenia", + + "regeneration": "Regeneracja", + "regeneration_desc": "Co kilka sekund odnawiasz zdrowie", + + "replicator": "Replikator", + "replicator_desc": "Kliknij [css_useSkill], aby stworzyć swoją replikę, która zadaje obrażenia po trafieniu", + + "retreat": "Odwrót", + "retreat_desc": "Kliknij [css_useSkill], aby powrócić na resp", + + "returntosender": "Zwrot do Nadawcy", + "returntosender_desc": "Pierwsze trafienie wroga powoduje, że wraca on na swój resp", + + "richboy": "Bogacz", + "richboy_desc": "Na początku rundy otrzymujesz losową kwotę gotówki", + + "robinhood": "Robin Hood", + "robinhood_desc": "Zadanie obrażeń przeciwnikowi powoduje kradzież jego pieniędzy", + + "rubber": "Gumowe Kule", + "rubber_desc": "Twoje pociski znacznie spowalniają graczy", + + "saper": "Saper", + "saper_desc": "Możesz szybciej podłożyć bombę i ją rozbroić", + + "secondlife": "Druga Szansa", + "secondlife_desc": "Po śmierci odradzasz się z taką samą ilością zdrowia", + + "shade": "Cień", + "shade_desc": "Teleportujesz się za plecy trafionego wroga", + "shade_nospace": "Brak miejsca", + + "shortbomb": "Krótka Bomba", + "shortbomb_desc": "Bomba wybucha znacznie szybciej", + + "silent": "Cichociemny", + "silent_desc": "Twoje kroki i skoki są niesłyszalne dla INNYCH graczy", + + "sniperelite": "SzeliS", + "sniperelite_desc": "Kliknij [css_useSkill], aby zamienić aktualną broń na AWP", + + "soldier": "Żołnierz", "soldier_desc": "Masz losowy mnożnik obrażeń", "soldier_desc2": "Twój mnożnik obrażeń wynosi: {0}x", - "swapposition_desc": "Zamiana miejscami z losowym wrogiem. Kliknij [css_useSkill], cooldown 30s", - "welcome_message": "Witaj {PLAYER} na serwerze {SERVER_NAME}!\nAktualna wersja jRandomSkills: {VERSION} ({SKILLS_COUNT} supermocy).\n\nPierwotnie plugin stworzona przez:\n{AUTHOR1}\nZmodyfikowany i ulepszony przez:\n{AUTHOR2}", + "soundmaker": "Dźwiękowiec", + "soundmaker_desc": "Kliknij [css_useSkill], aby wywołać dzwięk u każdego przeciwnika", + + "spectator": "Obserwator", + "spectator_desc": "Kliknij [css_useSkill], aby obserwować losowego przeciwnika", + + "swapposition": "Zamiana Miejsc", + "swapposition_desc": "Kliknij [css_useSkill], aby zamienić się miejscami z losowym przeciwnikiem", + + "teleporter": "Teleporter", + "teleporter_desc": "Zamieniasz się miejscami z trafionym przeciwnikiem", + + "thief": "Złodziej", + "thief_desc": "Możesz ukraść supermoc wybranemu graczowi", + "thief_enemy_info": "Twoja supermoc została skradziona.", + "thief_player_info": "Moc gracza '{0}' została skradziona.", + "thief_select_info": "Wybierz gracza, którego supermoc chcesz ukraść:", + + "thirdeye": "Trzecie Oko", + "thirdeye_desc": "Kliknij [css_useSkill], aby aktywować trzecią osobę", + + "toxicsmoke": "Toksyczny Dym", + "toxicsmoke_desc": "Twoje granaty dymny zadają obrażenia", + + "wallhack": "Wallhack", + "wallhack_desc": "Widzisz wrogów przez ściany", + + "watchmaker": "Zegarmistrz", + "watchmaker_desc": "Każdy rzut granatem zmienia czas rundy", + "watchmaker_ct": "Czas rundy został skrócony o {0} sekund.", + "watchmaker_tt": "Czas rundy został wydłużony o {0} sekund", + + "weaponsswap": "Zamiana Broni", + "weaponsswap_desc": "Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem", + "weaponsswap_hud_info2": "Nie posiadasz broni na zamiane", + + "zeus": "Zeus", + "zeus_desc": "Zeus x27 natychmiastowo się odnawia", + + "your_skill": "Twoja aktualna moc", + "enemy_skill": "Supermoc przeciwnika", + "observer_skill": "Moc gracza", + "welcome_message": "Witaj {PLAYER} na serwerze {SERVER_NAME}!\nAktualna wersja jRandomSkills: {VERSION} ({SKILLS_COUNT} supermocy).\n\nPierwotnie plugin stworzona przez:\n{AUTHOR1}\nZmodyfikowany i ulepszony przez:\n{AUTHOR2}\nOficjalny discord: https://discord.gg/72nzFguNtd", + "drawing_skill": "Losowanie mocy", + "disabled_weapon": "Nie możesz używać tej broni", + "hud_info": "Poczekaj jeszcze {0} sekund", + "hud_info_no_enemy": "Nie znaleziono przeciwnika", + "active_hud_info": "Działa jeszcze przez {0} milisekund", + + "skills_menu": "Lista Super Mocy", "no_player": "Nie znaleziono pasującego gracza.", "duplicate_player": "Znaleziono więcej niż jednego gracza o tej samej nazwie.", - "drawing_skill": "Losowanie mocy", - "your_skill": "Twoja aktualna moc", - "summary_start": "======PODSUMOWANIE=Z=OSTATNIEJ=RUNDY======", - "summary_end": "============================================", - "enemy_skill": "Supermoc przeciwnika", - "teammate_skills": "Supermoce twoich sojuszników", - "observer_skill": "Moc gracza", - "game_start": "Gra rozpoczęta!", - "invalid_map": "Niepoprawnie podano nazwę mapy!", - "loading_map": "Ładowanie nowej mapy", - "skills_menu": "Lista Super Mocy", - "correct_form_setskill": "Poprawne użycie: CHATCOLORS.RED!setskill ", + "selectplayerskill_command": "Wpisz /t", + "selectplayerskill_incorrect_enemy_index": "Nie znaleziono gracza o takim index'ie.", + "skill_not_found_setskill": "Nie znaleziono takiej CHATCOLORS.REDsupermocy", - "error_setskill": "Nie udało się ustawić CHATCOLORS.REDsupermocy", + "player_not_found_setskill": "Nie znaleziono takiego CHATCOLORS.REDgracza", + "correct_form_setskill": "Poprawne użycie: CHATCOLORS.RED!setskill ", + "correct_form_setscore": "Poprawne użycie: CHATCOLORS.RED!setscore ", "done_setskill": "Ustawiono Supermoc", + "error_setskill": "Nie udało się ustawić CHATCOLORS.REDsupermocy", "for_setskill": "dla", - "none": "Brak", - "dwarf": "MiniMajk", - "swapoosition": "Zamiana Miejsc", - "killerflash": "Zabójczy Flash", - "soldier": "Żołnierz", - "armored": "Gruby", - "aimbot": "Aimbot", - "retreat": "Odwrót", - "enemyspawn": "Resp Wroga", - "zeus": "Zeus", - "radarhack": "Radarowiec", - "quickshot": "Szybkostrzelność", - "planter": "Samowolka", - "silent": "Cichociemny", - "frozendecoy": "Zamrażający Decoy", - "timemanipulator": "Spowlnienie Czasu", - "godmode": "Nieśmiertelność", - "randomweapon": "Losowa Broń", - "weaponsswap": "Zamiana Broni", - "wallhack": "Wallhack", - "flash": "Flash", - "paweljumper": "Pawel Jumper", - "bunnyhop": "Królik", - "impostor": "Szpieg", - "oneshot": "Jednostrzałowiec", - "muhammed": "Muhammed", - "richboy": "Bogacz", - "rambo": "Rambo", - "medic": "Medyk", - "ghost": "Duszek", - "chicken": "Kurczak", - "astronaut": "Astronauta", - "disarmament": "Rozbrojenie", - "antyflash": "Anty Flash", - "behind": "Obrót Wroga", - "infiniteammo": "Nieskończone Ammo", - "catapult": "Katapulta", - "dracula": "Drakula", - "teleporter": "Teleporter", - "saper": "Saper", - "phoenix": "Phoenix", - "pilot": "Pilot", - "shade": "Cień", - "antyhead": "Żelazna Głowa" + "invalid_map": "Nazwa mapy została wprowadzona nieprawidłowo!", + "loading_map": "Ładowanie nowej mapy", + + "pause": "Mecz został wstrzymany.", + "unpause": "Mecz został wznowiony.", + "healed": "Zostałeś uleczony.", + "game_start": "Gra rozpoczęta!", + + "teammate_skills": "Supermoce twoich sojuszników", + "summary_start": "======PODSUMOWANIE=Z=OSTATNIEJ=RUNDY======", + "summary_end": "============================================" } \ No newline at end of file diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/lang/pt-br.json b/jRandomSkills - Server Files/plugins/jRandomSkills/lang/pt-br.json new file mode 100644 index 0000000..9993d21 --- /dev/null +++ b/jRandomSkills - Server Files/plugins/jRandomSkills/lang/pt-br.json @@ -0,0 +1,410 @@ +{ + "none": "Nenhum", + "none_desc": "Você não tem nenhuma habilidade", + + "aimbot": "Aimbot", + "aimbot_desc": "Cada bala que você acertar conta como um tiro na cabeça", + + "anomaly": "Anomalia", + "anomaly_desc": "Você retrocede alguns segundos no tempo", + + "antyflash": "Anti-Flash", + "antyflash_desc": "Você é imune a granadas de flash, e suas granadas de flash duram 7 segundos", + + "antyhead": "Cabeça de Ferro", + "antyhead_desc": "Você não recebe dano de tiros na cabeça", + + "areareaper": "Ceifador de Zonas", + "areareaper_desc": "Você pode escolher um local de bomba para desativar", + "areareaper_incorrect_site": "Nenhum local de bomba encontrado.", + "areareaper_no_site": "Nenhum local de bomba encontrado.", + "areareaper_select_info": "Escolha o local de bomba que deseja desativar:", + "areareaper_site_disabled": "Local de bomba {0} foi desativado - nenhuma bomba pode ser plantada lá!", + "areareaper_used_info": "Seu poder já foi usado.", + + "armored": "Blindado", + "armored_desc": "Você tem um multiplicador de dano recebido aleatório", + "armored_desc2": "Seu multiplicador de dano recebido é: {0}x", + + "assassin": "Assassino", + "assassin_desc": "Você causa mais dano aos inimigos por trás", + + "astronaut": "Astronauta", + "astronaut_desc": "Você recebe um valor de gravidade aleatório no início da rodada", + "astronaut_desc2": "Sua gravidade aleatória é: {0}x", + + "baseball": "Jogador de Beisebol", + "baseball_desc": "Seu chamariz ricocheteia nas paredes e mata instantaneamente um inimigo ao acertar", + + "behind": "Giro do Inimigo", + "behind_desc": "Você tem uma chance aleatória de girar um inimigo 180 graus ao acertá-lo", + "behind_desc2": "Sua chance de girar um inimigo ao acertar é: {0}%", + + "blademaster": "Mestre das Lâminas", + "blademaster_desc": "Enquanto segura uma faca, você tem uma alta chance de desviar de um tiro", + + "bunnyhop": "Coelho", + "bunnyhop_desc": "Você ganha \"BunnyHop\" automático", + + "c4camouflage": "Camuflagem C4", + "c4camouflage_desc": "Você fica invisível enquanto segura a bomba", + + "catapult": "Catapulta", + "catapult_desc": "Você tem uma chance aleatória de lançar um inimigo para cima", + "catapult_desc2": "Sua chance de lançar um inimigo ao acertar é: {0}%", + + "chicken": "Galinha", + "chicken_desc": "Você ganha um modelo de galinha + 10% de movimento mais rápido - 50 HP", + + "chillout": "Descontraído", + "chillout_desc": "Plantar a bomba leva significativamente mais tempo", + + "cutter": "Cortador", + "cutter_desc": "Mata instantaneamente com uma faca", + + "darkness": "Escuridão", + "darkness_desc": "Aplica um efeito de escuridão a um inimigo escolhido", + "darkness_enemy_info": "Que as luzes se apaguem.", + "darkness_player_info": "A escuridão tomou conta do jogador '{0}'.", + "darkness_select_info": "Escolha o jogador ao qual deseja aplicar o efeito de escuridão:", + + "deactivator": "Desativador", + "deactivator_desc": "Escolha um jogador cuja habilidade você deseja desativar", + "deactivator_enemy_info": "Sua habilidade foi desativada.", + "deactivator_player_info": "A habilidade do jogador '{0}' foi desativada.", + "deactivator_select_info": "Escolha o jogador cuja habilidade você deseja desativar:", + + "deaf": "Surdo", + "deaf_desc": "Escolha um jogador para silenciar todos os sons", + "deaf_enemy_info": "Seus fones de ouvido saíram do jogo.", + "deaf_player_info": "O som foi desativado para o jogador '{0}'.", + "deaf_select_info": "Escolha o jogador para quem deseja silenciar todos os sons:", + + "disarmament": "Desarmamento", + "disarmament_desc": "Você tem uma chance aleatória de fazer um inimigo largar sua arma ao acertá-lo", + "disarmament_desc2": "Sua chance de desarmar um inimigo é: {0}%", + + "distancer": "Medidor de Distância", + "distancer_desc": "Você pode ver a distância até o inimigo mais próximo", + + "dracula": "Drácula", + "dracula_desc": "Acertar um inimigo restaura saúde igual a uma porcentagem do dano causado", + + "duplicator": "Duplicador", + "duplicator_desc": "Escolha um jogador para copiar sua habilidade", + "duplicator_player_info": "A habilidade do jogador '{0}' foi copiada.", + "duplicator_select_info": "Escolha o jogador cuja habilidade você deseja copiar:", + + "dwarf": "Anão", + "dwarf_desc": "Tamanho de personagem aleatório no início da rodada", + "dwarf_desc2": "Seu multiplicador de tamanho é: {0}x", + + "enemyspawn": "Spawn Inimigo", + "enemyspawn_desc": "Clique em [css_useSkill] para se teletransportar para o spawn inimigo", + + "explosiveshot": "Tiro Explosivo", + "explosiveshot_desc": "Chance aleatória de disparar uma bala explosiva enquanto atira", + "explosiveshot_desc2": "Sua chance de disparar uma bala explosiva: {0}%", + + "falconeye": "Olho de Falcão", + "falconeye_desc": "Clique em [css_useSkill] para ativar uma câmera com visão aérea", + + "fastreload": "Recarga Rápida", + "fastreload_desc": "Clique em [css_useSkill] para recarregar a arma que você está segurando", + + "flash": "Flash", + "flash_desc": "Velocidade de jogador aleatória no início da rodada", + "flash_desc2": "Seu multiplicador de velocidade é: {0}x", + + "fortnite": "Fortnite", + "fortnite_desc": "Clique em [css_useSkill] para criar uma barricada destrutível", + + "fragilebomb": "Bomba Frágil", + "fragilebomb_desc": "Atirar na bomba a danifica", + "fragilebomb_bomb_health": "Vida da bomba", + + "friendlyfire": "Fogo Amigo", + "friendlyfire_desc": "Atirar em companheiros de equipe os cura", + + "frozendecoy": "Chamariz Congelante", + "frozendecoy_desc": "Seu chamariz congela todos os jogadores próximos", + + "ghost": "Fantasma", + "ghost_desc": "Você é completamente invisível", + + "glaz": "Glaz", + "glaz_desc": "Você não pode ver granadas de fumaça", + + "glitch": "Glitch", + "glitch_desc": "Desativa o radar de um inimigo escolhido", + "glitch_enemy_info": "Seu radar foi desativado.", + "glitch_player_info": "O radar do jogador '{0}' foi desativado.", + "glitch_select_info": "Escolha o jogador cujo radar você deseja desativar:", + + "glue": "Cola", + "glue_desc": "Suas granadas grudam nas paredes", + + "godmode": "Modo Deus", + "godmode_desc": "Clique em [css_useSkill] para se tornar imortal por um curto período", + "godmode_off": "Imortalidade desativada", + "godmode_on": "Imortalidade ativada", + + "healingsmoke": "Fumaça Curativa", + "healingsmoke_desc": "Suas granadas de fumaça curam", + + "hermit": "Eremita", + "hermit_desc": "Matar restaura munição e uma porção de saúde", + + "holyhandgrenade": "Granada Sagrada", + "holyhandgrenade_desc": "Suas granadas explosivas causam dano dobrado e têm alcance dobrado", + + "impostor": "Impostor", + "impostor_desc": "Você começa a rodada com um modelo de jogador inimigo", + + "infiniteammo": "Munição Infinita", + "infiniteammo_desc": "Você recebe munição infinita para todas as suas armas", + + "jackal": "Rastreador", + "jackal_desc": "Escolha um jogador que deixará um rastro atrás dele", + "jackal_player_info": "O jogador '{0}' começará a deixar um rastro.", + "jackal_select_info": "Escolha o jogador que deixará um rastro:", + + "jammer": "Jammer", + "jammer_desc": "Escolha um jogador para desativar sua mira", + "jammer_enemy_info": "Sua mira foi desativada.", + "jammer_player_info": "A mira do jogador '{0}' foi desativada.", + "jammer_select_info": "Escolha o jogador cuja mira você deseja desativar:", + + "jumpban": "Sem Pernas", + "jumpban_desc": "Escolha um jogador que não poderá pular", + "jumpban_enemy_info": "Alguém cortou suas pernas.", + "jumpban_player_info": "O jogador '{0}' não pode mais pular.", + "jumpban_select_info": "Escolha o jogador que não poderá pular:", + + "jumpingjack": "Pula-Pula", + "jumpingjack_desc": "Pular restaura saúde", + + "killerflash": "Flash Mortal", + "killerflash_desc": "Qualquer um completamente cego pela sua granada de flash morre (incluindo você)", + + "lifeswap": "Troca de Vida", + "lifeswap_desc": "Escolha um jogador para trocar saúde com ele", + "lifeswap_enemy_info": "Alguém pegou sua saúde emprestada.", + "lifeswap_player_info": "Você trocou saúde com o jogador '{0}'.", + "lifeswap_select_info": "Escolha o jogador com quem deseja trocar saúde:", + + "longknife": "Faca Longa", + "longknife_desc": "Um ataque com faca primária causa dano independentemente da distância", + + "longzeus": "Zeus Longo", + "longzeus_desc": "Zeus causa dano independentemente da distância", + + "medic": "Médico", + "medic_desc": "Clique em [css_useSkill] para usar uma carga de cura que restaura 50 de saúde", + + "moneyswap": "Cobrador de Impostos", + "moneyswap_desc": "Escolha um jogador para trocar dinheiro com ele", + "moneyswap_enemy_info": "A receita federal te pegou.", + "moneyswap_player_info": "Você trocou dinheiro com o jogador '{0}'.", + "moneyswap_select_info": "Escolha o jogador com quem deseja trocar dinheiro:", + + "muhammed": "Muhammed", + "muhammed_desc": "Você explode ao morrer, matando jogadores próximos", + + "ninja": "Ninja", + "ninja_desc": "Ficar parado aumenta sua invisibilidade em 33%, agachar em 33%, e segurar uma faca em 33%", + + "nonades": "Sem Granadas", + "nonades_desc": "Granadas não causam dano a você", + + "norecoil": "Foco", + "norecoil_desc": "Sem recuo ao atirar", + + "noclip": "NoClip", + "noclip_desc": "Clique em [css_useSkill] para ativar noclip por um curto período", + + "oneshot": "Tiro Único", + "oneshot_desc": "Acertar um inimigo o mata instantaneamente", + + "onlyhead": "Apenas Cabeça", + "onlyhead_desc": "Você só recebe dano na cabeça", + + "paweljumper": "Pawel Jumper", + "paweljumper_desc": "Você ganha um pulo extra", + + "phoenix": "Fênix", + "phoenix_desc": "Você tem uma chance aleatória de renascer após a morte", + "phoenix_desc2": "Sua chance de renascer após a morte: {0}%", + "phoenix_respawn": "Você foi ressuscitado das cinzas graças ao poder de: CHATCOLORS.REDPhoenix", + + "psychicdefusing": "Desarme Psíquico", + "psychicdefusing_desc": "Quando você está perto da bomba, começa a desarmá-la", + "psychicdefusing_hud_info": "{0} segundos restantes para desarmar", + + "pilot": "Piloto", + "pilot_desc": "Voe por um tempo limitado. Segure [USE - E] para voar", + "pilot_hud_info": "Recarregando", + + "planter": "Plantador Livre", + "planter_desc": "Você pode plantar a bomba em qualquer lugar, com um tempo de detonação de 60 segundos.", + + "poison": "Veneno", + "poison_desc": "Escolha um jogador que receberá dano a cada poucos segundos", + "poison_enemy_info": "Você foi envenenado.", + "poison_player_info": "O jogador '{0}' foi envenenado.", + "poison_select_info": "Escolha o jogador que receberá dano a cada poucos segundos:", + + "primaryban": "Sem Rifles", + "primaryban_desc": "Escolha um jogador que não poderá usar rifles", + "primaryban_enemy_info": "Você não pode mais usar rifles.", + "primaryban_player_info": "O jogador '{0}' não pode mais usar rifles.", + "primaryban_select_info": "Escolha o jogador para proibir de usar rifles:", + + "prosthesis": "Prótese", + "prosthesis_desc": "Braços e pernas são à prova de balas", + + "push": "Empurrador", + "push_desc": "Você tem uma chance aleatória de empurrar um inimigo para trás ao acertá-lo", + "push_desc2": "Suas chances de repelir o inimigo são: {0}%", + + "pyro": "Piro", + "pyro_desc": "Molotov restaura saúde", + + "quickshot": "Tiro Rápido", + "quickshot_desc": "Todas as balas são disparadas muito rapidamente", + + "radarhack": "Hack de Radar", + "radarhack_desc": "Inimigos são visíveis no radar", + + "rambo": "Rambo", + "rambo_desc": "Você recebe uma quantidade aleatória de saúde no início da rodada", + + "randomweapon": "Arma Aleatória", + "randomweapon_desc": "Clique em [css_useSkill] para receber uma arma aleatória", + + "rezombie": "Re-Zumbi", + "rezombie_desc": "Após a morte, você renasce como um zumbi com mais saúde e sem armas", + + "reactivearmor": "Armadura Reativa", + "reactivearmor_desc": "A armadura absorve o primeiro dano recebido", + + "regeneration": "Regeneração", + "regeneration_desc": "Você restaura saúde a cada poucos segundos", + + "replicator": "Replicador", + "replicator_desc": "Clique em [css_useSkill] para criar uma réplica que causa dano ao acertar", + + "retreat": "Recuo", + "retreat_desc": "Clique em [css_useSkill] para retornar ao spawn", + + "returntosender": "Devolução ao Remetente", + "returntosender_desc": "O primeiro acerto em um inimigo o envia de volta ao seu spawn", + + "richboy": "Garoto Rico", + "richboy_desc": "Você recebe uma quantidade aleatória de dinheiro no início da rodada", + + "robinhood": "Robin Hood", + "robinhood_desc": "Causar dano a um inimigo rouba seu dinheiro", + + "rubber": "Balas de Borracha", + "rubber_desc": "Suas balas retardam significativamente os jogadores", + + "saper": "Sapeador", + "saper_desc": "Você pode plantar e desarmar bombas mais rápido", + + "secondlife": "Segunda Chance", + "secondlife_desc": "Após a morte, você renasce com a mesma quantidade de saúde", + + "shade": "Sombra", + "shade_desc": "Você se teletransporta para trás de um inimigo acertado", + "shade_nospace": "Sem espaço disponível", + + "shortbomb": "Fusível Curto", + "shortbomb_desc": "A bomba explode muito mais rápido", + + "silent": "Silencioso", + "silent_desc": "Seus passos e pulos são silenciosos para OUTROS jogadores", + + "sniperelite": "Atirador de Elite", + "sniperelite_desc": "Clique em [css_useSkill] para trocar sua arma atual por uma AWP", + + "soldier": "Soldado", + "soldier_desc": "Você tem um multiplicador de dano aleatório", + "soldier_desc2": "Seu multiplicador de dano é: {0}x", + + "soundmaker": "Criador de Som", + "soundmaker_desc": "Clique em [css_useSkill] para acionar um som para cada inimigo", + + "spectator": "Espectador", + "spectator_desc": "Clique em [css_useSkill] para observar um inimigo aleatório", + + "swapposition": "Troca de Posição", + "swapposition_desc": "Clique em [css_useSkill] para trocar de lugar com um inimigo aleatório", + + "teleporter": "Teletransportador", + "teleporter_desc": "Você troca de lugar com o inimigo acertado", + + "thief": "Ladrão", + "thief_desc": "Você pode roubar uma habilidade de um jogador escolhido", + "thief_enemy_info": "Sua habilidade foi roubada.", + "thief_player_info": "A habilidade do jogador '{0}' foi roubada.", + "thief_select_info": "Escolha o jogador cuja habilidade você deseja roubar:", + + "thirdeye": "Terceiro Olho", + "thirdeye_desc": "Clique em [css_useSkill] para ativar a visão em terceira pessoa", + + "toxicsmoke": "Fumaça Tóxica", + "toxicsmoke_desc": "Suas granadas de fumaça causam dano", + + "wallhack": "Wallhack", + "wallhack_desc": "Você pode ver inimigos através das paredes", + + "watchmaker": "Relojoeiro", + "watchmaker_desc": "Cada arremesso de granada altera o tempo da rodada", + "watchmaker_ct": "Tempo da rodada reduzido em {0} segundos.", + "watchmaker_tt": "Tempo da rodada estendido em {0} segundos.", + + "weaponsswap": "Troca de Armas", + "weaponsswap_desc": "Clique em [css_useSkill] para trocar armas com um inimigo aleatório", + "weaponsswap_hud_info2": "Você não tem arma para trocar", + + "zeus": "Zeus", + "zeus_desc": "Zeus x27 recarrega instantaneamente", + + "your_skill": "Seu poder atual", + "enemy_skill": "Habilidade do inimigo", + "observer_skill": "Poder do jogador", + "welcome_message": "Bem-vindo {PLAYER} ao {SERVER_NAME}!\nVersão atual do jRandomSkills: {VERSION} ({SKILLS_COUNT} habilidades).\n\nCriado originalmente por:\n{AUTHOR1}\nModificado e aprimorado por:\n{AUTHOR2}", + "drawing_skill": "Sorteando uma habilidade", + "disabled_weapon": "Você não pode usar esta arma", + + "hud_info": "Espere mais {0} segundos", + "hud_info_no_enemy": "Nenhum inimigo encontrado", + "active_hud_info": "Ativo por mais {0} milissegundos", + + "skills_menu": "Lista de Habilidades", + "no_player": "Nenhum jogador correspondente encontrado.", + "duplicate_player": "Mais de um jogador encontrado com o mesmo nome.", + "selectplayerskill_command": "Digite /t", + "selectplayerskill_incorrect_enemy_index": "Nenhum jogador encontrado com esse índice.", + + "skill_not_found_setskill": "Nenhuma habilidade CHATCOLORS.RED encontrada", + "player_not_found_setskill": "Nenhum jogador CHATCOLORS.RED encontrado", + "correct_form_setskill": "Uso correto: CHATCOLORS.RED!setskill ", + "correct_form_setscore": "Uso correto: CHATCOLORS.RED!setscore ", + "done_setskill": "Habilidade definida", + "error_setskill": "Falha ao definir a habilidade CHATCOLORS.RED", + "for_setskill": "para", + + "invalid_map": "Nome do mapa inserido incorretamente!", + "loading_map": "Carregando um novo mapa", + + "pause": "Partida pausada.", + "unpause": "Partida retomada.", + "healed": "Você foi curado.", + "game_start": "Jogo iniciado!", + + "teammate_skills": "Habilidades dos seus companheiros de equipe", + "summary_start": "=======RESUMO=DA=ÚLTIMA=RODADA=======", + "summary_end": "=======================================" +} \ No newline at end of file diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/lang/zh.json b/jRandomSkills - Server Files/plugins/jRandomSkills/lang/zh.json new file mode 100644 index 0000000..1882963 --- /dev/null +++ b/jRandomSkills - Server Files/plugins/jRandomSkills/lang/zh.json @@ -0,0 +1,410 @@ +{ + "none": "无", + "none_desc": "你没有任何技能", + + "aimbot": "自动瞄准", + "aimbot_desc": "你击中的每颗子弹都算作爆头", + + "anomaly": "异常", + "anomaly_desc": "你会倒退几秒钟的时间", + + "antyflash": "防闪", + "antyflash_desc": "你对闪光弹免疫,你的闪光弹持续7秒", + + "antyhead": "铁头", + "antyhead_desc": "你不会受到爆头伤害", + + "areareaper": "区域收割者", + "areareaper_desc": "你可以选择一个炸弹点进行禁用", + "areareaper_incorrect_site": "未找到此炸弹点。", + "areareaper_no_site": "未找到任何炸弹点。", + "areareaper_select_info": "选择你想禁用的炸弹点:", + "areareaper_site_disabled": "炸弹点 {0} 已被禁用 - 无法在此放置炸弹!", + "areareaper_used_info": "你的能力已被使用。", + + "armored": "装甲", + "armored_desc": "你有随机受到伤害的倍率", + "armored_desc2": "你的受到伤害倍率是:{0}x", + + "assassin": "刺客", + "assassin_desc": "从背后攻击敌人时造成更高的伤害", + + "astronaut": "宇航员", + "astronaut_desc": "回合开始时你会获得随机重力值", + "astronaut_desc2": "你的随机重力是:{0}x", + + "baseball": "棒球手", + "baseball_desc": "你的诱饵弹会在墙壁上反弹并在击中敌人时立即杀死", + + "behind": "敌人旋转", + "behind_desc": "你有随机几率在击中敌人时使其旋转180度", + "behind_desc2": "你击中敌人使其旋转的几率是:{0}%", + + "blademaster": "刀锋大师", + "blademaster_desc": "持刀时,你有很高几率格挡子弹", + + "bunnyhop": "兔子", + "bunnyhop_desc": "你获得自动“兔子跳”", + + "c4camouflage": "C4伪装", + "c4camouflage_desc": "你持有炸弹时隐形", + + "catapult": "弹射", + "catapult_desc": "你有随机几率将敌人向上弹射", + "catapult_desc2": "你击中敌人将其弹射的几率是:{0}%", + + "chicken": "鸡", + "chicken_desc": "你获得鸡模型 + 移动速度提高10% - 50生命值", + + "chillout": "悠闲", + "chillout_desc": "放置炸弹需要显著更长的时间", + + "cutter": "切割者", + "cutter_desc": "用刀可立即杀死敌人", + + "darkness": "黑暗", + "darkness_desc": "对选定的敌人施加黑暗效果", + "darkness_enemy_info": "让灯光熄灭。", + "darkness_player_info": "黑暗笼罩了玩家 '{0}'。", + "darkness_select_info": "选择你想施加黑暗效果的玩家:", + + "deactivator": "禁用者", + "deactivator_desc": "选择一个玩家以禁用其技能", + "deactivator_enemy_info": "你的技能已被禁用。", + "deactivator_player_info": "玩家 '{0}' 的技能已被禁用。", + "deactivator_select_info": "选择你想禁用其技能的玩家:", + + "deaf": "聾病", + "deaf_desc": "选择一个玩家以静音其所有声音", + "deaf_enemy_info": "你的耳机已退出游戏。", + "deaf_player_info": "玩家 '{0}' 的声音已被禁用。", + "deaf_select_info": "选择你想静音其所有声音的玩家:", + + "disarmament": "解除武装", + "disarmament_desc": "你有随机几率在击中敌人时使其丢下武器", + "disarmament_desc2": "你使敌人解除武装的几率是:{0}%", + + "distancer": "测距仪", + "distancer_desc": "你可以看到与最近敌人的距离", + + "dracula": "德古拉", + "dracula_desc": "击中敌人会根据造成的伤害百分比恢复你的生命值", + + "duplicator": "复制者", + "duplicator_desc": "选择一个玩家以复制其技能", + "duplicator_player_info": "玩家 '{0}' 的技能已被复制。", + "duplicator_select_info": "选择你想复制其技能的玩家:", + + "dwarf": "矮人", + "dwarf_desc": "回合开始时获得随机角色大小", + "dwarf_desc2": "你的体型倍率是:{0}x", + + "enemyspawn": "敌人出生点", + "enemyspawn_desc": "点击 [css_useSkill] 传送到敌人出生点", + + "explosiveshot": "爆炸射击", + "explosiveshot_desc": "射击时有随机几率发射爆炸子弹", + "explosiveshot_desc2": "你发射爆炸子弹的几率是:{0}%", + + "falconeye": "鹰眼", + "falconeye_desc": "点击 [css_useSkill] 激活鸟瞰视角摄像头", + + "fastreload": "快速装弹", + "fastreload_desc": "点击 [css_useSkill] 重新装填你当前持有的武器", + + "flash": "闪电", + "flash_desc": "回合开始时获得随机玩家速度", + "flash_desc2": "你的速度倍率是:{0}x", + + "fortnite": "堡垒之夜", + "fortnite_desc": "点击[css_useSkill]创建可破坏路障", + + "fragilebomb": "脆弱炸弹", + "fragilebomb_desc": "射击炸弹会对其造成伤害", + "fragilebomb_bomb_health": "炸弹生命值", + + "friendlyfire": "友军火力", + "friendlyfire_desc": "射击队友会治愈他们", + + "frozendecoy": "冰冻诱饵", + "frozendecoy_desc": "你的诱饵弹会冻结附近的所有玩家", + + "ghost": "幽灵", + "ghost_desc": "你完全隐形", + + "glaz": "格拉兹", + "glaz_desc": "你无法看到烟雾弹", + + "glitch": "故障", + "glitch_desc": "禁用选定敌人的雷达", + "glitch_enemy_info": "你的雷达已被禁用。", + "glitch_player_info": "玩家 '{0}' 的雷达已被禁用。", + "glitch_select_info": "选择你想禁用其雷达的玩家:", + + "glue": "粘胶", + "glue_desc": "你的手榴弹会粘在墙上", + + "godmode": "神模式", + "godmode_desc": "点击 [css_useSkill] 在短时间内变得无敌", + "godmode_off": "无敌状态已禁用", + "godmode_on": "无敌状态已启用", + + "healingsmoke": "治疗烟雾", + "healingsmoke_desc": "你的烟雾弹会治疗", + + "hermit": "隐士", + "hermit_desc": "击杀敌人会恢复弹药和部分生命值", + + "holyhandgrenade": "神圣手榴弹", + "holyhandgrenade_desc": "你的高爆手榴弹造成双倍伤害并拥有双倍范围", + + "impostor": "冒名顶替者", + "impostor_desc": "回合开始时你获得敌方玩家模型", + + "infiniteammo": "无限弹药", + "infiniteammo_desc": "你为所有武器获得无限弹药", + + "jackal": "追踪者", + "jackal_desc": "选择一个玩家,其身后会留下痕迹", + "jackal_player_info": "玩家 '{0}' 将开始留下痕迹。", + "jackal_select_info": "选择将留下痕迹的玩家:", + + "jammer": "干扰器", + "jammer_desc": "选择一个玩家以禁用其准星", + "jammer_enemy_info": "你的准星已被禁用。", + "jammer_player_info": "玩家 '{0}' 的准星已被禁用。", + "jammer_select_info": "选择你想禁用其准星的玩家:", + + "jumpban": "无腿", + "jumpban_desc": "选择一个玩家使其无法跳跃", + "jumpban_enemy_info": "有人切断了你的腿。", + "jumpban_player_info": "玩家 '{0}' 现在无法跳跃。", + "jumpban_select_info": "选择无法跳跃的玩家:", + + "jumpingjack": "跳跃杰克", + "jumpingjack_desc": "跳跃会恢复生命值", + + "killerflash": "致命闪光", + "killerflash_desc": "任何被你的闪光弹完全致盲的人都会死亡(包括你自己)", + + "lifeswap": "生命交换", + "lifeswap_desc": "选择一个玩家以交换生命值", + "lifeswap_enemy_info": "有人借走了你的生命值。", + "lifeswap_player_info": "你与玩家 '{0}' 交换了生命值。", + "lifeswap_select_info": "选择你想与之交换生命值的玩家:", + + "longknife": "长刀", + "longknife_desc": "近战刀具攻击无论距离远近均可造成伤害", + + "longzeus": "长宙斯", + "longzeus_desc": "宙斯电击枪无论距离多远都能造成伤害", + + "medic": "医务兵", + "medic_desc": "点击 [css_useSkill] 使用治疗装置恢复50点生命值", + + "moneyswap": "税务员", + "moneyswap_desc": "选择一个玩家以交换金钱", + "moneyswap_enemy_info": "税务局找上你了。", + "moneyswap_player_info": "你与玩家 '{0}' 交换了金钱。", + "moneyswap_select_info": "选择你想与之交换金钱的玩家:", + + "muhammed": "穆罕默德", + "muhammed_desc": "你死亡时会爆炸,杀死附近的玩家", + + "ninja": "忍者", + "ninja_desc": "站立不动增加33%隐形,蹲下增加33%,持刀增加33%", + + "nonades": "无手榴弹", + "nonades_desc": "手榴弹对你不造成伤害", + + "norecoil": "专注", + "norecoil_desc": "射击时无后坐力", + + "noclip": "无碰撞", + "noclip_desc": "点击 [css_useSkill] 在短时间内启用无碰撞模式", + + "oneshot": "一击必杀", + "oneshot_desc": "击中敌人立即杀死他们", + + "onlyhead": "仅头部", + "onlyhead_desc": "你只会在头部受到伤害", + + "paweljumper": "帕维尔跳跃者", + "paweljumper_desc": "你获得额外的跳跃", + + "phoenix": "凤凰", + "phoenix_desc": "你有随机几率在死亡后复活", + "phoenix_desc2": "你死亡后复活的几率是:{0}%", + "phoenix_respawn": "你因 CHATCOLORS.RED凤凰 的力量从灰烬中重生", + + "psychicdefusing": "心灵拆弹", + "psychicdefusing_desc": "当你靠近炸弹时,你开始拆除它", + "psychicdefusing_hud_info": "拆除还剩 {0} 秒", + + "pilot": "飞行员", + "pilot_desc": "在有限时间内飞行。按住 [USE - E] 飞行", + "pilot_hud_info": "正在充能", + + "planter": "自由种植者", + "planter_desc": "你可以在任何地方放置炸弹,引爆时间为60秒。", + + "poison": "毒药", + "poison_desc": "选择一个玩家,每隔几秒受到伤害", + "poison_enemy_info": "你被毒害了。", + "poison_player_info": "玩家 '{0}' 已被毒害。", + "poison_select_info": "选择每隔几秒将受到伤害的玩家:", + + "primaryban": "无步枪", + "primaryban_desc": "选择一个玩家使其无法使用步枪", + "primaryban_enemy_info": "你无法再使用步枪。", + "primaryban_player_info": "玩家 '{0}' 无法再使用步枪。", + "primaryban_select_info": "选择禁止使用步枪的玩家:", + + "prosthesis": "假肢", + "prosthesis_desc": "手臂和腿部防弹", + + "push": "推力者", + "push_desc": "你有随机几率在击中敌人时将其推回", + "push_desc2": "你击退敌人的几率为:{0}%", + + "pyro": "火焰兵", + "pyro_desc": "燃烧瓶会恢复生命值", + + "quickshot": "快速射击", + "quickshot_desc": "所有子弹射击速度极快", + + "radarhack": "雷达外挂", + "radarhack_desc": "雷达上可以看到敌人", + + "rambo": "兰博", + "rambo_desc": "回合开始时你获得随机数量的生命值", + + "randomweapon": "随机武器", + "randomweapon_desc": "点击 [css_useSkill] 获得随机武器", + + "rezombie": "重生僵尸", + "rezombie_desc": "死亡后你将作为僵尸复活,拥有更多生命值但无武器", + + "reactivearmor": "反应装甲", + "reactivearmor_desc": "装甲吸收首次受到的伤害", + + "regeneration": "再生", + "regeneration_desc": "每隔几秒恢复生命值", + + "replicator": "复制者", + "replicator_desc": "点击 [css_useSkill] 创建一个造成伤害的复制体", + + "retreat": "撤退", + "retreat_desc": "点击 [css_useSkill] 返回出生点", + + "returntosender": "退货", + "returntosender_desc": "首次击中敌人会将其送回出生点", + + "richboy": "富少", + "richboy_desc": "回合开始时你获得随机数量的钱", + + "robinhood": "罗宾汉", + "robinhood_desc": "对敌人造成伤害会偷取他们的钱", + + "rubber": "橡胶子弹", + "rubber_desc": "你的子弹会显著减慢玩家速度", + + "saper": "工兵", + "saper_desc": "你可以更快地放置和拆除炸弹", + + "secondlife": "第二次机会", + "secondlife_desc": "死亡后你会以相同生命值复活", + + "shade": "阴影", + "shade_desc": "你会传送到被击中敌人的背后", + "shade_nospace": "无可用空间", + + "shortbomb": "短引信", + "shortbomb_desc": "炸弹爆炸速度快得多", + + "silent": "无声", + "silent_desc": "你的脚步和跳跃对其他玩家无声", + + "sniperelite": "狙击精英", + "sniperelite_desc": "点击 [css_useSkill] 将当前武器替换为AWP", + + "soldier": "士兵", + "soldier_desc": "你有随机伤害倍率", + "soldier_desc2": "你的伤害倍率是:{0}x", + + "soundmaker": "声音制造者", + "soundmaker_desc": "点击 [css_useSkill] 为每个敌人触发一个声音", + + "spectator": "观察者", + "spectator_desc": "点击 [css_useSkill] 观察一个随机敌人", + + "swapposition": "位置交换", + "swapposition_desc": "点击 [css_useSkill] 与随机敌人交换位置", + + "teleporter": "传送者", + "teleporter_desc": "你与被击中的敌人交换位置", + + "thief": "小偷", + "thief_desc": "你可以从选定玩家那里偷取技能", + "thief_enemy_info": "你的技能被偷走了。", + "thief_player_info": "玩家 '{0}' 的技能被偷走了。", + "thief_select_info": "选择你想偷取其技能的玩家:", + + "thirdeye": "第三只眼", + "thirdeye_desc": "点击 [css_useSkill] 激活第三人称视角", + + "toxicsmoke": "毒烟", + "toxicsmoke_desc": "你的烟雾弹会造成伤害", + + "wallhack": "透视", + "wallhack_desc": "你可以通过墙壁看到敌人", + + "watchmaker": "钟表匠", + "watchmaker_desc": "每次投掷手榴弹都会改变回合时间", + "watchmaker_ct": "回合时间缩短了 {0} 秒。", + "watchmaker_tt": "回合时间延长了 {0} 秒。", + + "weaponsswap": "武器交换", + "weaponsswap_desc": "点击 [css_useSkill] 与随机敌人交换武器", + "weaponsswap_hud_info2": "你没有可交换的武器", + + "zeus": "宙斯", + "zeus_desc": "宙斯x27立即充能", + + "your_skill": "你当前的技能", + "enemy_skill": "敌人的技能", + "observer_skill": "玩家的技能", + "welcome_message": "欢迎 {PLAYER} 来到 {SERVER_NAME}!\n当前 jRandomSkills 版本:{VERSION}({SKILLS_COUNT} 个技能)。\n\n最初由以下人员创建:\n{AUTHOR1}\n由以下人员修改和改进:\n{AUTHOR2}", + "drawing_skill": "抽取技能", + "disabled_weapon": "你无法使用这把武器", + + "hud_info": "再等 {0} 秒", + "hud_info_no_enemy": "未找到敌人", + "active_hud_info": "还剩 {0} 毫秒有效", + + "skills_menu": "技能列表", + "no_player": "未找到匹配的玩家。", + "duplicate_player": "找到多个同名玩家。", + "selectplayerskill_command": "输入 /t", + "selectplayerskill_incorrect_enemy_index": "未找到该索引的玩家。", + + "skill_not_found_setskill": "未找到 CHATCOLORS.RED 技能", + "player_not_found_setskill": "未找到 CHATCOLORS.RED 玩家", + "correct_form_setskill": "正确用法:CHATCOLORS.RED!setskill <昵称> <技能>", + "correct_form_setscore": "正确用法:CHATCOLORS.RED!setscore ", + "done_setskill": "技能已设置", + "error_setskill": "无法设置 CHATCOLORS.RED 技能", + "for_setskill": "为", + + "invalid_map": "地图名称输入错误!", + "loading_map": "正在加载新地图", + + "pause": "比赛已暂停。", + "unpause": "比赛已恢复。", + "healed": "你已被治疗。", + "game_start": "游戏开始!", + + "teammate_skills": "你队友的技能", + "summary_start": "=============上一回合总结==============", + "summary_end": "=======================================" +} \ No newline at end of file diff --git a/readme-pl.md b/readme-pl.md index fb1d533..cf05678 100644 --- a/readme-pl.md +++ b/readme-pl.md @@ -1,15 +1,19 @@ + + +

+ ## 📌 Oznaczenie > [!NOTE] > Te repozytorium jest to fork [projektu](https://github.com/jakubbartosik/dRandomSkills) stworzonego przez [Jakuba Bartosika (D3X)](https://github.com/jakubbartosik). ## 💡 Opis -#### Co każdą rundę dostajesz losową supermoc. Plugin zrobiony pod CS2. -
- GitHub release       - GitHub latest commit       - Github all releases       - GitHub stars -
+jRandomSkills to plugin do CounterStrike 2, który wprowadza chaos i frajdę do rozgrywki! W każdej rundzie losowo otrzymujesz jedną z unikalnych supermocy – od niewidzialności, przez wybuchowe strzały, po manipulację kamerą. Zaskocz przeciwników, przejmij kontrolę nad meczem i odkryj dziesiątki kreatywnych umiejętności, które zmieniają dynamikę gry! #### Wybierz język: @@ -19,97 +23,129 @@ +## 🖼️ Prezentacja Pluginu +![Preview](./preview.gif) +![Preview2](./preview2.gif) -## ✨ Aktualne Supermoce (43) -> [!NOTE] -> Jeśli serwer jest postawiony na systemie **Windows** mogą wystąpić problemy z supormecami: **Aimbot**, **Gruby**, **Żołnierz**, **Jednostrzałowiec**. +## 🌐 Serwer testowy +Dołącz do serwera testowego 3v3 i wypróbuj plugin jRandomSkills: +- **Adres**: `jRandomSkills@pukawka.pl` +- **Hasło**: `public` +- **Godziny otwarcia**: `00:00-19:00` +- **Połącz URL**: `steam://connect/51.38.122.215:27235/public` +- **Połącz**: `connect 51.38.122.215:27235; password public` -- **Zamrażający Decoy:** Twój decoy zamraża wszystkich pobliskich graczy -- **Żołnierz:** Masz losowy mnożnik obrażeń (1.15 - 1.35)x -- **Gruby:** Masz losowy mnożnik otrzymywanych obrażeń (0.65 - 0.85)x -- **Aimbot:** Każdy twój trafiony pocisk jest liczony jako głowa -- **Odwrót:** Powrót na spawna. Kliknij [css_useSkill], cooldown 15s -- **Resp Wroga:** Teleportacja na spawn wroga. Kliknij [css_useSkill], cooldown 15s -- **Zeus:** Zeus x27 natychmiastowo się odnawia -- **Radarowiec:** Widzisz wrogów na radarze -- **Szybkostrzelność:** Brak cooldown przy strzelaniu -- **Samowolka:** Możesz podłożyć bombę w dowolnym miejscu, czas detonacji bomby trwa 60s -- **Cichociemny:** Twoje kroki i skoki są niesłyszalne dla INNYCH graczy -- **Zabójczy Flash:** Każdy całkowicie oślepiony twoim granatem umiera (również ty) -- **Spowlnienie Czasu:** Spowolnienie czasu dla wszystkich na 6 sekundy. Kliknij [css_useSkill], cooldown 30s -- **Nieśmiertelność:** Jesteś nieśmiertelny przez 2 sekundy. Kliknij [css_useSkill], cooldown 30s -- **Losowa Broń:** Dostajesz losową broń. Kliknij [css_useSkill], cooldown 15s -- **Zamiana Broni:** Zamieniasz się bronią z losowym wrogiem. Kliknij [css_useSkill], cooldown 30s -- **Wallhack:** Widzisz wrogów przez ściany -- **Zamiana Miejsc:** Zamiana miejscami z losowym wrogiem. Kliknij [css_useSkill], cooldown 30s -- **Mini Majk:** Losowa wielkość postaci na początku rundy (0.6 - 0.95) -- **Flash:** Losowa prędkośc postaci na początku rundy (1.2 - 3.0) -- **Paweł Jumper:** Otrzymujesz dodatkowy skok -- **Królik:** Otrzymujesz auto "BunnyHopa" -- **Szpieg:** Otrzymujesz na start rundy model postaci wroga -- **Jednostrzałowiec:** Po trafieniu od razu zabija przeciwnika -- **Muhammed:** Po śmierci wybucha i zabija graczy w obrębie -- **Bogacz:** Otrzymujesz losową ilość kasy na start rundy (+5000 - +14999) -- **Rambo:** Otrzymujesz losową ilość zdrowia na start rundy (+50 - +500) -- **Medyk:** Otrzymujesz losową ilość apteczek na start rundy (1 - 4) -- **Duszek:** Jesteś całkowicie niewidzialny -- **Kurczak:** Otrzymujesz model kurczaka + jesteś o 10% szybszy - 50hp -- **Astronauta:** Otrzymujesz losową ilość grawitacji na start rundy (0.1 - 0.7)x -- **Rozbrojenie:** Masz losową szanse na wyrzucenie broni wroga po trafieniu (20% - 40%) -- **Anty Flash:** Posiadasz odporność na flashe i 7 sekund trwają twoje flash'e -- **Obrót Wroga:** Masz losową szanse na obrócenie wroga o 180 stopni po trafieniu (20% - 40%) -- **Nieskończone Ammo:** Otrzymujesz nieskończoną ilość ammo do wszystkich swoich broni -- **Katapulta:** Masz losową szanse na podrzucenie wroga (20% - 40%) -- **Drakula:** Po trafieniu ofiary otrzymujesz zwrot zdrowia w postaci danego procentu zadanych obrażeń (0.3x) -- **Teleporter:** Zamieniasz się miejscami z trafionym wrogiem -- **Saper:** Możesz szybciej podłożyć bombę oraz ją zdefować -- **Phoenix:** Masz losową szans na odrodzenie się po śmierci -- **Pilot:** Latanie przez określony czas. Przytrzymaj [USE - E], aby latać -- **Cień:** Teleportujesz się za plecy trafionego wroga -- **Żelazna Głowa:** Nie otrzymujesz obrażeń w głowę +Kupujesz serwer na pukawce? Skorzystaj z mojego [kodu polecającego](https://pukawka.pl/pp,juzlus.html). -## Komendy Serwerowe -> [!TIP] -> **Bind do używania supermocy:** `bind x css_useSkill` +## ✨ Aktualne Supermoce (102) +
+Poniższa tabela przedstawia wszystkie dostępne supermoce w grze, wraz z ich opisami. -- **Lista supermocy:** `!skills` -- **[*] Ustawienie supermocy:** `!setskill `, `!setskill Juzlus Losowa Broń` -$\quad$ -- **[*] Zmiana mapy$^1$:** `!map `, `!map de_nuke` -- **[*] Zmiana mapy z warsztatu$^1$:** `!map `, `!map 3332005394` -- **[*] Szybkie rozpoczęcie gry$^1$:** `!map start` - -_[*] - wymaga uprawnień "@css/root", które można ustawić w game/csgo/addons/counterstrikesharp/configs/admins.json_ - -## ⚙️ Konfiguracja -Możliwość prostej konfiguracji każdej supermocy w pliku "**Config.cfg**" -```json -{ - "SkillsInfo": [ - { - "Name": "None", // Nazwa supermocy - "Active": true, // Czy supermoc ma być włączona przy uruchamianiu - "Cooldown": 30.0, // Ile trzeba odczekać przed następnym użyciem supermocy - "ChanceFrom": 1.0, // Minimalny mnożnik dla danych supermocy - "ChanceTo": 1.0, // Maksymalny mnożnik dla danych supermocy - "Team": 1, // Która drużyna może użyć tej supermocy - // 1 - Wszyscy - // 2 - Terrorist - // 3 - CounterTerrorist - "Only1v1": false // Supermoc działa tylko, gdy jesteś sam w drużynie - }, - ... - ], - "Settings": { - "LangCode": "en", // Wybierz język pluginu: en, pl - "Set_Skill": "ustawskill, setskill", - "SkillsList_Menu": "supermoc, skills, listamocy, supermoce, losowemoce", - "KillerSkillInfo": true, // Wyświetl na czacie informacje o supermocy twojego zabójcy - "TeamMateSkillInfo": true, // Wyświetl na czacie informacje o supermocach twoich sojuszników - "SummaryAfterTheRound": true // Wyświetl na czacie podsumowanie z ostatniej rundy - } -} -``` +| Nazwa | Opis | Czas odnowienia / Zakres | +|-------|------|-----------------------------------| +| Aimbot | Każdy twój trafiony pocisk liczy się jako strzał w głowę | - | +| Anomalia | Cofasz się o 5 sekund do tyłu | 15 s | +| Anty Flash | Posiadasz odporność na flash'e, a twoje flash'e trwają 7 sekund | - | +| Żelazna Głowa | Nie otrzymujesz obrażeń w głowę | - | +| Niszczyciel Stref | Możesz wybrać strefę detonacji, którą chcesz dezaktywować | - | +| Gruby | Masz losowy mnożnik otrzymywanych obrażeń | (0.65 - 0.85)x | +| Skrytobójca | Zadajesz podwójne obrażenia przeciwnikowi od tyłu | - | +| Astronauta | Na początku rundy otrzymujesz losową wartość grawitacji | (0.1 - 0.7)x | +| Bejsbolista | Twój wabik odbija się od ścian i natychmiastowo zabija wroga po trafieniu | - | +| Obrót Wroga | Masz losową szansę na obrócenie wroga o 180 stopni po trafieniu go | (20 - 40)% | +| Mistrz Ostrza | Trzymając nóż, masz duże szanse na odparcie strzału | - | +| Królik | Otrzymujesz auto "BunnyHopa" | - | +| C4 Kamuflaż | Kiedy trzymasz bombę, jesteś niewidzialny | - | +| Katapulta | Masz losową szanse na podrzucenie wroga | (20 - 40)% | +| Kurczak | Otrzymujesz model kurczaka + jesteś o 10% szybszy - 50hp | - | +| Wyluzowany | Podłożenie bomby zajmuje 10 sekund | - | +| Scyzoryk | Natychmiastowe zabójstwo nożem | - | +| Mrok | Nadaje efekt ciemności wybranemu przeciwnikowi | - | +| Deaktywator | Wybierasz gracza, którego supermoc chcesz wyłączyć | - | +| Głuchy | Wybierasz gracza, dla którego chcesz wyłączyć wszystkie dźwięki | - | +| Rozbrojenie | Masz losową szanse na wyrzucenie broni wroga po trafieniu | (65 - 85)% | +| Odległościomierz | Możesz zobaczyć odległość do najbliższego przeciwnika | - | +| Drakula | Po trafieniu ofiary odzyskujesz zdrowie równe pewnemu procentowi zadanych obrażeń | - | +| Duplikator | Wybierasz gracza, od którego chcesz skopiować supermoc | - | +| Mini Majk | Losowa wielkość postaci na początku rundy | (60 - 95)% | +| Resp Wroga | Kliknij [css_useSkill], aby teleportować się na resp wroga | 15 s | +| Strzał Wybuchowy | Losowa szansa wystrzelenia pocisku wybuchowego podczas strzelania | (15 - 30)% | +| Oko Sokoła | Kliknij [css_useSkill], aby aktywować kamerę z lotu ptaka | - | +| Szybkie Rączki | Kliknij [css_useSkill], aby przeładować broń, którą obecnie trzymasz | - | +| Flash | Losowa prędkość postaci na początku rundy | (1.2 - 3.0)x | +| Fortnite | Kliknij [css_useSkill], aby stworzyć barykadę, którą można zniszczyć | 2 s | +| Krucha Bomba | Strzelanie do bomby powoduje jej uszkodzenie | - | +| Ogień Przyjacielski | Strzelanie do członków drużyny leczy ich | - | +| Zamrażający Wabik | Twój decoy zamraża wszystkich graczy w pobliżu | - | +| Duszek | Jesteś całkowicie niewidzialny | - | +| Glaz | Nie widzisz granatów dymnych | - | +| Glitch | Wyłączasz radar wybranemu przeciwnikowi | - | +| Klej | Twoje granaty przyklejają się do ścian | - | +| Nieśmiertelność | Kliknij [css_useSkill], aby stać się nieśmiertelnym na krótką chwilę | 30 s | +| Leczący Dym | Twoje granaty dymne leczą | - | +| Pustelnik | Zabijanie przywraca amunicję i część zdrowia | - | +| Święty Granat Ręczny | Twoje granaty uderzeniowe zadają podwójne obrażenia i mają podwójny zasięg | - | +| Szpieg | Na początku rundy otrzymujesz model postaci przeciwnika | - | +| Nieskończone Ammo | Otrzymujesz nieskończoną ilość amunicji do wszystkich broni | - | +| Stópkarz | Wybierasz gracza, który pozostawi za sobą ślad | - | +| Zakłócacz | Wybierasz gracza, dla którego chcesz wyłączyć celownik | - | +| Beznogi | Wybierasz gracza, który nie będzie mógł skakać | - | +| Pajacyk | Skakanie przywraca zdrowie | - | +| Zabójczy Flash | Każdy całkowicie oślepiony twoim granatem umiera (również ty) | - | +| Zamiana Żyć | Wybierasz gracza, z którym chcesz wymienić się zdrowiem | - | +| Długi Nóż | Podstawowy atak nożem zadaje obrażenia niezależnie od odległości | - | +| Długi Zeus | Zeus zadaje obrażenia niezależnie od odległości | - | +| Medyk | Kliknij [css_useSkill], aby użyć ładunku leczniczego, który przywraca 50 punktów zdrowia | 1 s | +| Skarbówka | Wybierasz gracza, z którym chcesz zamienić się pieniędzmi | - | +| Muhammed | Po śmierci eksplodujesz i zabijasz graczy znajdujących się w zasięgu | - | +| Ninja | Stojąc nieruchomo zwiększasz swoją niewidzialność o 33%, kucając o 33%, a trzymając nóż o 33% | - | +| Pancernik | Granaty nie zadają Ci obrażeń | - | +| Skupienie | Brak odrzutu podczas strzelania | - | +| NoClip | Kliknij [css_useSkill], aby włączyć noclip na krótki czas | 30 s | +| Jednostrzałowiec | Po trafieniu natychmiast zabijasz przeciwnika | - | +| Tylko Głowa | Otrzymujesz obrażenia tylko w głowę | - | +| Pawel Jumper | Otrzymujesz dodatkowy skok | - | +| Feniks | Masz losową szans na odrodzenie się po śmierci | (20 - 40)% | +| Pilot | Latanie przez określony czas. Przytrzymaj [USE - E], aby latać | - | +| Samowolka | Bombę można podłożyć w dowolnym miejscu, a czas detonacji wynosi 60 sekund | - | +| Trutka | Wybierasz gracza, który co kilka sekund będzie otrzymywał obrażenia | - | +| Brak Karabinów | Wybierasz gracza, który nie może używać karabinów | - | +| Proteza | Ramiona i nogi są kuloodporne | - | +| Zdalne Rozbrajanie | Kiedy jesteś blisko bomby, zaczynasz ją rozbrajać | 10 s | +| Odpychacz | Masz losową szansę na odepchnięcie wroga po trafieniu go | 100% | +| Pyro | Molotow przywraca zdrowie | - | +| Szybkostrzelność | Wszystkie pociski są wystrzeliwane bardzo szybko | - | +| Radarowiec | Na radarze widać wrogów | - | +| Rambo | Na początku rundy otrzymujesz losową ilość zdrowia | +(50 - 501) HP | +| Losowa Broń | Kliknij [css_useSkill], aby otrzymać losową broń | 15 s | +| Pancerz Reaktywny | Pancerz pochłania pierwsze otrzymane obrażenia | 15 s | +| Regeneracja | Co kilka sekund odnawiasz zdrowie | - | +| Replikator | Kliknij [css_useSkill], aby stworzyć swoją replikę, która zadaje obrażenia po trafieniu | 15 s | +| Odwrót | Kliknij [css_useSkill], aby powrócić na resp | 15 s | +| Zwrot do Nadawcy | Pierwsze trafienie wroga powoduje, że wraca on na swój resp | - | +| Re-Zombie | Po śmierci odradzasz się jako zombie z większym zdrowiem i bez broni | - | +| Bogacz | Na początku rundy otrzymujesz losową kwotę gotówki | (5000 - 15000)$ | +| Robin Hood | Zadanie obrażeń przeciwnikowi powoduje kradzież jego pieniędzy | - | +| Gumowe Kule | Twoje pociski znacznie spowalniają graczy | - | +| Saper | Możesz szybciej podłożyć bombę i ją rozbroić | - | +| Druga Szansa | Po śmierci odradzasz się z taką samą ilością zdrowia | - | +| Cień | Teleportujesz się za plecy trafionego wroga | - | +| Krótka Bomba | Bomba wybucha znacznie szybciej | - | +| Cichociemny | Twoje kroki i skoki są niesłyszalne dla INNYCH graczy | - | +| SzeliS | Kliknij [css_useSkill], aby zamienić aktualną broń na AWP | 0 s | +| Żołnierz | Masz losowy mnożnik obrażeń | (1.15 - 1.35)x | +| Dźwiękowiec | Kliknij [css_useSkill], aby wywołać dźwięk u każdego przeciwnika | 5 s | +| Obserwator | Kliknij [css_useSkill], aby obserwować losowego przeciwnika | 0 s | +| Zamiana Miejsc | Kliknij [css_useSkill], aby zamienić się miejscami z losowym przeciwnikiem | 30 s | +| Zamiana Broni | Kliknij [css_useSkill], aby zamienić się bronią z losowym przeciwnikiem | 30 s | +| Teleporter | Zamieniasz się miejscami z trafionym przeciwnikiem | - | +| Złodziej | Możesz ukraść supermoc wybranemu graczowi | - | +| Trzecie Oko | Kliknij [css_useSkill], aby aktywować trzecią osobę | 0 s | +| Toksyczny Dym | Twoje granaty dymne zadają obrażenia | - | +| Wallhack | Widzisz wrogów przez ściany | - | +| Zegarmistrz | Każdy rzut granatem zmienia czas rundy o -10 lub +10 sekund | - | +| Zeus | Zeus x27 natychmiastowo się odnawia | - | +
## 💻 Instalacja 1. Zainstaluj / Kup **serwer CS2** @@ -120,23 +156,246 @@ Możliwość prostej konfiguracji każdej supermocy w pliku "**Config.cfg**" - Edytuj plik `gameinfo.gi` dodając nową linijkę ```json Game_LowViolence csgo_lv // Perfect World content override - Game csgo/addons/metamod // <-- Linijka do dodania + Game csgo/addons/metamod // <-- Linijka do dodania (kolejność ma znaczenie) Game csgo ``` 3. Zainstaluj **CounterStrikeSharp** - Pobierz [CounterStrikeSharp-With-Runtime](https://github.com/roflmuffin/CounterStrikeSharp/releases) - Wypakuj go do folderu `C2Server/game/csgo/` -4. Zainstaluj **jRandomSkills** +4. Zainstaluj **CS2TraceRay** + - Pobierz [CS2TraceRay](https://github.com/schwarper/CS2TraceRay/releases) + - Wypakuj go do folderu `CS2Server/game/csgo/addons/counterstrikesharp/` +5. Zainstaluj **jRandomSkills** - Pobierz [jRandomSkills](https://github.com/Juzlus/jRandomSkills/releases) - Wypakuj go do folderu `C2Server/game/csgo/addons/counterstrikesharp/plugins/` + - JEŚLI do pobrania jest plik `gamedata.json`: + - Wypakuj go do folderu `C2Server/server/game/csgo/addons/counterstrikesharp/gamedata/` -## 🖼️ Prezentacja Pluginu -![Preview](./preview.gif) +## Komendy Serwerowe +> [!TIP] +> **Bind do używania supermocy:** `bind x css_useSkill` + +
+Poniższa tabela przedstawia wszystkie dostępne komendy w grze, wraz z ich opisami. + +| Komenda | Przykład | Opis | Uprawnienia | +| - | - | - | - | +| `!setskill ` | `!setskill Juzlus Aimbot` | Ustawienie supermocy | `@jRandmosSkills/admin` | +| `!skills` | `!skills` | Lista supermocy | - | +| `!map ` | `!map de_nuke` | Zmiana mapy | `@jRandmosSkills/admin` | +| `!map ` | `!map 3332005394` | Zmiana mapy z warsztatu | `@jRandmosSkills/admin` | +| `!start` | `!start` | Rozpoczęcie gry z parametrami: `mp_forcecamera 0, mp_freezetime 5, mp_overtime_enable 1, sv_cheats 0` | `@jRandmosSkills/admin` | +| `!start sv` | `!start sv` | Rozpoczęcie gry z parametrami: `mp_forcecamera 0, mp_freezetime 0, mp_overtime_enable 1, sv_cheats 1` | `@jRandmosSkills/admin` | +| `!console ""` | `!console "sv_cheats 1"` | Uruchomienie komendy na serwerze | `@jRandmosSkills/root` | +| `!swap` | `!swap` | Zamiana stron | `@jRandmosSkills/admin` | +| `!shuffle` | `!shuffle` | Losowe dobranie graczy do drużyn | `@jRandmosSkills/admin` | +| `!pause` | `!pause` | Wstrzymanie gry | `@jRandmosSkills/admin` | +| `!heal` | `!heal` | Przywrócenie 100 punktów zdrowia | `@jRandmosSkills/root` | +| `!setscore ` | `!setscore 10 7` | Ustawienie wyniku gry | `@jRandmosSkills/root` | + +_Większość poleceń wymaga uprawnień, które należy ustawić w pliku: `game/csgo/addons/counterstrikesharp/configs/admins.json`_ +
+ +## 🔑 Uprawnienia +Aby nadać uprawnienia administracyjne w CounterStrikeSharp: +1. W folderze **`game/csgo/addons/counterstrikesharp/configs/`** utwórz plik **`admins.json`**. +2. Dodaj do niego poniższą zawartość: + ```json + { + "Juzlus": { + "identity": "STEAM_0:0:94913632", + "flags": ["@jRandmosSkills/admin", "@jRandmosSkills/root"] + } + } + ``` + `steamID` można znaleźć przy pomocy strony [steamidfinder](www.steamidfinder.com). +3. Zapisz plik i uruchom serwer, aby zastosować zmiany. + +## ⚙️ Konfiguracja +Wszystkie sypermoce można dostosować w pliku **`Config.cfg`** znajdującym się w folderze `game\csgo\addons\counterstrikesharp\plugins\jRandomSkills` + +```json +{ + "Settings": { + "LangCode": "en", // Język pluginu: en, pl, pt-br, zh + "GameMode": 0, // Tryb gry: + // 0 - Losowa supermoc dla każdego gracza + // 1 - Ta sama supermoc dla całej drużyny + // 2 - Ta sama supermoc dla wszystkich graczy + // 3 - Debug: Supormoce są przydzielane po kolei + "KillerSkillInfo": true, // Pokazuj supermoc zabójcy na czacie + "TeamMateSkillInfo": true, // Pokazuj supermoc sojuszników na czacie + "SummaryAfterTheRound": true, // Pokazuj podsumowanie z ostatniej rundy + "DebugMode": true, // Zapisuj aktywność do folderu 'Debug' + ... + }, + "SkillsInfo": [ + { + "NeedsTeammates": false, // Wymaga innych graczy w drużynie + "OnlyTeam": 0, // Dostępność supermocy: + // 0 - Wszyscy + // 2 - Terrorist + // 3 - CounterTerrorist + "Color": "#ff0000", // Kolor supermocy + "Active": true, // Włączona przy uruchamianiu + "Name": "Aimbot" // Nazwa supermocy + }, + ... + ] +} +``` + +## 🔗 Uwzględniona zależność +Plugin korzysta z zawartości następujących projektów: +- [CS2TraceRay](https://github.com/schwarper/CS2TraceRay) autorstwa [schwarper](https://github.com/schwarper) - system śledzenia promieni (Trace Ray) +- [CS2FlashingHtmlHudFix](https://github.com/girlglock/CS2FlashingHtmlHudFix) autorstwa [girlglock](https://github.com/girlglock) - poprawka migotania okienka z supermocą +- [ChaseMod](https://github.com/ipsvn/ChaseMod/blob/master/Utils/Memory/CCSMatch.cs) autorstwa [ipsvn](https://github.com/ipsvn) - ustawianie wyniku rund ## 📋 Lista Zmian -### v1.0.3 (by Juzlus) +
+v1.1.0 + +- #### Ogólne: + - ###### Dodano język brazylijski (portugalski) (Grok AI). + - ###### Dodano język chiński (Grok AI). + - ###### Dodano tryby gry. + - ###### Dodano konfigurację dla każdej supermocy. + - ###### Dodano tryb Debug Mode. + - ###### Dodano otrzymywanie broni dla klas z nimi związanymi (sugestia od [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)). + - ###### Wprowadzono ogólne poprawki i naprawiono błedy. +- #### Nowe moce: + - ##### Anomalia + - ###### Cofasz się o 5 sekund do tyłu. Cooldown: 15 s. + - ##### Niszczyciel Stref + - ###### Możesz wybrać strefę detonacji, którą chcesz dezaktywować. + - ##### Skrytobójca + - ###### Zadajesz podwójne obrażenia przeciwnikowi od tyłu. + - ##### Bejsbolista + - ###### Twój wabik odbija się od ścian i natychmiastowo zabija wroga po trafieniu. + - ##### Mistrz Ostrza + - ###### Trzymając nóż, masz duże szanse na odparcie strzału. + - ##### C4 Kamuflaż + - ###### Kiedy trzymasz bombę, jesteś niewidzialny. + - ##### Wyluzowany + - ###### Podłożenie bomby zajmuje 10 sekund. + - ##### Scyzoryk + - ###### Natychmiastowe zabójstwo nożem. + - ##### Mrok + - ###### Nadaje efekt ciemności wybranemu przeciwnikowi. + - ##### Deaktywator + - ###### Wybierasz gracza, którego supermoc chcesz wyłączyć. + - ##### Głuchy + - ###### Wybierasz gracza, dla którego chcesz wyłączyć wszystkie dźwięki. + - ##### Odległościomierz + - ###### Możesz zobaczyć odległość do najbliższego przeciwnika. + - ##### Duplikator + - ###### Wybierasz gracza, od którego chcesz skopiować supermoc. + - ##### Strzał Wybuchowy + - ###### Losowa szansa wystrzelenia pocisku wybuchowego podczas strzelania. Szansa: (15 - 30)%. + - ##### Oko Sokoła + - ###### Kliknij [css_useSkill], aby aktywować kamerę z lotu ptaka. + - ##### Szybkie Rączki + - ###### Kliknij [css_useSkill], aby przeładować broń, którą obecnie trzymasz. + - ##### Fortnite + - ###### Kliknij [css_useSkill], aby stworzyć barykadę, którą można zniszczyć. Cooldown: 2 s. + - ##### Krucha Bomba + - ###### Strzelanie do bomby powoduje jej uszkodzenie. + - ##### Ogień Przyjacielski + - ###### Strzelanie do członków drużyny leczy ich. + - ##### Glaz + - ###### Nie widzisz granatów dymnych. + - ##### Glitch (wymyślone przez [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)) + - ###### Wyłączasz radar wybranemu przeciwnikowi. + - ##### Klej (wymyślone przez [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)) + - ###### Twoje granaty przyklejają się do ścian. + - ##### Leczący Dym + - ###### Twoje granaty dymne leczą. + - ##### Pustelnik (wymyślone przez [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)) + - ###### Zabijanie przywraca amunicję i część zdrowia. + - ##### Święty Granat Ręczny + - ###### Twoje granaty uderzeniowe zadają podwójne obrażenia i mają podwójny zasięg. + - ##### Stópkarz + - ###### Wybierasz gracza, który pozostawi za sobą ślad. + - ##### Zakłócacz (wymyślone przez [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)) + - ###### Wybierasz gracza, dla którego chcesz wyłączyć celownik. + - ##### Beznogi + - ###### Wybierasz gracza, który nie będzie mógł skakać. + - ##### Pajacyk + - ###### Skakanie przywraca zdrowie. + - ##### Zamiana Żyć + - ###### Wybierasz gracza, z którym chcesz wymienić się zdrowiem. + - ##### Długi Nóż + - ###### Podstawowy atak nożem zadaje obrażenia niezależnie od odległości. + - ##### Długi Zeus + - ###### Zeus zadaje obrażenia niezależnie od odległości. + - ##### Skarbówka + - ###### Wybierasz gracza, z którym chcesz zamienić się pieniędzmi. + - ##### Ninja + - ###### Stojąc nieruchomo zwiększasz swoją niewidzialność o 33%, kucając o 33%, a trzymając nóż o 33%. + - ##### Pancernik + - ###### Granaty nie zadają Ci obrażeń. + - ##### Skupienie (wymyślone przez [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)) + - ###### Brak odrzutu podczas strzelania. + - ##### NoClip + - ###### Kliknij [css_useSkill], aby włączyć noclip na krótki czas. Cooldown: 30 s. + - ##### Tylko Głowa + - ###### Otrzymujesz obrażenia tylko w głowę. + - ##### Trutka + - ###### Wybierasz gracza, który co kilka sekund będzie otrzymywał obrażenia. + - ##### Brak Karabinów + - ###### Wybierasz gracza, który nie może używać karabinów. + - ##### Proteza + - ###### Ramiona i nogi są kuloodporne. + - ##### Zdalne Rozbrajanie + - ###### Kiedy jesteś blisko bomby, zaczynasz ją rozbrajać. Cooldown: 10 s. + - ##### Odpychacz + - ###### Masz losową szansę na odepchnięcie wroga po trafieniu go. Szansa: 100%. + - ##### Pyro + - ###### Molotow przywraca zdrowie. + - ##### Pancerz Reaktywny + - ###### Pancerz pochłania pierwsze otrzymane obrażenia. Cooldown: 15 s. + - ##### Regeneracja + - ###### Co kilka sekund odnawiasz zdrowie. + - ##### Replikator + - ###### Kliknij [css_useSkill], aby stworzyć replikę, która zadaje obrażenia po trafieniu. Cooldown: 15 s. + - ##### Zwrot do Nadawcy + - ###### Pierwsze trafienie wroga powoduje, że wraca on na swój resp. + - ##### Re-Zombie + - ###### Po śmierci odradzasz się jako zombie z większym zdrowiem i bez broni. + - ##### Robin Hood (wymyślone przez [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)) + - ###### Zadanie obrażeń przeciwnikowi powoduje kradzież jego pieniędzy. + - ##### Gumowe Kule (wymyślone przez [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)) + - ###### Twoje pociski znacznie spowalniają graczy. + - ##### Druga Szansa + - ###### Po śmierci odradzasz się z taką samą ilością zdrowia. + - ##### Krótka Bomba (wymyślone przez [ToRRent1812](https://github.com/Juzlus/jRandomSkills/issues/1)) + - ###### Bomba wybucha znacznie szybciej. + - ##### SzeliS + - ###### Kliknij [css_useSkill], aby zamienić aktualną broń na AWP. + - ##### Dźwiękowiec + - ###### Kliknij [css_useSkill], aby wywołać dźwięk u każdego przeciwnika. Cooldown: 5 s. + - ##### Obserwator + - ###### Kliknij [css_useSkill], aby obserwować losowego przeciwnika. + - ##### Złodziej + - ###### Możesz ukraść supermoc wybranemu graczowi. + - ##### Trzecie Oko + - ###### Kliknij [css_useSkill], aby aktywować trzecią osobę. + - ##### Toksyczny Dym + - ###### Twoje granaty dymne zadają obrażenia. + - ##### Wallhack + - ###### Widzisz wrogów przez ściany. + - ##### Zegarmistrz + - ###### Każdy rzut granatem zmienia czas rundy o -10 lub +10 sekund. +- #### Poprawki mocy: + - ###### Poprawiono opisy supermocy. + - ###### Naprawiono wszyskie zauważalne błedy. +
+ +
+v1.0.3 + - #### Ogólne: - ###### Dodano język angielski. - ###### Dodano wiadomość powitalną. @@ -185,8 +444,11 @@ Możliwość prostej konfiguracji każdej supermocy w pliku "**Config.cfg**" - ##### Duszek: - ###### Naprawiono bycie niewidzialnym po śmierci. - ###### Drobne poprawki dla reszty mocy. +
+ +
+v1.0.2 -### v1.0.2 (by Juzlus) - #### Nowe moce: - ##### Mini Majk: - ###### Losowa wielkość postaci w przedziale (60% - 95%). @@ -238,7 +500,19 @@ Możliwość prostej konfiguracji każdej supermocy w pliku "**Config.cfg**" - ###### Zmieniono: Zmineiono nazwę mocy z 'Eliminator' na 'Saper'. - ##### Teleporter: - ###### Naprawiono błąd, gdzie tylko gracz z supermocą był przeteleportowywany. +
+ +## 💝 Donate + + + + + ⠀ + + + + ## 📝 Kontakt -Jeśli masz jakieś pytanie, napisz na juzlus.biznes@gmail.com lub [Discord](https://discordapp.com/users/284780352042434570). +Jeśli masz jakieś pytanie, napisz na juzlus.biznes@gmail.com lub [jRandomSkills Discord](hhttps://discord.gg/72nzFguNtd).
+ GitHub release       + GitHub latest commit       + Github all releases       + GitHub stars       + Discord server +