v1.2.3.b2 - Part 2
## GENERAL - Added a css_entity admin command to check whether an entity with a given index/handle exists (prints the designer name to chat or console). - Added a TakeDamage post-hook (OnTakeDamagePost) alongside the existing pre-hook, so skills can now react after damage has actually been applied, not just before. - Added CreateMolotovProjectile (new CMolotovProjectile_CreateFunc signature) and CreateTrackedChicken entity helpers. - Added a weapon_mp7 → weapon_mp5sd fallback mapping. - Added class for KillfeedIcons ## SKILL IMPROVEMENTS - Aimbot: -- Only forces a headshot hitgroup once (skips if it's already a head or an invalid hitgroup), and now restores the original hitgroup value in the new post-damage hook instead of leaving it overwritten. - Tripwire: -- Reduced the default wire width from 1.5 to 0.7. ## NEW SKILLS: - Berserker: You deal more damage and move faster as your health gets lower. - Blast Shot: Press Attack2 with the MP5 to fire an HE grenade. - Demon Eye: You deal damage to every enemy you are looking at. - Fire Rain: Throw a decoy to call down a rain of Molotovs. - Flashlight: Click [css_useSkill] to turn the flashlight on or off; its light can blind enemies. - Healing Chicken: Your chickens heal you while you are nearby. - Jetkick: Select a player to jetkick - every shot they fire knocks them backwards until disabled. - Last Gasp: After you die, you deal damage to the enemy who killed you. - Take Ammo: Click [css_useSkill] to take the active weapon's magazine from a random enemy. - Team Teleport: Press [css_useSkill] to teleport to the teammate you're looking at.
This commit is contained in:
parent
203a0c3986
commit
8038a4d646
57 changed files with 3663 additions and 553 deletions
|
|
@ -1,20 +1,12 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Events;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.UserMessages;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using RayTraceAPI;
|
||||
using src.player.skills;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using static CounterStrikeSharp.API.Core.Listeners;
|
||||
using static src.jRandomSkills;
|
||||
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
|
||||
|
||||
namespace src.player
|
||||
{
|
||||
|
|
@ -106,6 +98,15 @@ namespace src.player
|
|||
}
|
||||
}
|
||||
|
||||
private static HookResult OnTakeDamagePost(DynamicHook h)
|
||||
{
|
||||
lock (setLock)
|
||||
{
|
||||
DispatchOnTakeDamage(h, true);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
private static HookResult OnTriggerEnter(DynamicHook hook)
|
||||
{
|
||||
lock (setLock)
|
||||
|
|
@ -172,33 +173,6 @@ namespace src.player
|
|||
}
|
||||
}
|
||||
|
||||
private static HookResult WeaponDrop(DynamicHook hook)
|
||||
{
|
||||
lock (setLock)
|
||||
{
|
||||
CCSPlayerController player = hook.GetParam<CCSPlayerController>(0);
|
||||
if (player == null || !player.IsValid)
|
||||
return HookResult.Continue;
|
||||
|
||||
var activeSkills = Instance.SkillPlayer
|
||||
.Where(p => !p.IsDrawing)
|
||||
.Select(p => p.Skill.ToString())
|
||||
.Distinct();
|
||||
|
||||
bool block = false;
|
||||
foreach (string skillName in activeSkills)
|
||||
{
|
||||
bool? result = (bool?)Instance.SkillAction(skillName, "WeaponDrop", [hook, player]);
|
||||
if (result == true)
|
||||
{
|
||||
block = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return block ? HookResult.Handled : HookResult.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EntitySpawned(CEntityInstance entity)
|
||||
{
|
||||
lock (setLock)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public interface ISkill
|
|||
public static void TypeSkill(CCSPlayerController _, string[] __) { }
|
||||
|
||||
public static void OnTakeDamage(DynamicHook _) { }
|
||||
public static void OnTakeDamagePost(DynamicHook _) { }
|
||||
public static void OnEntitySpawned(CEntityInstance _) { }
|
||||
public static void OnTick() { }
|
||||
public static void CheckTransmit([CastFrom(typeof(nint))] CCheckTransmitInfoList _) { }
|
||||
|
|
@ -70,8 +71,10 @@ public enum Skills
|
|||
Bankrupt,
|
||||
Baseball,
|
||||
Behind,
|
||||
Berserker,
|
||||
BladeMaster,
|
||||
BunnyHop,
|
||||
BlastShot,
|
||||
C4Camouflage,
|
||||
CarefulBullets,
|
||||
Catapult,
|
||||
|
|
@ -83,6 +86,7 @@ public enum Skills
|
|||
Deactivator,
|
||||
Deaf,
|
||||
DeathBomb,
|
||||
DemonEye,
|
||||
Disarmament,
|
||||
Distancer,
|
||||
Dash,
|
||||
|
|
@ -95,7 +99,9 @@ public enum Skills
|
|||
ExplosiveShot,
|
||||
FalconEye,
|
||||
FastReload,
|
||||
FireRain,
|
||||
Flash,
|
||||
Flashlight,
|
||||
Fortnite,
|
||||
FragileBomb,
|
||||
FriendlyFire,
|
||||
|
|
@ -108,6 +114,7 @@ public enum Skills
|
|||
Glue,
|
||||
GodMode,
|
||||
Grenadier,
|
||||
HealingChicken,
|
||||
HealingSmoke,
|
||||
Hermit,
|
||||
HolyHandGrenade,
|
||||
|
|
@ -121,11 +128,13 @@ public enum Skills
|
|||
Jackal,
|
||||
Jammer,
|
||||
Jester,
|
||||
JetKick,
|
||||
JumpBan,
|
||||
JumpCurse,
|
||||
JumpingJack,
|
||||
KillerFlash,
|
||||
Knockback,
|
||||
LastGasp,
|
||||
LifeSwap,
|
||||
LongKnife,
|
||||
LongZeus,
|
||||
|
|
@ -176,6 +185,8 @@ public enum Skills
|
|||
SoundMaker,
|
||||
Spectator,
|
||||
SwapPosition,
|
||||
TakeAmmo,
|
||||
TeamTeleport,
|
||||
Teleporter,
|
||||
Thief,
|
||||
ThirdEye,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ namespace src.player
|
|||
|
||||
Instance.HookUserMessage(208, PlayerMakeSound);
|
||||
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre);
|
||||
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamagePost, HookMode.Post);
|
||||
|
||||
Instance.RegisterEventHandler<EventBulletImpact>(BulletImpact);
|
||||
|
||||
|
|
@ -94,6 +95,7 @@ namespace src.player
|
|||
public static void Unload()
|
||||
{
|
||||
TryUnhook(() => VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamage, HookMode.Pre));
|
||||
TryUnhook(() => VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamagePost, HookMode.Post));
|
||||
TryUnhook(() => VirtualFunctions.CBaseTrigger_StartTouchFunc.Unhook(OnTriggerEnter, HookMode.Post));
|
||||
TryUnhook(() => VirtualFunctions.CBaseTrigger_EndTouchFunc.Unhook(OnTriggerExit, HookMode.Pre));
|
||||
TryUnhook(() => VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Unhook(OnWeaponCanAcquire, HookMode.Pre));
|
||||
|
|
@ -133,7 +135,7 @@ namespace src.player
|
|||
}
|
||||
}
|
||||
|
||||
private static void DispatchOnTakeDamage(DynamicHook h)
|
||||
private static void DispatchOnTakeDamage(DynamicHook h, bool post = false)
|
||||
{
|
||||
object[] args = [h];
|
||||
var seen = new HashSet<Skills>();
|
||||
|
|
@ -149,26 +151,26 @@ namespace src.player
|
|||
continue;
|
||||
}
|
||||
|
||||
InvokeOnTakeDamage(p.Skill, h, args);
|
||||
InvokeOnTakeDamage(p.Skill, h, args, post);
|
||||
}
|
||||
|
||||
if (deferred == null) return;
|
||||
foreach (var skill in deferred)
|
||||
InvokeOnTakeDamage(skill, h, args);
|
||||
InvokeOnTakeDamage(skill, h, args, post);
|
||||
}
|
||||
|
||||
private static void InvokeOnTakeDamage(Skills skill, DynamicHook h, object[] args)
|
||||
private static void InvokeOnTakeDamage(Skills skill, DynamicHook h, object[] args, bool post)
|
||||
{
|
||||
if (Config.LoadedConfig.DebugMode != true)
|
||||
{
|
||||
InvokeSkill(skill, "OnTakeDamage", args);
|
||||
InvokeSkill(skill, post ? "OnTakeDamagePost" : "OnTakeDamage", args);
|
||||
return;
|
||||
}
|
||||
|
||||
var info = h.GetParam<CTakeDamageInfo>(1);
|
||||
float before = info == null ? 0f : info.Damage;
|
||||
|
||||
InvokeSkill(skill, "OnTakeDamage", args);
|
||||
InvokeSkill(skill, post ? "OnTakeDamagePost" : "OnTakeDamage", args);
|
||||
|
||||
float after = info == null ? 0f : info.Damage;
|
||||
if (Math.Abs(before - after) > 0.01f)
|
||||
|
|
@ -345,6 +347,33 @@ namespace src.player
|
|||
}
|
||||
}
|
||||
|
||||
private static HookResult WeaponDrop(DynamicHook hook)
|
||||
{
|
||||
lock (setLock)
|
||||
{
|
||||
CCSPlayerController player = hook.GetParam<CCSPlayerController>(0);
|
||||
if (player == null || !player.IsValid)
|
||||
return HookResult.Continue;
|
||||
|
||||
var activeSkills = Instance.SkillPlayer
|
||||
.Where(p => !p.IsDrawing)
|
||||
.Select(p => p.Skill.ToString())
|
||||
.Distinct();
|
||||
|
||||
bool block = false;
|
||||
foreach (string skillName in activeSkills)
|
||||
{
|
||||
bool? result = (bool?)Instance.SkillAction(skillName, "WeaponDrop", [hook, player]);
|
||||
if (result == true)
|
||||
{
|
||||
block = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return block ? HookResult.Handled : HookResult.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Skills, string> _skillNames =
|
||||
Enum.GetValues<Skills>().ToDictionary(s => s, s => s.ToString());
|
||||
private static readonly HashSet<Skills> _activeSkillsSet = [];
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace src.player.skills
|
|||
public class Aimbot : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Aimbot;
|
||||
private static readonly ThreadLocal<Stack<(nint Address, HitGroup_t OldValue)>> _restoreStack = new(() => new Stack<(nint, HitGroup_t)>());
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
|
|
@ -50,7 +51,33 @@ namespace src.player.skills
|
|||
nint hitGroupData = Marshal.ReadIntPtr(hitGroupPointer, 16);
|
||||
if (hitGroupData == nint.Zero) return;
|
||||
|
||||
Marshal.WriteInt32(hitGroupData, 56, (int)HitGroup_t.HITGROUP_HEAD);
|
||||
nint address = hitGroupData + 56;
|
||||
HitGroup_t oldValue = (HitGroup_t)Marshal.ReadInt32(address);
|
||||
|
||||
if (oldValue == HitGroup_t.HITGROUP_HEAD || oldValue == HitGroup_t.HITGROUP_INVALID) return;
|
||||
|
||||
_restoreStack.Value!.Push((address, oldValue));
|
||||
Marshal.WriteInt32(address, (int)HitGroup_t.HITGROUP_HEAD);
|
||||
}
|
||||
|
||||
public static void OnTakeDamagePost(DynamicHook h)
|
||||
{
|
||||
var info = h.GetParam<CTakeDamageInfo>(1);
|
||||
|
||||
if (info == null || info.Handle == nint.Zero)
|
||||
return;
|
||||
|
||||
if (!SkillUtils.IsBulletDamage(info)) return;
|
||||
|
||||
if (_restoreStack.Value!.Count > 0)
|
||||
{
|
||||
var (address, oldValue) = _restoreStack.Value.Pop();
|
||||
|
||||
if (address == nint.Zero)
|
||||
return;
|
||||
|
||||
Marshal.WriteInt32(address, (int)oldValue);
|
||||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff0000", 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) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ namespace src.player.skills
|
|||
var attackerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(attacker)?.Index ?? attacker.Index));
|
||||
if (attackerInfo?.Skill != skillName) return;
|
||||
|
||||
SkillUtils.TakeHealth(victim!.PlayerPawn.Value, SkillsInfo.GetValue<int>(skillName, "damageDeal"), attacker, "decoy");
|
||||
SkillUtils.TakeHealth(victim!.PlayerPawn.Value, SkillsInfo.GetValue<int>(skillName, "damageDeal"), attacker, KillfeedIcons.Decoy);
|
||||
}
|
||||
|
||||
public static void OnEntitySpawned(CEntityInstance entity)
|
||||
|
|
|
|||
123
jRandomSkills - SRC Files/src/player/skills/Berserker.cs
Normal file
123
jRandomSkills - SRC Files/src/player/skills/Berserker.cs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
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 Berserker : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Berserker;
|
||||
public static readonly ConcurrentDictionary<uint, int> jumpedPlayers = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"), false);
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
jumpedPlayers.Clear();
|
||||
}
|
||||
|
||||
private static float CalculateNewVelocity(CCSPlayerPawn pawn, float maxValue)
|
||||
{
|
||||
if (pawn!.Health <= 0) return 1f;
|
||||
|
||||
float healthPercentage = pawn.MaxHealth > 0
|
||||
? Math.Clamp((float)pawn.Health / pawn.MaxHealth, 0f, 1f)
|
||||
: 0f;
|
||||
|
||||
float newValue = 1f + (maxValue - 1f) * (1f - healthPercentage);
|
||||
return Math.Max(1, Math.Min(maxValue, newValue));
|
||||
}
|
||||
|
||||
public static void OnTakeDamage(DynamicHook h)
|
||||
{
|
||||
CEntityInstance param = h.GetParam<CEntityInstance>(0);
|
||||
CTakeDamageInfo param2 = h.GetParam<CTakeDamageInfo>(1);
|
||||
|
||||
if (param == null || param.Entity == null || param2 == null || param2.Attacker == null || param2.Attacker.Value == null)
|
||||
return;
|
||||
|
||||
CCSPlayerPawn attackerPawn = new(param2.Attacker.Value.Handle);
|
||||
CCSPlayerPawn victimPawn = new(param.Handle);
|
||||
|
||||
if (attackerPawn.DesignerName != "player" || victimPawn.DesignerName != "player")
|
||||
return;
|
||||
|
||||
if (attackerPawn == null || attackerPawn.Controller?.Value == null || victimPawn == null || victimPawn.Controller?.Value == null)
|
||||
return;
|
||||
|
||||
CCSPlayerController attacker = PlayerManager.GetPlayerEvent(attackerPawn.Controller.Value.As<CCSPlayerController>())!;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index);
|
||||
if (playerInfo == null) return;
|
||||
|
||||
if (playerInfo.Skill == skillName)
|
||||
{
|
||||
float damageMultiplier = CalculateNewVelocity(attackerPawn, SkillsInfo.GetValue<float>(skillName, "maxDamageVelocity"));
|
||||
param2.Damage *= damageMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
public static void PlayerJump(EventPlayerJump @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (player == null || !player.IsValid) return;
|
||||
if (!jumpedPlayers.TryGetValue(player.Index, out _)) return;
|
||||
jumpedPlayers.AddOrUpdate(player.Index, Server.TickCount + 20, (k, v) => Server.TickCount + 20);
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerPawn == null || playerInfo == null) return;
|
||||
jumpedPlayers.TryAdd(player.Index, 0);
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
if (playerPawn == null) return;
|
||||
playerPawn.VelocityModifier = 1;
|
||||
jumpedPlayers.TryRemove(player.Index, out _);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (!Instance.IsPlayerValid(player)) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) continue;
|
||||
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || playerPawn.VelocityModifier == 0) continue;
|
||||
|
||||
var buttons = player.Buttons;
|
||||
float newSpeedVelocity = CalculateNewVelocity(playerPawn, SkillsInfo.GetValue<float>(skillName, "maxSpeedVelocity"));
|
||||
|
||||
if (buttons.HasFlag(PlayerButtons.Moveleft) || buttons.HasFlag(PlayerButtons.Moveright) || buttons.HasFlag(PlayerButtons.Forward) || buttons.HasFlag(PlayerButtons.Back))
|
||||
playerPawn.VelocityModifier = newSpeedVelocity;
|
||||
|
||||
if (jumpedPlayers.TryGetValue(player.Index, out var time) && time > Server.TickCount)
|
||||
continue;
|
||||
|
||||
if (!((PlayerFlags)player.Flags).HasFlag(PlayerFlags.FL_ONGROUND))
|
||||
playerPawn.AbsVelocity.Z = Math.Min(playerPawn.AbsVelocity.Z, 10);
|
||||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#cc2929", 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 maxSpeedVelocity = 2f, float maxDamageVelocity = 2f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float MaxSpeedVelocity { get; set; } = maxSpeedVelocity;
|
||||
public float MaxDamageVelocity { get; set; } = maxDamageVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
217
jRandomSkills - SRC Files/src/player/skills/BlastShot.cs
Normal file
217
jRandomSkills - SRC Files/src/player/skills/BlastShot.cs
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class BlastShot : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.BlastShot;
|
||||
private static readonly QAngle angle = new(13, -5, 5);
|
||||
private static readonly ConcurrentDictionary<int, (byte Team, uint Owner)> nades = [];
|
||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||
private static readonly string[] allowedWeapons = ["weapon_mp5sd"];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
SkillPlayerInfo.Clear();
|
||||
nades.Clear();
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
|
||||
{
|
||||
SteamID = player.Index,
|
||||
CanUse = true,
|
||||
Cooldown = DateTime.MinValue,
|
||||
});
|
||||
SkillUtils.TryGiveWeapon(player, CsItem.MP5SD);
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
SkillPlayerInfo.TryRemove(player.Index, out _);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
float cooldown = SkillsInfo.GetValue<float>(skillName, "cooldown");
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) continue;
|
||||
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid) continue;
|
||||
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) continue;
|
||||
|
||||
var buttons = player.Buttons;
|
||||
bool isAttack2 = (buttons & PlayerButtons.Attack2) != 0;
|
||||
|
||||
if (skillInfo.CanUse && isAttack2)
|
||||
{
|
||||
var weapon = playerPawn.WeaponServices?.ActiveWeapon?.Value;
|
||||
|
||||
if (weapon == null || !weapon.IsValid) continue;
|
||||
if (!allowedWeapons.Contains(SkillUtils.GetDesignerName(weapon))) continue;
|
||||
|
||||
skillInfo.CanUse = false;
|
||||
skillInfo.Cooldown = DateTime.Now;
|
||||
SpawnExplosion(player);
|
||||
}
|
||||
|
||||
UpdateHUD(player, skillInfo, cooldown);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo, float cooldownSkill)
|
||||
{
|
||||
float cooldown = 0;
|
||||
if (skillInfo != null)
|
||||
{
|
||||
float time = (int)Math.Ceiling((skillInfo.Cooldown.AddSeconds(cooldownSkill) - DateTime.Now).TotalSeconds);
|
||||
cooldown = Math.Max(time, 0);
|
||||
|
||||
if (cooldown == 0 && skillInfo?.CanUse == false)
|
||||
skillInfo.CanUse = true;
|
||||
}
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null) return;
|
||||
|
||||
if (cooldown == 0)
|
||||
playerInfo.PrintHTML = null;
|
||||
else
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
|
||||
}
|
||||
|
||||
private static void SpawnExplosion(CCSPlayerController player)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
|
||||
|
||||
float force = SkillsInfo.GetValue<float>(skillName, "force");
|
||||
|
||||
Vector pos = new(pawn.AbsOrigin.X, pawn.AbsOrigin.Y, pawn.AbsOrigin.Z + pawn.ViewOffset.Z);
|
||||
Vector vel = SkillUtils.GetForwardVector(pawn.EyeAngles) * force;
|
||||
|
||||
SkillUtils.CreateHEGrenadeProjectile(pos, angle, vel, player.TeamNum);
|
||||
nades.AddOrUpdate(Server.TickCount, (player.TeamNum, player.Index), (_, _) => (player.TeamNum, player.Index));
|
||||
}
|
||||
|
||||
public static void OnEntitySpawned(CEntityInstance entity)
|
||||
{
|
||||
if (entity.DesignerName != "hegrenade_projectile") return;
|
||||
|
||||
var heProjectile = entity.As<CBaseCSGrenadeProjectile>();
|
||||
if (heProjectile == null || !heProjectile.IsValid || heProjectile.AbsRotation == null) return;
|
||||
|
||||
int lastTick = Server.TickCount;
|
||||
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
if (heProjectile == null || !heProjectile.IsValid) return;
|
||||
if (!(NearlyEquals(angle.X, heProjectile.AbsRotation.X) && NearlyEquals(angle.Y, heProjectile.AbsRotation.Y) && NearlyEquals(angle.Z, heProjectile.AbsRotation.Z)))
|
||||
return;
|
||||
|
||||
heProjectile.TicksAtZeroVelocity = 100;
|
||||
heProjectile.Damage = SkillsInfo.GetValue<int>(skillName, "explosionDamage");
|
||||
heProjectile.DmgRadius = SkillsInfo.GetValue<float>(skillName, "explosionRadius");
|
||||
|
||||
if (nades.TryRemove(lastTick, out var source))
|
||||
heProjectile.Globalname = $"deathbomb_team_{source.Team}_{source.Owner}_{heProjectile.Index}";
|
||||
});
|
||||
}
|
||||
|
||||
public static void OnTakeDamage(DynamicHook h)
|
||||
{
|
||||
CEntityInstance param = h.GetParam<CEntityInstance>(0);
|
||||
CTakeDamageInfo param2 = h.GetParam<CTakeDamageInfo>(1);
|
||||
|
||||
if (param == null || param.Entity == null || param2 == null) return;
|
||||
|
||||
var nade = param2.Attacker.Value;
|
||||
if (nade == null || !nade.IsValid) return;
|
||||
|
||||
if (nade.DesignerName != "hegrenade_projectile") return;
|
||||
if (string.IsNullOrEmpty(nade.Globalname) || !nade.Globalname.StartsWith("deathbomb_team_")) return;
|
||||
|
||||
var parts = nade.Globalname.Split('_');
|
||||
if (parts.Length < 4) return;
|
||||
if (!int.TryParse(parts[2], out int nadeTeam)) return;
|
||||
if (!uint.TryParse(parts[3], out uint ownerIndex)) return;
|
||||
|
||||
CCSPlayerPawn victimPawn = new(param.Handle);
|
||||
|
||||
if (victimPawn.DesignerName != "player") return;
|
||||
if (victimPawn.Controller?.Value == null) return;
|
||||
|
||||
var victim = victimPawn.Controller.Value.As<CCSPlayerController>();
|
||||
if (victim == null || !victim.IsValid || victim.Index == ownerIndex) return;
|
||||
|
||||
var owner = Utilities.GetPlayerFromIndex((int)ownerIndex);
|
||||
if (owner != null && !owner.IsValid) owner = null;
|
||||
|
||||
if (victimPawn.TeamNum == nadeTeam)
|
||||
{
|
||||
float reduction = SkillsInfo.GetValue<float>(skillName, "dmgReductionForTeamates");
|
||||
param2.Damage *= 1f - Math.Clamp(reduction, 0f, 1f);
|
||||
|
||||
if (IsFriendlyFireOff())
|
||||
{
|
||||
int teamDamage = (int)param2.Damage;
|
||||
param2.Damage = 0;
|
||||
|
||||
if (teamDamage > 0)
|
||||
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, KillfeedIcons.Explosion);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (owner != null && param2.Damage >= victimPawn.Health)
|
||||
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, KillfeedIcons.Explosion);
|
||||
}
|
||||
|
||||
private static bool IsFriendlyFireOff()
|
||||
{
|
||||
bool ff = ConVar.Find("mp_friendlyfire")?.GetPrimitiveValue<bool>() ?? false;
|
||||
bool tae = ConVar.Find("mp_teammates_are_enemies")?.GetPrimitiveValue<bool>() ?? false;
|
||||
return !ff && !tae;
|
||||
}
|
||||
|
||||
private static bool NearlyEquals(float a, float b, float epsilon = 0.001f) => Math.Abs(a - b) < epsilon;
|
||||
|
||||
public class PlayerSkillInfo
|
||||
{
|
||||
public ulong SteamID { get; set; }
|
||||
public bool CanUse { get; set; }
|
||||
public DateTime Cooldown { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#7740c9", 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 = 400.0f, int explosionDamage = 60, float dmgReductionForTeamates = 0.5f, float cooldown = 10f, float force = 1000f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float ExplosionRadius { get; set; } = explosionRadius;
|
||||
public int ExplosionDamage { get; set; } = explosionDamage;
|
||||
public float DmgReductionForTeamates { get; set; } = dmgReductionForTeamates;
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public float Force { get; set; } = force;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using static src.jRandomSkills;
|
||||
|
|
@ -154,7 +155,7 @@ namespace src.player.skills
|
|||
{
|
||||
eventPlayer.ExecuteClientCommand($"play player/player_damagebody_0{Instance.Random.Next(4, 8)}");
|
||||
|
||||
SkillUtils.TakeHealth(playerPawn, SkillsInfo.GetValue<int>(skillName, "damageAfterMiss"), GetSkillOwner(playerIndex), "planted_c4");
|
||||
SkillUtils.TakeHealth(playerPawn, SkillsInfo.GetValue<int>(skillName, "damageAfterMiss"), GetSkillOwner(playerIndex), KillfeedIcons.Fist);
|
||||
}
|
||||
lastShot.TryRemove(playerIndex, out _);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core;
|
|||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
|
@ -132,14 +133,14 @@ namespace src.player.skills
|
|||
param2.Damage = 0;
|
||||
|
||||
if (teamDamage > 0)
|
||||
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, "hegrenade");
|
||||
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, KillfeedIcons.Explosion);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (owner != null && param2.Damage >= victimPawn.Health)
|
||||
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, "hegrenade");
|
||||
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, KillfeedIcons.Explosion);
|
||||
}
|
||||
|
||||
private static bool IsFriendlyFireOff()
|
||||
|
|
|
|||
80
jRandomSkills - SRC Files/src/player/skills/DemonEye.cs
Normal file
80
jRandomSkills - SRC Files/src/player/skills/DemonEye.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using static src.jRandomSkills;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class DemonEye : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.DemonEye;
|
||||
private static readonly Skills[] hidingSkills = [Skills.Ghost, Skills.Ninja, Skills.C4Camouflage];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
int tickCooldown = (int)(64 * SkillsInfo.GetValue<float>(skillName, "SecondCooldown"));
|
||||
if (Server.TickCount % tickCooldown != 0) return;
|
||||
|
||||
int damage = SkillsInfo.GetValue<int>(skillName, "damage");
|
||||
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
var playerEvent = PlayerManager.GetPlayerEvent(player);
|
||||
if (!Instance.IsPlayerValid(playerEvent)) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(playerEvent!.Index);
|
||||
if (playerInfo?.Skill == skillName)
|
||||
HitEnemies(playerEvent, damage);
|
||||
}
|
||||
}
|
||||
|
||||
private static void HitEnemies(CCSPlayerController player, int damage)
|
||||
{
|
||||
if (player == null || !player.IsValid || player.PlayerPawn?.Value == null) return;
|
||||
|
||||
int playerSlot = player.Slot;
|
||||
int playerBit = playerSlot % 32;
|
||||
|
||||
if (playerSlot < 0)
|
||||
return;
|
||||
|
||||
foreach (var enemy in PlayerManager.GetTickPlayers().FindAll(p => p != null && p.IsValid && p.Team != player.Team))
|
||||
{
|
||||
var enemyEvent = PlayerManager.GetPlayerEvent(enemy);
|
||||
if (enemyEvent == null || !enemyEvent.IsValid) continue;
|
||||
|
||||
var enemyPawn = enemyEvent.PlayerPawn?.Value;
|
||||
if (enemyPawn == null || !enemyPawn.IsValid || enemyPawn.Health <= 0) continue;
|
||||
|
||||
int enemySlot = enemy.Slot;
|
||||
if (enemySlot < 0)
|
||||
return;
|
||||
|
||||
int enemyBit = enemySlot % 32;
|
||||
uint playerMask = 1u << playerBit;
|
||||
uint enemyMask = 1u << enemyBit;
|
||||
|
||||
bool playerSeesEnemy = (enemyPawn.EntitySpottedState.SpottedByMask[0] & playerMask) != 0;
|
||||
|
||||
if (playerSeesEnemy)
|
||||
{
|
||||
SkillUtils.TakeHealth(enemyPawn, damage, player, KillfeedIcons.Fist);
|
||||
enemyEvent.EmitSound("Player.DamageBody.Onlooker");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 float SecondCooldown { get; set; } = secondCooldown;
|
||||
public int Damage { get; set; } = damage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core;
|
|||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
|
@ -238,14 +239,14 @@ namespace src.player.skills
|
|||
param2.Damage = 0;
|
||||
|
||||
if (teamDamage > 0)
|
||||
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, "planted_c4");
|
||||
SkillUtils.TakeHealth(victimPawn, teamDamage, owner, KillfeedIcons.Explosion);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (owner != null && param2.Damage >= victimPawn.Health)
|
||||
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, "planted_c4");
|
||||
SkillUtils.RegisterKillCredit(victim.Index, owner.Index, KillfeedIcons.Explosion);
|
||||
}
|
||||
|
||||
private static bool IsFriendlyFireOff()
|
||||
|
|
|
|||
144
jRandomSkills - SRC Files/src/player/skills/FireRain.cs
Normal file
144
jRandomSkills - SRC Files/src/player/skills/FireRain.cs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
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 FireRain : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.FireRain;
|
||||
private static readonly QAngle angle = new(10, -4, 13);
|
||||
private static readonly ConcurrentDictionary<uint, byte> decoys = [];
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
KillAllDecoys();
|
||||
}
|
||||
|
||||
private static void KillAllDecoys()
|
||||
{
|
||||
foreach (var decoyIndex in decoys.Keys.ToArray())
|
||||
{
|
||||
var decoy = Utilities.GetEntityFromIndex<CDecoyProjectile>((int)decoyIndex);
|
||||
if (decoy != null && decoy.IsValid && decoy.DesignerName == "decoy_projectile")
|
||||
decoy.AddEntityIOEvent("Kill", decoy, delay: 0.1f);
|
||||
}
|
||||
|
||||
decoys.Clear();
|
||||
}
|
||||
|
||||
private static void SpawnRain(CCSPlayerController player, Vector targetPos)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null)
|
||||
return;
|
||||
|
||||
const int grenadeCount = 5;
|
||||
const float spawnHeight = 800.0f;
|
||||
const float approachDistance = 600.0f;
|
||||
const float clusterRadius = 130.0f;
|
||||
const float flightTime = 0.65f;
|
||||
const float gravity = 800.0f;
|
||||
|
||||
float approachAngle = Random.Shared.NextSingle() * MathF.Tau;
|
||||
float dirX = MathF.Cos(approachAngle);
|
||||
float dirY = MathF.Sin(approachAngle);
|
||||
|
||||
Vector skyCenter = new(
|
||||
targetPos.X + dirX * approachDistance,
|
||||
targetPos.Y + dirY * approachDistance,
|
||||
targetPos.Z + spawnHeight
|
||||
);
|
||||
|
||||
float dx = targetPos.X - skyCenter.X;
|
||||
float dy = targetPos.Y - skyCenter.Y;
|
||||
float dz = targetPos.Z - skyCenter.Z;
|
||||
|
||||
float vx = dx / flightTime;
|
||||
float vy = dy / flightTime;
|
||||
float vz = (dz + 0.5f * gravity * flightTime * flightTime) / flightTime;
|
||||
|
||||
Vector velocity = new(vx, vy, vz);
|
||||
|
||||
float yaw = MathF.Atan2(vy, vx) * (180.0f / MathF.PI);
|
||||
float horizontalSpeed = MathF.Sqrt(vx * vx + vy * vy);
|
||||
float pitch = -MathF.Atan2(vz, horizontalSpeed) * (180.0f / MathF.PI);
|
||||
QAngle launchAngle = new(pitch, yaw, 0.0f);
|
||||
|
||||
for (int i = 0; i < grenadeCount; i++)
|
||||
{
|
||||
float offsetAngle = Random.Shared.NextSingle() * MathF.Tau;
|
||||
float offsetDist = MathF.Sqrt(Random.Shared.NextSingle()) * clusterRadius;
|
||||
|
||||
float offsetX = MathF.Cos(offsetAngle) * offsetDist;
|
||||
float offsetY = MathF.Sin(offsetAngle) * offsetDist;
|
||||
|
||||
Vector spawnPos = new(
|
||||
skyCenter.X + offsetX,
|
||||
skyCenter.Y + offsetY,
|
||||
skyCenter.Z
|
||||
);
|
||||
|
||||
SkillUtils.CreateMolotovProjectile(spawnPos, launchAngle, velocity, player.TeamNum);
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnEntitySpawned(CEntityInstance entity)
|
||||
{
|
||||
var name = entity.DesignerName;
|
||||
if (name != "decoy_projectile")
|
||||
return;
|
||||
|
||||
var decoy = entity.As<CDecoyProjectile>();
|
||||
if (decoy == null || !decoy.IsValid || decoy.OwnerEntity == null || decoy.OwnerEntity.Value == null || !decoy.OwnerEntity.Value.IsValid) return;
|
||||
|
||||
var pawn = decoy.OwnerEntity.Value.As<CCSPlayerPawn>();
|
||||
if (pawn == null || !pawn.IsValid || pawn.Controller == null || pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
|
||||
|
||||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
decoys.TryAdd(decoy.Index, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
uint key = (uint)@event.Entityid;
|
||||
if (decoys.ContainsKey(key))
|
||||
{
|
||||
var decoy = Utilities.GetEntityFromIndex<CDecoyProjectile>(@event.Entityid);
|
||||
if (decoy != null && decoy.IsValid)
|
||||
decoy.AddEntityIOEvent("Kill", decoy, delay: 0.1f);
|
||||
decoys.TryRemove(key, out _);
|
||||
SpawnRain(player, new Vector(@event.X, @event.Y, @event.Z));
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
466
jRandomSkills - SRC Files/src/player/skills/Flashlight.cs
Normal file
466
jRandomSkills - SRC Files/src/player/skills/Flashlight.cs
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
// https://github.com/creazy231/cs2-css-flashlight
|
||||
|
||||
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 Flashlight : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.Flashlight;
|
||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||
|
||||
public class PlayerSkillInfo
|
||||
{
|
||||
public ulong SteamID { get; set; }
|
||||
public bool CanUse { get; set; }
|
||||
public DateTime Cooldown { get; set; }
|
||||
public uint LightEntityIndex { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
ClearAllEntities();
|
||||
SkillPlayerInfo.Clear();
|
||||
}
|
||||
|
||||
public static void RoundEnd()
|
||||
{
|
||||
ClearAllEntities();
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (player == null || !player.IsValid)
|
||||
continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
|
||||
if (playerInfo?.Skill != skillName)
|
||||
continue;
|
||||
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
|
||||
continue;
|
||||
|
||||
UpdateHUD(player, skillInfo);
|
||||
|
||||
if (!skillInfo.IsActive || skillInfo.LightEntityIndex == 0)
|
||||
continue;
|
||||
|
||||
var lightEntity = Utilities.GetEntityFromIndex<CBarnLight>((int)skillInfo.LightEntityIndex);
|
||||
|
||||
if (lightEntity == null || !lightEntity.IsValid)
|
||||
{
|
||||
skillInfo.IsActive = false;
|
||||
skillInfo.LightEntityIndex = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
UpdateLightPosition(player, lightEntity);
|
||||
|
||||
if (Server.TickCount % 32 != 0) continue;
|
||||
CanBlind(player, lightEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid)
|
||||
return;
|
||||
|
||||
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
|
||||
{
|
||||
SteamID = player.Index,
|
||||
CanUse = true,
|
||||
Cooldown = DateTime.MinValue,
|
||||
LightEntityIndex = 0,
|
||||
IsActive = false
|
||||
});
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
RemovePlayerLight(player.Index);
|
||||
SkillPlayerInfo.TryRemove(player.Index, out _);
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (victim != null && victim.IsValid)
|
||||
RemovePlayerLight(victim.Index);
|
||||
}
|
||||
|
||||
public static void UseSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid)
|
||||
return;
|
||||
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0)
|
||||
return;
|
||||
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
|
||||
return;
|
||||
|
||||
if (!skillInfo.CanUse)
|
||||
return;
|
||||
|
||||
skillInfo.CanUse = false;
|
||||
skillInfo.Cooldown = DateTime.Now;
|
||||
|
||||
CBarnLight? lightEntity = null;
|
||||
if (skillInfo.LightEntityIndex != 0)
|
||||
lightEntity = Utilities.GetEntityFromIndex<CBarnLight>((int)skillInfo.LightEntityIndex);
|
||||
|
||||
if (lightEntity == null || !lightEntity.IsValid)
|
||||
CreatePlayerFlashlight(player, skillInfo);
|
||||
else
|
||||
{
|
||||
skillInfo.IsActive = !skillInfo.IsActive;
|
||||
lightEntity.Enabled = skillInfo.IsActive;
|
||||
|
||||
if (skillInfo.IsActive)
|
||||
{
|
||||
lightEntity.AcceptInput("TurnOn");
|
||||
UpdateLightPosition(player, lightEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightEntity.AcceptInput("TurnOff");
|
||||
lightEntity.Teleport(new Vector(0, 0, -1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreatePlayerFlashlight(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
|
||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null)
|
||||
return;
|
||||
|
||||
RemovePlayerLight(player.Index);
|
||||
|
||||
if (EntityManager.OverBudget())
|
||||
return;
|
||||
|
||||
var light = Utilities.CreateEntityByName<CBarnLight>("light_barn");
|
||||
|
||||
if (light == null || !light.IsValid)
|
||||
return;
|
||||
|
||||
EntityManager.RegisterEntity(light.Index, player.Index, "light_barn");
|
||||
|
||||
int colorR = SkillsInfo.GetValue<int>(skillName, "colorR");
|
||||
int colorG = SkillsInfo.GetValue<int>(skillName, "colorG");
|
||||
int colorB = SkillsInfo.GetValue<int>(skillName, "colorB");
|
||||
float brightness = SkillsInfo.GetValue<float>(skillName, "brightness");
|
||||
float range = SkillsInfo.GetValue<float>(skillName, "range");
|
||||
|
||||
light.Enabled = true;
|
||||
light.Color = Color.FromArgb(255, Math.Clamp(colorR, 0, 255), Math.Clamp(colorG, 0, 255), Math.Clamp(colorB, 0, 255));
|
||||
light.ColorTemperature = 6500;
|
||||
light.Brightness = brightness;
|
||||
light.Range = range;
|
||||
light.SoftX = 1f;
|
||||
light.SoftY = 1f;
|
||||
light.Skirt = 0.5f;
|
||||
light.SkirtNear = 1.0f;
|
||||
light.CastShadows = 0;
|
||||
light.DirectLight = 3;
|
||||
light.SizeParams.X = 45;
|
||||
light.SizeParams.Y = 45;
|
||||
light.SizeParams.Z = 0.03f;
|
||||
|
||||
using (var keyValues = new CEntityKeyValues())
|
||||
{
|
||||
light.DispatchSpawn(keyValues);
|
||||
}
|
||||
|
||||
light.AcceptInput("TurnOn");
|
||||
|
||||
skillInfo.LightEntityIndex = light.Index;
|
||||
skillInfo.IsActive = true;
|
||||
|
||||
UpdateLightPosition(player, light);
|
||||
}
|
||||
|
||||
private static void UpdateLightPosition(CCSPlayerController player, CBarnLight light)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null || pawn.V_angle == null)
|
||||
return;
|
||||
|
||||
Vector eyePos = new(
|
||||
pawn.AbsOrigin.X,
|
||||
pawn.AbsOrigin.Y,
|
||||
pawn.AbsOrigin.Z + pawn.ViewOffset.Z
|
||||
);
|
||||
|
||||
Vector forward = SkillUtils.GetForwardVector(pawn.V_angle);
|
||||
|
||||
const float distance = 18.0f;
|
||||
|
||||
Vector lightPos = new(
|
||||
eyePos.X + forward.X * distance,
|
||||
eyePos.Y + forward.Y * distance,
|
||||
eyePos.Z + forward.Z * distance
|
||||
);
|
||||
|
||||
light.Teleport(lightPos, pawn.V_angle, null);
|
||||
}
|
||||
|
||||
private static void CanBlind(CCSPlayerController owner, CBarnLight light)
|
||||
{
|
||||
var ownerPawn = owner.PlayerPawn.Value;
|
||||
if (ownerPawn == null || !ownerPawn.IsValid || ownerPawn.AbsOrigin == null || ownerPawn.V_angle == null)
|
||||
return;
|
||||
|
||||
if (light == null || !light.IsValid || light.AbsOrigin == null)
|
||||
return;
|
||||
|
||||
float blindDuration = SkillsInfo.GetValue<float>(skillName, "blindDuration");
|
||||
float blindAlpha = SkillsInfo.GetValue<float>(skillName, "blindAlpha");
|
||||
|
||||
float blindAngle = SkillsInfo.GetValue<float>(skillName, "blindAngle");
|
||||
float range = SkillsInfo.GetValue<float>(skillName, "range");
|
||||
float rangeSq = range * range;
|
||||
|
||||
Vector eyePos = new(
|
||||
ownerPawn.AbsOrigin.X,
|
||||
ownerPawn.AbsOrigin.Y,
|
||||
ownerPawn.AbsOrigin.Z + ownerPawn.ViewOffset.Z
|
||||
);
|
||||
Vector ownerForward = SkillUtils.GetForwardVector(ownerPawn.V_angle);
|
||||
Vector lightPos = new(
|
||||
eyePos.X + ownerForward.X * 18.0f,
|
||||
eyePos.Y + ownerForward.Y * 18.0f,
|
||||
eyePos.Z + ownerForward.Z * 18.0f
|
||||
);
|
||||
|
||||
float minDot = MathF.Cos(blindAngle * MathF.PI / 180.0f);
|
||||
|
||||
foreach (var target in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (target == null || !target.IsValid || target.Index == owner.Index || target.Team == owner.Team)
|
||||
continue;
|
||||
|
||||
var targetInfo = PlayerManager.GetPlayerByIndex(target.Index);
|
||||
if (targetInfo != null && targetInfo.Skill == Skills.AntyFlash)
|
||||
continue;
|
||||
|
||||
var targetPawn = target.PlayerPawn.Value;
|
||||
|
||||
if (targetPawn == null || !targetPawn.IsValid || targetPawn.Health <= 0 || target.TeamNum == owner.TeamNum)
|
||||
continue;
|
||||
|
||||
bool targetBlinded = targetPawn.BlindUntilTime > Server.CurrentTime;
|
||||
bool ownerBlinded = ownerPawn.BlindUntilTime > Server.CurrentTime;
|
||||
var (playerSeesEnemy, enemySeesPlayer) = ArePlayersSpottedBothWays(owner, ownerPawn, target, targetPawn);
|
||||
|
||||
bool needPlayerSees = !ownerBlinded;
|
||||
bool needEnemySees = !targetBlinded;
|
||||
|
||||
if (ownerBlinded && targetBlinded)
|
||||
continue;
|
||||
|
||||
if (needPlayerSees && !playerSeesEnemy)
|
||||
continue;
|
||||
|
||||
if (needEnemySees && !enemySeesPlayer)
|
||||
continue;
|
||||
|
||||
Vector targetEyePos = new(
|
||||
targetPawn.AbsOrigin.X,
|
||||
targetPawn.AbsOrigin.Y,
|
||||
targetPawn.AbsOrigin.Z + targetPawn.ViewOffset.Z
|
||||
);
|
||||
|
||||
Vector toTarget = new(
|
||||
targetEyePos.X - lightPos.X,
|
||||
targetEyePos.Y - lightPos.Y,
|
||||
targetEyePos.Z - lightPos.Z
|
||||
);
|
||||
|
||||
float distanceSq = toTarget.X * toTarget.X + toTarget.Y * toTarget.Y + toTarget.Z * toTarget.Z;
|
||||
|
||||
if (distanceSq <= 0.0001f || distanceSq > rangeSq)
|
||||
continue;
|
||||
|
||||
float distance = MathF.Sqrt(distanceSq);
|
||||
float invLength = 1.0f / distance;
|
||||
|
||||
Vector directionToTarget = new(
|
||||
toTarget.X * invLength,
|
||||
toTarget.Y * invLength,
|
||||
toTarget.Z * invLength
|
||||
);
|
||||
|
||||
float sourceDot = ownerForward.X * directionToTarget.X +
|
||||
ownerForward.Y * directionToTarget.Y +
|
||||
ownerForward.Z * directionToTarget.Z;
|
||||
|
||||
if (sourceDot < minDot)
|
||||
continue;
|
||||
|
||||
Vector targetForward = SkillUtils.GetForwardVector(targetPawn.V_angle);
|
||||
|
||||
Vector fromTargetToLight = new(
|
||||
lightPos.X - targetEyePos.X,
|
||||
lightPos.Y - targetEyePos.Y,
|
||||
lightPos.Z - targetEyePos.Z
|
||||
);
|
||||
|
||||
float targetDistanceSq = fromTargetToLight.X * fromTargetToLight.X +
|
||||
fromTargetToLight.Y * fromTargetToLight.Y +
|
||||
fromTargetToLight.Z * fromTargetToLight.Z;
|
||||
|
||||
if (targetDistanceSq <= 0.0001f)
|
||||
continue;
|
||||
|
||||
float targetInvLength = 1.0f / MathF.Sqrt(targetDistanceSq);
|
||||
|
||||
fromTargetToLight.X *= targetInvLength;
|
||||
fromTargetToLight.Y *= targetInvLength;
|
||||
fromTargetToLight.Z *= targetInvLength;
|
||||
|
||||
float targetDot = targetForward.X * fromTargetToLight.X +
|
||||
targetForward.Y * fromTargetToLight.Y +
|
||||
targetForward.Z * fromTargetToLight.Z;
|
||||
|
||||
if (targetDot < minDot)
|
||||
continue;
|
||||
|
||||
BlindPlayers(targetPawn, blindDuration, blindAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
private static void BlindPlayers(CCSPlayerPawn pawn, float blindDuration, float blindAlpha)
|
||||
{
|
||||
var rng = jRandomSkills.Instance.Random;
|
||||
float now = Server.CurrentTime;
|
||||
|
||||
bool alreadyBlinded = pawn.BlindUntilTime > now;
|
||||
|
||||
if (!alreadyBlinded)
|
||||
pawn.BlindStartTime = now;
|
||||
|
||||
pawn.BlindUntilTime = now + blindDuration;
|
||||
|
||||
pawn.FlashDuration = blindDuration + (float)rng.NextDouble() * 0.05f;
|
||||
pawn.FlashMaxAlpha = blindAlpha + (float)rng.NextDouble() * 0.5f;
|
||||
|
||||
Utilities.SetStateChanged(pawn, "CCSPlayerPawnBase", "m_flFlashDuration");
|
||||
Utilities.SetStateChanged(pawn, "CCSPlayerPawnBase", "m_flFlashMaxAlpha");
|
||||
}
|
||||
|
||||
private static (bool, bool) ArePlayersSpottedBothWays(CCSPlayerController player, CCSPlayerPawn playerPawn, CCSPlayerController enemy, CCSPlayerPawn enemyPawn)
|
||||
{
|
||||
int playerSlot = player.Slot;
|
||||
int enemySlot = enemy.Slot;
|
||||
|
||||
if (playerSlot < 0 || enemySlot < 0)
|
||||
return (false, false);
|
||||
|
||||
int playerBit = playerSlot % 32;
|
||||
int enemyBit = enemySlot % 32;
|
||||
|
||||
uint playerMask = 1u << playerBit;
|
||||
uint enemyMask = 1u << enemyBit;
|
||||
|
||||
bool playerSeesEnemy = (enemyPawn.EntitySpottedState.SpottedByMask[0] & playerMask) != 0;
|
||||
bool enemySeesPlayer = (playerPawn.EntitySpottedState.SpottedByMask[0] & enemyMask) != 0;
|
||||
|
||||
return (playerSeesEnemy, enemySeesPlayer);
|
||||
}
|
||||
|
||||
private static void RemovePlayerLight(uint playerIndex)
|
||||
{
|
||||
if (SkillPlayerInfo.TryGetValue(playerIndex, out var info) && info.LightEntityIndex != 0)
|
||||
{
|
||||
EntityManager.DestroyEntity(info.LightEntityIndex);
|
||||
info.LightEntityIndex = 0;
|
||||
info.IsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
float cooldown = 0;
|
||||
|
||||
float time = (float)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "cooldown")) - DateTime.Now).TotalSeconds);
|
||||
cooldown = Math.Max(time, 0);
|
||||
|
||||
if (cooldown == 0 && !skillInfo.CanUse)
|
||||
skillInfo.CanUse = true;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
|
||||
if (playerInfo == null)
|
||||
return;
|
||||
|
||||
if (cooldown == 0)
|
||||
playerInfo.PrintHTML = null;
|
||||
else
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
|
||||
}
|
||||
|
||||
private static void ClearAllEntities()
|
||||
{
|
||||
foreach (var key in SkillPlayerInfo.Keys)
|
||||
RemovePlayerLight(key);
|
||||
}
|
||||
|
||||
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.Legendary,
|
||||
float cooldown = 2f,
|
||||
int colorR = 255,
|
||||
int colorG = 255,
|
||||
int colorB = 255,
|
||||
float brightness = 1.5f,
|
||||
float range = 1200.0f,
|
||||
float blindDuration = 5f,
|
||||
float blindAngle = 10.0f,
|
||||
float blindAlpha = 200
|
||||
) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public int ColorR { get; set; } = colorR;
|
||||
public int ColorG { get; set; } = colorG;
|
||||
public int ColorB { get; set; } = colorB;
|
||||
public float Brightness { get; set; } = brightness;
|
||||
public float Range { get; set; } = range;
|
||||
public float BlindDuration { get; set; } = blindDuration;
|
||||
public float BlindAlpha { get; set; } = blindAlpha;
|
||||
public float BlindAngle { get; set; } = blindAngle;
|
||||
}
|
||||
}
|
||||
}
|
||||
167
jRandomSkills - SRC Files/src/player/skills/HealingChicken.cs
Normal file
167
jRandomSkills - SRC Files/src/player/skills/HealingChicken.cs
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
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 HealingChicken : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.HealingChicken;
|
||||
|
||||
private class ChickenState
|
||||
{
|
||||
public CChicken? Chicken { get; set; }
|
||||
public Vector? LastOrigin { get; set; }
|
||||
public int TickCounter { get; set; }
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<uint, List<ChickenState>> activeChickens = new();
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
activeChickens.Clear();
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
SpawnChicken(player);
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (activeChickens.TryRemove(player.Index, out var chickens))
|
||||
foreach (var state in chickens)
|
||||
if (state.Chicken != null && state.Chicken.IsValid)
|
||||
state.Chicken.Remove();
|
||||
}
|
||||
|
||||
private static void SpawnChicken(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
|
||||
|
||||
int amount = SkillsInfo.GetValue<int>(skillName, "amount");
|
||||
var list = new List<ChickenState>();
|
||||
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
CChicken? chicken = EntityManager.CreateTrackedChicken(player.Index);
|
||||
if (chicken == null || !chicken.IsValid) continue;
|
||||
|
||||
chicken.Render = Color.LightGreen;
|
||||
|
||||
Vector offset = new(
|
||||
(float)(100 * Math.Cos(2 * Math.PI * i / amount)),
|
||||
(float)(100 * Math.Sin(2 * Math.PI * i / amount)),
|
||||
0
|
||||
);
|
||||
|
||||
chicken.Teleport(new Vector(pawn.AbsOrigin.X + offset.X, pawn.AbsOrigin.Y + offset.Y, pawn.AbsOrigin.Z + offset.Z));
|
||||
chicken.Leader.Raw = pawn.Index;
|
||||
|
||||
list.Add(new ChickenState { Chicken = chicken, LastOrigin = null, TickCounter = 0 });
|
||||
}
|
||||
|
||||
activeChickens[player.Index] = list;
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
int tickCooldown = SkillsInfo.GetValue<int>(skillName, "tickCooldown");
|
||||
if (Server.TickCount % tickCooldown == 0) return;
|
||||
|
||||
var players = PlayerManager.GetTickPlayers().ToArray();
|
||||
int healAmount = SkillsInfo.GetValue<int>(skillName, "heal");
|
||||
float healRadius = SkillsInfo.GetValue<float>(skillName, "healRadius");
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
if (playerInfo?.Skill != skillName) continue;
|
||||
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) continue;
|
||||
|
||||
if (!activeChickens.TryGetValue(player.Index, out var chickens)) continue;
|
||||
|
||||
for (int i = chickens.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var state = chickens[i];
|
||||
if (state.Chicken == null || !state.Chicken.IsValid || state.Chicken.AbsOrigin == null)
|
||||
{
|
||||
chickens.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
var chicken = state.Chicken;
|
||||
|
||||
if (chicken.Leader.Raw != player.Pawn.Raw)
|
||||
chicken.Leader.Raw = player.Pawn.Raw;
|
||||
|
||||
Vector currentOrigin = new(chicken.AbsOrigin.X, chicken.AbsOrigin.Y, chicken.AbsOrigin.Z);
|
||||
|
||||
if (state.LastOrigin != null)
|
||||
{
|
||||
float dx = currentOrigin.X - state.LastOrigin.X;
|
||||
float dy = currentOrigin.Y - state.LastOrigin.Y;
|
||||
float dist2D = MathF.Sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (dist2D > 0.05f && dist2D < 20.0f)
|
||||
{
|
||||
float boostFactor = 2.5f;
|
||||
Vector newPos = new(
|
||||
currentOrigin.X + (dx * boostFactor),
|
||||
currentOrigin.Y + (dy * boostFactor),
|
||||
currentOrigin.Z
|
||||
);
|
||||
|
||||
chicken.Teleport(newPos, chicken.AbsRotation, chicken.AbsVelocity);
|
||||
state.LastOrigin = newPos;
|
||||
}
|
||||
else
|
||||
state.LastOrigin = currentOrigin;
|
||||
}
|
||||
else
|
||||
state.LastOrigin = currentOrigin;
|
||||
|
||||
float pdx = pawn.AbsOrigin.X - state.LastOrigin.X;
|
||||
float pdy = pawn.AbsOrigin.Y - state.LastOrigin.Y;
|
||||
float pdz = pawn.AbsOrigin.Z - state.LastOrigin.Z;
|
||||
float distToPlayer = MathF.Sqrt(pdx * pdx + pdy * pdy + pdz * pdz);
|
||||
|
||||
if (distToPlayer <= healRadius)
|
||||
{
|
||||
state.TickCounter++;
|
||||
if (state.TickCounter >= tickCooldown)
|
||||
{
|
||||
SkillUtils.AddHealth(pawn, healAmount);
|
||||
state.TickCounter = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
state.TickCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#b5ab8f", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 1, Rarity rarity = Rarity.Legendary, int amount = 3, int heal = 2, int tickCooldown = 16, float healRadius = 150.0f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public int Amount { get; set; } = amount;
|
||||
public int Heal { get; set; } = heal;
|
||||
public int TickCooldown { get; set; } = tickCooldown;
|
||||
public float HealRadius { get; set; } = healRadius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Commands.Targeting;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
|
|
@ -39,7 +40,7 @@ namespace src.player.skills
|
|||
bool hasC4 = pawn.WeaponServices.MyWeapons.Any(w => w.Value?.DesignerName == "weapon_c4");
|
||||
if (!hasC4) continue;
|
||||
|
||||
SkillUtils.TakeHealth(pawn, damage, owner, "planted_c4");
|
||||
SkillUtils.TakeHealth(pawn, damage, owner, KillfeedIcons.C4);
|
||||
playerEvent?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core;
|
|||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
|
||||
|
|
@ -353,7 +354,10 @@ namespace src.player.skills
|
|||
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
if (playerPawn != null)
|
||||
SkillUtils.TakeHealth(playerPawn, (int)dealDamage, GetShooter(param2), param2.Ability?.Value?.DesignerName);
|
||||
{
|
||||
KillfeedIcons? killfeed = KillfeedIconsExtensions.FromWeaponName(param2.Ability?.Value?.DesignerName);
|
||||
SkillUtils.TakeHealth(playerPawn, (int)dealDamage, GetShooter(param2), killfeed ?? KillfeedIcons.Leg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using static src.jRandomSkills;
|
||||
using System.Collections.Concurrent;
|
||||
using src.utils;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using static src.jRandomSkills;
|
||||
using Timer = CounterStrikeSharp.API.Modules.Timers.Timer;
|
||||
|
||||
namespace src.player.skills
|
||||
|
|
@ -209,7 +210,7 @@ namespace src.player.skills
|
|||
var attackerTeam = attackerPawn.TeamNum;
|
||||
var replicaTeam = replica.Globalname.EndsWith("CT") ? 3 : 2;
|
||||
|
||||
SkillUtils.TakeHealth(attackerPawn, attackerTeam != replicaTeam ? SkillsInfo.GetValue<int>(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue<int>(skillName, "YourTeamDamage"), owner, "planted_c4");
|
||||
SkillUtils.TakeHealth(attackerPawn, attackerTeam != replicaTeam ? SkillsInfo.GetValue<int>(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue<int>(skillName, "YourTeamDamage"), owner, KillfeedIcons.Player);
|
||||
}
|
||||
|
||||
private static CCSPlayerController? GetReplicaOwner(uint replicaIndex)
|
||||
|
|
|
|||
166
jRandomSkills - SRC Files/src/player/skills/JetKick.cs
Normal file
166
jRandomSkills - SRC Files/src/player/skills/JetKick.cs
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class JetKick : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.JetKick;
|
||||
private static readonly ConcurrentDictionary<uint, byte> targetedPlayers = [];
|
||||
private static readonly ConcurrentDictionary<uint, uint> playersToTarget = [];
|
||||
private static readonly object setLock = new();
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
lock (setLock)
|
||||
{
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
DisableSkill(player);
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
targetedPlayers.Clear();
|
||||
playersToTarget.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
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 = PlayerManager.GetTickPlayers().Where(p => p != null && p.IsValid).Select(p => PlayerManager.GetPlayerEvent(p)).Where(p => p != null && p.IsValid && p.Team != player.Team && p.PlayerPawn?.Value != null && p.PlayerPawn.Value.IsValid && p.PlayerPawn.Value.Health > 0 && !p.IsHLTV && p.Team != CsTeam.Spectator && p.Team != CsTeam.None).ToArray();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
string enemyId = commands[0];
|
||||
|
||||
if (!uint.TryParse(enemyId, out uint enemyIndex))
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}" + playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index"));
|
||||
return;
|
||||
}
|
||||
|
||||
var enemy = Utilities.GetPlayerFromIndex((int)enemyIndex);
|
||||
|
||||
if (enemy == null)
|
||||
{
|
||||
playerEvent.PrintToChat($" {ChatColors.Red}" + playerEvent.GetTranslation("selectplayerskill_incorrect_enemy_index"));
|
||||
return;
|
||||
}
|
||||
|
||||
targetedPlayers.TryAdd(enemy.Index, 0);
|
||||
playersToTarget[player.Index] = enemy.Index;
|
||||
|
||||
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
||||
if (enemyEvent == null || !enemyEvent.IsValid) return;
|
||||
|
||||
playerInfo.SkillUsed = true;
|
||||
|
||||
playerEvent.PrintToChat($" {ChatColors.Green}" + playerEvent.GetTranslation("jetkick_player_info", enemy.PlayerName));
|
||||
enemyEvent.PrintToChat($" {ChatColors.Red}" + enemyEvent.GetTranslation("jetkick_enemy_info"));
|
||||
}
|
||||
|
||||
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 = PlayerManager.GetTickPlayers().Where(p => p != null && p.IsValid).Select(p => PlayerManager.GetPlayerEvent(p)).Where(p => p != null && p.IsValid && p.Team != player.Team && p.PlayerPawn?.Value != null && p.PlayerPawn.Value.IsValid && p.PlayerPawn.Value.Health > 0 && !p.IsHLTV && p.Team != CsTeam.Spectator && p.Team != CsTeam.None).ToArray();
|
||||
|
||||
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 (playersToTarget.TryRemove(player.Index, out uint targetIndex))
|
||||
{
|
||||
var target = PlayerManager.GetPlayerFromEvent(Utilities.GetPlayerFromIndex((int)targetIndex));
|
||||
if (target != null && target.IsValid)
|
||||
{
|
||||
if (target.PawnIsAlive && !SkillUtils.IsFreezeTime())
|
||||
target.PrintToChat($" {ChatColors.Green}" + target.GetTranslation("jetkick_disable_info"));
|
||||
}
|
||||
targetedPlayers.TryRemove(targetIndex, out _);
|
||||
}
|
||||
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
targetedPlayers.TryRemove(player.Index, out _);
|
||||
SkillUtils.CloseMenu(player);
|
||||
}
|
||||
|
||||
public static void WeaponFire(EventWeaponFire @event)
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
if (!targetedPlayers.ContainsKey(player.Index)) return;
|
||||
if (!SkillUtils.FiresBullets(@event.Weapon)) return;
|
||||
|
||||
PushPlayer(player);
|
||||
}
|
||||
|
||||
private static void PushPlayer(CCSPlayerController player)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0) return;
|
||||
|
||||
Vector newVelocity = -SkillUtils.GetForwardVector(playerPawn.V_angle) * SkillsInfo.GetValue<float>(skillName, "pushVelocity");
|
||||
playerPawn.Teleport(null, null, newVelocity);
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#5a4fd1", 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 pushVelocity = 400f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float PushVelocity { get; set; } = pushVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using CounterStrikeSharp.API.Core;
|
|||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using static src.jRandomSkills;
|
||||
|
|
@ -30,7 +31,7 @@ namespace src.player.skills
|
|||
if (!SkillsInfo.GetValue<bool>(skillName, "friendlyFire") && player!.Team == attacker!.Team) return;
|
||||
|
||||
if (attackerInfo?.Skill == skillName && playerInfo?.Skill != Skills.AntyFlash && player!.PlayerPawn.Value!.FlashDuration >= SkillsInfo.GetValue<float>(skillName, "flashDuration"))
|
||||
SkillUtils.TakeHealth(player.PlayerPawn.Value, 9999, attacker, "weapon_flashbang");
|
||||
SkillUtils.TakeHealth(player.PlayerPawn.Value, 9999, attacker, KillfeedIcons.Flashbang);
|
||||
}
|
||||
|
||||
public static void GrenadeThrown(EventGrenadeThrown @event)
|
||||
|
|
|
|||
58
jRandomSkills - SRC Files/src/player/skills/LastGasp.cs
Normal file
58
jRandomSkills - SRC Files/src/player/skills/LastGasp.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class LastGasp : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.LastGasp;
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void PlayerDeath(EventPlayerDeath @event)
|
||||
{
|
||||
var victim = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
var attacker = PlayerManager.GetPlayerEvent(@event.Attacker);
|
||||
|
||||
if (victim == null || !victim.IsValid || attacker == null || !attacker.IsValid)
|
||||
return;
|
||||
|
||||
var victimPawn = victim.PlayerPawn?.Value;
|
||||
var attackerPawn = attacker.PlayerPawn?.Value;
|
||||
|
||||
if (victimPawn == null || !victimPawn.IsValid || attackerPawn == null || !attackerPawn.IsValid)
|
||||
return;
|
||||
|
||||
var victimInfo = PlayerManager.GetPlayerByIndex(victim!.Index);
|
||||
if (victimInfo?.Skill != skillName)
|
||||
return;
|
||||
|
||||
int damageAfterDeath = SkillsInfo.GetValue<int>(skillName, "DamageAfterDeath");
|
||||
bool canKill = SkillsInfo.GetValue<bool>(skillName, "CanKill");
|
||||
|
||||
if (!canKill)
|
||||
{
|
||||
int newHealth = (int)(attackerPawn.Health - damageAfterDeath);
|
||||
if (newHealth <= 0)
|
||||
damageAfterDeath = damageAfterDeath - 1 + newHealth;
|
||||
|
||||
}
|
||||
|
||||
SkillUtils.TakeHealth(attackerPawn, damageAfterDeath, victim, KillfeedIcons.Fist);
|
||||
PlayerManager.GetPlayerFromEvent(attacker)?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");
|
||||
}
|
||||
|
||||
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 int DamageAfterDeath { get; set; } = damageAfterDeath;
|
||||
public bool CanKill { get; set; } = canKill;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using static src.jRandomSkills;
|
||||
|
|
@ -76,7 +77,8 @@ namespace src.player.skills
|
|||
var playerInfo = PlayerManager.GetPlayerByIndex(eventPlayer.Index);
|
||||
if (playerInfo == null || playerInfo.Skill != skillName) return HookResult.Continue;
|
||||
|
||||
KnifeHit(eventPlayer, true);
|
||||
KillfeedIcons? killfeedIcon = KillfeedIconsExtensions.FromWeapon(weapon);
|
||||
KnifeHit(eventPlayer, true, killfeedIcon);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
|
|
@ -94,10 +96,11 @@ namespace src.player.skills
|
|||
var activeWeapon = pawn.WeaponServices.ActiveWeapon.Value;
|
||||
if (activeWeapon == null || !activeWeapon.IsValid || (activeWeapon.DesignerName != "weapon_knife" && activeWeapon.DesignerName != "weapon_bayonet")) return;
|
||||
|
||||
KnifeHit(player, false);
|
||||
KillfeedIcons? killfeedIcon = KillfeedIconsExtensions.FromWeapon(activeWeapon);
|
||||
KnifeHit(player, false, killfeedIcon);
|
||||
}
|
||||
|
||||
private unsafe static void KnifeHit(CCSPlayerController player, bool heavyHit)
|
||||
private unsafe static void KnifeHit(CCSPlayerController player, bool heavyHit, KillfeedIcons? killfeedIcon)
|
||||
{
|
||||
var pawn = player!.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null)
|
||||
|
|
@ -119,7 +122,7 @@ namespace src.player.skills
|
|||
if (!SkillsInfo.GetValue<bool>(skillName, "friendlyFire") && player.Team == target.Team) return;
|
||||
|
||||
target.PlayerPawn.Value.EmitSound("Player.DamageBody.Onlooker");
|
||||
SkillUtils.TakeHealth(target.PlayerPawn.Value, heavyHit ? Instance.Random.Next(45, 55) : Instance.Random.Next(21, 34), player, "weapon_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)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using static src.jRandomSkills;
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ namespace src.player.skills
|
|||
if (target.Handle == player.Handle) return;
|
||||
if (!SkillsInfo.GetValue<bool>(skillName, "friendlyFire") && player.Team == target.Team) return;
|
||||
|
||||
SkillUtils.TakeHealth(target.PlayerPawn.Value, 9999, player, "weapon_taser");
|
||||
SkillUtils.TakeHealth(target.PlayerPawn.Value, 9999, player, KillfeedIcons.Taser);
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using System.Collections.Concurrent;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
|
|
@ -65,7 +66,7 @@ namespace src.player.skills
|
|||
|
||||
if (pawn.Health <= SkillsInfo.GetValue<int>(skillName, "MinHealth")) continue;
|
||||
|
||||
SkillUtils.TakeHealth(pawn, SkillsInfo.GetValue<int>(skillName, "Damage"), GetSkillOwner(playerIndex), "planted_c4");
|
||||
SkillUtils.TakeHealth(pawn, SkillsInfo.GetValue<int>(skillName, "Damage"), GetSkillOwner(playerIndex), KillfeedIcons.Spray);
|
||||
|
||||
if (Server.TickCount % cooldown2 == 0)
|
||||
PlayerManager.GetPlayerFromEvent(player)?.ExecuteClientCommand($"play player/player_damagebody_0{jRandomSkills.Instance.Random.Next(4, 8)}");
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ using CounterStrikeSharp.API;
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using static src.jRandomSkills;
|
||||
using System.Collections.Concurrent;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
|
|
@ -62,7 +61,7 @@ namespace src.player.skills
|
|||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (player == null || !player.IsValid) return;
|
||||
SkillPlayerInfo.TryRemove(player.Index, out _);
|
||||
EntityManager.DestroyPlayerEntities(player.Index);
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
|
|
@ -164,7 +163,7 @@ namespace src.player.skills
|
|||
var attackerTeam = attackerPawn.TeamNum;
|
||||
var replicaTeam = replica.Globalname.EndsWith("CT") ? 3 : 2;
|
||||
|
||||
SkillUtils.TakeHealth(attackerPawn, attackerTeam != replicaTeam ? SkillsInfo.GetValue<int>(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue<int>(skillName, "YourTeamDamage"), owner, "planted_c4");
|
||||
SkillUtils.TakeHealth(attackerPawn, attackerTeam != replicaTeam ? SkillsInfo.GetValue<int>(skillName, "EnemyTeamDamage") : SkillsInfo.GetValue<int>(skillName, "YourTeamDamage"), owner, KillfeedIcons.Player);
|
||||
}
|
||||
|
||||
private static CCSPlayerController? GetReplicaOwner(uint replicaIndex)
|
||||
|
|
|
|||
300
jRandomSkills - SRC Files/src/player/skills/TakeAmmo.cs
Normal file
300
jRandomSkills - SRC Files/src/player/skills/TakeAmmo.cs
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using static src.jRandomSkills;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class TakeAmmo : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.TakeAmmo;
|
||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||
private static readonly object setLock = new();
|
||||
private static readonly ConcurrentDictionary<string, (int, string)> OriginalWeaponMaxAmmo = new();
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
lock (setLock)
|
||||
{
|
||||
SkillPlayerInfo.Clear();
|
||||
}
|
||||
|
||||
foreach (var kvp in OriginalWeaponMaxAmmo)
|
||||
{
|
||||
var vdata = VirtualFunctions.GetCSWeaponDataFromKey(-1, kvp.Value.Item2);
|
||||
if (vdata != null)
|
||||
vdata.PrimaryReserveAmmoMax = kvp.Value.Item1;
|
||||
}
|
||||
OriginalWeaponMaxAmmo.Clear();
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
|
||||
{
|
||||
SteamID = player.Index,
|
||||
CanUse = true,
|
||||
Cooldown = DateTime.MinValue,
|
||||
LastClick = DateTime.MinValue,
|
||||
FindedEnemy = true,
|
||||
EnemyHaveAmmo = true,
|
||||
MaxWeaponAmmo = new ConcurrentDictionary<string, int>()
|
||||
});
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (SkillPlayerInfo.TryRemove(player.Index, out var _))
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
|
||||
var weaponServices = player.PlayerPawn?.Value?.WeaponServices;
|
||||
if (weaponServices == null) return;
|
||||
|
||||
foreach (var _weapon in weaponServices.MyWeapons.ToArray())
|
||||
{
|
||||
if (_weapon == null || !_weapon.IsValid) continue;
|
||||
|
||||
var weapon = _weapon?.Value;
|
||||
if (weapon == null || string.IsNullOrEmpty(weapon.DesignerName)) continue;
|
||||
|
||||
OriginalWeaponMaxAmmo.TryGetValue(weapon.DesignerName, out var items);
|
||||
|
||||
weapon.ReserveAmmo.Fill(items.Item1);
|
||||
Utilities.SetStateChanged(weapon, "CBasePlayerWeapon", "m_pReserveAmmo");
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
var players = PlayerManager.GetTickPlayers().ToArray();
|
||||
foreach (var player in players)
|
||||
{
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo?.Skill != skillName) continue;
|
||||
|
||||
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
|
||||
{
|
||||
bool recentClick = skillInfo.LastClick.AddSeconds(4) >= DateTime.Now;
|
||||
UpdateHUD(player, skillInfo, recentClick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo, bool showInfo)
|
||||
{
|
||||
float cooldown = 0;
|
||||
if (skillInfo != null)
|
||||
{
|
||||
float time = (int)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "cooldown")) - DateTime.Now).TotalSeconds);
|
||||
cooldown = Math.Max(time, 0);
|
||||
|
||||
if (cooldown == 0 && skillInfo?.CanUse == false)
|
||||
skillInfo.CanUse = true;
|
||||
}
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null) return;
|
||||
|
||||
if (cooldown == 0)
|
||||
{
|
||||
if (showInfo)
|
||||
playerInfo.PrintHTML =
|
||||
skillInfo != null && !skillInfo.FindedEnemy
|
||||
? $"<font color='#FF0000'>{player.GetTranslation("takeammo_hud_info1")}</font>"
|
||||
: skillInfo != null && !skillInfo.EnemyHaveAmmo ? $"<font color='#FF0000'>{player.GetTranslation("takeammo_hud_info2")}</font>" : null;
|
||||
else
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
return;
|
||||
}
|
||||
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
|
||||
}
|
||||
|
||||
public static void UseSkill(CCSPlayerController player)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn.Value;
|
||||
if (playerPawn?.CBodyComponent == null) return;
|
||||
|
||||
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
|
||||
{
|
||||
if (!player.IsValid || playerPawn.Health <= 0) return;
|
||||
if (skillInfo.CanUse)
|
||||
{
|
||||
CCSPlayerController? enemy = GetRandomEnemy(player);
|
||||
if (enemy == null)
|
||||
{
|
||||
skillInfo.FindedEnemy = false;
|
||||
skillInfo.LastClick = DateTime.Now;
|
||||
return;
|
||||
}
|
||||
|
||||
int playerMagazines = GetMagazinesCount(player);
|
||||
int enemyMagazines = GetMagazinesCount(enemy);
|
||||
|
||||
if (enemyMagazines == 0)
|
||||
{
|
||||
skillInfo.FindedEnemy = true;
|
||||
skillInfo.EnemyHaveAmmo = false;
|
||||
skillInfo.LastClick = DateTime.Now;
|
||||
return;
|
||||
}
|
||||
|
||||
skillInfo.EnemyHaveAmmo = true;
|
||||
skillInfo.FindedEnemy = true;
|
||||
skillInfo.CanUse = false;
|
||||
skillInfo.Cooldown = DateTime.Now;
|
||||
|
||||
Server.NextFrame(() =>
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
if (enemy == null || !enemy.IsValid) return;
|
||||
|
||||
SetMagazines(player, playerMagazines + enemyMagazines);
|
||||
SetMagazines(enemy, 0);
|
||||
|
||||
PlayerManager.GetPlayerFromEvent(enemy)?.ExecuteClientCommand($"play sounds/weapons/g3sg1/g3sg1_clipout");
|
||||
|
||||
var enemyEvent = PlayerManager.GetPlayerFromEvent(enemy);
|
||||
if (enemyEvent == null || !enemyEvent.IsValid) return;
|
||||
enemyEvent.PrintToChat($" {ChatColors.Red}" + enemyEvent.GetTranslation("takeammo_enemy_info"));
|
||||
});
|
||||
}
|
||||
else
|
||||
skillInfo.LastClick = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetMagazinesCount(CCSPlayerController player)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.Health <= 0) return 0;
|
||||
|
||||
var ws = pawn.WeaponServices;
|
||||
if (ws == null) return 0;
|
||||
|
||||
var activeWeapon = ws.ActiveWeapon?.Value;
|
||||
if (activeWeapon == null || !activeWeapon.IsValid || activeWeapon.VData == null || string.IsNullOrEmpty(activeWeapon.DesignerName)) return 0;
|
||||
|
||||
if (activeWeapon.VData.PrimaryAmmoType == 7 && activeWeapon.ReserveAmmo.Length >= 1)
|
||||
return (int)(activeWeapon.ReserveAmmo[0] / activeWeapon.VData.MaxClip1);
|
||||
|
||||
int magazines = activeWeapon.VData.ReserveAmmoAsClips && activeWeapon.ReserveAmmo.Length >= 1 ? activeWeapon.ReserveAmmo[0] : 0;
|
||||
return magazines;
|
||||
}
|
||||
|
||||
private static void SetMagazines(CCSPlayerController player, int magazines)
|
||||
{
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.Health <= 0) return;
|
||||
|
||||
var ws = pawn.WeaponServices;
|
||||
if (ws == null) return;
|
||||
|
||||
var activeWeapon = ws.ActiveWeapon?.Value;
|
||||
if (activeWeapon == null || !activeWeapon.IsValid || activeWeapon.VData == null || string.IsNullOrEmpty(activeWeapon.DesignerName)) return;
|
||||
|
||||
if (activeWeapon.VData.PrimaryAmmoType == 7)
|
||||
magazines = (int)(magazines * activeWeapon.VData.MaxClip1);
|
||||
|
||||
activeWeapon.ReserveAmmo.Fill(magazines);
|
||||
Utilities.SetStateChanged(activeWeapon, "CBasePlayerWeapon", "m_pReserveAmmo");
|
||||
|
||||
string weaponName = activeWeapon.DesignerName;
|
||||
string weaponIndex = activeWeapon.AttributeManager.Item.ItemDefinitionIndex.ToString();
|
||||
|
||||
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
|
||||
{
|
||||
if (skillInfo.MaxWeaponAmmo.TryGetValue(weaponName, out int currentMax))
|
||||
skillInfo.MaxWeaponAmmo[weaponName] = Math.Max(currentMax, magazines);
|
||||
else
|
||||
skillInfo.MaxWeaponAmmo.TryAdd(weaponName, magazines);
|
||||
}
|
||||
|
||||
var vdata = VirtualFunctions.GetCSWeaponDataFromKey(-1, weaponIndex);
|
||||
if (vdata == null) return;
|
||||
|
||||
if (!OriginalWeaponMaxAmmo.ContainsKey(weaponName))
|
||||
OriginalWeaponMaxAmmo.TryAdd(weaponName, (vdata.PrimaryReserveAmmoMax, weaponIndex));
|
||||
|
||||
vdata.PrimaryReserveAmmoMax = Math.Max(vdata.PrimaryReserveAmmoMax, magazines);
|
||||
}
|
||||
|
||||
public static void WeaponEquip(EventItemEquip @event)
|
||||
{
|
||||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
string weaponName = @event.Item;
|
||||
if (string.IsNullOrEmpty(weaponName)) return;
|
||||
|
||||
if (OriginalWeaponMaxAmmo.TryGetValue("weapon_" + weaponName, out var items))
|
||||
{
|
||||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn == null) return;
|
||||
|
||||
var ws = pawn.WeaponServices;
|
||||
if (ws == null) return;
|
||||
|
||||
var activeWeapon = ws.ActiveWeapon?.Value;
|
||||
if (activeWeapon == null || !activeWeapon.IsValid || string.IsNullOrEmpty(activeWeapon.DesignerName)) return;
|
||||
|
||||
int ammoLimit = items.Item1;
|
||||
|
||||
if (SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo))
|
||||
{
|
||||
if (skillInfo.MaxWeaponAmmo.TryGetValue("weapon_" + weaponName, out int personalMax))
|
||||
ammoLimit = Math.Max(ammoLimit, personalMax);
|
||||
}
|
||||
|
||||
if (activeWeapon.ReserveAmmo.Length > 0 && activeWeapon.ReserveAmmo[0] > ammoLimit)
|
||||
{
|
||||
activeWeapon.ReserveAmmo.Fill(ammoLimit);
|
||||
Utilities.SetStateChanged(activeWeapon, "CBasePlayerWeapon", "m_pReserveAmmo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CCSPlayerController? GetRandomEnemy(CCSPlayerController player)
|
||||
{
|
||||
CCSPlayerController[] enemies = [.. PlayerManager.GetTickPlayers().FindAll(e =>
|
||||
e.Team != player.Team &&
|
||||
e.PlayerPawn?.Value?.Health > 0 &&
|
||||
e.PlayerPawn?.Value?.WeaponServices?.ActiveWeapon?.Value?.ReserveAmmo.Length > 0
|
||||
)];
|
||||
if (enemies.Length == 0) return null;
|
||||
return enemies[Instance.Random.Next(enemies.Length)];
|
||||
}
|
||||
|
||||
public class PlayerSkillInfo
|
||||
{
|
||||
public ulong SteamID { get; set; }
|
||||
public bool CanUse { get; set; }
|
||||
public DateTime Cooldown { get; set; }
|
||||
public DateTime LastClick { get; set; }
|
||||
public bool FindedEnemy { get; set; }
|
||||
public bool EnemyHaveAmmo { get; set; }
|
||||
public ConcurrentDictionary<string, int> MaxWeaponAmmo { get; set; } = new();
|
||||
}
|
||||
|
||||
public class WeaponInfo
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
public required int Clip1 { get; set; }
|
||||
public required int Clip2 { 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 float Cooldown { get; set; } = cooldown;
|
||||
}
|
||||
}
|
||||
}
|
||||
257
jRandomSkills - SRC Files/src/player/skills/TeamTeleport.cs
Normal file
257
jRandomSkills - SRC Files/src/player/skills/TeamTeleport.cs
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class TeamTeleport : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.TeamTeleport;
|
||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||
|
||||
public class PlayerSkillInfo
|
||||
{
|
||||
public ulong SteamID { get; set; }
|
||||
public bool CanUse { get; set; }
|
||||
public DateTime Cooldown { get; set; }
|
||||
public string? TeamateName { get; set; }
|
||||
public uint? TeamateIndex { get; set; }
|
||||
public Vector? TeamatePosition { get; set; }
|
||||
public int NoSpace { get; set; }
|
||||
public int NoEnemy { get; set; }
|
||||
}
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
SkillPlayerInfo.Clear();
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
if (playerInfo?.Skill != skillName) continue;
|
||||
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) continue;
|
||||
|
||||
GetTeamate(player, skillInfo);
|
||||
UpdateHUD(player, skillInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
|
||||
{
|
||||
SteamID = player.Index,
|
||||
CanUse = true,
|
||||
Cooldown = DateTime.MinValue,
|
||||
TeamateName = null,
|
||||
TeamateIndex = null,
|
||||
TeamatePosition = null,
|
||||
NoSpace = int.MinValue,
|
||||
NoEnemy = int.MinValue
|
||||
});
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null) return;
|
||||
SkillPlayerInfo.TryRemove(player.Index, out _);
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
}
|
||||
|
||||
public static void UseSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0) return;
|
||||
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) return;
|
||||
if (!skillInfo.CanUse) return;
|
||||
|
||||
skillInfo.NoEnemy = int.MinValue;
|
||||
skillInfo.NoSpace = int.MinValue;
|
||||
|
||||
if (skillInfo.TeamateIndex == null || skillInfo.TeamatePosition == null)
|
||||
{
|
||||
skillInfo.NoEnemy = Server.TickCount + (64 * 2);
|
||||
return;
|
||||
}
|
||||
|
||||
var victim = PlayerManager.GetTickPlayers().FirstOrDefault(p => p.Index == skillInfo.TeamateIndex.Value);
|
||||
if (victim == null || !victim.IsValid)
|
||||
{
|
||||
skillInfo.NoEnemy = Server.TickCount + (64 * 2);
|
||||
return;
|
||||
}
|
||||
|
||||
TeleportToTeamate(player, victim, skillInfo.TeamatePosition, skillInfo);
|
||||
}
|
||||
|
||||
private static void GetTeamate(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null || playerPawn.V_angle == null || playerPawn.ViewOffset == null)
|
||||
return;
|
||||
|
||||
Vector eyePos = new(playerPawn.AbsOrigin.X, playerPawn.AbsOrigin.Y, playerPawn.AbsOrigin.Z + playerPawn.ViewOffset.Z);
|
||||
Vector playerForward = SkillUtils.GetForwardVector(playerPawn.V_angle);
|
||||
|
||||
float teleportAngle = SkillsInfo.GetValue<float>(skillName, "teleportAngle");
|
||||
float minDot = MathF.Cos(teleportAngle * MathF.PI / 180.0f);
|
||||
|
||||
skillInfo.TeamateIndex = null;
|
||||
skillInfo.TeamateName = null;
|
||||
skillInfo.TeamatePosition = null;
|
||||
|
||||
foreach (var teammate in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (teammate == null || !teammate.IsValid || teammate.Index == player.Index || teammate.Team != player.Team)
|
||||
continue;
|
||||
|
||||
var teammatePawn = teammate.PlayerPawn?.Value;
|
||||
if (teammatePawn == null || !teammatePawn.IsValid || teammatePawn.Health <= 0 || teammatePawn.AbsOrigin == null)
|
||||
continue;
|
||||
|
||||
Vector targetPos = new(teammatePawn.AbsOrigin.X, teammatePawn.AbsOrigin.Y, teammatePawn.AbsOrigin.Z + (teammatePawn.ViewOffset.Z * 0.5f));
|
||||
Vector toTarget = new(targetPos.X - eyePos.X, targetPos.Y - eyePos.Y, targetPos.Z - eyePos.Z);
|
||||
|
||||
float distanceSq = toTarget.X * toTarget.X + toTarget.Y * toTarget.Y + toTarget.Z * toTarget.Z;
|
||||
if (distanceSq <= 0.0001f)
|
||||
continue;
|
||||
|
||||
float distance = MathF.Sqrt(distanceSq);
|
||||
|
||||
float invLength = 1.0f / distance;
|
||||
|
||||
toTarget.X *= invLength;
|
||||
toTarget.Y *= invLength;
|
||||
toTarget.Z *= invLength;
|
||||
|
||||
float dot = playerForward.X * toTarget.X + playerForward.Y * toTarget.Y + playerForward.Z * toTarget.Z;
|
||||
|
||||
if (distance > 30.0f && dot < minDot)
|
||||
continue;
|
||||
|
||||
skillInfo.TeamateIndex = teammate.Index;
|
||||
skillInfo.TeamateName = teammate.PlayerName;
|
||||
skillInfo.TeamatePosition = new Vector(teammatePawn.AbsOrigin.X, teammatePawn.AbsOrigin.Y, teammatePawn.AbsOrigin.Z);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe static bool CheckTeleport(CCSPlayerController attacker, CCSPlayerController victim, Vector startPos, Vector endPos, QAngle angle)
|
||||
{
|
||||
var attackerPawn = attacker.PlayerPawn.Value;
|
||||
if (attackerPawn == null || !attackerPawn.IsValid) return false;
|
||||
|
||||
var victimPawn = victim.PlayerPawn.Value;
|
||||
if (victimPawn == null || !victimPawn.IsValid) return false;
|
||||
|
||||
var result = RayTrace.TraceHullShape(
|
||||
startPos,
|
||||
endPos,
|
||||
victim,
|
||||
attackerPawn.Collision.Mins,
|
||||
attackerPawn.Collision.Maxs,
|
||||
null,
|
||||
null,
|
||||
angle
|
||||
);
|
||||
|
||||
if (!result.HasValue)
|
||||
return false;
|
||||
|
||||
return !result.Value.DidHit;
|
||||
}
|
||||
|
||||
private static void TeleportToTeamate(CCSPlayerController player, CCSPlayerController victim, Vector position, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || player.AbsRotation == null) return;
|
||||
|
||||
QAngle playerAngles = new(player.AbsRotation.X, player.AbsRotation.Y, player.AbsRotation.Z);
|
||||
float distance = SkillsInfo.GetValue<float>(skillName, "teleportDistance");
|
||||
|
||||
int[] angles = [0, 90, -90, 179];
|
||||
bool teleported = false;
|
||||
|
||||
foreach (int extraAngle in angles)
|
||||
{
|
||||
QAngle targetAngle = new(0, playerAngles.Y + extraAngle, 0);
|
||||
Vector direction = SkillUtils.GetForwardVector(targetAngle);
|
||||
|
||||
Vector targetPos = position - (direction * distance);
|
||||
Vector traceStart = position - (direction * 20f);
|
||||
|
||||
if (CheckTeleport(player, victim, traceStart, targetPos, targetAngle))
|
||||
{
|
||||
playerPawn.Teleport(targetPos, targetAngle, Vector.Zero);
|
||||
teleported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!teleported)
|
||||
skillInfo.NoSpace = Server.TickCount + (64 * 2);
|
||||
else
|
||||
{
|
||||
skillInfo.NoSpace = int.MinValue;
|
||||
skillInfo.NoEnemy = int.MinValue;
|
||||
skillInfo.CanUse = false;
|
||||
skillInfo.Cooldown = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
float cooldown = 0;
|
||||
|
||||
float time = (float)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "cooldown")) - DateTime.Now).TotalSeconds);
|
||||
cooldown = Math.Max(time, 0);
|
||||
|
||||
if (cooldown == 0 && !skillInfo.CanUse)
|
||||
skillInfo.CanUse = true;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
if (playerInfo == null) return;
|
||||
|
||||
if (cooldown != 0)
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
|
||||
else if (skillInfo.NoSpace >= Server.TickCount)
|
||||
playerInfo.PrintHTML = $"<font color='#FF0000'>{player.GetTranslation("shade_nospace")}</font>";
|
||||
else if (skillInfo.NoEnemy >= Server.TickCount)
|
||||
playerInfo.PrintHTML = $"<font color='#FF0000'>{player.GetTranslation("teamteleport_noenemy")}</font>";
|
||||
else
|
||||
{
|
||||
if (skillInfo.TeamateName == null)
|
||||
playerInfo.PrintHTML = null;
|
||||
else
|
||||
{
|
||||
string color = player.Team == CsTeam.Terrorist ? "#FFA500" : "#ADD8E6";
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("teamteleport_hud_info", $"<font color='{color}'>{System.Net.WebUtility.HtmlEncode(skillInfo.TeamateName)}</font>")}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#bcf542", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = true, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = 15f, float teleportAngle = 10.0f, float teleportDistance = 100f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public float TeleportAngle { get; set; } = teleportAngle;
|
||||
public float TeleportDistance { get; set; } = teleportDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
|
||||
namespace src.player.skills
|
||||
|
|
@ -38,7 +39,7 @@ namespace src.player.skills
|
|||
int damage = (int)(@event.DmgHealth * SkillsInfo.GetValue<float>(skillName, "healthTakenScale"));
|
||||
damage = Math.Min(damage, SkillsInfo.GetValue<int>(skillName, "maxTakenDamagePerShot"));
|
||||
|
||||
SkillUtils.TakeHealth(attackerEvent.PlayerPawn.Value, damage, victimEvent, "planted_c4");
|
||||
SkillUtils.TakeHealth(attackerEvent.PlayerPawn.Value, damage, victimEvent, KillfeedIcons.Armor);
|
||||
attackerEvent.EmitSound("Player.DamageBody.Onlooker");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
|||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.UserMessages;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
|
|
@ -360,7 +361,7 @@ namespace src.player.skills
|
|||
|
||||
if (CheckHasKnife(thrower!)) return;
|
||||
|
||||
SkillUtils.TakeHealth(victimPawn, SkillsInfo.GetValue<int>(skillName, "damage"), thrower, "weapon_knife");
|
||||
SkillUtils.TakeHealth(victimPawn, SkillsInfo.GetValue<int>(skillName, "damage"), thrower, KillfeedIcons.Knife);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using jRandomSkills.src.utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
|
@ -95,7 +96,7 @@ namespace src.player.skills
|
|||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) continue;
|
||||
|
||||
if (SkillUtils.GetDistance(smoke.Key, pawn.AbsOrigin) <= smokeRadius)
|
||||
if (SkillUtils.TakeHealth(pawn, smokeDamage, thrower, "smokegrenade"))
|
||||
if (SkillUtils.TakeHealth(pawn, smokeDamage, thrower, KillfeedIcons.Smokegrenade))
|
||||
player.EmitSound("Player.DamageBody.Onlooker");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ namespace src.player.skills
|
|||
public DateTime LastAttempt { get; set; }
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#ff3b3b", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = -1, Rarity rarity = Rarity.Rare, float radarDuration = 5f, float triggerRadius = 24f, float wireHeight = 30f, float wireWidth = 1.5f, 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) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float RadarDuration { get; set; } = radarDuration;
|
||||
public float TriggerRadius { get; set; } = triggerRadius;
|
||||
|
|
|
|||
|
|
@ -195,7 +195,6 @@ namespace src.player.skills
|
|||
|
||||
itemServices.HasHelmet = gear.HasHelmet;
|
||||
itemServices.HasDefuser = gear.HasDefuser;
|
||||
Utilities.SetStateChanged(pawn, "CCSPlayerPawn", "m_pItemServices");
|
||||
}
|
||||
|
||||
private static (WeaponInfo[]?, bool) GetWeapons(CCSPlayerController player)
|
||||
|
|
@ -272,7 +271,7 @@ namespace src.player.skills
|
|||
|
||||
private static CCSPlayerController? GetRandomEnemy(CCSPlayerController player)
|
||||
{
|
||||
CCSPlayerController[] enemies = [.. PlayerManager.GetTickPlayers().FindAll(e => e.Team != player.Team && e.PawnIsAlive)];
|
||||
CCSPlayerController[] enemies = [.. PlayerManager.GetTickPlayers().FindAll(e => e.Team != player.Team && e.PlayerPawn?.Value?.Health > 0)];
|
||||
if (enemies.Length == 0) return null;
|
||||
return enemies[Instance.Random.Next(enemies.Length)];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue