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
|
|
@ -31,7 +31,7 @@ namespace src
|
||||||
public override string ModuleName => "[CS2] [ jRandomSkills ]";
|
public override string ModuleName => "[CS2] [ jRandomSkills ]";
|
||||||
public override string ModuleAuthor => "D3X (Original), Juzlus (Modifier), ByDexterTR (Contributor)";
|
public override string ModuleAuthor => "D3X (Original), Juzlus (Modifier), ByDexterTR (Contributor)";
|
||||||
public override string ModuleDescription => "Plugin adds random skills every round for CS2 by D3X. Modified by Juzlus.";
|
public override string ModuleDescription => "Plugin adds random skills every round for CS2 by D3X. Modified by Juzlus.";
|
||||||
public override string ModuleVersion => "1.2.3.b5";
|
public override string ModuleVersion => "1.2.3.b6";
|
||||||
|
|
||||||
public override void Load(bool hotReload)
|
public override void Load(bool hotReload)
|
||||||
{
|
{
|
||||||
|
|
@ -371,6 +371,18 @@ namespace src
|
||||||
public int HideHUD { get; set; }
|
public int HideHUD { get; set; }
|
||||||
public bool SkillUsed = false;
|
public bool SkillUsed = false;
|
||||||
public bool? HudOnDeathBlocked { get; set; }
|
public bool? HudOnDeathBlocked { get; set; }
|
||||||
|
public HudCacheEntry? HudCache { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class HudCacheEntry
|
||||||
|
{
|
||||||
|
public uint PlayerIndex;
|
||||||
|
public object? Config;
|
||||||
|
public string? Header;
|
||||||
|
public string? Center;
|
||||||
|
public string? Extra;
|
||||||
|
public bool IsDescription;
|
||||||
|
public string? Content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class jSkill_SkillInfo(Skills skill, string color, bool display)
|
public class jSkill_SkillInfo(Skills skill, string color, bool display)
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Explosivschuss",
|
"blastshot": "Explosivschuss",
|
||||||
"blastshot_desc": "Drücke Attack2 mit der MP5, um eine HE-Granate abzufeuern",
|
"blastshot_desc": "Drücke Attack2 mit der MP5, um eine HE-Granate abzufeuern",
|
||||||
|
|
||||||
|
"bounty": "Kopfgeld",
|
||||||
|
"bounty_desc": "Setze ein Kopfgeld auf einen Gegner aus; wer ihn tötet, bekommt das Geld",
|
||||||
|
"bounty_select_info": "Wähle einen Spieler:",
|
||||||
|
"bounty_player_info": "Du hast {1}$ Kopfgeld auf '{0}' ausgesetzt.",
|
||||||
|
"bounty_enemy_info": "Auf deinen Kopf wurden {0}$ ausgesetzt.",
|
||||||
|
"bounty_claimed_info": "Du hast '{0}' getötet und {1}$ kassiert.",
|
||||||
|
|
||||||
"bunnyhop": "Hase",
|
"bunnyhop": "Hase",
|
||||||
"bunnyhop_desc": "Du erhältst automatisch bunnyhop",
|
"bunnyhop_desc": "Du erhältst automatisch bunnyhop",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Zufällige Charaktergröße zu Beginn der Runde",
|
"dwarf_desc": "Zufällige Charaktergröße zu Beginn der Runde",
|
||||||
"dwarf_desc2": "Dein Größenmultiplikator beträgt: {0}x",
|
"dwarf_desc2": "Dein Größenmultiplikator beträgt: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "EMP-Granate",
|
||||||
|
"empgrenade_desc": "Wer von deiner Granate getroffen wird, verliert kurzzeitig Radar und Fadenkreuz",
|
||||||
|
"empgrenade_enemy_info": "Eine EMP-Granate hat dein Radar und Fadenkreuz lahmgelegt.",
|
||||||
|
|
||||||
"enemyspawn": "Feindes-Spawn",
|
"enemyspawn": "Feindes-Spawn",
|
||||||
"enemyspawn_desc": "Klicke auf [css_useSkill], um zum Feindes-Spawn zu teleportieren",
|
"enemyspawn_desc": "Klicke auf [css_useSkill], um zum Feindes-Spawn zu teleportieren",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Keine Oberfläche zum Einhaken.",
|
"grapple_no_anchor_info": "Keine Oberfläche zum Einhaken.",
|
||||||
"grapple_pulling_info": "ZUG",
|
"grapple_pulling_info": "ZUG",
|
||||||
|
|
||||||
|
"gravitydecoy": "Schwerkraft-Ablenker",
|
||||||
|
"gravitydecoy_desc": "Dein Ablenkungsköder verändert die Schwerkraft aller in der Nähe",
|
||||||
|
|
||||||
"grenadier": "Grenadier",
|
"grenadier": "Grenadier",
|
||||||
"grenadier_desc": "Du hast unendlich viele Granaten",
|
"grenadier_desc": "Du hast unendlich viele Granaten",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingchicken": "Heilendes Huhn",
|
"healingchicken": "Heilendes Huhn",
|
||||||
"healingchicken_desc": "Deine Hühner heilen dich, solange du in ihrer Nähe bist",
|
"healingchicken_desc": "Deine Hühner heilen dich, solange du in ihrer Nähe bist",
|
||||||
|
|
||||||
|
"heavyweight": "Schwergewicht",
|
||||||
|
"heavyweight_desc": "Fähigkeiten, die dich stoßen oder verlangsamen, wirken nicht auf dich",
|
||||||
|
|
||||||
"hermit": "Einsiedler",
|
"hermit": "Einsiedler",
|
||||||
"hermit_desc": "Durch das Töten von Gegnern werden Munition und ein Teil der Gesundheit wiederhergestellt",
|
"hermit_desc": "Durch das Töten von Gegnern werden Munition und ein Teil der Gesundheit wiederhergestellt",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"bankrupt_player_info": "Der Spieler ‚{0}‘ ist bankrott.",
|
"bankrupt_player_info": "Der Spieler ‚{0}‘ ist bankrott.",
|
||||||
"bankrupt_select_info": "Wähle einen Spieler aus, der bankrott gehen soll:",
|
"bankrupt_select_info": "Wähle einen Spieler aus, der bankrott gehen soll:",
|
||||||
|
|
||||||
|
"nemesis": "Nemesis",
|
||||||
|
"nemesis_desc": "Der von dir markierte Spieler erleidet zusätzlichen Schaden",
|
||||||
|
"nemesis_select_info": "Wähle einen Spieler:",
|
||||||
|
"nemesis_player_info": "Du hast '{0}' markiert.",
|
||||||
|
"nemesis_enemy_info": "Du wurdest als Nemesis markiert und erleidest jetzt von allen zusätzlichen Schaden.",
|
||||||
|
|
||||||
"nightmare": "Albtraum",
|
"nightmare": "Albtraum",
|
||||||
"nightmare_desc": "Lass einen ausgewählten Gegner eine schreckliche Vision erleben",
|
"nightmare_desc": "Lass einen ausgewählten Gegner eine schreckliche Vision erleben",
|
||||||
"nightmare_disable_info": "Der Albtraum ist vorbei.",
|
"nightmare_disable_info": "Der Albtraum ist vorbei.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Prothese",
|
"prosthesis": "Prothese",
|
||||||
"prosthesis_desc": "Arme und Beine sind kugelsicher",
|
"prosthesis_desc": "Arme und Beine sind kugelsicher",
|
||||||
|
|
||||||
|
"punisher": "Bestrafer",
|
||||||
|
"punisher_desc": "Du sammelst einen Teil des erlittenen Schadens und legst ihn auf deinen nächsten Treffer",
|
||||||
|
"punisher_released_info": "Du hast {0} zusätzlichen Schaden verursacht und ebenso viel Leben erhalten.",
|
||||||
|
|
||||||
"push": "Pusher",
|
"push": "Pusher",
|
||||||
"push_desc": "Du hast eine zufällige Chance, einen Gegner zurückzustoßen, wenn du ihn triffst",
|
"push_desc": "Du hast eine zufällige Chance, einen Gegner zurückzustoßen, wenn du ihn triffst",
|
||||||
"push_desc2": "Deine Chancen, den Gegner zurückzustoßen, betragen: {0} %",
|
"push_desc2": "Deine Chancen, den Gegner zurückzustoßen, betragen: {0} %",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Zurück zum Absender",
|
"returntosender": "Zurück zum Absender",
|
||||||
"returntosender_desc": "Der erste Treffer eines Gegners schickt ihn zurück zu seinem Spawn",
|
"returntosender_desc": "Der erste Treffer eines Gegners schickt ihn zurück zu seinem Spawn",
|
||||||
|
|
||||||
|
"rewind": "Rückspulen",
|
||||||
|
"rewind_desc": "Drücke [css_useSkill], um hier eine Marke zu setzen und kurz darauf dorthin zurückzukehren",
|
||||||
|
"rewind_pending_info": "RÜCKKEHR: {0}",
|
||||||
|
|
||||||
"richboy": "Rich Boy",
|
"richboy": "Rich Boy",
|
||||||
"richboy_desc": "Du erhältst zu Beginn der Runde einen zufälligen Geldbetrag",
|
"richboy_desc": "Du erhältst zu Beginn der Runde einen zufälligen Geldbetrag",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Stolperdraht platziert.",
|
"tripwire_placed_info": "Stolperdraht platziert.",
|
||||||
"tripwire_triggered_info": "'{0}' hat deinen Stolperdraht ausgelöst.",
|
"tripwire_triggered_info": "'{0}' hat deinen Stolperdraht ausgelöst.",
|
||||||
|
|
||||||
|
"truearmor": "Echte Rüstung",
|
||||||
|
"truearmor_desc": "Ein Teil des Schadens geht auf deine Rüstung statt auf dein Leben",
|
||||||
|
|
||||||
|
"voodoo": "Voodoo",
|
||||||
|
"voodoo_desc": "Der markierte Gegner erleidet einen Teil des Schadens, den du erleidest",
|
||||||
|
"voodoo_select_info": "Wähle einen Spieler:",
|
||||||
|
"voodoo_player_info": "Du hast '{0}' an deinen Voodoo gebunden.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Du kannst Feinde durch Wände hindurch sehen",
|
"wallhack_desc": "Du kannst Feinde durch Wände hindurch sehen",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Blast Shot",
|
"blastshot": "Blast Shot",
|
||||||
"blastshot_desc": "Press Attack2 with the MP5 to fire an HE grenade",
|
"blastshot_desc": "Press Attack2 with the MP5 to fire an HE grenade",
|
||||||
|
|
||||||
|
"bounty": "Bounty",
|
||||||
|
"bounty_desc": "Put a price on an enemy's head; whoever kills them takes the money",
|
||||||
|
"bounty_select_info": "Choose a player:",
|
||||||
|
"bounty_player_info": "You put a {1}$ bounty on '{0}'.",
|
||||||
|
"bounty_enemy_info": "A {0}$ bounty was placed on your head.",
|
||||||
|
"bounty_claimed_info": "You killed '{0}' and claimed {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Bunny",
|
"bunnyhop": "Bunny",
|
||||||
"bunnyhop_desc": "You get auto \"BunnyHop\"",
|
"bunnyhop_desc": "You get auto \"BunnyHop\"",
|
||||||
|
|
||||||
|
|
@ -137,6 +144,10 @@
|
||||||
"dwarf_desc": "Random character size at the start of the round",
|
"dwarf_desc": "Random character size at the start of the round",
|
||||||
"dwarf_desc2": "Your size multiplier is: {0}x",
|
"dwarf_desc2": "Your size multiplier is: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "EMP Grenade",
|
||||||
|
"empgrenade_desc": "Anyone hurt by your grenade loses their radar and crosshair for a while",
|
||||||
|
"empgrenade_enemy_info": "An EMP grenade knocked out your radar and crosshair.",
|
||||||
|
|
||||||
"enemyspawn": "Enemy Spawn",
|
"enemyspawn": "Enemy Spawn",
|
||||||
"enemyspawn_desc": "Click [css_useSkill] to teleport to the enemy spawn",
|
"enemyspawn_desc": "Click [css_useSkill] to teleport to the enemy spawn",
|
||||||
|
|
||||||
|
|
@ -223,6 +234,9 @@
|
||||||
"grapple_no_anchor_info": "No surface to hook onto.",
|
"grapple_no_anchor_info": "No surface to hook onto.",
|
||||||
"grapple_pulling_info": "PULLING",
|
"grapple_pulling_info": "PULLING",
|
||||||
|
|
||||||
|
"gravitydecoy": "Gravity Decoy",
|
||||||
|
"gravitydecoy_desc": "Your decoy changes the gravity of everyone nearby",
|
||||||
|
|
||||||
"grenadier": "Grenadier",
|
"grenadier": "Grenadier",
|
||||||
"grenadier_desc": "You have infinite hegrenade",
|
"grenadier_desc": "You have infinite hegrenade",
|
||||||
|
|
||||||
|
|
@ -232,6 +246,9 @@
|
||||||
"healingsmoke": "Healing Smoke",
|
"healingsmoke": "Healing Smoke",
|
||||||
"healingsmoke_desc": "Your smoke grenades heal",
|
"healingsmoke_desc": "Your smoke grenades heal",
|
||||||
|
|
||||||
|
"heavyweight": "Heavyweight",
|
||||||
|
"heavyweight_desc": "Skills that push or slow you down have no effect on you",
|
||||||
|
|
||||||
"hermit": "Hermit",
|
"hermit": "Hermit",
|
||||||
"hermit_desc": "Killing restores ammo and a portion of health",
|
"hermit_desc": "Killing restores ammo and a portion of health",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"demoneye": "Demon Eye",
|
"demoneye": "Demon Eye",
|
||||||
"demoneye_desc": "You deal damage to every enemy you are looking at",
|
"demoneye_desc": "You deal damage to every enemy you are looking at",
|
||||||
|
|
||||||
|
"nemesis": "Nemesis",
|
||||||
|
"nemesis_desc": "The player you mark takes extra damage",
|
||||||
|
"nemesis_select_info": "Choose a player:",
|
||||||
|
"nemesis_player_info": "You marked '{0}'.",
|
||||||
|
"nemesis_enemy_info": "You have been marked as a nemesis, you now take extra damage from everyone.",
|
||||||
|
|
||||||
"nightmare": "Nightmare",
|
"nightmare": "Nightmare",
|
||||||
"nightmare_desc": "Force a chosen enemy to experience a terrifying vision",
|
"nightmare_desc": "Force a chosen enemy to experience a terrifying vision",
|
||||||
"nightmare_disable_info": "The nightmare has faded.",
|
"nightmare_disable_info": "The nightmare has faded.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Prosthesis",
|
"prosthesis": "Prosthesis",
|
||||||
"prosthesis_desc": "Arms and legs are bulletproof",
|
"prosthesis_desc": "Arms and legs are bulletproof",
|
||||||
|
|
||||||
|
"punisher": "Punisher",
|
||||||
|
"punisher_desc": "You bank part of the damage you take and add it to your next hit",
|
||||||
|
"punisher_released_info": "You dealt {0} extra damage and healed for the same amount.",
|
||||||
|
|
||||||
"push": "Pusher",
|
"push": "Pusher",
|
||||||
"push_desc": "You have a random chance to push an enemy back when hitting them",
|
"push_desc": "You have a random chance to push an enemy back when hitting them",
|
||||||
"push_desc2": "Your chances of pushing back the enemy are: {0}%",
|
"push_desc2": "Your chances of pushing back the enemy are: {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Return to Sender",
|
"returntosender": "Return to Sender",
|
||||||
"returntosender_desc": "The first hit on an enemy sends them back to their spawn",
|
"returntosender_desc": "The first hit on an enemy sends them back to their spawn",
|
||||||
|
|
||||||
|
"rewind": "Rewind",
|
||||||
|
"rewind_desc": "Click [css_useSkill] to drop a marker where you stand and return to it shortly after",
|
||||||
|
"rewind_pending_info": "RETURN: {0}",
|
||||||
|
|
||||||
"richboy": "Rich Boy",
|
"richboy": "Rich Boy",
|
||||||
"richboy_desc": "You receive a random amount of money at the start of the round",
|
"richboy_desc": "You receive a random amount of money at the start of the round",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Tripwire placed.",
|
"tripwire_placed_info": "Tripwire placed.",
|
||||||
"tripwire_triggered_info": "'{0}' triggered your tripwire.",
|
"tripwire_triggered_info": "'{0}' triggered your tripwire.",
|
||||||
|
|
||||||
|
"truearmor": "True Armor",
|
||||||
|
"truearmor_desc": "Part of the damage you take is paid by your armor instead of your health",
|
||||||
|
|
||||||
|
"voodoo": "Voodoo",
|
||||||
|
"voodoo_desc": "The enemy you mark also takes part of the damage you take",
|
||||||
|
"voodoo_select_info": "Choose a player:",
|
||||||
|
"voodoo_player_info": "You bound '{0}' to your voodoo.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "You can see enemies through walls",
|
"wallhack_desc": "You can see enemies through walls",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Tir explosif",
|
"blastshot": "Tir explosif",
|
||||||
"blastshot_desc": "Appuyez sur Attack2 avec le MP5 pour tirer une grenade HE",
|
"blastshot_desc": "Appuyez sur Attack2 avec le MP5 pour tirer une grenade HE",
|
||||||
|
|
||||||
|
"bounty": "Prime",
|
||||||
|
"bounty_desc": "Mets une prime sur la tête d'un ennemi ; celui qui le tue empoche l'argent",
|
||||||
|
"bounty_select_info": "Choisis un joueur :",
|
||||||
|
"bounty_player_info": "Tu as mis une prime de {1}$ sur '{0}'.",
|
||||||
|
"bounty_enemy_info": "Une prime de {0}$ a été mise sur ta tête.",
|
||||||
|
"bounty_claimed_info": "Tu as tué '{0}' et empoché {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Lapin",
|
"bunnyhop": "Lapin",
|
||||||
"bunnyhop_desc": "Vous obtenez l’auto « BunnyHop »",
|
"bunnyhop_desc": "Vous obtenez l’auto « BunnyHop »",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Taille du personnage aléatoire au début du round",
|
"dwarf_desc": "Taille du personnage aléatoire au début du round",
|
||||||
"dwarf_desc2": "Votre multiplicateur de taille est : {0}x",
|
"dwarf_desc2": "Votre multiplicateur de taille est : {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "Grenade EMP",
|
||||||
|
"empgrenade_desc": "Ceux que ta grenade blesse perdent leur radar et leur viseur un moment",
|
||||||
|
"empgrenade_enemy_info": "Une grenade EMP a coupé ton radar et ton viseur.",
|
||||||
|
|
||||||
"enemyspawn": "Spawn Ennemi",
|
"enemyspawn": "Spawn Ennemi",
|
||||||
"enemyspawn_desc": "Appuyez sur [css_useSkill] pour vous téléporter au spawn ennemi",
|
"enemyspawn_desc": "Appuyez sur [css_useSkill] pour vous téléporter au spawn ennemi",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Aucune surface pour accrocher le grappin.",
|
"grapple_no_anchor_info": "Aucune surface pour accrocher le grappin.",
|
||||||
"grapple_pulling_info": "TRACTION",
|
"grapple_pulling_info": "TRACTION",
|
||||||
|
|
||||||
|
"gravitydecoy": "Leurre gravitationnel",
|
||||||
|
"gravitydecoy_desc": "Ton leurre modifie la gravité de tous ceux qui sont à proximité",
|
||||||
|
|
||||||
"grenadier": "Grenadier",
|
"grenadier": "Grenadier",
|
||||||
"grenadier_desc": "Tu as des grenades HE infinies",
|
"grenadier_desc": "Tu as des grenades HE infinies",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingchicken": "Poulet guérisseur",
|
"healingchicken": "Poulet guérisseur",
|
||||||
"healingchicken_desc": "Vos poulets vous soignent lorsque vous êtes à proximité",
|
"healingchicken_desc": "Vos poulets vous soignent lorsque vous êtes à proximité",
|
||||||
|
|
||||||
|
"heavyweight": "Poids lourd",
|
||||||
|
"heavyweight_desc": "Les compétences qui te poussent ou te ralentissent n'ont aucun effet sur toi",
|
||||||
|
|
||||||
"hermit": "Ermite",
|
"hermit": "Ermite",
|
||||||
"hermit_desc": "Tuer restaure des munitions et une partie de vos PV",
|
"hermit_desc": "Tuer restaure des munitions et une partie de vos PV",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"bankrupt_player_info": "Le joueur « {0} » est en faillite.",
|
"bankrupt_player_info": "Le joueur « {0} » est en faillite.",
|
||||||
"bankrupt_select_info": "Mettre un joueur en faillite :",
|
"bankrupt_select_info": "Mettre un joueur en faillite :",
|
||||||
|
|
||||||
|
"nemesis": "Némésis",
|
||||||
|
"nemesis_desc": "Le joueur que tu marques subit des dégâts supplémentaires",
|
||||||
|
"nemesis_select_info": "Choisis un joueur :",
|
||||||
|
"nemesis_player_info": "Tu as marqué '{0}'.",
|
||||||
|
"nemesis_enemy_info": "Vous avez été marqué comme némésis, vous subissez désormais des dégâts supplémentaires de la part de tous.",
|
||||||
|
|
||||||
"nightmare": "Cauchemar",
|
"nightmare": "Cauchemar",
|
||||||
"nightmare_desc": "Faites subir une vision terrifiante à un ennemi choisi",
|
"nightmare_desc": "Faites subir une vision terrifiante à un ennemi choisi",
|
||||||
"nightmare_disable_info": "Le cauchemar s'est dissipé.",
|
"nightmare_disable_info": "Le cauchemar s'est dissipé.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Prothèses",
|
"prosthesis": "Prothèses",
|
||||||
"prosthesis_desc": "Les bras et les jambes sont pare-balles",
|
"prosthesis_desc": "Les bras et les jambes sont pare-balles",
|
||||||
|
|
||||||
|
"punisher": "Punisseur",
|
||||||
|
"punisher_desc": "Tu accumules une partie des dégâts subis et l'ajoutes à ton prochain tir",
|
||||||
|
"punisher_released_info": "Tu as infligé {0} dégâts en plus et récupéré autant de vie.",
|
||||||
|
|
||||||
"push": "Pousseur",
|
"push": "Pousseur",
|
||||||
"push_desc": "Vous avez une chance aléatoire de repousser un ennemi en le touchant",
|
"push_desc": "Vous avez une chance aléatoire de repousser un ennemi en le touchant",
|
||||||
"push_desc2": "Votre chance de repousser l’ennemi est : {0}%",
|
"push_desc2": "Votre chance de repousser l’ennemi est : {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Retour à l’Expéditeur",
|
"returntosender": "Retour à l’Expéditeur",
|
||||||
"returntosender_desc": "Le premier coup porté à un ennemi le renvoie à son spawn",
|
"returntosender_desc": "Le premier coup porté à un ennemi le renvoie à son spawn",
|
||||||
|
|
||||||
|
"rewind": "Rembobinage",
|
||||||
|
"rewind_desc": "Appuie sur [css_useSkill] pour poser un repère ici et y revenir peu après",
|
||||||
|
"rewind_pending_info": "RETOUR : {0}",
|
||||||
|
|
||||||
"richboy": "Gosse de Riche",
|
"richboy": "Gosse de Riche",
|
||||||
"richboy_desc": "Vous recevez une somme d’argent aléatoire au début du round",
|
"richboy_desc": "Vous recevez une somme d’argent aléatoire au début du round",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Fil-piège placé.",
|
"tripwire_placed_info": "Fil-piège placé.",
|
||||||
"tripwire_triggered_info": "'{0}' a déclenché votre fil-piège.",
|
"tripwire_triggered_info": "'{0}' a déclenché votre fil-piège.",
|
||||||
|
|
||||||
|
"truearmor": "Vraie armure",
|
||||||
|
"truearmor_desc": "Une partie des dégâts est absorbée par ton armure au lieu de ta vie",
|
||||||
|
|
||||||
|
"voodoo": "Vaudou",
|
||||||
|
"voodoo_desc": "L'ennemi que tu marques subit aussi une partie des dégâts que tu reçois",
|
||||||
|
"voodoo_select_info": "Choisis un joueur :",
|
||||||
|
"voodoo_player_info": "Tu as lié '{0}' à ton vaudou.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Vous pouvez voir les ennemis à travers les murs",
|
"wallhack_desc": "Vous pouvez voir les ennemis à travers les murs",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Mocne Uderzenie",
|
"blastshot": "Mocne Uderzenie",
|
||||||
"blastshot_desc": "Naciśnij Attack2 na MP5, aby wystrzelić granat HE",
|
"blastshot_desc": "Naciśnij Attack2 na MP5, aby wystrzelić granat HE",
|
||||||
|
|
||||||
|
"bounty": "Nagroda",
|
||||||
|
"bounty_desc": "Wyznacz nagrodę za głowę wroga; kto go zabije, dostaje pieniądze",
|
||||||
|
"bounty_select_info": "Wybierz gracza:",
|
||||||
|
"bounty_player_info": "Wyznaczyłeś nagrodę {1}$ za '{0}'.",
|
||||||
|
"bounty_enemy_info": "Za twoją głowę wyznaczono {0}$.",
|
||||||
|
"bounty_claimed_info": "Zabiłeś '{0}' i zgarnąłeś {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Królik",
|
"bunnyhop": "Królik",
|
||||||
"bunnyhop_desc": "Otrzymujesz auto \"BunnyHopa\"",
|
"bunnyhop_desc": "Otrzymujesz auto \"BunnyHopa\"",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Losowa wielkość postaci na początku rundy",
|
"dwarf_desc": "Losowa wielkość postaci na początku rundy",
|
||||||
"dwarf_desc2": "Twój mnożnik wielkości to {0}x",
|
"dwarf_desc2": "Twój mnożnik wielkości to {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "Granat EMP",
|
||||||
|
"empgrenade_desc": "Kto oberwie twoim granatem, na chwilę traci radar i celownik",
|
||||||
|
"empgrenade_enemy_info": "Granat EMP wyłączył twój radar i celownik.",
|
||||||
|
|
||||||
"enemyspawn": "Resp Wroga",
|
"enemyspawn": "Resp Wroga",
|
||||||
"enemyspawn_desc": "Kliknij [css_useSkill], aby teleportować się na resp wroga",
|
"enemyspawn_desc": "Kliknij [css_useSkill], aby teleportować się na resp wroga",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Brak powierzchni do zaczepienia haka.",
|
"grapple_no_anchor_info": "Brak powierzchni do zaczepienia haka.",
|
||||||
"grapple_pulling_info": "PRZYCIĄGANIE",
|
"grapple_pulling_info": "PRZYCIĄGANIE",
|
||||||
|
|
||||||
|
"gravitydecoy": "Grawitacyjna wabik",
|
||||||
|
"gravitydecoy_desc": "Twój wabik zmienia grawitację wszystkich w pobliżu",
|
||||||
|
|
||||||
"grenadier": "Granatnik",
|
"grenadier": "Granatnik",
|
||||||
"grenadier_desc": "Masz nieskończone granaty odłamkowe",
|
"grenadier_desc": "Masz nieskończone granaty odłamkowe",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingchicken": "Lecząca Kura",
|
"healingchicken": "Lecząca Kura",
|
||||||
"healingchicken_desc": "Twoje kury leczą Cię, gdy jesteś w pobliżu",
|
"healingchicken_desc": "Twoje kury leczą Cię, gdy jesteś w pobliżu",
|
||||||
|
|
||||||
|
"heavyweight": "Waga ciężka",
|
||||||
|
"heavyweight_desc": "Umiejętności, które cię popychają lub spowalniają, nie działają na ciebie",
|
||||||
|
|
||||||
"hermit": "Pustelnik",
|
"hermit": "Pustelnik",
|
||||||
"hermit_desc": "Zabijanie przywraca amunicję i część zdrowia",
|
"hermit_desc": "Zabijanie przywraca amunicję i część zdrowia",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"moneyswap_player_info": "Wymieniłeś swoje pieniądze z graczem '{0}'.",
|
"moneyswap_player_info": "Wymieniłeś swoje pieniądze z graczem '{0}'.",
|
||||||
"moneyswap_select_info": "Zamień się kasą z graczem:",
|
"moneyswap_select_info": "Zamień się kasą z graczem:",
|
||||||
|
|
||||||
|
"nemesis": "Nemezis",
|
||||||
|
"nemesis_desc": "Oznaczony gracz otrzymuje dodatkowe obrażenia",
|
||||||
|
"nemesis_select_info": "Wybierz gracza:",
|
||||||
|
"nemesis_player_info": "Oznaczyłeś '{0}'.",
|
||||||
|
"nemesis_enemy_info": "Zostałeś oznaczony jako nemezis, teraz otrzymujesz dodatkowe obrażenia od wszystkich.",
|
||||||
|
|
||||||
"nightmare": "Koszmar",
|
"nightmare": "Koszmar",
|
||||||
"nightmare_desc": "Wywołaj u wybranego przeciwnika przerażającą wizję",
|
"nightmare_desc": "Wywołaj u wybranego przeciwnika przerażającą wizję",
|
||||||
"nightmare_disable_info": "Koszmar minął.",
|
"nightmare_disable_info": "Koszmar minął.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Proteza",
|
"prosthesis": "Proteza",
|
||||||
"prosthesis_desc": "Ramiona i nogi są kuloodporne",
|
"prosthesis_desc": "Ramiona i nogi są kuloodporne",
|
||||||
|
|
||||||
|
"punisher": "Karzyciel",
|
||||||
|
"punisher_desc": "Gromadzisz część otrzymanych obrażeń i dodajesz je do następnego trafienia",
|
||||||
|
"punisher_released_info": "Zadałeś {0} dodatkowych obrażeń i odzyskałeś tyle samo życia.",
|
||||||
|
|
||||||
"push": "Odpychacz",
|
"push": "Odpychacz",
|
||||||
"push_desc": "Masz losową szansę na odepchnięcie wroga po trafieniu go",
|
"push_desc": "Masz losową szansę na odepchnięcie wroga po trafieniu go",
|
||||||
"push_desc2": "Twoje szanse na odepchnięcie wroga to: {0}%",
|
"push_desc2": "Twoje szanse na odepchnięcie wroga to: {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Zwrot do Nadawcy",
|
"returntosender": "Zwrot do Nadawcy",
|
||||||
"returntosender_desc": "Pierwsze trafienie wroga powoduje, że wraca on na swój resp",
|
"returntosender_desc": "Pierwsze trafienie wroga powoduje, że wraca on na swój resp",
|
||||||
|
|
||||||
|
"rewind": "Przewijanie",
|
||||||
|
"rewind_desc": "Naciśnij [css_useSkill], aby zostawić znacznik i wkrótce do niego wrócić",
|
||||||
|
"rewind_pending_info": "POWRÓT: {0}",
|
||||||
|
|
||||||
"richboy": "Bogacz",
|
"richboy": "Bogacz",
|
||||||
"richboy_desc": "Na początku rundy otrzymujesz losową kwotę gotówki",
|
"richboy_desc": "Na początku rundy otrzymujesz losową kwotę gotówki",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Linka została rozstawiona.",
|
"tripwire_placed_info": "Linka została rozstawiona.",
|
||||||
"tripwire_triggered_info": "'{0}' uruchomił Twoją linkę.",
|
"tripwire_triggered_info": "'{0}' uruchomił Twoją linkę.",
|
||||||
|
|
||||||
|
"truearmor": "Prawdziwy pancerz",
|
||||||
|
"truearmor_desc": "Część obrażeń pokrywa twój pancerz zamiast zdrowia",
|
||||||
|
|
||||||
|
"voodoo": "Voodoo",
|
||||||
|
"voodoo_desc": "Oznaczony wróg również otrzymuje część obrażeń, które ty dostajesz",
|
||||||
|
"voodoo_select_info": "Wybierz gracza:",
|
||||||
|
"voodoo_player_info": "Związałeś '{0}' swoim voodoo.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Widzisz wrogów przez ściany",
|
"wallhack_desc": "Widzisz wrogów przez ściany",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Tiro Explosivo",
|
"blastshot": "Tiro Explosivo",
|
||||||
"blastshot_desc": "Pressione Attack2 com a MP5 para disparar uma granada HE",
|
"blastshot_desc": "Pressione Attack2 com a MP5 para disparar uma granada HE",
|
||||||
|
|
||||||
|
"bounty": "Recompensa",
|
||||||
|
"bounty_desc": "Coloque um preço na cabeça de um inimigo; quem o matar leva o dinheiro",
|
||||||
|
"bounty_select_info": "Escolha um jogador:",
|
||||||
|
"bounty_player_info": "Você colocou {1}$ de recompensa em '{0}'.",
|
||||||
|
"bounty_enemy_info": "Puseram {0}$ de recompensa na sua cabeça.",
|
||||||
|
"bounty_claimed_info": "Você matou '{0}' e levou {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Coelho",
|
"bunnyhop": "Coelho",
|
||||||
"bunnyhop_desc": "Você ganha \"BunnyHop\" automático",
|
"bunnyhop_desc": "Você ganha \"BunnyHop\" automático",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Sua altura agora é aleatória",
|
"dwarf_desc": "Sua altura agora é aleatória",
|
||||||
"dwarf_desc2": "Seu multiplicador de altura é: {0}x",
|
"dwarf_desc2": "Seu multiplicador de altura é: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "Granada EMP",
|
||||||
|
"empgrenade_desc": "Quem se ferir com sua granada perde o radar e a mira por um tempo",
|
||||||
|
"empgrenade_enemy_info": "Uma granada EMP derrubou seu radar e sua mira.",
|
||||||
|
|
||||||
"enemyspawn": "Spawn Inimigo",
|
"enemyspawn": "Spawn Inimigo",
|
||||||
"enemyspawn_desc": "Clique em [css_useSkill] para se teletransportar para a base inimiga",
|
"enemyspawn_desc": "Clique em [css_useSkill] para se teletransportar para a base inimiga",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Nenhuma superfície para prender o gancho.",
|
"grapple_no_anchor_info": "Nenhuma superfície para prender o gancho.",
|
||||||
"grapple_pulling_info": "PUXANDO",
|
"grapple_pulling_info": "PUXANDO",
|
||||||
|
|
||||||
|
"gravitydecoy": "Chamariz Gravitacional",
|
||||||
|
"gravitydecoy_desc": "Seu chamariz muda a gravidade de todos que estão por perto",
|
||||||
|
|
||||||
"grenadier": "Bomberman",
|
"grenadier": "Bomberman",
|
||||||
"grenadier_desc": "Você tem HEs infinitas",
|
"grenadier_desc": "Você tem HEs infinitas",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingchicken": "Galinha Curadora",
|
"healingchicken": "Galinha Curadora",
|
||||||
"healingchicken_desc": "Suas galinhas curam você enquanto você estiver por perto",
|
"healingchicken_desc": "Suas galinhas curam você enquanto você estiver por perto",
|
||||||
|
|
||||||
|
"heavyweight": "Peso Pesado",
|
||||||
|
"heavyweight_desc": "Habilidades que empurram ou te deixam lento não fazem efeito em você",
|
||||||
|
|
||||||
"hermit": "Sanguessuga",
|
"hermit": "Sanguessuga",
|
||||||
"hermit_desc": "Matar restaura munição e uma parte da sua vida",
|
"hermit_desc": "Matar restaura munição e uma parte da sua vida",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"moneyswap_player_info": "Você trocou dinheiro com o jogador '{0}'.",
|
"moneyswap_player_info": "Você trocou dinheiro com o jogador '{0}'.",
|
||||||
"moneyswap_select_info": "Trocar dinheiro c/ jogador:",
|
"moneyswap_select_info": "Trocar dinheiro c/ jogador:",
|
||||||
|
|
||||||
|
"nemesis": "Nêmesis",
|
||||||
|
"nemesis_desc": "O jogador que você marcar recebe dano extra",
|
||||||
|
"nemesis_select_info": "Escolha um jogador:",
|
||||||
|
"nemesis_player_info": "Você marcou '{0}'.",
|
||||||
|
"nemesis_enemy_info": "Você foi marcado como nêmesis, agora recebe dano extra de todos.",
|
||||||
|
|
||||||
"nightmare": "Pesadelo",
|
"nightmare": "Pesadelo",
|
||||||
"nightmare_desc": "Faça um inimigo escolhido ter uma visão aterrorizante",
|
"nightmare_desc": "Faça um inimigo escolhido ter uma visão aterrorizante",
|
||||||
"nightmare_disable_info": "O pesadelo desapareceu.",
|
"nightmare_disable_info": "O pesadelo desapareceu.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Prótese",
|
"prosthesis": "Prótese",
|
||||||
"prosthesis_desc": "Braços e pernas são à prova de balas",
|
"prosthesis_desc": "Braços e pernas são à prova de balas",
|
||||||
|
|
||||||
|
"punisher": "Punidor",
|
||||||
|
"punisher_desc": "Você guarda parte do dano recebido e soma no seu próximo tiro",
|
||||||
|
"punisher_released_info": "Você causou {0} de dano extra e recuperou a mesma vida.",
|
||||||
|
|
||||||
"push": "Empurrão",
|
"push": "Empurrão",
|
||||||
"push_desc": "Você tem uma chance aleatória de empurrar um inimigo ao acertá-lo",
|
"push_desc": "Você tem uma chance aleatória de empurrar um inimigo ao acertá-lo",
|
||||||
"push_desc2": "Suas chances de empurrar o inimigo são: {0}%",
|
"push_desc2": "Suas chances de empurrar o inimigo são: {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Devolução ao Remetente",
|
"returntosender": "Devolução ao Remetente",
|
||||||
"returntosender_desc": "O primeiro tiro em um inimigo o envia de volta a sua base",
|
"returntosender_desc": "O primeiro tiro em um inimigo o envia de volta a sua base",
|
||||||
|
|
||||||
|
"rewind": "Retroceder",
|
||||||
|
"rewind_desc": "Clique em [css_useSkill] para deixar uma marca aqui e voltar a ela logo depois",
|
||||||
|
"rewind_pending_info": "RETORNO: {0}",
|
||||||
|
|
||||||
"richboy": "Filhinho de Papai",
|
"richboy": "Filhinho de Papai",
|
||||||
"richboy_desc": "Você recebe uma quantidade aleatória de dinheiro no início da rodada",
|
"richboy_desc": "Você recebe uma quantidade aleatória de dinheiro no início da rodada",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Fio de armadilha colocado.",
|
"tripwire_placed_info": "Fio de armadilha colocado.",
|
||||||
"tripwire_triggered_info": "'{0}' acionou seu fio.",
|
"tripwire_triggered_info": "'{0}' acionou seu fio.",
|
||||||
|
|
||||||
|
"truearmor": "Armadura Real",
|
||||||
|
"truearmor_desc": "Parte do dano que você recebe sai do colete em vez da vida",
|
||||||
|
|
||||||
|
"voodoo": "Vodu",
|
||||||
|
"voodoo_desc": "O inimigo que você marcar também recebe parte do dano que você leva",
|
||||||
|
"voodoo_select_info": "Escolha um jogador:",
|
||||||
|
"voodoo_player_info": "Você ligou '{0}' ao seu vodu.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Você pode ver inimigos através das paredes",
|
"wallhack_desc": "Você pode ver inimigos através das paredes",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Взрывной выстрел",
|
"blastshot": "Взрывной выстрел",
|
||||||
"blastshot_desc": "Нажмите Attack2 на MP5, чтобы выстрелить гранатой HE",
|
"blastshot_desc": "Нажмите Attack2 на MP5, чтобы выстрелить гранатой HE",
|
||||||
|
|
||||||
|
"bounty": "Награда",
|
||||||
|
"bounty_desc": "Назначь награду за голову врага; тот, кто убьёт его, получит деньги",
|
||||||
|
"bounty_select_info": "Выберите игрока:",
|
||||||
|
"bounty_player_info": "Вы назначили награду {1}$ за '{0}'.",
|
||||||
|
"bounty_enemy_info": "За вашу голову назначили {0}$.",
|
||||||
|
"bounty_claimed_info": "Вы убили '{0}' и получили {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Заяц",
|
"bunnyhop": "Заяц",
|
||||||
"bunnyhop_desc": "Вы получаете автоматический «БанниХоп»",
|
"bunnyhop_desc": "Вы получаете автоматический «БанниХоп»",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Случайный размер персонажа в начале раунда",
|
"dwarf_desc": "Случайный размер персонажа в начале раунда",
|
||||||
"dwarf_desc2": "Ваш множитель размера: {0}x",
|
"dwarf_desc2": "Ваш множитель размера: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "ЭМИ-граната",
|
||||||
|
"empgrenade_desc": "Тот, кто пострадал от вашей гранаты, на время теряет радар и прицел",
|
||||||
|
"empgrenade_enemy_info": "ЭМИ-граната вывела из строя ваш радар и прицел.",
|
||||||
|
|
||||||
"enemyspawn": "Спавн врагов",
|
"enemyspawn": "Спавн врагов",
|
||||||
"enemyspawn_desc": "Нажмите [css_useSkill], чтобы телепортироваться на спавн врагов",
|
"enemyspawn_desc": "Нажмите [css_useSkill], чтобы телепортироваться на спавн врагов",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Нет поверхности для зацепа.",
|
"grapple_no_anchor_info": "Нет поверхности для зацепа.",
|
||||||
"grapple_pulling_info": "ПРИТЯГИВАНИЕ",
|
"grapple_pulling_info": "ПРИТЯГИВАНИЕ",
|
||||||
|
|
||||||
|
"gravitydecoy": "Гравитационная обманка",
|
||||||
|
"gravitydecoy_desc": "Ваша обманка меняет гравитацию всех, кто рядом",
|
||||||
|
|
||||||
"grenadier": "Гренадёр",
|
"grenadier": "Гренадёр",
|
||||||
"grenadier_desc": "У вас бесконечные осколочные гранаты",
|
"grenadier_desc": "У вас бесконечные осколочные гранаты",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingsmoke": "Лечащий дым",
|
"healingsmoke": "Лечащий дым",
|
||||||
"healingsmoke_desc": "Ваши дымовые гранаты лечат",
|
"healingsmoke_desc": "Ваши дымовые гранаты лечат",
|
||||||
|
|
||||||
|
"heavyweight": "Тяжеловес",
|
||||||
|
"heavyweight_desc": "Способности, которые толкают или замедляют, на вас не действуют",
|
||||||
|
|
||||||
"hermit": "Отшельник",
|
"hermit": "Отшельник",
|
||||||
"hermit_desc": "Убийства восстанавливают боеприпасы и часть здоровья",
|
"hermit_desc": "Убийства восстанавливают боеприпасы и часть здоровья",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"moneyswap_player_info": "Вы обменялись деньгами с игроком '{0}'.",
|
"moneyswap_player_info": "Вы обменялись деньгами с игроком '{0}'.",
|
||||||
"moneyswap_select_info": "Обменять деньги с игроком:",
|
"moneyswap_select_info": "Обменять деньги с игроком:",
|
||||||
|
|
||||||
|
"nemesis": "Немезида",
|
||||||
|
"nemesis_desc": "Отмеченный вами игрок получает больше урона",
|
||||||
|
"nemesis_select_info": "Выберите игрока:",
|
||||||
|
"nemesis_player_info": "Вы отметили '{0}'.",
|
||||||
|
"nemesis_enemy_info": "Вы отмечены как немезида и теперь получаете больше урона от всех.",
|
||||||
|
|
||||||
"nightmare": "Кошмар",
|
"nightmare": "Кошмар",
|
||||||
"nightmare_desc": "Заставьте выбранного противника увидеть кошмарное видение",
|
"nightmare_desc": "Заставьте выбранного противника увидеть кошмарное видение",
|
||||||
"nightmare_disable_info": "Кошмар рассеялся.",
|
"nightmare_disable_info": "Кошмар рассеялся.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Протез",
|
"prosthesis": "Протез",
|
||||||
"prosthesis_desc": "Руки и ноги защищены от пуль",
|
"prosthesis_desc": "Руки и ноги защищены от пуль",
|
||||||
|
|
||||||
|
"punisher": "Каратель",
|
||||||
|
"punisher_desc": "Вы копите часть полученного урона и добавляете его к следующему попаданию",
|
||||||
|
"punisher_released_info": "Вы нанесли {0} дополнительного урона и восстановили столько же здоровья.",
|
||||||
|
|
||||||
"push": "Толкач",
|
"push": "Толкач",
|
||||||
"push_desc": "Есть шанс оттолкнуть врага назад при попадании",
|
"push_desc": "Есть шанс оттолкнуть врага назад при попадании",
|
||||||
"push_desc2": "Ваш шанс оттолкнуть врага: {0}%",
|
"push_desc2": "Ваш шанс оттолкнуть врага: {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Вернуть отправителю",
|
"returntosender": "Вернуть отправителю",
|
||||||
"returntosender_desc": "Первое попадание по врагу отправляет его обратно на спавн",
|
"returntosender_desc": "Первое попадание по врагу отправляет его обратно на спавн",
|
||||||
|
|
||||||
|
"rewind": "Перемотка",
|
||||||
|
"rewind_desc": "Нажмите [css_useSkill], чтобы оставить метку здесь и вскоре вернуться к ней",
|
||||||
|
"rewind_pending_info": "ВОЗВРАТ: {0}",
|
||||||
|
|
||||||
"richboy": "Богач",
|
"richboy": "Богач",
|
||||||
"richboy_desc": "Вы получаете случайную сумму денег в начале раунда",
|
"richboy_desc": "Вы получаете случайную сумму денег в начале раунда",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Растяжка установлена.",
|
"tripwire_placed_info": "Растяжка установлена.",
|
||||||
"tripwire_triggered_info": "'{0}' задел вашу растяжку.",
|
"tripwire_triggered_info": "'{0}' задел вашу растяжку.",
|
||||||
|
|
||||||
|
"truearmor": "Настоящая броня",
|
||||||
|
"truearmor_desc": "Часть урона принимает броня, а не здоровье",
|
||||||
|
|
||||||
|
"voodoo": "Вуду",
|
||||||
|
"voodoo_desc": "Отмеченный враг тоже получает часть урона, который получаете вы",
|
||||||
|
"voodoo_select_info": "Выберите игрока:",
|
||||||
|
"voodoo_player_info": "Вы привязали '{0}' к своему вуду.",
|
||||||
|
|
||||||
"wallhack": "Воллхак",
|
"wallhack": "Воллхак",
|
||||||
"wallhack_desc": "Вы видите врагов сквозь стены",
|
"wallhack_desc": "Вы видите врагов сквозь стены",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Patlama Atışı",
|
"blastshot": "Patlama Atışı",
|
||||||
"blastshot_desc": "MP5 ile sağ tıklayarak el bombası fırlat",
|
"blastshot_desc": "MP5 ile sağ tıklayarak el bombası fırlat",
|
||||||
|
|
||||||
|
"bounty": "Ödül Avı",
|
||||||
|
"bounty_desc": "Bir düşmana ödül koy, onu öldüren parayı alır",
|
||||||
|
"bounty_select_info": "Birini seçin:",
|
||||||
|
"bounty_player_info": "'{0}' için {1}$ ödül koydun.",
|
||||||
|
"bounty_enemy_info": "Başına {0}$ ödül kondu.",
|
||||||
|
"bounty_claimed_info": "'{0}' oyuncusunu öldürdün ve {1}$ kazandın.",
|
||||||
|
|
||||||
"bunnyhop": "Tavşan",
|
"bunnyhop": "Tavşan",
|
||||||
"bunnyhop_desc": "Otomatik BunnyHop yaparsın",
|
"bunnyhop_desc": "Otomatik BunnyHop yaparsın",
|
||||||
|
|
||||||
|
|
@ -137,6 +144,10 @@
|
||||||
"dwarf_desc": "Rastgele karakter boyutu",
|
"dwarf_desc": "Rastgele karakter boyutu",
|
||||||
"dwarf_desc2": "Boyutun: {0}x",
|
"dwarf_desc2": "Boyutun: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "EMP Bombası",
|
||||||
|
"empgrenade_desc": "El bomban, hasar verdiğin düşmanın radarını ve nişangahını kapatır",
|
||||||
|
"empgrenade_enemy_info": "Radarın ve nişangahın kapandı.",
|
||||||
|
|
||||||
"enemyspawn": "Base Baskını",
|
"enemyspawn": "Base Baskını",
|
||||||
"enemyspawn_desc": "[css_useSkill] tuşuna basarak düşman doğma noktasına ışınlan",
|
"enemyspawn_desc": "[css_useSkill] tuşuna basarak düşman doğma noktasına ışınlan",
|
||||||
|
|
||||||
|
|
@ -223,6 +234,9 @@
|
||||||
"grapple_no_anchor_info": "Kanca atılacak yüzey yok",
|
"grapple_no_anchor_info": "Kanca atılacak yüzey yok",
|
||||||
"grapple_pulling_info": "ÇEKİLİYOR",
|
"grapple_pulling_info": "ÇEKİLİYOR",
|
||||||
|
|
||||||
|
"gravitydecoy": "Yerçekimi Yanıltıcısı",
|
||||||
|
"gravitydecoy_desc": "Yanıltıcı bomban yakındaki herkesin yerçekimini değiştirir",
|
||||||
|
|
||||||
"grenadier": "Bombacı",
|
"grenadier": "Bombacı",
|
||||||
"grenadier_desc": "El bomban sınırsız",
|
"grenadier_desc": "El bomban sınırsız",
|
||||||
|
|
||||||
|
|
@ -232,6 +246,9 @@
|
||||||
"healingsmoke": "Şifalı Sis",
|
"healingsmoke": "Şifalı Sis",
|
||||||
"healingsmoke_desc": "Sis bomban iyileştirir",
|
"healingsmoke_desc": "Sis bomban iyileştirir",
|
||||||
|
|
||||||
|
"heavyweight": "Ağır Sıklet",
|
||||||
|
"heavyweight_desc": "Seni iten ve yavaşlatan yetenekler işlemez",
|
||||||
|
|
||||||
"hermit": "Münzevi",
|
"hermit": "Münzevi",
|
||||||
"hermit_desc": "Birini öldürünce mermin ve canın yenilenir",
|
"hermit_desc": "Birini öldürünce mermin ve canın yenilenir",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"demoneye": "Şeytani Göz",
|
"demoneye": "Şeytani Göz",
|
||||||
"demoneye_desc": "Baktığın tüm düşmana hasar verirsin",
|
"demoneye_desc": "Baktığın tüm düşmana hasar verirsin",
|
||||||
|
|
||||||
|
"nemesis": "Ezeli Rakip",
|
||||||
|
"nemesis_desc": "İşaretlediğin düşman herkesten daha fazla hasar alır",
|
||||||
|
"nemesis_select_info": "Birini seçin:",
|
||||||
|
"nemesis_player_info": "'{0}' artık herkesten daha fazla hasar alacak.",
|
||||||
|
"nemesis_enemy_info": "İşaretlendin, artık herkesten daha fazla hasar alıyorsun.",
|
||||||
|
|
||||||
"nightmare": "Kabus",
|
"nightmare": "Kabus",
|
||||||
"nightmare_desc": "Seçtiğin rakibe kabus gördür",
|
"nightmare_desc": "Seçtiğin rakibe kabus gördür",
|
||||||
"nightmare_disable_info": "Kabus sona erdi.",
|
"nightmare_disable_info": "Kabus sona erdi.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Protez",
|
"prosthesis": "Protez",
|
||||||
"prosthesis_desc": "Kolların ve bacakların kurşun geçirmez",
|
"prosthesis_desc": "Kolların ve bacakların kurşun geçirmez",
|
||||||
|
|
||||||
|
"punisher": "İntikam",
|
||||||
|
"punisher_desc": "Aldığın hasarı biriktirir, sonraki vuruşunda geri verirsin",
|
||||||
|
"punisher_released_info": "{0} ekstra hasar verdin ve o kadar can kazandın.",
|
||||||
|
|
||||||
"push": "İtici",
|
"push": "İtici",
|
||||||
"push_desc": "Düşmana vurduğunda onu geri itme şansın olur",
|
"push_desc": "Düşmana vurduğunda onu geri itme şansın olur",
|
||||||
"push_desc2": "Geri itme şansın: %{0}",
|
"push_desc2": "Geri itme şansın: %{0}",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "İade",
|
"returntosender": "İade",
|
||||||
"returntosender_desc": "Düşmana ilk vuruşun onu kendi başlangıcına ışınlar",
|
"returntosender_desc": "Düşmana ilk vuruşun onu kendi başlangıcına ışınlar",
|
||||||
|
|
||||||
|
"rewind": "Geri Sarma",
|
||||||
|
"rewind_desc": "[css_useSkill] tuşuna basarak iz bırak, birazdan oraya geri dön",
|
||||||
|
"rewind_pending_info": "DÖNÜŞ: {0}",
|
||||||
|
|
||||||
"richboy": "Zengin Çocuk",
|
"richboy": "Zengin Çocuk",
|
||||||
"richboy_desc": "Rastgele miktarda paran olur",
|
"richboy_desc": "Rastgele miktarda paran olur",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Tel gerildi.",
|
"tripwire_placed_info": "Tel gerildi.",
|
||||||
"tripwire_triggered_info": "'{0}' teline takıldı.",
|
"tripwire_triggered_info": "'{0}' teline takıldı.",
|
||||||
|
|
||||||
|
"truearmor": "Gerçek Zırh",
|
||||||
|
"truearmor_desc": "Aldığın hasarın bir kısmını canın yerine zırhın karşılar",
|
||||||
|
|
||||||
|
"voodoo": "Vudu",
|
||||||
|
"voodoo_desc": "Aldığın hasarın bir kısmını işaretlediğin düşman da alır",
|
||||||
|
"voodoo_select_info": "Birini seçin:",
|
||||||
|
"voodoo_player_info": "'{0}' oyuncusunu kendine bağladın.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Düşmanları duvar arkasından görürsün",
|
"wallhack_desc": "Düşmanları duvar arkasından görürsün",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,13 @@
|
||||||
"blademaster": "我的刀能档子弹!",
|
"blademaster": "我的刀能档子弹!",
|
||||||
"blademaster_desc": "持刀时,你有很高几率格挡子弹",
|
"blademaster_desc": "持刀时,你有很高几率格挡子弹",
|
||||||
|
|
||||||
|
"bounty": "悬赏",
|
||||||
|
"bounty_desc": "对一名敌人悬赏,击杀他的人可以获得赏金",
|
||||||
|
"bounty_select_info": "选择一名玩家:",
|
||||||
|
"bounty_player_info": "你对 '{0}' 悬赏了 {1}$。",
|
||||||
|
"bounty_enemy_info": "有人对你悬赏了 {0}$。",
|
||||||
|
"bounty_claimed_info": "你击杀了 '{0}',获得 {1}$。",
|
||||||
|
|
||||||
"bunnyhop": "连跳大佬",
|
"bunnyhop": "连跳大佬",
|
||||||
"bunnyhop_desc": "你获得自动连跳的能力",
|
"bunnyhop_desc": "你获得自动连跳的能力",
|
||||||
|
|
||||||
|
|
@ -131,6 +138,10 @@
|
||||||
"dwarf_desc": "回合开始时获得随机角色大小",
|
"dwarf_desc": "回合开始时获得随机角色大小",
|
||||||
"dwarf_desc2": "你的体型倍率是:{0}x",
|
"dwarf_desc2": "你的体型倍率是:{0}x",
|
||||||
|
|
||||||
|
"empgrenade": "电磁脉冲手雷",
|
||||||
|
"empgrenade_desc": "被你的手雷伤到的人会暂时失去雷达和准星",
|
||||||
|
"empgrenade_enemy_info": "电磁脉冲手雷让你的雷达和准星失效了。",
|
||||||
|
|
||||||
"enemyspawn": "传送敌人出生点",
|
"enemyspawn": "传送敌人出生点",
|
||||||
"enemyspawn_desc": "点击 [css_useSkill] 传送到敌人出生点",
|
"enemyspawn_desc": "点击 [css_useSkill] 传送到敌人出生点",
|
||||||
|
|
||||||
|
|
@ -211,12 +222,18 @@
|
||||||
"grapple_no_anchor_info": "没有可以钩住的表面。",
|
"grapple_no_anchor_info": "没有可以钩住的表面。",
|
||||||
"grapple_pulling_info": "拉动中",
|
"grapple_pulling_info": "拉动中",
|
||||||
|
|
||||||
|
"gravitydecoy": "重力诱饵",
|
||||||
|
"gravitydecoy_desc": "你的诱饵会改变附近所有人的重力",
|
||||||
|
|
||||||
"grenadier": "投弹手",
|
"grenadier": "投弹手",
|
||||||
"grenadier_desc": "你拥有无限高爆手雷",
|
"grenadier_desc": "你拥有无限高爆手雷",
|
||||||
|
|
||||||
"healingsmoke": "治疗烟雾",
|
"healingsmoke": "治疗烟雾",
|
||||||
"healingsmoke_desc": "你的烟雾弹会治疗",
|
"healingsmoke_desc": "你的烟雾弹会治疗",
|
||||||
|
|
||||||
|
"heavyweight": "重量级",
|
||||||
|
"heavyweight_desc": "推开你或让你减速的技能对你无效",
|
||||||
|
|
||||||
"hermit": "隐士",
|
"hermit": "隐士",
|
||||||
"hermit_desc": "击杀敌人会恢复弹药和部分生命值",
|
"hermit_desc": "击杀敌人会恢复弹药和部分生命值",
|
||||||
|
|
||||||
|
|
@ -330,6 +347,12 @@
|
||||||
"deathbomb_desc": "你死亡时会爆炸,杀死附近的玩家",
|
"deathbomb_desc": "你死亡时会爆炸,杀死附近的玩家",
|
||||||
"deathbomb_explosion": "砰!",
|
"deathbomb_explosion": "砰!",
|
||||||
|
|
||||||
|
"nemesis": "宿敌",
|
||||||
|
"nemesis_desc": "被你标记的玩家会受到额外伤害",
|
||||||
|
"nemesis_select_info": "选择一名玩家:",
|
||||||
|
"nemesis_player_info": "你标记了 '{0}'。",
|
||||||
|
"nemesis_enemy_info": "你被标记为宿敌,现在会受到所有人的额外伤害。",
|
||||||
|
|
||||||
"nightmare": "nightmare",
|
"nightmare": "nightmare",
|
||||||
"nightmare_desc": "nightmare_desc",
|
"nightmare_desc": "nightmare_desc",
|
||||||
"nightmare_disable_info": "nightmare_disable_info",
|
"nightmare_disable_info": "nightmare_disable_info",
|
||||||
|
|
@ -393,6 +416,10 @@
|
||||||
"prosthesis": "假肢",
|
"prosthesis": "假肢",
|
||||||
"prosthesis_desc": "手臂和腿部防弹",
|
"prosthesis_desc": "手臂和腿部防弹",
|
||||||
|
|
||||||
|
"punisher": "惩罚者",
|
||||||
|
"punisher_desc": "你会积攒受到伤害的一部分,并加到下一次命中上",
|
||||||
|
"punisher_released_info": "你造成了 {0} 点额外伤害,并回复了同样的生命值。",
|
||||||
|
|
||||||
"push": "推力者",
|
"push": "推力者",
|
||||||
"push_desc": "你有随机几率在击中敌人时将其推回",
|
"push_desc": "你有随机几率在击中敌人时将其推回",
|
||||||
"push_desc2": "你击退敌人的几率为:{0}%",
|
"push_desc2": "你击退敌人的几率为:{0}%",
|
||||||
|
|
@ -430,6 +457,10 @@
|
||||||
"returntosender": "发送他们房子!!!",
|
"returntosender": "发送他们房子!!!",
|
||||||
"returntosender_desc": "首次击中敌人会将其送回出生点",
|
"returntosender_desc": "首次击中敌人会将其送回出生点",
|
||||||
|
|
||||||
|
"rewind": "回溯",
|
||||||
|
"rewind_desc": "按 [css_useSkill] 在原地留下标记,稍后回到那里",
|
||||||
|
"rewind_pending_info": "回溯:{0}",
|
||||||
|
|
||||||
"richboy": "富少",
|
"richboy": "富少",
|
||||||
"richboy_desc": "回合开始时你获得随机数量的钱",
|
"richboy_desc": "回合开始时你获得随机数量的钱",
|
||||||
|
|
||||||
|
|
@ -507,6 +538,14 @@
|
||||||
"tripwire_placed_info": "tripwire_placed_info",
|
"tripwire_placed_info": "tripwire_placed_info",
|
||||||
"tripwire_triggered_info": "tripwire_triggered_info: {0}",
|
"tripwire_triggered_info": "tripwire_triggered_info: {0}",
|
||||||
|
|
||||||
|
"truearmor": "真实护甲",
|
||||||
|
"truearmor_desc": "你受到的一部分伤害由护甲承担,而不是生命值",
|
||||||
|
|
||||||
|
"voodoo": "巫毒",
|
||||||
|
"voodoo_desc": "被你标记的敌人也会受到你所受伤害的一部分",
|
||||||
|
"voodoo_select_info": "选择一名玩家:",
|
||||||
|
"voodoo_player_info": "你把 '{0}' 绑到了你的巫毒上。",
|
||||||
|
|
||||||
"wallhack": "透视",
|
"wallhack": "透视",
|
||||||
"wallhack_desc": "你可以通过墙壁看到敌人",
|
"wallhack_desc": "你可以通过墙壁看到敌人",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,13 +45,13 @@ namespace src.player
|
||||||
var teams = Utilities.FindAllEntitiesByDesignerName<CCSTeam>("cs_team_manager").Where(t => t != null).ToList();
|
var teams = Utilities.FindAllEntitiesByDesignerName<CCSTeam>("cs_team_manager").Where(t => t != null).ToList();
|
||||||
var tTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.Terrorist);
|
var tTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.Terrorist);
|
||||||
var ctTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.CounterTerrorist);
|
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;
|
return HookResult.Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
Instance.RegisterEventHandler<EventRoundFreezeEnd>((@event, info) =>
|
Instance.RegisterEventHandler<EventRoundFreezeEnd>((@event, info) =>
|
||||||
{
|
{
|
||||||
WriteToDebug($"Freeze time ended.");
|
WriteToDebug($"Freeze time ended.{WarmupTag()}");
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ namespace src.player
|
||||||
var teams = Utilities.FindAllEntitiesByDesignerName<CCSTeam>("cs_team_manager").Where(t => t != null).ToList();
|
var teams = Utilities.FindAllEntitiesByDesignerName<CCSTeam>("cs_team_manager").Where(t => t != null).ToList();
|
||||||
var tTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.Terrorist);
|
var tTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.Terrorist);
|
||||||
var ctTeam = teams.FirstOrDefault(t => t.TeamNum == (int)CsTeam.CounterTerrorist);
|
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;
|
return HookResult.Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -137,6 +137,13 @@ namespace src.player
|
||||||
return HookResult.Continue;
|
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)
|
public static void WriteToDebug(string message)
|
||||||
{
|
{
|
||||||
if (Config.LoadedConfig.DebugMode != true)
|
if (Config.LoadedConfig.DebugMode != true)
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ public enum Skills
|
||||||
BladeMaster,
|
BladeMaster,
|
||||||
BunnyHop,
|
BunnyHop,
|
||||||
BlastShot,
|
BlastShot,
|
||||||
|
Bounty,
|
||||||
C4Camouflage,
|
C4Camouflage,
|
||||||
CarefulBullets,
|
CarefulBullets,
|
||||||
Catapult,
|
Catapult,
|
||||||
|
|
@ -95,6 +96,7 @@ public enum Skills
|
||||||
Dracula,
|
Dracula,
|
||||||
Duplicator,
|
Duplicator,
|
||||||
Dwarf,
|
Dwarf,
|
||||||
|
EmpGrenade,
|
||||||
EnemySpawn,
|
EnemySpawn,
|
||||||
ExpensiveAmmo,
|
ExpensiveAmmo,
|
||||||
ExplodingBarrel,
|
ExplodingBarrel,
|
||||||
|
|
@ -116,9 +118,11 @@ public enum Skills
|
||||||
Glue,
|
Glue,
|
||||||
GodMode,
|
GodMode,
|
||||||
Grapple,
|
Grapple,
|
||||||
|
GravityDecoy,
|
||||||
Grenadier,
|
Grenadier,
|
||||||
HealingChicken,
|
HealingChicken,
|
||||||
HealingSmoke,
|
HealingSmoke,
|
||||||
|
Heavyweight,
|
||||||
Hermit,
|
Hermit,
|
||||||
HolyHandGrenade,
|
HolyHandGrenade,
|
||||||
HomingNades,
|
HomingNades,
|
||||||
|
|
@ -148,6 +152,7 @@ public enum Skills
|
||||||
Medic,
|
Medic,
|
||||||
Miner,
|
Miner,
|
||||||
MoneySwap,
|
MoneySwap,
|
||||||
|
Nemesis,
|
||||||
Nightmare,
|
Nightmare,
|
||||||
Ninja,
|
Ninja,
|
||||||
NoNades,
|
NoNades,
|
||||||
|
|
@ -163,6 +168,7 @@ public enum Skills
|
||||||
Poison,
|
Poison,
|
||||||
PrimaryBan,
|
PrimaryBan,
|
||||||
Prosthesis,
|
Prosthesis,
|
||||||
|
Punisher,
|
||||||
Push,
|
Push,
|
||||||
Pyro,
|
Pyro,
|
||||||
QuickShot,
|
QuickShot,
|
||||||
|
|
@ -175,6 +181,7 @@ public enum Skills
|
||||||
Replicator,
|
Replicator,
|
||||||
Retreat,
|
Retreat,
|
||||||
ReturnToSender,
|
ReturnToSender,
|
||||||
|
Rewind,
|
||||||
RichBoy,
|
RichBoy,
|
||||||
Ricochet,
|
Ricochet,
|
||||||
RobinHood,
|
RobinHood,
|
||||||
|
|
@ -199,6 +206,8 @@ public enum Skills
|
||||||
ThrowingKnife,
|
ThrowingKnife,
|
||||||
ToxicSmoke,
|
ToxicSmoke,
|
||||||
Tripwire,
|
Tripwire,
|
||||||
|
TrueArmor,
|
||||||
|
Voodoo,
|
||||||
Wallhack,
|
Wallhack,
|
||||||
Watchmaker,
|
Watchmaker,
|
||||||
WeaponsSwap,
|
WeaponsSwap,
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace src.player
|
||||||
public static readonly SkillsInfo.DefaultSkillInfo[] counterterroristSkills = [.. SkillsInfo.LoadedConfig.Where(s => s.OnlyTeam == (int)CsTeam.CounterTerrorist)];
|
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 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, jSkill_SkillInfo> staticSkills = [];
|
||||||
public static readonly ConcurrentDictionary<uint, uint> playersCustomFOV = [];
|
public static readonly ConcurrentDictionary<uint, uint> playersCustomFOV = [];
|
||||||
private static readonly object setLock = new();
|
private static readonly object setLock = new();
|
||||||
|
|
@ -564,6 +564,7 @@ namespace src.player
|
||||||
|
|
||||||
PlayerManager.UnregisterPlayer(player.Index);
|
PlayerManager.UnregisterPlayer(player.Index);
|
||||||
EntityManager.DestroyPlayerEntities(player.Index);
|
EntityManager.DestroyPlayerEntities(player.Index);
|
||||||
|
SkillUtils.ClearHudSuppression(player.Index);
|
||||||
|
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
}
|
}
|
||||||
|
|
@ -602,6 +603,8 @@ namespace src.player
|
||||||
var pawn = player.PlayerPawn?.Value;
|
var pawn = player.PlayerPawn?.Value;
|
||||||
if (pawn == null || !pawn.IsValid) return;
|
if (pawn == null || !pawn.IsValid) return;
|
||||||
|
|
||||||
|
SkillUtils.ClearHudSuppression(player.Index);
|
||||||
|
|
||||||
pawn.HideHUD = (uint)(pawn.HideHUD & ~(1 << 8));
|
pawn.HideHUD = (uint)(pawn.HideHUD & ~(1 << 8));
|
||||||
Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_iHideHUD");
|
Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_iHideHUD");
|
||||||
|
|
||||||
|
|
@ -768,6 +771,21 @@ namespace src.player
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = Config.LoadedConfig.HtmlHudCustomisation;
|
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 emptySymbol = $"<font class='fontSize-{(string.IsNullOrEmpty(headerLine) || string.IsNullOrEmpty(config.HeaderLineSize) ? "l" : "ml")}'> </font>";
|
||||||
var emptySymbol2 = $"<font class='fontSize-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}";
|
: $"<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;
|
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);
|
player.PrintToCenterHtml(hudContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,8 @@ namespace src.player
|
||||||
SkillsUsedThisMap.Clear();
|
SkillsUsedThisMap.Clear();
|
||||||
nextRoundPicks.Clear();
|
nextRoundPicks.Clear();
|
||||||
|
|
||||||
|
SkillUtils.ClearAllHudSuppression();
|
||||||
|
|
||||||
playersCustomFOV.Clear();
|
playersCustomFOV.Clear();
|
||||||
playersSkills.Clear();
|
playersSkills.Clear();
|
||||||
staticSkills.Clear();
|
staticSkills.Clear();
|
||||||
|
|
@ -275,6 +277,7 @@ namespace src.player
|
||||||
public required HashSet<Skills> NeedsTeammates { get; init; }
|
public required HashSet<Skills> NeedsTeammates { get; init; }
|
||||||
public required HashSet<Skills> CtOnly { get; init; }
|
public required HashSet<Skills> CtOnly { get; init; }
|
||||||
public required HashSet<Skills> TOnly { 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 TerroristCount { get; init; }
|
||||||
public required int CounterTerroristCount { 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)),
|
NeedsTeammates = ToSkillSet(SkillsInfo.LoadedConfig.Where(s => s.NeedsTeammates).Select(s => s.Name)),
|
||||||
CtOnly = ToSkillSet(counterterroristSkills.Select(s => s.Name)),
|
CtOnly = ToSkillSet(counterterroristSkills.Select(s => s.Name)),
|
||||||
TOnly = ToSkillSet(terroristSkills.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),
|
TerroristCount = validPlayers.Count(p => p.Team == CsTeam.Terrorist),
|
||||||
CounterTerroristCount = validPlayers.Count(p => p.Team == CsTeam.CounterTerrorist),
|
CounterTerroristCount = validPlayers.Count(p => p.Team == CsTeam.CounterTerrorist),
|
||||||
};
|
};
|
||||||
|
|
@ -328,9 +334,12 @@ namespace src.player
|
||||||
else
|
else
|
||||||
skillList.RemoveAll(s => ctx.TOnly.Contains(s.Skill));
|
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();
|
if (skillList.Count == 0) skills.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,10 +347,10 @@ namespace src.player
|
||||||
|
|
||||||
if (gameMode == Config.GameModes.NoRepeat)
|
if (gameMode == Config.GameModes.NoRepeat)
|
||||||
{
|
{
|
||||||
if (playersSkills.TryGetValue(player.Index, out ConcurrentBag<jSkill_SkillInfo>? value))
|
if (playersSkills.TryGetValue(player.Index, out HashSet<Skills>? value))
|
||||||
value.Add(randomSkill);
|
value.Add(randomSkill.Skill);
|
||||||
else
|
else
|
||||||
playersSkills.TryAdd(player.Index, [randomSkill]);
|
playersSkills.TryAdd(player.Index, [randomSkill.Skill]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return randomSkill;
|
return randomSkill;
|
||||||
|
|
@ -358,6 +367,7 @@ namespace src.player
|
||||||
|
|
||||||
var def = SkillsInfo.LoadedConfig.FirstOrDefault(d => d.Name == name);
|
var def = SkillsInfo.LoadedConfig.FirstOrDefault(d => d.Name == name);
|
||||||
if (def == null) return false;
|
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.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;
|
if (def.MaxPerServer >= 0 && assignmentCounts.TryGetValue(pick.Skill, out var c) && c >= def.MaxPerServer) return false;
|
||||||
|
|
||||||
|
|
@ -648,9 +658,12 @@ namespace src.player
|
||||||
else
|
else
|
||||||
skillList.RemoveAll(s => terroristSkills.Any(s2 => s2.Name == s.Skill.ToString()));
|
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();
|
if (skillList.Count == 0) skills.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,9 @@ namespace src.player.skills
|
||||||
public class Assassin : ISkill
|
public class Assassin : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Assassin;
|
private const Skills skillName = Skills.Assassin;
|
||||||
private static readonly string[] nadeWeapons =
|
private const string infernoWeapon = "weapon_inferno";
|
||||||
[
|
|
||||||
"weapon_inferno", "weapon_molotov", "weapon_incgrenade", "weapon_flashbang",
|
private static bool IsNade(string? weapon) => weapon == infernoWeapon || WeaponPool.IsGrenade(weapon);
|
||||||
"weapon_smokegrenade", "weapon_decoy", "weapon_hegrenade"
|
|
||||||
];
|
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
|
|
@ -46,7 +44,7 @@ namespace src.player.skills
|
||||||
|
|
||||||
var weapon = param2.Ability?.Value;
|
var weapon = param2.Ability?.Value;
|
||||||
if (weapon == null || !weapon.IsValid) return;
|
if (weapon == null || !weapon.IsValid) return;
|
||||||
if (nadeWeapons.Contains(weapon.DesignerName)) return;
|
if (IsNade(weapon.DesignerName)) return;
|
||||||
|
|
||||||
if (IsBehind(attacker, victim))
|
if (IsBehind(attacker, victim))
|
||||||
param2.Damage *= SkillsInfo.GetValue<float>(skillName, "damageMultiplier");
|
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 bomb = PlayerManager.GetTickBomb();
|
||||||
|
|
||||||
|
var hidden = SkillUtils.ResolveHiddenPawns(invisiblePlayers.Keys, null);
|
||||||
|
if (hidden.Count == 0) return;
|
||||||
|
|
||||||
foreach (var (info, player) in infoList)
|
foreach (var (info, player) in infoList)
|
||||||
{
|
{
|
||||||
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
||||||
|
|
||||||
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
|
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 (target.Index == player.Index) continue;
|
||||||
if (playerController == null || !playerController.IsValid || playerController.Index == player.Index)
|
if (player.Team == target.Team) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (player.Team == playerController.Team)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var playerPawn = playerController.PlayerPawn.Value;
|
|
||||||
if (playerPawn == null || !playerPawn.IsValid) continue;
|
|
||||||
|
|
||||||
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
||||||
if (targetHandle != nint.Zero && playerPawn.Handle == targetHandle)
|
if (targetHandle != nint.Zero && target.Pawn.Handle == targetHandle) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)playerPawn.Index);
|
if (info.TransmitEntities.Contains(target.Pawn.Index))
|
||||||
if (entity == null || !entity.IsValid) continue;
|
info.TransmitEntities.Remove(target.Pawn.Index);
|
||||||
|
|
||||||
if (info.TransmitEntities.Contains(entity.Index))
|
SkillUtils.HideCarriedEntities(info, target.Pawn);
|
||||||
info.TransmitEntities.Remove(entity.Index);
|
|
||||||
|
|
||||||
SkillUtils.HideCarriedEntities(info, playerPawn);
|
|
||||||
|
|
||||||
if (bomb == null) continue;
|
if (bomb == null) continue;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ namespace src.player.skills
|
||||||
public class CarefulBullets : ISkill
|
public class CarefulBullets : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.CarefulBullets;
|
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, byte> targetPlayers = [];
|
||||||
private static readonly ConcurrentDictionary<uint, bool> lastShot = [];
|
private static readonly ConcurrentDictionary<uint, bool> lastShot = [];
|
||||||
private static readonly ConcurrentDictionary<uint, int> hitPlayer = [];
|
private static readonly ConcurrentDictionary<uint, int> hitPlayer = [];
|
||||||
|
|
@ -153,7 +154,7 @@ namespace src.player.skills
|
||||||
{
|
{
|
||||||
if (lastShot.TryRemove(playerIndex, out bool didHit) && !didHit)
|
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);
|
SkillUtils.TakeHealth(playerPawn, SkillsInfo.GetValue<int>(skillName, "damageAfterMiss"), GetSkillOwner(playerIndex), KillfeedIcons.Fist);
|
||||||
}
|
}
|
||||||
|
|
@ -257,8 +258,9 @@ namespace src.player.skills
|
||||||
targetToPlayer.TryRemove(index, out _);
|
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;
|
public int DamageAfterMiss { get; set; } = damageAfterMiss;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ namespace src.player.skills
|
||||||
if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return;
|
if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return;
|
||||||
var attackerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
var attackerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
||||||
|
|
||||||
|
if (Heavyweight.Resists(victim)) return;
|
||||||
|
|
||||||
if (attackerInfo?.Skill == skillName && victim!.PawnIsAlive)
|
if (attackerInfo?.Skill == skillName && victim!.PawnIsAlive)
|
||||||
if (Instance.Random.NextDouble() <= attackerInfo.SkillChance)
|
if (Instance.Random.NextDouble() <= attackerInfo.SkillChance)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,7 @@ namespace src.player.skills
|
||||||
public class Chicken : ISkill
|
public class Chicken : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Chicken;
|
private const Skills skillName = Skills.Chicken;
|
||||||
private static readonly HashSet<string> disabledWeapons =
|
private static HashSet<string> disabledWeapons => WeaponPool.Rifles;
|
||||||
[
|
|
||||||
"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 const string chickenModelPath = "models/chicken/chicken.vmdl";
|
private const string chickenModelPath = "models/chicken/chicken.vmdl";
|
||||||
private static readonly ConcurrentDictionary<uint, uint> chickens = [];
|
private static readonly ConcurrentDictionary<uint, uint> chickens = [];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ namespace src.player.skills
|
||||||
{
|
{
|
||||||
var cameraProp = Utilities.GetEntityFromIndex<CDynamicProp>((int)playerSkill.CameraProp);
|
var cameraProp = Utilities.GetEntityFromIndex<CDynamicProp>((int)playerSkill.CameraProp);
|
||||||
if (cameraProp != null && cameraProp.IsValid)
|
if (cameraProp != null && cameraProp.IsValid)
|
||||||
cameraProp.EmitSound("SolidMetal.BulletImpact");
|
cameraProp.EmitSound("SolidMetal.BulletImpact", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||||
|
|
||||||
SkillUtils.SafeKillEntity<CDynamicProp>(playerSkill.CameraProp);
|
SkillUtils.SafeKillEntity<CDynamicProp>(playerSkill.CameraProp);
|
||||||
playerSkill.CameraProp = null;
|
playerSkill.CameraProp = null;
|
||||||
|
|
@ -414,8 +414,9 @@ namespace src.player.skills
|
||||||
public required QAngle LastCameraAngle { get; set; }
|
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;
|
public float Cooldown { get; set; } = cooldown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,8 @@ namespace src.player.skills
|
||||||
eventPlayerPawn.AbsVelocity.X = newVelocity.X;
|
eventPlayerPawn.AbsVelocity.X = newVelocity.X;
|
||||||
eventPlayerPawn.AbsVelocity.Y = newVelocity.Y;
|
eventPlayerPawn.AbsVelocity.Y = newVelocity.Y;
|
||||||
eventPlayerPawn.AbsVelocity.Z = newVelocity.Z;
|
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 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 JumpVelocity { get; set; } = jumpVelocity;
|
||||||
public float PushVelocity { get; set; } = pushVelocity;
|
public float PushVelocity { get; set; } = pushVelocity;
|
||||||
public bool AnyDirection { get; set; } = anyDirection;
|
public bool AnyDirection { get; set; } = anyDirection;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ namespace src.player.skills
|
||||||
public class DeathBomb : ISkill
|
public class DeathBomb : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.DeathBomb;
|
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 QAngle angle = new(10, -5, 9);
|
||||||
private static readonly ConcurrentDictionary<int, (byte Team, uint Owner)> nades = [];
|
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")}",
|
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");
|
border: !PlayerManager.GetTickPlayers().Any(p => p.Team == player.Team && p != player) ? "tb" : "t");
|
||||||
|
|
||||||
var fileNames = new[] { "radiobotfallback01", "radiobotfallback02", "radiobotfallback04" };
|
player.EmitSound(voiceLines[Random.Shared.Next(voiceLines.Length)], volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||||
var randomFile = fileNames[new Random().Next(fileNames.Length)];
|
|
||||||
player.ExecuteClientCommand($"play vo/agents/balkan/{randomFile}.vsnd");
|
|
||||||
|
|
||||||
nades.AddOrUpdate(Server.TickCount, (player.TeamNum, player.Index), (_, _) => (player.TeamNum, player.Index));
|
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;
|
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 float ExplosionRadius { get; set; } = explosionRadius;
|
||||||
public int ExplosionDamage { get; set; } = explosionDamage;
|
public int ExplosionDamage { get; set; } = explosionDamage;
|
||||||
public float DmgReductionForTeamates { get; set; } = dmgReductionForTeamates;
|
public float DmgReductionForTeamates { get; set; } = dmgReductionForTeamates;
|
||||||
|
|
|
||||||
|
|
@ -66,13 +66,14 @@ namespace src.player.skills
|
||||||
if (playerSeesEnemy)
|
if (playerSeesEnemy)
|
||||||
{
|
{
|
||||||
SkillUtils.TakeHealth(enemyPawn, damage, player, KillfeedIcons.Fist);
|
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 float SecondCooldown { get; set; } = secondCooldown;
|
||||||
public int Damage { get; set; } = damage;
|
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()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||||
|
DecoyRing.PreloadAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NewRound()
|
public static void NewRound()
|
||||||
{
|
{
|
||||||
KillAllDecoys();
|
KillAllDecoys();
|
||||||
rainMolotovs.Clear();
|
rainMolotovs.Clear();
|
||||||
|
DecoyRing.ClearAll(skillName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void KillAllDecoys()
|
private static void KillAllDecoys()
|
||||||
|
|
@ -276,7 +278,14 @@ namespace src.player.skills
|
||||||
if (decoy != null && decoy.IsValid)
|
if (decoy != null && decoy.IsValid)
|
||||||
decoy.AddEntityIOEvent("Kill", decoy, delay: 0.1f);
|
decoy.AddEntityIOEvent("Kill", decoy, delay: 0.1f);
|
||||||
decoys.TryRemove(key, out _);
|
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);
|
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>();
|
var box = param.As<CDynamicProp>();
|
||||||
if (box == null || !box.IsValid) return;
|
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))
|
if (barricades.TryGetValue(box.Index, out int health))
|
||||||
{
|
{
|
||||||
|
|
@ -178,8 +178,9 @@ namespace src.player.skills
|
||||||
public DateTime Cooldown { get; set; }
|
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 float Cooldown { get; set; } = cooldown;
|
||||||
public int BarricadeHealth { get; set; } = barricadeHealth;
|
public int BarricadeHealth { get; set; } = barricadeHealth;
|
||||||
public string PropModel { get; set; } = propModel;
|
public string PropModel { get; set; } = propModel;
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,19 @@ namespace src.player.skills
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||||
|
DecoyRing.PreloadAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NewRound()
|
public static void NewRound()
|
||||||
{
|
{
|
||||||
decoys.Clear();
|
decoys.Clear();
|
||||||
|
DecoyRing.ClearAll(skillName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RoundEnd()
|
||||||
|
{
|
||||||
|
decoys.Clear();
|
||||||
|
DecoyRing.ClearAll(skillName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DecoyStarted(EventDecoyStarted @event)
|
public static void DecoyStarted(EventDecoyStarted @event)
|
||||||
|
|
@ -31,7 +39,9 @@ namespace src.player.skills
|
||||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||||
if (playerInfo?.Skill != skillName) return;
|
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)
|
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))
|
foreach (var decoy in decoys.Keys.Where(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z))
|
||||||
decoys.TryRemove(decoy, out _);
|
decoys.TryRemove(decoy, out _);
|
||||||
|
|
||||||
|
DecoyRing.Hide(skillName, (uint)@event.Entityid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnTick()
|
public static void OnTick()
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,13 @@ namespace src.player.skills
|
||||||
public class Ghost : ISkill
|
public class Ghost : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Ghost;
|
private const Skills skillName = Skills.Ghost;
|
||||||
private static readonly string[] allowedWeapons = [
|
private static readonly HashSet<string> alwaysAllowed = new(StringComparer.Ordinal)
|
||||||
"weapon_molotov", "weapon_incgrenade", "weapon_flashbang", "weapon_smokegrenade", "weapon_decoy", "weapon_hegrenade", "weapon_knife", "weapon_bayonet", "weapon_c4"
|
{
|
||||||
];
|
"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 static readonly ConcurrentDictionary<uint, byte> invisiblePlayers = [];
|
||||||
private const string bloodParticle = "particles/blood_impact/blood_impact_high.vpcf";
|
private const string bloodParticle = "particles/blood_impact/blood_impact_high.vpcf";
|
||||||
private const string cameraViewModel = "models/sprays/spray_plane.vmdl";
|
private const string cameraViewModel = "models/sprays/spray_plane.vmdl";
|
||||||
|
|
@ -61,38 +65,30 @@ namespace src.player.skills
|
||||||
var bomb = PlayerManager.GetTickBomb();
|
var bomb = PlayerManager.GetTickBomb();
|
||||||
uint? bombOwnerIndex = bomb != null && bomb.IsValid ? bomb.OwnerEntity?.Index : null;
|
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)
|
foreach (var (info, player) in infoList)
|
||||||
{
|
{
|
||||||
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
||||||
|
|
||||||
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
|
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 (target.Index == player.Index) continue;
|
||||||
if (playerController == null || !playerController.IsValid || playerController.Index == player.Index)
|
if (player.Team == target.Team) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (player.Team == playerController.Team)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var playerPawn = playerController.PlayerPawn.Value;
|
|
||||||
if (playerPawn == null || !playerPawn.IsValid) continue;
|
|
||||||
|
|
||||||
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
||||||
if (targetHandle != nint.Zero && playerPawn.Handle == targetHandle)
|
if (targetHandle != nint.Zero && target.Pawn.Handle == targetHandle) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)playerPawn.Index);
|
if (info.TransmitEntities.Contains(target.Pawn.Index))
|
||||||
if (entity == null || !entity.IsValid) continue;
|
info.TransmitEntities.Remove(target.Pawn.Index);
|
||||||
|
|
||||||
if (info.TransmitEntities.Contains(entity.Index))
|
SkillUtils.HideCarriedEntities(info, target.Pawn);
|
||||||
info.TransmitEntities.Remove(entity.Index);
|
|
||||||
|
|
||||||
SkillUtils.HideCarriedEntities(info, playerPawn);
|
|
||||||
|
|
||||||
// Hide the bomb as well, but only while this hidden player is the one holding it.
|
// 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))
|
if (info.TransmitEntities.Contains(bomb.Index))
|
||||||
info.TransmitEntities.Remove(bomb.Index);
|
info.TransmitEntities.Remove(bomb.Index);
|
||||||
|
|
@ -156,7 +152,7 @@ namespace src.player.skills
|
||||||
foreach (var player in PlayerManager.GetTickPlayers())
|
foreach (var player in PlayerManager.GetTickPlayers())
|
||||||
{
|
{
|
||||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||||
if (playerInfo?.Skill == skillName)
|
if (playerInfo?.Skill == skillName && SkillUtils.IsHudFrame())
|
||||||
UpdateHUD(player);
|
UpdateHUD(player);
|
||||||
|
|
||||||
if (player.LifeState != (byte)LifeState_t.LIFE_ALIVE)
|
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))
|
if (weapon != null && weapon.IsValid && weapon.Value != null && weapon.Value.IsValid && !string.IsNullOrEmpty(weapon.Value.DesignerName))
|
||||||
{
|
{
|
||||||
string weaponName = 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.NextPrimaryAttackTick = disableWeapon ? int.MaxValue : Server.TickCount;
|
||||||
weapon.Value.NextSecondaryAttackTick = 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;
|
if (playerInfo == null) return;
|
||||||
|
|
||||||
var weapon = pawn.WeaponServices.ActiveWeapon.Value;
|
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;
|
playerInfo.PrintHTML = null;
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,18 @@ namespace src.player.skills
|
||||||
{
|
{
|
||||||
if (smokes.IsEmpty || playersWithSkill.IsEmpty) return;
|
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)
|
foreach (var (info, player) in infoList)
|
||||||
{
|
{
|
||||||
if (player == null || !player.IsValid) continue;
|
if (player == null || !player.IsValid) continue;
|
||||||
|
|
@ -51,21 +63,34 @@ namespace src.player.skills
|
||||||
var observerTarget = player.Pawn?.Value?.ObserverServices?.ObserverTarget?.Value?.Handle ?? nint.Zero;
|
var observerTarget = player.Pawn?.Value?.ObserverServices?.ObserverTarget?.Value?.Handle ?? nint.Zero;
|
||||||
if (observerTarget == nint.Zero) continue;
|
if (observerTarget == nint.Zero) continue;
|
||||||
|
|
||||||
var observedPlayer = PlayerManager.GetTickPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == observerTarget);
|
pawnOwners ??= BuildPawnOwners();
|
||||||
if (observedPlayer == null) continue;
|
|
||||||
|
|
||||||
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)
|
foreach (var index in smokeIndexes)
|
||||||
|
if (info.TransmitEntities.Contains(index))
|
||||||
|
info.TransmitEntities.Remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<nint, uint> BuildPawnOwners()
|
||||||
{
|
{
|
||||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)entityIndex);
|
var players = PlayerManager.GetTickPlayers();
|
||||||
if (entity == null || !entity.IsValid) continue;
|
Dictionary<nint, uint> owners = new(players.Count);
|
||||||
|
|
||||||
if (info.TransmitEntities.Contains(entity.Index))
|
foreach (var p in players)
|
||||||
info.TransmitEntities.Remove(entity.Index);
|
{
|
||||||
}
|
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)
|
public static void GrenadeThrown(EventGrenadeThrown @event)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ namespace src.player.skills
|
||||||
public class Glitch : ISkill
|
public class Glitch : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Glitch;
|
private const Skills skillName = Skills.Glitch;
|
||||||
|
private const string ownerTag = "Glitch";
|
||||||
private static readonly ConcurrentDictionary<uint, byte> glitchedPlayers = [];
|
private static readonly ConcurrentDictionary<uint, byte> glitchedPlayers = [];
|
||||||
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
||||||
private static readonly object setLock = new();
|
private static readonly object setLock = new();
|
||||||
|
|
@ -100,7 +101,7 @@ namespace src.player.skills
|
||||||
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
||||||
if (enemyEvent == null || !enemyEvent.IsValid) return;
|
if (enemyEvent == null || !enemyEvent.IsValid) return;
|
||||||
|
|
||||||
enemyEvent.ReplicateConVar("sv_disable_radar", "1");
|
SkillUtils.SetRadarDisabled(enemyEvent, ownerTag, true);
|
||||||
playerInfo.SkillUsed = true;
|
playerInfo.SkillUsed = true;
|
||||||
|
|
||||||
playerEvent.PrintToChat($" {ChatColors.Green}" + playerEvent.GetTranslation("glitch_player_info", enemy.PlayerName));
|
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;
|
if (!glitchedPlayers.ContainsKey(bot.Index)) return;
|
||||||
|
|
||||||
player.ReplicateConVar("sv_disable_radar", "1");
|
SkillUtils.SetRadarDisabled(player, ownerTag, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EnableSkill(CCSPlayerController player)
|
public static void EnableSkill(CCSPlayerController player)
|
||||||
|
|
@ -146,7 +147,7 @@ namespace src.player.skills
|
||||||
var target = PlayerManager.GetPlayerFromEvent(Utilities.GetPlayerFromIndex((int)targetIndex));
|
var target = PlayerManager.GetPlayerFromEvent(Utilities.GetPlayerFromIndex((int)targetIndex));
|
||||||
if (target != null && target.IsValid)
|
if (target != null && target.IsValid)
|
||||||
{
|
{
|
||||||
target.ReplicateConVar("sv_disable_radar", "0");
|
SkillUtils.SetRadarDisabled(target, ownerTag, false);
|
||||||
if (target.PawnIsAlive && !SkillUtils.IsFreezeTime())
|
if (target.PawnIsAlive && !SkillUtils.IsFreezeTime())
|
||||||
target.PrintToChat($" {ChatColors.Green}" + target.GetTranslation("glitch_disable_info"));
|
target.PrintToChat($" {ChatColors.Green}" + target.GetTranslation("glitch_disable_info"));
|
||||||
}
|
}
|
||||||
|
|
@ -161,7 +162,7 @@ namespace src.player.skills
|
||||||
var player = @event.Userid;
|
var player = @event.Userid;
|
||||||
if (player == null || !player.IsValid) return;
|
if (player == null || !player.IsValid) return;
|
||||||
|
|
||||||
player.ReplicateConVar("sv_disable_radar", "0");
|
SkillUtils.SetRadarDisabled(player, ownerTag, false);
|
||||||
glitchedPlayers.TryRemove(player.Index, out _);
|
glitchedPlayers.TryRemove(player.Index, out _);
|
||||||
SkillUtils.CloseMenu(player);
|
SkillUtils.CloseMenu(player);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,13 @@ namespace src.player.skills
|
||||||
private static readonly Color counterTerroristRope = Color.FromArgb(255, 52, 92, 138);
|
private static readonly Color counterTerroristRope = Color.FromArgb(255, 52, 92, 138);
|
||||||
|
|
||||||
private const double attemptCooldown = .3;
|
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()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||||
|
jRandomSkills.Instance.AddToManifest(hookModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NewRound()
|
public static void NewRound()
|
||||||
|
|
@ -131,6 +134,8 @@ namespace src.player.skills
|
||||||
skillInfo.Anchor = anchor;
|
skillInfo.Anchor = anchor;
|
||||||
skillInfo.EndTick = Server.TickCount + (int)(SkillsInfo.GetValue<float>(skillName, "maxPullSeconds") * 64);
|
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())
|
if (!EntityManager.OverBudget())
|
||||||
{
|
{
|
||||||
Color ropeColor = player.Team == CsTeam.Terrorist ? terroristRope : counterTerroristRope;
|
Color ropeColor = player.Team == CsTeam.Terrorist ? terroristRope : counterTerroristRope;
|
||||||
|
|
@ -155,15 +160,102 @@ namespace src.player.skills
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.EmitSound("SolidMetal.BulletImpact");
|
|
||||||
return true;
|
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)
|
private static void DestroyRope(PlayerSkillInfo skillInfo)
|
||||||
{
|
{
|
||||||
skillInfo.Anchor = null;
|
skillInfo.Anchor = null;
|
||||||
skillInfo.EndTick = 0;
|
skillInfo.EndTick = 0;
|
||||||
|
|
||||||
|
DestroyHook(skillInfo);
|
||||||
|
|
||||||
if (skillInfo.RopeIndex == null) return;
|
if (skillInfo.RopeIndex == null) return;
|
||||||
|
|
||||||
uint ropeIndex = skillInfo.RopeIndex.Value;
|
uint ropeIndex = skillInfo.RopeIndex.Value;
|
||||||
|
|
@ -176,26 +268,7 @@ namespace src.player.skills
|
||||||
{
|
{
|
||||||
if (!liveRopes.TryRemove(ropeIndex, out _)) return;
|
if (!liveRopes.TryRemove(ropeIndex, out _)) return;
|
||||||
|
|
||||||
var rope = Utilities.GetEntityFromIndex<CBeam>((int)ropeIndex);
|
EntityManager.DestroyBeam(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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SweepOrphanRopes()
|
private static void SweepOrphanRopes()
|
||||||
|
|
@ -299,11 +372,13 @@ namespace src.player.skills
|
||||||
public DateTime LastAttempt { get; set; }
|
public DateTime LastAttempt { get; set; }
|
||||||
public Vector? Anchor { get; set; }
|
public Vector? Anchor { get; set; }
|
||||||
public uint? RopeIndex { get; set; }
|
public uint? RopeIndex { get; set; }
|
||||||
|
public uint? HookIndex { get; set; }
|
||||||
public int EndTick { 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 Cooldown { get; set; } = cooldown;
|
||||||
public float MaxDistance { get; set; } = maxDistance;
|
public float MaxDistance { get; set; } = maxDistance;
|
||||||
public float MinDistance { get; set; } = minDistance;
|
public float MinDistance { get; set; } = minDistance;
|
||||||
|
|
@ -311,6 +386,8 @@ namespace src.player.skills
|
||||||
public float PullSpeed { get; set; } = pullSpeed;
|
public float PullSpeed { get; set; } = pullSpeed;
|
||||||
public float MaxPullSeconds { get; set; } = maxPullSeconds;
|
public float MaxPullSeconds { get; set; } = maxPullSeconds;
|
||||||
public float RopeWidth { get; set; } = ropeWidth;
|
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.GetDistance(smokePos, pawn.AbsOrigin) <= smokeRadius)
|
||||||
if (SkillUtils.AddHealth(pawn, smokeHeal))
|
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);
|
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 int SmokeHeal { get; set; } = smokeHeal;
|
||||||
public float SmokeRadius { get; set; } = smokeRadius;
|
public float SmokeRadius { get; set; } = smokeRadius;
|
||||||
public int TickCooldown { get; set; } = tickCooldown;
|
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
|
public class Hermit : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Hermit;
|
private const Skills skillName = Skills.Hermit;
|
||||||
private static readonly ConcurrentDictionary<string, int> ConcurrentDictionary = new(
|
private const int fallbackReserveAmmo = 100;
|
||||||
[
|
|
||||||
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;
|
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
|
|
@ -43,9 +31,11 @@ namespace src.player.skills
|
||||||
var weapon = pawn.WeaponServices.ActiveWeapon.Value;
|
var weapon = pawn.WeaponServices.ActiveWeapon.Value;
|
||||||
if (weapon == null || !weapon.IsValid || weapon.VData == null) return;
|
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.Clip1 = weapon.VData.MaxClip1;
|
||||||
weapon.ReserveAmmo.Fill(maxReserveAmmoClip);
|
weapon.ReserveAmmo.Fill(reserve);
|
||||||
|
|
||||||
Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_iClip1");
|
Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_iClip1");
|
||||||
Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_pReserveAmmo");
|
Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_pReserveAmmo");
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ namespace src.player.skills
|
||||||
public class HotBomb : ISkill
|
public class HotBomb : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.HotBomb;
|
private const Skills skillName = Skills.HotBomb;
|
||||||
|
private const string hurtSound = "Player.DamageBody.Victim";
|
||||||
private readonly static ConcurrentDictionary<uint, byte> players = [];
|
private readonly static ConcurrentDictionary<uint, byte> players = [];
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
|
|
@ -41,7 +42,7 @@ namespace src.player.skills
|
||||||
if (!hasC4) continue;
|
if (!hasC4) continue;
|
||||||
|
|
||||||
SkillUtils.TakeHealth(pawn, damage, owner, KillfeedIcons.C4);
|
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 float Cooldown { get; set; } = cooldown;
|
||||||
public int Damage { get; set; } = damage;
|
public int Damage { get; set; } = damage;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ namespace src.player.skills
|
||||||
var player = Utilities.GetPlayerFromIndex((int)playerSkill.PlayerIndex);
|
var player = Utilities.GetPlayerFromIndex((int)playerSkill.PlayerIndex);
|
||||||
if (player == null || !player.IsValid) return;
|
if (player == null || !player.IsValid) return;
|
||||||
|
|
||||||
player.EmitSound("SolidMetal.BulletImpact");
|
player.EmitSound("SolidMetal.BulletImpact", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||||
|
|
||||||
CDynamicProp? cloneProp = null;
|
CDynamicProp? cloneProp = null;
|
||||||
if (playerSkill.CloneProp != null)
|
if (playerSkill.CloneProp != null)
|
||||||
|
|
@ -468,8 +468,9 @@ namespace src.player.skills
|
||||||
public List<ulong> Weapons { get; set; } = [];
|
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 Cooldown { get; set; } = cooldown;
|
||||||
public float Duration { get; set; } = duration;
|
public float Duration { get; set; } = duration;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,18 @@ namespace src.player.skills
|
||||||
|
|
||||||
private static void SendAlertToAll()
|
private static void SendAlertToAll()
|
||||||
{
|
{
|
||||||
|
holdersTick = int.MinValue;
|
||||||
|
|
||||||
foreach (var player in PlayerManager.GetTickPlayers())
|
foreach (var player in PlayerManager.GetTickPlayers())
|
||||||
{
|
{
|
||||||
if (!CheckIlliterateSkill(player)) continue;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ namespace src.player.skills
|
||||||
|
|
||||||
if (!consumedReplicas.TryAdd(replica.Index, 0)) return;
|
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();
|
if (ActiveTimers.TryRemove((int)replica.Index, out var timer)) timer?.Kill();
|
||||||
|
|
||||||
var owner = GetReplicaOwner(replica.Index);
|
var owner = GetReplicaOwner(replica.Index);
|
||||||
|
|
@ -230,8 +230,9 @@ namespace src.player.skills
|
||||||
public DateTime Cooldown { get; set; }
|
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 Cooldown { get; set; } = cooldown;
|
||||||
public float DurationRun { get; set; } = durationRun;
|
public float DurationRun { get; set; } = durationRun;
|
||||||
public float DurationCrouch { get; set; } = durationCrouch;
|
public float DurationCrouch { get; set; } = durationCrouch;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ namespace src.player.skills
|
||||||
public class Jammer : ISkill
|
public class Jammer : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Jammer;
|
private const Skills skillName = Skills.Jammer;
|
||||||
|
private const string ownerTag = "Jammer";
|
||||||
private static readonly ConcurrentDictionary<uint, byte> jammedPlayers = [];
|
private static readonly ConcurrentDictionary<uint, byte> jammedPlayers = [];
|
||||||
private static readonly ConcurrentDictionary<uint, uint> jammerToTarget = [];
|
private static readonly ConcurrentDictionary<uint, uint> jammerToTarget = [];
|
||||||
private static readonly object setLock = new();
|
private static readonly object setLock = new();
|
||||||
|
|
@ -118,14 +119,7 @@ namespace src.player.skills
|
||||||
|
|
||||||
private static void SetCrosshair(CCSPlayerController player, bool enabled)
|
private static void SetCrosshair(CCSPlayerController player, bool enabled)
|
||||||
{
|
{
|
||||||
var pawn = player.PlayerPawn.Value;
|
SkillUtils.SetCrosshairHidden(player, ownerTag, !enabled);
|
||||||
if (pawn == null || !pawn.IsValid) return;
|
|
||||||
|
|
||||||
pawn.HideHUD = (uint)(enabled
|
|
||||||
? (pawn.HideHUD & ~(1 << 8))
|
|
||||||
: (pawn.HideHUD | (1 << 8)));
|
|
||||||
|
|
||||||
Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_iHideHUD");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void BotTakeover(EventBotTakeover @event)
|
public static void BotTakeover(EventBotTakeover @event)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ namespace src.player.skills
|
||||||
public class Jester : ISkill
|
public class Jester : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Jester;
|
private const Skills skillName = Skills.Jester;
|
||||||
|
private const string toggleSound = "Weapon_Taser.ChargeReady";
|
||||||
private static readonly ConcurrentDictionary<uint, JesterInfo> jesters = [];
|
private static readonly ConcurrentDictionary<uint, JesterInfo> jesters = [];
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
|
|
@ -196,7 +197,7 @@ namespace src.player.skills
|
||||||
|
|
||||||
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
var playerEvent = PlayerManager.GetPlayerFromEvent(player);
|
||||||
if (playerEvent != null && playerEvent.IsValid)
|
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");
|
var minTime = SkillsInfo.GetValue<float>(skillName, "minTime");
|
||||||
|
|
@ -275,8 +276,9 @@ namespace src.player.skills
|
||||||
public Timer? Timer { get; set; } = null;
|
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 MinTime { get; set; } = minTime;
|
||||||
public float MaxTime { get; set; } = maxTime;
|
public float MaxTime { get; set; } = maxTime;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,8 @@ namespace src.player.skills
|
||||||
|
|
||||||
private static void PushPlayer(CCSPlayerController player)
|
private static void PushPlayer(CCSPlayerController player)
|
||||||
{
|
{
|
||||||
|
if (Heavyweight.Resists(player)) return;
|
||||||
|
|
||||||
var playerPawn = player.PlayerPawn.Value;
|
var playerPawn = player.PlayerPawn.Value;
|
||||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0) return;
|
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ namespace src.player.skills
|
||||||
public class LastGasp : ISkill
|
public class LastGasp : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.LastGasp;
|
private const Skills skillName = Skills.LastGasp;
|
||||||
|
private const string hurtSound = "Player.DamageBody.Victim";
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
|
|
@ -45,11 +46,12 @@ namespace src.player.skills
|
||||||
}
|
}
|
||||||
|
|
||||||
SkillUtils.TakeHealth(attackerPawn, damageAfterDeath, victim, KillfeedIcons.Fist);
|
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 int DamageAfterDeath { get; set; } = damageAfterDeath;
|
||||||
public bool CanKill { get; set; } = canKill;
|
public bool CanKill { get; set; } = canKill;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ namespace src.player.skills
|
||||||
public class LongKnife : ISkill
|
public class LongKnife : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.LongKnife;
|
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 static bool hooked = false;
|
||||||
private const int actionCode = 503;
|
private const int actionCode = 503;
|
||||||
|
|
@ -121,12 +124,15 @@ namespace src.player.skills
|
||||||
|
|
||||||
if (!SkillsInfo.GetValue<bool>(skillName, "friendlyFire") && player.Team == target.Team) return;
|
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);
|
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 float MaxDistance { get; set; } = maxDistance;
|
||||||
public bool FriendlyFire { get; set; } = friendlyFire;
|
public bool FriendlyFire { get; set; } = friendlyFire;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,19 @@ namespace src.player.skills
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||||
|
DecoyRing.PreloadAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NewRound()
|
public static void NewRound()
|
||||||
{
|
{
|
||||||
decoys.Clear();
|
decoys.Clear();
|
||||||
|
DecoyRing.ClearAll(skillName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RoundEnd()
|
||||||
|
{
|
||||||
|
decoys.Clear();
|
||||||
|
DecoyRing.ClearAll(skillName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DecoyStarted(EventDecoyStarted @event)
|
public static void DecoyStarted(EventDecoyStarted @event)
|
||||||
|
|
@ -31,7 +39,9 @@ namespace src.player.skills
|
||||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||||
if (playerInfo?.Skill != skillName) return;
|
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)
|
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))
|
foreach (var decoy in decoys.Keys.Where(v => v.X == @event.X && v.Y == @event.Y && v.Z == @event.Z))
|
||||||
decoys.TryRemove(decoy, out _);
|
decoys.TryRemove(decoy, out _);
|
||||||
|
|
||||||
|
DecoyRing.Hide(skillName, (uint)@event.Entityid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnTick()
|
public static void OnTick()
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ namespace src.player.skills
|
||||||
skillInfo.Cooldown = DateTime.Now;
|
skillInfo.Cooldown = DateTime.Now;
|
||||||
skillInfo.Count -= 1;
|
skillInfo.Count -= 1;
|
||||||
SkillUtils.AddHealth(playerPawn, SkillsInfo.GetValue<int>(skillName, "healthToAdd"));
|
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 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 HealthToAdd { get; set; } = healthToAdd;
|
||||||
public int HealthShotLimit { get; set; } = healthShotLimit;
|
public int HealthShotLimit { get; set; } = healthShotLimit;
|
||||||
public float Cooldown { get; set; } = cooldown;
|
public float Cooldown { get; set; } = cooldown;
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ namespace src.player.skills
|
||||||
position.Z += 60;
|
position.Z += 60;
|
||||||
grenade.Teleport(position);
|
grenade.Teleport(position);
|
||||||
|
|
||||||
grenade.EmitSound("IncGrenade.Bounce_M");
|
grenade.EmitSound("IncGrenade.Bounce_M", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||||
|
|
||||||
grenade.DetonateTime = Server.CurrentTime + .5f;
|
grenade.DetonateTime = Server.CurrentTime + .5f;
|
||||||
Utilities.SetStateChanged(grenade, "CBaseGrenade", "m_flDetonateTime");
|
Utilities.SetStateChanged(grenade, "CBaseGrenade", "m_flDetonateTime");
|
||||||
|
|
@ -161,8 +161,9 @@ namespace src.player.skills
|
||||||
SkillUtils.UpdateGrenadeCount(player, CsItem.HEGrenade, 1);
|
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 float DetonationRange { get; set; } = detonationRange;
|
||||||
public int GrenadeLimit { get; set; } = grenadeLimit;
|
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
|
public class Nightmare : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Nightmare;
|
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> playersToTarget = [];
|
||||||
private static readonly ConcurrentDictionary<uint, uint> targetVolumes = [];
|
private static readonly ConcurrentDictionary<uint, uint> targetVolumes = [];
|
||||||
private static readonly object setLock = new();
|
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));
|
playerEvent.PrintToChat($" {ChatColors.Green}" + playerEvent.GetTranslation("nightmare_player_info", enemy.PlayerName));
|
||||||
|
|
||||||
if (enemyEvent != null && enemyEvent.IsValid)
|
if (enemyEvent != null && enemyEvent.IsValid)
|
||||||
|
{
|
||||||
enemyEvent.PrintToChat($" {ChatColors.Red}" + enemyEvent.GetTranslation("nightmare_enemy_info"));
|
enemyEvent.PrintToChat($" {ChatColors.Red}" + enemyEvent.GetTranslation("nightmare_enemy_info"));
|
||||||
|
SkillUtils.EmitSoundToPlayer(enemyEvent, cursedSound, SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DisableSkill(CCSPlayerController player)
|
public static void DisableSkill(CCSPlayerController player)
|
||||||
|
|
@ -227,8 +231,9 @@ namespace src.player.skills
|
||||||
EntityManager.DestroyEntity(volumeIndex);
|
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 string PostProcessing { get; set; } = postProcessing;
|
||||||
public float FadeTime { get; set; } = fadeTime;
|
public float FadeTime { get; set; } = fadeTime;
|
||||||
public float MinExposure { get; set; } = minExposure;
|
public float MinExposure { get; set; } = minExposure;
|
||||||
|
|
|
||||||
|
|
@ -63,37 +63,29 @@ namespace src.player.skills
|
||||||
var bomb = PlayerManager.GetTickBomb();
|
var bomb = PlayerManager.GetTickBomb();
|
||||||
uint? bombOwnerIndex = bomb != null && bomb.IsValid ? bomb.OwnerEntity?.Index : null;
|
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)
|
foreach (var (info, player) in infoList)
|
||||||
{
|
{
|
||||||
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
if (player == null || !player.IsValid || player.Team == CsTeam.Spectator) continue;
|
||||||
|
|
||||||
var targetHandle = player.Pawn.Value?.ObserverServices?.ObserverTarget.Value?.Handle ?? nint.Zero;
|
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 (target.Index == player.Index) continue;
|
||||||
if (playerController == null || !playerController.IsValid || playerController.Index == player.Index)
|
if (player.Team == target.Team) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (player.Team == playerController.Team)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var playerPawn = playerController.PlayerPawn.Value;
|
|
||||||
if (playerPawn == null || !playerPawn.IsValid) continue;
|
|
||||||
|
|
||||||
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
// Only the actively spectated pawn stays transmitted; hiding it breaks the camera.
|
||||||
if (targetHandle != nint.Zero && playerPawn.Handle == targetHandle)
|
if (targetHandle != nint.Zero && target.Pawn.Handle == targetHandle) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
var entity = Utilities.GetEntityFromIndex<CBaseEntity>((int)playerPawn.Index);
|
if (info.TransmitEntities.Contains(target.Pawn.Index))
|
||||||
if (entity == null || !entity.IsValid) continue;
|
info.TransmitEntities.Remove(target.Pawn.Index);
|
||||||
|
|
||||||
if (info.TransmitEntities.Contains(entity.Index))
|
SkillUtils.HideCarriedEntities(info, target.Pawn);
|
||||||
info.TransmitEntities.Remove(entity.Index);
|
|
||||||
|
|
||||||
SkillUtils.HideCarriedEntities(info, playerPawn);
|
if (bomb == null || !target.HoldsBomb) continue;
|
||||||
|
|
||||||
if (bomb == null || bombOwnerIndex != playerController.Index) continue;
|
|
||||||
|
|
||||||
if (info.TransmitEntities.Contains(bomb.Index))
|
if (info.TransmitEntities.Contains(bomb.Index))
|
||||||
info.TransmitEntities.Remove(bomb.Index);
|
info.TransmitEntities.Remove(bomb.Index);
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,14 @@ namespace src.player.skills
|
||||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly HashSet<string> blockedWeapons =
|
private const string infernoDamage = "inferno";
|
||||||
["hegrenade", "inferno", "decoy", "flashbang", "smokegrenade", "molotov"];
|
|
||||||
|
|
||||||
public static bool PlayerHurtPre(EventPlayerHurt @event)
|
public static bool PlayerHurtPre(EventPlayerHurt @event)
|
||||||
{
|
{
|
||||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||||
if (!Instance.IsPlayerValid(player)) return false;
|
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;
|
if (PlayerManager.GetPlayerByIndex(player!.Index)?.Skill != skillName) return false;
|
||||||
|
|
||||||
SkillUtils.RestoreHealth(player);
|
SkillUtils.RestoreHealth(player);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ namespace src.player.skills
|
||||||
public class PawelJumper : ISkill
|
public class PawelJumper : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.PawelJumper;
|
private const Skills skillName = Skills.PawelJumper;
|
||||||
|
private const string jumpSound = "Default.WalkJump";
|
||||||
private static readonly int?[] J = new int?[64];
|
private static readonly int?[] J = new int?[64];
|
||||||
private static readonly PlayerButtons[] LB = new PlayerButtons[64];
|
private static readonly PlayerButtons[] LB = new PlayerButtons[64];
|
||||||
|
|
||||||
|
|
@ -73,13 +74,17 @@ namespace src.player.skills
|
||||||
{
|
{
|
||||||
J[player.Slot]++;
|
J[player.Slot]++;
|
||||||
playerEventPawn.AbsVelocity.Z = 300;
|
playerEventPawn.AbsVelocity.Z = 300;
|
||||||
|
|
||||||
|
if (J[player.Slot] > 1)
|
||||||
|
playerEventPawn.EmitSound(jumpSound, volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||||
}
|
}
|
||||||
|
|
||||||
LB[player.Slot] = buttons;
|
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 ExtraJumpsMin { get; set; } = extraJumpsMin;
|
||||||
public int ExtraJumpsMax { get; set; } = extraJumpsMax;
|
public int ExtraJumpsMax { get; set; } = extraJumpsMax;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,29 @@ namespace src.player.skills
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||||
|
Instance.AddToManifest(SkillsInfo.GetValue<string>(skillName, "particleName"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void NewRound()
|
public static void NewRound()
|
||||||
{
|
{
|
||||||
|
foreach (var pilotInfo in PlayerPilotInfo.Values)
|
||||||
|
ClearTrail(pilotInfo);
|
||||||
|
|
||||||
PlayerPilotInfo.Clear();
|
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()
|
public static void OnTick()
|
||||||
{
|
{
|
||||||
foreach (var player in PlayerManager.GetTickPlayers())
|
foreach (var player in PlayerManager.GetTickPlayers())
|
||||||
|
|
@ -39,7 +55,9 @@ namespace src.player.skills
|
||||||
|
|
||||||
public static void DisableSkill(CCSPlayerController player)
|
public static void DisableSkill(CCSPlayerController player)
|
||||||
{
|
{
|
||||||
PlayerPilotInfo.TryRemove(player.Index, out _);
|
if (PlayerPilotInfo.TryRemove(player.Index, out var pilotInfo))
|
||||||
|
ClearTrail(pilotInfo);
|
||||||
|
|
||||||
SkillUtils.ResetPrintHTML(player);
|
SkillUtils.ResetPrintHTML(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,9 +114,18 @@ namespace src.player.skills
|
||||||
);
|
);
|
||||||
|
|
||||||
if (inUse)
|
if (inUse)
|
||||||
|
{
|
||||||
ApplyPilotEffect(player);
|
ApplyPilotEffect(player);
|
||||||
else if (pilotInfo.Fuel <= 0)
|
StartTrail(player, playerPawn, pilotInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pilotInfo.TrailIndex != null)
|
||||||
|
ClearTrail(pilotInfo);
|
||||||
|
|
||||||
|
if (pilotInfo.Fuel <= 0)
|
||||||
pilotInfo.IsFlying = false;
|
pilotInfo.IsFlying = false;
|
||||||
|
}
|
||||||
|
|
||||||
pilotInfo.LastButtons = buttons;
|
pilotInfo.LastButtons = buttons;
|
||||||
UpdateHUD(player, pilotInfo);
|
UpdateHUD(player, pilotInfo);
|
||||||
|
|
@ -132,6 +159,62 @@ namespace src.player.skills
|
||||||
return "#FF0000";
|
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)
|
private static void ApplyPilotEffect(CCSPlayerController player)
|
||||||
{
|
{
|
||||||
var playerPawn = player.PlayerPawn.Value;
|
var playerPawn = player.PlayerPawn.Value;
|
||||||
|
|
@ -168,10 +251,13 @@ namespace src.player.skills
|
||||||
public int JumpCount { get; set; } = 0;
|
public int JumpCount { get; set; } = 0;
|
||||||
public float LastJumpTime { get; set; } = 0;
|
public float LastJumpTime { get; set; } = 0;
|
||||||
public bool IsFlying { get; set; } = false;
|
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 MaximumFuel { get; set; } = maximumFuel;
|
||||||
public float FuelConsumption { get; set; } = fuelConsumption;
|
public float FuelConsumption { get; set; } = fuelConsumption;
|
||||||
public float Refuelling { get; set; } = refuelling;
|
public float Refuelling { get; set; } = refuelling;
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,8 @@ namespace src.player.skills
|
||||||
public static void OnTick()
|
public static void OnTick()
|
||||||
{
|
{
|
||||||
float currentTime = Server.CurrentTime;
|
float currentTime = Server.CurrentTime;
|
||||||
|
bool hudFrame = SkillUtils.IsHudFrame();
|
||||||
|
|
||||||
foreach (var player in PlayerManager.GetTickPlayers().Where(p => p.Team == CsTeam.Terrorist))
|
foreach (var player in PlayerManager.GetTickPlayers().Where(p => p.Team == CsTeam.Terrorist))
|
||||||
{
|
{
|
||||||
if (!Instance.IsPlayerValid(player)) continue;
|
if (!Instance.IsPlayerValid(player)) continue;
|
||||||
|
|
@ -111,7 +113,7 @@ namespace src.player.skills
|
||||||
pawn.InBombZone = true;
|
pawn.InBombZone = true;
|
||||||
Schema.SetSchemaValue<bool>(pawn.Handle, "CCSPlayerPawn", "m_bInBombZone", 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;
|
float remaining = plantTime + 3f - currentTime;
|
||||||
playerInfo.PrintHTML = $"{player.GetTranslation("planter_planting", $"<font color='#00FF00'>{Math.Max(0, remaining):0.0}s</font>")}";
|
playerInfo.PrintHTML = $"{player.GetTranslation("planter_planting", $"<font color='#00FF00'>{Math.Max(0, remaining):0.0}s</font>")}";
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ namespace src.player.skills
|
||||||
public class Poison : ISkill
|
public class Poison : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Poison;
|
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, byte> poisonedPlayers = [];
|
||||||
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
||||||
private static readonly ConcurrentDictionary<uint, uint> targetToPlayer = [];
|
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);
|
SkillUtils.TakeHealth(pawn, SkillsInfo.GetValue<int>(skillName, "Damage"), GetSkillOwner(playerIndex), KillfeedIcons.Spray);
|
||||||
|
|
||||||
if (Server.TickCount % cooldown2 == 0)
|
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);
|
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 int Damage { get; set; } = damage;
|
||||||
public float Cooldown { get; set; } = cooldown;
|
public float Cooldown { get; set; } = cooldown;
|
||||||
public int MinHealth { get; set; } = minHealth;
|
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, byte> bannedPlayers = [];
|
||||||
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
||||||
private static readonly object setLock = new();
|
private static readonly object setLock = new();
|
||||||
private static readonly string[] disabledWeapons =
|
private static HashSet<string> disabledWeapons => WeaponPool.Rifles;
|
||||||
[
|
|
||||||
"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"
|
|
||||||
];
|
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ namespace src.player.skills
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.Defusing)
|
if (!info.Defusing)
|
||||||
pawn.EmitSound("c4.disarmstart");
|
pawn.EmitSound("c4.disarmstart", volume: SkillsInfo.GetValue<float>(skillName, "soundVolume"));
|
||||||
info.Defusing = true;
|
info.Defusing = true;
|
||||||
info.DefusingTime -= (1f / tickRate);
|
info.DefusingTime -= (1f / tickRate);
|
||||||
|
|
||||||
|
|
@ -128,8 +128,9 @@ namespace src.player.skills
|
||||||
public float DefusingTime { get; set; }
|
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 MaxDefusingRange { get; set; } = maxDefusingRange;
|
||||||
public float DefusingTime { get; set; } = defusingTime;
|
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)
|
if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (Heavyweight.Resists(victim)) return;
|
||||||
|
|
||||||
var playerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
var playerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
||||||
|
|
||||||
if (playerInfo?.Skill == skillName && victim!.PawnIsAlive)
|
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 ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = new();
|
||||||
private static readonly object setLock = new();
|
private static readonly object setLock = new();
|
||||||
|
|
||||||
private static readonly HashSet<string> pistols = new(StringComparer.Ordinal)
|
private static HashSet<string> pistols => WeaponPool.Pistols;
|
||||||
{
|
private static HashSet<string> rifles => WeaponPool.Rifles;
|
||||||
"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"
|
|
||||||
};
|
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
|
|
@ -104,6 +93,19 @@ namespace src.player.skills
|
||||||
RemoveAndGiveWeapon(player);
|
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)
|
private static void RemoveAndGiveWeapon(CCSPlayerController player)
|
||||||
{
|
{
|
||||||
var pawn = player.PlayerPawn.Value;
|
var pawn = player.PlayerPawn.Value;
|
||||||
|
|
@ -117,12 +119,15 @@ namespace src.player.skills
|
||||||
if (playerWeapons.Count == 0)
|
if (playerWeapons.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var available = pistols.Concat(rifles).Where(w => !playerWeapons.Contains(w)).ToArray();
|
var availablePistols = pistols.Where(w => !playerWeapons.Contains(w)).ToArray();
|
||||||
if (available.Length == 0)
|
var availableRifles = rifles.Where(w => !playerWeapons.Contains(w)).ToArray();
|
||||||
|
if (availablePistols.Length == 0 && availableRifles.Length == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bool isPistol = RollPistol(availablePistols.Length > 0, availableRifles.Length > 0);
|
||||||
|
var available = isPistol ? availablePistols : availableRifles;
|
||||||
|
|
||||||
string newWeapon = available[Instance.Random.Next(available.Length)];
|
string newWeapon = available[Instance.Random.Next(available.Length)];
|
||||||
bool isPistol = pistols.Contains(newWeapon);
|
|
||||||
|
|
||||||
string? weaponToRemove = null;
|
string? weaponToRemove = null;
|
||||||
foreach (var item in pawn.WeaponServices.MyWeapons)
|
foreach (var item in pawn.WeaponServices.MyWeapons)
|
||||||
|
|
@ -163,9 +168,11 @@ namespace src.player.skills
|
||||||
public DateTime Cooldown { get; set; }
|
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 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;
|
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);
|
var owner = GetReplicaOwner(replica.Index);
|
||||||
EntityManager.DestroyEntity(replica.Index);
|
EntityManager.DestroyEntity(replica.Index);
|
||||||
|
|
@ -183,8 +183,9 @@ namespace src.player.skills
|
||||||
public DateTime Cooldown { get; set; }
|
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 float Cooldown { get; set; } = cooldown;
|
||||||
public int YourTeamDamage { get; set; } = yourTeamDamage;
|
public int YourTeamDamage { get; set; } = yourTeamDamage;
|
||||||
public int EnemyTeamDamage { get; set; } = enemyTeamDamage;
|
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
|
public class Ricochet : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Ricochet;
|
private const Skills skillName = Skills.Ricochet;
|
||||||
|
private const string bounceSound = "FX_RicochetSound.Ricochet_Legacy";
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<uint, ImpactBudget> impactBudgets = [];
|
private static readonly ConcurrentDictionary<uint, ImpactBudget> impactBudgets = [];
|
||||||
private static readonly HashSet<uint> ownedTracers = [];
|
private static readonly HashSet<uint> ownedTracers = [];
|
||||||
|
|
@ -57,18 +58,10 @@ namespace src.player.skills
|
||||||
|
|
||||||
if (PlayerManager.GetPlayerByIndex(player.Index)?.Skill != skillName) return;
|
if (PlayerManager.GetPlayerByIndex(player.Index)?.Skill != skillName) return;
|
||||||
|
|
||||||
if (!RayTrace.IsAvailable)
|
if (!RayTrace.IsAvailable) return;
|
||||||
{
|
|
||||||
Trace("RayTrace module unavailable");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pawn = player.PlayerPawn?.Value;
|
var pawn = player.PlayerPawn?.Value;
|
||||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
|
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
||||||
{
|
|
||||||
Trace("shooter pawn invalid or dead");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryConsumeBudget(player.Index)) return;
|
if (!TryConsumeBudget(player.Index)) return;
|
||||||
|
|
||||||
|
|
@ -76,32 +69,14 @@ namespace src.player.skills
|
||||||
Vector3 impact = new(@event.X, @event.Y, @event.Z);
|
Vector3 impact = new(@event.X, @event.Y, @event.Z);
|
||||||
|
|
||||||
Vector3 toImpact = impact - eyePos;
|
Vector3 toImpact = impact - eyePos;
|
||||||
if (toImpact.LengthSquared() < 1f)
|
if (toImpact.LengthSquared() < 1f) return;
|
||||||
{
|
|
||||||
Trace("impact too close to eye");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 direction = Vector3.Normalize(toImpact);
|
Vector3 direction = Vector3.Normalize(toImpact);
|
||||||
|
|
||||||
var surface = RayTrace.TraceShape(player, ToVector(eyePos), ToVector(impact + direction * 8f), worldOnlyMask, 0);
|
var surface = RayTrace.TraceShape(player, ToVector(eyePos), ToVector(impact + direction * 8f), worldOnlyMask, 0);
|
||||||
if (surface == null)
|
if (surface == null || !surface.Value.DidHit) return;
|
||||||
{
|
|
||||||
Trace("surface trace returned null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!surface.Value.DidHit)
|
if (!TryResolveNormal(player, surface.Value, direction, out Vector3 normal)) return;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bounce(player, pawn, surface.Value.EndPos, direction, normal);
|
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));
|
KillfeedIcons? killfeedIcon = KillfeedIconsExtensions.FromWeaponName(SkillUtils.GetDesignerName(pawn.WeaponServices?.ActiveWeapon?.Value));
|
||||||
|
|
||||||
List<Vector3> path = [];
|
List<Vector3> path = [];
|
||||||
|
List<int> soundAt = [];
|
||||||
|
|
||||||
for (int i = 0; i < bounces; i++)
|
for (int i = 0; i < bounces; i++)
|
||||||
{
|
{
|
||||||
direction = Vector3.Reflect(direction, normal);
|
direction = Vector3.Reflect(direction, normal);
|
||||||
|
|
||||||
Vector3 start = point + normal * 2f;
|
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;
|
Vector3 end = start + direction * segmentDistance;
|
||||||
|
|
||||||
var hit = RayTrace.TraceShape(player, ToVector(start), ToVector(end));
|
var hit = RayTrace.TraceShape(player, ToVector(start), ToVector(end));
|
||||||
if (hit == null)
|
if (hit == null) break;
|
||||||
{
|
|
||||||
Trace($"bounce {i + 1}: segment trace returned null");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 stop = hit.Value.DidHit ? hit.Value.EndPos : end;
|
Vector3 stop = hit.Value.DidHit ? hit.Value.EndPos : end;
|
||||||
path.Add(stop);
|
path.Add(stop);
|
||||||
|
|
||||||
if (!hit.Value.DidHit)
|
if (!hit.Value.DidHit) break;
|
||||||
{
|
|
||||||
Trace($"bounce {i + 1}: no surface, len={Vector3.Distance(start, stop):0.#}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit.Value.HitPlayer(out var victim))
|
if (hit.Value.HitPlayer(out var victim))
|
||||||
{
|
{
|
||||||
|
|
@ -150,17 +122,14 @@ namespace src.player.skills
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryResolveNormal(player, hit.Value, direction, out normal))
|
if (!TryResolveNormal(player, hit.Value, direction, out normal)) break;
|
||||||
{
|
|
||||||
Trace($"bounce {i + 1}: could not resolve normal");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
soundAt.Add(path.Count - 1);
|
||||||
point = hit.Value.EndPos;
|
point = hit.Value.EndPos;
|
||||||
damage *= damageFalloff;
|
damage *= damageFalloff;
|
||||||
}
|
}
|
||||||
|
|
||||||
StartFlight(player, path);
|
StartFlight(player, path, soundAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnTick()
|
public static void OnTick()
|
||||||
|
|
@ -191,11 +160,12 @@ namespace src.player.skills
|
||||||
float tail = MathF.Max(head - trail, flight.Cumulative[segment]);
|
float tail = MathF.Max(head - trail, flight.Cumulative[segment]);
|
||||||
|
|
||||||
UpdateTracer(flight, PointAt(flight, tail), PointAt(flight, head));
|
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 (path.Count < 2) return;
|
||||||
if (!SkillsInfo.GetValue<bool>(skillName, "showTracer")) return;
|
if (!SkillsInfo.GetValue<bool>(skillName, "showTracer")) return;
|
||||||
|
|
@ -223,10 +193,27 @@ namespace src.player.skills
|
||||||
Cumulative = cumulative,
|
Cumulative = cumulative,
|
||||||
TotalLength = total,
|
TotalLength = total,
|
||||||
DeadlineTick = Server.TickCount + (int)(total / speed * 64f) + 128,
|
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)
|
private static int SegmentAt(Flight flight, float distance)
|
||||||
{
|
{
|
||||||
for (int i = flight.Points.Length - 2; i >= 0; i--)
|
for (int i = flight.Points.Length - 2; i >= 0; i--)
|
||||||
|
|
@ -332,9 +319,8 @@ namespace src.player.skills
|
||||||
beam.DispatchSpawn();
|
beam.DispatchSpawn();
|
||||||
return beam;
|
return beam;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
Trace($"beam create failed: {ex.Message}");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -352,7 +338,6 @@ namespace src.player.skills
|
||||||
if (beam == null)
|
if (beam == null)
|
||||||
{
|
{
|
||||||
ownedTracers.Remove(beamIndex);
|
ownedTracers.Remove(beamIndex);
|
||||||
Trace($"tracer {beamIndex} vanished before release");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -395,9 +380,6 @@ namespace src.player.skills
|
||||||
if (beam != null) HideTracer(beam);
|
if (beam != null) HideTracer(beam);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ownedTracers.Count > 0)
|
|
||||||
Trace($"pool reset: {ownedTracers.Count} tracer(s) released");
|
|
||||||
|
|
||||||
tracerPool.Clear();
|
tracerPool.Clear();
|
||||||
ownedTracers.Clear();
|
ownedTracers.Clear();
|
||||||
}
|
}
|
||||||
|
|
@ -454,7 +436,6 @@ namespace src.player.skills
|
||||||
int finalDamage = (int)MathF.Round(damage);
|
int finalDamage = (int)MathF.Round(damage);
|
||||||
if (finalDamage <= 0) return;
|
if (finalDamage <= 0) return;
|
||||||
|
|
||||||
Trace($"hit {victimEvent.PlayerName} for {finalDamage}");
|
|
||||||
SkillUtils.TakeHealth(victimPawn, finalDamage, attacker, killfeedIcon ?? KillfeedIcons.Leg);
|
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;
|
if (TryRefineNormal(player, result.EndPos, direction, rough, out normal)) return true;
|
||||||
|
|
||||||
Trace("surface refine failed, using rough normal");
|
|
||||||
normal = rough;
|
normal = rough;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -600,11 +580,6 @@ namespace src.player.skills
|
||||||
return Vector3.Distance(point, baseHit) <= tolerance;
|
return Vector3.Distance(point, baseHit) <= tolerance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Trace(string message)
|
|
||||||
{
|
|
||||||
Debug.WriteToDebug($"[Ricochet] {message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryConsumeBudget(uint playerIndex)
|
private static bool TryConsumeBudget(uint playerIndex)
|
||||||
{
|
{
|
||||||
int tick = Server.TickCount;
|
int tick = Server.TickCount;
|
||||||
|
|
@ -637,12 +612,15 @@ namespace src.player.skills
|
||||||
public required float[] Cumulative { get; set; }
|
public required float[] Cumulative { get; set; }
|
||||||
public required float TotalLength { get; set; }
|
public required float TotalLength { get; set; }
|
||||||
public required int DeadlineTick { get; set; }
|
public required int DeadlineTick { get; set; }
|
||||||
|
public required int[] SoundAt { get; set; }
|
||||||
public float Travelled { get; set; }
|
public float Travelled { get; set; }
|
||||||
|
public int NextSound { get; set; }
|
||||||
public uint? BeamIndex { 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 int Bounces { get; set; } = bounces;
|
||||||
public float SegmentDistance { get; set; } = segmentDistance;
|
public float SegmentDistance { get; set; } = segmentDistance;
|
||||||
public float DamageMultiplier { get; set; } = damageMultiplier;
|
public float DamageMultiplier { get; set; } = damageMultiplier;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ namespace src.player.skills
|
||||||
if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return;
|
if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return;
|
||||||
var attackerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
var attackerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
||||||
|
|
||||||
|
if (Heavyweight.Resists(victim)) return;
|
||||||
|
|
||||||
var victimPawn = victim!.PlayerPawn.Value;
|
var victimPawn = victim!.PlayerPawn.Value;
|
||||||
if (victimPawn == null || !victimPawn.IsValid) return;
|
if (victimPawn == null || !victimPawn.IsValid) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,7 @@ namespace src.player.skills
|
||||||
private static readonly object setLock = new();
|
private static readonly object setLock = new();
|
||||||
|
|
||||||
private const string weapon_awp = "weapon_awp";
|
private const string weapon_awp = "weapon_awp";
|
||||||
private static readonly string[] rifles =
|
private static HashSet<string> rifles => WeaponPool.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"
|
|
||||||
];
|
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
|
|
@ -81,7 +75,7 @@ namespace src.player.skills
|
||||||
foreach (var index in AWPs.ToList())
|
foreach (var index in AWPs.ToList())
|
||||||
SkillUtils.SafeKillEntity<CBasePlayerWeapon>(index);
|
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(() =>
|
Server.NextFrame(() =>
|
||||||
{
|
{
|
||||||
if (player == null || !player.IsValid || player.LifeState != (byte)LifeState_t.LIFE_ALIVE) return;
|
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 (SkillPlayerInfo.IsEmpty) return;
|
||||||
|
|
||||||
|
if (Server.TickCount % 60 != 0) return;
|
||||||
|
|
||||||
int cooldown = SkillsInfo.GetValue<int>(skillName, "cooldown");
|
int cooldown = SkillsInfo.GetValue<int>(skillName, "cooldown");
|
||||||
if (cooldown < 1) cooldown = 1;
|
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()
|
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))
|
.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)
|
if (entities.Count == 0)
|
||||||
{
|
{
|
||||||
player.PlayerPawn.Value!.EmitSound(soundEventName, volume: 1f);
|
player.PlayerPawn.Value!.EmitSound(soundEventName, volume: volume);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entity = Utilities.GetEntityFromIndex<CDynamicProp>((int)entities[0]);
|
var entity = Utilities.GetEntityFromIndex<CDynamicProp>((int)entities[0]);
|
||||||
if (entity != null && entity.IsValid)
|
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;
|
public int Cooldown { get; set; } = cooldown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ namespace src.player.skills
|
||||||
SetMagazines(player, playerMagazines + enemyMagazines);
|
SetMagazines(player, playerMagazines + enemyMagazines);
|
||||||
SetMagazines(enemy, 0);
|
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);
|
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
||||||
if (enemyEvent == null || !enemyEvent.IsValid) return;
|
if (enemyEvent == null || !enemyEvent.IsValid) return;
|
||||||
|
|
@ -299,8 +299,9 @@ namespace src.player.skills
|
||||||
public required int Reserve { get; set; }
|
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;
|
public float Cooldown { get; set; } = cooldown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,13 @@ namespace src.player.skills
|
||||||
damage = Math.Min(damage, SkillsInfo.GetValue<int>(skillName, "maxTakenDamagePerShot"));
|
damage = Math.Min(damage, SkillsInfo.GetValue<int>(skillName, "maxTakenDamagePerShot"));
|
||||||
|
|
||||||
SkillUtils.TakeHealth(attackerEvent.PlayerPawn.Value, damage, victimEvent, KillfeedIcons.Armor);
|
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 float HealthTakenScale { get; set; } = healthTakenScale;
|
||||||
public int MaxTakenDamagePerShot { get; set; } = maxTakenDamagePerShot;
|
public int MaxTakenDamagePerShot { get; set; } = maxTakenDamagePerShot;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ namespace src.player.skills
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SkillUtils.TakeHealth(pawn, damage, thrower, KillfeedIcons.Smokegrenade))
|
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);
|
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 int SmokeDamage { get; set; } = smokeDamage;
|
||||||
public float SmokeRadius { get; set; } = smokeRadius;
|
public float SmokeRadius { get; set; } = smokeRadius;
|
||||||
public int TickCooldown { get; set; } = tickCooldown;
|
public int TickCooldown { get; set; } = tickCooldown;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ namespace src.player.skills
|
||||||
public class Tripwire : ISkill
|
public class Tripwire : ISkill
|
||||||
{
|
{
|
||||||
private const Skills skillName = Skills.Tripwire;
|
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, WireInfo> wires = [];
|
||||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||||
|
|
@ -267,7 +268,7 @@ namespace src.player.skills
|
||||||
var ownerEvent = PlayerManager.GetPlayerFromEvent(owner);
|
var ownerEvent = PlayerManager.GetPlayerFromEvent(owner);
|
||||||
if (ownerEvent != null && ownerEvent.IsValid)
|
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));
|
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 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 RadarDuration { get; set; } = radarDuration;
|
||||||
public float TriggerRadius { get; set; } = triggerRadius;
|
public float TriggerRadius { get; set; } = triggerRadius;
|
||||||
public float WireHeight { get; set; } = wireHeight;
|
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
|
else
|
||||||
Localization.PrintTranslationToChatAll($" {ChatColors.LightBlue}{{0}}", ["watchmaker_ct"], true, [roundTime]);
|
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();
|
var proxy = Utilities.FindAllEntitiesByDesignerName<CCSGameRulesProxy>("cs_gamerules").FirstOrDefault();
|
||||||
if (proxy == null) return;
|
if (proxy == null) return;
|
||||||
Utilities.SetStateChanged(proxy, "CCSGameRulesProxy", "m_pGameRules");
|
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 int ChangeRoundTime { get; set; } = changeRoundTime;
|
||||||
public string SoundEvent { get; set; } = soundEvent;
|
public string SoundEvent { get; set; } = soundEvent;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,7 @@ namespace src.player.skills
|
||||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||||
private static readonly object setLock = new();
|
private static readonly object setLock = new();
|
||||||
|
|
||||||
private static readonly HashSet<string> weapons = [ "weapon_deagle", "weapon_revolver", "weapon_glock", "weapon_usp_silencer",
|
private static HashSet<string> weapons => WeaponPool.All;
|
||||||
"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" ];
|
|
||||||
|
|
||||||
public static void LoadSkill()
|
public static void LoadSkill()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ namespace src.utils
|
||||||
using (var sr = new StreamReader(fs))
|
using (var sr = new StreamReader(fs))
|
||||||
json = sr.ReadToEnd();
|
json = sr.ReadToEnd();
|
||||||
newConfig = JsonConvert.DeserializeObject<SettingsModel>(json) ?? new SettingsModel();
|
newConfig = JsonConvert.DeserializeObject<SettingsModel>(json) ?? new SettingsModel();
|
||||||
|
|
||||||
|
if (IsSectionMissing(json, nameof(SettingsModel.Weapons)))
|
||||||
|
SaveConfig(newConfig);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
@ -45,6 +48,18 @@ namespace src.utils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsSectionMissing(string json, string section)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Newtonsoft.Json.Linq.JObject.Parse(json)[section] == null;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void SaveConfig(SettingsModel config)
|
public static void SaveConfig(SettingsModel config)
|
||||||
{
|
{
|
||||||
lock (fileLock)
|
lock (fileLock)
|
||||||
|
|
@ -92,6 +107,7 @@ namespace src.utils
|
||||||
public string DisableHUDOnDeathPermission { get; set; }
|
public string DisableHUDOnDeathPermission { get; set; }
|
||||||
public bool DisableSkillsOnRoundEnd { get; set; }
|
public bool DisableSkillsOnRoundEnd { get; set; }
|
||||||
public int? CurseSkillPerPlayer { get; set; }
|
public int? CurseSkillPerPlayer { get; set; }
|
||||||
|
public WeaponPools Weapons { get; set; }
|
||||||
public LanguageSystem LanguageSystem { get; set; }
|
public LanguageSystem LanguageSystem { get; set; }
|
||||||
public HtmlHudCustomisation HtmlHudCustomisation { get; set; }
|
public HtmlHudCustomisation HtmlHudCustomisation { get; set; }
|
||||||
public ChatMessage ChatMessage { get; set; }
|
public ChatMessage ChatMessage { get; set; }
|
||||||
|
|
@ -124,6 +140,31 @@ namespace src.utils
|
||||||
DisableSkillsOnRoundEnd = false;
|
DisableSkillsOnRoundEnd = false;
|
||||||
CurseSkillPerPlayer = null;
|
CurseSkillPerPlayer = null;
|
||||||
|
|
||||||
|
Weapons = new WeaponPools
|
||||||
|
{
|
||||||
|
Rifle =
|
||||||
|
[
|
||||||
|
"weapon_ak47", "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"
|
||||||
|
],
|
||||||
|
Pistol =
|
||||||
|
[
|
||||||
|
"weapon_deagle", "weapon_revolver", "weapon_glock", "weapon_usp_silencer",
|
||||||
|
"weapon_cz75a", "weapon_fiveseven", "weapon_p250", "weapon_tec9",
|
||||||
|
"weapon_elite", "weapon_hkp2000"
|
||||||
|
],
|
||||||
|
Grenade =
|
||||||
|
[
|
||||||
|
"weapon_hegrenade", "weapon_flashbang", "weapon_smokegrenade",
|
||||||
|
"weapon_molotov", "weapon_incgrenade", "weapon_decoy"
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
LanguageSystem = new LanguageSystem
|
LanguageSystem = new LanguageSystem
|
||||||
{
|
{
|
||||||
DefaultLangCode = "en",
|
DefaultLangCode = "en",
|
||||||
|
|
@ -204,6 +245,13 @@ namespace src.utils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class WeaponPools
|
||||||
|
{
|
||||||
|
public required List<string> Rifle { get; set; }
|
||||||
|
public required List<string> Pistol { get; set; }
|
||||||
|
public required List<string> Grenade { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class ChatMessage
|
public class ChatMessage
|
||||||
{
|
{
|
||||||
public required float MaxWidth { get; set; }
|
public required float MaxWidth { get; set; }
|
||||||
|
|
|
||||||
204
jRandomSkills - SRC Files/src/utils/DecoyRing.cs
Normal file
204
jRandomSkills - SRC Files/src/utils/DecoyRing.cs
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
using CounterStrikeSharp.API;
|
||||||
|
using CounterStrikeSharp.API.Core;
|
||||||
|
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||||
|
using CounterStrikeSharp.API.Modules.Timers;
|
||||||
|
using CounterStrikeSharp.API.Modules.Utils;
|
||||||
|
using src.player;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace src.utils
|
||||||
|
{
|
||||||
|
public static class DecoyRing
|
||||||
|
{
|
||||||
|
private const string discModel = "models/dev/grenade_trajectory/grenade_target.vmdl";
|
||||||
|
|
||||||
|
private const float discBaseRadius = 13.462f;
|
||||||
|
private const int discAlpha = 178;
|
||||||
|
|
||||||
|
private const int outerSegments = 24;
|
||||||
|
private const int innerSegments = 18;
|
||||||
|
private const float ringHeight = 3f;
|
||||||
|
|
||||||
|
private const float maxLifetime = 25f;
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<string, Ring> rings = [];
|
||||||
|
|
||||||
|
private sealed class Ring
|
||||||
|
{
|
||||||
|
public uint? Disc { get; set; }
|
||||||
|
public List<uint> Beams { get; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PreloadAssets()
|
||||||
|
{
|
||||||
|
jRandomSkills.Instance.AddToManifest(discModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Show(Skills skill, uint id, Vector center, float radius)
|
||||||
|
{
|
||||||
|
if (radius <= 0) return;
|
||||||
|
|
||||||
|
string key = MakeKey(skill, id);
|
||||||
|
var ring = new Ring();
|
||||||
|
if (!rings.TryAdd(key, ring)) return;
|
||||||
|
|
||||||
|
SpawnDisc(center, radius, ring);
|
||||||
|
|
||||||
|
if (!EntityManager.OverBudget())
|
||||||
|
{
|
||||||
|
Color color = GetSkillColor(skill);
|
||||||
|
SpawnRing(center, radius, outerSegments, color, ring);
|
||||||
|
SpawnRing(center, radius * .5f, innerSegments, color, ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
jRandomSkills.Instance.AddTimer(maxLifetime, () => Hide(skill, id), TimerFlags.STOP_ON_MAPCHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Hide(Skills skill, uint id)
|
||||||
|
{
|
||||||
|
if (!rings.TryRemove(MakeKey(skill, id), out var ring)) return;
|
||||||
|
Destroy(ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ClearAll(Skills skill)
|
||||||
|
{
|
||||||
|
string prefix = skill + "|";
|
||||||
|
|
||||||
|
foreach (var key in rings.Keys)
|
||||||
|
{
|
||||||
|
if (!key.StartsWith(prefix, StringComparison.Ordinal)) continue;
|
||||||
|
if (!rings.TryRemove(key, out var ring)) continue;
|
||||||
|
|
||||||
|
Destroy(ring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Destroy(Ring ring)
|
||||||
|
{
|
||||||
|
foreach (uint beamIndex in ring.Beams)
|
||||||
|
EntityManager.DestroyBeam(beamIndex);
|
||||||
|
|
||||||
|
ring.Beams.Clear();
|
||||||
|
|
||||||
|
if (ring.Disc == null) return;
|
||||||
|
|
||||||
|
uint discIndex = ring.Disc.Value;
|
||||||
|
ring.Disc = null;
|
||||||
|
|
||||||
|
EntityManager.DestroyEntity(discIndex, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string MakeKey(Skills skill, uint id)
|
||||||
|
{
|
||||||
|
return string.Create(CultureInfo.InvariantCulture, $"{skill}|{id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color GetSkillColor(Skills skill)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string hex = SkillsInfo.GetValue<string>(skill, "color");
|
||||||
|
if (!string.IsNullOrEmpty(hex))
|
||||||
|
return ColorTranslator.FromHtml(hex);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
return Color.White;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SpawnDisc(Vector center, float radius, Ring ring)
|
||||||
|
{
|
||||||
|
var disc = EntityManager.CreateTrackedPropOverride(EntityManager.SystemOwnerIndex);
|
||||||
|
if (disc == null || !disc.IsValid) return;
|
||||||
|
|
||||||
|
uint discIndex = disc.Index;
|
||||||
|
ring.Disc = discIndex;
|
||||||
|
|
||||||
|
float scale = radius / discBaseRadius;
|
||||||
|
Vector pos = new(center.X, center.Y, center.Z + 1f);
|
||||||
|
|
||||||
|
Server.NextFrame(() =>
|
||||||
|
{
|
||||||
|
var prop = Utilities.GetEntityFromIndex<CDynamicProp>((int)discIndex);
|
||||||
|
if (prop == null || !prop.IsValid) return;
|
||||||
|
|
||||||
|
var node = prop.CBodyComponent?.SceneNode?.Owner?.Entity;
|
||||||
|
if (node != null)
|
||||||
|
node.Flags = (uint)(node.Flags & ~(1 << 2));
|
||||||
|
|
||||||
|
MakeNonSolid(prop);
|
||||||
|
|
||||||
|
prop.SetModel(discModel);
|
||||||
|
prop.Teleport(pos, new QAngle(0, 0, 0));
|
||||||
|
prop.DispatchSpawn();
|
||||||
|
|
||||||
|
prop.Render = Color.FromArgb(discAlpha, 255, 255, 255);
|
||||||
|
Utilities.SetStateChanged(prop, "CBaseModelEntity", "m_clrRender");
|
||||||
|
|
||||||
|
var skeleton = prop.CBodyComponent?.SceneNode?.GetSkeletonInstance();
|
||||||
|
if (skeleton != null)
|
||||||
|
{
|
||||||
|
skeleton.Scale = scale;
|
||||||
|
prop.AcceptInput("SetScale", null, null, scale.ToString(CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
Utilities.SetStateChanged(prop, "CBaseEntity", "m_CBodyComponent");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MakeNonSolid(CDynamicProp prop)
|
||||||
|
{
|
||||||
|
var collision = prop.Collision;
|
||||||
|
if (collision == null) return;
|
||||||
|
|
||||||
|
collision.SolidType = SolidType_t.SOLID_NONE;
|
||||||
|
collision.SolidFlags = 12;
|
||||||
|
|
||||||
|
var attribute = collision.CollisionAttribute;
|
||||||
|
if (attribute == null) return;
|
||||||
|
|
||||||
|
attribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_NEVER;
|
||||||
|
attribute.CollisionFunctionMask = 0;
|
||||||
|
attribute.InteractsAs = 0;
|
||||||
|
attribute.InteractsWith = 0;
|
||||||
|
attribute.InteractsExclude = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SpawnRing(Vector center, float radius, int segments, Color color, Ring ring)
|
||||||
|
{
|
||||||
|
if (segments < 3 || radius <= 0) return;
|
||||||
|
|
||||||
|
float step = MathF.Tau / segments;
|
||||||
|
Vector previous = PointOn(center, radius, 0);
|
||||||
|
|
||||||
|
for (int i = 1; i <= segments; i++)
|
||||||
|
{
|
||||||
|
Vector next = PointOn(center, radius, step * i);
|
||||||
|
|
||||||
|
var beam = EntityManager.CreateTrackedBeam(EntityManager.SystemOwnerIndex, previous, next, color);
|
||||||
|
if (beam != null && beam.IsValid)
|
||||||
|
{
|
||||||
|
beam.Width = 1.2f;
|
||||||
|
beam.EndWidth = 1.2f;
|
||||||
|
|
||||||
|
Utilities.SetStateChanged(beam, "CBeam", "m_fWidth");
|
||||||
|
Utilities.SetStateChanged(beam, "CBeam", "m_fEndWidth");
|
||||||
|
|
||||||
|
ring.Beams.Add(beam.Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector PointOn(Vector center, float radius, float angle)
|
||||||
|
{
|
||||||
|
return new Vector(
|
||||||
|
center.X + MathF.Cos(angle) * radius,
|
||||||
|
center.Y + MathF.Sin(angle) * radius,
|
||||||
|
center.Z + ringHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -273,6 +273,40 @@ namespace src.utils
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool DestroyBeam(uint entityIndex)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var beam = Utilities.GetEntityFromIndex<CBeam>((int)entityIndex);
|
||||||
|
if (beam != null && beam.IsValid)
|
||||||
|
{
|
||||||
|
beam.Width = 0;
|
||||||
|
beam.EndWidth = 0;
|
||||||
|
beam.Render = Color.FromArgb(0, 0, 0, 0);
|
||||||
|
|
||||||
|
Utilities.SetStateChanged(beam, "CBeam", "m_fWidth");
|
||||||
|
Utilities.SetStateChanged(beam, "CBeam", "m_fEndWidth");
|
||||||
|
Utilities.SetStateChanged(beam, "CBaseModelEntity", "m_clrRender");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Server.PrintToConsole($"[EntityManager] DestroyBeam {entityIndex}: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool killed = DestroyEntity(entityIndex);
|
||||||
|
|
||||||
|
if (!SuppressKills)
|
||||||
|
Server.NextFrame(() =>
|
||||||
|
{
|
||||||
|
var leftover = Utilities.GetEntityFromIndex<CBeam>((int)entityIndex);
|
||||||
|
if (leftover != null && leftover.IsValid)
|
||||||
|
leftover.Remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
return killed;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool DestroyEntity<T>(uint? entityIndex) where T : CBaseEntity
|
public static bool DestroyEntity<T>(uint? entityIndex) where T : CBaseEntity
|
||||||
{
|
{
|
||||||
if (entityIndex == null) return false;
|
if (entityIndex == null) return false;
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ namespace jRandomSkills.src.utils
|
||||||
"weapon_sg556" => KillfeedIcons.Sg556,
|
"weapon_sg556" => KillfeedIcons.Sg556,
|
||||||
"weapon_famas" => KillfeedIcons.Famas,
|
"weapon_famas" => KillfeedIcons.Famas,
|
||||||
"weapon_galilar" => KillfeedIcons.Galilar,
|
"weapon_galilar" => KillfeedIcons.Galilar,
|
||||||
"weapon_m4a4" => KillfeedIcons.M4A4,
|
"weapon_m4a1" => KillfeedIcons.M4A4,
|
||||||
"weapon_m4a1_silencer" => KillfeedIcons.M4A1,
|
"weapon_m4a1_silencer" => KillfeedIcons.M4A1,
|
||||||
"weapon_ak47" => KillfeedIcons.Ak47,
|
"weapon_ak47" => KillfeedIcons.Ak47,
|
||||||
"weapon_aug" => KillfeedIcons.Aug,
|
"weapon_aug" => KillfeedIcons.Aug,
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace src.utils
|
||||||
LazySig<MemoryFunctionVoid<CBasePlayerPawn, QAngle>>("SnapViewAngles", s => new(s));
|
LazySig<MemoryFunctionVoid<CBasePlayerPawn, QAngle>>("SnapViewAngles", s => new(s));
|
||||||
// private static readonly int collisionRulesChangedOffset = GameData.GetOffset("CBaseEntity_CollisionRulesChanged");
|
// private static readonly int collisionRulesChangedOffset = GameData.GetOffset("CBaseEntity_CollisionRulesChanged");
|
||||||
|
|
||||||
public static void PrintToChat(CCSPlayerController player, string? msg, string border = "tb", string? title = null)
|
public static void PrintToChat(CCSPlayerController player, string? msg, string border = "tb", string? title = null, bool ignoreIlliterate = false)
|
||||||
{
|
{
|
||||||
if (!player.IsValid) return;
|
if (!player.IsValid) return;
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ namespace src.utils
|
||||||
char symbol = config.LineSymbol;
|
char symbol = config.LineSymbol;
|
||||||
if (string.IsNullOrEmpty(title)) title = player.GetTranslation("jRandomSkills");
|
if (string.IsNullOrEmpty(title)) title = player.GetTranslation("jRandomSkills");
|
||||||
|
|
||||||
if (Illiterate.CheckIlliterateSkill(player))
|
if (!ignoreIlliterate && Illiterate.CheckIlliterateSkill(player))
|
||||||
msg = Illiterate.GetRandomText(msg);
|
msg = Illiterate.GetRandomText(msg);
|
||||||
|
|
||||||
if (border.Contains('t') && config.LineShow)
|
if (border.Contains('t') && config.LineShow)
|
||||||
|
|
@ -60,11 +60,39 @@ namespace src.utils
|
||||||
player.PrintToChat($" {MeansureString.GetTextDashed("", maxWidth, symbol, config.LineColor)}");
|
player.PrintToChat($" {MeansureString.GetTextDashed("", maxWidth, symbol, config.LineColor)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EmitSoundToPlayer(CCSPlayerController? listener, string soundEvent, float volume)
|
||||||
|
{
|
||||||
|
var target = PlayerManager.GetPlayerFromEvent(listener);
|
||||||
|
if (target == null || !target.IsValid) return;
|
||||||
|
|
||||||
|
target.EmitSound(soundEvent, new RecipientFilter(target), volume);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsFreezeTime()
|
public static bool IsFreezeTime()
|
||||||
{
|
{
|
||||||
return jRandomSkills.Instance?.GameRules?.FreezePeriod == true;
|
return jRandomSkills.Instance?.GameRules?.FreezePeriod == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsPistolRound()
|
||||||
|
{
|
||||||
|
var gameRules = jRandomSkills.Instance?.GameRules;
|
||||||
|
if (gameRules == null) return false;
|
||||||
|
|
||||||
|
if (gameRules.TotalRoundsPlayed == 0 || gameRules.GameRestart) return true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ConVar.Find("mp_halftime")?.GetPrimitiveValue<bool>() != true) return false;
|
||||||
|
|
||||||
|
int maxRounds = ConVar.Find("mp_maxrounds")?.GetPrimitiveValue<int>() ?? 0;
|
||||||
|
return maxRounds > 0 && maxRounds / 2 == gameRules.TotalRoundsPlayed;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsHudFrame() => Server.TickCount % 4 == 0;
|
public static bool IsHudFrame() => Server.TickCount % 4 == 0;
|
||||||
|
|
||||||
public static void RegisterSkill(Skills skill, string color, bool display = true)
|
public static void RegisterSkill(Skills skill, string color, bool display = true)
|
||||||
|
|
@ -396,7 +424,8 @@ namespace src.utils
|
||||||
Skills.Deaf, Skills.ExpensiveAmmo, Skills.Giant, Skills.Glitch,
|
Skills.Deaf, Skills.ExpensiveAmmo, Skills.Giant, Skills.Glitch,
|
||||||
Skills.Jammer, Skills.JumpBan, Skills.JumpCurse, Skills.LifeSwap,
|
Skills.Jammer, Skills.JumpBan, Skills.JumpCurse, Skills.LifeSwap,
|
||||||
Skills.Magnifier, Skills.MoneySwap, Skills.Nightmare, Skills.Poison,
|
Skills.Magnifier, Skills.MoneySwap, Skills.Nightmare, Skills.Poison,
|
||||||
Skills.JetKick, Skills.PrimaryBan, Skills.Thief, Skills.WildThrow
|
Skills.JetKick, Skills.PrimaryBan, Skills.Thief, Skills.WildThrow,
|
||||||
|
Skills.Voodoo, Skills.Nemesis, Skills.Bounty
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly HashSet<string> curseSkillNames = new(curseSkills.Select(s => s.ToString()), StringComparer.Ordinal);
|
private static readonly HashSet<string> curseSkillNames = new(curseSkills.Select(s => s.ToString()), StringComparer.Ordinal);
|
||||||
|
|
@ -490,6 +519,73 @@ namespace src.utils
|
||||||
else curseCounts[victimIndex] = used - 1;
|
else curseCounts[victimIndex] = used - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const uint crosshairBit = 1u << 8;
|
||||||
|
|
||||||
|
private static readonly object hudSuppressionLock = new();
|
||||||
|
private static readonly Dictionary<uint, HashSet<string>> crosshairOwners = [];
|
||||||
|
private static readonly Dictionary<uint, HashSet<string>> radarOwners = [];
|
||||||
|
|
||||||
|
public static void SetCrosshairHidden(CCSPlayerController? player, string owner, bool hide)
|
||||||
|
{
|
||||||
|
if (player == null || !player.IsValid) return;
|
||||||
|
|
||||||
|
var pawn = player.PlayerPawn?.Value;
|
||||||
|
if (pawn == null || !pawn.IsValid) return;
|
||||||
|
|
||||||
|
if (!TryUpdateOwners(crosshairOwners, player.Index, owner, hide, out bool suppressed)) return;
|
||||||
|
|
||||||
|
if (suppressed) pawn.HideHUD |= crosshairBit;
|
||||||
|
else pawn.HideHUD &= ~crosshairBit;
|
||||||
|
|
||||||
|
Utilities.SetStateChanged(pawn, "CBasePlayerPawn", "m_iHideHUD");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetRadarDisabled(CCSPlayerController? player, string owner, bool disable)
|
||||||
|
{
|
||||||
|
if (player == null || !player.IsValid) return;
|
||||||
|
if (!TryUpdateOwners(radarOwners, player.Index, owner, disable, out bool suppressed)) return;
|
||||||
|
|
||||||
|
player.ReplicateConVar("sv_disable_radar", suppressed ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ClearHudSuppression(uint playerIndex)
|
||||||
|
{
|
||||||
|
lock (hudSuppressionLock)
|
||||||
|
{
|
||||||
|
crosshairOwners.Remove(playerIndex);
|
||||||
|
radarOwners.Remove(playerIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ClearAllHudSuppression()
|
||||||
|
{
|
||||||
|
lock (hudSuppressionLock)
|
||||||
|
{
|
||||||
|
crosshairOwners.Clear();
|
||||||
|
radarOwners.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryUpdateOwners(Dictionary<uint, HashSet<string>> registry, uint playerIndex, string owner, bool claim, out bool suppressed)
|
||||||
|
{
|
||||||
|
lock (hudSuppressionLock)
|
||||||
|
{
|
||||||
|
if (!registry.TryGetValue(playerIndex, out var owners))
|
||||||
|
{
|
||||||
|
owners = [];
|
||||||
|
registry[playerIndex] = owners;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool before = owners.Count > 0;
|
||||||
|
bool changed = claim ? owners.Add(owner) : owners.Remove(owner);
|
||||||
|
|
||||||
|
suppressed = owners.Count > 0;
|
||||||
|
if (!suppressed) registry.Remove(playerIndex);
|
||||||
|
|
||||||
|
return changed && before != suppressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static CCSPlayerController[] GetSelectableEnemies(CCSPlayerController player, bool respectCurseLimit = false)
|
public static CCSPlayerController[] GetSelectableEnemies(CCSPlayerController player, bool respectCurseLimit = false)
|
||||||
{
|
{
|
||||||
if (player == null || !player.IsValid) return [];
|
if (player == null || !player.IsValid) return [];
|
||||||
|
|
@ -575,6 +671,26 @@ namespace src.utils
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly record struct HiddenPawn(uint Index, CsTeam Team, CCSPlayerPawn Pawn, bool HoldsBomb);
|
||||||
|
|
||||||
|
public static List<HiddenPawn> ResolveHiddenPawns(ICollection<uint> playerIndexes, uint? bombOwnerIndex)
|
||||||
|
{
|
||||||
|
List<HiddenPawn> hidden = new(playerIndexes.Count);
|
||||||
|
|
||||||
|
foreach (var playerIndex in playerIndexes)
|
||||||
|
{
|
||||||
|
var controller = PlayerManager.GetPlayerEvent(Utilities.GetPlayerFromIndex((int)playerIndex));
|
||||||
|
if (controller == null || !controller.IsValid) continue;
|
||||||
|
|
||||||
|
var pawn = controller.PlayerPawn.Value;
|
||||||
|
if (pawn == null || !pawn.IsValid) continue;
|
||||||
|
|
||||||
|
hidden.Add(new HiddenPawn(controller.Index, controller.Team, pawn, bombOwnerIndex == controller.Index));
|
||||||
|
}
|
||||||
|
|
||||||
|
return hidden;
|
||||||
|
}
|
||||||
|
|
||||||
public static void HideCarriedEntities(CCheckTransmitInfo info, CCSPlayerPawn? pawn)
|
public static void HideCarriedEntities(CCheckTransmitInfo info, CCSPlayerPawn? pawn)
|
||||||
{
|
{
|
||||||
if (pawn == null || !pawn.IsValid) return;
|
if (pawn == null || !pawn.IsValid) return;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ namespace src.utils
|
||||||
private static SkillsInfoModel? _indexedConfig;
|
private static SkillsInfoModel? _indexedConfig;
|
||||||
private static ConcurrentDictionary<string, DefaultSkillInfo> _byName = new();
|
private static ConcurrentDictionary<string, DefaultSkillInfo> _byName = new();
|
||||||
private static readonly ConcurrentDictionary<(Type Type, string Key), MemberInfo?> _memberCache = new();
|
private static readonly ConcurrentDictionary<(Type Type, string Key), MemberInfo?> _memberCache = new();
|
||||||
|
private static readonly ConcurrentDictionary<(DefaultSkillInfo Config, string Key, Type Target), object?> _valueCache = new();
|
||||||
|
|
||||||
public static SkillsInfoModel LoadSkillsInfo()
|
public static SkillsInfoModel LoadSkillsInfo()
|
||||||
{
|
{
|
||||||
|
|
@ -92,6 +93,12 @@ namespace src.utils
|
||||||
if (!_byName.TryGetValue(skill.ToString()!, out var skillConfig) || skillConfig == null)
|
if (!_byName.TryGetValue(skill.ToString()!, out var skillConfig) || skillConfig == null)
|
||||||
return default!;
|
return default!;
|
||||||
|
|
||||||
|
object? cached = _valueCache.GetOrAdd((skillConfig, key, typeof(T)), k => Resolve(k.Config, k.Key, k.Target));
|
||||||
|
return cached == null ? default! : (T)cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? Resolve(DefaultSkillInfo skillConfig, string key, Type targetType)
|
||||||
|
{
|
||||||
var member = _memberCache.GetOrAdd((skillConfig.GetType(), key), k =>
|
var member = _memberCache.GetOrAdd((skillConfig.GetType(), key), k =>
|
||||||
{
|
{
|
||||||
MemberInfo? m = k.Type.GetProperty(k.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
MemberInfo? m = k.Type.GetProperty(k.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
||||||
|
|
@ -106,11 +113,10 @@ namespace src.utils
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
|
|
||||||
if (value == null) return default!;
|
if (value == null) return null;
|
||||||
|
|
||||||
Type targetType = typeof(T);
|
|
||||||
Type? underlyingType = Nullable.GetUnderlyingType(targetType);
|
Type? underlyingType = Nullable.GetUnderlyingType(targetType);
|
||||||
return (T)Convert.ChangeType(value, underlyingType ?? targetType);
|
return Convert.ChangeType(value, underlyingType ?? targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EnsureIndex()
|
private static void EnsureIndex()
|
||||||
|
|
@ -124,6 +130,7 @@ namespace src.utils
|
||||||
_byName = dict;
|
_byName = dict;
|
||||||
_indexedConfig = config;
|
_indexedConfig = config;
|
||||||
_memberCache.Clear();
|
_memberCache.Clear();
|
||||||
|
_valueCache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SkillsInfoModel : ConcurrentBag<DefaultSkillInfo>
|
public class SkillsInfoModel : ConcurrentBag<DefaultSkillInfo>
|
||||||
|
|
@ -147,10 +154,11 @@ namespace src.utils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DefaultSkillInfo(Skills skill, bool active = true, string color = "#ffffff", 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)
|
public class DefaultSkillInfo(Skills skill, bool active = true, string color = "#ffffff", 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, bool disableOnPistolRound = false)
|
||||||
{
|
{
|
||||||
public bool NeedsTeammates { get; set; } = needsTeammates;
|
public bool NeedsTeammates { get; set; } = needsTeammates;
|
||||||
public bool DisableOnFreezeTime { get; set; } = disableOnFreezeTime;
|
public bool DisableOnFreezeTime { get; set; } = disableOnFreezeTime;
|
||||||
|
public bool DisableOnPistolRound { get; set; } = disableOnPistolRound;
|
||||||
public int OnlyTeam { get; set; } = (int)onlyTeam;
|
public int OnlyTeam { get; set; } = (int)onlyTeam;
|
||||||
public string Color { get; set; } = color;
|
public string Color { get; set; } = color;
|
||||||
public bool Active { get; set; } = active;
|
public bool Active { get; set; } = active;
|
||||||
|
|
|
||||||
84
jRandomSkills - SRC Files/src/utils/WeaponPool.cs
Normal file
84
jRandomSkills - SRC Files/src/utils/WeaponPool.cs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
namespace src.utils
|
||||||
|
{
|
||||||
|
public static class WeaponPool
|
||||||
|
{
|
||||||
|
private static readonly object buildLock = new();
|
||||||
|
private static bool built;
|
||||||
|
|
||||||
|
private static HashSet<string> rifles = new(StringComparer.Ordinal);
|
||||||
|
private static HashSet<string> pistols = new(StringComparer.Ordinal);
|
||||||
|
private static HashSet<string> grenades = new(StringComparer.Ordinal);
|
||||||
|
private static HashSet<string> all = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
|
private static string[] rifleArray = [];
|
||||||
|
private static string[] pistolArray = [];
|
||||||
|
private static string[] grenadeArray = [];
|
||||||
|
private static string[] allArray = [];
|
||||||
|
|
||||||
|
public static HashSet<string> Rifles { get { Build(); return rifles; } }
|
||||||
|
public static HashSet<string> Pistols { get { Build(); return pistols; } }
|
||||||
|
public static HashSet<string> Grenades { get { Build(); return grenades; } }
|
||||||
|
public static HashSet<string> All { get { Build(); return all; } }
|
||||||
|
|
||||||
|
public static string[] RifleList { get { Build(); return rifleArray; } }
|
||||||
|
public static string[] PistolList { get { Build(); return pistolArray; } }
|
||||||
|
public static string[] GrenadeList { get { Build(); return grenadeArray; } }
|
||||||
|
public static string[] AllList { get { Build(); return allArray; } }
|
||||||
|
|
||||||
|
public static bool IsRifle(string? weapon) => weapon != null && Rifles.Contains(Normalize(weapon));
|
||||||
|
public static bool IsPistol(string? weapon) => weapon != null && Pistols.Contains(Normalize(weapon));
|
||||||
|
public static bool IsGrenade(string? weapon) => weapon != null && Grenades.Contains(Normalize(weapon));
|
||||||
|
public static bool IsWeapon(string? weapon) => weapon != null && All.Contains(Normalize(weapon));
|
||||||
|
|
||||||
|
public static string Normalize(string weapon)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(weapon)) return string.Empty;
|
||||||
|
return weapon.StartsWith("weapon_", StringComparison.Ordinal) ? weapon : "weapon_" + weapon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Invalidate()
|
||||||
|
{
|
||||||
|
lock (buildLock) built = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Build()
|
||||||
|
{
|
||||||
|
if (built) return;
|
||||||
|
|
||||||
|
lock (buildLock)
|
||||||
|
{
|
||||||
|
if (built) return;
|
||||||
|
|
||||||
|
var pools = Config.LoadedConfig?.Weapons;
|
||||||
|
|
||||||
|
rifles = Collect(pools?.Rifle);
|
||||||
|
pistols = Collect(pools?.Pistol);
|
||||||
|
grenades = Collect(pools?.Grenade);
|
||||||
|
|
||||||
|
all = new HashSet<string>(rifles, StringComparer.Ordinal);
|
||||||
|
all.UnionWith(pistols);
|
||||||
|
|
||||||
|
rifleArray = [.. rifles];
|
||||||
|
pistolArray = [.. pistols];
|
||||||
|
grenadeArray = [.. grenades];
|
||||||
|
allArray = [.. all];
|
||||||
|
|
||||||
|
built = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HashSet<string> Collect(List<string>? source)
|
||||||
|
{
|
||||||
|
var set = new HashSet<string>(StringComparer.Ordinal);
|
||||||
|
if (source == null) return set;
|
||||||
|
|
||||||
|
foreach (var entry in source)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(entry)) continue;
|
||||||
|
set.Add(Normalize(entry.Trim()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
|
@ -22,6 +22,54 @@
|
||||||
"DisableHUDOnDeathPermission": "@jRandomSkills/death",
|
"DisableHUDOnDeathPermission": "@jRandomSkills/death",
|
||||||
"DisableSkillsOnRoundEnd": false,
|
"DisableSkillsOnRoundEnd": false,
|
||||||
"CurseSkillPerPlayer": null,
|
"CurseSkillPerPlayer": null,
|
||||||
|
"Weapons": {
|
||||||
|
"Rifle": [
|
||||||
|
"weapon_ak47",
|
||||||
|
"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"
|
||||||
|
],
|
||||||
|
"Pistol": [
|
||||||
|
"weapon_deagle",
|
||||||
|
"weapon_revolver",
|
||||||
|
"weapon_glock",
|
||||||
|
"weapon_usp_silencer",
|
||||||
|
"weapon_cz75a",
|
||||||
|
"weapon_fiveseven",
|
||||||
|
"weapon_p250",
|
||||||
|
"weapon_tec9",
|
||||||
|
"weapon_elite",
|
||||||
|
"weapon_hkp2000"
|
||||||
|
],
|
||||||
|
"Grenade": [
|
||||||
|
"weapon_hegrenade",
|
||||||
|
"weapon_flashbang",
|
||||||
|
"weapon_smokegrenade",
|
||||||
|
"weapon_molotov",
|
||||||
|
"weapon_incgrenade",
|
||||||
|
"weapon_decoy"
|
||||||
|
]
|
||||||
|
},
|
||||||
"LanguageSystem": {
|
"LanguageSystem": {
|
||||||
"DefaultLangCode": "en",
|
"DefaultLangCode": "en",
|
||||||
"DisableGeoLite": false,
|
"DisableGeoLite": false,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Explosivschuss",
|
"blastshot": "Explosivschuss",
|
||||||
"blastshot_desc": "Drücke Attack2 mit der MP5, um eine HE-Granate abzufeuern",
|
"blastshot_desc": "Drücke Attack2 mit der MP5, um eine HE-Granate abzufeuern",
|
||||||
|
|
||||||
|
"bounty": "Kopfgeld",
|
||||||
|
"bounty_desc": "Setze ein Kopfgeld auf einen Gegner aus; wer ihn tötet, bekommt das Geld",
|
||||||
|
"bounty_select_info": "Wähle einen Spieler:",
|
||||||
|
"bounty_player_info": "Du hast {1}$ Kopfgeld auf '{0}' ausgesetzt.",
|
||||||
|
"bounty_enemy_info": "Auf deinen Kopf wurden {0}$ ausgesetzt.",
|
||||||
|
"bounty_claimed_info": "Du hast '{0}' getötet und {1}$ kassiert.",
|
||||||
|
|
||||||
"bunnyhop": "Hase",
|
"bunnyhop": "Hase",
|
||||||
"bunnyhop_desc": "Du erhältst automatisch bunnyhop",
|
"bunnyhop_desc": "Du erhältst automatisch bunnyhop",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Zufällige Charaktergröße zu Beginn der Runde",
|
"dwarf_desc": "Zufällige Charaktergröße zu Beginn der Runde",
|
||||||
"dwarf_desc2": "Dein Größenmultiplikator beträgt: {0}x",
|
"dwarf_desc2": "Dein Größenmultiplikator beträgt: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "EMP-Granate",
|
||||||
|
"empgrenade_desc": "Wer von deiner Granate getroffen wird, verliert kurzzeitig Radar und Fadenkreuz",
|
||||||
|
"empgrenade_enemy_info": "Eine EMP-Granate hat dein Radar und Fadenkreuz lahmgelegt.",
|
||||||
|
|
||||||
"enemyspawn": "Feindes-Spawn",
|
"enemyspawn": "Feindes-Spawn",
|
||||||
"enemyspawn_desc": "Klicke auf [css_useSkill], um zum Feindes-Spawn zu teleportieren",
|
"enemyspawn_desc": "Klicke auf [css_useSkill], um zum Feindes-Spawn zu teleportieren",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Keine Oberfläche zum Einhaken.",
|
"grapple_no_anchor_info": "Keine Oberfläche zum Einhaken.",
|
||||||
"grapple_pulling_info": "ZUG",
|
"grapple_pulling_info": "ZUG",
|
||||||
|
|
||||||
|
"gravitydecoy": "Schwerkraft-Ablenker",
|
||||||
|
"gravitydecoy_desc": "Dein Ablenkungsköder verändert die Schwerkraft aller in der Nähe",
|
||||||
|
|
||||||
"grenadier": "Grenadier",
|
"grenadier": "Grenadier",
|
||||||
"grenadier_desc": "Du hast unendlich viele Granaten",
|
"grenadier_desc": "Du hast unendlich viele Granaten",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingchicken": "Heilendes Huhn",
|
"healingchicken": "Heilendes Huhn",
|
||||||
"healingchicken_desc": "Deine Hühner heilen dich, solange du in ihrer Nähe bist",
|
"healingchicken_desc": "Deine Hühner heilen dich, solange du in ihrer Nähe bist",
|
||||||
|
|
||||||
|
"heavyweight": "Schwergewicht",
|
||||||
|
"heavyweight_desc": "Fähigkeiten, die dich stoßen oder verlangsamen, wirken nicht auf dich",
|
||||||
|
|
||||||
"hermit": "Einsiedler",
|
"hermit": "Einsiedler",
|
||||||
"hermit_desc": "Durch das Töten von Gegnern werden Munition und ein Teil der Gesundheit wiederhergestellt",
|
"hermit_desc": "Durch das Töten von Gegnern werden Munition und ein Teil der Gesundheit wiederhergestellt",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"bankrupt_player_info": "Der Spieler ‚{0}‘ ist bankrott.",
|
"bankrupt_player_info": "Der Spieler ‚{0}‘ ist bankrott.",
|
||||||
"bankrupt_select_info": "Wähle einen Spieler aus, der bankrott gehen soll:",
|
"bankrupt_select_info": "Wähle einen Spieler aus, der bankrott gehen soll:",
|
||||||
|
|
||||||
|
"nemesis": "Nemesis",
|
||||||
|
"nemesis_desc": "Der von dir markierte Spieler erleidet zusätzlichen Schaden",
|
||||||
|
"nemesis_select_info": "Wähle einen Spieler:",
|
||||||
|
"nemesis_player_info": "Du hast '{0}' markiert.",
|
||||||
|
"nemesis_enemy_info": "Du wurdest als Nemesis markiert und erleidest jetzt von allen zusätzlichen Schaden.",
|
||||||
|
|
||||||
"nightmare": "Albtraum",
|
"nightmare": "Albtraum",
|
||||||
"nightmare_desc": "Lass einen ausgewählten Gegner eine schreckliche Vision erleben",
|
"nightmare_desc": "Lass einen ausgewählten Gegner eine schreckliche Vision erleben",
|
||||||
"nightmare_disable_info": "Der Albtraum ist vorbei.",
|
"nightmare_disable_info": "Der Albtraum ist vorbei.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Prothese",
|
"prosthesis": "Prothese",
|
||||||
"prosthesis_desc": "Arme und Beine sind kugelsicher",
|
"prosthesis_desc": "Arme und Beine sind kugelsicher",
|
||||||
|
|
||||||
|
"punisher": "Bestrafer",
|
||||||
|
"punisher_desc": "Du sammelst einen Teil des erlittenen Schadens und legst ihn auf deinen nächsten Treffer",
|
||||||
|
"punisher_released_info": "Du hast {0} zusätzlichen Schaden verursacht und ebenso viel Leben erhalten.",
|
||||||
|
|
||||||
"push": "Pusher",
|
"push": "Pusher",
|
||||||
"push_desc": "Du hast eine zufällige Chance, einen Gegner zurückzustoßen, wenn du ihn triffst",
|
"push_desc": "Du hast eine zufällige Chance, einen Gegner zurückzustoßen, wenn du ihn triffst",
|
||||||
"push_desc2": "Deine Chancen, den Gegner zurückzustoßen, betragen: {0} %",
|
"push_desc2": "Deine Chancen, den Gegner zurückzustoßen, betragen: {0} %",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Zurück zum Absender",
|
"returntosender": "Zurück zum Absender",
|
||||||
"returntosender_desc": "Der erste Treffer eines Gegners schickt ihn zurück zu seinem Spawn",
|
"returntosender_desc": "Der erste Treffer eines Gegners schickt ihn zurück zu seinem Spawn",
|
||||||
|
|
||||||
|
"rewind": "Rückspulen",
|
||||||
|
"rewind_desc": "Drücke [css_useSkill], um hier eine Marke zu setzen und kurz darauf dorthin zurückzukehren",
|
||||||
|
"rewind_pending_info": "RÜCKKEHR: {0}",
|
||||||
|
|
||||||
"richboy": "Rich Boy",
|
"richboy": "Rich Boy",
|
||||||
"richboy_desc": "Du erhältst zu Beginn der Runde einen zufälligen Geldbetrag",
|
"richboy_desc": "Du erhältst zu Beginn der Runde einen zufälligen Geldbetrag",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Stolperdraht platziert.",
|
"tripwire_placed_info": "Stolperdraht platziert.",
|
||||||
"tripwire_triggered_info": "'{0}' hat deinen Stolperdraht ausgelöst.",
|
"tripwire_triggered_info": "'{0}' hat deinen Stolperdraht ausgelöst.",
|
||||||
|
|
||||||
|
"truearmor": "Echte Rüstung",
|
||||||
|
"truearmor_desc": "Ein Teil des Schadens geht auf deine Rüstung statt auf dein Leben",
|
||||||
|
|
||||||
|
"voodoo": "Voodoo",
|
||||||
|
"voodoo_desc": "Der markierte Gegner erleidet einen Teil des Schadens, den du erleidest",
|
||||||
|
"voodoo_select_info": "Wähle einen Spieler:",
|
||||||
|
"voodoo_player_info": "Du hast '{0}' an deinen Voodoo gebunden.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Du kannst Feinde durch Wände hindurch sehen",
|
"wallhack_desc": "Du kannst Feinde durch Wände hindurch sehen",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Blast Shot",
|
"blastshot": "Blast Shot",
|
||||||
"blastshot_desc": "Press Attack2 with the MP5 to fire an HE grenade",
|
"blastshot_desc": "Press Attack2 with the MP5 to fire an HE grenade",
|
||||||
|
|
||||||
|
"bounty": "Bounty",
|
||||||
|
"bounty_desc": "Put a price on an enemy's head; whoever kills them takes the money",
|
||||||
|
"bounty_select_info": "Choose a player:",
|
||||||
|
"bounty_player_info": "You put a {1}$ bounty on '{0}'.",
|
||||||
|
"bounty_enemy_info": "A {0}$ bounty was placed on your head.",
|
||||||
|
"bounty_claimed_info": "You killed '{0}' and claimed {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Bunny",
|
"bunnyhop": "Bunny",
|
||||||
"bunnyhop_desc": "You get auto \"BunnyHop\"",
|
"bunnyhop_desc": "You get auto \"BunnyHop\"",
|
||||||
|
|
||||||
|
|
@ -137,6 +144,10 @@
|
||||||
"dwarf_desc": "Random character size at the start of the round",
|
"dwarf_desc": "Random character size at the start of the round",
|
||||||
"dwarf_desc2": "Your size multiplier is: {0}x",
|
"dwarf_desc2": "Your size multiplier is: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "EMP Grenade",
|
||||||
|
"empgrenade_desc": "Anyone hurt by your grenade loses their radar and crosshair for a while",
|
||||||
|
"empgrenade_enemy_info": "An EMP grenade knocked out your radar and crosshair.",
|
||||||
|
|
||||||
"enemyspawn": "Enemy Spawn",
|
"enemyspawn": "Enemy Spawn",
|
||||||
"enemyspawn_desc": "Click [css_useSkill] to teleport to the enemy spawn",
|
"enemyspawn_desc": "Click [css_useSkill] to teleport to the enemy spawn",
|
||||||
|
|
||||||
|
|
@ -223,6 +234,9 @@
|
||||||
"grapple_no_anchor_info": "No surface to hook onto.",
|
"grapple_no_anchor_info": "No surface to hook onto.",
|
||||||
"grapple_pulling_info": "PULLING",
|
"grapple_pulling_info": "PULLING",
|
||||||
|
|
||||||
|
"gravitydecoy": "Gravity Decoy",
|
||||||
|
"gravitydecoy_desc": "Your decoy changes the gravity of everyone nearby",
|
||||||
|
|
||||||
"grenadier": "Grenadier",
|
"grenadier": "Grenadier",
|
||||||
"grenadier_desc": "You have infinite hegrenade",
|
"grenadier_desc": "You have infinite hegrenade",
|
||||||
|
|
||||||
|
|
@ -232,6 +246,9 @@
|
||||||
"healingsmoke": "Healing Smoke",
|
"healingsmoke": "Healing Smoke",
|
||||||
"healingsmoke_desc": "Your smoke grenades heal",
|
"healingsmoke_desc": "Your smoke grenades heal",
|
||||||
|
|
||||||
|
"heavyweight": "Heavyweight",
|
||||||
|
"heavyweight_desc": "Skills that push or slow you down have no effect on you",
|
||||||
|
|
||||||
"hermit": "Hermit",
|
"hermit": "Hermit",
|
||||||
"hermit_desc": "Killing restores ammo and a portion of health",
|
"hermit_desc": "Killing restores ammo and a portion of health",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"demoneye": "Demon Eye",
|
"demoneye": "Demon Eye",
|
||||||
"demoneye_desc": "You deal damage to every enemy you are looking at",
|
"demoneye_desc": "You deal damage to every enemy you are looking at",
|
||||||
|
|
||||||
|
"nemesis": "Nemesis",
|
||||||
|
"nemesis_desc": "The player you mark takes extra damage",
|
||||||
|
"nemesis_select_info": "Choose a player:",
|
||||||
|
"nemesis_player_info": "You marked '{0}'.",
|
||||||
|
"nemesis_enemy_info": "You have been marked as a nemesis, you now take extra damage from everyone.",
|
||||||
|
|
||||||
"nightmare": "Nightmare",
|
"nightmare": "Nightmare",
|
||||||
"nightmare_desc": "Force a chosen enemy to experience a terrifying vision",
|
"nightmare_desc": "Force a chosen enemy to experience a terrifying vision",
|
||||||
"nightmare_disable_info": "The nightmare has faded.",
|
"nightmare_disable_info": "The nightmare has faded.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Prosthesis",
|
"prosthesis": "Prosthesis",
|
||||||
"prosthesis_desc": "Arms and legs are bulletproof",
|
"prosthesis_desc": "Arms and legs are bulletproof",
|
||||||
|
|
||||||
|
"punisher": "Punisher",
|
||||||
|
"punisher_desc": "You bank part of the damage you take and add it to your next hit",
|
||||||
|
"punisher_released_info": "You dealt {0} extra damage and healed for the same amount.",
|
||||||
|
|
||||||
"push": "Pusher",
|
"push": "Pusher",
|
||||||
"push_desc": "You have a random chance to push an enemy back when hitting them",
|
"push_desc": "You have a random chance to push an enemy back when hitting them",
|
||||||
"push_desc2": "Your chances of pushing back the enemy are: {0}%",
|
"push_desc2": "Your chances of pushing back the enemy are: {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Return to Sender",
|
"returntosender": "Return to Sender",
|
||||||
"returntosender_desc": "The first hit on an enemy sends them back to their spawn",
|
"returntosender_desc": "The first hit on an enemy sends them back to their spawn",
|
||||||
|
|
||||||
|
"rewind": "Rewind",
|
||||||
|
"rewind_desc": "Click [css_useSkill] to drop a marker where you stand and return to it shortly after",
|
||||||
|
"rewind_pending_info": "RETURN: {0}",
|
||||||
|
|
||||||
"richboy": "Rich Boy",
|
"richboy": "Rich Boy",
|
||||||
"richboy_desc": "You receive a random amount of money at the start of the round",
|
"richboy_desc": "You receive a random amount of money at the start of the round",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Tripwire placed.",
|
"tripwire_placed_info": "Tripwire placed.",
|
||||||
"tripwire_triggered_info": "'{0}' triggered your tripwire.",
|
"tripwire_triggered_info": "'{0}' triggered your tripwire.",
|
||||||
|
|
||||||
|
"truearmor": "True Armor",
|
||||||
|
"truearmor_desc": "Part of the damage you take is paid by your armor instead of your health",
|
||||||
|
|
||||||
|
"voodoo": "Voodoo",
|
||||||
|
"voodoo_desc": "The enemy you mark also takes part of the damage you take",
|
||||||
|
"voodoo_select_info": "Choose a player:",
|
||||||
|
"voodoo_player_info": "You bound '{0}' to your voodoo.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "You can see enemies through walls",
|
"wallhack_desc": "You can see enemies through walls",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Tir explosif",
|
"blastshot": "Tir explosif",
|
||||||
"blastshot_desc": "Appuyez sur Attack2 avec le MP5 pour tirer une grenade HE",
|
"blastshot_desc": "Appuyez sur Attack2 avec le MP5 pour tirer une grenade HE",
|
||||||
|
|
||||||
|
"bounty": "Prime",
|
||||||
|
"bounty_desc": "Mets une prime sur la tête d'un ennemi ; celui qui le tue empoche l'argent",
|
||||||
|
"bounty_select_info": "Choisis un joueur :",
|
||||||
|
"bounty_player_info": "Tu as mis une prime de {1}$ sur '{0}'.",
|
||||||
|
"bounty_enemy_info": "Une prime de {0}$ a été mise sur ta tête.",
|
||||||
|
"bounty_claimed_info": "Tu as tué '{0}' et empoché {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Lapin",
|
"bunnyhop": "Lapin",
|
||||||
"bunnyhop_desc": "Vous obtenez l’auto « BunnyHop »",
|
"bunnyhop_desc": "Vous obtenez l’auto « BunnyHop »",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Taille du personnage aléatoire au début du round",
|
"dwarf_desc": "Taille du personnage aléatoire au début du round",
|
||||||
"dwarf_desc2": "Votre multiplicateur de taille est : {0}x",
|
"dwarf_desc2": "Votre multiplicateur de taille est : {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "Grenade EMP",
|
||||||
|
"empgrenade_desc": "Ceux que ta grenade blesse perdent leur radar et leur viseur un moment",
|
||||||
|
"empgrenade_enemy_info": "Une grenade EMP a coupé ton radar et ton viseur.",
|
||||||
|
|
||||||
"enemyspawn": "Spawn Ennemi",
|
"enemyspawn": "Spawn Ennemi",
|
||||||
"enemyspawn_desc": "Appuyez sur [css_useSkill] pour vous téléporter au spawn ennemi",
|
"enemyspawn_desc": "Appuyez sur [css_useSkill] pour vous téléporter au spawn ennemi",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Aucune surface pour accrocher le grappin.",
|
"grapple_no_anchor_info": "Aucune surface pour accrocher le grappin.",
|
||||||
"grapple_pulling_info": "TRACTION",
|
"grapple_pulling_info": "TRACTION",
|
||||||
|
|
||||||
|
"gravitydecoy": "Leurre gravitationnel",
|
||||||
|
"gravitydecoy_desc": "Ton leurre modifie la gravité de tous ceux qui sont à proximité",
|
||||||
|
|
||||||
"grenadier": "Grenadier",
|
"grenadier": "Grenadier",
|
||||||
"grenadier_desc": "Tu as des grenades HE infinies",
|
"grenadier_desc": "Tu as des grenades HE infinies",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingchicken": "Poulet guérisseur",
|
"healingchicken": "Poulet guérisseur",
|
||||||
"healingchicken_desc": "Vos poulets vous soignent lorsque vous êtes à proximité",
|
"healingchicken_desc": "Vos poulets vous soignent lorsque vous êtes à proximité",
|
||||||
|
|
||||||
|
"heavyweight": "Poids lourd",
|
||||||
|
"heavyweight_desc": "Les compétences qui te poussent ou te ralentissent n'ont aucun effet sur toi",
|
||||||
|
|
||||||
"hermit": "Ermite",
|
"hermit": "Ermite",
|
||||||
"hermit_desc": "Tuer restaure des munitions et une partie de vos PV",
|
"hermit_desc": "Tuer restaure des munitions et une partie de vos PV",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"bankrupt_player_info": "Le joueur « {0} » est en faillite.",
|
"bankrupt_player_info": "Le joueur « {0} » est en faillite.",
|
||||||
"bankrupt_select_info": "Mettre un joueur en faillite :",
|
"bankrupt_select_info": "Mettre un joueur en faillite :",
|
||||||
|
|
||||||
|
"nemesis": "Némésis",
|
||||||
|
"nemesis_desc": "Le joueur que tu marques subit des dégâts supplémentaires",
|
||||||
|
"nemesis_select_info": "Choisis un joueur :",
|
||||||
|
"nemesis_player_info": "Tu as marqué '{0}'.",
|
||||||
|
"nemesis_enemy_info": "Vous avez été marqué comme némésis, vous subissez désormais des dégâts supplémentaires de la part de tous.",
|
||||||
|
|
||||||
"nightmare": "Cauchemar",
|
"nightmare": "Cauchemar",
|
||||||
"nightmare_desc": "Faites subir une vision terrifiante à un ennemi choisi",
|
"nightmare_desc": "Faites subir une vision terrifiante à un ennemi choisi",
|
||||||
"nightmare_disable_info": "Le cauchemar s'est dissipé.",
|
"nightmare_disable_info": "Le cauchemar s'est dissipé.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Prothèses",
|
"prosthesis": "Prothèses",
|
||||||
"prosthesis_desc": "Les bras et les jambes sont pare-balles",
|
"prosthesis_desc": "Les bras et les jambes sont pare-balles",
|
||||||
|
|
||||||
|
"punisher": "Punisseur",
|
||||||
|
"punisher_desc": "Tu accumules une partie des dégâts subis et l'ajoutes à ton prochain tir",
|
||||||
|
"punisher_released_info": "Tu as infligé {0} dégâts en plus et récupéré autant de vie.",
|
||||||
|
|
||||||
"push": "Pousseur",
|
"push": "Pousseur",
|
||||||
"push_desc": "Vous avez une chance aléatoire de repousser un ennemi en le touchant",
|
"push_desc": "Vous avez une chance aléatoire de repousser un ennemi en le touchant",
|
||||||
"push_desc2": "Votre chance de repousser l’ennemi est : {0}%",
|
"push_desc2": "Votre chance de repousser l’ennemi est : {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Retour à l’Expéditeur",
|
"returntosender": "Retour à l’Expéditeur",
|
||||||
"returntosender_desc": "Le premier coup porté à un ennemi le renvoie à son spawn",
|
"returntosender_desc": "Le premier coup porté à un ennemi le renvoie à son spawn",
|
||||||
|
|
||||||
|
"rewind": "Rembobinage",
|
||||||
|
"rewind_desc": "Appuie sur [css_useSkill] pour poser un repère ici et y revenir peu après",
|
||||||
|
"rewind_pending_info": "RETOUR : {0}",
|
||||||
|
|
||||||
"richboy": "Gosse de Riche",
|
"richboy": "Gosse de Riche",
|
||||||
"richboy_desc": "Vous recevez une somme d’argent aléatoire au début du round",
|
"richboy_desc": "Vous recevez une somme d’argent aléatoire au début du round",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Fil-piège placé.",
|
"tripwire_placed_info": "Fil-piège placé.",
|
||||||
"tripwire_triggered_info": "'{0}' a déclenché votre fil-piège.",
|
"tripwire_triggered_info": "'{0}' a déclenché votre fil-piège.",
|
||||||
|
|
||||||
|
"truearmor": "Vraie armure",
|
||||||
|
"truearmor_desc": "Une partie des dégâts est absorbée par ton armure au lieu de ta vie",
|
||||||
|
|
||||||
|
"voodoo": "Vaudou",
|
||||||
|
"voodoo_desc": "L'ennemi que tu marques subit aussi une partie des dégâts que tu reçois",
|
||||||
|
"voodoo_select_info": "Choisis un joueur :",
|
||||||
|
"voodoo_player_info": "Tu as lié '{0}' à ton vaudou.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Vous pouvez voir les ennemis à travers les murs",
|
"wallhack_desc": "Vous pouvez voir les ennemis à travers les murs",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Mocne Uderzenie",
|
"blastshot": "Mocne Uderzenie",
|
||||||
"blastshot_desc": "Naciśnij Attack2 na MP5, aby wystrzelić granat HE",
|
"blastshot_desc": "Naciśnij Attack2 na MP5, aby wystrzelić granat HE",
|
||||||
|
|
||||||
|
"bounty": "Nagroda",
|
||||||
|
"bounty_desc": "Wyznacz nagrodę za głowę wroga; kto go zabije, dostaje pieniądze",
|
||||||
|
"bounty_select_info": "Wybierz gracza:",
|
||||||
|
"bounty_player_info": "Wyznaczyłeś nagrodę {1}$ za '{0}'.",
|
||||||
|
"bounty_enemy_info": "Za twoją głowę wyznaczono {0}$.",
|
||||||
|
"bounty_claimed_info": "Zabiłeś '{0}' i zgarnąłeś {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Królik",
|
"bunnyhop": "Królik",
|
||||||
"bunnyhop_desc": "Otrzymujesz auto \"BunnyHopa\"",
|
"bunnyhop_desc": "Otrzymujesz auto \"BunnyHopa\"",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Losowa wielkość postaci na początku rundy",
|
"dwarf_desc": "Losowa wielkość postaci na początku rundy",
|
||||||
"dwarf_desc2": "Twój mnożnik wielkości to {0}x",
|
"dwarf_desc2": "Twój mnożnik wielkości to {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "Granat EMP",
|
||||||
|
"empgrenade_desc": "Kto oberwie twoim granatem, na chwilę traci radar i celownik",
|
||||||
|
"empgrenade_enemy_info": "Granat EMP wyłączył twój radar i celownik.",
|
||||||
|
|
||||||
"enemyspawn": "Resp Wroga",
|
"enemyspawn": "Resp Wroga",
|
||||||
"enemyspawn_desc": "Kliknij [css_useSkill], aby teleportować się na resp wroga",
|
"enemyspawn_desc": "Kliknij [css_useSkill], aby teleportować się na resp wroga",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Brak powierzchni do zaczepienia haka.",
|
"grapple_no_anchor_info": "Brak powierzchni do zaczepienia haka.",
|
||||||
"grapple_pulling_info": "PRZYCIĄGANIE",
|
"grapple_pulling_info": "PRZYCIĄGANIE",
|
||||||
|
|
||||||
|
"gravitydecoy": "Grawitacyjna wabik",
|
||||||
|
"gravitydecoy_desc": "Twój wabik zmienia grawitację wszystkich w pobliżu",
|
||||||
|
|
||||||
"grenadier": "Granatnik",
|
"grenadier": "Granatnik",
|
||||||
"grenadier_desc": "Masz nieskończone granaty odłamkowe",
|
"grenadier_desc": "Masz nieskończone granaty odłamkowe",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingchicken": "Lecząca Kura",
|
"healingchicken": "Lecząca Kura",
|
||||||
"healingchicken_desc": "Twoje kury leczą Cię, gdy jesteś w pobliżu",
|
"healingchicken_desc": "Twoje kury leczą Cię, gdy jesteś w pobliżu",
|
||||||
|
|
||||||
|
"heavyweight": "Waga ciężka",
|
||||||
|
"heavyweight_desc": "Umiejętności, które cię popychają lub spowalniają, nie działają na ciebie",
|
||||||
|
|
||||||
"hermit": "Pustelnik",
|
"hermit": "Pustelnik",
|
||||||
"hermit_desc": "Zabijanie przywraca amunicję i część zdrowia",
|
"hermit_desc": "Zabijanie przywraca amunicję i część zdrowia",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"moneyswap_player_info": "Wymieniłeś swoje pieniądze z graczem '{0}'.",
|
"moneyswap_player_info": "Wymieniłeś swoje pieniądze z graczem '{0}'.",
|
||||||
"moneyswap_select_info": "Zamień się kasą z graczem:",
|
"moneyswap_select_info": "Zamień się kasą z graczem:",
|
||||||
|
|
||||||
|
"nemesis": "Nemezis",
|
||||||
|
"nemesis_desc": "Oznaczony gracz otrzymuje dodatkowe obrażenia",
|
||||||
|
"nemesis_select_info": "Wybierz gracza:",
|
||||||
|
"nemesis_player_info": "Oznaczyłeś '{0}'.",
|
||||||
|
"nemesis_enemy_info": "Zostałeś oznaczony jako nemezis, teraz otrzymujesz dodatkowe obrażenia od wszystkich.",
|
||||||
|
|
||||||
"nightmare": "Koszmar",
|
"nightmare": "Koszmar",
|
||||||
"nightmare_desc": "Wywołaj u wybranego przeciwnika przerażającą wizję",
|
"nightmare_desc": "Wywołaj u wybranego przeciwnika przerażającą wizję",
|
||||||
"nightmare_disable_info": "Koszmar minął.",
|
"nightmare_disable_info": "Koszmar minął.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Proteza",
|
"prosthesis": "Proteza",
|
||||||
"prosthesis_desc": "Ramiona i nogi są kuloodporne",
|
"prosthesis_desc": "Ramiona i nogi są kuloodporne",
|
||||||
|
|
||||||
|
"punisher": "Karzyciel",
|
||||||
|
"punisher_desc": "Gromadzisz część otrzymanych obrażeń i dodajesz je do następnego trafienia",
|
||||||
|
"punisher_released_info": "Zadałeś {0} dodatkowych obrażeń i odzyskałeś tyle samo życia.",
|
||||||
|
|
||||||
"push": "Odpychacz",
|
"push": "Odpychacz",
|
||||||
"push_desc": "Masz losową szansę na odepchnięcie wroga po trafieniu go",
|
"push_desc": "Masz losową szansę na odepchnięcie wroga po trafieniu go",
|
||||||
"push_desc2": "Twoje szanse na odepchnięcie wroga to: {0}%",
|
"push_desc2": "Twoje szanse na odepchnięcie wroga to: {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Zwrot do Nadawcy",
|
"returntosender": "Zwrot do Nadawcy",
|
||||||
"returntosender_desc": "Pierwsze trafienie wroga powoduje, że wraca on na swój resp",
|
"returntosender_desc": "Pierwsze trafienie wroga powoduje, że wraca on na swój resp",
|
||||||
|
|
||||||
|
"rewind": "Przewijanie",
|
||||||
|
"rewind_desc": "Naciśnij [css_useSkill], aby zostawić znacznik i wkrótce do niego wrócić",
|
||||||
|
"rewind_pending_info": "POWRÓT: {0}",
|
||||||
|
|
||||||
"richboy": "Bogacz",
|
"richboy": "Bogacz",
|
||||||
"richboy_desc": "Na początku rundy otrzymujesz losową kwotę gotówki",
|
"richboy_desc": "Na początku rundy otrzymujesz losową kwotę gotówki",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Linka została rozstawiona.",
|
"tripwire_placed_info": "Linka została rozstawiona.",
|
||||||
"tripwire_triggered_info": "'{0}' uruchomił Twoją linkę.",
|
"tripwire_triggered_info": "'{0}' uruchomił Twoją linkę.",
|
||||||
|
|
||||||
|
"truearmor": "Prawdziwy pancerz",
|
||||||
|
"truearmor_desc": "Część obrażeń pokrywa twój pancerz zamiast zdrowia",
|
||||||
|
|
||||||
|
"voodoo": "Voodoo",
|
||||||
|
"voodoo_desc": "Oznaczony wróg również otrzymuje część obrażeń, które ty dostajesz",
|
||||||
|
"voodoo_select_info": "Wybierz gracza:",
|
||||||
|
"voodoo_player_info": "Związałeś '{0}' swoim voodoo.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Widzisz wrogów przez ściany",
|
"wallhack_desc": "Widzisz wrogów przez ściany",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Tiro Explosivo",
|
"blastshot": "Tiro Explosivo",
|
||||||
"blastshot_desc": "Pressione Attack2 com a MP5 para disparar uma granada HE",
|
"blastshot_desc": "Pressione Attack2 com a MP5 para disparar uma granada HE",
|
||||||
|
|
||||||
|
"bounty": "Recompensa",
|
||||||
|
"bounty_desc": "Coloque um preço na cabeça de um inimigo; quem o matar leva o dinheiro",
|
||||||
|
"bounty_select_info": "Escolha um jogador:",
|
||||||
|
"bounty_player_info": "Você colocou {1}$ de recompensa em '{0}'.",
|
||||||
|
"bounty_enemy_info": "Puseram {0}$ de recompensa na sua cabeça.",
|
||||||
|
"bounty_claimed_info": "Você matou '{0}' e levou {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Coelho",
|
"bunnyhop": "Coelho",
|
||||||
"bunnyhop_desc": "Você ganha \"BunnyHop\" automático",
|
"bunnyhop_desc": "Você ganha \"BunnyHop\" automático",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Sua altura agora é aleatória",
|
"dwarf_desc": "Sua altura agora é aleatória",
|
||||||
"dwarf_desc2": "Seu multiplicador de altura é: {0}x",
|
"dwarf_desc2": "Seu multiplicador de altura é: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "Granada EMP",
|
||||||
|
"empgrenade_desc": "Quem se ferir com sua granada perde o radar e a mira por um tempo",
|
||||||
|
"empgrenade_enemy_info": "Uma granada EMP derrubou seu radar e sua mira.",
|
||||||
|
|
||||||
"enemyspawn": "Spawn Inimigo",
|
"enemyspawn": "Spawn Inimigo",
|
||||||
"enemyspawn_desc": "Clique em [css_useSkill] para se teletransportar para a base inimiga",
|
"enemyspawn_desc": "Clique em [css_useSkill] para se teletransportar para a base inimiga",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Nenhuma superfície para prender o gancho.",
|
"grapple_no_anchor_info": "Nenhuma superfície para prender o gancho.",
|
||||||
"grapple_pulling_info": "PUXANDO",
|
"grapple_pulling_info": "PUXANDO",
|
||||||
|
|
||||||
|
"gravitydecoy": "Chamariz Gravitacional",
|
||||||
|
"gravitydecoy_desc": "Seu chamariz muda a gravidade de todos que estão por perto",
|
||||||
|
|
||||||
"grenadier": "Bomberman",
|
"grenadier": "Bomberman",
|
||||||
"grenadier_desc": "Você tem HEs infinitas",
|
"grenadier_desc": "Você tem HEs infinitas",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingchicken": "Galinha Curadora",
|
"healingchicken": "Galinha Curadora",
|
||||||
"healingchicken_desc": "Suas galinhas curam você enquanto você estiver por perto",
|
"healingchicken_desc": "Suas galinhas curam você enquanto você estiver por perto",
|
||||||
|
|
||||||
|
"heavyweight": "Peso Pesado",
|
||||||
|
"heavyweight_desc": "Habilidades que empurram ou te deixam lento não fazem efeito em você",
|
||||||
|
|
||||||
"hermit": "Sanguessuga",
|
"hermit": "Sanguessuga",
|
||||||
"hermit_desc": "Matar restaura munição e uma parte da sua vida",
|
"hermit_desc": "Matar restaura munição e uma parte da sua vida",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"moneyswap_player_info": "Você trocou dinheiro com o jogador '{0}'.",
|
"moneyswap_player_info": "Você trocou dinheiro com o jogador '{0}'.",
|
||||||
"moneyswap_select_info": "Trocar dinheiro c/ jogador:",
|
"moneyswap_select_info": "Trocar dinheiro c/ jogador:",
|
||||||
|
|
||||||
|
"nemesis": "Nêmesis",
|
||||||
|
"nemesis_desc": "O jogador que você marcar recebe dano extra",
|
||||||
|
"nemesis_select_info": "Escolha um jogador:",
|
||||||
|
"nemesis_player_info": "Você marcou '{0}'.",
|
||||||
|
"nemesis_enemy_info": "Você foi marcado como nêmesis, agora recebe dano extra de todos.",
|
||||||
|
|
||||||
"nightmare": "Pesadelo",
|
"nightmare": "Pesadelo",
|
||||||
"nightmare_desc": "Faça um inimigo escolhido ter uma visão aterrorizante",
|
"nightmare_desc": "Faça um inimigo escolhido ter uma visão aterrorizante",
|
||||||
"nightmare_disable_info": "O pesadelo desapareceu.",
|
"nightmare_disable_info": "O pesadelo desapareceu.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Prótese",
|
"prosthesis": "Prótese",
|
||||||
"prosthesis_desc": "Braços e pernas são à prova de balas",
|
"prosthesis_desc": "Braços e pernas são à prova de balas",
|
||||||
|
|
||||||
|
"punisher": "Punidor",
|
||||||
|
"punisher_desc": "Você guarda parte do dano recebido e soma no seu próximo tiro",
|
||||||
|
"punisher_released_info": "Você causou {0} de dano extra e recuperou a mesma vida.",
|
||||||
|
|
||||||
"push": "Empurrão",
|
"push": "Empurrão",
|
||||||
"push_desc": "Você tem uma chance aleatória de empurrar um inimigo ao acertá-lo",
|
"push_desc": "Você tem uma chance aleatória de empurrar um inimigo ao acertá-lo",
|
||||||
"push_desc2": "Suas chances de empurrar o inimigo são: {0}%",
|
"push_desc2": "Suas chances de empurrar o inimigo são: {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Devolução ao Remetente",
|
"returntosender": "Devolução ao Remetente",
|
||||||
"returntosender_desc": "O primeiro tiro em um inimigo o envia de volta a sua base",
|
"returntosender_desc": "O primeiro tiro em um inimigo o envia de volta a sua base",
|
||||||
|
|
||||||
|
"rewind": "Retroceder",
|
||||||
|
"rewind_desc": "Clique em [css_useSkill] para deixar uma marca aqui e voltar a ela logo depois",
|
||||||
|
"rewind_pending_info": "RETORNO: {0}",
|
||||||
|
|
||||||
"richboy": "Filhinho de Papai",
|
"richboy": "Filhinho de Papai",
|
||||||
"richboy_desc": "Você recebe uma quantidade aleatória de dinheiro no início da rodada",
|
"richboy_desc": "Você recebe uma quantidade aleatória de dinheiro no início da rodada",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Fio de armadilha colocado.",
|
"tripwire_placed_info": "Fio de armadilha colocado.",
|
||||||
"tripwire_triggered_info": "'{0}' acionou seu fio.",
|
"tripwire_triggered_info": "'{0}' acionou seu fio.",
|
||||||
|
|
||||||
|
"truearmor": "Armadura Real",
|
||||||
|
"truearmor_desc": "Parte do dano que você recebe sai do colete em vez da vida",
|
||||||
|
|
||||||
|
"voodoo": "Vodu",
|
||||||
|
"voodoo_desc": "O inimigo que você marcar também recebe parte do dano que você leva",
|
||||||
|
"voodoo_select_info": "Escolha um jogador:",
|
||||||
|
"voodoo_player_info": "Você ligou '{0}' ao seu vodu.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Você pode ver inimigos através das paredes",
|
"wallhack_desc": "Você pode ver inimigos através das paredes",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Взрывной выстрел",
|
"blastshot": "Взрывной выстрел",
|
||||||
"blastshot_desc": "Нажмите Attack2 на MP5, чтобы выстрелить гранатой HE",
|
"blastshot_desc": "Нажмите Attack2 на MP5, чтобы выстрелить гранатой HE",
|
||||||
|
|
||||||
|
"bounty": "Награда",
|
||||||
|
"bounty_desc": "Назначь награду за голову врага; тот, кто убьёт его, получит деньги",
|
||||||
|
"bounty_select_info": "Выберите игрока:",
|
||||||
|
"bounty_player_info": "Вы назначили награду {1}$ за '{0}'.",
|
||||||
|
"bounty_enemy_info": "За вашу голову назначили {0}$.",
|
||||||
|
"bounty_claimed_info": "Вы убили '{0}' и получили {1}$.",
|
||||||
|
|
||||||
"bunnyhop": "Заяц",
|
"bunnyhop": "Заяц",
|
||||||
"bunnyhop_desc": "Вы получаете автоматический «БанниХоп»",
|
"bunnyhop_desc": "Вы получаете автоматический «БанниХоп»",
|
||||||
|
|
||||||
|
|
@ -144,6 +151,10 @@
|
||||||
"dwarf_desc": "Случайный размер персонажа в начале раунда",
|
"dwarf_desc": "Случайный размер персонажа в начале раунда",
|
||||||
"dwarf_desc2": "Ваш множитель размера: {0}x",
|
"dwarf_desc2": "Ваш множитель размера: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "ЭМИ-граната",
|
||||||
|
"empgrenade_desc": "Тот, кто пострадал от вашей гранаты, на время теряет радар и прицел",
|
||||||
|
"empgrenade_enemy_info": "ЭМИ-граната вывела из строя ваш радар и прицел.",
|
||||||
|
|
||||||
"enemyspawn": "Спавн врагов",
|
"enemyspawn": "Спавн врагов",
|
||||||
"enemyspawn_desc": "Нажмите [css_useSkill], чтобы телепортироваться на спавн врагов",
|
"enemyspawn_desc": "Нажмите [css_useSkill], чтобы телепортироваться на спавн врагов",
|
||||||
|
|
||||||
|
|
@ -230,6 +241,9 @@
|
||||||
"grapple_no_anchor_info": "Нет поверхности для зацепа.",
|
"grapple_no_anchor_info": "Нет поверхности для зацепа.",
|
||||||
"grapple_pulling_info": "ПРИТЯГИВАНИЕ",
|
"grapple_pulling_info": "ПРИТЯГИВАНИЕ",
|
||||||
|
|
||||||
|
"gravitydecoy": "Гравитационная обманка",
|
||||||
|
"gravitydecoy_desc": "Ваша обманка меняет гравитацию всех, кто рядом",
|
||||||
|
|
||||||
"grenadier": "Гренадёр",
|
"grenadier": "Гренадёр",
|
||||||
"grenadier_desc": "У вас бесконечные осколочные гранаты",
|
"grenadier_desc": "У вас бесконечные осколочные гранаты",
|
||||||
|
|
||||||
|
|
@ -239,6 +253,9 @@
|
||||||
"healingsmoke": "Лечащий дым",
|
"healingsmoke": "Лечащий дым",
|
||||||
"healingsmoke_desc": "Ваши дымовые гранаты лечат",
|
"healingsmoke_desc": "Ваши дымовые гранаты лечат",
|
||||||
|
|
||||||
|
"heavyweight": "Тяжеловес",
|
||||||
|
"heavyweight_desc": "Способности, которые толкают или замедляют, на вас не действуют",
|
||||||
|
|
||||||
"hermit": "Отшельник",
|
"hermit": "Отшельник",
|
||||||
"hermit_desc": "Убийства восстанавливают боеприпасы и часть здоровья",
|
"hermit_desc": "Убийства восстанавливают боеприпасы и часть здоровья",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"moneyswap_player_info": "Вы обменялись деньгами с игроком '{0}'.",
|
"moneyswap_player_info": "Вы обменялись деньгами с игроком '{0}'.",
|
||||||
"moneyswap_select_info": "Обменять деньги с игроком:",
|
"moneyswap_select_info": "Обменять деньги с игроком:",
|
||||||
|
|
||||||
|
"nemesis": "Немезида",
|
||||||
|
"nemesis_desc": "Отмеченный вами игрок получает больше урона",
|
||||||
|
"nemesis_select_info": "Выберите игрока:",
|
||||||
|
"nemesis_player_info": "Вы отметили '{0}'.",
|
||||||
|
"nemesis_enemy_info": "Вы отмечены как немезида и теперь получаете больше урона от всех.",
|
||||||
|
|
||||||
"nightmare": "Кошмар",
|
"nightmare": "Кошмар",
|
||||||
"nightmare_desc": "Заставьте выбранного противника увидеть кошмарное видение",
|
"nightmare_desc": "Заставьте выбранного противника увидеть кошмарное видение",
|
||||||
"nightmare_disable_info": "Кошмар рассеялся.",
|
"nightmare_disable_info": "Кошмар рассеялся.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Протез",
|
"prosthesis": "Протез",
|
||||||
"prosthesis_desc": "Руки и ноги защищены от пуль",
|
"prosthesis_desc": "Руки и ноги защищены от пуль",
|
||||||
|
|
||||||
|
"punisher": "Каратель",
|
||||||
|
"punisher_desc": "Вы копите часть полученного урона и добавляете его к следующему попаданию",
|
||||||
|
"punisher_released_info": "Вы нанесли {0} дополнительного урона и восстановили столько же здоровья.",
|
||||||
|
|
||||||
"push": "Толкач",
|
"push": "Толкач",
|
||||||
"push_desc": "Есть шанс оттолкнуть врага назад при попадании",
|
"push_desc": "Есть шанс оттолкнуть врага назад при попадании",
|
||||||
"push_desc2": "Ваш шанс оттолкнуть врага: {0}%",
|
"push_desc2": "Ваш шанс оттолкнуть врага: {0}%",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "Вернуть отправителю",
|
"returntosender": "Вернуть отправителю",
|
||||||
"returntosender_desc": "Первое попадание по врагу отправляет его обратно на спавн",
|
"returntosender_desc": "Первое попадание по врагу отправляет его обратно на спавн",
|
||||||
|
|
||||||
|
"rewind": "Перемотка",
|
||||||
|
"rewind_desc": "Нажмите [css_useSkill], чтобы оставить метку здесь и вскоре вернуться к ней",
|
||||||
|
"rewind_pending_info": "ВОЗВРАТ: {0}",
|
||||||
|
|
||||||
"richboy": "Богач",
|
"richboy": "Богач",
|
||||||
"richboy_desc": "Вы получаете случайную сумму денег в начале раунда",
|
"richboy_desc": "Вы получаете случайную сумму денег в начале раунда",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Растяжка установлена.",
|
"tripwire_placed_info": "Растяжка установлена.",
|
||||||
"tripwire_triggered_info": "'{0}' задел вашу растяжку.",
|
"tripwire_triggered_info": "'{0}' задел вашу растяжку.",
|
||||||
|
|
||||||
|
"truearmor": "Настоящая броня",
|
||||||
|
"truearmor_desc": "Часть урона принимает броня, а не здоровье",
|
||||||
|
|
||||||
|
"voodoo": "Вуду",
|
||||||
|
"voodoo_desc": "Отмеченный враг тоже получает часть урона, который получаете вы",
|
||||||
|
"voodoo_select_info": "Выберите игрока:",
|
||||||
|
"voodoo_player_info": "Вы привязали '{0}' к своему вуду.",
|
||||||
|
|
||||||
"wallhack": "Воллхак",
|
"wallhack": "Воллхак",
|
||||||
"wallhack_desc": "Вы видите врагов сквозь стены",
|
"wallhack_desc": "Вы видите врагов сквозь стены",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
"blastshot": "Patlama Atışı",
|
"blastshot": "Patlama Atışı",
|
||||||
"blastshot_desc": "MP5 ile sağ tıklayarak el bombası fırlat",
|
"blastshot_desc": "MP5 ile sağ tıklayarak el bombası fırlat",
|
||||||
|
|
||||||
|
"bounty": "Ödül Avı",
|
||||||
|
"bounty_desc": "Bir düşmana ödül koy, onu öldüren parayı alır",
|
||||||
|
"bounty_select_info": "Birini seçin:",
|
||||||
|
"bounty_player_info": "'{0}' için {1}$ ödül koydun.",
|
||||||
|
"bounty_enemy_info": "Başına {0}$ ödül kondu.",
|
||||||
|
"bounty_claimed_info": "'{0}' oyuncusunu öldürdün ve {1}$ kazandın.",
|
||||||
|
|
||||||
"bunnyhop": "Tavşan",
|
"bunnyhop": "Tavşan",
|
||||||
"bunnyhop_desc": "Otomatik BunnyHop yaparsın",
|
"bunnyhop_desc": "Otomatik BunnyHop yaparsın",
|
||||||
|
|
||||||
|
|
@ -137,6 +144,10 @@
|
||||||
"dwarf_desc": "Rastgele karakter boyutu",
|
"dwarf_desc": "Rastgele karakter boyutu",
|
||||||
"dwarf_desc2": "Boyutun: {0}x",
|
"dwarf_desc2": "Boyutun: {0}x",
|
||||||
|
|
||||||
|
"empgrenade": "EMP Bombası",
|
||||||
|
"empgrenade_desc": "El bomban, hasar verdiğin düşmanın radarını ve nişangahını kapatır",
|
||||||
|
"empgrenade_enemy_info": "Radarın ve nişangahın kapandı.",
|
||||||
|
|
||||||
"enemyspawn": "Base Baskını",
|
"enemyspawn": "Base Baskını",
|
||||||
"enemyspawn_desc": "[css_useSkill] tuşuna basarak düşman doğma noktasına ışınlan",
|
"enemyspawn_desc": "[css_useSkill] tuşuna basarak düşman doğma noktasına ışınlan",
|
||||||
|
|
||||||
|
|
@ -223,6 +234,9 @@
|
||||||
"grapple_no_anchor_info": "Kanca atılacak yüzey yok",
|
"grapple_no_anchor_info": "Kanca atılacak yüzey yok",
|
||||||
"grapple_pulling_info": "ÇEKİLİYOR",
|
"grapple_pulling_info": "ÇEKİLİYOR",
|
||||||
|
|
||||||
|
"gravitydecoy": "Yerçekimi Yanıltıcısı",
|
||||||
|
"gravitydecoy_desc": "Yanıltıcı bomban yakındaki herkesin yerçekimini değiştirir",
|
||||||
|
|
||||||
"grenadier": "Bombacı",
|
"grenadier": "Bombacı",
|
||||||
"grenadier_desc": "El bomban sınırsız",
|
"grenadier_desc": "El bomban sınırsız",
|
||||||
|
|
||||||
|
|
@ -232,6 +246,9 @@
|
||||||
"healingsmoke": "Şifalı Sis",
|
"healingsmoke": "Şifalı Sis",
|
||||||
"healingsmoke_desc": "Sis bomban iyileştirir",
|
"healingsmoke_desc": "Sis bomban iyileştirir",
|
||||||
|
|
||||||
|
"heavyweight": "Ağır Sıklet",
|
||||||
|
"heavyweight_desc": "Seni iten ve yavaşlatan yetenekler işlemez",
|
||||||
|
|
||||||
"hermit": "Münzevi",
|
"hermit": "Münzevi",
|
||||||
"hermit_desc": "Birini öldürünce mermin ve canın yenilenir",
|
"hermit_desc": "Birini öldürünce mermin ve canın yenilenir",
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@
|
||||||
"demoneye": "Şeytani Göz",
|
"demoneye": "Şeytani Göz",
|
||||||
"demoneye_desc": "Baktığın tüm düşmana hasar verirsin",
|
"demoneye_desc": "Baktığın tüm düşmana hasar verirsin",
|
||||||
|
|
||||||
|
"nemesis": "Ezeli Rakip",
|
||||||
|
"nemesis_desc": "İşaretlediğin düşman herkesten daha fazla hasar alır",
|
||||||
|
"nemesis_select_info": "Birini seçin:",
|
||||||
|
"nemesis_player_info": "'{0}' artık herkesten daha fazla hasar alacak.",
|
||||||
|
"nemesis_enemy_info": "İşaretlendin, artık herkesten daha fazla hasar alıyorsun.",
|
||||||
|
|
||||||
"nightmare": "Kabus",
|
"nightmare": "Kabus",
|
||||||
"nightmare_desc": "Seçtiğin rakibe kabus gördür",
|
"nightmare_desc": "Seçtiğin rakibe kabus gördür",
|
||||||
"nightmare_disable_info": "Kabus sona erdi.",
|
"nightmare_disable_info": "Kabus sona erdi.",
|
||||||
|
|
@ -423,6 +446,10 @@
|
||||||
"prosthesis": "Protez",
|
"prosthesis": "Protez",
|
||||||
"prosthesis_desc": "Kolların ve bacakların kurşun geçirmez",
|
"prosthesis_desc": "Kolların ve bacakların kurşun geçirmez",
|
||||||
|
|
||||||
|
"punisher": "İntikam",
|
||||||
|
"punisher_desc": "Aldığın hasarı biriktirir, sonraki vuruşunda geri verirsin",
|
||||||
|
"punisher_released_info": "{0} ekstra hasar verdin ve o kadar can kazandın.",
|
||||||
|
|
||||||
"push": "İtici",
|
"push": "İtici",
|
||||||
"push_desc": "Düşmana vurduğunda onu geri itme şansın olur",
|
"push_desc": "Düşmana vurduğunda onu geri itme şansın olur",
|
||||||
"push_desc2": "Geri itme şansın: %{0}",
|
"push_desc2": "Geri itme şansın: %{0}",
|
||||||
|
|
@ -460,6 +487,10 @@
|
||||||
"returntosender": "İade",
|
"returntosender": "İade",
|
||||||
"returntosender_desc": "Düşmana ilk vuruşun onu kendi başlangıcına ışınlar",
|
"returntosender_desc": "Düşmana ilk vuruşun onu kendi başlangıcına ışınlar",
|
||||||
|
|
||||||
|
"rewind": "Geri Sarma",
|
||||||
|
"rewind_desc": "[css_useSkill] tuşuna basarak iz bırak, birazdan oraya geri dön",
|
||||||
|
"rewind_pending_info": "DÖNÜŞ: {0}",
|
||||||
|
|
||||||
"richboy": "Zengin Çocuk",
|
"richboy": "Zengin Çocuk",
|
||||||
"richboy_desc": "Rastgele miktarda paran olur",
|
"richboy_desc": "Rastgele miktarda paran olur",
|
||||||
|
|
||||||
|
|
@ -549,6 +580,14 @@
|
||||||
"tripwire_placed_info": "Tel gerildi.",
|
"tripwire_placed_info": "Tel gerildi.",
|
||||||
"tripwire_triggered_info": "'{0}' teline takıldı.",
|
"tripwire_triggered_info": "'{0}' teline takıldı.",
|
||||||
|
|
||||||
|
"truearmor": "Gerçek Zırh",
|
||||||
|
"truearmor_desc": "Aldığın hasarın bir kısmını canın yerine zırhın karşılar",
|
||||||
|
|
||||||
|
"voodoo": "Vudu",
|
||||||
|
"voodoo_desc": "Aldığın hasarın bir kısmını işaretlediğin düşman da alır",
|
||||||
|
"voodoo_select_info": "Birini seçin:",
|
||||||
|
"voodoo_player_info": "'{0}' oyuncusunu kendine bağladın.",
|
||||||
|
|
||||||
"wallhack": "Wallhack",
|
"wallhack": "Wallhack",
|
||||||
"wallhack_desc": "Düşmanları duvar arkasından görürsün",
|
"wallhack_desc": "Düşmanları duvar arkasından görürsün",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,13 @@
|
||||||
"blademaster": "我的刀能档子弹!",
|
"blademaster": "我的刀能档子弹!",
|
||||||
"blademaster_desc": "持刀时,你有很高几率格挡子弹",
|
"blademaster_desc": "持刀时,你有很高几率格挡子弹",
|
||||||
|
|
||||||
|
"bounty": "悬赏",
|
||||||
|
"bounty_desc": "对一名敌人悬赏,击杀他的人可以获得赏金",
|
||||||
|
"bounty_select_info": "选择一名玩家:",
|
||||||
|
"bounty_player_info": "你对 '{0}' 悬赏了 {1}$。",
|
||||||
|
"bounty_enemy_info": "有人对你悬赏了 {0}$。",
|
||||||
|
"bounty_claimed_info": "你击杀了 '{0}',获得 {1}$。",
|
||||||
|
|
||||||
"bunnyhop": "连跳大佬",
|
"bunnyhop": "连跳大佬",
|
||||||
"bunnyhop_desc": "你获得自动连跳的能力",
|
"bunnyhop_desc": "你获得自动连跳的能力",
|
||||||
|
|
||||||
|
|
@ -131,6 +138,10 @@
|
||||||
"dwarf_desc": "回合开始时获得随机角色大小",
|
"dwarf_desc": "回合开始时获得随机角色大小",
|
||||||
"dwarf_desc2": "你的体型倍率是:{0}x",
|
"dwarf_desc2": "你的体型倍率是:{0}x",
|
||||||
|
|
||||||
|
"empgrenade": "电磁脉冲手雷",
|
||||||
|
"empgrenade_desc": "被你的手雷伤到的人会暂时失去雷达和准星",
|
||||||
|
"empgrenade_enemy_info": "电磁脉冲手雷让你的雷达和准星失效了。",
|
||||||
|
|
||||||
"enemyspawn": "传送敌人出生点",
|
"enemyspawn": "传送敌人出生点",
|
||||||
"enemyspawn_desc": "点击 [css_useSkill] 传送到敌人出生点",
|
"enemyspawn_desc": "点击 [css_useSkill] 传送到敌人出生点",
|
||||||
|
|
||||||
|
|
@ -211,12 +222,18 @@
|
||||||
"grapple_no_anchor_info": "没有可以钩住的表面。",
|
"grapple_no_anchor_info": "没有可以钩住的表面。",
|
||||||
"grapple_pulling_info": "拉动中",
|
"grapple_pulling_info": "拉动中",
|
||||||
|
|
||||||
|
"gravitydecoy": "重力诱饵",
|
||||||
|
"gravitydecoy_desc": "你的诱饵会改变附近所有人的重力",
|
||||||
|
|
||||||
"grenadier": "投弹手",
|
"grenadier": "投弹手",
|
||||||
"grenadier_desc": "你拥有无限高爆手雷",
|
"grenadier_desc": "你拥有无限高爆手雷",
|
||||||
|
|
||||||
"healingsmoke": "治疗烟雾",
|
"healingsmoke": "治疗烟雾",
|
||||||
"healingsmoke_desc": "你的烟雾弹会治疗",
|
"healingsmoke_desc": "你的烟雾弹会治疗",
|
||||||
|
|
||||||
|
"heavyweight": "重量级",
|
||||||
|
"heavyweight_desc": "推开你或让你减速的技能对你无效",
|
||||||
|
|
||||||
"hermit": "隐士",
|
"hermit": "隐士",
|
||||||
"hermit_desc": "击杀敌人会恢复弹药和部分生命值",
|
"hermit_desc": "击杀敌人会恢复弹药和部分生命值",
|
||||||
|
|
||||||
|
|
@ -330,6 +347,12 @@
|
||||||
"deathbomb_desc": "你死亡时会爆炸,杀死附近的玩家",
|
"deathbomb_desc": "你死亡时会爆炸,杀死附近的玩家",
|
||||||
"deathbomb_explosion": "砰!",
|
"deathbomb_explosion": "砰!",
|
||||||
|
|
||||||
|
"nemesis": "宿敌",
|
||||||
|
"nemesis_desc": "被你标记的玩家会受到额外伤害",
|
||||||
|
"nemesis_select_info": "选择一名玩家:",
|
||||||
|
"nemesis_player_info": "你标记了 '{0}'。",
|
||||||
|
"nemesis_enemy_info": "你被标记为宿敌,现在会受到所有人的额外伤害。",
|
||||||
|
|
||||||
"nightmare": "nightmare",
|
"nightmare": "nightmare",
|
||||||
"nightmare_desc": "nightmare_desc",
|
"nightmare_desc": "nightmare_desc",
|
||||||
"nightmare_disable_info": "nightmare_disable_info",
|
"nightmare_disable_info": "nightmare_disable_info",
|
||||||
|
|
@ -393,6 +416,10 @@
|
||||||
"prosthesis": "假肢",
|
"prosthesis": "假肢",
|
||||||
"prosthesis_desc": "手臂和腿部防弹",
|
"prosthesis_desc": "手臂和腿部防弹",
|
||||||
|
|
||||||
|
"punisher": "惩罚者",
|
||||||
|
"punisher_desc": "你会积攒受到伤害的一部分,并加到下一次命中上",
|
||||||
|
"punisher_released_info": "你造成了 {0} 点额外伤害,并回复了同样的生命值。",
|
||||||
|
|
||||||
"push": "推力者",
|
"push": "推力者",
|
||||||
"push_desc": "你有随机几率在击中敌人时将其推回",
|
"push_desc": "你有随机几率在击中敌人时将其推回",
|
||||||
"push_desc2": "你击退敌人的几率为:{0}%",
|
"push_desc2": "你击退敌人的几率为:{0}%",
|
||||||
|
|
@ -430,6 +457,10 @@
|
||||||
"returntosender": "发送他们房子!!!",
|
"returntosender": "发送他们房子!!!",
|
||||||
"returntosender_desc": "首次击中敌人会将其送回出生点",
|
"returntosender_desc": "首次击中敌人会将其送回出生点",
|
||||||
|
|
||||||
|
"rewind": "回溯",
|
||||||
|
"rewind_desc": "按 [css_useSkill] 在原地留下标记,稍后回到那里",
|
||||||
|
"rewind_pending_info": "回溯:{0}",
|
||||||
|
|
||||||
"richboy": "富少",
|
"richboy": "富少",
|
||||||
"richboy_desc": "回合开始时你获得随机数量的钱",
|
"richboy_desc": "回合开始时你获得随机数量的钱",
|
||||||
|
|
||||||
|
|
@ -507,6 +538,14 @@
|
||||||
"tripwire_placed_info": "tripwire_placed_info",
|
"tripwire_placed_info": "tripwire_placed_info",
|
||||||
"tripwire_triggered_info": "tripwire_triggered_info: {0}",
|
"tripwire_triggered_info": "tripwire_triggered_info: {0}",
|
||||||
|
|
||||||
|
"truearmor": "真实护甲",
|
||||||
|
"truearmor_desc": "你受到的一部分伤害由护甲承担,而不是生命值",
|
||||||
|
|
||||||
|
"voodoo": "巫毒",
|
||||||
|
"voodoo_desc": "被你标记的敌人也会受到你所受伤害的一部分",
|
||||||
|
"voodoo_select_info": "选择一名玩家:",
|
||||||
|
"voodoo_player_info": "你把 '{0}' 绑到了你的巫毒上。",
|
||||||
|
|
||||||
"wallhack": "透视",
|
"wallhack": "透视",
|
||||||
"wallhack_desc": "你可以通过墙壁看到敌人",
|
"wallhack_desc": "你可以通过墙壁看到敌人",
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue