diff --git a/WASDMenuAPI - SRC Files/WASDMenuAPI.csproj b/WASDMenuAPI - SRC Files/WASDMenuAPI.csproj index ddda590..564cd1d 100644 --- a/WASDMenuAPI - SRC Files/WASDMenuAPI.csproj +++ b/WASDMenuAPI - SRC Files/WASDMenuAPI.csproj @@ -7,7 +7,7 @@ - + diff --git a/jRandomSkills - SRC Files/jRandomSkills.csproj b/jRandomSkills - SRC Files/jRandomSkills.csproj index ead9b06..e853387 100644 --- a/jRandomSkills - SRC Files/jRandomSkills.csproj +++ b/jRandomSkills - SRC Files/jRandomSkills.csproj @@ -19,7 +19,7 @@ - + diff --git a/jRandomSkills - SRC Files/src/jRandomSkills.cs b/jRandomSkills - SRC Files/src/jRandomSkills.cs index 49e474e..26bdc3d 100644 --- a/jRandomSkills - SRC Files/src/jRandomSkills.cs +++ b/jRandomSkills - SRC Files/src/jRandomSkills.cs @@ -31,7 +31,7 @@ namespace src public override string ModuleName => "[CS2] [ jRandomSkills ]"; public override string ModuleAuthor => "D3X (Original), Juzlus (Modifier), ByDexterTR (Contributor)"; public override string ModuleDescription => "Plugin adds random skills every round for CS2 by D3X. Modified by Juzlus."; - public override string ModuleVersion => "1.2.3.b8"; + public override string ModuleVersion => "1.2.3.b9"; public override void Load(bool hotReload) { diff --git a/jRandomSkills - SRC Files/src/player/EntityEvents.cs b/jRandomSkills - SRC Files/src/player/EntityEvents.cs index 825b860..c98cc41 100644 --- a/jRandomSkills - SRC Files/src/player/EntityEvents.cs +++ b/jRandomSkills - SRC Files/src/player/EntityEvents.cs @@ -1,4 +1,4 @@ -using CounterStrikeSharp.API; +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Modules.Memory; @@ -89,6 +89,7 @@ namespace src.player lock (setLock) { CountDamageResolution(info); + SkillUtils.TrackHealthBeforeHit(entity, info); object[] args = [entity, info]; DispatchOnTakeDamage(entity, info, args); diff --git a/jRandomSkills - SRC Files/src/player/PlayerEvents.cs b/jRandomSkills - SRC Files/src/player/PlayerEvents.cs index a92791f..8f5507d 100644 --- a/jRandomSkills - SRC Files/src/player/PlayerEvents.cs +++ b/jRandomSkills - SRC Files/src/player/PlayerEvents.cs @@ -798,6 +798,8 @@ namespace src.player return; } + if (designer == "planted_c4" && player.Team == CsTeam.CounterTerrorist) return; + if (designer.Contains("button") || designer.Contains("weapon") || designer.Contains("blocker")) return; } } diff --git a/jRandomSkills - SRC Files/src/player/RoundEvents.cs b/jRandomSkills - SRC Files/src/player/RoundEvents.cs index e53c1b6..9908d4f 100644 --- a/jRandomSkills - SRC Files/src/player/RoundEvents.cs +++ b/jRandomSkills - SRC Files/src/player/RoundEvents.cs @@ -1,4 +1,4 @@ -using CounterStrikeSharp.API; +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Modules.Admin; @@ -182,6 +182,7 @@ namespace src.player Instance.RemoveListener(CheckTransmit); Fortnite.skillInThisRound = false; + SkillUtils.ClearHealthBeforeHit(); EntityManager.SuppressKills = true; try diff --git a/jRandomSkills - SRC Files/src/player/skills/Dracula.cs b/jRandomSkills - SRC Files/src/player/skills/Dracula.cs index 4f082ba..3e6b7d3 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Dracula.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Dracula.cs @@ -1,4 +1,4 @@ -using CounterStrikeSharp.API; +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using src.utils; @@ -9,7 +9,6 @@ namespace src.player.skills public class Dracula : ISkill { private const Skills skillName = Skills.Dracula; - public static void LoadSkill() { SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(skillName, "color")); @@ -20,11 +19,11 @@ namespace src.player.skills var attacker = PlayerManager.GetPlayerEvent(@event.Attacker); var victim = PlayerManager.GetPlayerEvent(@event.Userid); - if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return; + if (!Instance.IsPlayerValid(attacker) || victim == null || !victim.IsValid || attacker == victim) return; var playerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index); + if (playerInfo?.Skill != skillName) return; - if (playerInfo?.Skill == skillName && victim!.PawnIsAlive) - HealAttacker(attacker!, @event.DmgHealth); + HealAttacker(attacker!, SkillUtils.CapToVictimHealth(victim, @event.DmgHealth)); } public static void DisableSkill(CCSPlayerController player) @@ -46,22 +45,30 @@ namespace src.player.skills private static void HealAttacker(CCSPlayerController attacker, float damage) { - var attackerPawn = attacker.PlayerPawn?.Value; - if (attackerPawn == null || !attackerPawn.IsValid) return; - - if (attackerPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE || attackerPawn.Health <= 0) return; - int extraHealth = (int)(damage * SkillsInfo.GetValue(skillName, "healthRegainScale")); if (extraHealth <= 0) return; - attackerPawn.Health += extraHealth; - Utilities.SetStateChanged(attackerPawn, "CBaseEntity", "m_iHealth"); + uint attackerIndex = attacker.Index; - if (attackerPawn.MaxHealth < attackerPawn.Health) + Server.NextFrame(() => { - attackerPawn.MaxHealth = attackerPawn.Health; - Utilities.SetStateChanged(attackerPawn, "CBaseEntity", "m_iMaxHealth"); - } + var target = Utilities.GetPlayerFromIndex((int)attackerIndex); + if (target == null || !target.IsValid) return; + + var attackerPawn = target.PlayerPawn?.Value; + if (attackerPawn == null || !attackerPawn.IsValid) return; + + if (attackerPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE || attackerPawn.Health <= 0) return; + + attackerPawn.Health += extraHealth; + Utilities.SetStateChanged(attackerPawn, "CBaseEntity", "m_iHealth"); + + if (attackerPawn.MaxHealth < attackerPawn.Health) + { + attackerPawn.MaxHealth = attackerPawn.Health; + Utilities.SetStateChanged(attackerPawn, "CBaseEntity", "m_iMaxHealth"); + } + }); } public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#FA050D", 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 healthRegainScale = .3f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity) diff --git a/jRandomSkills - SRC Files/src/player/skills/Iana.cs b/jRandomSkills - SRC Files/src/player/skills/Iana.cs index f160033..f21f33d 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Iana.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Iana.cs @@ -302,13 +302,43 @@ namespace src.player.skills return shooter != null && shooter.IsValid ? shooter : null; } + private static void AbsorbWithClone(CBaseEntity damagedEntity, CTakeDamageInfo damageInfo) + { + if (damageInfo.Damage <= 0) return; + + CCSPlayerPawn victimPawn = new(damagedEntity.Handle); + if (!victimPawn.IsValid || victimPawn.DesignerName != "player") return; + + var victimController = victimPawn.Controller?.Value; + if (victimController == null || !victimController.IsValid) return; + + var victim = PlayerManager.GetPlayerEvent(victimController.As()); + if (victim == null || !victim.IsValid) return; + + if (PlayerManager.GetPlayerByIndex(victim.Index)?.Skill != skillName) return; + if (!playersInfo.TryGetValue(victim.Index, out var playerSkill)) return; + + bool hasClone = playerSkill.CloneProp != null; + if (!hasClone && playerSkill.LastHit + 4 <= Server.TickCount) return; + + damageInfo.Damage = 0; + + if (!hasClone) return; + + KillClone(playerSkill); + playerSkill.LastHit = Server.TickCount; + } + public static void OnTakeDamage(CBaseEntity damagedEntity, CTakeDamageInfo damageInfo) { if (damagedEntity == null || damagedEntity.Entity == null || damageInfo == null) return; - if (string.IsNullOrEmpty(damagedEntity.Entity.Name)) return; - if (!damagedEntity.Entity.Name.StartsWith("IanaClone_")) return; + if (string.IsNullOrEmpty(damagedEntity.Entity.Name) || !damagedEntity.Entity.Name.StartsWith("IanaClone_")) + { + AbsorbWithClone(damagedEntity, damageInfo); + return; + } var nameParams = damagedEntity.Entity.Name.Split('_')[2]; _ = uint.TryParse(nameParams, out uint userIndex); @@ -357,26 +387,6 @@ namespace src.player.skills } } - public static void PlayerHurt(EventPlayerHurt @event) - { - var victim = PlayerManager.GetPlayerEvent(@event.Userid); - if (victim == null || !victim.IsValid) return; - - if (PlayerManager.GetPlayerByIndex(victim.Index)?.Skill != skillName) return; - - if (playersInfo.TryGetValue(victim.Index, out var playerSkill)) - { - if (playerSkill.CloneProp != null) - { - KillClone(playerSkill); - playerSkill.LastHit = Server.TickCount; - } - - if (playerSkill.LastHit + 4 > Server.TickCount) - SkillUtils.RestoreHealth(victim); - } - } - private static void BlockWeapon(CCSPlayerController player, bool block) { if (player == null || !player.IsValid) return; diff --git a/jRandomSkills - SRC Files/src/player/skills/Pyro.cs b/jRandomSkills - SRC Files/src/player/skills/Pyro.cs index 4bdcc77..4621dda 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Pyro.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Pyro.cs @@ -1,4 +1,4 @@ -using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Utils; using src.utils; @@ -17,19 +17,46 @@ namespace src.player.skills SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(skillName, "color")); } - public static void PlayerHurt(EventPlayerHurt @event) + private const string infernoDamage = "inferno"; + + private static bool IsInfernoDamage(CTakeDamageInfo damageInfo) { - var victim = PlayerManager.GetPlayerEvent(@event.Userid); - int damage = @event.DmgHealth; - string weapon = @event.Weapon; + var ability = damageInfo.Ability?.Value; + if (ability != null && ability.IsValid && ability.DesignerName == infernoDamage) return true; - if (weapon != "inferno" || !Instance.IsPlayerValid(victim)) return; - var victimInfo = PlayerManager.GetPlayerByIndex(victim!.Index); + var inflictor = damageInfo.Inflictor?.Value; + return inflictor != null && inflictor.IsValid && inflictor.DesignerName == infernoDamage; + } - if (victimInfo == null || victimInfo.Skill != skillName) return; + public static void OnTakeDamage(CBaseEntity damagedEntity, CTakeDamageInfo damageInfo) + { + if (damagedEntity == null || !damagedEntity.IsValid || damageInfo == null) return; + if (damageInfo.Damage <= 0 || !IsInfernoDamage(damageInfo)) return; - var pawn = victim!.PlayerPawn.Value; - SkillUtils.AddHealth(pawn, (int)(damage * SkillsInfo.GetValue(skillName, "regenerationMultiplier"))); + CCSPlayerPawn victimPawn = new(damagedEntity.Handle); + if (!victimPawn.IsValid || victimPawn.DesignerName != "player") return; + + var victimController = victimPawn.Controller?.Value; + if (victimController == null || !victimController.IsValid) return; + + var victim = PlayerManager.GetPlayerEvent(victimController.As()); + if (victim == null || !victim.IsValid) return; + + if (PlayerManager.GetPlayerByIndex(victim.Index)?.Skill != skillName) return; + + float damage = damageInfo.Damage; + float net = damage * (SkillsInfo.GetValue(skillName, "regenerationMultiplier") - 1f); + + if (net < 0) + { + damageInfo.Damage = -net; + return; + } + + damageInfo.Damage = 0; + + int heal = (int)MathF.Round(net); + if (heal > 0) SkillUtils.AddHealth(victimPawn, heal); } public static void GrenadeThrown(EventGrenadeThrown @event) diff --git a/jRandomSkills - SRC Files/src/player/skills/ReturnToSender.cs b/jRandomSkills - SRC Files/src/player/skills/ReturnToSender.cs index c91e050..c3e82d0 100644 --- a/jRandomSkills - SRC Files/src/player/skills/ReturnToSender.cs +++ b/jRandomSkills - SRC Files/src/player/skills/ReturnToSender.cs @@ -1,4 +1,4 @@ -using CounterStrikeSharp.API; +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using static src.jRandomSkills; @@ -26,7 +26,6 @@ namespace src.player.skills { var attacker = PlayerManager.GetPlayerEvent(@event.Attacker); var victim = PlayerManager.GetPlayerEvent(@event.Userid); - int damage = @event.DmgHealth; if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return; var attackerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index); diff --git a/jRandomSkills - SRC Files/src/player/skills/RobinHood.cs b/jRandomSkills - SRC Files/src/player/skills/RobinHood.cs index b95ca3f..b5f1b4a 100644 --- a/jRandomSkills - SRC Files/src/player/skills/RobinHood.cs +++ b/jRandomSkills - SRC Files/src/player/skills/RobinHood.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Cvars; using CounterStrikeSharp.API.Modules.Utils; using src.utils; using static src.jRandomSkills; @@ -15,16 +16,18 @@ namespace src.player.skills SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue(skillName, "color")); } + private static int GetMaxMoney() => ConVar.Find("mp_maxmoney")?.GetPrimitiveValue() ?? 16000; + public static void PlayerHurt(EventPlayerHurt @event) { var victim = PlayerManager.GetPlayerEvent(@event.Userid); var attacker = PlayerManager.GetPlayerEvent(@event.Attacker); - var damage = @event.DmgHealth; - if (!Instance.IsPlayerValid(attacker) || !Instance.IsPlayerValid(victim) || attacker == victim) return; + if (!Instance.IsPlayerValid(attacker) || victim == null || !victim.IsValid || attacker == victim) return; var attackerInfo = PlayerManager.GetPlayerByIndex(attacker!.Index); if (attackerInfo?.Skill != skillName) return; + int damage = SkillUtils.CapToVictimHealth(victim, @event.DmgHealth); int moneyToSteal = damage * SkillsInfo.GetValue(skillName, "moneyMultiplier"); StealMoney(victim!, attacker!, moneyToSteal); } @@ -35,11 +38,17 @@ namespace src.player.skills var attackerMoneyServices = attacker?.InGameMoneyServices; if (victimMoneyServices == null || attackerMoneyServices == null) return; - var moneyToAdd = victimMoneyServices.Account < money ? victimMoneyServices.Account : money; - victimMoneyServices.Account = Math.Max(victimMoneyServices.Account - money, 0); + int maxMoney = GetMaxMoney(); + int headroom = Math.Max(maxMoney - attackerMoneyServices.Account, 0); + + int transfer = Math.Min(money, victimMoneyServices.Account); + transfer = Math.Min(transfer, headroom); + if (transfer <= 0) return; + + victimMoneyServices.Account -= transfer; Utilities.SetStateChanged(victim!, "CCSPlayerController", "m_pInGameMoneyServices"); - attackerMoneyServices.Account = Math.Min(attackerMoneyServices.Account + moneyToAdd, 16000); + attackerMoneyServices.Account += transfer; Utilities.SetStateChanged(attacker!, "CCSPlayerController", "m_pInGameMoneyServices"); } diff --git a/jRandomSkills - SRC Files/src/player/skills/Voodoo.cs b/jRandomSkills - SRC Files/src/player/skills/Voodoo.cs index ddaf66c..d23c820 100644 --- a/jRandomSkills - SRC Files/src/player/skills/Voodoo.cs +++ b/jRandomSkills - SRC Files/src/player/skills/Voodoo.cs @@ -1,4 +1,4 @@ -using CounterStrikeSharp.API; +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using jRandomSkills.src.utils; @@ -138,7 +138,7 @@ namespace src.player.skills if (victimPawn == null || !victimPawn.IsValid || victimPawn.Health <= 0) return; if (victimPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) return; - int reflected = (int)MathF.Round(@event.DmgHealth * SkillsInfo.GetValue(skillName, "reflectPercent")); + int reflected = (int)MathF.Round(SkillUtils.CapToVictimHealth(owner, @event.DmgHealth) * SkillsInfo.GetValue(skillName, "reflectPercent")); if (reflected < 1) return; SkillUtils.TakeHealth(victimPawn, reflected, owner, KillfeedIcons.Fist); diff --git a/jRandomSkills - SRC Files/src/utils/Config.cs b/jRandomSkills - SRC Files/src/utils/Config.cs index 4f55eae..8766989 100644 --- a/jRandomSkills - SRC Files/src/utils/Config.cs +++ b/jRandomSkills - SRC Files/src/utils/Config.cs @@ -290,8 +290,11 @@ namespace src.utils public class WeaponPools { + [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)] public required List Rifle { get; set; } + [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)] public required List Pistol { get; set; } + [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)] public required List Grenade { get; set; } } diff --git a/jRandomSkills - SRC Files/src/utils/RayTrace.cs b/jRandomSkills - SRC Files/src/utils/RayTrace.cs index 5ac6e22..92f314f 100644 --- a/jRandomSkills - SRC Files/src/utils/RayTrace.cs +++ b/jRandomSkills - SRC Files/src/utils/RayTrace.cs @@ -7,6 +7,7 @@ using RayTraceAPI; using System.Drawing; using System.Numerics; using TraceOptions = RayTraceAPI.TraceOptions; +using TraceResult = RayTraceAPI.TraceResult; using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; namespace src.utils diff --git a/jRandomSkills - SRC Files/src/utils/SkillUtils.cs b/jRandomSkills - SRC Files/src/utils/SkillUtils.cs index a7cde3f..9599df3 100644 --- a/jRandomSkills - SRC Files/src/utils/SkillUtils.cs +++ b/jRandomSkills - SRC Files/src/utils/SkillUtils.cs @@ -619,6 +619,34 @@ namespace src.utils .Cast()]; } + private static readonly ConcurrentDictionary healthBeforeHit = []; + + public static void TrackHealthBeforeHit(CBaseEntity? damagedEntity, CTakeDamageInfo? damageInfo) + { + if (damagedEntity == null || damageInfo == null || damageInfo.Damage <= 0) return; + + CCSPlayerPawn victimPawn = new(damagedEntity.Handle); + if (!victimPawn.IsValid || victimPawn.DesignerName != "player") return; + + var victimController = victimPawn.Controller?.Value; + if (victimController == null || !victimController.IsValid) return; + + var victim = PlayerManager.GetPlayerEvent(victimController.As()); + if (victim == null || !victim.IsValid) return; + + healthBeforeHit[victim.Index] = victimPawn.Health; + } + + public static int CapToVictimHealth(CCSPlayerController? victim, int dmgHealth) + { + if (victim == null || !victim.IsValid) return dmgHealth; + if (!healthBeforeHit.TryGetValue(victim.Index, out int healthBefore) || healthBefore <= 0) return dmgHealth; + + return dmgHealth > healthBefore ? healthBefore : dmgHealth; + } + + public static void ClearHealthBeforeHit() => healthBeforeHit.Clear(); + public static bool TakeHealth(CCSPlayerPawn? pawn, int damage, CCSPlayerController? damageAttacker = null, KillfeedIcons? killfeedIcon = null) { if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE) diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/WASDMenuAPI.dll b/jRandomSkills - Server Files/plugins/jRandomSkills/WASDMenuAPI.dll index e69cf33..d0aee34 100644 Binary files a/jRandomSkills - Server Files/plugins/jRandomSkills/WASDMenuAPI.dll and b/jRandomSkills - Server Files/plugins/jRandomSkills/WASDMenuAPI.dll differ diff --git a/jRandomSkills - Server Files/plugins/jRandomSkills/jRandomSkills.dll b/jRandomSkills - Server Files/plugins/jRandomSkills/jRandomSkills.dll index 595e711..1753ecb 100644 Binary files a/jRandomSkills - Server Files/plugins/jRandomSkills/jRandomSkills.dll and b/jRandomSkills - Server Files/plugins/jRandomSkills/jRandomSkills.dll differ