v1.2.3.b6
New skills (9) - Bounty: put a cash price on an enemy's head, the killer collects it. - EmpGrenade: grenade victims lose radar and crosshair for a while. - GravityDecoy: the decoy alters gravity for everyone in its radius. - Heavyweight: immune to push and slow effects from other skills. - Nemesis: the marked player takes extra damage from everyone. - Punisher: banks part of the damage you take and releases it on your next hit. - Rewind: drop a marker and teleport back to it shortly after. - TrueArmor: armor absorbs part of incoming damage instead of health. - Voodoo: the marked enemy shares the damage you take. Shared systems - DecoyRing: reusable ground ring so decoy skills show their real area of effect. Adopted by FireRain, FrozenDecoy, GravityDecoy and MagneticDecoy. - WeaponPool: single cached weapon classification (rifle/pistol/grenade) with a normalizing lookup, backed by the new config Weapons section. Replaces the duplicated hardcoded arrays in Assassin, Chicken, Ghost, NoNades, PrimaryBan, RandomWeapon, SniperElite and WeaponsSwap. [because of compatibility with WeaponRestrict] - HUD suppression registry in SkillUtils: crosshair and radar hiding is now refcounted per owner, so overlapping skills (Glitch, Jammer, EmpGrenade) cannot restore each other's state early. - SkillUtils.ResolveHiddenPawns: shared invisible-pawn resolution for C4Camouflage, Ghost and Ninja. - Config gained a Weapons section with automatic migration for existing installs, plus a per-skill DisableOnPistolRound switch honoured by both the round draw and css_setskill. Sound - Volume rebalance - Add SkillUtils.EmitSoundToPlayer with a private RecipientFilter. A null filter had been broadcasting every skill sound to all clients. Migrated 16 call sites: Poison, DemonEye, ToxicSmoke, CarefulBullets, Thorns, HotBomb, LastGasp, LongKnife, Nightmare, Jester, Tripwire, Medic, HealingSmoke, Rewind, Watchmaker. - New effects: LongKnife knife-hit feedback (Weapon_Knife.Hit.Heavy/Light), Grapple hook impact, Fortnite barricade placement, Ricochet bounce, Nightmare cursed tone, Replicator/Illusionist spawn, PsychicDefusing defuse cue, TakeAmmo pickup, Tripwire and Jammer trigger tones. - 29 skills gained a configurable SoundVolume, LongKnife also HitSoundVolume. - Grapple: emit the hook impact at the hook entity instead of at the owner so the enemy team can locate it. - PawelJumper: the engine already plays the first jump, only extra jumps emit. Models and visuals - Grapple: real hook model with configurable hookScale and hookEmbed so the hook sits in the surface it hit. - Pilot: glowing exhaust trail parented to the pawn, active only while airborne. Performance - SkillsInfo.GetValue now resolves through a ConcurrentDictionary cache instead of reflecting on every call; invalidated on config reload. - HUD render cache keyed on player, config, description flag and the three source lines; identical frames skip the rebuild. - Glaz.CheckTransmit: hoist smoke index resolution out of the per-viewer loop and build the pawn-owner map lazily. - playersSkills switched from ConcurrentBag to HashSet<Skills>, turning the NoRepeat filter from an O(n) scan into a set lookup. Fixes - NoRepeat could hand a player two or three skills in one round because the history bag was never deduplicated; the HashSet rewrite closes it. - SniperElite: restore the saved weapon after the halftime team swap instead of dropping it on the pistol round. - Illiterate: the holder alert now reaches chat and is exempt from its own scrambler via PrintToChat(ignoreIlliterate). - EntityManager.DestroyBeam: zero out width and render colour before the kill so beams cannot linger visibly, with a next-frame Remove fallback. - Ricochet: drop all 18 diagnostic Trace calls and the Trace helper; the skill measured stable over 48h and the tracing dominated the debug log. Debug - Tag round start, round end and freeze-time-end lines with [WARMUP] so warmup load is separable from live rounds.
This commit is contained in:
parent
615c55b2da
commit
b2d2c5bf9a
93 changed files with 3414 additions and 329 deletions
|
|
@ -45,13 +45,13 @@ namespace src.player
|
|||
var teams = Utilities.FindAllEntitiesByDesignerName<CCSTeam>("cs_team_manager").Where(t => t != null).ToList();
|
||||
var tTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.Terrorist);
|
||||
var ctTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.CounterTerrorist);
|
||||
WriteToDebug($"Round #{tTeam?.Score + ctTeam?.Score + 1} (CT {ctTeam?.Score} : {tTeam?.Score} TT) started.");
|
||||
WriteToDebug($"Round #{tTeam?.Score + ctTeam?.Score + 1} (CT {ctTeam?.Score} : {tTeam?.Score} TT) started.{WarmupTag()}");
|
||||
return HookResult.Continue;
|
||||
});
|
||||
|
||||
Instance.RegisterEventHandler<EventRoundFreezeEnd>((@event, info) =>
|
||||
{
|
||||
WriteToDebug($"Freeze time ended.");
|
||||
WriteToDebug($"Freeze time ended.{WarmupTag()}");
|
||||
return HookResult.Continue;
|
||||
});
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ namespace src.player
|
|||
var teams = Utilities.FindAllEntitiesByDesignerName<CCSTeam>("cs_team_manager").Where(t => t != null).ToList();
|
||||
var tTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.Terrorist);
|
||||
var ctTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.CounterTerrorist);
|
||||
WriteToDebug($"Round #{tTeam?.Score + ctTeam?.Score} (CT {ctTeam?.Score} : {tTeam?.Score} TT) ended.");
|
||||
WriteToDebug($"Round #{tTeam?.Score + ctTeam?.Score} (CT {ctTeam?.Score} : {tTeam?.Score} TT) ended.{WarmupTag()}");
|
||||
return HookResult.Continue;
|
||||
});
|
||||
|
||||
|
|
@ -137,6 +137,13 @@ namespace src.player
|
|||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private static string WarmupTag()
|
||||
{
|
||||
var gameRules = Instance?.GameRules;
|
||||
if (gameRules == null || gameRules.Handle == IntPtr.Zero) return " [gamerules unavailable]";
|
||||
return gameRules.WarmupPeriod ? " [WARMUP]" : string.Empty;
|
||||
}
|
||||
|
||||
public static void WriteToDebug(string message)
|
||||
{
|
||||
if (Config.LoadedConfig.DebugMode != true)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ public enum Skills
|
|||
BladeMaster,
|
||||
BunnyHop,
|
||||
BlastShot,
|
||||
Bounty,
|
||||
C4Camouflage,
|
||||
CarefulBullets,
|
||||
Catapult,
|
||||
|
|
@ -95,6 +96,7 @@ public enum Skills
|
|||
Dracula,
|
||||
Duplicator,
|
||||
Dwarf,
|
||||
EmpGrenade,
|
||||
EnemySpawn,
|
||||
ExpensiveAmmo,
|
||||
ExplodingBarrel,
|
||||
|
|
@ -116,9 +118,11 @@ public enum Skills
|
|||
Glue,
|
||||
GodMode,
|
||||
Grapple,
|
||||
GravityDecoy,
|
||||
Grenadier,
|
||||
HealingChicken,
|
||||
HealingSmoke,
|
||||
Heavyweight,
|
||||
Hermit,
|
||||
HolyHandGrenade,
|
||||
HomingNades,
|
||||
|
|
@ -148,6 +152,7 @@ public enum Skills
|
|||
Medic,
|
||||
Miner,
|
||||
MoneySwap,
|
||||
Nemesis,
|
||||
Nightmare,
|
||||
Ninja,
|
||||
NoNades,
|
||||
|
|
@ -163,6 +168,7 @@ public enum Skills
|
|||
Poison,
|
||||
PrimaryBan,
|
||||
Prosthesis,
|
||||
Punisher,
|
||||
Push,
|
||||
Pyro,
|
||||
QuickShot,
|
||||
|
|
@ -175,6 +181,7 @@ public enum Skills
|
|||
Replicator,
|
||||
Retreat,
|
||||
ReturnToSender,
|
||||
Rewind,
|
||||
RichBoy,
|
||||
Ricochet,
|
||||
RobinHood,
|
||||
|
|
@ -199,6 +206,8 @@ public enum Skills
|
|||
ThrowingKnife,
|
||||
ToxicSmoke,
|
||||
Tripwire,
|
||||
TrueArmor,
|
||||
Voodoo,
|
||||
Wallhack,
|
||||
Watchmaker,
|
||||
WeaponsSwap,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace src.player
|
|||
public static readonly SkillsInfo.DefaultSkillInfo[] counterterroristSkills = [.. SkillsInfo.LoadedConfig.Where(s => s.OnlyTeam == (int)CsTeam.CounterTerrorist)];
|
||||
private static readonly SkillsInfo.DefaultSkillInfo[] allTeamsSkills = [.. SkillsInfo.LoadedConfig.Where(s => s.OnlyTeam == 0)];
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, ConcurrentBag<jSkill_SkillInfo>> playersSkills = [];
|
||||
private static readonly ConcurrentDictionary<uint, HashSet<Skills>> playersSkills = [];
|
||||
public static readonly ConcurrentDictionary<uint, jSkill_SkillInfo> staticSkills = [];
|
||||
public static readonly ConcurrentDictionary<uint, uint> playersCustomFOV = [];
|
||||
private static readonly object setLock = new();
|
||||
|
|
@ -564,6 +564,7 @@ namespace src.player
|
|||
|
||||
PlayerManager.UnregisterPlayer(player.Index);
|
||||
EntityManager.DestroyPlayerEntities(player.Index);
|
||||
SkillUtils.ClearHudSuppression(player.Index);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
|
@ -602,6 +603,8 @@ namespace src.player
|
|||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn == null || !pawn.IsValid) return;
|
||||
|
||||
SkillUtils.ClearHudSuppression(player.Index);
|
||||
|
||||
pawn.HideHUD = (uint)(pawn.HideHUD & ~(1 << 8));
|
||||
Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_iHideHUD");
|
||||
|
||||
|
|
@ -768,6 +771,21 @@ namespace src.player
|
|||
}
|
||||
|
||||
var config = Config.LoadedConfig.HtmlHudCustomisation;
|
||||
|
||||
var cache = skillPlayer?.HudCache;
|
||||
if (cache != null
|
||||
&& cache.Content != null
|
||||
&& cache.PlayerIndex == player.Index
|
||||
&& ReferenceEquals(cache.Config, config)
|
||||
&& cache.IsDescription == isDescription
|
||||
&& string.Equals(cache.Header, headerLine, StringComparison.Ordinal)
|
||||
&& string.Equals(cache.Center, centerLine, StringComparison.Ordinal)
|
||||
&& string.Equals(cache.Extra, extraLine, StringComparison.Ordinal))
|
||||
{
|
||||
player.PrintToCenterHtml(cache.Content);
|
||||
return;
|
||||
}
|
||||
|
||||
var emptySymbol = $"<font class='fontSize-{(string.IsNullOrEmpty(headerLine) || string.IsNullOrEmpty(config.HeaderLineSize) ? "l" : "ml")}'> </font>";
|
||||
var emptySymbol2 = $"<font class='fontSize-ml'> </font>";
|
||||
|
||||
|
|
@ -782,6 +800,19 @@ namespace src.player
|
|||
: $"<br>{emptySymbol}<font class='fontSize-{(isDescription ? config.SkillDescriptionLineSize : config.InfoLineSize)}' color='{(isDescription ? config.SkillDescriptionLineColor : config.InfoLineColor)}'>{extraLine}</font>{emptySymbol}";
|
||||
|
||||
var hudContent = "<jRS/>" + infoLine + skillLine + remainingLine;
|
||||
|
||||
if (skillPlayer != null)
|
||||
{
|
||||
cache ??= skillPlayer.HudCache = new HudCacheEntry();
|
||||
cache.PlayerIndex = player.Index;
|
||||
cache.Config = config;
|
||||
cache.Header = headerLine;
|
||||
cache.Center = centerLine;
|
||||
cache.Extra = extraLine;
|
||||
cache.IsDescription = isDescription;
|
||||
cache.Content = hudContent;
|
||||
}
|
||||
|
||||
player.PrintToCenterHtml(hudContent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,6 +195,8 @@ namespace src.player
|
|||
SkillsUsedThisMap.Clear();
|
||||
nextRoundPicks.Clear();
|
||||
|
||||
SkillUtils.ClearAllHudSuppression();
|
||||
|
||||
playersCustomFOV.Clear();
|
||||
playersSkills.Clear();
|
||||
staticSkills.Clear();
|
||||
|
|
@ -275,6 +277,7 @@ namespace src.player
|
|||
public required HashSet<Skills> NeedsTeammates { get; init; }
|
||||
public required HashSet<Skills> CtOnly { get; init; }
|
||||
public required HashSet<Skills> TOnly { get; init; }
|
||||
public required HashSet<Skills> PistolRoundBanned { get; init; }
|
||||
public required int TerroristCount { get; init; }
|
||||
public required int CounterTerroristCount { get; init; }
|
||||
}
|
||||
|
|
@ -296,6 +299,9 @@ namespace src.player
|
|||
NeedsTeammates = ToSkillSet(SkillsInfo.LoadedConfig.Where(s => s.NeedsTeammates).Select(s => s.Name)),
|
||||
CtOnly = ToSkillSet(counterterroristSkills.Select(s => s.Name)),
|
||||
TOnly = ToSkillSet(terroristSkills.Select(s => s.Name)),
|
||||
PistolRoundBanned = SkillUtils.IsPistolRound()
|
||||
? ToSkillSet(SkillsInfo.LoadedConfig.Where(s => s.DisableOnPistolRound).Select(s => s.Name))
|
||||
: [],
|
||||
TerroristCount = validPlayers.Count(p => p.Team == CsTeam.Terrorist),
|
||||
CounterTerroristCount = validPlayers.Count(p => p.Team == CsTeam.CounterTerrorist),
|
||||
};
|
||||
|
|
@ -328,9 +334,12 @@ namespace src.player
|
|||
else
|
||||
skillList.RemoveAll(s => ctx.TOnly.Contains(s.Skill));
|
||||
|
||||
if (gameMode == Config.GameModes.NoRepeat && playersSkills.TryGetValue(player.Index, out ConcurrentBag<jSkill_SkillInfo>? skills))
|
||||
if (ctx.PistolRoundBanned.Count != 0)
|
||||
skillList.RemoveAll(s => ctx.PistolRoundBanned.Contains(s.Skill));
|
||||
|
||||
if (gameMode == Config.GameModes.NoRepeat && playersSkills.TryGetValue(player.Index, out HashSet<Skills>? skills))
|
||||
{
|
||||
skillList.RemoveAll(s => skills.Any(s2 => s2.Skill == s.Skill));
|
||||
skillList.RemoveAll(s => skills.Contains(s.Skill));
|
||||
if (skillList.Count == 0) skills.Clear();
|
||||
}
|
||||
|
||||
|
|
@ -338,10 +347,10 @@ namespace src.player
|
|||
|
||||
if (gameMode == Config.GameModes.NoRepeat)
|
||||
{
|
||||
if (playersSkills.TryGetValue(player.Index, out ConcurrentBag<jSkill_SkillInfo>? value))
|
||||
value.Add(randomSkill);
|
||||
if (playersSkills.TryGetValue(player.Index, out HashSet<Skills>? value))
|
||||
value.Add(randomSkill.Skill);
|
||||
else
|
||||
playersSkills.TryAdd(player.Index, [randomSkill]);
|
||||
playersSkills.TryAdd(player.Index, [randomSkill.Skill]);
|
||||
}
|
||||
|
||||
return randomSkill;
|
||||
|
|
@ -358,6 +367,7 @@ namespace src.player
|
|||
|
||||
var def = SkillsInfo.LoadedConfig.FirstOrDefault(d => d.Name == name);
|
||||
if (def == null) return false;
|
||||
if (def.DisableOnPistolRound && SkillUtils.IsPistolRound()) return false;
|
||||
if (def.NeedsTeammates && validPlayers.Count(p => p.Team == player.Team) == 1) return false;
|
||||
if (def.MaxPerServer >= 0 && assignmentCounts.TryGetValue(pick.Skill, out var c) && c >= def.MaxPerServer) return false;
|
||||
|
||||
|
|
@ -648,9 +658,12 @@ namespace src.player
|
|||
else
|
||||
skillList.RemoveAll(s => terroristSkills.Any(s2 => s2.Name == s.Skill.ToString()));
|
||||
|
||||
if (gameMode == Config.GameModes.NoRepeat && playersSkills.TryGetValue(player.Index, out ConcurrentBag<jSkill_SkillInfo>? skills))
|
||||
if (SkillUtils.IsPistolRound())
|
||||
skillList.RemoveAll(s => SkillsInfo.GetValue<bool>(s.Skill, "disableOnPistolRound"));
|
||||
|
||||
if (gameMode == Config.GameModes.NoRepeat && playersSkills.TryGetValue(player.Index, out HashSet<Skills>? skills))
|
||||
{
|
||||
skillList.RemoveAll(s => skills.Any(s2 => s2.Skill == s.Skill));
|
||||
skillList.RemoveAll(s => skills.Contains(s.Skill));
|
||||
if (skillList.Count == 0) skills.Clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,9 @@ namespace src.player.skills
|
|||
public class Assassin : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Assassin;
|
||||
private static readonly string[] nadeWeapons =
|
||||
[
|
||||
"weapon_inferno", "weapon_molotov", "weapon_incgrenade", "weapon_flashbang",
|
||||
"weapon_smokegrenade", "weapon_decoy", "weapon_hegrenade"
|
||||
];
|
||||
private const string infernoWeapon = "weapon_inferno";
|
||||
|
||||
private static bool IsNade(string? weapon) => weapon == infernoWeapon || WeaponPool.IsGrenade(weapon);
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
|
|
@ -46,7 +44,7 @@ namespace src.player.skills
|
|||
|
||||
var weapon = param2.Ability?.Value;
|
||||
if (weapon == null || !weapon.IsValid) return;
|
||||
if (nadeWeapons.Contains(weapon.DesignerName)) return;
|
||||
if (IsNade(weapon.DesignerName)) return;
|
||||
|
||||
if (IsBehind(attacker, victim))
|
||||
param2.Damage *= SkillsInfo.GetValue<float>(skillName, "damageMultiplier");
|
||||
|
|
|
|||
175
jRandomSkills - SRC Files/src/player/skills/Bounty.cs
Normal file
175
jRandomSkills - SRC Files/src/player/skills/Bounty.cs
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class Bounty : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Bounty;
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, byte> bountyTargets = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> ownerToTarget = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
bountyTargets.Clear();
|
||||
ownerToTarget.Clear();
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
bountyTargets.TryRemove(playerIndex, out _);
|
||||
ownerToTarget.TryRemove(playerIndex, out _);
|
||||
|
||||
foreach (var kvp in ownerToTarget)
|
||||
if (kvp.Value == playerIndex)
|
||||
ownerToTarget.TryRemove(kvp.Key, out _);
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null) return;
|
||||
playerInfo.SkillUsed = false;
|
||||
|
||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||
if (playerEvent == null || !playerEvent.IsValid) return;
|
||||
|
||||
var enemies = SkillUtils.GetSelectableEnemies(player, true);
|
||||
if (enemies.Length > 0)
|
||||
{
|
||||
ConcurrentBag<(string, string)> menuItems = new(enemies.Select(e => (e.PlayerName, e.Index.ToString())));
|
||||
SkillUtils.CreateMenu(player, menuItems);
|
||||
}
|
||||
else
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
if (ownerToTarget.TryRemove(player.Index, out uint targetIndex))
|
||||
bountyTargets.TryRemove(targetIndex, out _);
|
||||
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
if (Server.TickCount % 32 != 0) return;
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null || playerInfo.Skill != skillName) continue;
|
||||
if (!SkillUtils.HasMenu(player)) continue;
|
||||
|
||||
var enemies = SkillUtils.GetSelectableEnemies(player, true);
|
||||
|
||||
ConcurrentBag<(string, string)> menuItems = new(enemies.Select(e => (e.PlayerName, e.Index.ToString())));
|
||||
SkillUtils.UpdateMenu(player, menuItems);
|
||||
}
|
||||
}
|
||||
|
||||
public static void TypeSkill(CCSPlayerController player, string[] commands)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||
if (playerEvent == null || !playerEvent.IsValid) return;
|
||||
|
||||
if (playerInfo.SkillUsed)
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("areareaper_used_info")}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (commands.Length == 0 || !uint.TryParse(commands[0], out uint enemyIndex))
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
return;
|
||||
}
|
||||
|
||||
var enemy = Utilities.GetPlayerFromIndex((int)enemyIndex);
|
||||
if (enemy == null || !enemy.IsValid)
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
return;
|
||||
}
|
||||
|
||||
bountyTargets[enemy.Index] = 0;
|
||||
ownerToTarget[player.Index] = enemy.Index;
|
||||
playerInfo.SkillUsed = true;
|
||||
|
||||
int reward = SkillsInfo.GetValue<int>(skillName, "reward");
|
||||
|
||||
playerEvent.PrintToChat($" {ChatColors.Green}{playerEvent.GetTranslation("bounty_player_info", enemy.PlayerName, reward)}");
|
||||
|
||||
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
||||
if (enemyEvent != null && enemyEvent.IsValid)
|
||||
enemyEvent.PrintToChat($" {ChatColors.Red}{enemyEvent.GetTranslation("bounty_enemy_info", reward)}");
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
if (bountyTargets.IsEmpty) return;
|
||||
|
||||
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (victim == null || !victim.IsValid) return;
|
||||
|
||||
if (!bountyTargets.TryRemove(victim.Index, out _)) return;
|
||||
|
||||
foreach (var kvp in ownerToTarget)
|
||||
if (kvp.Value == victim.Index)
|
||||
ownerToTarget.TryRemove(kvp.Key, out _);
|
||||
|
||||
var killer = PlayerManager.GetPlayerEvent(@event.Attacker);
|
||||
if (killer == null || !killer.IsValid) return;
|
||||
if (killer.Index == victim.Index) return;
|
||||
if (killer.Team == victim.Team) return;
|
||||
|
||||
int reward = SkillsInfo.GetValue<int>(skillName, "reward");
|
||||
if (!GiveMoney(killer, reward)) return;
|
||||
|
||||
var killerEvent = PlayerManager.GetPlayerFromEvent(killer);
|
||||
if (killerEvent != null && killerEvent.IsValid)
|
||||
killerEvent.PrintToChat($" {ChatColors.Green}{killerEvent.GetTranslation("bounty_claimed_info", victim.PlayerName, reward)}");
|
||||
}
|
||||
|
||||
private static int GetMaxMoney() => ConVar.Find("mp_maxmoney")?.GetPrimitiveValue<int>() ?? 16000;
|
||||
|
||||
private static bool GiveMoney(CCSPlayerController player, int amount)
|
||||
{
|
||||
var moneyServices = player.InGameMoneyServices;
|
||||
if (moneyServices == null) return false;
|
||||
|
||||
int maxMoney = GetMaxMoney();
|
||||
if (moneyServices.Account >= maxMoney) return false;
|
||||
|
||||
moneyServices.Account = Math.Clamp(moneyServices.Account + amount, 0, maxMoney);
|
||||
Utilities.SetStateChanged(player, "CCSPlayerController", "m_pInGameMoneyServices");
|
||||
return true;
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#f2c14e", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int reward = 300) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public int Reward { get; set; } = reward;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -105,35 +105,27 @@ namespace src.player.skills
|
|||
|
||||
var bomb = PlayerManager.GetTickBomb();
|
||||
|
||||
var hidden = SkillUtils.ResolveHiddenPawns(invisiblePlayers.Keys, null);
|
||||
if (hidden.Count == 0) return;
|
||||
|
||||
foreach (var (info, player) in infoList)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
||||
|
||||
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
|
||||
|
||||
foreach (var playerIndex in invisiblePlayers.Keys)
|
||||
foreach (var target in hidden)
|
||||
{
|
||||
var playerController = PlayerManager.GetPlayerEvent(Utilities.GetPlayerFromIndex((int)playerIndex));
|
||||
if (playerController == null || !playerController.IsValid || playerController.Index == player.Index)
|
||||
continue;
|
||||
|
||||
if (player.Team == playerController.Team)
|
||||
continue;
|
||||
|
||||
var playerPawn = playerController.PlayerPawn.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid) continue;
|
||||
if (target.Index == player.Index) continue;
|
||||
if (player.Team == target.Team) continue;
|
||||
|
||||
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
||||
if (targetHandle != nint.Zero && playerPawn.Handle == targetHandle)
|
||||
continue;
|
||||
if (targetHandle != nint.Zero && target.Pawn.Handle == targetHandle) continue;
|
||||
|
||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)playerPawn.Index);
|
||||
if (entity == null || !entity.IsValid) continue;
|
||||
if (info.TransmitEntities.Contains(target.Pawn.Index))
|
||||
info.TransmitEntities.Remove(target.Pawn.Index);
|
||||
|
||||
if (info.TransmitEntities.Contains(entity.Index))
|
||||
info.TransmitEntities.Remove(entity.Index);
|
||||
|
||||
SkillUtils.HideCarriedEntities(info, playerPawn);
|
||||
SkillUtils.HideCarriedEntities(info, target.Pawn);
|
||||
|
||||
if (bomb == null) continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace src.player.skills
|
|||
public class CarefulBullets : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.CarefulBullets;
|
||||
private const string hurtSound = "Player.DamageBody.Victim";
|
||||
private static readonly ConcurrentDictionary<uint, byte> targetPlayers = [];
|
||||
private static readonly ConcurrentDictionary<uint, bool> lastShot = [];
|
||||
private static readonly ConcurrentDictionary<uint, int> hitPlayer = [];
|
||||
|
|
@ -153,7 +154,7 @@ namespace src.player.skills
|
|||
{
|
||||
if (lastShot.TryRemove(playerIndex, out bool didHit) && !didHit)
|
||||
{
|
||||
eventPlayer.ExecuteClientCommand($"play player/player_damagebody_0{Instance.Random.Next(4, 8)}");
|
||||
SkillUtils.EmitSoundToPlayer(eventPlayer, hurtSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
SkillUtils.TakeHealth(playerPawn, SkillsInfo.GetValue<int>(skillName, "damageAfterMiss"), GetSkillOwner(playerIndex), KillfeedIcons.Fist);
|
||||
}
|
||||
|
|
@ -257,8 +258,9 @@ namespace src.player.skills
|
|||
targetToPlayer.TryRemove(index, out _);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#db6c35", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int damageAfterMiss = 5) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#db6c35", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int damageAfterMiss = 5, float soundVolume = .35f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int DamageAfterMiss { get; set; } = damageAfterMiss;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ namespace src.player.skills
|
|||
if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return;
|
||||
var attackerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
||||
|
||||
if (Heavyweight.Resists(victim)) return;
|
||||
|
||||
if (attackerInfo?.Skill == skillName && victim!.PawnIsAlive)
|
||||
if (Instance.Random.NextDouble() <= attackerInfo.SkillChance)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,16 +10,7 @@ namespace src.player.skills
|
|||
public class Chicken : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Chicken;
|
||||
private static readonly HashSet<string> disabledWeapons =
|
||||
[
|
||||
"weapon_ak47", "weapon_m4a4", "weapon_m4a1", "weapon_m4a1_silencer",
|
||||
"weapon_famas", "weapon_galilar", "weapon_aug", "weapon_sg556",
|
||||
"weapon_mp9", "weapon_mac10", "weapon_bizon", "weapon_mp7",
|
||||
"weapon_ump45", "weapon_p90", "weapon_mp5sd", "weapon_ssg08",
|
||||
"weapon_awp", "weapon_scar20", "weapon_g3sg1", "weapon_nova",
|
||||
"weapon_xm1014", "weapon_mag7", "weapon_sawedoff", "weapon_m249",
|
||||
"weapon_negev"
|
||||
];
|
||||
private static HashSet<string> disabledWeapons => WeaponPool.Rifles;
|
||||
private const string chickenModelPath = "models/chicken/chicken.vmdl";
|
||||
private static readonly ConcurrentDictionary<uint, uint> chickens = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace src.player.skills
|
|||
{
|
||||
var cameraProp = Utilities.GetEntityFromIndex<CDynamicProp>((int)playerSkill.CameraProp);
|
||||
if (cameraProp != null && cameraProp.IsValid)
|
||||
cameraProp.EmitSound("SolidMetal.BulletImpact");
|
||||
cameraProp.EmitSound("SolidMetal.BulletImpact", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
SkillUtils.SafeKillEntity<CDynamicProp>(playerSkill.CameraProp);
|
||||
playerSkill.CameraProp = null;
|
||||
|
|
@ -414,8 +414,9 @@ namespace src.player.skills
|
|||
public required QAngle LastCameraAngle { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#34ebd5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 30) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#34ebd5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 30, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ namespace src.player.skills
|
|||
eventPlayerPawn.AbsVelocity.X = newVelocity.X;
|
||||
eventPlayerPawn.AbsVelocity.Y = newVelocity.Y;
|
||||
eventPlayerPawn.AbsVelocity.Z = newVelocity.Z;
|
||||
|
||||
eventPlayerPawn.EmitSound("Default.WalkJump", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,8 +166,9 @@ namespace src.player.skills
|
|||
public int JumpReleasedTicks { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#42bbfc", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float jumpVelocity = 150f, float pushVelocity = 600f, bool anyDirection = true, float cooldown = 2f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#42bbfc", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float jumpVelocity = 150f, float pushVelocity = 600f, bool anyDirection = true, float cooldown = 2f, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float JumpVelocity { get; set; } = jumpVelocity;
|
||||
public float PushVelocity { get; set; } = pushVelocity;
|
||||
public bool AnyDirection { get; set; } = anyDirection;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace src.player.skills
|
|||
public class DeathBomb : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.DeathBomb;
|
||||
private static readonly string[] voiceLines = ["balkan.radiobotfallback01", "balkan.radiobotfallback02", "balkan.radiobotfallback04"];
|
||||
private static readonly QAngle angle = new(10, -5, 9);
|
||||
private static readonly ConcurrentDictionary<int, (byte Team, uint Owner)> nades = [];
|
||||
|
||||
|
|
@ -61,9 +62,7 @@ namespace src.player.skills
|
|||
SkillUtils.PrintToChat(_p, $"{ChatColors.DarkRed}\u202A{player.PlayerName}\u202C: {ChatColors.Lime}{_p.GetTranslation("deathbomb_explosion")}",
|
||||
border: !PlayerManager.GetTickPlayers().Any(p => p.Team == player.Team && p != player) ? "tb" : "t");
|
||||
|
||||
var fileNames = new[] { "radiobotfallback01", "radiobotfallback02", "radiobotfallback04" };
|
||||
var randomFile = fileNames[new Random().Next(fileNames.Length)];
|
||||
player.ExecuteClientCommand($"play vo/agents/balkan/{randomFile}.vsnd");
|
||||
player.EmitSound(voiceLines[Random.Shared.Next(voiceLines.Length)], volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
nades.AddOrUpdate(Server.TickCount, (player.TeamNum, player.Index), (_, _) => (player.TeamNum, player.Index));
|
||||
}
|
||||
|
|
@ -136,8 +135,9 @@ namespace src.player.skills
|
|||
return player != null && player.IsValid && player.PlayerPawn?.Value != null;
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#F5CB42", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float explosionRadius = 500.0f, int explosionDamage = 999, float dmgReductionForTeamates = 0.5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#F5CB42", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float explosionRadius = 500.0f, int explosionDamage = 999, float dmgReductionForTeamates = 0.5f, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float ExplosionRadius { get; set; } = explosionRadius;
|
||||
public int ExplosionDamage { get; set; } = explosionDamage;
|
||||
public float DmgReductionForTeamates { get; set; } = dmgReductionForTeamates;
|
||||
|
|
|
|||
|
|
@ -66,13 +66,14 @@ namespace src.player.skills
|
|||
if (playerSeesEnemy)
|
||||
{
|
||||
SkillUtils.TakeHealth(enemyPawn, damage, player, KillfeedIcons.Fist);
|
||||
enemyEvent.EmitSound("Player.DamageBody.Onlooker");
|
||||
SkillUtils.EmitSoundToPlayer(enemyEvent, "Player.DamageBody.Victim", SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#c91243", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float secondCooldown = 1f, int damage = 5) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#c91243", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float secondCooldown = 1f, int damage = 5, float soundVolume = .3f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float SecondCooldown { get; set; } = secondCooldown;
|
||||
public int Damage { get; set; } = damage;
|
||||
}
|
||||
|
|
|
|||
154
jRandomSkills - SRC Files/src/player/skills/EmpGrenade.cs
Normal file
154
jRandomSkills - SRC Files/src/player/skills/EmpGrenade.cs
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class EmpGrenade : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.EmpGrenade;
|
||||
|
||||
private const string ownerTag = "EmpGrenade";
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, int> jammedUntilTick = [];
|
||||
private static readonly ConcurrentDictionary<uint, int> playersWithSkill = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
RestoreAll();
|
||||
jammedUntilTick.Clear();
|
||||
}
|
||||
|
||||
public static void RoundEnd()
|
||||
{
|
||||
RestoreAll();
|
||||
jammedUntilTick.Clear();
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
jammedUntilTick.TryRemove(playerIndex, out _);
|
||||
playersWithSkill.TryRemove(playerIndex, out _);
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (victim == null || !victim.IsValid) return;
|
||||
|
||||
if (jammedUntilTick.TryRemove(victim.Index, out _))
|
||||
SetHud(victim.Index, false);
|
||||
}
|
||||
|
||||
public static void PlayerHurt(EventPlayerHurt @event)
|
||||
{
|
||||
if (@event.Weapon != "hegrenade") return;
|
||||
|
||||
var attacker = PlayerManager.GetPlayerEvent(@event.Attacker);
|
||||
if (attacker == null || !attacker.IsValid) return;
|
||||
|
||||
var attackerInfo = PlayerManager.GetPlayerByIndex(attacker.Index);
|
||||
if (attackerInfo?.Skill != skillName) return;
|
||||
|
||||
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (victim == null || !victim.IsValid) return;
|
||||
|
||||
float duration = SkillsInfo.GetValue<float>(skillName, "jamSeconds");
|
||||
jammedUntilTick[victim.Index] = Server.TickCount + (int)(duration * 64);
|
||||
SetHud(victim.Index, true);
|
||||
|
||||
var victimEvent = PlayerManager.GetPlayerFromEvent(victim);
|
||||
if (victimEvent != null && victimEvent.IsValid)
|
||||
victimEvent.PrintToChat($" {ChatColors.Red}{victimEvent.GetTranslation("empgrenade_enemy_info")}");
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
if (jammedUntilTick.IsEmpty) return;
|
||||
|
||||
int now = Server.TickCount;
|
||||
|
||||
foreach (var kvp in jammedUntilTick)
|
||||
{
|
||||
if (now < kvp.Value) continue;
|
||||
if (!jammedUntilTick.TryRemove(kvp.Key, out _)) continue;
|
||||
|
||||
SetHud(kvp.Key, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RestoreAll()
|
||||
{
|
||||
foreach (var playerIndex in jammedUntilTick.Keys)
|
||||
SetHud(playerIndex, false);
|
||||
}
|
||||
|
||||
private static void SetHud(uint playerIndex, bool jam)
|
||||
{
|
||||
var player = Utilities.GetPlayerFromIndex((int)playerIndex);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
ApplyHud(player, jam);
|
||||
ApplyHud(PlayerManager.GetPlayerFromEvent(player), jam);
|
||||
}
|
||||
|
||||
private static void ApplyHud(CCSPlayerController? player, bool jam)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
SkillUtils.SetCrosshairHidden(player, ownerTag, jam);
|
||||
SkillUtils.SetRadarDisabled(player, ownerTag, jam);
|
||||
}
|
||||
|
||||
public static void GrenadeThrown(EventGrenadeThrown @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
if (@event.Weapon != "hegrenade") return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
if (playersWithSkill.TryGetValue(player.Index, out int grenadesLeft) && grenadesLeft > 1)
|
||||
{
|
||||
playersWithSkill[player.Index] = grenadesLeft - 1;
|
||||
player!.GiveNamedItem("weapon_hegrenade");
|
||||
SkillUtils.UpdateGrenadeCount(player, CsItem.HEGrenade, grenadesLeft - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
int grenadeLimit = SkillsInfo.GetValue<int>(skillName, "grenadeLimit");
|
||||
playersWithSkill[player.Index] = grenadeLimit;
|
||||
|
||||
SkillUtils.TryGiveWeapon(player, CsItem.HEGrenade);
|
||||
SkillUtils.UpdateGrenadeCount(player, CsItem.HEGrenade, grenadeLimit);
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
playersWithSkill.TryRemove(player.Index, out _);
|
||||
SkillUtils.UpdateGrenadeCount(player, CsItem.HEGrenade, 1);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#3ad6e8", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Uncommon, float jamSeconds = 3f, int grenadeLimit = 2) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float JamSeconds { get; set; } = jamSeconds;
|
||||
public int GrenadeLimit { get; set; } = grenadeLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,12 +19,14 @@ namespace src.player.skills
|
|||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
DecoyRing.PreloadAssets();
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
KillAllDecoys();
|
||||
rainMolotovs.Clear();
|
||||
DecoyRing.ClearAll(skillName);
|
||||
}
|
||||
|
||||
private static void KillAllDecoys()
|
||||
|
|
@ -276,7 +278,14 @@ namespace src.player.skills
|
|||
if (decoy != null && decoy.IsValid)
|
||||
decoy.AddEntityIOEvent("Kill", decoy, delay: 0.1f);
|
||||
decoys.TryRemove(key, out _);
|
||||
SpawnRain(player, new Vector(@event.X, @event.Y, @event.Z));
|
||||
|
||||
Vector impact = new(@event.X, @event.Y, @event.Z);
|
||||
SpawnRain(player, impact);
|
||||
|
||||
DecoyRing.Show(skillName, key, impact, 130f);
|
||||
jRandomSkills.Instance.AddTimer(SkillsInfo.GetValue<float>(skillName, "markerSeconds"),
|
||||
() => DecoyRing.Hide(skillName, key),
|
||||
CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -286,8 +295,9 @@ namespace src.player.skills
|
|||
SkillUtils.TryGiveWeapon(player, CsItem.DecoyGrenade);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffbf47", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Epic) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffbf47", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Epic, float markerSeconds = 4f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float MarkerSeconds { get; set; } = markerSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@ namespace src.player.skills
|
|||
|
||||
var box = param.As<CDynamicProp>();
|
||||
if (box == null || !box.IsValid) return;
|
||||
box.EmitSound("Wood_Plank.BulletImpact", volume: 1f);
|
||||
box.EmitSound("Wood_Plank.BulletImpact", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
if (barricades.TryGetValue(box.Index, out int health))
|
||||
{
|
||||
|
|
@ -178,8 +178,9 @@ namespace src.player.skills
|
|||
public DateTime Cooldown { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1b04cc", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 5, Rarity rarity = Rarity.Common, float cooldown = 2f, int barricadeHealth = 115, string propModel = "models/props/de_aztec/hr_aztec/aztec_scaffolding/aztec_scaffold_wall_support_128.vmdl") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1b04cc", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 5, Rarity rarity = Rarity.Common, float cooldown = 2f, int barricadeHealth = 115, string propModel = "models/props/de_aztec/hr_aztec/aztec_scaffolding/aztec_scaffold_wall_support_128.vmdl", float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public int BarricadeHealth { get; set; } = barricadeHealth;
|
||||
public string PropModel { get; set; } = propModel;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,19 @@ namespace src.player.skills
|
|||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
DecoyRing.PreloadAssets();
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
decoys.Clear();
|
||||
DecoyRing.ClearAll(skillName);
|
||||
}
|
||||
|
||||
public static void RoundEnd()
|
||||
{
|
||||
decoys.Clear();
|
||||
DecoyRing.ClearAll(skillName);
|
||||
}
|
||||
|
||||
public static void DecoyStarted(EventDecoyStarted @event)
|
||||
|
|
@ -31,7 +39,9 @@ namespace src.player.skills
|
|||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
decoys.TryAdd(new Vector(@event.X, @event.Y, @event.Z), 0);
|
||||
Vector pos = new(@event.X, @event.Y, @event.Z);
|
||||
decoys.TryAdd(pos, 0);
|
||||
DecoyRing.Show(skillName, (uint)@event.Entityid, pos, SkillsInfo.GetValue<float>(skillName, "triggerRadius"));
|
||||
}
|
||||
|
||||
public static void DecoyDetonate(EventDecoyDetonate @event)
|
||||
|
|
@ -44,6 +54,8 @@ namespace src.player.skills
|
|||
|
||||
foreach (var decoy in decoys.Keys.Where(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z))
|
||||
decoys.TryRemove(decoy, out _);
|
||||
|
||||
DecoyRing.Hide(skillName, (uint)@event.Entityid);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
|
|
|
|||
|
|
@ -13,9 +13,13 @@ namespace src.player.skills
|
|||
public class Ghost : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Ghost;
|
||||
private static readonly string[] allowedWeapons = [
|
||||
"weapon_molotov", "weapon_incgrenade", "weapon_flashbang", "weapon_smokegrenade", "weapon_decoy", "weapon_hegrenade", "weapon_knife", "weapon_bayonet", "weapon_c4"
|
||||
];
|
||||
private static readonly HashSet<string> alwaysAllowed = new(StringComparer.Ordinal)
|
||||
{
|
||||
"weapon_knife", "weapon_bayonet", "weapon_c4"
|
||||
};
|
||||
|
||||
private static bool IsAllowed(string? weapon) =>
|
||||
weapon != null && (alwaysAllowed.Contains(weapon) || WeaponPool.IsGrenade(weapon));
|
||||
private static readonly ConcurrentDictionary<uint, byte> invisiblePlayers = [];
|
||||
private const string bloodParticle = "particles/blood_impact/blood_impact_high.vpcf";
|
||||
private const string cameraViewModel = "models/sprays/spray_plane.vmdl";
|
||||
|
|
@ -61,38 +65,30 @@ namespace src.player.skills
|
|||
var bomb = PlayerManager.GetTickBomb();
|
||||
uint? bombOwnerIndex = bomb != null && bomb.IsValid ? bomb.OwnerEntity?.Index : null;
|
||||
|
||||
var hidden = SkillUtils.ResolveHiddenPawns(invisiblePlayers.Keys, bombOwnerIndex);
|
||||
if (hidden.Count == 0) return;
|
||||
|
||||
foreach (var (info, player) in infoList)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
||||
|
||||
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
|
||||
|
||||
foreach (var playerIndex in invisiblePlayers.Keys)
|
||||
foreach (var target in hidden)
|
||||
{
|
||||
var playerController = Utilities.GetPlayerFromIndex((int)playerIndex);
|
||||
if (playerController == null || !playerController.IsValid || playerController.Index == player.Index)
|
||||
continue;
|
||||
|
||||
if (player.Team == playerController.Team)
|
||||
continue;
|
||||
|
||||
var playerPawn = playerController.PlayerPawn.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid) continue;
|
||||
if (target.Index == player.Index) continue;
|
||||
if (player.Team == target.Team) continue;
|
||||
|
||||
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
||||
if (targetHandle != nint.Zero && playerPawn.Handle == targetHandle)
|
||||
continue;
|
||||
if (targetHandle != nint.Zero && target.Pawn.Handle == targetHandle) continue;
|
||||
|
||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)playerPawn.Index);
|
||||
if (entity == null || !entity.IsValid) continue;
|
||||
if (info.TransmitEntities.Contains(target.Pawn.Index))
|
||||
info.TransmitEntities.Remove(target.Pawn.Index);
|
||||
|
||||
if (info.TransmitEntities.Contains(entity.Index))
|
||||
info.TransmitEntities.Remove(entity.Index);
|
||||
|
||||
SkillUtils.HideCarriedEntities(info, playerPawn);
|
||||
SkillUtils.HideCarriedEntities(info, target.Pawn);
|
||||
|
||||
// Hide the bomb as well, but only while this hidden player is the one holding it.
|
||||
if (bomb == null || bombOwnerIndex != playerController.Index) continue;
|
||||
if (bomb == null || !target.HoldsBomb) continue;
|
||||
|
||||
if (info.TransmitEntities.Contains(bomb.Index))
|
||||
info.TransmitEntities.Remove(bomb.Index);
|
||||
|
|
@ -156,7 +152,7 @@ namespace src.player.skills
|
|||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill == skillName)
|
||||
if (playerInfo?.Skill == skillName && SkillUtils.IsHudFrame())
|
||||
UpdateHUD(player);
|
||||
|
||||
if (player.LifeState != (byte)LifeState_t.LIFE_ALIVE)
|
||||
|
|
@ -206,7 +202,7 @@ namespace src.player.skills
|
|||
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid && !string.IsNullOrEmpty(weapon.Value.DesignerName))
|
||||
{
|
||||
string weaponName = weapon.Value.DesignerName;
|
||||
if (!allowedWeapons.Contains(weaponName))
|
||||
if (!IsAllowed(weaponName))
|
||||
{
|
||||
weapon.Value.NextPrimaryAttackTick = disableWeapon ? int.MaxValue : Server.TickCount;
|
||||
weapon.Value.NextSecondaryAttackTick = disableWeapon ? int.MaxValue : Server.TickCount;
|
||||
|
|
@ -227,7 +223,7 @@ namespace src.player.skills
|
|||
if (playerInfo == null) return;
|
||||
|
||||
var weapon = pawn.WeaponServices.ActiveWeapon.Value;
|
||||
if (weapon == null || !weapon.IsValid || allowedWeapons.Contains(weapon.DesignerName))
|
||||
if (weapon == null || !weapon.IsValid || IsAllowed(weapon.DesignerName))
|
||||
{
|
||||
playerInfo.PrintHTML = null;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,18 @@ namespace src.player.skills
|
|||
{
|
||||
if (smokes.IsEmpty || playersWithSkill.IsEmpty) return;
|
||||
|
||||
List<uint> smokeIndexes = new(smokes.Count);
|
||||
foreach (var entityIndex in smokes.Keys)
|
||||
{
|
||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)entityIndex);
|
||||
if (entity == null || !entity.IsValid) continue;
|
||||
smokeIndexes.Add(entity.Index);
|
||||
}
|
||||
|
||||
if (smokeIndexes.Count == 0) return;
|
||||
|
||||
Dictionary<nint, uint>? pawnOwners = null;
|
||||
|
||||
foreach (var (info, player) in infoList)
|
||||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
|
@ -51,23 +63,36 @@ namespace src.player.skills
|
|||
var observerTarget = player.Pawn?.Value?.ObserverServices?.ObserverTarget?.Value?.Handle ?? nint.Zero;
|
||||
if (observerTarget == nint.Zero) continue;
|
||||
|
||||
var observedPlayer = PlayerManager.GetTickPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == observerTarget);
|
||||
if (observedPlayer == null) continue;
|
||||
pawnOwners ??= BuildPawnOwners();
|
||||
|
||||
if (PlayerManager.GetPlayerByIndex(observedPlayer.Index)?.Skill != skillName) continue;
|
||||
if (!pawnOwners.TryGetValue(observerTarget, out uint observedIndex)) continue;
|
||||
if (PlayerManager.GetPlayerByIndex(observedIndex)?.Skill != skillName) continue;
|
||||
}
|
||||
|
||||
foreach (var entityIndex in smokes.Keys)
|
||||
{
|
||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)entityIndex);
|
||||
if (entity == null || !entity.IsValid) continue;
|
||||
|
||||
if (info.TransmitEntities.Contains(entity.Index))
|
||||
info.TransmitEntities.Remove(entity.Index);
|
||||
}
|
||||
foreach (var index in smokeIndexes)
|
||||
if (info.TransmitEntities.Contains(index))
|
||||
info.TransmitEntities.Remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<nint, uint> BuildPawnOwners()
|
||||
{
|
||||
var players = PlayerManager.GetTickPlayers();
|
||||
Dictionary<nint, uint> owners = new(players.Count);
|
||||
|
||||
foreach (var p in players)
|
||||
{
|
||||
if (p == null || !p.IsValid) continue;
|
||||
|
||||
nint handle = p.Pawn?.Value?.Handle ?? nint.Zero;
|
||||
if (handle == nint.Zero) continue;
|
||||
|
||||
owners.TryAdd(handle, p.Index);
|
||||
}
|
||||
|
||||
return owners;
|
||||
}
|
||||
|
||||
public static void GrenadeThrown(EventGrenadeThrown @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace src.player.skills
|
|||
public class Glitch : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Glitch;
|
||||
private const string ownerTag = "Glitch";
|
||||
private static readonly ConcurrentDictionary<uint, byte> glitchedPlayers = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
||||
private static readonly object setLock = new();
|
||||
|
|
@ -100,7 +101,7 @@ namespace src.player.skills
|
|||
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
||||
if (enemyEvent == null || !enemyEvent.IsValid) return;
|
||||
|
||||
enemyEvent.ReplicateConVar("sv_disable_radar", "1");
|
||||
SkillUtils.SetRadarDisabled(enemyEvent, ownerTag, true);
|
||||
playerInfo.SkillUsed = true;
|
||||
|
||||
playerEvent.PrintToChat($" {ChatColors.Green}" + playerEvent.GetTranslation("glitch_player_info", enemy.PlayerName));
|
||||
|
|
@ -117,7 +118,7 @@ namespace src.player.skills
|
|||
|
||||
if (!glitchedPlayers.ContainsKey(bot.Index)) return;
|
||||
|
||||
player.ReplicateConVar("sv_disable_radar", "1");
|
||||
SkillUtils.SetRadarDisabled(player, ownerTag, true);
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
|
|
@ -146,7 +147,7 @@ namespace src.player.skills
|
|||
var target = PlayerManager.GetPlayerFromEvent(Utilities.GetPlayerFromIndex((int)targetIndex));
|
||||
if (target != null && target.IsValid)
|
||||
{
|
||||
target.ReplicateConVar("sv_disable_radar", "0");
|
||||
SkillUtils.SetRadarDisabled(target, ownerTag, false);
|
||||
if (target.PawnIsAlive && !SkillUtils.IsFreezeTime())
|
||||
target.PrintToChat($" {ChatColors.Green}" + target.GetTranslation("glitch_disable_info"));
|
||||
}
|
||||
|
|
@ -161,7 +162,7 @@ namespace src.player.skills
|
|||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
player.ReplicateConVar("sv_disable_radar", "0");
|
||||
SkillUtils.SetRadarDisabled(player, ownerTag, false);
|
||||
glitchedPlayers.TryRemove(player.Index, out _);
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,13 @@ namespace src.player.skills
|
|||
private static readonly Color counterTerroristRope = Color.FromArgb(255, 52, 92, 138);
|
||||
|
||||
private const double attemptCooldown = .3;
|
||||
private const string hookModel = "models/generic/grapplinghook_01/grapplinghook_hook_01_open.vmdl";
|
||||
private const string hookSound = "SolidMetal.BulletImpact";
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
jRandomSkills.Instance.AddToManifest(hookModel);
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
|
|
@ -131,6 +134,8 @@ namespace src.player.skills
|
|||
skillInfo.Anchor = anchor;
|
||||
skillInfo.EndTick = Server.TickCount + (int)(SkillsInfo.GetValue<float>(skillName, "maxPullSeconds") * 64);
|
||||
|
||||
SpawnHook(player, skillInfo, anchor, result.Value.NormalX, result.Value.NormalY, result.Value.NormalZ);
|
||||
|
||||
if (!EntityManager.OverBudget())
|
||||
{
|
||||
Color ropeColor = player.Team == CsTeam.Terrorist ? terroristRope : counterTerroristRope;
|
||||
|
|
@ -155,15 +160,102 @@ namespace src.player.skills
|
|||
}
|
||||
}
|
||||
|
||||
player.EmitSound("SolidMetal.BulletImpact");
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void EmitHookSound(CBaseEntity? source, CCSPlayerController player)
|
||||
{
|
||||
float volume = SkillsInfo.GetValue<float>(skillName, "soundVolume");
|
||||
|
||||
if (source != null && source.IsValid)
|
||||
{
|
||||
source.EmitSound(hookSound, volume: volume);
|
||||
return;
|
||||
}
|
||||
|
||||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn != null && pawn.IsValid)
|
||||
pawn.EmitSound(hookSound, volume: volume);
|
||||
}
|
||||
|
||||
private static void SpawnHook(CCSPlayerController player, PlayerSkillInfo skillInfo, Vector anchor, float normalX, float normalY, float normalZ)
|
||||
{
|
||||
float length = MathF.Sqrt(normalX * normalX + normalY * normalY + normalZ * normalZ);
|
||||
if (length < .0001f)
|
||||
{
|
||||
EmitHookSound(null, player);
|
||||
return;
|
||||
}
|
||||
|
||||
normalX /= length;
|
||||
normalY /= length;
|
||||
normalZ /= length;
|
||||
|
||||
var hook = EntityManager.CreateTrackedPropOverride(player.Index);
|
||||
if (hook == null || !hook.IsValid)
|
||||
{
|
||||
EmitHookSound(null, player);
|
||||
return;
|
||||
}
|
||||
|
||||
float pitch = -MathF.Asin(Math.Clamp(-normalZ, -1f, 1f)) * 180f / MathF.PI;
|
||||
float yaw = MathF.Atan2(-normalY, -normalX) * 180f / MathF.PI;
|
||||
QAngle angle = new(pitch, yaw, 0);
|
||||
|
||||
float scale = SkillsInfo.GetValue<float>(skillName, "hookScale");
|
||||
float embed = SkillsInfo.GetValue<float>(skillName, "hookEmbed") * scale;
|
||||
Vector pos = new(anchor.X + normalX * embed, anchor.Y + normalY * embed, anchor.Z + normalZ * embed);
|
||||
|
||||
uint hookIndex = hook.Index;
|
||||
skillInfo.HookIndex = hookIndex;
|
||||
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
var prop = Utilities.GetEntityFromIndex<CDynamicProp>((int)hookIndex);
|
||||
if (prop == null || !prop.IsValid)
|
||||
{
|
||||
EmitHookSound(null, player);
|
||||
return;
|
||||
}
|
||||
|
||||
var node = prop.CBodyComponent?.SceneNode?.Owner?.Entity;
|
||||
if (node != null)
|
||||
node.Flags = (uint)(node.Flags & ~(1 << 2));
|
||||
|
||||
prop.SetModel(hookModel);
|
||||
prop.Teleport(pos, angle);
|
||||
prop.DispatchSpawn();
|
||||
|
||||
EmitHookSound(prop, player);
|
||||
|
||||
var skeleton = prop.CBodyComponent?.SceneNode?.GetSkeletonInstance();
|
||||
if (skeleton != null)
|
||||
{
|
||||
skeleton.Scale = scale;
|
||||
prop.AcceptInput("SetScale", null, null, scale.ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
Utilities.SetStateChanged(prop, "CBaseEntity", "m_CBodyComponent");
|
||||
});
|
||||
}
|
||||
|
||||
private static void DestroyHook(PlayerSkillInfo skillInfo)
|
||||
{
|
||||
if (skillInfo.HookIndex == null) return;
|
||||
|
||||
uint hookIndex = skillInfo.HookIndex.Value;
|
||||
skillInfo.HookIndex = null;
|
||||
|
||||
EntityManager.DestroyEntity(hookIndex);
|
||||
}
|
||||
|
||||
private static void DestroyRope(PlayerSkillInfo skillInfo)
|
||||
{
|
||||
skillInfo.Anchor = null;
|
||||
skillInfo.EndTick = 0;
|
||||
|
||||
DestroyHook(skillInfo);
|
||||
|
||||
if (skillInfo.RopeIndex == null) return;
|
||||
|
||||
uint ropeIndex = skillInfo.RopeIndex.Value;
|
||||
|
|
@ -176,26 +268,7 @@ namespace src.player.skills
|
|||
{
|
||||
if (!liveRopes.TryRemove(ropeIndex, out _)) return;
|
||||
|
||||
var rope = Utilities.GetEntityFromIndex<CBeam>((int)ropeIndex);
|
||||
if (rope != null && rope.IsValid)
|
||||
{
|
||||
rope.Width = 0;
|
||||
rope.EndWidth = 0;
|
||||
rope.Render = Color.FromArgb(0, 0, 0, 0);
|
||||
|
||||
Utilities.SetStateChanged(rope, "CBeam", "m_fWidth");
|
||||
Utilities.SetStateChanged(rope, "CBeam", "m_fEndWidth");
|
||||
Utilities.SetStateChanged(rope, "CBaseModelEntity", "m_clrRender");
|
||||
}
|
||||
|
||||
EntityManager.DestroyEntity(ropeIndex);
|
||||
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
var leftover = Utilities.GetEntityFromIndex<CBeam>((int)ropeIndex);
|
||||
if (leftover != null && leftover.IsValid)
|
||||
leftover.Remove();
|
||||
});
|
||||
EntityManager.DestroyBeam(ropeIndex);
|
||||
}
|
||||
|
||||
private static void SweepOrphanRopes()
|
||||
|
|
@ -299,11 +372,13 @@ namespace src.player.skills
|
|||
public DateTime LastAttempt { get; set; }
|
||||
public Vector? Anchor { get; set; }
|
||||
public uint? RopeIndex { get; set; }
|
||||
public uint? HookIndex { get; set; }
|
||||
public int EndTick { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#38e0c4", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, float cooldown = 10f, float maxDistance = 1500f, float minDistance = 150f, float stopDistance = 90f, float pullSpeed = 850f, float maxPullSeconds = 3f, float ropeWidth = 0.8f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#38e0c4", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, float cooldown = 10f, float maxDistance = 1500f, float minDistance = 150f, float stopDistance = 90f, float pullSpeed = 850f, float maxPullSeconds = 3f, float ropeWidth = 0.8f, float hookEmbed = 8f, float hookScale = .4f, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public float MaxDistance { get; set; } = maxDistance;
|
||||
public float MinDistance { get; set; } = minDistance;
|
||||
|
|
@ -311,6 +386,8 @@ namespace src.player.skills
|
|||
public float PullSpeed { get; set; } = pullSpeed;
|
||||
public float MaxPullSeconds { get; set; } = maxPullSeconds;
|
||||
public float RopeWidth { get; set; } = ropeWidth;
|
||||
public float HookEmbed { get; set; } = hookEmbed;
|
||||
public float HookScale { get; set; } = hookScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
189
jRandomSkills - SRC Files/src/player/skills/GravityDecoy.cs
Normal file
189
jRandomSkills - SRC Files/src/player/skills/GravityDecoy.cs
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class GravityDecoy : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.GravityDecoy;
|
||||
|
||||
private const float defaultGravity = 1f;
|
||||
|
||||
private static readonly ConcurrentDictionary<Vector, byte> decoys = [];
|
||||
private static readonly ConcurrentDictionary<uint, int> playersWithSkill = [];
|
||||
private static readonly ConcurrentDictionary<uint, byte> affected = [];
|
||||
private static readonly ConcurrentDictionary<uint, byte> restoreOnRespawn = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
DecoyRing.PreloadAssets();
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
RestoreAll();
|
||||
decoys.Clear();
|
||||
DecoyRing.ClearAll(skillName);
|
||||
}
|
||||
|
||||
public static void RoundEnd()
|
||||
{
|
||||
RestoreAll();
|
||||
decoys.Clear();
|
||||
DecoyRing.ClearAll(skillName);
|
||||
}
|
||||
|
||||
public static void DecoyStarted(EventDecoyStarted @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
Vector pos = new(@event.X, @event.Y, @event.Z);
|
||||
decoys.TryAdd(pos, 0);
|
||||
DecoyRing.Show(skillName, (uint)@event.Entityid, pos, SkillsInfo.GetValue<float>(skillName, "triggerRadius"));
|
||||
}
|
||||
|
||||
public static void DecoyDetonate(EventDecoyDetonate @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
foreach (var decoy in decoys.Keys.Where(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z))
|
||||
decoys.TryRemove(decoy, out _);
|
||||
|
||||
DecoyRing.Hide(skillName, (uint)@event.Entityid);
|
||||
|
||||
if (decoys.IsEmpty) RestoreAll();
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
if (decoys.IsEmpty && affected.IsEmpty && restoreOnRespawn.IsEmpty) return;
|
||||
|
||||
if (decoys.IsEmpty && !affected.IsEmpty) RestoreAll();
|
||||
|
||||
float radius = SkillsInfo.GetValue<float>(skillName, "triggerRadius");
|
||||
float gravity = SkillsInfo.GetValue<float>(skillName, "gravityScale");
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
if (player.Team is not (CsTeam.CounterTerrorist or CsTeam.Terrorist)) continue;
|
||||
|
||||
var eventPlayer = PlayerManager.GetPlayerEvent(player);
|
||||
if (eventPlayer == null || !eventPlayer.IsValid) continue;
|
||||
|
||||
var pawn = eventPlayer.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) continue;
|
||||
if (pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) continue;
|
||||
|
||||
if (restoreOnRespawn.TryRemove(eventPlayer.Index, out _))
|
||||
pawn.ActualGravityScale = defaultGravity;
|
||||
|
||||
bool inside = !decoys.IsEmpty && decoys.Keys.Any(d => SkillUtils.GetDistance(d, pawn.AbsOrigin) <= radius);
|
||||
|
||||
if (inside)
|
||||
{
|
||||
if (!affected.TryAdd(eventPlayer.Index, 0)) continue;
|
||||
pawn.ActualGravityScale = gravity;
|
||||
}
|
||||
else if (affected.TryRemove(eventPlayer.Index, out _))
|
||||
pawn.ActualGravityScale = defaultGravity;
|
||||
}
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (victim == null || !victim.IsValid) return;
|
||||
|
||||
if (!affected.TryRemove(victim.Index, out _)) return;
|
||||
|
||||
Restore(victim.Index);
|
||||
restoreOnRespawn[victim.Index] = 0;
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
affected.TryRemove(playerIndex, out _);
|
||||
restoreOnRespawn.TryRemove(playerIndex, out _);
|
||||
playersWithSkill.TryRemove(playerIndex, out _);
|
||||
}
|
||||
|
||||
private static void RestoreAll()
|
||||
{
|
||||
foreach (uint playerIndex in affected.Keys)
|
||||
Restore(playerIndex);
|
||||
|
||||
foreach (uint playerIndex in restoreOnRespawn.Keys)
|
||||
Restore(playerIndex);
|
||||
|
||||
affected.Clear();
|
||||
restoreOnRespawn.Clear();
|
||||
}
|
||||
|
||||
private static void Restore(uint playerIndex)
|
||||
{
|
||||
var player = Utilities.GetPlayerFromIndex((int)playerIndex);
|
||||
var pawn = player?.PlayerPawn?.Value;
|
||||
|
||||
if (pawn != null && pawn.IsValid)
|
||||
pawn.ActualGravityScale = defaultGravity;
|
||||
}
|
||||
|
||||
public static void GrenadeThrown(EventGrenadeThrown @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
if (@event.Weapon != "decoy") return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
if (playersWithSkill.TryGetValue(player.Index, out int grenadesLeft) && grenadesLeft > 1)
|
||||
{
|
||||
playersWithSkill[player.Index] = grenadesLeft - 1;
|
||||
player!.GiveNamedItem("weapon_decoy");
|
||||
SkillUtils.UpdateGrenadeCount(player, CsItem.DecoyGrenade, grenadesLeft - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
int grenadeLimit = SkillsInfo.GetValue<int>(skillName, "grenadeLimit");
|
||||
playersWithSkill[player.Index] = grenadeLimit;
|
||||
|
||||
SkillUtils.TryGiveWeapon(player, CsItem.DecoyGrenade);
|
||||
SkillUtils.UpdateGrenadeCount(player, CsItem.DecoyGrenade, grenadeLimit);
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
playersWithSkill.TryRemove(player.Index, out _);
|
||||
SkillUtils.UpdateGrenadeCount(player, CsItem.DecoyGrenade, 1);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#a06cd5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float triggerRadius = 180f, float gravityScale = .5f, int grenadeLimit = 2) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float TriggerRadius { get; set; } = triggerRadius;
|
||||
public float GravityScale { get; set; } = gravityScale;
|
||||
public int GrenadeLimit { get; set; } = grenadeLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ namespace src.player.skills
|
|||
|
||||
if (SkillUtils.GetDistance(smokePos, pawn.AbsOrigin) <= smokeRadius)
|
||||
if (SkillUtils.AddHealth(pawn, smokeHeal))
|
||||
player.EmitSound("Healthshot.Success");
|
||||
SkillUtils.EmitSoundToPlayer(player, "Healthshot.Success", SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -156,8 +156,9 @@ namespace src.player.skills
|
|||
SkillUtils.UpdateGrenadeCount(player, CsItem.SmokeGrenade, 1);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1fe070", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int smokeHeal = 1, float smokeRadius = 180, int tickCooldown = 16, int grenadeLimit = 1) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#1fe070", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int smokeHeal = 1, float smokeRadius = 180, int tickCooldown = 16, int grenadeLimit = 1, float soundVolume = .5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int SmokeHeal { get; set; } = smokeHeal;
|
||||
public float SmokeRadius { get; set; } = smokeRadius;
|
||||
public int TickCooldown { get; set; } = tickCooldown;
|
||||
|
|
|
|||
55
jRandomSkills - SRC Files/src/player/skills/Heavyweight.cs
Normal file
55
jRandomSkills - SRC Files/src/player/skills/Heavyweight.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class Heavyweight : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Heavyweight;
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, byte> holders = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
holders.Clear();
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
holders[player.Index] = 0;
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null) return;
|
||||
holders.TryRemove(player.Index, out _);
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
holders.TryRemove(playerIndex, out _);
|
||||
}
|
||||
|
||||
public static bool Resists(CCSPlayerController? player)
|
||||
{
|
||||
if (player == null || !player.IsValid || holders.IsEmpty) return false;
|
||||
|
||||
if (holders.ContainsKey(player.Index)) return true;
|
||||
|
||||
uint routedIndex = PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index;
|
||||
return routedIndex != player.Index && holders.ContainsKey(routedIndex);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#8d6e63", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Uncommon) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,19 +10,7 @@ namespace src.player.skills
|
|||
public class Hermit : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Hermit;
|
||||
private static readonly ConcurrentDictionary<string, int> ConcurrentDictionary = new(
|
||||
[
|
||||
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", 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", 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", 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", 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", 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", 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", 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", 3), new KeyValuePair<string, int>("weapon_m249", 2), new KeyValuePair<string, int>("weapon_negev", 2)
|
||||
]);
|
||||
private static readonly ConcurrentDictionary<string, int> maxReserveAmmo = ConcurrentDictionary;
|
||||
private const int fallbackReserveAmmo = 100;
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
|
|
@ -43,9 +31,11 @@ namespace src.player.skills
|
|||
var weapon = pawn.WeaponServices.ActiveWeapon.Value;
|
||||
if (weapon == null || !weapon.IsValid || weapon.VData == null) return;
|
||||
|
||||
var maxReserveAmmoClip = maxReserveAmmo.TryGetValue(weapon.DesignerName, out var reserve) ? reserve : 100;
|
||||
int reserve = weapon.As<CCSWeaponBase>().GetVData<CCSWeaponBaseVData>()?.PrimaryReserveAmmoMax ?? 0;
|
||||
if (reserve <= 0) reserve = fallbackReserveAmmo;
|
||||
|
||||
weapon.Clip1 = weapon.VData.MaxClip1;
|
||||
weapon.ReserveAmmo.Fill(maxReserveAmmoClip);
|
||||
weapon.ReserveAmmo.Fill(reserve);
|
||||
|
||||
Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_iClip1");
|
||||
Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_pReserveAmmo");
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace src.player.skills
|
|||
public class HotBomb : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.HotBomb;
|
||||
private const string hurtSound = "Player.DamageBody.Victim";
|
||||
private readonly static ConcurrentDictionary<uint, byte> players = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
|
|
@ -41,7 +42,7 @@ namespace src.player.skills
|
|||
if (!hasC4) continue;
|
||||
|
||||
SkillUtils.TakeHealth(pawn, damage, owner, KillfeedIcons.C4);
|
||||
playerEvent?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");
|
||||
SkillUtils.EmitSoundToPlayer(playerEvent, hurtSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,8 +122,9 @@ namespace src.player.skills
|
|||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#baf081", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 1, Rarity rarity = Rarity.Common, float cooldown = 1, int damage = 2) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#baf081", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 1, Rarity rarity = Rarity.Common, float cooldown = 1, int damage = 2, float soundVolume = .35f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public int Damage { get; set; } = damage;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ namespace src.player.skills
|
|||
var player = Utilities.GetPlayerFromIndex((int)playerSkill.PlayerIndex);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
player.EmitSound("SolidMetal.BulletImpact");
|
||||
player.EmitSound("SolidMetal.BulletImpact", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
CDynamicProp? cloneProp = null;
|
||||
if (playerSkill.CloneProp != null)
|
||||
|
|
@ -468,8 +468,9 @@ namespace src.player.skills
|
|||
public List<ulong> Weapons { get; set; } = [];
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#d0d930", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 30, float duration = 10) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#d0d930", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 30, float duration = 10, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public float Duration { get; set; } = duration;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,11 +50,19 @@ namespace src.player.skills
|
|||
|
||||
private static void SendAlertToAll()
|
||||
{
|
||||
holdersTick = int.MinValue;
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (!CheckIlliterateSkill(player)) continue;
|
||||
player.PrintToCenterAlert(player.GetTranslationWithoutIlliterate("illiterate_alert"));
|
||||
}
|
||||
|
||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||
if (playerEvent == null || !playerEvent.IsValid) continue;
|
||||
|
||||
string alert = playerEvent.GetTranslationWithoutIlliterate("illiterate_alert");
|
||||
playerEvent.PrintToCenterAlert(alert);
|
||||
SkillUtils.PrintToChat(playerEvent, $"{ChatColors.Red}{alert}", ignoreIlliterate: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CheckIlliterateSkill(CCSPlayerController? player)
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ namespace src.player.skills
|
|||
|
||||
if (!consumedReplicas.TryAdd(replica.Index, 0)) return;
|
||||
|
||||
replica.EmitSound("GlassBottle.BulletImpact", volume: 1f);
|
||||
replica.EmitSound("GlassBottle.BulletImpact", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
if (ActiveTimers.TryRemove((int)replica.Index, out var timer)) timer?.Kill();
|
||||
|
||||
var owner = GetReplicaOwner(replica.Index);
|
||||
|
|
@ -230,8 +230,9 @@ namespace src.player.skills
|
|||
public DateTime Cooldown { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#42f5ef", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = 30f, float durationRun = 5, float durationCrouch = 12, int yourTeamDamage = 10, int enemyTeamDamage = 20) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#42f5ef", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = 30f, float durationRun = 5, float durationCrouch = 12, int yourTeamDamage = 10, int enemyTeamDamage = 20, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public float DurationRun { get; set; } = durationRun;
|
||||
public float DurationCrouch { get; set; } = durationCrouch;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace src.player.skills
|
|||
public class Jammer : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Jammer;
|
||||
private const string ownerTag = "Jammer";
|
||||
private static readonly ConcurrentDictionary<uint, byte> jammedPlayers = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> jammerToTarget = [];
|
||||
private static readonly object setLock = new();
|
||||
|
|
@ -118,14 +119,7 @@ namespace src.player.skills
|
|||
|
||||
private static void SetCrosshair(CCSPlayerController player, bool enabled)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid) return;
|
||||
|
||||
pawn.HideHUD = (uint)(enabled
|
||||
? (pawn.HideHUD & ~(1 << 8))
|
||||
: (pawn.HideHUD | (1 << 8)));
|
||||
|
||||
Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_iHideHUD");
|
||||
SkillUtils.SetCrosshairHidden(player, ownerTag, !enabled);
|
||||
}
|
||||
|
||||
public static void BotTakeover(EventBotTakeover @event)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace src.player.skills
|
|||
public class Jester : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Jester;
|
||||
private const string toggleSound = "Weapon_Taser.ChargeReady";
|
||||
private static readonly ConcurrentDictionary<uint, JesterInfo> jesters = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
|
|
@ -196,7 +197,7 @@ namespace src.player.skills
|
|||
|
||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||
if (playerEvent != null && playerEvent.IsValid)
|
||||
playerEvent.ExecuteClientCommand("play sounds/weapons/taser/taser_charge_ready");
|
||||
SkillUtils.EmitSoundToPlayer(playerEvent, toggleSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
|
||||
var minTime = SkillsInfo.GetValue<float>(skillName, "minTime");
|
||||
|
|
@ -275,8 +276,9 @@ namespace src.player.skills
|
|||
public Timer? Timer { get; set; } = null;
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#8f108f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float minTime = 10f, float maxTime = 25f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#8f108f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float minTime = 10f, float maxTime = 25f, float soundVolume = .5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float MinTime { get; set; } = minTime;
|
||||
public float MaxTime { get; set; } = maxTime;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@ namespace src.player.skills
|
|||
|
||||
private static void PushPlayer(CCSPlayerController player)
|
||||
{
|
||||
if (Heavyweight.Resists(player)) return;
|
||||
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace src.player.skills
|
|||
public class LastGasp : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.LastGasp;
|
||||
private const string hurtSound = "Player.DamageBody.Victim";
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
|
|
@ -45,11 +46,12 @@ namespace src.player.skills
|
|||
}
|
||||
|
||||
SkillUtils.TakeHealth(attackerPawn, damageAfterDeath, victim, KillfeedIcons.Fist);
|
||||
PlayerManager.GetPlayerFromEvent(attacker)?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");
|
||||
SkillUtils.EmitSoundToPlayer(attacker, hurtSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#88bdba", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, int damageAfterDeath = 30, bool canKill = true) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#88bdba", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, int damageAfterDeath = 30, bool canKill = true, float soundVolume = .35f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int DamageAfterDeath { get; set; } = damageAfterDeath;
|
||||
public bool CanKill { get; set; } = canKill;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ namespace src.player.skills
|
|||
public class LongKnife : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.LongKnife;
|
||||
private const string victimSound = "Player.DamageBody.Victim";
|
||||
private const string heavyHitSound = "Weapon_Knife.Hit.Heavy.Flesh";
|
||||
private const string lightHitSound = "Weapon_Knife.Hit.Light.Flesh";
|
||||
|
||||
private static bool hooked = false;
|
||||
private const int actionCode = 503;
|
||||
|
|
@ -121,12 +124,15 @@ namespace src.player.skills
|
|||
|
||||
if (!SkillsInfo.GetValue<bool>(skillName, "friendlyFire") && player.Team == target.Team) return;
|
||||
|
||||
target.PlayerPawn.Value.EmitSound("Player.DamageBody.Onlooker");
|
||||
SkillUtils.EmitSoundToPlayer(target, victimSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
SkillUtils.EmitSoundToPlayer(player, heavyHit ? heavyHitSound : lightHitSound, SkillsInfo.GetValue<float>(skillName, "hitSoundVolume"));
|
||||
SkillUtils.TakeHealth(target.PlayerPawn.Value, heavyHit ? Instance.Random.Next(45, 55) : Instance.Random.Next(21, 34), player, killfeedIcon ?? KillfeedIcons.Knife);
|
||||
}
|
||||
|
||||
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? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float maxDistance = 4096f, bool friendlyFire = true) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
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? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float maxDistance = 4096f, bool friendlyFire = true, float soundVolume = .35f, float hitSoundVolume = .35f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float HitSoundVolume { get; set; } = hitSoundVolume;
|
||||
public float MaxDistance { get; set; } = maxDistance;
|
||||
public bool FriendlyFire { get; set; } = friendlyFire;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,19 @@ namespace src.player.skills
|
|||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
DecoyRing.PreloadAssets();
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
decoys.Clear();
|
||||
DecoyRing.ClearAll(skillName);
|
||||
}
|
||||
|
||||
public static void RoundEnd()
|
||||
{
|
||||
decoys.Clear();
|
||||
DecoyRing.ClearAll(skillName);
|
||||
}
|
||||
|
||||
public static void DecoyStarted(EventDecoyStarted @event)
|
||||
|
|
@ -31,7 +39,9 @@ namespace src.player.skills
|
|||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
decoys.TryAdd(new Vector(@event.X, @event.Y, @event.Z), 0);
|
||||
Vector pos = new(@event.X, @event.Y, @event.Z);
|
||||
decoys.TryAdd(pos, 0);
|
||||
DecoyRing.Show(skillName, (uint)@event.Entityid, pos, SkillsInfo.GetValue<float>(skillName, "triggerRadius"));
|
||||
}
|
||||
|
||||
public static void DecoyDetonate(EventDecoyDetonate @event)
|
||||
|
|
@ -44,6 +54,8 @@ namespace src.player.skills
|
|||
|
||||
foreach (var decoy in decoys.Keys.Where(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z))
|
||||
decoys.TryRemove(decoy, out _);
|
||||
|
||||
DecoyRing.Hide(skillName, (uint)@event.Entityid);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ namespace src.player.skills
|
|||
skillInfo.Cooldown = DateTime.Now;
|
||||
skillInfo.Count -= 1;
|
||||
SkillUtils.AddHealth(playerPawn, SkillsInfo.GetValue<int>(skillName, "healthToAdd"));
|
||||
player.EmitSound("Healthshot.Success");
|
||||
SkillUtils.EmitSoundToPlayer(player, "Healthshot.Success", SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -106,8 +106,9 @@ namespace src.player.skills
|
|||
public DateTime Cooldown { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#10c212", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int healthToAdd = 50, int healthShotLimit = 3, float cooldown = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#10c212", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int healthToAdd = 50, int healthShotLimit = 3, float cooldown = 1f, float soundVolume = .5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int HealthToAdd { get; set; } = healthToAdd;
|
||||
public int HealthShotLimit { get; set; } = healthShotLimit;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ namespace src.player.skills
|
|||
position.Z += 60;
|
||||
grenade.Teleport(position);
|
||||
|
||||
grenade.EmitSound("IncGrenade.Bounce_M");
|
||||
grenade.EmitSound("IncGrenade.Bounce_M", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
grenade.DetonateTime = Server.CurrentTime + .5f;
|
||||
Utilities.SetStateChanged(grenade, "CBaseGrenade", "m_flDetonateTime");
|
||||
|
|
@ -161,8 +161,9 @@ namespace src.player.skills
|
|||
SkillUtils.UpdateGrenadeCount(player, CsItem.HEGrenade, 1);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#adf542", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float detonationRange = 130, int grenadeLimit = 3) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#adf542", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float detonationRange = 130, int grenadeLimit = 3, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float DetonationRange { get; set; } = detonationRange;
|
||||
public int GrenadeLimit { get; set; } = grenadeLimit;
|
||||
}
|
||||
|
|
|
|||
156
jRandomSkills - SRC Files/src/player/skills/Nemesis.cs
Normal file
156
jRandomSkills - SRC Files/src/player/skills/Nemesis.cs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using static src.jRandomSkills;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class Nemesis : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Nemesis;
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, byte> markedPlayers = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> ownerToTarget = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
markedPlayers.Clear();
|
||||
ownerToTarget.Clear();
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
markedPlayers.TryRemove(playerIndex, out _);
|
||||
ownerToTarget.TryRemove(playerIndex, out _);
|
||||
|
||||
foreach (var kvp in ownerToTarget)
|
||||
if (kvp.Value == playerIndex)
|
||||
ownerToTarget.TryRemove(kvp.Key, out _);
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null) return;
|
||||
playerInfo.SkillUsed = false;
|
||||
|
||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||
if (playerEvent == null || !playerEvent.IsValid) return;
|
||||
|
||||
var enemies = SkillUtils.GetSelectableEnemies(player, true);
|
||||
if (enemies.Length > 0)
|
||||
{
|
||||
ConcurrentBag<(string, string)> menuItems = new(enemies.Select(e => (e.PlayerName, e.Index.ToString())));
|
||||
SkillUtils.CreateMenu(player, menuItems);
|
||||
}
|
||||
else
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
if (ownerToTarget.TryRemove(player.Index, out uint targetIndex))
|
||||
markedPlayers.TryRemove(targetIndex, out _);
|
||||
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
if (Server.TickCount % 32 != 0) return;
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null || playerInfo.Skill != skillName) continue;
|
||||
if (!SkillUtils.HasMenu(player)) continue;
|
||||
|
||||
var enemies = SkillUtils.GetSelectableEnemies(player, true);
|
||||
|
||||
ConcurrentBag<(string, string)> menuItems = new(enemies.Select(e => (e.PlayerName, e.Index.ToString())));
|
||||
SkillUtils.UpdateMenu(player, menuItems);
|
||||
}
|
||||
}
|
||||
|
||||
public static void TypeSkill(CCSPlayerController player, string[] commands)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||
if (playerEvent == null || !playerEvent.IsValid) return;
|
||||
|
||||
if (playerInfo.SkillUsed)
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("areareaper_used_info")}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (commands.Length == 0 || !uint.TryParse(commands[0], out uint enemyIndex))
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
return;
|
||||
}
|
||||
|
||||
var enemy = Utilities.GetPlayerFromIndex((int)enemyIndex);
|
||||
if (enemy == null || !enemy.IsValid)
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
return;
|
||||
}
|
||||
|
||||
markedPlayers[enemy.Index] = 0;
|
||||
ownerToTarget[player.Index] = enemy.Index;
|
||||
playerInfo.SkillUsed = true;
|
||||
|
||||
playerEvent.PrintToChat($" {ChatColors.Green}{playerEvent.GetTranslation("nemesis_player_info", enemy.PlayerName)}");
|
||||
|
||||
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
||||
if (enemyEvent != null && enemyEvent.IsValid)
|
||||
enemyEvent.PrintToChat($" {ChatColors.Red}{enemyEvent.GetTranslation("nemesis_enemy_info")}");
|
||||
}
|
||||
|
||||
public static void OnTakeDamage(DynamicHook h)
|
||||
{
|
||||
if (markedPlayers.IsEmpty) return;
|
||||
|
||||
CEntityInstance param = h.GetParam<CEntityInstance>(0);
|
||||
CTakeDamageInfo param2 = h.GetParam<CTakeDamageInfo>(1);
|
||||
if (param == null || !param.IsValid || param2 == null) return;
|
||||
|
||||
var victimPawn = param.As<CCSPlayerPawn>();
|
||||
if (victimPawn == null || !victimPawn.IsValid || victimPawn.DesignerName != "player") return;
|
||||
|
||||
var victimController = victimPawn.Controller.Value;
|
||||
if (victimController == null || !victimController.IsValid) return;
|
||||
|
||||
var victim = victimController.As<CCSPlayerController>();
|
||||
if (victim == null || !victim.IsValid) return;
|
||||
|
||||
uint victimIndex = PlayerManager.GetPlayerEvent(victim)?.Index ?? victim.Index;
|
||||
if (!markedPlayers.ContainsKey(victimIndex)) return;
|
||||
|
||||
param2.Damage *= 1f + SkillsInfo.GetValue<float>(skillName, "extraDamagePercent");
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#b8003a", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Rare, float extraDamagePercent = .25f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float ExtraDamagePercent { get; set; } = extraDamagePercent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ namespace src.player.skills
|
|||
public class Nightmare : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Nightmare;
|
||||
private const string cursedSound = "UI.ArmsRace.FinalKill_Tone";
|
||||
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> targetVolumes = [];
|
||||
private static readonly object setLock = new();
|
||||
|
|
@ -129,7 +130,10 @@ namespace src.player.skills
|
|||
playerEvent.PrintToChat($" {ChatColors.Green}" + playerEvent.GetTranslation("nightmare_player_info", enemy.PlayerName));
|
||||
|
||||
if (enemyEvent != null && enemyEvent.IsValid)
|
||||
{
|
||||
enemyEvent.PrintToChat($" {ChatColors.Red}" + enemyEvent.GetTranslation("nightmare_enemy_info"));
|
||||
SkillUtils.EmitSoundToPlayer(enemyEvent, cursedSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
|
|
@ -227,8 +231,9 @@ namespace src.player.skills
|
|||
EntityManager.DestroyEntity(volumeIndex);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#5b2c6f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, string postProcessing = "lighting/postprocessing/effects/death_cam_phase1_low_violence.vpost", float fadeTime = .25f, float minExposure = .5f, float maxExposure = 2f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#5b2c6f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, string postProcessing = "lighting/postprocessing/effects/death_cam_phase1_low_violence.vpost", float fadeTime = .25f, float minExposure = .5f, float maxExposure = 2f, float soundVolume = .5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public string PostProcessing { get; set; } = postProcessing;
|
||||
public float FadeTime { get; set; } = fadeTime;
|
||||
public float MinExposure { get; set; } = minExposure;
|
||||
|
|
|
|||
|
|
@ -63,37 +63,29 @@ namespace src.player.skills
|
|||
var bomb = PlayerManager.GetTickBomb();
|
||||
uint? bombOwnerIndex = bomb != null && bomb.IsValid ? bomb.OwnerEntity?.Index : null;
|
||||
|
||||
var hidden = SkillUtils.ResolveHiddenPawns(invisiblePlayers.Keys, bombOwnerIndex);
|
||||
if (hidden.Count == 0) return;
|
||||
|
||||
foreach (var (info, player) in infoList)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
||||
|
||||
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
|
||||
|
||||
foreach (var playerIndex in invisiblePlayers.Keys)
|
||||
foreach (var target in hidden)
|
||||
{
|
||||
var playerController = PlayerManager.GetPlayerEvent(Utilities.GetPlayerFromIndex((int)playerIndex));
|
||||
if (playerController == null || !playerController.IsValid || playerController.Index == player.Index)
|
||||
continue;
|
||||
|
||||
if (player.Team == playerController.Team)
|
||||
continue;
|
||||
|
||||
var playerPawn = playerController.PlayerPawn.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid) continue;
|
||||
if (target.Index == player.Index) continue;
|
||||
if (player.Team == target.Team) continue;
|
||||
|
||||
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
||||
if (targetHandle != nint.Zero && playerPawn.Handle == targetHandle)
|
||||
continue;
|
||||
if (targetHandle != nint.Zero && target.Pawn.Handle == targetHandle) continue;
|
||||
|
||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)playerPawn.Index);
|
||||
if (entity == null || !entity.IsValid) continue;
|
||||
if (info.TransmitEntities.Contains(target.Pawn.Index))
|
||||
info.TransmitEntities.Remove(target.Pawn.Index);
|
||||
|
||||
if (info.TransmitEntities.Contains(entity.Index))
|
||||
info.TransmitEntities.Remove(entity.Index);
|
||||
SkillUtils.HideCarriedEntities(info, target.Pawn);
|
||||
|
||||
SkillUtils.HideCarriedEntities(info, playerPawn);
|
||||
|
||||
if (bomb == null || bombOwnerIndex != playerController.Index) continue;
|
||||
if (bomb == null || !target.HoldsBomb) continue;
|
||||
|
||||
if (info.TransmitEntities.Contains(bomb.Index))
|
||||
info.TransmitEntities.Remove(bomb.Index);
|
||||
|
|
|
|||
|
|
@ -15,15 +15,14 @@ namespace src.player.skills
|
|||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> blockedWeapons =
|
||||
["hegrenade", "inferno", "decoy", "flashbang", "smokegrenade", "molotov"];
|
||||
private const string infernoDamage = "inferno";
|
||||
|
||||
public static bool PlayerHurtPre(EventPlayerHurt @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (!Instance.IsPlayerValid(player)) return false;
|
||||
|
||||
if (!blockedWeapons.Contains(@event.Weapon)) return false;
|
||||
if (@event.Weapon != infernoDamage && !WeaponPool.IsGrenade(@event.Weapon)) return false;
|
||||
if (PlayerManager.GetPlayerByIndex(player!.Index)?.Skill != skillName) return false;
|
||||
|
||||
SkillUtils.RestoreHealth(player);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace src.player.skills
|
|||
public class PawelJumper : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.PawelJumper;
|
||||
private const string jumpSound = "Default.WalkJump";
|
||||
private static readonly int?[] J = new int?[64];
|
||||
private static readonly PlayerButtons[] LB = new PlayerButtons[64];
|
||||
|
||||
|
|
@ -73,13 +74,17 @@ namespace src.player.skills
|
|||
{
|
||||
J[player.Slot]++;
|
||||
playerEventPawn.AbsVelocity.Z = 300;
|
||||
|
||||
if (J[player.Slot] > 1)
|
||||
playerEventPawn.EmitSound(jumpSound, volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
|
||||
LB[player.Slot] = buttons;
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#FFA500", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int extraJumpsMin = 1, int extraJumpsMax = 4) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#FFA500", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int extraJumpsMin = 1, int extraJumpsMax = 4, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int ExtraJumpsMin { get; set; } = extraJumpsMin;
|
||||
public int ExtraJumpsMax { get; set; } = extraJumpsMax;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,29 @@ namespace src.player.skills
|
|||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
Instance.AddToManifest(SkillsInfo.GetValue<string>(skillName, "particleName"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
foreach (var pilotInfo in PlayerPilotInfo.Values)
|
||||
ClearTrail(pilotInfo);
|
||||
|
||||
PlayerPilotInfo.Clear();
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
if (PlayerPilotInfo.TryGetValue(player.Index, out var pilotInfo))
|
||||
{
|
||||
ClearTrail(pilotInfo);
|
||||
pilotInfo.IsFlying = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
|
|
@ -39,7 +55,9 @@ namespace src.player.skills
|
|||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
PlayerPilotInfo.TryRemove(player.Index, out _);
|
||||
if (PlayerPilotInfo.TryRemove(player.Index, out var pilotInfo))
|
||||
ClearTrail(pilotInfo);
|
||||
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
}
|
||||
|
||||
|
|
@ -96,9 +114,18 @@ namespace src.player.skills
|
|||
);
|
||||
|
||||
if (inUse)
|
||||
{
|
||||
ApplyPilotEffect(player);
|
||||
else if (pilotInfo.Fuel <= 0)
|
||||
pilotInfo.IsFlying = false;
|
||||
StartTrail(player, playerPawn, pilotInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pilotInfo.TrailIndex != null)
|
||||
ClearTrail(pilotInfo);
|
||||
|
||||
if (pilotInfo.Fuel <= 0)
|
||||
pilotInfo.IsFlying = false;
|
||||
}
|
||||
|
||||
pilotInfo.LastButtons = buttons;
|
||||
UpdateHUD(player, pilotInfo);
|
||||
|
|
@ -132,6 +159,62 @@ namespace src.player.skills
|
|||
return "#FF0000";
|
||||
}
|
||||
|
||||
private static void StartTrail(CCSPlayerController player, CCSPlayerPawn pawn, Pilot_PlayerInfo pilotInfo)
|
||||
{
|
||||
if (pilotInfo.TrailIndex != null)
|
||||
{
|
||||
var existing = Utilities.GetEntityFromIndex<CParticleSystem>((int)pilotInfo.TrailIndex.Value);
|
||||
if (existing != null && existing.IsValid) return;
|
||||
pilotInfo.TrailIndex = null;
|
||||
}
|
||||
|
||||
if (pawn.AbsOrigin == null) return;
|
||||
|
||||
var particle = EntityManager.CreateTrackedParticleSystem(player.Index, SkillsInfo.GetValue<string>(skillName, "particleName"));
|
||||
if (particle == null || !particle.IsValid) return;
|
||||
|
||||
float offset = SkillsInfo.GetValue<float>(skillName, "particleOffset");
|
||||
particle.Teleport(new Vector(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z + offset));
|
||||
particle.AcceptInput("SetParent", pawn, particle, "!activator");
|
||||
particle.AcceptInput("Start");
|
||||
|
||||
pilotInfo.TrailIndex = particle.Index;
|
||||
}
|
||||
|
||||
private static void StopTrail(Pilot_PlayerInfo pilotInfo)
|
||||
{
|
||||
if (pilotInfo.TrailIndex == null) return;
|
||||
|
||||
uint index = pilotInfo.TrailIndex.Value;
|
||||
pilotInfo.TrailIndex = null;
|
||||
|
||||
var particle = Utilities.GetEntityFromIndex<CParticleSystem>((int)index);
|
||||
if (particle != null && particle.IsValid)
|
||||
{
|
||||
particle.AcceptInput("Stop");
|
||||
particle.AcceptInput("DestroyImmediately");
|
||||
}
|
||||
|
||||
EntityManager.DestroyEntity(index);
|
||||
|
||||
if (EntityManager.SuppressKills) return;
|
||||
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
var leftover = Utilities.GetEntityFromIndex<CParticleSystem>((int)index);
|
||||
if (leftover != null && leftover.IsValid)
|
||||
leftover.Remove();
|
||||
});
|
||||
}
|
||||
|
||||
private static void ClearTrail(Pilot_PlayerInfo pilotInfo)
|
||||
{
|
||||
StopTrail(pilotInfo);
|
||||
|
||||
foreach (var leftover in EntityManager.GetPlayerEntities((uint)pilotInfo.SteamID, "particle_system"))
|
||||
EntityManager.DestroyEntity(leftover);
|
||||
}
|
||||
|
||||
private static void ApplyPilotEffect(CCSPlayerController player)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
|
|
@ -168,10 +251,13 @@ namespace src.player.skills
|
|||
public int JumpCount { get; set; } = 0;
|
||||
public float LastJumpTime { get; set; } = 0;
|
||||
public bool IsFlying { get; set; } = false;
|
||||
public uint? TrailIndex { 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? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float maximumFuel = 150f, float fuelConsumption = .64f, float refuelling = .1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
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? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float maximumFuel = 150f, float fuelConsumption = .64f, float refuelling = .1f, string particleName = "particles/inferno_fx/incgrenade_thrown_trail.vpcf", float particleOffset = 0f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public string ParticleName { get; set; } = particleName;
|
||||
public float ParticleOffset { get; set; } = particleOffset;
|
||||
public float MaximumFuel { get; set; } = maximumFuel;
|
||||
public float FuelConsumption { get; set; } = fuelConsumption;
|
||||
public float Refuelling { get; set; } = refuelling;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ namespace src.player.skills
|
|||
public static void OnTick()
|
||||
{
|
||||
float currentTime = Server.CurrentTime;
|
||||
bool hudFrame = SkillUtils.IsHudFrame();
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers().Where(p => p.Team == CsTeam.Terrorist))
|
||||
{
|
||||
if (!Instance.IsPlayerValid(player)) continue;
|
||||
|
|
@ -111,7 +113,7 @@ namespace src.player.skills
|
|||
pawn.InBombZone = true;
|
||||
Schema.SetSchemaValue<bool>(pawn.Handle, "CCSPlayerPawn", "m_bInBombZone", true);
|
||||
|
||||
if (plantingPlayers.TryGetValue(player.Index, out float plantTime))
|
||||
if (hudFrame && plantingPlayers.TryGetValue(player.Index, out float plantTime))
|
||||
{
|
||||
float remaining = plantTime + 3f - currentTime;
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("planter_planting", $"<font color='#00FF00'>{Math.Max(0, remaining):0.0}s</font>")}";
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace src.player.skills
|
|||
public class Poison : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Poison;
|
||||
private const string poisonSound = "Player.DamageBody.Victim";
|
||||
private static readonly ConcurrentDictionary<uint, byte> poisonedPlayers = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> targetToPlayer = [];
|
||||
|
|
@ -69,7 +70,7 @@ namespace src.player.skills
|
|||
SkillUtils.TakeHealth(pawn, SkillsInfo.GetValue<int>(skillName, "Damage"), GetSkillOwner(playerIndex), KillfeedIcons.Spray);
|
||||
|
||||
if (Server.TickCount % cooldown2 == 0)
|
||||
PlayerManager.GetPlayerFromEvent(player)?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");
|
||||
SkillUtils.EmitSoundToPlayer(player, poisonSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,8 +187,9 @@ namespace src.player.skills
|
|||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#902eff", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = .85f, int damage = 1, int minHealth = 30) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#902eff", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = .85f, int damage = 1, int minHealth = 30, float soundVolume = .3f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int Damage { get; set; } = damage;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public int MinHealth { get; set; } = minHealth;
|
||||
|
|
|
|||
|
|
@ -12,16 +12,7 @@ namespace src.player.skills
|
|||
private static readonly ConcurrentDictionary<uint, byte> bannedPlayers = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
||||
private static readonly object setLock = new();
|
||||
private static readonly string[] disabledWeapons =
|
||||
[
|
||||
"weapon_ak47", "weapon_m4a4", "weapon_m4a1", "weapon_m4a1_silencer",
|
||||
"weapon_famas", "weapon_galilar", "weapon_aug", "weapon_sg556",
|
||||
"weapon_mp9", "weapon_mac10", "weapon_bizon", "weapon_mp7",
|
||||
"weapon_ump45", "weapon_p90", "weapon_mp5sd", "weapon_ssg08",
|
||||
"weapon_awp", "weapon_scar20", "weapon_g3sg1", "weapon_nova",
|
||||
"weapon_xm1014", "weapon_mag7", "weapon_sawedoff", "weapon_m249",
|
||||
"weapon_negev"
|
||||
];
|
||||
private static HashSet<string> disabledWeapons => WeaponPool.Rifles;
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ namespace src.player.skills
|
|||
}
|
||||
|
||||
if (!info.Defusing)
|
||||
pawn.EmitSound("c4.disarmstart");
|
||||
pawn.EmitSound("c4.disarmstart", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
info.Defusing = true;
|
||||
info.DefusingTime -= (1f / tickRate);
|
||||
|
||||
|
|
@ -128,8 +128,9 @@ namespace src.player.skills
|
|||
public float DefusingTime { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#507529", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float maxDefusingRange = 80f, float defusingTime = 10f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#507529", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float maxDefusingRange = 80f, float defusingTime = 10f, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float MaxDefusingRange { get; set; } = maxDefusingRange;
|
||||
public float DefusingTime { get; set; } = defusingTime;
|
||||
}
|
||||
|
|
|
|||
110
jRandomSkills - SRC Files/src/player/skills/Punisher.cs
Normal file
110
jRandomSkills - SRC Files/src/player/skills/Punisher.cs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class Punisher : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Punisher;
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, float> storedDamage = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
storedDamage.Clear();
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
storedDamage[player.Index] = 0f;
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null) return;
|
||||
|
||||
storedDamage.TryRemove(player.Index, out _);
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
storedDamage.TryRemove(playerIndex, out _);
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (victim == null || !victim.IsValid) return;
|
||||
|
||||
if (storedDamage.ContainsKey(victim.Index))
|
||||
storedDamage[victim.Index] = 0f;
|
||||
}
|
||||
|
||||
public static void OnTakeDamage(DynamicHook h)
|
||||
{
|
||||
if (storedDamage.IsEmpty) return;
|
||||
|
||||
CEntityInstance param = h.GetParam<CEntityInstance>(0);
|
||||
CTakeDamageInfo param2 = h.GetParam<CTakeDamageInfo>(1);
|
||||
if (param == null || !param.IsValid || param2 == null) return;
|
||||
|
||||
var victimPawn = param.As<CCSPlayerPawn>();
|
||||
if (victimPawn == null || !victimPawn.IsValid || victimPawn.DesignerName != "player") return;
|
||||
|
||||
var victimController = victimPawn.Controller.Value;
|
||||
if (victimController == null || !victimController.IsValid) return;
|
||||
|
||||
var victim = victimController.As<CCSPlayerController>();
|
||||
if (victim == null || !victim.IsValid) return;
|
||||
|
||||
uint victimIndex = PlayerManager.GetPlayerEvent(victim)?.Index ?? victim.Index;
|
||||
|
||||
var attacker = param2.Attacker?.Value?.As<CCSPlayerPawn>();
|
||||
var attackerController = attacker?.Controller?.Value?.As<CCSPlayerController>();
|
||||
uint? attackerIndex = attackerController != null && attackerController.IsValid
|
||||
? PlayerManager.GetPlayerEvent(attackerController)?.Index ?? attackerController.Index
|
||||
: null;
|
||||
|
||||
if (attackerIndex.HasValue && attackerIndex.Value != victimIndex && storedDamage.TryGetValue(attackerIndex.Value, out float banked) && banked > 0f)
|
||||
{
|
||||
storedDamage[attackerIndex.Value] = 0f;
|
||||
param2.Damage += banked;
|
||||
|
||||
var puncher = CounterStrikeSharp.API.Utilities.GetPlayerFromIndex((int)attackerIndex.Value);
|
||||
var puncherPawn = puncher?.PlayerPawn?.Value;
|
||||
|
||||
if (puncherPawn != null && puncherPawn.IsValid && puncherPawn.Health > 0)
|
||||
SkillUtils.SetHealth(puncherPawn, puncherPawn.Health + (int)MathF.Round(banked));
|
||||
|
||||
var puncherEvent = PlayerManager.GetPlayerFromEvent(puncher);
|
||||
if (puncherEvent != null && puncherEvent.IsValid)
|
||||
puncherEvent.PrintToChat($" {ChatColors.Green}{puncherEvent.GetTranslation("punisher_released_info", (int)MathF.Round(banked))}");
|
||||
}
|
||||
|
||||
if (!storedDamage.ContainsKey(victimIndex)) return;
|
||||
if (attackerIndex.HasValue && attackerIndex.Value == victimIndex) return;
|
||||
|
||||
float ratio = SkillsInfo.GetValue<float>(skillName, "storePercent");
|
||||
float cap = SkillsInfo.GetValue<float>(skillName, "maxStored");
|
||||
|
||||
float stored = storedDamage[victimIndex] + (param2.Damage * ratio);
|
||||
storedDamage[victimIndex] = MathF.Min(stored, cap);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffb347", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float storePercent = .5f, float maxStored = 100f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float StorePercent { get; set; } = storePercent;
|
||||
public float MaxStored { get; set; } = maxStored;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,8 @@ namespace src.player.skills
|
|||
if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim)
|
||||
return;
|
||||
|
||||
if (Heavyweight.Resists(victim)) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
||||
|
||||
if (playerInfo?.Skill == skillName && victim!.PawnIsAlive)
|
||||
|
|
|
|||
|
|
@ -13,19 +13,8 @@ namespace src.player.skills
|
|||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = new();
|
||||
private static readonly object setLock = new();
|
||||
|
||||
private static readonly HashSet<string> pistols = new(StringComparer.Ordinal)
|
||||
{
|
||||
"weapon_deagle", "weapon_revolver", "weapon_glock", "weapon_usp_silencer",
|
||||
"weapon_cz75a", "weapon_fiveseven", "weapon_p250", "weapon_tec9", "weapon_elite", "weapon_hkp2000"
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> rifles = new(StringComparer.Ordinal)
|
||||
{
|
||||
"weapon_mp9", "weapon_mac10", "weapon_bizon", "weapon_mp7", "weapon_ump45", "weapon_p90",
|
||||
"weapon_mp5sd", "weapon_famas", "weapon_galilar", "weapon_m4a1", "weapon_m4a1_silencer", "weapon_ak47",
|
||||
"weapon_aug", "weapon_sg556", "weapon_ssg08", "weapon_awp", "weapon_scar20", "weapon_g3sg1",
|
||||
"weapon_nova", "weapon_xm1014", "weapon_mag7", "weapon_sawedoff", "weapon_m249", "weapon_negev"
|
||||
};
|
||||
private static HashSet<string> pistols => WeaponPool.Pistols;
|
||||
private static HashSet<string> rifles => WeaponPool.Rifles;
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
|
|
@ -104,6 +93,19 @@ namespace src.player.skills
|
|||
RemoveAndGiveWeapon(player);
|
||||
}
|
||||
|
||||
private static bool RollPistol(bool pistolAvailable, bool rifleAvailable)
|
||||
{
|
||||
if (!rifleAvailable) return true;
|
||||
if (!pistolAvailable) return false;
|
||||
|
||||
float pistolChance = Math.Max(SkillsInfo.GetValue<float>(skillName, "pistolChance"), 0);
|
||||
float rifleChance = Math.Max(SkillsInfo.GetValue<float>(skillName, "rifleChance"), 0);
|
||||
float total = pistolChance + rifleChance;
|
||||
|
||||
if (total <= 0) return Instance.Random.Next(2) == 0;
|
||||
return Instance.Random.NextDouble() * total < pistolChance;
|
||||
}
|
||||
|
||||
private static void RemoveAndGiveWeapon(CCSPlayerController player)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
|
|
@ -117,12 +119,15 @@ namespace src.player.skills
|
|||
if (playerWeapons.Count == 0)
|
||||
return;
|
||||
|
||||
var available = pistols.Concat(rifles).Where(w => !playerWeapons.Contains(w)).ToArray();
|
||||
if (available.Length == 0)
|
||||
var availablePistols = pistols.Where(w => !playerWeapons.Contains(w)).ToArray();
|
||||
var availableRifles = rifles.Where(w => !playerWeapons.Contains(w)).ToArray();
|
||||
if (availablePistols.Length == 0 && availableRifles.Length == 0)
|
||||
return;
|
||||
|
||||
bool isPistol = RollPistol(availablePistols.Length > 0, availableRifles.Length > 0);
|
||||
var available = isPistol ? availablePistols : availableRifles;
|
||||
|
||||
string newWeapon = available[Instance.Random.Next(available.Length)];
|
||||
bool isPistol = pistols.Contains(newWeapon);
|
||||
|
||||
string? weaponToRemove = null;
|
||||
foreach (var item in pawn.WeaponServices.MyWeapons)
|
||||
|
|
@ -163,9 +168,11 @@ namespace src.player.skills
|
|||
public DateTime Cooldown { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#e0873a", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 15f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#e0873a", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 15f, float pistolChance = 60f, float rifleChance = 40f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public float PistolChance { get; set; } = pistolChance;
|
||||
public float RifleChance { get; set; } = rifleChance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ namespace src.player.skills
|
|||
|
||||
if (!consumedReplicas.TryAdd(replica.Index, 0)) return;
|
||||
|
||||
replica.EmitSound("GlassBottle.BulletImpact", volume: 1f);
|
||||
replica.EmitSound("GlassBottle.BulletImpact", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
var owner = GetReplicaOwner(replica.Index);
|
||||
EntityManager.DestroyEntity(replica.Index);
|
||||
|
|
@ -183,8 +183,9 @@ namespace src.player.skills
|
|||
public DateTime Cooldown { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#a3000b", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = 15f, int yourTeamDamage = 10, int enemyTeamDamage = 20) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#a3000b", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = 15f, int yourTeamDamage = 10, int enemyTeamDamage = 20, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public int YourTeamDamage { get; set; } = yourTeamDamage;
|
||||
public int EnemyTeamDamage { get; set; } = enemyTeamDamage;
|
||||
|
|
|
|||
205
jRandomSkills - SRC Files/src/player/skills/Rewind.cs
Normal file
205
jRandomSkills - SRC Files/src/player/skills/Rewind.cs
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class Rewind : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Rewind;
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
foreach (var skillInfo in SkillPlayerInfo.Values)
|
||||
DestroyMarker(skillInfo);
|
||||
|
||||
SkillPlayerInfo.Clear();
|
||||
}
|
||||
|
||||
public static void RoundEnd()
|
||||
{
|
||||
foreach (var skillInfo in SkillPlayerInfo.Values)
|
||||
DestroyMarker(skillInfo);
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
SkillPlayerInfo[player.Index] = new PlayerSkillInfo
|
||||
{
|
||||
CanUse = true,
|
||||
Cooldown = DateTime.MinValue,
|
||||
};
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null) return;
|
||||
|
||||
if (SkillPlayerInfo.TryRemove(player.Index, out var skillInfo))
|
||||
DestroyMarker(skillInfo);
|
||||
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
if (SkillPlayerInfo.TryRemove(playerIndex, out var skillInfo))
|
||||
DestroyMarker(skillInfo);
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
|
||||
{
|
||||
skillInfo.ReturnTick = 0;
|
||||
DestroyMarker(skillInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UseSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) return;
|
||||
if (!skillInfo.CanUse || skillInfo.ReturnTick != 0) return;
|
||||
|
||||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
|
||||
|
||||
skillInfo.Mark = new Vector(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z);
|
||||
skillInfo.MarkAngle = new QAngle(0, pawn.V_angle.Y, 0);
|
||||
skillInfo.ReturnTick = Server.TickCount + (int)(SkillsInfo.GetValue<float>(skillName, "returnDelay") * 64);
|
||||
skillInfo.CanUse = false;
|
||||
skillInfo.Cooldown = DateTime.Now;
|
||||
|
||||
SpawnMarker(player, skillInfo);
|
||||
SkillUtils.EmitSoundToPlayer(player, "UIPanorama.buttonclick", SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
if (SkillPlayerInfo.IsEmpty) return;
|
||||
|
||||
bool hudFrame = SkillUtils.IsHudFrame();
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) continue;
|
||||
if (PlayerManager.GetPlayerByIndex(player.Index)?.Skill != skillName) continue;
|
||||
|
||||
if (skillInfo.ReturnTick != 0 && Server.TickCount >= skillInfo.ReturnTick)
|
||||
{
|
||||
skillInfo.ReturnTick = 0;
|
||||
Teleport(player, skillInfo);
|
||||
DestroyMarker(skillInfo);
|
||||
}
|
||||
|
||||
if (hudFrame)
|
||||
UpdateHUD(player, skillInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Teleport(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
if (skillInfo.Mark == null) return;
|
||||
|
||||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
|
||||
{
|
||||
skillInfo.Mark = null;
|
||||
return;
|
||||
}
|
||||
|
||||
pawn.Teleport(skillInfo.Mark, skillInfo.MarkAngle, new Vector(0, 0, 0));
|
||||
skillInfo.Mark = null;
|
||||
}
|
||||
|
||||
private static void SpawnMarker(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
if (skillInfo.Mark == null) return;
|
||||
if (EntityManager.OverBudget()) return;
|
||||
|
||||
Color color = Color.White;
|
||||
try { color = ColorTranslator.FromHtml(SkillsInfo.GetValue<string>(skillName, "color")); }
|
||||
catch { }
|
||||
|
||||
Vector bottom = new(skillInfo.Mark.X, skillInfo.Mark.Y, skillInfo.Mark.Z + 2);
|
||||
Vector top = new(skillInfo.Mark.X, skillInfo.Mark.Y, skillInfo.Mark.Z + 68);
|
||||
|
||||
var beam = EntityManager.CreateTrackedBeam(player.Index, bottom, top, color);
|
||||
if (beam == null || !beam.IsValid) return;
|
||||
|
||||
beam.Width = .6f;
|
||||
beam.EndWidth = .6f;
|
||||
|
||||
Utilities.SetStateChanged(beam, "CBeam", "m_fWidth");
|
||||
Utilities.SetStateChanged(beam, "CBeam", "m_fEndWidth");
|
||||
|
||||
skillInfo.MarkerIndex = beam.Index;
|
||||
}
|
||||
|
||||
private static void DestroyMarker(PlayerSkillInfo skillInfo)
|
||||
{
|
||||
if (skillInfo.MarkerIndex == null) return;
|
||||
|
||||
uint markerIndex = skillInfo.MarkerIndex.Value;
|
||||
skillInfo.MarkerIndex = null;
|
||||
|
||||
EntityManager.DestroyBeam(markerIndex);
|
||||
}
|
||||
|
||||
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
float time = (int)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "cooldown")) - DateTime.Now).TotalSeconds);
|
||||
float cooldown = Math.Max(time, 0);
|
||||
|
||||
if (cooldown == 0 && !skillInfo.CanUse)
|
||||
skillInfo.CanUse = true;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
if (playerInfo == null) return;
|
||||
|
||||
if (skillInfo.ReturnTick != 0)
|
||||
{
|
||||
int remaining = (int)Math.Ceiling((skillInfo.ReturnTick - Server.TickCount) / 64f);
|
||||
playerInfo.PrintHTML = $"<font color='#00FF00'>{player.GetTranslation("rewind_pending_info", Math.Max(remaining, 0))}</font>";
|
||||
}
|
||||
else if (cooldown == 0)
|
||||
playerInfo.PrintHTML = null;
|
||||
else
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
|
||||
}
|
||||
|
||||
public class PlayerSkillInfo
|
||||
{
|
||||
public bool CanUse { get; set; }
|
||||
public DateTime Cooldown { get; set; }
|
||||
public Vector? Mark { get; set; }
|
||||
public QAngle? MarkAngle { get; set; }
|
||||
public uint? MarkerIndex { get; set; }
|
||||
public int ReturnTick { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#4fc3f7", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Uncommon, float returnDelay = 4f, float cooldown = 30f, float soundVolume = .5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float ReturnDelay { get; set; } = returnDelay;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ namespace src.player.skills
|
|||
public class Ricochet : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Ricochet;
|
||||
private const string bounceSound = "FX_RicochetSound.Ricochet_Legacy";
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, ImpactBudget> impactBudgets = [];
|
||||
private static readonly HashSet<uint> ownedTracers = [];
|
||||
|
|
@ -57,18 +58,10 @@ namespace src.player.skills
|
|||
|
||||
if (PlayerManager.GetPlayerByIndex(player.Index)?.Skill != skillName) return;
|
||||
|
||||
if (!RayTrace.IsAvailable)
|
||||
{
|
||||
Trace("RayTrace module unavailable");
|
||||
return;
|
||||
}
|
||||
if (!RayTrace.IsAvailable) return;
|
||||
|
||||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
|
||||
{
|
||||
Trace("shooter pawn invalid or dead");
|
||||
return;
|
||||
}
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
if (!TryConsumeBudget(player.Index)) return;
|
||||
|
||||
|
|
@ -76,32 +69,14 @@ namespace src.player.skills
|
|||
Vector3 impact = new(@event.X, @event.Y, @event.Z);
|
||||
|
||||
Vector3 toImpact = impact - eyePos;
|
||||
if (toImpact.LengthSquared() < 1f)
|
||||
{
|
||||
Trace("impact too close to eye");
|
||||
return;
|
||||
}
|
||||
if (toImpact.LengthSquared() < 1f) return;
|
||||
|
||||
Vector3 direction = Vector3.Normalize(toImpact);
|
||||
|
||||
var surface = RayTrace.TraceShape(player, ToVector(eyePos), ToVector(impact + direction * 8f), worldOnlyMask, 0);
|
||||
if (surface == null)
|
||||
{
|
||||
Trace("surface trace returned null");
|
||||
return;
|
||||
}
|
||||
if (surface == null || !surface.Value.DidHit) return;
|
||||
|
||||
if (!surface.Value.DidHit)
|
||||
{
|
||||
Trace($"surface trace missed (fraction={surface.Value.Fraction:0.###})");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryResolveNormal(player, surface.Value, direction, out Vector3 normal))
|
||||
{
|
||||
Trace("could not resolve surface normal");
|
||||
return;
|
||||
}
|
||||
if (!TryResolveNormal(player, surface.Value, direction, out Vector3 normal)) return;
|
||||
|
||||
Bounce(player, pawn, surface.Value.EndPos, direction, normal);
|
||||
}
|
||||
|
|
@ -118,31 +93,28 @@ namespace src.player.skills
|
|||
KillfeedIcons? killfeedIcon = KillfeedIconsExtensions.FromWeaponName(SkillUtils.GetDesignerName(pawn.WeaponServices?.ActiveWeapon?.Value));
|
||||
|
||||
List<Vector3> path = [];
|
||||
List<int> soundAt = [];
|
||||
|
||||
for (int i = 0; i < bounces; i++)
|
||||
{
|
||||
direction = Vector3.Reflect(direction, normal);
|
||||
|
||||
Vector3 start = point + normal * 2f;
|
||||
if (path.Count == 0) path.Add(start);
|
||||
if (path.Count == 0)
|
||||
{
|
||||
path.Add(start);
|
||||
soundAt.Add(0);
|
||||
}
|
||||
|
||||
Vector3 end = start + direction * segmentDistance;
|
||||
|
||||
var hit = RayTrace.TraceShape(player, ToVector(start), ToVector(end));
|
||||
if (hit == null)
|
||||
{
|
||||
Trace($"bounce {i + 1}: segment trace returned null");
|
||||
break;
|
||||
}
|
||||
if (hit == null) break;
|
||||
|
||||
Vector3 stop = hit.Value.DidHit ? hit.Value.EndPos : end;
|
||||
path.Add(stop);
|
||||
|
||||
if (!hit.Value.DidHit)
|
||||
{
|
||||
Trace($"bounce {i + 1}: no surface, len={Vector3.Distance(start, stop):0.#}");
|
||||
break;
|
||||
}
|
||||
if (!hit.Value.DidHit) break;
|
||||
|
||||
if (hit.Value.HitPlayer(out var victim))
|
||||
{
|
||||
|
|
@ -150,17 +122,14 @@ namespace src.player.skills
|
|||
break;
|
||||
}
|
||||
|
||||
if (!TryResolveNormal(player, hit.Value, direction, out normal))
|
||||
{
|
||||
Trace($"bounce {i + 1}: could not resolve normal");
|
||||
break;
|
||||
}
|
||||
if (!TryResolveNormal(player, hit.Value, direction, out normal)) break;
|
||||
|
||||
soundAt.Add(path.Count - 1);
|
||||
point = hit.Value.EndPos;
|
||||
damage *= damageFalloff;
|
||||
}
|
||||
|
||||
StartFlight(player, path);
|
||||
StartFlight(player, path, soundAt);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
|
|
@ -191,11 +160,12 @@ namespace src.player.skills
|
|||
float tail = MathF.Max(head - trail, flight.Cumulative[segment]);
|
||||
|
||||
UpdateTracer(flight, PointAt(flight, tail), PointAt(flight, head));
|
||||
EmitBounceSound(flight, tail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void StartFlight(CCSPlayerController player, List<Vector3> path)
|
||||
private static void StartFlight(CCSPlayerController player, List<Vector3> path, List<int> soundAt)
|
||||
{
|
||||
if (path.Count < 2) return;
|
||||
if (!SkillsInfo.GetValue<bool>(skillName, "showTracer")) return;
|
||||
|
|
@ -223,10 +193,27 @@ namespace src.player.skills
|
|||
Cumulative = cumulative,
|
||||
TotalLength = total,
|
||||
DeadlineTick = Server.TickCount + (int)(total / speed * 64f) + 128,
|
||||
SoundAt = [.. soundAt.Where(index => index < points.Length)],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitBounceSound(Flight flight, float tail)
|
||||
{
|
||||
if (flight.NextSound >= flight.SoundAt.Length) return;
|
||||
if (tail < flight.Cumulative[flight.SoundAt[flight.NextSound]]) return;
|
||||
|
||||
while (flight.NextSound < flight.SoundAt.Length && tail >= flight.Cumulative[flight.SoundAt[flight.NextSound]])
|
||||
flight.NextSound++;
|
||||
|
||||
if (flight.BeamIndex == null) return;
|
||||
|
||||
var beam = ResolveTracer(flight.BeamIndex.Value);
|
||||
if (beam == null) return;
|
||||
|
||||
beam.EmitSound(bounceSound, volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
|
||||
private static int SegmentAt(Flight flight, float distance)
|
||||
{
|
||||
for (int i = flight.Points.Length - 2; i >= 0; i--)
|
||||
|
|
@ -332,9 +319,8 @@ namespace src.player.skills
|
|||
beam.DispatchSpawn();
|
||||
return beam;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
Trace($"beam create failed: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -352,7 +338,6 @@ namespace src.player.skills
|
|||
if (beam == null)
|
||||
{
|
||||
ownedTracers.Remove(beamIndex);
|
||||
Trace($"tracer {beamIndex} vanished before release");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -395,9 +380,6 @@ namespace src.player.skills
|
|||
if (beam != null) HideTracer(beam);
|
||||
}
|
||||
|
||||
if (ownedTracers.Count > 0)
|
||||
Trace($"pool reset: {ownedTracers.Count} tracer(s) released");
|
||||
|
||||
tracerPool.Clear();
|
||||
ownedTracers.Clear();
|
||||
}
|
||||
|
|
@ -454,7 +436,6 @@ namespace src.player.skills
|
|||
int finalDamage = (int)MathF.Round(damage);
|
||||
if (finalDamage <= 0) return;
|
||||
|
||||
Trace($"hit {victimEvent.PlayerName} for {finalDamage}");
|
||||
SkillUtils.TakeHealth(victimPawn, finalDamage, attacker, killfeedIcon ?? KillfeedIcons.Leg);
|
||||
}
|
||||
|
||||
|
|
@ -466,7 +447,6 @@ namespace src.player.skills
|
|||
|
||||
if (TryRefineNormal(player, result.EndPos, direction, rough, out normal)) return true;
|
||||
|
||||
Trace("surface refine failed, using rough normal");
|
||||
normal = rough;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -600,11 +580,6 @@ namespace src.player.skills
|
|||
return Vector3.Distance(point, baseHit) <= tolerance;
|
||||
}
|
||||
|
||||
private static void Trace(string message)
|
||||
{
|
||||
Debug.WriteToDebug($"[Ricochet] {message}");
|
||||
}
|
||||
|
||||
private static bool TryConsumeBudget(uint playerIndex)
|
||||
{
|
||||
int tick = Server.TickCount;
|
||||
|
|
@ -637,12 +612,15 @@ namespace src.player.skills
|
|||
public required float[] Cumulative { get; set; }
|
||||
public required float TotalLength { get; set; }
|
||||
public required int DeadlineTick { get; set; }
|
||||
public required int[] SoundAt { get; set; }
|
||||
public float Travelled { get; set; }
|
||||
public int NextSound { get; set; }
|
||||
public uint? BeamIndex { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffd75e", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Rare, int bounces = 3, float segmentDistance = 1200f, float damageMultiplier = .5f, float fallbackDamage = 25f, bool respectArmor = true, float damageFalloff = .75f, int maxImpactsPerTick = 2, bool showTracer = true, float tracerWidth = 0.5f, float tracerSpeed = 2600f, float tracerLength = 220f, int maxActiveTracers = 12, float normalProbeOffset = 6f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ffd75e", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Rare, int bounces = 3, float segmentDistance = 1200f, float damageMultiplier = .5f, float fallbackDamage = 25f, bool respectArmor = true, float damageFalloff = .75f, int maxImpactsPerTick = 2, bool showTracer = true, float tracerWidth = 0.5f, float tracerSpeed = 2600f, float tracerLength = 220f, int maxActiveTracers = 12, float normalProbeOffset = 6f, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int Bounces { get; set; } = bounces;
|
||||
public float SegmentDistance { get; set; } = segmentDistance;
|
||||
public float DamageMultiplier { get; set; } = damageMultiplier;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ namespace src.player.skills
|
|||
if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return;
|
||||
var attackerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
||||
|
||||
if (Heavyweight.Resists(victim)) return;
|
||||
|
||||
var victimPawn = victim!.PlayerPawn.Value;
|
||||
if (victimPawn == null || !victimPawn.IsValid) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,7 @@ namespace src.player.skills
|
|||
private static readonly object setLock = new();
|
||||
|
||||
private const string weapon_awp = "weapon_awp";
|
||||
private static readonly string[] rifles =
|
||||
[
|
||||
"weapon_mp9", "weapon_mac10", "weapon_bizon", "weapon_mp7", "weapon_ump45", "weapon_p90",
|
||||
"weapon_mp5sd", "weapon_famas", "weapon_galilar", "weapon_m4a1", "weapon_m4a1_silencer", "weapon_ak47",
|
||||
"weapon_aug", "weapon_sg556", "weapon_ssg08", "weapon_awp", "weapon_scar20", "weapon_g3sg1",
|
||||
"weapon_nova", "weapon_xm1014", "weapon_mag7", "weapon_sawedoff", "weapon_m249", "weapon_negev"
|
||||
];
|
||||
private static HashSet<string> rifles => WeaponPool.Rifles;
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
|
|
@ -81,7 +75,7 @@ namespace src.player.skills
|
|||
foreach (var index in AWPs.ToList())
|
||||
SkillUtils.SafeKillEntity<CBasePlayerWeapon>(index);
|
||||
|
||||
if (savedWeapons.TryGetValue(player.Index, out string? savedWeapon) && !string.IsNullOrWhiteSpace(savedWeapon))
|
||||
if (!SkillUtils.IsPistolRound() && savedWeapons.TryGetValue(player.Index, out string? savedWeapon) && !string.IsNullOrWhiteSpace(savedWeapon))
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
if (player == null || !player.IsValid || player.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
||||
|
|
|
|||
|
|
@ -100,9 +100,13 @@ namespace src.player.skills
|
|||
{
|
||||
if (SkillPlayerInfo.IsEmpty) return;
|
||||
|
||||
if (Server.TickCount % 60 != 0) return;
|
||||
|
||||
int cooldown = SkillsInfo.GetValue<int>(skillName, "cooldown");
|
||||
if (cooldown < 1) cooldown = 1;
|
||||
if (Server.TickCount % (60 * cooldown) != 0) return;
|
||||
if ((Server.TickCount / 60) % cooldown != 0) return;
|
||||
|
||||
float volume = SkillsInfo.GetValue<float>(skillName, "soundVolume");
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers()
|
||||
.Where(p => p != null && p.IsValid && p.PlayerPawn.Value != null && p.PlayerPawn.Value.IsValid && p.PlayerPawn.Value.Health > 0))
|
||||
|
|
@ -111,18 +115,19 @@ namespace src.player.skills
|
|||
|
||||
if (entities.Count == 0)
|
||||
{
|
||||
player.PlayerPawn.Value!.EmitSound(soundEventName, volume: 1f);
|
||||
player.PlayerPawn.Value!.EmitSound(soundEventName, volume: volume);
|
||||
continue;
|
||||
}
|
||||
|
||||
var entity = Utilities.GetEntityFromIndex<CDynamicProp>((int)entities[0]);
|
||||
if (entity != null && entity.IsValid)
|
||||
entity.EmitSound(soundEventName, volume: 1f);
|
||||
entity.EmitSound(soundEventName, volume: volume);
|
||||
}
|
||||
}
|
||||
|
||||
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? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int cooldown = 2) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
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? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int cooldown = 2, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int Cooldown { get; set; } = cooldown;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ namespace src.player.skills
|
|||
SetMagazines(player, playerMagazines + enemyMagazines);
|
||||
SetMagazines(enemy, 0);
|
||||
|
||||
PlayerManager.GetPlayerFromEvent(enemy)?.ExecuteClientCommand($"play sounds/weapons/g3sg1/g3sg1_clipout");
|
||||
player.PlayerPawn?.Value?.EmitSound("BaseCombatCharacter.AmmoPickup", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
||||
if (enemyEvent == null || !enemyEvent.IsValid) return;
|
||||
|
|
@ -299,8 +299,9 @@ namespace src.player.skills
|
|||
public required int Reserve { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#5eb8b0", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 30f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#5eb8b0", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float cooldown = 30f, float soundVolume = 1f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,12 +40,13 @@ namespace src.player.skills
|
|||
damage = Math.Min(damage, SkillsInfo.GetValue<int>(skillName, "maxTakenDamagePerShot"));
|
||||
|
||||
SkillUtils.TakeHealth(attackerEvent.PlayerPawn.Value, damage, victimEvent, KillfeedIcons.Armor);
|
||||
attackerEvent.EmitSound("Player.DamageBody.Onlooker");
|
||||
SkillUtils.EmitSoundToPlayer(attackerEvent, "Player.DamageBody.Victim", SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#962631", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float healthTakenScale = .3f, int maxTakenDamagePerShot = 37) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#962631", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, float healthTakenScale = .3f, int maxTakenDamagePerShot = 37, float soundVolume = .35f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float HealthTakenScale { get; set; } = healthTakenScale;
|
||||
public int MaxTakenDamagePerShot { get; set; } = maxTakenDamagePerShot;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ namespace src.player.skills
|
|||
}
|
||||
|
||||
if (SkillUtils.TakeHealth(pawn, damage, thrower, KillfeedIcons.Smokegrenade))
|
||||
player.EmitSound("Player.DamageBody.Onlooker");
|
||||
SkillUtils.EmitSoundToPlayer(eventPlayer, "Player.DamageBody.Victim", SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -170,8 +170,9 @@ namespace src.player.skills
|
|||
SkillUtils.UpdateGrenadeCount(player, CsItem.SmokeGrenade, 1);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#507529", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int smokeDamage = 2, float smokeRadius = 180, int tickCooldown = 17, int grenadeLimit = 1, float dmgReductionForTeamates = 0.5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#507529", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Common, int smokeDamage = 2, float smokeRadius = 180, int tickCooldown = 17, int grenadeLimit = 1, float dmgReductionForTeamates = 0.5f, float soundVolume = .3f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int SmokeDamage { get; set; } = smokeDamage;
|
||||
public float SmokeRadius { get; set; } = smokeRadius;
|
||||
public int TickCooldown { get; set; } = tickCooldown;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace src.player.skills
|
|||
public class Tripwire : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Tripwire;
|
||||
private const string triggerSound = "Weapon_Taser.ChargeReady";
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, WireInfo> wires = [];
|
||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||
|
|
@ -267,7 +268,7 @@ namespace src.player.skills
|
|||
var ownerEvent = PlayerManager.GetPlayerFromEvent(owner);
|
||||
if (ownerEvent != null && ownerEvent.IsValid)
|
||||
{
|
||||
ownerEvent.ExecuteClientCommand("play sounds/weapons/taser/taser_charge_ready");
|
||||
SkillUtils.EmitSoundToPlayer(ownerEvent, triggerSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
ownerEvent.PrintToChat($" {ChatColors.Red}" + ownerEvent.GetTranslation("tripwire_triggered_info", enemyEvent.PlayerName));
|
||||
}
|
||||
}
|
||||
|
|
@ -314,8 +315,9 @@ namespace src.player.skills
|
|||
public DateTime LastAttempt { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff3b3b", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, float radarDuration = 5f, float triggerRadius = 24f, float wireHeight = 30f, float wireWidth = 0.7f, float maxWallDistance = 400f, float cooldown = 20f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff3b3b", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, float radarDuration = 5f, float triggerRadius = 24f, float wireHeight = 30f, float wireWidth = 0.7f, float maxWallDistance = 400f, float cooldown = 20f, float soundVolume = .5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public float RadarDuration { get; set; } = radarDuration;
|
||||
public float TriggerRadius { get; set; } = triggerRadius;
|
||||
public float WireHeight { get; set; } = wireHeight;
|
||||
|
|
|
|||
116
jRandomSkills - SRC Files/src/player/skills/TrueArmor.cs
Normal file
116
jRandomSkills - SRC Files/src/player/skills/TrueArmor.cs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class TrueArmor : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.TrueArmor;
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, byte> holders = [];
|
||||
private static readonly ConcurrentDictionary<uint, int> pending = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
pending.Clear();
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
holders[player.Index] = 0;
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null) return;
|
||||
holders.TryRemove(player.Index, out _);
|
||||
pending.TryRemove(player.Index, out _);
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
holders.TryRemove(playerIndex, out _);
|
||||
pending.TryRemove(playerIndex, out _);
|
||||
}
|
||||
|
||||
public static void OnTakeDamage(DynamicHook h)
|
||||
{
|
||||
if (holders.IsEmpty) return;
|
||||
|
||||
if (!TryResolveVictim(h, out var victim, out var victimPawn, out var info)) return;
|
||||
if (!holders.ContainsKey(victim!.Index)) return;
|
||||
|
||||
int armor = victimPawn!.ArmorValue;
|
||||
if (armor <= 0) return;
|
||||
|
||||
float damage = info!.Damage;
|
||||
if (damage <= 0) return;
|
||||
|
||||
float ratio = SkillsInfo.GetValue<float>(skillName, "armorShare");
|
||||
float absorbed = MathF.Min(damage * ratio, armor);
|
||||
if (absorbed <= 0) return;
|
||||
|
||||
info.Damage = damage - absorbed;
|
||||
|
||||
pending[victim.Index] = (int)MathF.Round(armor - absorbed);
|
||||
victimPawn.ArmorValue = 0;
|
||||
|
||||
Utilities.SetStateChanged(victimPawn, "CCSPlayerPawn", "m_ArmorValue");
|
||||
|
||||
Debug.WriteToDebug($"[TrueArmor] {victim.PlayerName}: raw={damage:0.#} absorbed={absorbed:0.#} " +
|
||||
$"passed={info.Damage:0.#} armor={armor}->{pending[victim.Index]} hp={victimPawn.Health}");
|
||||
}
|
||||
|
||||
public static void OnTakeDamagePost(DynamicHook h)
|
||||
{
|
||||
if (pending.IsEmpty) return;
|
||||
|
||||
if (!TryResolveVictim(h, out var victim, out var victimPawn, out _)) return;
|
||||
if (!pending.TryRemove(victim!.Index, out int restored)) return;
|
||||
|
||||
victimPawn!.ArmorValue = restored;
|
||||
Utilities.SetStateChanged(victimPawn, "CCSPlayerPawn", "m_ArmorValue");
|
||||
}
|
||||
|
||||
private static bool TryResolveVictim(DynamicHook h, out CCSPlayerController? victim, out CCSPlayerPawn? pawn, out CTakeDamageInfo? info)
|
||||
{
|
||||
victim = null;
|
||||
pawn = null;
|
||||
info = null;
|
||||
|
||||
CEntityInstance param = h.GetParam<CEntityInstance>(0);
|
||||
CTakeDamageInfo param2 = h.GetParam<CTakeDamageInfo>(1);
|
||||
if (param == null || !param.IsValid || param2 == null) return false;
|
||||
|
||||
var victimPawn = param.As<CCSPlayerPawn>();
|
||||
if (victimPawn == null || !victimPawn.IsValid || victimPawn.DesignerName != "player") return false;
|
||||
|
||||
var controller = victimPawn.Controller.Value;
|
||||
if (controller == null || !controller.IsValid) return false;
|
||||
|
||||
var resolved = controller.As<CCSPlayerController>();
|
||||
if (resolved == null || !resolved.IsValid) return false;
|
||||
|
||||
var routed = PlayerManager.GetPlayerEvent(resolved);
|
||||
victim = routed != null && routed.IsValid ? routed : resolved;
|
||||
pawn = victimPawn;
|
||||
info = param2;
|
||||
return true;
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#9ad3f5", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Uncommon, float armorShare = .33f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float ArmorShare { get; set; } = armorShare;
|
||||
}
|
||||
}
|
||||
}
|
||||
157
jRandomSkills - SRC Files/src/player/skills/Voodoo.cs
Normal file
157
jRandomSkills - SRC Files/src/player/skills/Voodoo.cs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class Voodoo : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Voodoo;
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, uint> ownerToVictim = [];
|
||||
private static readonly ConcurrentDictionary<uint, byte> reflecting = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
ownerToVictim.Clear();
|
||||
reflecting.Clear();
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public static void PlayerDisconnect(uint playerIndex)
|
||||
{
|
||||
ownerToVictim.TryRemove(playerIndex, out _);
|
||||
reflecting.TryRemove(playerIndex, out _);
|
||||
|
||||
foreach (var kvp in ownerToVictim)
|
||||
if (kvp.Value == playerIndex)
|
||||
ownerToVictim.TryRemove(kvp.Key, out _);
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null) return;
|
||||
playerInfo.SkillUsed = false;
|
||||
|
||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||
if (playerEvent == null || !playerEvent.IsValid) return;
|
||||
|
||||
var enemies = SkillUtils.GetSelectableEnemies(player, true);
|
||||
if (enemies.Length > 0)
|
||||
{
|
||||
ConcurrentBag<(string, string)> menuItems = new(enemies.Select(e => (e.PlayerName, e.Index.ToString())));
|
||||
SkillUtils.CreateMenu(player, menuItems);
|
||||
}
|
||||
else
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
ownerToVictim.TryRemove(player.Index, out _);
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
if (Server.TickCount % 32 != 0) return;
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null || playerInfo.Skill != skillName) continue;
|
||||
if (!SkillUtils.HasMenu(player)) continue;
|
||||
|
||||
var enemies = SkillUtils.GetSelectableEnemies(player, true);
|
||||
|
||||
ConcurrentBag<(string, string)> menuItems = new(enemies.Select(e => (e.PlayerName, e.Index.ToString())));
|
||||
SkillUtils.UpdateMenu(player, menuItems);
|
||||
}
|
||||
}
|
||||
|
||||
public static void TypeSkill(CCSPlayerController player, string[] commands)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||
if (playerEvent == null || !playerEvent.IsValid) return;
|
||||
|
||||
if (playerInfo.SkillUsed)
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("areareaper_used_info")}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (commands.Length == 0 || !uint.TryParse(commands[0], out uint enemyIndex))
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
return;
|
||||
}
|
||||
|
||||
var enemy = Utilities.GetPlayerFromIndex((int)enemyIndex);
|
||||
if (enemy == null || !enemy.IsValid)
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}{playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index")}");
|
||||
return;
|
||||
}
|
||||
|
||||
ownerToVictim[player.Index] = enemy.Index;
|
||||
playerInfo.SkillUsed = true;
|
||||
|
||||
playerEvent.PrintToChat($" {ChatColors.Green}{playerEvent.GetTranslation("voodoo_player_info", enemy.PlayerName)}");
|
||||
}
|
||||
|
||||
public static void PlayerHurt(EventPlayerHurt @event)
|
||||
{
|
||||
if (ownerToVictim.IsEmpty) return;
|
||||
|
||||
var owner = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (owner == null || !owner.IsValid) return;
|
||||
|
||||
if (!ownerToVictim.TryGetValue(owner.Index, out uint victimIndex)) return;
|
||||
if (@event.DmgHealth <= 0) return;
|
||||
|
||||
if (!reflecting.TryAdd(owner.Index, 0)) return;
|
||||
|
||||
try
|
||||
{
|
||||
var victim = Utilities.GetPlayerFromIndex((int)victimIndex);
|
||||
if (victim == null || !victim.IsValid) return;
|
||||
|
||||
var victimPawn = victim.PlayerPawn?.Value;
|
||||
if (victimPawn == null || !victimPawn.IsValid || victimPawn.Health <= 0) return;
|
||||
if (victimPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
||||
|
||||
int reflected = (int)MathF.Round(@event.DmgHealth * SkillsInfo.GetValue<float>(skillName, "reflectPercent"));
|
||||
if (reflected < 1) return;
|
||||
|
||||
SkillUtils.TakeHealth(victimPawn, reflected, owner, KillfeedIcons.Fist);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reflecting.TryRemove(owner.Index, out _);
|
||||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#7b2d8b", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Rare, float reflectPercent = .5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float ReflectPercent { get; set; } = reflectPercent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,15 +50,16 @@ namespace src.player.skills
|
|||
else
|
||||
Localization.PrintTranslationToChatAll($" {ChatColors.LightBlue}{{0}}", ["watchmaker_ct"], true, [roundTime]);
|
||||
|
||||
player.EmitSound(SkillsInfo.GetValue<string>(skillName, "SoundEvent"));
|
||||
SkillUtils.EmitSoundToPlayer(player, SkillsInfo.GetValue<string>(skillName, "SoundEvent"), SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||
|
||||
var proxy = Utilities.FindAllEntitiesByDesignerName<CCSGameRulesProxy>("cs_gamerules").FirstOrDefault();
|
||||
if (proxy == null) return;
|
||||
Utilities.SetStateChanged(proxy, "CCSGameRulesProxy", "m_pGameRules");
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff462e", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 1, Rarity rarity = Rarity.Common, int changeRoundTime = 7, string soundEvent = "UIPanorama.sidemenu_select") : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff462e", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 1, Rarity rarity = Rarity.Common, int changeRoundTime = 7, string soundEvent = "UIPanorama.sidemenu_select", float soundVolume = .5f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float SoundVolume { get; set; } = soundVolume;
|
||||
public int ChangeRoundTime { get; set; } = changeRoundTime;
|
||||
public string SoundEvent { get; set; } = soundEvent;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,7 @@ namespace src.player.skills
|
|||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||
private static readonly object setLock = new();
|
||||
|
||||
private static readonly HashSet<string> weapons = [ "weapon_deagle", "weapon_revolver", "weapon_glock", "weapon_usp_silencer",
|
||||
"weapon_cz75a", "weapon_fiveseven", "weapon_p250", "weapon_tec9", "weapon_elite", "weapon_hkp2000",
|
||||
"weapon_mp9", "weapon_mac10", "weapon_bizon", "weapon_mp7", "weapon_ump45", "weapon_p90", "weapon_sg556",
|
||||
"weapon_mp5sd", "weapon_famas", "weapon_galilar", "weapon_m4a4", "weapon_m4a1_silencer", "weapon_ak47",
|
||||
"weapon_aug", "weapon_sg556", "weapon_ssg08", "weapon_awp", "weapon_scar20", "weapon_g3sg1",
|
||||
"weapon_nova", "weapon_xm1014", "weapon_mag7", "weapon_sawedoff", "weapon_m249", "weapon_negev" ];
|
||||
private static HashSet<string> weapons => WeaponPool.All;
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue