Updates & Fixes

# Updates & Fixes
- Vote system: Timer now resets after each vote
- Automatic copying of gamedata files from source to server (Thanks to vinicius-trev for the help)
- Improved power assignment at round start
- Observers can now see invisible players.
- Added geolocation support for Turkey and Czechia
- New power: Illiterate
- In development: Smoker skill
- Baseball: Decoy now have the same collision as players (PlayerClip)
- Noclip: Reworked
- Pilot: Currently broken
- Replicator: Added crouching animations for replicas
- SoundMaker: Reworked (automatically play a sound every 2s (only for you))
- Wallhack: Glow disabled for dead players

# TODO
- Add/update descriptions for new/reworked skills
- Fix Pilot, SniperElite
This commit is contained in:
Juzlus 2026-02-14 05:33:17 +01:00
parent f76093ef6e
commit 09803748bc
28 changed files with 691 additions and 295 deletions

View file

@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -16,7 +17,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.362" /> <PackageReference Include="CounterStrikeSharp.API" Version="1.0.362" />
<PackageReference Include="CS2TraceRay" Version="1.0.9" /> <PackageReference Include="CS2TraceRay" Version="1.0.9" />
<PackageReference Include="MaxMind.Db" Version="4.3.4" /> <PackageReference Include="MaxMind.Db" Version="4.3.4">
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup> </ItemGroup>
@ -45,6 +47,8 @@
<ServerLangDir>$(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\plugins\jRandomSkills\languages</ServerLangDir> <ServerLangDir>$(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\plugins\jRandomSkills\languages</ServerLangDir>
<SourceDLL>$(MSBuildProjectDirectory)\bin\Debug\net8.0</SourceDLL> <SourceDLL>$(MSBuildProjectDirectory)\bin\Debug\net8.0</SourceDLL>
<ServerDLL>$(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\plugins\jRandomSkills</ServerDLL> <ServerDLL>$(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\plugins\jRandomSkills</ServerDLL>
<SourceGamedataDir>$(MSBuildProjectDirectory)\src\gamedata</SourceGamedataDir>
<ServerGamedataDir>$(MSBuildProjectDirectory)\..\jRandomSkills - Server Files\gamedata</ServerGamedataDir>
</PropertyGroup> </PropertyGroup>
<!-- Copy language files to server directory --> <!-- Copy language files to server directory -->
@ -63,8 +67,20 @@
<ItemGroup> <ItemGroup>
<CompiledDLL Include="$(SourceDLL)\jRandomSkills.dll" /> <CompiledDLL Include="$(SourceDLL)\jRandomSkills.dll" />
<CompiledDLL Include="$(SourceDLL)\WASDMenuAPI.dll" /> <CompiledDLL Include="$(SourceDLL)\WASDMenuAPI.dll" />
<CompiledDLL Include="$(SourceDLL)\MaxMind.Db.dll" />
<CompiledDLL Include="$(SourceDLL)\Newtonsoft.Json.dll" />
</ItemGroup> </ItemGroup>
<MakeDir Directories="$(ServerDLL)" Condition="!Exists('$(ServerDLL)')" /> <MakeDir Directories="$(ServerDLL)" Condition="!Exists('$(ServerDLL)')" />
<Copy SourceFiles="@(CompiledDLL)" DestinationFiles="@(CompiledDLL->'$(ServerDLL)\\%(Filename)%(Extension)')" SkipUnchangedFiles="false" /> <Copy SourceFiles="@(CompiledDLL)" DestinationFiles="@(CompiledDLL->'$(ServerDLL)\\%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
</Target> </Target>
<!-- Copy gamedata files to server directory -->
<Target Name="CopyGamedataFilesToServer" AfterTargets="Build">
<Message Text="Copying gamedata files from $(SourceGamedataDir) to $(ServerGamedataDir)" Importance="High" />
<ItemGroup>
<GamedataFiles Include="$(SourceGamedataDir)\**\*.*" />
</ItemGroup>
<MakeDir Directories="$(ServerGamedataDir)" Condition="!Exists('$(ServerGamedataDir)')" />
<Copy SourceFiles="@(GamedataFiles)" DestinationFiles="@(GamedataFiles->'$(ServerGamedataDir)\\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
</Target>
</Project> </Project>

View file

@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using src.utils; using src.utils;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
namespace src.command namespace src.command
{ {
@ -10,6 +11,20 @@ namespace src.command
{ {
private static readonly ConcurrentDictionary<VoteData, byte> votes = []; private static readonly ConcurrentDictionary<VoteData, byte> votes = [];
private static void StartVoteTimer(VoteData vote, string commandName)
{
vote.ActiveTimer?.Kill();
vote.ActiveTimer = jRandomSkills.Instance.AddTimer(vote.TimeToVote, () =>
{
if (!votes.ContainsKey(vote) || !vote.GetActive()) return;
vote.SetActive(false);
vote.TimeToNextSameVoting = vote.TimeToNextVoting;
Localization.PrintTranslationToChatAll($" {ChatColors.Red}{{0}}", ["vote_timeout"], [commandName]);
});
}
private static VoteData? CreateVote(VoteType voteType, string? args = null) private static VoteData? CreateVote(VoteType voteType, string? args = null)
{ {
var vote = new VoteData(10, var vote = new VoteData(10,
@ -27,21 +42,15 @@ namespace src.command
foreach (var player in Utilities.GetPlayers()) foreach (var player in Utilities.GetPlayers())
player.EmitSound("UIPanorama.tab_mainmenu_news"); player.EmitSound("UIPanorama.tab_mainmenu_news");
if (vote == null) return vote; StartVoteTimer(vote!, commandName);
jRandomSkills.Instance.AddTimer(vote.TimeToVote, () =>
{
if (!votes.ContainsKey(vote) || !vote.GetActive()) return;
vote.SetActive(false);
vote.TimeToNextSameVoting = vote.TimeToNextVoting;
Localization.PrintTranslationToChatAll($" {ChatColors.Red}{{0}}", ["vote_timeout"], [commandName]);
});
float[] times = [vote.TimeToVote, vote.TimeToVote + vote.TimeToNextVoting, vote.TimeToVote + vote.TimeToNextSameVoting]; float[] times = [vote!.TimeToVote, vote.TimeToVote + vote.TimeToNextVoting, vote.TimeToVote + vote.TimeToNextSameVoting];
jRandomSkills.Instance.AddTimer(times.Max(), () => jRandomSkills.Instance.AddTimer(times.Max(), () =>
{ {
if (!votes.ContainsKey(vote)) return; if (!votes.ContainsKey(vote)) return;
votes.TryRemove(vote, out _); votes.TryRemove(vote, out _);
}); });
return vote; return vote;
} }
@ -78,16 +87,21 @@ namespace src.command
private static void CheckVote(VoteData vote) private static void CheckVote(VoteData vote)
{ {
int voted = vote.PlayersVoted.Count; int voted = vote.PlayersVoted.Count;
int playerCount = Utilities.GetPlayers().Where(p => !p.IsBot).ToArray().Length; int playerCount = Utilities.GetPlayers().Count(p => !p.IsBot);
int playersNeeded = (int)Math.Ceiling(playerCount * (vote.PercentagesToSuccess / 100f)); int playersNeeded = (int)Math.Ceiling(playerCount * (vote.PercentagesToSuccess / 100f));
string commandName = $"!{VoteTypeCommands.GetCommand(vote.Type)?.Replace("css_", "")}{(!string.IsNullOrEmpty(vote?.Args) ? $" {vote?.Args}" : "")}";
if (voted >= playersNeeded) if (voted >= playersNeeded)
{ {
vote!.ActiveTimer?.Kill();
vote.SuccessAction.Invoke(); vote.SuccessAction.Invoke();
vote.SetActive(false); vote.SetActive(false);
} }
else else
Localization.PrintTranslationToChatAll($" {ChatColors.Yellow}{{0}} '!{VoteTypeCommands.GetCommand(vote.Type)?.Replace("css_", "")}{(!string.IsNullOrEmpty(vote?.Args) ? $" {vote?.Args}" : "")}': {ChatColors.Green}{voted}/{playersNeeded}", ["vote_vote"]); {
StartVoteTimer(vote!, commandName);
Localization.PrintTranslationToChatAll($" {ChatColors.Yellow}{{0}} '': {ChatColors.Green}{voted}/{playersNeeded}", ["vote_vote"]);
}
} }
} }
@ -103,7 +117,7 @@ namespace src.command
public VoteType Type { get; set; } = type; public VoteType Type { get; set; } = type;
public string? Args { get; set; } = args; public string? Args { get; set; } = args;
public ConcurrentDictionary<ulong, byte> PlayersVoted { get; set; } = []; public ConcurrentDictionary<ulong, byte> PlayersVoted { get; set; } = [];
public Timer? ActiveTimer { get; set; }
private DateTime CreatedTime { get; set; } = DateTime.Now; private DateTime CreatedTime { get; set; } = DateTime.Now;
public void SetActive(bool active) public void SetActive(bool active)

View file

@ -0,0 +1,23 @@
{
"SmokeGrenadeProjectile_CreateFunc": {
"signatures": {
"library": "server",
"windows": "48 8B C4 48 89 58 ? 48 89 68 ? 48 89 70 ? 57 41 56 41 57 48 81 EC ? ? ? ? 48 8B B4 24 ? ? ? ? 4D 8B F8",
"linux": "55 4C 89 C1 48 89 E5 41 57 49 89 FF 41 56 45 89 CE"
}
},
"HEGrenadeProjectile_CreateFunc": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 8B AC 24 ? ? ? ? 49 8B F8",
"linux": "55 4C 89 C1 48 89 E5 41 57 49 89 D7"
}
},
"Shoot_Secondary": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 ? 57 48 83 EC 20 44 0F BF C2",
"linux": "55 48 89 E5 41 54 53 48 89 FB 66 83 FE 65"
}
}
}

View file

@ -27,7 +27,7 @@ namespace src
public override string ModuleName => "[CS2] [ jRandomSkills ]"; public override string ModuleName => "[CS2] [ jRandomSkills ]";
public override string ModuleAuthor => "D3X, Juzlus"; 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 ModuleDescription => "Plugin adds random skills every round for CS2 by D3X. Modified by Juzlus.";
public override string ModuleVersion => "1.10.0"; public override string ModuleVersion => "1.2.1";
public override void Load(bool hotReload) public override void Load(bool hotReload)
{ {

View file

@ -100,6 +100,7 @@ public enum Skills
Hermit, Hermit,
HolyHandGrenade, HolyHandGrenade,
Iana, Iana,
Illiterate,
Impostor, Impostor,
InfiniteAmmo, InfiniteAmmo,
Jackal, Jackal,
@ -150,6 +151,7 @@ public enum Skills
Shade, Shade,
ShortBomb, ShortBomb,
Silent, Silent,
Smoker,
SniperElite, SniperElite,
Soldier, Soldier,
SoundMaker, SoundMaker,

View file

@ -8,15 +8,18 @@ using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.UserMessages; using CounterStrikeSharp.API.Modules.UserMessages;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using src.player.skills;
using src.utils; using src.utils;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using static CounterStrikeSharp.API.Core.Listeners; using static CounterStrikeSharp.API.Core.Listeners;
using static src.jRandomSkills; using static src.jRandomSkills;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
namespace src.player namespace src.player
{ {
public static partial class Event public static partial class Event
{ {
private static Timer? setSkillTimer = null;
private static DateTime freezeTimeEnd = DateTime.MinValue; private static DateTime freezeTimeEnd = DateTime.MinValue;
private static bool isTransmitRegistered = false; private static bool isTransmitRegistered = false;
public static readonly jSkill_SkillInfo noneSkill = new(Skills.None, SkillsInfo.GetValue<string>(Skills.None, "color"), false); public static readonly jSkill_SkillInfo noneSkill = new(Skills.None, SkillsInfo.GetValue<string>(Skills.None, "color"), false);
@ -39,6 +42,7 @@ namespace src.player
Instance.RegisterEventHandler<EventPlayerConnectFull>(PlayerConnectFull); Instance.RegisterEventHandler<EventPlayerConnectFull>(PlayerConnectFull);
Instance.RegisterEventHandler<EventPlayerDisconnect>(PlayerDisconnect); Instance.RegisterEventHandler<EventPlayerDisconnect>(PlayerDisconnect);
// Instance.RegisterEventHandler<EventPlayerChat>(PlayerChat); // Instance.RegisterEventHandler<EventPlayerChat>(PlayerChat);
Instance.RegisterEventHandler<EventPlayerSpawned>(PlayerSpawned);
Instance.RegisterEventHandler<EventRoundStart>(RoundStart); Instance.RegisterEventHandler<EventRoundStart>(RoundStart);
Instance.RegisterEventHandler<EventRoundEnd>(RoundEnd); Instance.RegisterEventHandler<EventRoundEnd>(RoundEnd);
@ -384,6 +388,32 @@ namespace src.player
return HookResult.Continue; return HookResult.Continue;
} }
private static HookResult PlayerSpawned(EventPlayerSpawned @event, GameEventInfo info)
{
lock (setLock)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return HookResult.Continue;
var skillPlayer = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (skillPlayer == null) return HookResult.Continue;
if (setSkillTimer != null)
{
skillPlayer.IsDrawing = true;
return HookResult.Continue;
}
skillPlayer.IsDrawing = false;
if (Instance?.GameRules != null &&
Instance?.GameRules.WarmupPeriod == false &&
skillPlayer.Skill == Skills.None &&
skillPlayer.SpecialSkill == Skills.None)
SetRandomSkill(player);
return HookResult.Continue;
}
}
private static HookResult RoundStart(EventRoundStart @event, GameEventInfo info) private static HookResult RoundStart(EventRoundStart @event, GameEventInfo info)
{ {
lock (setLock) lock (setLock)
@ -401,7 +431,11 @@ namespace src.player
Instance.RemoveListener<CheckTransmit>(CheckTransmit); Instance.RemoveListener<CheckTransmit>(CheckTransmit);
int freezetime = ConVar.Find("mp_freezetime")?.GetPrimitiveValue<Int32>() ?? 0; int freezetime = ConVar.Find("mp_freezetime")?.GetPrimitiveValue<Int32>() ?? 0;
freezeTimeEnd = DateTime.Now.AddSeconds(freezetime + (Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0)); freezeTimeEnd = DateTime.Now.AddSeconds(freezetime + (Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0));
Instance?.AddTimer((Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0) + Math.Max(freezetime - Config.LoadedConfig.SkillTimeBeforeStart, 0) + .3f, SetSkill);
setSkillTimer?.Kill();
float timeToDraw = (Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0) + Math.Max(freezetime - Config.LoadedConfig.SkillTimeBeforeStart, 0) + .3f;
setSkillTimer = Instance?.AddTimer(timeToDraw, SetSkill);
return HookResult.Continue; return HookResult.Continue;
} }
} }
@ -447,6 +481,7 @@ namespace src.player
private static HookResult RoundEnd(EventRoundEnd @event, GameEventInfo info) private static HookResult RoundEnd(EventRoundEnd @event, GameEventInfo info)
{ {
Illiterate.Disable();
lock (setLock) lock (setLock)
{ {
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid)) foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid))
@ -567,6 +602,7 @@ namespace src.player
private static void SetSkill() private static void SetSkill()
{ {
setSkillTimer = null;
lock (setLock) lock (setLock)
{ {
var validPlayers = Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot && !p.IsHLTV && p.Team is CsTeam.CounterTerrorist or CsTeam.Terrorist).ToList(); var validPlayers = Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot && !p.IsHLTV && p.Team is CsTeam.CounterTerrorist or CsTeam.Terrorist).ToList();
@ -670,6 +706,11 @@ namespace src.player
skillPlayer.Skill = randomSkill.Skill; skillPlayer.Skill = randomSkill.Skill;
skillPlayer.SpecialSkill = Skills.None; skillPlayer.SpecialSkill = Skills.None;
if (randomSkill.Skill == Skills.Illiterate)
Illiterate.Enable();
Instance?.AddTimer(.2f, () =>
{
if (SkillsInfo.GetValue<bool>(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime()) if (SkillsInfo.GetValue<bool>(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime())
Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () => Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () =>
{ {
@ -678,6 +719,7 @@ namespace src.player
}); });
else else
Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]);
});
Debug.WriteToDebug($"Player {skillPlayer.PlayerName} has got the skill \"{player.GetSkillName(randomSkill.Skill)}\"."); Debug.WriteToDebug($"Player {skillPlayer.PlayerName} has got the skill \"{player.GetSkillName(randomSkill.Skill)}\".");
skillPlayer.SkillHudExpired = DateTime.Now.AddSeconds(Config.LoadedConfig.SkillHudDuration); skillPlayer.SkillHudExpired = DateTime.Now.AddSeconds(Config.LoadedConfig.SkillHudDuration);
@ -685,7 +727,7 @@ namespace src.player
if (Config.LoadedConfig.TeamMateSkillChatInfo) if (Config.LoadedConfig.TeamMateSkillChatInfo)
{ {
Instance?.AddTimer(.5f, () => Instance?.AddTimer(.6f, () =>
{ {
foreach (var teammate in teammates) foreach (var teammate in teammates)
{ {
@ -732,6 +774,7 @@ namespace src.player
var skillPlayer = Instance?.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); var skillPlayer = Instance?.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (skillPlayer == null) return; if (skillPlayer == null) return;
skillPlayer.IsDrawing = false;
if (player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid) if (player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid)
{ {
skillPlayer.Skill = Skills.None; skillPlayer.Skill = Skills.None;
@ -792,13 +835,20 @@ namespace src.player
skillPlayer.Skill = randomSkill.Skill; skillPlayer.Skill = randomSkill.Skill;
skillPlayer.SpecialSkill = Skills.None; skillPlayer.SpecialSkill = Skills.None;
if (randomSkill.Skill == Skills.Illiterate)
Illiterate.Enable();
Instance?.AddTimer(.2f, () =>
{
if (SkillsInfo.GetValue<bool>(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime()) if (SkillsInfo.GetValue<bool>(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime())
Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () => { Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () =>
{
if (Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID && p.Skill == randomSkill.Skill) == null) return; if (Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID && p.Skill == randomSkill.Skill) == null) return;
Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]);
}); });
else else
Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]); Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]);
});
Debug.WriteToDebug($"Player {skillPlayer.PlayerName} has got the skill \"{player.GetSkillName(randomSkill.Skill)}\"."); Debug.WriteToDebug($"Player {skillPlayer.PlayerName} has got the skill \"{player.GetSkillName(randomSkill.Skill)}\".");
skillPlayer.SkillDescriptionHudExpired = DateTime.Now.AddSeconds(Config.LoadedConfig.SkillDescriptionDuration); skillPlayer.SkillDescriptionHudExpired = DateTime.Now.AddSeconds(Config.LoadedConfig.SkillDescriptionDuration);
@ -820,6 +870,14 @@ namespace src.player
lock (setLock) lock (setLock)
{ {
if (player == null || !player.IsValid) return; if (player == null || !player.IsValid) return;
if (Illiterate.CheckIlliterateSkill(player))
{
headerLine = Illiterate.GetRandomText(headerLine);
centerLine = Illiterate.GetRandomText(centerLine);
extraLine = Illiterate.GetRandomText(extraLine);
}
var config = Config.LoadedConfig.HtmlHudCustomisation; var config = Config.LoadedConfig.HtmlHudCustomisation;
var emptySymbol = $"<font class='fontSize-{(string.IsNullOrEmpty(headerLine) ? "l" : "ml")}'> </font>"; var emptySymbol = $"<font class='fontSize-{(string.IsNullOrEmpty(headerLine) ? "l" : "ml")}'> </font>";
var emptySymbol2 = $"<font class='fontSize-ml'> </font>"; var emptySymbol2 = $"<font class='fontSize-ml'> </font>";

View file

@ -62,7 +62,7 @@ namespace src.player
infoLine = player.GetTranslation("your_skill"); infoLine = player.GetTranslation("your_skill");
skillLine = player.GetTranslation("none"); skillLine = player.GetTranslation("none");
} }
else if (skillPlayer.IsDrawing) else if (skillPlayer.IsDrawing && player.PawnIsAlive)
{ {
var randomSkill = SkillData.Skills.ToArray()[Instance.Random.Next(SkillData.Skills.Count)]; var randomSkill = SkillData.Skills.ToArray()[Instance.Random.Next(SkillData.Skills.Count)];
infoLine = player.GetTranslation("drawing_skill"); infoLine = player.GetTranslation("drawing_skill");

View file

@ -51,6 +51,9 @@ namespace src.player.skills
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return; if (playerInfo?.Skill != skillName) return;
decoys.TryAdd(decoy, 0); decoys.TryAdd(decoy, 0);
decoy.Collision.CollisionAttribute.InteractsWith = pawn.Collision.CollisionAttribute.InteractsWith;
decoy.Collision.CollisionGroup = pawn.Collision.CollisionGroup;
} }
public static void DecoyStarted(EventDecoyStarted @event) public static void DecoyStarted(EventDecoyStarted @event)

View file

@ -1,7 +1,6 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using src.utils; using src.utils;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@ -62,8 +61,19 @@ namespace src.player.skills
foreach (var (info, player) in infoList) foreach (var (info, player) in infoList)
{ {
if (player == null || !player.IsValid) continue; if (player == null || !player.IsValid) continue;
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
bool isObservingC4Camouflage = false;
if (targetHandle != nint.Zero)
{
var target = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == targetHandle);
var targetInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == target?.SteamID);
if (targetInfo?.Skill == skillName) isObservingC4Camouflage = true;
}
foreach (var _player in invisiblePlayers.Keys) foreach (var _player in invisiblePlayers.Keys)
if (player.SteamID != _player.SteamID) if (player.SteamID != _player.SteamID && !isObservingC4Camouflage)
{ {
var playerPawn = _player.PlayerPawn.Value; var playerPawn = _player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid) continue; if (playerPawn == null || !playerPawn.IsValid) continue;

View file

@ -151,12 +151,13 @@ namespace src.player.skills
pawn!.CameraServices!.ViewEntity.Raw = player.CameraView.EntityHandle.Raw; pawn!.CameraServices!.ViewEntity.Raw = player.CameraView.EntityHandle.Raw;
SkillUtils.ApplyScreenColor(player.Player, 0, 0, 255, 20, 100, 1020); SkillUtils.ApplyScreenColor(player.Player, 0, 0, 255, 20, 100, 1020);
Timer? cameraTimer = null; ulong? playerSteamID = player.Player?.SteamID;
ulong playerSteamID = player.Player.SteamID; if (playerSteamID == null) return;
Timer? cameraTimer = null;
cameraTimer = jRandomSkills.Instance.AddTimer(2f, () => cameraTimer = jRandomSkills.Instance.AddTimer(2f, () =>
{ {
var target = Utilities.GetPlayerFromSteamId(playerSteamID); var target = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == playerSteamID);
if (target == null || !target.IsValid || !target.PawnIsAlive) if (target == null || !target.IsValid || !target.PawnIsAlive)
{ {
cameraTimer?.Kill(); cameraTimer?.Kill();

View file

@ -112,24 +112,26 @@ namespace src.player.skills
private static void SetUpPostProcessing(CCSPlayerController player, bool turnOff = false) private static void SetUpPostProcessing(CCSPlayerController player, bool turnOff = false)
{ {
if (player == null || !player.IsValid) return; if (player == null || !player.IsValid) return;
ulong playerSteamID = player.SteamID;
ulong? playerSteamID = player?.SteamID;
if (playerSteamID == null) return;
lock (setLock) lock (setLock)
{ {
if (!turnOff) if (!turnOff)
{ {
playersInDark.TryAdd(playerSteamID, 0); playersInDark.TryAdd((ulong)playerSteamID, 0);
ApplyColor(player); ApplyColor(player);
Timer? darkTimer = null; Timer? darkTimer = null;
darkTimer = Instance.AddTimer(5f, () => { darkTimer = Instance.AddTimer(5f, () => {
if (!playersInDark.ContainsKey(playerSteamID)) if (!playersInDark.ContainsKey((ulong)playerSteamID))
{ {
darkTimer?.Kill(); darkTimer?.Kill();
return; return;
} }
var target = Utilities.GetPlayerFromSteamId(playerSteamID); var target = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == playerSteamID);
if (target == null || !target.IsValid) if (target == null || !target.IsValid)
{ {
darkTimer?.Kill(); darkTimer?.Kill();
@ -137,18 +139,18 @@ namespace src.player.skills
} }
if (target.PawnIsAlive) if (target.PawnIsAlive)
ApplyColor(player); ApplyColor(target);
}, TimerFlags.STOP_ON_MAPCHANGE | TimerFlags.REPEAT); }, TimerFlags.STOP_ON_MAPCHANGE | TimerFlags.REPEAT);
} }
else else
{ {
SkillUtils.ApplyScreenColor(player, r: 0, g: 0, b: 0, a: 0, duration: 200, holdTime: 0); SkillUtils.ApplyScreenColor(player, r: 0, g: 0, b: 0, a: 0, duration: 200, holdTime: 0);
playersInDark.TryRemove(player.SteamID, out _); playersInDark.TryRemove((ulong)playerSteamID, out _);
} }
} }
} }
private static void ApplyColor(CCSPlayerController player) private static void ApplyColor(CCSPlayerController? player)
{ {
SkillUtils.ApplyScreenColor(player, SkillUtils.ApplyScreenColor(player,
r: SkillsInfo.GetValue<int>(skillName, "R"), r: SkillsInfo.GetValue<int>(skillName, "R"),

View file

@ -1,7 +1,6 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using src.utils; using src.utils;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@ -65,9 +64,20 @@ namespace src.player.skills
{ {
foreach (var (info, player) in infoList) foreach (var (info, player) in infoList)
{ {
if (player == null) continue; if (player == null || !player.IsValid) continue;
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
bool isObservingGhost = false;
if (targetHandle != nint.Zero)
{
var target = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == targetHandle);
var targetInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == target?.SteamID);
if (targetInfo?.Skill == skillName) isObservingGhost = true;
}
foreach (var _player in invisiblePlayers.Keys) foreach (var _player in invisiblePlayers.Keys)
if (player.SteamID != _player.SteamID) if (player.SteamID != _player.SteamID && !isObservingGhost)
{ {
var playerPawn = _player.PlayerPawn.Value; var playerPawn = _player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid) continue; if (playerPawn == null || !playerPawn.IsValid) continue;

View file

@ -154,12 +154,13 @@ namespace src.player.skills
KillClone(playerSkill); KillClone(playerSkill);
}); });
Timer? cloneTimer = null; ulong? playerSteamID = player?.SteamID;
ulong playerSteamID = player.SteamID; if (playerSteamID == null) return;
Timer? cloneTimer = null;
cloneTimer = jRandomSkills.Instance.AddTimer(2f, () => cloneTimer = jRandomSkills.Instance.AddTimer(2f, () =>
{ {
var target = Utilities.GetPlayerFromSteamId(playerSteamID); var target = Utilities.GetPlayers().FirstOrDefault(p => p.IsValid && p.SteamID == playerSteamID);
if (target == null || !target.IsValid || !target.PawnIsAlive) if (target == null || !target.IsValid || !target.PawnIsAlive)
{ {
cloneTimer?.Kill(); cloneTimer?.Kill();

View file

@ -0,0 +1,77 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using src.utils;
namespace src.player.skills
{
public class Illiterate : ISkill
{
private const Skills skillName = Skills.Illiterate;
private static bool isActive = false;
private static int offset = jRandomSkills.Instance.Random.Next(0, 26);
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
isActive = false;
}
public static void EnableSkill(CCSPlayerController player)
{
isActive = true;
}
public static void Enable()
{
isActive = true;
}
public static void Disable()
{
isActive = false;
}
public static bool CheckIlliterateSkill(CCSPlayerController? player)
{
if (!isActive || player == null || !player.IsValid) return false;
if (player.Team == CsTeam.Spectator) return false;
var playersWithSkill = jRandomSkills.Instance.SkillPlayer.Where(p => p.Skill == skillName).Select(p => p.SteamID);
if (!playersWithSkill.Any()) return false;
return Utilities.GetPlayers().Any(
p => p.IsValid &&
p.PawnIsAlive &&
p.Team != player.Team
&& playersWithSkill.Contains(p.SteamID));
}
public static string? GetRandomText(string? input)
{
if (string.IsNullOrEmpty(input)) return null;
if (Server.TickCount % 64 == 0)
offset = jRandomSkills.Instance.Random.Next(1, 26);
return new string([.. input.Select(c =>
{
if (char.IsDigit(c)) return '?';
if (!char.IsLetter(c)) return c;
char baseChar = char.IsUpper(c) ? 'A' : 'a';
return (char)(baseChar + (c - baseChar + offset) % 26);
})]);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1466F5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float maximumFuel = 150f, float fuelConsumption = .64f, float refuelling = .1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public float MaximumFuel { get; set; } = maximumFuel;
public float FuelConsumption { get; set; } = fuelConsumption;
public float Refuelling { get; set; } = refuelling;
}
}
}

View file

@ -107,9 +107,9 @@ namespace src.player.skills
if (Config.LoadedConfig.CS2TraceRayDebug) if (Config.LoadedConfig.CS2TraceRayDebug)
{ {
CreateLine(eyePos, endPos, Color.FromArgb(255, 255, 255, 0)); SkillUtils.CreateLine(eyePos, endPos, Color.FromArgb(255, 255, 255, 0));
CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.EndPos.X, trace.EndPos.Y, trace.EndPos.Z), Color.FromArgb(255, 255, 0, 0)); SkillUtils.CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.EndPos.X, trace.EndPos.Y, trace.EndPos.Z), Color.FromArgb(255, 255, 0, 0));
CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.Position.X, trace.Position.Y, trace.Position.Z), Color.FromArgb(255, 0, 0, 255)); SkillUtils.CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.Position.X, trace.Position.Y, trace.Position.Z), Color.FromArgb(255, 0, 0, 255));
if (trace.DidHit()) if (trace.DidHit())
{ {
@ -133,24 +133,6 @@ namespace src.player.skills
SkillUtils.TakeHealth(target.PlayerPawn.Value, heavyHit ? Instance.Random.Next(45, 55) : Instance.Random.Next(21, 34)); SkillUtils.TakeHealth(target.PlayerPawn.Value, heavyHit ? Instance.Random.Next(45, 55) : Instance.Random.Next(21, 34));
} }
private static void CreateLine(Vector start, Vector end, Color color)
{
CBeam beam = Utilities.CreateEntityByName<CBeam>("beam")!;
if (beam == null) return;
beam.Render = color;
beam.Width = 2.0f;
beam.EndWidth = 2.0f;
beam.Teleport(start);
beam.EndPos.X = end.X;
beam.EndPos.Y = end.Y;
beam.EndPos.Z = end.Z;
beam.DispatchSpawn();
beam.AcceptInput("FollowEntity", beam, null!, "");
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#c9f8ff", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float maxDistance = 4096f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#c9f8ff", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float maxDistance = 4096f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{ {
public float MaxDistance { get; set; } = maxDistance; public float MaxDistance { get; set; } = maxDistance;

View file

@ -45,9 +45,9 @@ namespace src.player.skills
if (Config.LoadedConfig.CS2TraceRayDebug) if (Config.LoadedConfig.CS2TraceRayDebug)
{ {
CreateLine(eyePos, endPos, Color.FromArgb(255, 255, 255, 0)); SkillUtils.CreateLine(eyePos, endPos, Color.FromArgb(255, 255, 255, 0));
CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.EndPos.X, trace.EndPos.Y, trace.EndPos.Z), Color.FromArgb(255, 255, 0, 0)); SkillUtils.CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.EndPos.X, trace.EndPos.Y, trace.EndPos.Z), Color.FromArgb(255, 255, 0, 0));
CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.Position.X, trace.Position.Y, trace.Position.Z), Color.FromArgb(255, 0, 0, 255)); SkillUtils.CreateLine(new Vector(trace.StartPos.X, trace.StartPos.Y, trace.StartPos.Z), new Vector(trace.Position.X, trace.Position.Y, trace.Position.Z), Color.FromArgb(255, 0, 0, 255));
if (trace.DidHit()) if (trace.DidHit())
{ {
@ -70,24 +70,6 @@ namespace src.player.skills
SkillUtils.TryGiveWeapon(player, CsItem.Zeus); SkillUtils.TryGiveWeapon(player, CsItem.Zeus);
} }
private static void CreateLine(Vector start, Vector end, Color color)
{
CBeam beam = Utilities.CreateEntityByName<CBeam>("beam")!;
if (beam == null) return;
beam.Render = color;
beam.Width = 2.0f;
beam.EndWidth = 2.0f;
beam.Teleport(start);
beam.EndPos.X = end.X;
beam.EndPos.Y = end.Y;
beam.EndPos.Z = end.Z;
beam.DispatchSpawn();
beam.AcceptInput("FollowEntity", beam, null!, "");
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#6effc7", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float maxDistance = 4096f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#6effc7", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float maxDistance = 4096f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{ {
public float MaxDistance { get; set; } = maxDistance; public float MaxDistance { get; set; } = maxDistance;

View file

@ -1,7 +1,6 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using src.utils; using src.utils;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@ -57,9 +56,20 @@ namespace src.player.skills
{ {
foreach (var (info, player) in infoList) foreach (var (info, player) in infoList)
{ {
if (player == null) continue; if (player == null || !player.IsValid) continue;
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
bool isObservingNinja = false;
if (targetHandle != nint.Zero)
{
var target = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == targetHandle);
var targetInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == target?.SteamID);
if (targetInfo?.Skill == skillName) isObservingNinja = true;
}
foreach (var _player in invisiblePlayers.Keys) foreach (var _player in invisiblePlayers.Keys)
if (player.SteamID != _player.SteamID) if (player.SteamID != _player.SteamID && !isObservingNinja)
{ {
var playerPawn = _player.PlayerPawn.Value; var playerPawn = _player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid) continue; if (playerPawn == null || !playerPawn.IsValid) continue;

View file

@ -1,9 +1,13 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using static src.jRandomSkills; using CS2TraceRay.Class;
using System.Collections.Concurrent; using CS2TraceRay.Struct;
using src.utils; using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
namespace src.player.skills namespace src.player.skills
{ {
@ -87,52 +91,139 @@ namespace src.player.skills
public static void UseSkill(CCSPlayerController player) public static void UseSkill(CCSPlayerController player)
{ {
var playerPawn = player.PlayerPawn.Value; var playerPawn = player.PlayerPawn.Value;
var duration = SkillsInfo.GetValue<float>(skillName, "duration");
if (playerPawn?.CBodyComponent == null) return; if (playerPawn?.CBodyComponent == null) return;
if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo)) if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo))
{ {
if (!player.IsValid || !player.PawnIsAlive) return; if (skillInfo.IsFlying)
{
StopFlying(player, skillInfo);
return;
}
if (skillInfo.CanUse) if (skillInfo.CanUse)
{ {
var duration = SkillsInfo.GetValue<float>(skillName, "duration");
skillInfo.CanUse = false; skillInfo.CanUse = false;
skillInfo.IsFlying = true; skillInfo.IsFlying = true;
skillInfo.Cooldown = DateTime.Now; skillInfo.Cooldown = DateTime.Now;
skillInfo.LastPosition = playerPawn.AbsOrigin == null ? null : new Vector(playerPawn.AbsOrigin.X, playerPawn.AbsOrigin.Y, playerPawn.AbsOrigin.Z); skillInfo.LastPosition = playerPawn.AbsOrigin == null ? null : new Vector(playerPawn.AbsOrigin.X, playerPawn.AbsOrigin.Y, playerPawn.AbsOrigin.Z);
SetNoclip(player, true);
skillInfo.Timer?.Kill();
playerPawn.ActualMoveType = MoveType_t.MOVETYPE_NOCLIP; skillInfo.Timer = Instance.AddTimer(duration, () =>
Instance.AddTimer(duration, () => {
if (playerPawn == null || !playerPawn.IsValid || !skillInfo.IsFlying) return;
skillInfo.IsFlying = false;
playerPawn.ActualMoveType = MoveType_t.MOVETYPE_WALK;
});
Instance.AddTimer(duration + 4, () => {
if (playerPawn == null || !playerPawn.IsValid || !player.PawnIsAlive || skillInfo.IsFlying) return;
if (skillInfo.LastPosition == null || playerPawn.AbsOrigin == null) return;
skillInfo.IsFlying = false;
var diff = Math.Abs(playerPawn.AbsOrigin.Z - skillInfo.LastPosition.Z);
if (diff > 3000 && playerPawn.AbsOrigin.Z < skillInfo.LastPosition.Z)
playerPawn.Teleport(skillInfo.LastPosition, null, new Vector(0,0,0));
});
}
else if (skillInfo.IsFlying)
{ {
skillInfo.IsFlying = false; StopFlying(player, skillInfo);
playerPawn.ActualMoveType = MoveType_t.MOVETYPE_WALK;
Instance.AddTimer(4, () => {
if (playerPawn == null || !playerPawn.IsValid || !player.PawnIsAlive || skillInfo.IsFlying) return;
if (skillInfo.LastPosition == null || playerPawn.AbsOrigin == null) return;
skillInfo.IsFlying = false;
var diff = Math.Abs(playerPawn.AbsOrigin.Z - skillInfo.LastPosition.Z);
if (diff > 3000 && playerPawn.AbsOrigin.Z < skillInfo.LastPosition.Z)
playerPawn.Teleport(skillInfo.LastPosition, null, new Vector(0, 0, 0));
}); });
} }
} }
} }
private static void SetNoclip(CCSPlayerController player, bool noclip = true)
{
if (player == null || !player.IsValid) return;
var playerPawn = player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid || !player.PawnIsAlive) return;
playerPawn.MoveType = noclip ? MoveType_t.MOVETYPE_NOCLIP : MoveType_t.MOVETYPE_WALK;
Schema.SetSchemaValue(playerPawn.Handle, "CBaseEntity", "m_nActualMoveType", (int)playerPawn.MoveType);
Utilities.SetStateChanged(playerPawn, "CBaseEntity", "m_MoveType");
}
private static void StopFlying(CCSPlayerController player, PlayerSkillInfo skillInfo)
{
skillInfo.Timer?.Kill();
skillInfo.Timer = null;
if (!skillInfo.IsFlying) return;
skillInfo.IsFlying = false;
if (player == null || !player.IsValid || !player.PawnIsAlive) return;
SetNoclip(player, false);
var playerPawn = player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid || skillInfo.IsFlying) return;
Vector? safePoint = GetCorrectPosition(player, skillInfo);
playerPawn.Teleport(safePoint ?? skillInfo.LastPosition, null, new Vector(0, 0, 0));
}
private static Vector? GetCorrectPosition(CCSPlayerController player, PlayerSkillInfo skillInfo)
{
var playerPawn = player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null) return null;
Vector currentPos = playerPawn.AbsOrigin;
float offset = 50;
Vector[] checkOffsets =
{
currentPos,
currentPos + new Vector(offset, 0, 10),
currentPos + new Vector(-offset, 0, 10),
currentPos + new Vector(0, offset, 10),
currentPos + new Vector(0, -offset, 10),
currentPos + new Vector(offset, 0, 60),
currentPos + new Vector(-offset, 0, 60),
currentPos + new Vector(0, offset, 60),
currentPos + new Vector(0, -offset, 60),
};
ulong mask = playerPawn.Collision.CollisionAttribute.InteractsWith;
ulong contents = playerPawn.Collision.CollisionGroup;
bool hasGround = false;
foreach (Vector targetPos in checkOffsets)
{
Vector start = new(targetPos.X, targetPos.Y, targetPos.Z + 70);
Vector end = new(targetPos.X, targetPos.Y, targetPos.Z - 1000);
CGameTrace groundTrace = TraceRay.TraceShape(start, end, mask, contents, player);
if (!groundTrace.DidHit()) continue;
hasGround = true;
Vector newPos =
groundTrace.EndPos.Z > targetPos.Z
? new(groundTrace.EndPos.X, groundTrace.EndPos.Y, groundTrace.EndPos.Z)
: targetPos;
if (IsPositionSafe(newPos, player))
return newPos;
}
if (hasGround)
skillInfo.Cooldown = DateTime.Now.AddSeconds(-SkillsInfo.GetValue<float>(skillName, "cooldown") + SkillsInfo.GetValue<float>(skillName, "cooldownWhenStuck"));
return hasGround ? currentPos : null;
}
private static bool IsPositionSafe(Vector pos, CCSPlayerController player)
{
var playerPawn = player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null) return false;
float footHeight = 0;
float headHeight = 70;
float innerDist = 12;
ulong mask = playerPawn.Collision.CollisionAttribute.InteractsWith;
ulong contents = playerPawn.Collision.CollisionGroup;
Vector s1 = new(pos.X - innerDist, pos.Y - innerDist, pos.Z + footHeight);
Vector e1 = new(pos.X + innerDist, pos.Y + innerDist, pos.Z + headHeight);
CGameTrace t1 = TraceRay.TraceShape(s1, e1, mask, contents, player);
if (t1.DidHit() || t1.AllSolid) return false;
Vector s2 = new(pos.X + innerDist, pos.Y - innerDist, pos.Z + footHeight);
Vector e2 = new(pos.X - innerDist, pos.Y + innerDist, pos.Z + headHeight);
CGameTrace t2 = TraceRay.TraceShape(s2, e2, mask, contents, player);
if (t2.DidHit() || t2.AllSolid) return false;
return true;
}
public class PlayerSkillInfo public class PlayerSkillInfo
{ {
public ulong SteamID { get; set; } public ulong SteamID { get; set; }
@ -140,11 +231,13 @@ namespace src.player.skills
public bool IsFlying { get; set; } public bool IsFlying { get; set; }
public DateTime Cooldown { get; set; } public DateTime Cooldown { get; set; }
public Vector? LastPosition { get; set; } public Vector? LastPosition { get; set; }
public Timer? Timer { get; set; }
} }
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#44ebd4", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float cooldown = 30f, float duration = 2f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#44ebd4", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float cooldown = 30f, float duration = 2f, float cooldownWhenStuck = 5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{ {
public float Cooldown { get; set; } = cooldown; public float Cooldown { get; set; } = cooldown;
public float CooldownWhenStuck { get; set; } = cooldownWhenStuck;
public float Duration { get; set; } = duration; public float Duration { get; set; } = duration;
} }
} }

View file

@ -9,7 +9,6 @@ namespace src.player.skills
public class PawelJumper : ISkill public class PawelJumper : ISkill
{ {
private const 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 int?[] J = new int?[64];
private static readonly PlayerButtons[] LB = new PlayerButtons[64]; private static readonly PlayerButtons[] LB = new PlayerButtons[64];
@ -71,7 +70,6 @@ namespace src.player.skills
playerPawn.AbsVelocity.Z = 300; playerPawn.AbsVelocity.Z = 300;
} }
LF[player.Slot] = flags;
LB[player.Slot] = buttons; LB[player.Slot] = buttons;
} }

View file

@ -38,6 +38,7 @@ namespace src.player.skills
{ {
SteamID = player.SteamID, SteamID = player.SteamID,
Fuel = SkillsInfo.GetValue<float>(skillName, "maximumFuel"), Fuel = SkillsInfo.GetValue<float>(skillName, "maximumFuel"),
LastButtons = 0
}); });
} }
@ -49,17 +50,38 @@ namespace src.player.skills
private static void HandlePilot(CCSPlayerController player) private static void HandlePilot(CCSPlayerController player)
{ {
var playerPawn = player.PlayerPawn.Value;
if (playerPawn == null || !playerPawn.IsValid) return;
if (!PlayerPilotInfo.TryGetValue(player.SteamID, out var pilotInfo)) return;
var flags = (PlayerFlags)playerPawn.Flags;
var buttons = player.Buttons; var buttons = player.Buttons;
bool isJumpDown = (playerPawn.MovementServices?.Buttons?.ButtonStates[0] & (ulong)PlayerButtons.Jump) != 0 || (buttons & PlayerButtons.Jump) != 0;
bool wasJumpDown = (pilotInfo.LastButtons & PlayerButtons.Jump) != 0;
bool jumpPressed = (isJumpDown && !wasJumpDown)
|| (playerPawn.MovementServices?.QueuedButtonChangeMask & (ulong)PlayerButtons.Jump) != 0;
bool isOnGround = (flags & PlayerFlags.FL_ONGROUND) != 0;
bool inUse = jumpPressed && !isOnGround;
var maximumFuel = SkillsInfo.GetValue<float>(skillName, "maximumFuel"); var maximumFuel = SkillsInfo.GetValue<float>(skillName, "maximumFuel");
if (PlayerPilotInfo.TryGetValue(player.SteamID, out var pilotInfo)) pilotInfo.Fuel = Math.Min(
{ Math.Max(
pilotInfo.Fuel = Math.Min(Math.Max(0, pilotInfo.Fuel - (buttons.HasFlag(PlayerButtons.Use) ? SkillsInfo.GetValue<float>(skillName, "fuelConsumption") : -SkillsInfo.GetValue<float>(skillName, "refuelling"))), maximumFuel); 0,
if (buttons.HasFlag(PlayerButtons.Use)) pilotInfo.Fuel - (inUse
if (pilotInfo.Fuel > 0 && player.PlayerPawn.Value != null && player.PlayerPawn.Value.IsValid && !player.PlayerPawn.Value.IsDefusing) ? SkillsInfo.GetValue<float>(skillName, "fuelConsumption")
: -SkillsInfo.GetValue<float>(skillName, "refuelling"))),
maximumFuel);
pilotInfo.LastButtons = buttons;
if (inUse && pilotInfo.Fuel > 0)
ApplyPilotEffect(player); ApplyPilotEffect(player);
UpdateHUD(player, pilotInfo); UpdateHUD(player, pilotInfo);
} }
}
private static void UpdateHUD(CCSPlayerController player, Pilot_PlayerInfo pilotInfo) private static void UpdateHUD(CCSPlayerController player, Pilot_PlayerInfo pilotInfo)
{ {
@ -121,6 +143,7 @@ namespace src.player.skills
{ {
public ulong SteamID { get; set; } public ulong SteamID { get; set; }
public float Fuel { get; set; } public float Fuel { get; set; }
public PlayerButtons LastButtons { get; set; }
} }
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1466F5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float maximumFuel = 150f, float fuelConsumption = .64f, float refuelling = .1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1466F5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float maximumFuel = 150f, float fuelConsumption = .64f, float refuelling = .1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)

View file

@ -100,15 +100,19 @@ namespace src.player.skills
float distance = 40; float distance = 40;
Vector pos = playerPawn.AbsOrigin + SkillUtils.GetForwardVector(playerPawn.AbsRotation) * distance; Vector pos = playerPawn.AbsOrigin + SkillUtils.GetForwardVector(playerPawn.AbsRotation) * distance;
if (((PlayerFlags)playerPawn.Flags).HasFlag(PlayerFlags.FL_DUCKING))
pos.Z -= 19;
replica.Flags = playerPawn.Flags; replica.Flags = playerPawn.Flags;
replica.Flags |= (uint)Flags_t.FL_DUCKING; replica.Flags |= (uint)Flags_t.FL_DUCKING;
replica.Collision.SolidType = SolidType_t.SOLID_VPHYSICS; replica.Collision.SolidType = SolidType_t.SOLID_VPHYSICS;
replica.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags = (uint)(replica.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags & ~(1 << 2)); replica.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags = (uint)(replica.CBodyComponent!.SceneNode!.Owner!.Entity!.Flags & ~(1 << 2));
replica.SetModel(playerPawn!.CBodyComponent!.SceneNode!.GetSkeletonInstance().ModelState.ModelName); replica.SetModel(playerPawn!.CBodyComponent!.SceneNode!.GetSkeletonInstance().ModelState.ModelName);
replica.Entity!.Name = replica.Globalname = $"Replica_{Server.TickCount}_{(player.Team == CsTeam.CounterTerrorist ? "CT" : "TT")}"; replica.Entity!.Name = replica.Globalname = $"Replica_{Server.TickCount}_{(player.Team == CsTeam.CounterTerrorist ? "CT" : "TT")}";
replica.UseAnimGraph = false;
string animName = "idle_for_turns_stand_pistol";
if (((PlayerFlags)playerPawn.Flags).HasFlag(PlayerFlags.FL_DUCKING))
animName = "idle_for_turns_crouch_pistol";
replica.AcceptInput("SetAnimation", value: animName);
replica.Teleport(pos, playerPawn.AbsRotation, null); replica.Teleport(pos, playerPawn.AbsRotation, null);
replica.DispatchSpawn(); replica.DispatchSpawn();
} }

View file

@ -0,0 +1,75 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Utils;
using Microsoft.Extensions.Logging;
using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
namespace src.player.skills
{
public class Smoker : ISkill
{
private const Skills skillName = Skills.Smoker;
private readonly static ConcurrentDictionary<uint, int> smokes = [];
private static readonly object setLock = new();
public static void LoadSkill()
{
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
}
public static void NewRound()
{
lock (setLock)
smokes.Clear();
}
public static void EnableSkill(CCSPlayerController player)
{
SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade);
}
public static void SmokegrenadeDetonate(EventSmokegrenadeDetonate @event)
{
Server.PrintToChatAll("BOOM");
var player = @event.Userid;
if (player == null || !player.IsValid) return;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
var smoke = Utilities.GetEntityFromIndex<CSmokeGrenadeProjectile>(@event.Entityid);
if (smoke == null || !smoke.IsValid) return;
smokes.TryAdd(smoke.Index, Server.TickCount);
// smoke.SmokeEffectTickBegin = Server.TickCount - ((19 - 15) * 64);
smoke.NextThinkTick = 0;
// Utilities.SetStateChanged(smoke, "CSmokeGrenadeProjectile", "m_nSmokeEffectTickBegin");
Utilities.SetStateChanged(smoke, "CBaseEntity", "m_nNextThinkTick");
}
public static void SmokegrenadeExpired(EventSmokegrenadeExpired @event)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return;
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo?.Skill != skillName) return;
Vector pos = new(@event.X, @event.Y, @event.Z);
SkillUtils.CreateSmokeGrenadeProjectile(pos, new QAngle(0, 0, 0), new Vector(0, 0, 0), player.TeamNum);
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#b5ab8f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
}
}
}

View file

@ -1,18 +1,22 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.UserMessages;
using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Utils;
using static src.jRandomSkills;
using System.Collections.Concurrent;
using src.utils; using src.utils;
using System.Collections.Concurrent;
using static src.jRandomSkills;
namespace src.player.skills namespace src.player.skills
{ {
public class SoundMaker : ISkill public class SoundMaker : ISkill
{ {
private const Skills skillName = Skills.SoundMaker; private const Skills skillName = Skills.SoundMaker;
private static readonly ConcurrentDictionary<ulong, PlayerSkillInfo> SkillPlayerInfo = []; private static readonly ConcurrentDictionary<ulong, byte> SkillPlayerInfo = [];
private static readonly object setLock = new(); private static readonly object setLock = new();
private const string soundEventName = "Hostage.Pain";
private const uint soundEventHash = 1876781570;
public static void LoadSkill() public static void LoadSkill()
{ {
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color")); SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
@ -26,12 +30,7 @@ namespace src.player.skills
public static void EnableSkill(CCSPlayerController player) public static void EnableSkill(CCSPlayerController player)
{ {
SkillPlayerInfo.TryAdd(player.SteamID, new PlayerSkillInfo SkillPlayerInfo.TryAdd(player.SteamID, 0);
{
SteamID = player.SteamID,
CanUse = true,
Cooldown = DateTime.MinValue,
});
} }
public static void DisableSkill(CCSPlayerController player) public static void DisableSkill(CCSPlayerController player)
@ -49,78 +48,40 @@ namespace src.player.skills
SkillPlayerInfo.TryRemove(player.SteamID, out _); SkillPlayerInfo.TryRemove(player.SteamID, out _);
} }
public static void PlayerMakeSound(UserMessage um)
{
var soundevent = um.ReadUInt("soundevent_hash");
if (soundevent != soundEventHash) return;
var userIndex = um.ReadUInt("source_entity_index");
if (userIndex == 0) return;
var sourcePlayer = Utilities.GetPlayers().FirstOrDefault(p => p.Pawn?.Value != null && p.Pawn.Value.IsValid && p.Pawn.Value.Index == userIndex);
if (sourcePlayer == null || !sourcePlayer.IsValid) return;
var toRemove = um.Recipients.Where(r =>
{
if (r.Team == sourcePlayer.Team) return true;
if (SkillPlayerInfo.ContainsKey(r.SteamID)) return false;
return true;
}).ToList();
foreach (var player in toRemove)
um.Recipients.Remove(player);
}
public static void OnTick() public static void OnTick()
{ {
foreach (var player in Utilities.GetPlayers()) if (Server.TickCount % (60 * SkillsInfo.GetValue<int>(skillName, "cooldown")) != 0) return;
{
var playerInfo = Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); foreach (var player in Utilities.GetPlayers()
if (playerInfo?.Skill == skillName) .Where(p => p != null && p.IsValid && p.PawnIsAlive && p.PlayerPawn.Value != null && p.PlayerPawn.Value.IsValid))
if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo)) player.PlayerPawn.Value!.EmitSound(soundEventName, volume: 1f);
UpdateHUD(player, skillInfo);
}
} }
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#e3ed8c", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int cooldown = 2) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{ {
float cooldown = 0; public int Cooldown { get; set; } = cooldown;
if (skillInfo != null)
{
float time = (int)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "Cooldown")) - DateTime.Now).TotalSeconds);
cooldown = Math.Max(time, 0);
if (cooldown == 0 && skillInfo?.CanUse == false)
skillInfo.CanUse = true;
}
var playerInfo = Instance.SkillPlayer.FirstOrDefault(s => s.SteamID == player?.SteamID);
if (playerInfo == null) return;
if (cooldown == 0)
playerInfo.PrintHTML = null;
else
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
}
public static void UseSkill(CCSPlayerController player)
{
var playerPawn = player.PlayerPawn.Value;
if (playerPawn?.CBodyComponent == null) return;
if (SkillPlayerInfo.TryGetValue(player.SteamID, out var skillInfo))
{
if (!player.IsValid || !player.PawnIsAlive) return;
if (skillInfo.CanUse)
{
skillInfo.CanUse = false;
skillInfo.Cooldown = DateTime.Now;
MakeSound(player);
}
}
}
private static void MakeSound(CCSPlayerController player)
{
foreach (var enemy in Utilities.GetPlayers().Where(p => p.Team != player.Team))
if (enemy != null && enemy.IsValid && enemy.PawnIsAlive && enemy.PlayerPawn.Value != null && enemy.PlayerPawn.Value.IsValid)
enemy.PlayerPawn.Value.EmitSound(
enemy.Team == CsTeam.CounterTerrorist
? SkillsInfo.GetValue<string>(skillName, "CTSoundEvent")
: SkillsInfo.GetValue<string>(skillName, "TSoundEvent")
, volume: 1f);
}
public class PlayerSkillInfo
{
public ulong SteamID { get; set; }
public bool CanUse { get; set; }
public DateTime Cooldown { get; set; }
}
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#e3ed8c", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float cooldown = 5f, string ctSoundEvent = "c4.disarmstart", string tSoundEvent = "C4.PlantSoundB") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{
public float Cooldown { get; set; } = cooldown;
public string CTSoundEvent { get; set; } = ctSoundEvent;
public string TSoundEvent { get; set; } = tSoundEvent;
} }
} }
} }

View file

@ -95,10 +95,6 @@ namespace src.player.skills
var trigger = SkillUtils.CreateTrigger(triggerName, SkillsInfo.GetValue<float>(skillName, "smokeRadius"), new Vector(@event.X, @event.Y, @event.Z)); var trigger = SkillUtils.CreateTrigger(triggerName, SkillsInfo.GetValue<float>(skillName, "smokeRadius"), new Vector(@event.X, @event.Y, @event.Z));
if (trigger == null) return; if (trigger == null) return;
triggers.TryAdd(trigger, 0); triggers.TryAdd(trigger, 0);
new VirtualFunctionVoid<CBaseEntity>(trigger.Handle, 153);
} }
public static void SmokegrenadeExpired(EventSmokegrenadeExpired @event) public static void SmokegrenadeExpired(EventSmokegrenadeExpired @event)
@ -138,7 +134,7 @@ namespace src.player.skills
} }
} }
public class SkillConfig(Skills skill = skillName, bool active = false, string color = "#507529", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int smokeDamage = 2, float smokeRadius = 180) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#507529", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int smokeDamage = 2, float smokeRadius = 180) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{ {
public int SmokeDamage { get; set; } = smokeDamage; public int SmokeDamage { get; set; } = smokeDamage;
public float SmokeRadius { get; set; } = smokeRadius; public float SmokeRadius { get; set; } = smokeRadius;

View file

@ -13,7 +13,7 @@ namespace src.player.skills
{ {
private const Skills skillName = Skills.Wallhack; private const Skills skillName = Skills.Wallhack;
private static readonly ConcurrentDictionary<ulong, byte> playersInAction = []; private static readonly ConcurrentDictionary<ulong, byte> playersInAction = [];
private static readonly ConcurrentBag<(CDynamicProp, CDynamicProp, CsTeam)> glows = []; private static readonly ConcurrentBag<(CDynamicProp, CDynamicProp, CsTeam, uint)> glows = [];
public static void LoadSkill() public static void LoadSkill()
{ {
@ -32,6 +32,9 @@ namespace src.player.skills
foreach (var glow in glows) foreach (var glow in glows)
{ {
var enemy = Utilities.GetPlayers().FirstOrDefault(e => e.IsValid && e.Index == glow.Item4);
if (enemy != null && enemy.PawnIsAlive)
if (glow.Item3 != player.Team && (playerInfo?.Skill == skillName || (observerInfo != null && observerInfo?.Skill == skillName))) if (glow.Item3 != player.Team && (playerInfo?.Skill == skillName || (observerInfo != null && observerInfo?.Skill == skillName)))
continue; continue;
@ -110,7 +113,7 @@ namespace src.player.skills
modelRelay.AcceptInput("FollowEntity", enemyPawn, modelRelay, "!activator"); modelRelay.AcceptInput("FollowEntity", enemyPawn, modelRelay, "!activator");
modelGlow.AcceptInput("FollowEntity", modelRelay, modelGlow, "!activator"); modelGlow.AcceptInput("FollowEntity", modelRelay, modelGlow, "!activator");
glows.Add((modelRelay, modelGlow, enemy.Team)); glows.Add((modelRelay, modelGlow, enemy.Team, enemy.Index));
} }
} }

View file

@ -1,5 +1,7 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using static src.jRandomSkills; using static src.jRandomSkills;
namespace src.utils namespace src.utils
@ -69,6 +71,9 @@ namespace src.utils
public class SettingsModel public class SettingsModel
{ {
[DisplayName("Game Mode")]
[Description("TESTfafw..")]
[Range(0, 5)]
public int GameMode { get; set; } public int GameMode { get; set; }
public bool YourSkillChatInfo { get; set; } public bool YourSkillChatInfo { get; set; }
public bool KillerSkillChatInfo { get; set; } public bool KillerSkillChatInfo { get; set; }
@ -120,6 +125,8 @@ namespace src.utils
new LanguageInfo("PT-BR, PT, BR, AO, CV, GW, MZ, ST, TL", "pt-br"), new LanguageInfo("PT-BR, PT, BR, AO, CV, GW, MZ, ST, TL", "pt-br"),
new LanguageInfo("FR, MC, HT", "fr"), new LanguageInfo("FR, MC, HT", "fr"),
new LanguageInfo("DE, AT, CH, LI, LU, BE", "de"), new LanguageInfo("DE, AT, CH, LI, LU, BE", "de"),
new LanguageInfo("TR", "tr"),
new LanguageInfo("CZ", "cs"),
new LanguageInfo("PL", "pl"), new LanguageInfo("PL", "pl"),
new LanguageInfo("EN, GB, US", "en") new LanguageInfo("EN, GB, US", "en")
] ]

View file

@ -6,6 +6,7 @@ using Newtonsoft.Json;
using System.Net; using System.Net;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using src.player; using src.player;
using src.player.skills;
namespace src.utils namespace src.utils
{ {
@ -80,7 +81,7 @@ namespace src.utils
} }
var value = Math.Round((double)(chance ?? 1), 2); var value = Math.Round((double)(chance ?? 1), 2);
var skillNameText = GetTranslation(skill.ToString().ToLower(), langCode, value); var skillNameText = GetTranslation(skill.ToString().ToLower(), langCode, player, value);
if (skillNameText.Contains('%')) skillNameText = skillNameText.Replace(value.ToString(), Math.Round(value * 100, 0).ToString()); if (skillNameText.Contains('%')) skillNameText = skillNameText.Replace(value.ToString(), Math.Round(value * 100, 0).ToString());
return skillNameText; return skillNameText;
} }
@ -104,7 +105,7 @@ namespace src.utils
var skillName = $"{skill.ToString().ToLower()}_desc2"; var skillName = $"{skill.ToString().ToLower()}_desc2";
var value = Math.Round((double)(chance ?? 1), 2); var value = Math.Round((double)(chance ?? 1), 2);
var desc2 = GetTranslation(skillName, langCode, value); var desc2 = GetTranslation(skillName, langCode, player, value);
var skilLDescription = desc2 == skillName var skilLDescription = desc2 == skillName
? player.GetTranslation($"{skill.ToString().ToLower()}_desc") ? player.GetTranslation($"{skill.ToString().ToLower()}_desc")
@ -127,7 +128,7 @@ namespace src.utils
for (int i = 0; i < key.Length; i++) for (int i = 0; i < key.Length; i++)
{ {
object[] currentArgs = args != null && i < args.Length ? args[i] : []; object[] currentArgs = args != null && i < args.Length ? args[i] : [];
string translation = GetTranslation(key[i], langCode, currentArgs); string translation = GetTranslation(key[i], langCode, null, currentArgs);
translations.Add(translation); translations.Add(translation);
} }
player.PrintToChat(string.Format(message, [.. translations])); player.PrintToChat(string.Format(message, [.. translations]));
@ -137,10 +138,10 @@ namespace src.utils
public static string GetTranslation(this CCSPlayerController player, string key, params object[] args) public static string GetTranslation(this CCSPlayerController player, string key, params object[] args)
{ {
string langCode = GetLangCode(player); string langCode = GetLangCode(player);
return GetTranslation(key, langCode, args); return GetTranslation(key, langCode, player, args);
} }
public static string GetTranslation(string key, string? langCode = null, params object[] args) public static string GetTranslation(string key, string? langCode = null, CCSPlayerController? player = null, params object[] args)
{ {
langCode ??= defaultLangCode; langCode ??= defaultLangCode;
if (_translations.TryGetValue(langCode, out var langDict) && langDict.TryGetValue(key, out var translation)) if (_translations.TryGetValue(langCode, out var langDict) && langDict.TryGetValue(key, out var translation))
@ -152,9 +153,14 @@ namespace src.utils
output = output.Replace("CHATCOLORS.RED", ChatColors.Red.ToString()); output = output.Replace("CHATCOLORS.RED", ChatColors.Red.ToString());
if (Config.LoadedConfig.AlternativeSkillButton != null) if (Config.LoadedConfig.AlternativeSkillButton != null)
output = output.Replace("css_useSkill", $"css_useSkill/{Config.LoadedConfig.AlternativeSkillButton}"); output = output.Replace("css_useSkill", $"css_useSkill/{Config.LoadedConfig.AlternativeSkillButton}");
if (Illiterate.CheckIlliterateSkill(player))
return Illiterate.GetRandomText(output);
return output; return output;
} }
if (langCode != defaultLangCode)
return GetTranslation(key, null, player, args);
return key; return key;
} }
@ -188,7 +194,10 @@ namespace src.utils
if (string.IsNullOrEmpty(playerIP)) return null; if (string.IsNullOrEmpty(playerIP)) return null;
if (!File.Exists(geoliteFilePath)) return null; if (!File.Exists(geoliteFilePath)) return null;
using var reader = new Reader(geoliteFilePath); using var reader = new Reader(geoliteFilePath);
var ip = IPAddress.Parse(playerIP);
if (!IPAddress.TryParse(playerIP, out var ip))
return null;
var data = reader.Find<ConcurrentDictionary<string, object>>(ip); var data = reader.Find<ConcurrentDictionary<string, object>>(ip);
if (data == null || data.IsEmpty) return null; if (data == null || data.IsEmpty) return null;

