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

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

View file

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

View file

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