Rework pilot, fix spawnspoints location

# Updates & Fixes (v1.2.1.b4)
- Pilot (Rework): Completely rewritten jump and fuel logic. You must now double-click space to activate flying. Re-activating in mid-air is now smoother and fuel consumption is properly clamped.
- Hermit: Increased default `HealthToAdd` to 100 and adjusted reserve ammo values.
- Planter / ShortBomb: Notifications now reach all valid players regardless of life status.
- ChillOut: Removed redundant empty center-print messages.
- System & Optimization:
    - Skill Detection: Faster lookups for enabled skills using the core skill list.
    - Round Logic: More stable round termination using direct game rules calls.
    - SkillUtils: Fixed spawn point selection bugs and memory referencing issues.
This commit is contained in:
Juzlus 2026-04-06 20:59:03 +02:00
parent 17f26a1458
commit 3954fc3af4
13 changed files with 74 additions and 46 deletions

View file

@ -28,7 +28,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.2.1.b3"; public override string ModuleVersion => "1.2.1.b4";
public override void Load(bool hotReload) public override void Load(bool hotReload)
{ {
@ -197,7 +197,7 @@ namespace src
Console.ForegroundColor = (ConsoleColor)CS2ConsoleColors.Cyan; Console.ForegroundColor = (ConsoleColor)CS2ConsoleColors.Cyan;
Console.Write(", SkillButton: "); Console.Write(", SkillButton: ");
Console.ForegroundColor = (ConsoleColor)CS2ConsoleColors.LightBlue; Console.ForegroundColor = (ConsoleColor)CS2ConsoleColors.LightBlue;
Console.Write(Config.LoadedConfig.AlternativeSkillButton); Console.Write(Config.LoadedConfig.AlternativeSkillButton ?? "(NULL)");
Console.ForegroundColor = (ConsoleColor)CS2ConsoleColors.Cyan; Console.ForegroundColor = (ConsoleColor)CS2ConsoleColors.Cyan;
Console.Write(", HtmlHudFix: "); Console.Write(", HtmlHudFix: ");
@ -239,7 +239,7 @@ namespace src
foreach (Skills skill in Enum.GetValues(typeof(Skills))) foreach (Skills skill in Enum.GetValues(typeof(Skills)))
if (skill.ToString() == "None") if (skill.ToString() == "None")
continue; continue;
else if (SkillsInfo.GetValue<bool>(skill, "active")) else if (SkillData.Skills.Any(s => s.Skill == skill))
enabled.Add(skill); enabled.Add(skill);
else else
disabled.Add(skill); disabled.Add(skill);

View file

@ -523,5 +523,7 @@
"wildthrow_select_info": "Select a player:", "wildthrow_select_info": "Select a player:",
"throwingknife": "Throwing Knife", "throwingknife": "Throwing Knife",
"throwingknife_desc": "Click [css_useSkill] to throw a knife. But watch out for others" "throwingknife_desc": "Click [css_useSkill] to throw a knife. But watch out for others",
"planter_planting": "Planting ({0})..."
} }

View file

@ -87,7 +87,6 @@ namespace src.player.skills
{ {
float remaining = plantTime + extraTime - currentTime; float remaining = plantTime + extraTime - currentTime;
playerInfo.PrintHTML = $"{player.GetTranslation("planter_planting", $"<font color='#00FF00'>{Math.Max(0, remaining):0.0}s</font>")}"; playerInfo.PrintHTML = $"{player.GetTranslation("planter_planting", $"<font color='#00FF00'>{Math.Max(0, remaining):0.0}s</font>")}";
player.PrintToCenter("");
} }
} }
} }

View file

@ -12,15 +12,15 @@ namespace src.player.skills
private const Skills skillName = Skills.Hermit; private const Skills skillName = Skills.Hermit;
private static readonly ConcurrentDictionary<string, int> ConcurrentDictionary = new( private static readonly ConcurrentDictionary<string, int> ConcurrentDictionary = new(
[ [
new KeyValuePair<string, int>("weapon_glock", 120), new KeyValuePair<string, int>("weapon_usp_silencer", 24), new KeyValuePair<string, int>("weapon_hkp2000", 52), new KeyValuePair<string, int>("weapon_p250", 26), new KeyValuePair<string, int>("weapon_glock", 3), new KeyValuePair<string, int>("weapon_usp_silencer", 2), new KeyValuePair<string, int>("weapon_hkp2000", 4), new KeyValuePair<string, int>("weapon_p250", 3),
new KeyValuePair<string, int>("weapon_cz75", 12), new KeyValuePair<string, int>("weapon_deagle", 35), new KeyValuePair<string, int>("weapon_fiveseven", 100), new KeyValuePair<string, int>("weapon_elite", 120), new KeyValuePair<string, int>("weapon_cz75", 2), new KeyValuePair<string, int>("weapon_deagle", 3), new KeyValuePair<string, int>("weapon_fiveseven", 2), new KeyValuePair<string, int>("weapon_elite", 2),
new KeyValuePair<string, int>("weapon_tec9", 90), new KeyValuePair<string, int>("weapon_revolver", 8), new KeyValuePair<string, int>("weapon_mac10", 100), new KeyValuePair<string, int>("weapon_mp9", 120), new KeyValuePair<string, int>("weapon_tec9", 3), new KeyValuePair<string, int>("weapon_revolver", 2), new KeyValuePair<string, int>("weapon_mac10", 3), new KeyValuePair<string, int>("weapon_mp9", 2),
new KeyValuePair<string, int>("weapon_mp7", 120), new KeyValuePair<string, int>("weapon_mp5", 120), new KeyValuePair<string, int>("weapon_mp5sd", 120), new KeyValuePair<string, int>("weapon_ump45", 100), new KeyValuePair<string, int>("weapon_mp7", 3), new KeyValuePair<string, int>("weapon_mp5", 3), new KeyValuePair<string, int>("weapon_mp5sd", 3), new KeyValuePair<string, int>("weapon_ump45", 3),
new KeyValuePair<string, int>("weapon_p90", 100), new KeyValuePair<string, int>("weapon_bizon", 120), new KeyValuePair<string, int>("weapon_ak47", 90), new KeyValuePair<string, int>("weapon_m4a1", 90), new KeyValuePair<string, int>("weapon_p90", 2), new KeyValuePair<string, int>("weapon_bizon", 2), new KeyValuePair<string, int>("weapon_ak47", 3), new KeyValuePair<string, int>("weapon_m4a1", 4),
new KeyValuePair<string, int>("weapon_m4a1_silencer", 80), new KeyValuePair<string, int>("weapon_galilar", 90), new KeyValuePair<string, int>("weapon_famas", 90), new KeyValuePair<string, int>("weapon_aug", 90), new KeyValuePair<string, int>("weapon_m4a1_silencer", 3), new KeyValuePair<string, int>("weapon_galilar", 4), new KeyValuePair<string, int>("weapon_famas", 4), new KeyValuePair<string, int>("weapon_aug", 3),
new KeyValuePair<string, int>("weapon_sg556", 90), new KeyValuePair<string, int>("weapon_ssg08", 90), new KeyValuePair<string, int>("weapon_awp", 30), new KeyValuePair<string, int>("weapon_scar20", 90), new KeyValuePair<string, int>("weapon_sg556", 3), new KeyValuePair<string, int>("weapon_ssg08", 2), new KeyValuePair<string, int>("weapon_awp", 2), new KeyValuePair<string, int>("weapon_scar20", 2),
new KeyValuePair<string, int>("weapon_g3sg1", 90), new KeyValuePair<string, int>("weapon_nova", 32), new KeyValuePair<string, int>("weapon_xm1014", 32), new KeyValuePair<string, int>("weapon_sawedoff", 32), new KeyValuePair<string, int>("weapon_g3sg1", 2), new KeyValuePair<string, int>("weapon_nova", 32), new KeyValuePair<string, int>("weapon_xm1014", 32), new KeyValuePair<string, int>("weapon_sawedoff", 32),
new KeyValuePair<string, int>("weapon_mag7", 32), new KeyValuePair<string, int>("weapon_m249", 200), new KeyValuePair<string, int>("weapon_negev", 300) new KeyValuePair<string, int>("weapon_mag7", 3), new KeyValuePair<string, int>("weapon_m249", 2), new KeyValuePair<string, int>("weapon_negev", 2)
]); ]);
private static readonly ConcurrentDictionary<string, int> maxReserveAmmo = ConcurrentDictionary; private static readonly ConcurrentDictionary<string, int> maxReserveAmmo = ConcurrentDictionary;
@ -52,7 +52,7 @@ namespace src.player.skills
SkillUtils.AddHealth(pawn, SkillsInfo.GetValue<int>(skillName, "healthToAdd")); SkillUtils.AddHealth(pawn, SkillsInfo.GetValue<int>(skillName, "healthToAdd"));
} }
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ded678", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int healthToAdd = 25) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission) public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ded678", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int healthToAdd = 100) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission)
{ {
public int HealthToAdd { get; set; } = healthToAdd; public int HealthToAdd { get; set; } = healthToAdd;
} }

View file

@ -34,12 +34,7 @@ namespace src.player.skills
public static void EnableSkill(CCSPlayerController player) public static void EnableSkill(CCSPlayerController player)
{ {
PlayerPilotInfo.TryAdd(player.SteamID, new Pilot_PlayerInfo PlayerPilotInfo.TryAdd(player.SteamID, new Pilot_PlayerInfo { SteamID = player.SteamID });
{
SteamID = player.SteamID,
Fuel = SkillsInfo.GetValue<float>(skillName, "maximumFuel"),
LastButtons = 0
});
} }
public static void DisableSkill(CCSPlayerController player) public static void DisableSkill(CCSPlayerController player)
@ -57,29 +52,55 @@ namespace src.player.skills
var flags = (PlayerFlags)playerPawn.Flags; var flags = (PlayerFlags)playerPawn.Flags;
var buttons = player.Buttons; var buttons = player.Buttons;
float currentTime = Server.CurrentTime;
bool isJumpDown = (playerPawn.MovementServices?.Buttons?.ButtonStates[0] & (ulong)PlayerButtons.Jump) != 0 || (buttons & PlayerButtons.Jump) != 0; bool isJumpDown = (buttons & PlayerButtons.Jump) != 0
|| (playerPawn.MovementServices?.Buttons?.ButtonStates[0] & (ulong)PlayerButtons.Jump) != 0;
bool wasJumpDown = (pilotInfo.LastButtons & PlayerButtons.Jump) != 0; bool wasJumpDown = (pilotInfo.LastButtons & PlayerButtons.Jump) != 0;
bool jumpPressed = (isJumpDown && !wasJumpDown) bool jumpPressed = (isJumpDown && !wasJumpDown)
|| (playerPawn.MovementServices?.QueuedButtonChangeMask & (ulong)PlayerButtons.Jump) != 0; || (playerPawn.MovementServices?.QueuedButtonChangeMask & (ulong)PlayerButtons.Jump) != 0;
bool isOnGround = (flags & PlayerFlags.FL_ONGROUND) != 0; bool isOnGround = (flags & PlayerFlags.FL_ONGROUND) != 0;
bool inUse = jumpPressed && !isOnGround;
var maximumFuel = SkillsInfo.GetValue<float>(skillName, "maximumFuel"); if (jumpPressed && !isOnGround)
pilotInfo.Fuel = Math.Min( {
Math.Max( if (pilotInfo.JumpCount == 0)
pilotInfo.JumpCount++;
else
{
pilotInfo.JumpCount++;
pilotInfo.LastJumpTime = currentTime;
if (pilotInfo.JumpCount >= 2)
pilotInfo.IsFlying = true;
}
}
else if (!isJumpDown && currentTime - pilotInfo.LastJumpTime > .1f)
pilotInfo.IsFlying = false;
if (isOnGround)
{
pilotInfo.IsFlying = false;
if (isOnGround) pilotInfo.JumpCount = 0;
}
bool inUse = pilotInfo.IsFlying && pilotInfo.Fuel > 0 && !isOnGround;
float maximumFuel = SkillsInfo.GetValue<float>(skillName, "maximumFuel");
float consumption = SkillsInfo.GetValue<float>(skillName, "fuelConsumption");
float refuelling = SkillsInfo.GetValue<float>(skillName, "refuelling");
pilotInfo.Fuel = Math.Clamp(
pilotInfo.Fuel + (inUse ? -consumption : refuelling),
0, 0,
pilotInfo.Fuel - (inUse maximumFuel
? SkillsInfo.GetValue<float>(skillName, "fuelConsumption") );
: -SkillsInfo.GetValue<float>(skillName, "refuelling"))),
maximumFuel);
pilotInfo.LastButtons = buttons;
if (inUse && pilotInfo.Fuel > 0) if (inUse)
ApplyPilotEffect(player); ApplyPilotEffect(player);
else if (pilotInfo.Fuel <= 0)
pilotInfo.IsFlying = false;
pilotInfo.LastButtons = buttons;
UpdateHUD(player, pilotInfo); UpdateHUD(player, pilotInfo);
} }
@ -141,9 +162,12 @@ namespace src.player.skills
public class Pilot_PlayerInfo public class Pilot_PlayerInfo
{ {
public ulong SteamID { get; set; } public required ulong SteamID { get; set; }
public float Fuel { get; set; } public float Fuel { get; set; } = SkillsInfo.GetValue<float>(skillName, "maximumFuel");
public PlayerButtons LastButtons { get; set; } public PlayerButtons LastButtons { get; set; } = 0;
public int JumpCount { get; set; } = 0;
public float LastJumpTime { get; set; } = 0;
public bool IsFlying { get; set; } = false;
} }
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

@ -47,7 +47,7 @@ namespace src.player.skills
if (plantedBomb != null) if (plantedBomb != null)
Server.NextFrame(() => plantedBomb.C4Blow = Server.CurrentTime + SkillsInfo.GetValue<int>(skillName, "extraC4BlowTime")); Server.NextFrame(() => plantedBomb.C4Blow = Server.CurrentTime + SkillsInfo.GetValue<int>(skillName, "extraC4BlowTime"));
foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && p.PawnIsAlive)) foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid))
p.PrintToCenterAlert(p.GetTranslation("bombplanted", SkillsInfo.GetValue<int>(skillName, "extraC4BlowTime"))); p.PrintToCenterAlert(p.GetTranslation("bombplanted", SkillsInfo.GetValue<int>(skillName, "extraC4BlowTime")));
} }

View file

@ -4,6 +4,7 @@ using CounterStrikeSharp.API.Modules.Utils;
using static src.jRandomSkills; using static src.jRandomSkills;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using src.utils; using src.utils;
using CounterStrikeSharp.API.Modules.Entities.Constants;
namespace src.player.skills namespace src.player.skills
{ {

View file

@ -27,7 +27,7 @@ namespace src.player.skills
if (plantedBomb != null) if (plantedBomb != null)
Server.NextFrame(() => plantedBomb.C4Blow = Server.CurrentTime + SkillsInfo.GetValue<int>(skillName, "detonationTime")); Server.NextFrame(() => plantedBomb.C4Blow = Server.CurrentTime + SkillsInfo.GetValue<int>(skillName, "detonationTime"));
foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && p.PawnIsAlive)) foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid))
p.PrintToCenterAlert(p.GetTranslation("bombplanted", SkillsInfo.GetValue<int>(skillName, "detonationTime"))); p.PrintToCenterAlert(p.GetTranslation("bombplanted", SkillsInfo.GetValue<int>(skillName, "detonationTime")));
} }

View file

@ -1,7 +1,6 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Entities.Constants;
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;

View file

@ -162,12 +162,12 @@ namespace src.utils
? "info_player_counterterrorist" ? "info_player_counterterrorist"
: "info_player_terrorist"; : "info_player_terrorist";
var spawns = Utilities.FindAllEntitiesByDesignerName<SpawnPoint>(spawnPointName).ToList(); var spawns = Utilities.FindAllEntitiesByDesignerName<SpawnPoint>(spawnPointName).Where(s => s.IsValid && s.Enabled).ToList();
if (spawns.Count != 0) if (spawns.Count != 0)
{ {
var randomSpawn = spawns[jRandomSkills.Instance.Random.Next(spawns.Count)]; var randomSpawn = spawns[jRandomSkills.Instance.Random.Next(spawns.Count)];
if (randomSpawn != null && randomSpawn.IsValid && randomSpawn.AbsOrigin != null) if (randomSpawn != null && randomSpawn.IsValid && randomSpawn.AbsOrigin != null)
return randomSpawn.AbsOrigin; return new Vector(randomSpawn.AbsOrigin.X, randomSpawn.AbsOrigin.Y, randomSpawn.AbsOrigin.Z);
} }
return null; return null;
} }
@ -415,7 +415,8 @@ namespace src.utils
short tScore = (short)(winnerTeam == CsTeam.Terrorist ? tTeams.Score + 1 : tTeams.Score); short tScore = (short)(winnerTeam == CsTeam.Terrorist ? tTeams.Score + 1 : tTeams.Score);
UpdateServerTeamScores(ctScore, tScore); UpdateServerTeamScores(ctScore, tScore);
TerminateRoundFunc.Invoke(jRandomSkills.Instance.GameRules.Handle, 5f, winnerTeam == CsTeam.CounterTerrorist ? RoundEndReason.BombDefused : RoundEndReason.TargetBombed, 0, 0); jRandomSkills.Instance.GameRules?.TerminateRound(5f, winnerTeam == CsTeam.CounterTerrorist ? RoundEndReason.BombDefused : RoundEndReason.TargetBombed);
// TerminateRoundFunc.Invoke(jRandomSkills.Instance.GameRules.Handle, 5f, winnerTeam == CsTeam.CounterTerrorist ? RoundEndReason.BombDefused : RoundEndReason.TargetBombed, 0, 0);
} }
private static void UpdateServerTeamScores(short ctScore, short tScore) private static void UpdateServerTeamScores(short ctScore, short tScore)

View file

@ -523,5 +523,7 @@
"wildthrow_select_info": "Select a player:", "wildthrow_select_info": "Select a player:",
"throwingknife": "Throwing Knife", "throwingknife": "Throwing Knife",
"throwingknife_desc": "Click [css_useSkill] to throw a knife. But watch out for others" "throwingknife_desc": "Click [css_useSkill] to throw a knife. But watch out for others",
"planter_planting": "Planting ({0})..."
} }