View file

@ -9,6 +9,7 @@ using CounterStrikeSharp.API.Modules.Utils;
using src.player; using src.player;
using src.player.skills; using src.player.skills;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Drawing;
using System.Globalization; using System.Globalization;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using WASDMenuAPI.Classes; using WASDMenuAPI.Classes;
@ -19,15 +20,21 @@ namespace src.utils
public static class SkillUtils public static class SkillUtils
{ {
private static readonly MemoryFunctionWithReturn<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, int> HEGrenadeProjectile_CreateFunc = new(GameData.GetSignature("HEGrenadeProjectile_CreateFunc")); private static readonly MemoryFunctionWithReturn<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, int> HEGrenadeProjectile_CreateFunc = new(GameData.GetSignature("HEGrenadeProjectile_CreateFunc"));
private static readonly MemoryFunctionWithReturn<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, int> SmokeGrenadeProjectile_CreateFunc = new(GameData.GetSignature("SmokeGrenadeProjectile_CreateFunc"));
private static readonly MemoryFunctionVoid<nint, float, RoundEndReason, nint, nint> TerminateRoundFunc = new(GameData.GetSignature("CCSGameRules_TerminateRound")); private static readonly MemoryFunctionVoid<nint, float, RoundEndReason, nint, nint> TerminateRoundFunc = new(GameData.GetSignature("CCSGameRules_TerminateRound"));
public static void PrintToChat(CCSPlayerController player, string msg, string border = "tb", string? title = null) public static void PrintToChat(CCSPlayerController player, string msg, string border = "tb", string? title = null)
{ {
if (!player.IsValid) return;
var config = Config.LoadedConfig.ChatMessage; var config = Config.LoadedConfig.ChatMessage;
float maxWidth = config.MaxWidth; float maxWidth = config.MaxWidth;
char symbol = config.LineSymbol; char symbol = config.LineSymbol;
if (string.IsNullOrEmpty(title)) title = player.GetTranslation("jRandomSkills"); if (string.IsNullOrEmpty(title)) title = player.GetTranslation("jRandomSkills");
if (Illiterate.CheckIlliterateSkill(player))
msg = Illiterate.GetRandomText(msg);
if (border.Contains('t') && config.LineShow) if (border.Contains('t') && config.LineShow)
player.PrintToChat($" {MeansureString.GetTextDashed($"{(config.TagFormat.Contains("{TAG}") ? config.TagFormat.Replace("{TAG}", title) : $"\u0002◢◆◤ {title} ◥◆◣")}", maxWidth, symbol, config.LineColor)}"); player.PrintToChat($" {MeansureString.GetTextDashed($"{(config.TagFormat.Contains("{TAG}") ? config.TagFormat.Replace("{TAG}", title) : $"\u0002◢◆◤ {title} ◥◆◣")}", maxWidth, symbol, config.LineColor)}");
if (!string.IsNullOrEmpty(msg) && config.InfoMessageShow) if (!string.IsNullOrEmpty(msg) && config.InfoMessageShow)
@ -86,9 +93,29 @@ namespace src.utils
return new Vector(x, y, z); return new Vector(x, y, z);
} }
public static CBeam? CreateLine(Vector start, Vector end, Color color)
public static void ApplyScreenColor(CCSPlayerController player, int r, int g, int b, int a, int duration, int holdTime, int flags = 1)
{ {
CBeam beam = Utilities.CreateEntityByName<CBeam>("beam")!;
if (beam == null) return null;
beam.Render = color;
beam.Width = 2.0f;
beam.EndWidth = 2.0f;
beam.Teleport(start);
beam.EndPos.X = end.X;
beam.EndPos.Y = end.Y;
beam.EndPos.Z = end.Z;
beam.DispatchSpawn();
return beam;
}
public static void ApplyScreenColor(CCSPlayerController? player, int r, int g, int b, int a, int duration, int holdTime, int flags = 1)
{
if (player == null || !player.IsValid) return;
using var msg = UserMessage.FromPartialName("Fade"); using var msg = UserMessage.FromPartialName("Fade");
if (msg == null) return; if (msg == null) return;
int packageColor = (a << 24) | (b << 16) | (g << 8) | r; int packageColor = (a << 24) | (b << 16) | (g << 8) | r;
@ -142,6 +169,11 @@ namespace src.utils
HEGrenadeProjectile_CreateFunc.Invoke(pos.Handle, angle.Handle, vel.Handle, vel.Handle, IntPtr.Zero, 44, teamNum); HEGrenadeProjectile_CreateFunc.Invoke(pos.Handle, angle.Handle, vel.Handle, vel.Handle, IntPtr.Zero, 44, teamNum);
} }
public static void CreateSmokeGrenadeProjectile(Vector pos, QAngle angle, Vector vel, int teamNum)
{
SmokeGrenadeProjectile_CreateFunc.Invoke(pos.Handle, angle.Handle, vel.Handle, vel.Handle, IntPtr.Zero, 45, teamNum);
}
public static void TakeHealth(CCSPlayerPawn? pawn, int damage) public static void TakeHealth(CCSPlayerPawn? pawn, int damage)
{ {
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
@ -280,9 +312,11 @@ namespace src.utils
var playerInfo = jRandomSkills.Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID); var playerInfo = jRandomSkills.Instance.SkillPlayer.FirstOrDefault(p => p.SteamID == player.SteamID);
if (playerInfo == null) return; if (playerInfo == null) return;
bool isIlliterate = Illiterate.CheckIlliterateSkill(player);
Dictionary<string, Action<CCSPlayerController, IWasdMenuOption>> list = []; Dictionary<string, Action<CCSPlayerController, IWasdMenuOption>> list = [];
foreach (var item in items) foreach (var item in items)
list.TryAdd(item.Item1, (p, option) => list.TryAdd(isIlliterate ? Illiterate.GetRandomText(item.Item1) : item.Item1, (p, option) =>
{ {
jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { item.Item2 }]); jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { item.Item2 }]);
manager.CloseMenu(p); manager.CloseMenu(p);
@ -329,15 +363,17 @@ namespace src.utils
string itemText = $"<font class='fontSize-{config.WSADMenuItemLineSize}' color='{config.WSADMenuItemLineColor}'>{{0}}</font><br>"; string itemText = $"<font class='fontSize-{config.WSADMenuItemLineSize}' color='{config.WSADMenuItemLineColor}'>{{0}}</font><br>";
string itemHoverText = $"<font class='fontSize-{config.WSADMenuItemLineSize}'><font color='purple'>[ </font><font color='{config.WSADMenuItemHoverLineColor}'>{{0}}</font><font color='purple'> ]</font></font><br>"; string itemHoverText = $"<font class='fontSize-{config.WSADMenuItemLineSize}'><font color='purple'>[ </font><font color='{config.WSADMenuItemHoverLineColor}'>{{0}}</font><font color='purple'> ]</font></font><br>";
bool isIlliterate = Illiterate.CheckIlliterateSkill(player);
IWasdMenu menu = manager.CreateMenu(hudContent, itemText, itemHoverText, controllsLine); IWasdMenu menu = manager.CreateMenu(hudContent, itemText, itemHoverText, controllsLine);
foreach (var enemy in enemies) foreach (var enemy in enemies)
menu.Add(enemy.Item1, (p, option) => menu.Add(isIlliterate ? Illiterate.GetRandomText(enemy.Item1) : enemy.Item1, (p, option) =>
{ {
jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { enemy.Item2 }]); jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { enemy.Item2 }]);
manager.CloseMenu(p); manager.CloseMenu(p);
}); });
if (lastElement != null) if (lastElement != null)
menu.Add(lastElement.Value.Item1, (p, option) => menu.Add(isIlliterate ? Illiterate.GetRandomText(lastElement.Value.Item1) : lastElement.Value.Item1, (p, option) =>
{ {
jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { lastElement.Value.Item2 }]); jRandomSkills.Instance.SkillAction(playerInfo.Skill.ToString(), "TypeSkill", [p, new[] { lastElement.Value.Item2 }]);
if (lastElement.Value.Item3) if (lastElement.Value.Item3)