From 43db0d09c90e78a5d527ccbc0f710d77ea355b32 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sun, 21 Nov 2021 09:19:09 -0800 Subject: [PATCH] fix: Weapons cleanup (#857) * Removes linq * Removes list allocation for area effect * Removes redundant swing overload * Cleans up code --- Projects/Server/Interfaces.cs | 3 +- .../UOContent/Items/Weapons/BaseWeapon.cs | 381 ++++++++---------- Projects/UOContent/Items/Weapons/Fists.cs | 2 +- .../Items/Weapons/Ranged/BaseRanged.cs | 2 +- 4 files changed, 173 insertions(+), 215 deletions(-) diff --git a/Projects/Server/Interfaces.cs b/Projects/Server/Interfaces.cs index 587abead0..3e46e8bb2 100644 --- a/Projects/Server/Interfaces.cs +++ b/Projects/Server/Interfaces.cs @@ -22,8 +22,7 @@ namespace Server { int MaxRange { get; } void OnBeforeSwing(Mobile attacker, Mobile defender); - TimeSpan OnSwing(Mobile attacker, Mobile defender); - TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus); + TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0); void GetStatusDamage(Mobile from, out int min, out int max); } diff --git a/Projects/UOContent/Items/Weapons/BaseWeapon.cs b/Projects/UOContent/Items/Weapons/BaseWeapon.cs index b50b97f32..8e183a7b9 100644 --- a/Projects/UOContent/Items/Weapons/BaseWeapon.cs +++ b/Projects/UOContent/Items/Weapons/BaseWeapon.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; +using Server.Collections; using Server.Engines.Craft; using Server.Ethics; using Server.Factions; @@ -695,8 +695,6 @@ namespace Server.Items } } - public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender) => OnSwing(attacker, defender, 1.0); - public virtual void GetStatusDamage(Mobile from, out int min, out int max) { GetBaseDamageRange(from, out var baseMin, out var baseMax); @@ -713,7 +711,7 @@ namespace Server.Items } } - public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus) + public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0) { var canSwing = true; @@ -723,12 +721,12 @@ namespace Server.Items if (canSwing) { - canSwing = !(attacker.Spell is Spell sp) || !sp.IsCasting || !sp.BlocksMovement; + canSwing = attacker.Spell is not Spell sp || !sp.IsCasting || !sp.BlocksMovement; } if (canSwing) { - canSwing = !(attacker is PlayerMobile p) || p.PeacedUntil <= Core.Now; + canSwing = attacker is not PlayerMobile p || p.PeacedUntil <= Core.Now; } } @@ -786,7 +784,7 @@ namespace Server.Items public override void OnAfterDuped(Item newItem) { - if (!(newItem is BaseWeapon weap)) + if (newItem is not BaseWeapon weap) { return; } @@ -877,8 +875,8 @@ namespace Server.Items return true; } - if (Layer == Layer.OneHanded && layer == Layer.TwoHanded && !(item is BaseShield) && - !(item is BaseEquipableLight)) + if (Layer == Layer.OneHanded && layer == Layer.TwoHanded && item is not BaseShield && + item is not BaseEquipableLight) { m.SendLocalizedMessage(500215); // You can only wield one weapon at a time. return true; @@ -1096,7 +1094,6 @@ namespace Server.Items var defWeapon = defender.Weapon as BaseWeapon; var atkSkill = attacker.Skills[atkWeapon?.Skill ?? SkillName.Wrestling]; - // Skill defSkill = defender.Skills[defWeapon.Skill]; var atkValue = atkWeapon?.GetAttackSkillValue(attacker, defender) ?? 0.0; var defValue = defWeapon?.GetDefendSkillValue(attacker, defender) ?? 0.0; @@ -1209,23 +1206,11 @@ namespace Server.Items } else { - if (atkValue <= -50.0) - { - atkValue = -49.9; - } - - if (defValue <= -50.0) - { - defValue = -49.9; - } - - ourValue = atkValue + 50.0; - theirValue = defValue + 50.0; + ourValue = Math.Max(0.1, atkValue + 50.0); + theirValue = Math.Max(0.1, defValue + 50.0); } - var chance = ourValue / (theirValue * 2.0); - - chance *= 1.0 + (double)bonus / 100; + var chance = ourValue / (theirValue * 2.0) * 1.0 + (double)bonus / 100; if (Core.AOS && chance < 0.02) { @@ -1418,7 +1403,7 @@ namespace Server.Items return defender.CheckSkill(SkillName.Parry, chance); } - if (defender.Weapon is Fists || defender.Weapon is BaseRanged) + if (defender.Weapon is Server.Items.Fists or BaseRanged) { return false; } @@ -1459,9 +1444,8 @@ namespace Server.Items return defender.CheckSkill(SkillName.Parry, chance); } - return - aosChance > Utility - .RandomDouble(); // Only skillcheck if wielding a shield & there's no effect from Bushido + // Only skillcheck if wielding a shield & there's no effect from Bushido + return aosChance > Utility.RandomDouble(); } public virtual int AbsorbDamageAOS(Mobile attacker, Mobile defender, int damage) @@ -1493,9 +1477,8 @@ namespace Server.Items if (Confidence.IsConfident(defender)) { - defender.SendLocalizedMessage( - 1063117 - ); // Your confidence reassures you as you successfully block your opponent's blow. + // Your confidence reassures you as you successfully block your opponent's blow. + defender.SendLocalizedMessage(1063117); var bushido = defender.Skills.Bushido.Value; @@ -1590,7 +1573,7 @@ namespace Server.Items return 0; } - if (!(attacker is BaseCreature bc) || bc.PackInstinct == PackInstinct.None || !bc.Controlled && !bc.Summoned) + if (attacker is not BaseCreature bc || bc.PackInstinct == PackInstinct.None || !bc.Controlled && !bc.Summoned) { return 0; } @@ -1603,16 +1586,26 @@ namespace Server.Items } var eable = defender.GetMobilesInRange(1); - var inPack = 1 + eable - .Where(m => m != attacker && (m.PackInstinct & bc.PackInstinct) != 0 && (m.Controlled || m.Summoned)) - .Count(m => master == (m.ControlMaster ?? m.SummonMaster) && m.Combatant == defender); + var inPack = 1; + foreach (var m in eable) + { + if (m != attacker && (m.PackInstinct & bc.PackInstinct) != 0 && (m.Controlled || m.Summoned) && + master == (m.ControlMaster ?? m.SummonMaster) && m.Combatant == defender) + { + inPack++; + } + } eable.Free(); - return inPack >= 5 ? 100 : - inPack >= 4 ? 75 : - inPack >= 3 ? 50 : - inPack >= 2 ? 25 : 0; + return inPack switch + { + >= 5 => 100, + 4 => 75, + 3 => 50, + 2 => 25, + _ => 0 + }; } public virtual void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1.0) @@ -1688,12 +1681,9 @@ namespace Server.Items if (!attacker.Player) { - if (defender is PlayerMobile pm) + if (defender is PlayerMobile pm && pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType()) { - if (pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType()) - { - percentageBonus += 100; - } + percentageBonus += 100; } } else if (!defender.Player) @@ -1769,16 +1759,14 @@ namespace Server.Items { damage = 1; } - else if (Core.AOS && damage == 0) // parried + // Parried + else if (Core.AOS && damage == 0 && a?.Validate(attacker) == true) { - if (a?.Validate(attacker) == true) /*&& a.CheckMana( attacker, true )*/ - // Parried special moves have no mana cost - { - a = null; - WeaponAbility.ClearCurrentAbility(attacker); - - attacker.SendLocalizedMessage(1061140); // Your attack was parried! - } + /*&& a.CheckMana( attacker, true )*/ + // Parried special moves have no mana cost + a = null; + WeaponAbility.ClearCurrentAbility(attacker); + attacker.SendLocalizedMessage(1061140); // Your attack was parried! } AddBlood(attacker, defender, damage); @@ -1936,9 +1924,8 @@ namespace Server.Items if (context?.Type == typeof(WraithFormSpell)) { - wraithLeech = - 5 + (int)(15 * attacker.Skills.SpiritSpeak.Value / - 100); // Wraith form gives an additional 5-20% mana leech + // Wraith form gives an additional 5-20% mana leech + wraithLeech = 5 + (int)(15 * attacker.Skills.SpiritSpeak.Value / 100); // Mana leeched by the Wraith Form spell is actually stolen, not just leeched. defender.Mana -= AOS.Scale(damageGiven, wraithLeech); @@ -1967,10 +1954,10 @@ namespace Server.Items } } - if (m_MaxHits > 0 && (MaxRange <= 1 && (defender is Slime || defender is AcidElemental) || - Utility.RandomDouble() < .04)) // Stratics says 50% chance, seems more like 4%.. + // Stratics says 50% chance, seems more like 4%.. + if (m_MaxHits > 0 && MaxRange <= 1 && defender is Slime or AcidElemental |Utility.RandomDouble() < .04) { - if (MaxRange <= 1 && (defender is Slime || defender is AcidElemental)) + if (MaxRange <= 1 && defender is Slime or AcidElemental) { attacker.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500263); // *Acid blood scars your weapon!* } @@ -1979,29 +1966,23 @@ namespace Server.Items { HitPoints += 2; } + else if (m_Hits > 0) + { + --HitPoints; + } + else if (m_MaxHits > 1) + { + --MaxHitPoints; + + if (Parent is Mobile mobile) + { + // Your equipment is severely damaged. + mobile.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1061121); + } + } else { - if (m_Hits > 0) - { - --HitPoints; - } - else if (m_MaxHits > 1) - { - --MaxHitPoints; - - if (Parent is Mobile mobile) - { - mobile.LocalOverheadMessage( - MessageType.Regular, - 0x3B2, - 1061121 // Your equipment is severely damaged. - ); - } - } - else - { - Delete(); - } + Delete(); } } @@ -2021,16 +2002,20 @@ namespace Server.Items if (Core.AOS) { - var physChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPhysicalArea) * - propertyBonus); + var physChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPhysicalArea) * propertyBonus); + var fireChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireArea) * propertyBonus); + var coldChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitColdArea) * propertyBonus); - var poisChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPoisonArea) * - propertyBonus); - var nrgyChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitEnergyArea) * - propertyBonus); + + var poisChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPoisonArea) * propertyBonus); + + var nrgyChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitEnergyArea) * propertyBonus); if (physChance != 0 && physChance > Utility.Random(100)) { @@ -2092,10 +2077,10 @@ namespace Server.Items DoDispel(attacker, defender); } - var laChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerAttack) * - propertyBonus); - var ldChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerDefend) * - propertyBonus); + var laChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerAttack) * propertyBonus); + var ldChance = + (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerDefend) * propertyBonus); if (laChance != 0 && laChance > Utility.Random(100)) { @@ -2121,7 +2106,7 @@ namespace Server.Items it.ReceivedHonorContext?.OnTargetHit(attacker); } - if (!(this is BaseRanged)) + if (this is not BaseRanged) { if (AnimalForm.UnderTransformation(attacker, typeof(GiantSerpent))) { @@ -2157,7 +2142,7 @@ namespace Server.Items // SDI bonus damageBonus += AosAttributes.GetValue(attacker, AosAttribute.SpellDamage); - if(PsychicAttack.Registry.TryGetValue(attacker,out var timer)) + if (PsychicAttack.Registry.TryGetValue(attacker,out var timer)) { damageBonus -= timer.SpellDamageMalus; } @@ -2319,13 +2304,8 @@ namespace Server.Items attacker.PlaySound(GetMissAttackSound(attacker, defender)); defender.PlaySound(GetMissDefendSound(attacker, defender)); - var ability = WeaponAbility.GetCurrentAbility(attacker); - - ability?.OnMiss(attacker, defender); - - var move = SpecialMove.GetCurrentMove(attacker); - - move?.OnMiss(attacker, defender); + WeaponAbility.GetCurrentAbility(attacker)?.OnMiss(attacker, defender); + SpecialMove.GetCurrentMove(attacker)?.OnMiss(attacker, defender); if (defender is IHonorTarget target) { @@ -2417,56 +2397,38 @@ namespace Server.Items { var bonus = VirtualDamageBonus; - switch (m_Quality) + bonus += m_Quality switch { - case WeaponQuality.Low: - bonus -= 20; - break; - case WeaponQuality.Exceptional: - bonus += 20; - break; - } + WeaponQuality.Low => -20, + WeaponQuality.Exceptional => 20, + _ => 0 + }; - switch (m_DamageLevel) + return bonus + m_DamageLevel switch { - case WeaponDamageLevel.Ruin: - bonus += 15; - break; - case WeaponDamageLevel.Might: - bonus += 20; - break; - case WeaponDamageLevel.Force: - bonus += 25; - break; - case WeaponDamageLevel.Power: - bonus += 30; - break; - case WeaponDamageLevel.Vanq: - bonus += 35; - break; - } - - return bonus; + WeaponDamageLevel.Ruin => 15, + WeaponDamageLevel.Might => 20, + WeaponDamageLevel.Force => 25, + WeaponDamageLevel.Power => 30, + WeaponDamageLevel.Vanq => 35, + _ => bonus + }; } public virtual double ScaleDamageAOS(Mobile attacker, double damage, bool checkSkills) { if (checkSkills) { - attacker.CheckSkill( - SkillName.Tactics, - 0.0, - attacker.Skills.Tactics.Cap - ); // Passively check tactics for gain - attacker.CheckSkill( - SkillName.Anatomy, - 0.0, - attacker.Skills.Anatomy.Cap - ); // Passively check Anatomy for gain + // Passively check tactics for gain + attacker.CheckSkill(SkillName.Tactics, 0.0, attacker.Skills.Tactics.Cap); + + // Passively check Anatomy for gain + attacker.CheckSkill(SkillName.Anatomy, 0.0, attacker.Skills.Anatomy.Cap); if (Type == WeaponType.Axe) { - attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain + // Passively check Lumberjacking for gain + attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); } } @@ -2536,20 +2498,16 @@ namespace Server.Items { if (checkSkills) { - attacker.CheckSkill( - SkillName.Tactics, - 0.0, - attacker.Skills.Tactics.Cap - ); // Passively check tactics for gain - attacker.CheckSkill( - SkillName.Anatomy, - 0.0, - attacker.Skills.Anatomy.Cap - ); // Passively check Anatomy for gain + // Passively check tactics for gain + attacker.CheckSkill(SkillName.Tactics, 0.0, attacker.Skills.Tactics.Cap); + + // Passively check Anatomy for gain + attacker.CheckSkill(SkillName.Anatomy, 0.0, attacker.Skills.Anatomy.Cap); if (Type == WeaponType.Axe) { - attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain + // Passively check Lumberjacking for gain + attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); } } @@ -2633,9 +2591,9 @@ namespace Server.Items var damage = (int)ScaleDamageOld(attacker, GetBaseDamage(attacker), true); // pre-AOS, halve damage if the defender is a player or the attacker is not a player - if (defender is PlayerMobile || !(attacker is PlayerMobile)) + if (defender is PlayerMobile || attacker is not PlayerMobile) { - damage = (int)(damage / 2.0); + damage /= 2; } return damage; @@ -2643,6 +2601,11 @@ namespace Server.Items public virtual void PlayHurtAnimation(Mobile from) { + if (from.Mounted) + { + return; + } + int action; int frames; @@ -2667,12 +2630,10 @@ namespace Server.Items frames = 5; break; } - default: return; - } - - if (from.Mounted) - { - return; + default: + { + return; + } } from.Animate(action, frames, 1, true, false, 0); @@ -2695,10 +2656,18 @@ namespace Server.Items switch (Animation) { default: - action = Utility.Random(4, 3); - break; - case WeaponAnimation.ShootBow: return; // 7 - case WeaponAnimation.ShootXBow: return; // 8 + { + action = Utility.Random(4, 3); + break; + } + case WeaponAnimation.ShootBow: + { + return; // 7 + } + case WeaponAnimation.ShootXBow: + { + return; // 8 + } } break; @@ -2728,7 +2697,10 @@ namespace Server.Items break; } - default: return; + default: + { + return; + } } from.Animate(action, 7, 1, true, false, 0); @@ -2739,11 +2711,11 @@ namespace Server.Items public int GetElementalDamageHue() { GetDamageTypes(null, out _, out var fire, out var cold, out var pois, out var nrgy, out _, out _); - // Order is Cold, Energy, Fire, Poison, Physical left var currentMax = 50; var hue = 0; + // Order is Cold, Energy, Fire, Poison, Physical if (pois >= currentMax) { hue = 1267 + (pois - 50) / 10; @@ -2812,7 +2784,7 @@ namespace Server.Items * formatting show, and remove CLILOCs embedded: more like OSI * did with the books that had markup, etc. * - * This will have a negative effect on a few event things imgame + * This will have a negative effect on a few event things in-game * as is. * * If we cant find a more OSI-ish way to clean it up, we can @@ -2828,29 +2800,10 @@ namespace Server.Items /* list.Add( 1062613, Utility.FixHtml( m_EngravedText ) ); */ } - public override bool AllowEquippedCast(Mobile from) - { - if (base.AllowEquippedCast(from)) - { - return true; - } + public override bool AllowEquippedCast(Mobile from) => + base.AllowEquippedCast(from) || Attributes.SpellChanneling != 0; - return Attributes.SpellChanneling != 0; - } - - public virtual int GetLuckBonus() - { - var resInfo = CraftResources.GetInfo(m_Resource); - - var attrInfo = resInfo?.AttributeInfo; - - if (attrInfo == null) - { - return 0; - } - - return attrInfo.WeaponLuck; - } + public virtual int GetLuckBonus() => CraftResources.GetInfo(m_Resource)?.AttributeInfo?.WeaponLuck ?? 0; public override void GetProperties(ObjectPropertyList list) { @@ -3235,17 +3188,25 @@ namespace Server.Items switch (Skill) { case SkillName.Swords: - list.Add(1061172); - break; // skill required: swordsmanship + { + list.Add(1061172); // skill required: swordsmanship + break; + } case SkillName.Macing: - list.Add(1061173); - break; // skill required: mace fighting + { + list.Add(1061173); // skill required: mace fighting + break; + } case SkillName.Fencing: - list.Add(1061174); - break; // skill required: fencing + { + list.Add(1061174); // skill required: fencing + break; + } case SkillName.Archery: - list.Add(1061175); - break; // skill required: archery + { + list.Add(1061175); // skill required: archery + break; + } } } @@ -3351,13 +3312,7 @@ namespace Server.Items public virtual int GetHitAttackSound(Mobile attacker, Mobile defender) { var sound = attacker.GetAttackSound(); - - if (sound == -1) - { - sound = HitSound; - } - - return sound; + return sound == -1 ? HitSound : sound; } public virtual int GetHitDefendSound(Mobile attacker, Mobile defender) => defender.GetHurtSound(); @@ -3518,33 +3473,37 @@ namespace Server.Items var range = Core.ML ? 5 : 10; var eable = from.GetMobilesInRange(range); - var list = eable.Where( - m => - from != m && defender != m && SpellHelper.ValidIndirectTarget(from, m) - && from.CanBeHarmful(m, false) && (!Core.ML || from.InLOS(m)) - ) - .ToList(); + using var queue = PooledRefQueue.Create(); + foreach (var m in eable) + { + if (from != m && defender != m && SpellHelper.ValidIndirectTarget(from, m) + && from.CanBeHarmful(m, false) && (!Core.ML || from.InLOS(m))) + { + queue.Enqueue(m); + } + } eable.Free(); - if (list.Count == 0) + if (queue.Count == 0) { return; } Effects.PlaySound(from.Location, map, sound); - for (var i = 0; i < list.Count; ++i) + while (queue.Count > 0) { - var m = list[i]; + var m = queue.Dequeue(); var scalar = Core.ML ? 1.0 : (11 - from.GetDistanceToSqrt(m)) / 10; - var damage = GetBaseDamage(from); if (scalar <= 0) { continue; } + var damage = GetBaseDamage(from); + if (scalar < 1.0) { damage *= (11 - from.GetDistanceToSqrt(m)) / 10; diff --git a/Projects/UOContent/Items/Weapons/Fists.cs b/Projects/UOContent/Items/Weapons/Fists.cs index 8be6fe5ac..b2fe3fc93 100644 --- a/Projects/UOContent/Items/Weapons/Fists.cs +++ b/Projects/UOContent/Items/Weapons/Fists.cs @@ -157,7 +157,7 @@ namespace Server.Items } } - public override TimeSpan OnSwing(Mobile attacker, Mobile defender) + public override TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0) { if (!Core.AOS) { diff --git a/Projects/UOContent/Items/Weapons/Ranged/BaseRanged.cs b/Projects/UOContent/Items/Weapons/Ranged/BaseRanged.cs index 2c66dd3f2..a3a393a33 100644 --- a/Projects/UOContent/Items/Weapons/Ranged/BaseRanged.cs +++ b/Projects/UOContent/Items/Weapons/Ranged/BaseRanged.cs @@ -37,7 +37,7 @@ namespace Server.Items public override SkillName AccuracySkill => SkillName.Archery; - public override TimeSpan OnSwing(Mobile attacker, Mobile defender) + public override TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus = 1.0) { // WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker );