diff --git a/Projects/UOContent/Mobiles/BaseCreature.cs b/Projects/UOContent/Mobiles/BaseCreature.cs index f846378ac..1debdd3cd 100644 --- a/Projects/UOContent/Mobiles/BaseCreature.cs +++ b/Projects/UOContent/Mobiles/BaseCreature.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; +using Server.Collections; using Server.ContextMenus; using Server.Engines.ConPVP; using Server.Engines.MLQuests; @@ -512,11 +512,11 @@ namespace Server.Mobiles public virtual bool DeathAdderCharmable => false; // TODO: Find the pub 31 tweaks to the DispelDifficulty and apply them of course. - public virtual double DispelDifficulty // at this skill level we dispel 50% chance - => 0.0; + // at this skill level we dispel 50% chance + public virtual double DispelDifficulty => 0.0; - public virtual double DispelFocus // at difficulty - focus we have 0%, at difficulty + focus we have 100% - => 20.0; + // at difficulty - focus we have 0%, at difficulty + focus we have 100% + public virtual double DispelFocus => 20.0; public virtual bool DisplayWeight => Backpack is StrongBackpack; @@ -1169,9 +1169,8 @@ namespace Server.Mobiles if (m_MLQuests == null) { - return - MLQuestSystem - .EmptyList; // return EmptyList, but don't cache it (run construction again next time) + // return EmptyList, but don't cache it (run construction again next time) + return MLQuestSystem.EmptyList; } } @@ -1211,7 +1210,7 @@ namespace Server.Mobiles return false; } - if (!(m is BaseCreature c) || m is MilitiaFighter) + if (m is not BaseCreature c || m is MilitiaFighter) { return true; } @@ -2153,11 +2152,8 @@ namespace Server.Mobiles // even if they can't offer you anything at the moment if (MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile mobile) { - MLQuestSystem.Tell( - this, - mobile, - 1074893 - ); // You need to mark your quest items so I don't take the wrong object. Then speak to me. + // You need to mark your quest items so I don't take the wrong object. Then speak to me. + MLQuestSystem.Tell(this, mobile, 1074893); return false; } @@ -2536,8 +2532,8 @@ namespace Server.Mobiles public override bool IsHarmfulCriminal(Mobile target) => (!Controlled || target != m_ControlMaster) && (!Summoned || target != m_SummonMaster) && - (!(target is BaseCreature creature) || !creature.InitialInnocent || creature.Controlled) && - (!(target is PlayerMobile mobile) || mobile.PermaFlags.Count <= 0) && base.IsHarmfulCriminal(target); + (target is not BaseCreature { InitialInnocent: true } creature || creature.Controlled) && + (target is not PlayerMobile mobile || mobile.PermaFlags.Count <= 0) && base.IsHarmfulCriminal(target); public override void CriminalAction(bool message) { @@ -2837,18 +2833,6 @@ namespace Server.Mobiles return null; } - public static void Cap(ref int val, int min, int max) - { - if (val < min) - { - val = min; - } - else if (val > max) - { - val = max; - } - } - public override void OnDoubleClick(Mobile from) { if (from.AccessLevel >= AccessLevel.GameMaster && !Body.IsHuman) @@ -2903,7 +2887,8 @@ namespace Server.Mobiles } else if (Controlled && Commandable) { - if (IsBonded) // Intentional difference (showing ONLY bonded when bonded instead of bonded & tame) + // Intentional difference (showing ONLY bonded when bonded instead of bonded & tame) + if (IsBonded) { list.Add(1049608); // (bonded) } @@ -3028,7 +3013,7 @@ namespace Server.Mobiles { var de = list[i]; - if (de.Damager == m || !(de.Damager is BaseCreature bc)) + if (de.Damager == m || de.Damager is not BaseCreature bc) { continue; } @@ -3144,10 +3129,8 @@ namespace Server.Mobiles if (rights.Count > 0) { - rights[0].m_Damage = - (int)(rights[0].m_Damage * - 1.25 - ); // This would be the first valid person attacking it. Gets a 25% bonus. Per 1/19/07 Five on Friday + // This would be the first valid person attacking it. Gets a 25% bonus. Per 1/19/07 Five on Friday + rights[0].m_Damage = (int)(rights[0].m_Damage * 1.25); if (rights.Count > 1) { @@ -3155,24 +3138,14 @@ namespace Server.Mobiles } var topDamage = rights[0].m_Damage; - int minDamage; - if (hitsMax >= 3000) + int minDamage = hitsMax switch { - minDamage = topDamage / 16; - } - else if (hitsMax >= 1000) - { - minDamage = topDamage / 8; - } - else if (hitsMax >= 200) - { - minDamage = topDamage / 4; - } - else - { - minDamage = topDamage / 2; - } + >= 3000 => topDamage / 16, + >= 1000 => topDamage / 8, + >= 200 => topDamage / 4, + _ => topDamage / 2 + }; for (var i = 0; i < rights.Count; ++i) { @@ -3271,127 +3244,126 @@ namespace Server.Mobiles GiftOfLifeSpell.HandleDeath(this); CheckStatTimers(); + return; } - else - { - if (!Summoned && !NoKillAwards) - { - var totalFame = Fame / 100; - var totalKarma = -Karma / 100; - if (Map == Map.Felucca) + if (!Summoned && !NoKillAwards) + { + var totalFame = Fame / 100; + var totalKarma = -Karma / 100; + + if (Map == Map.Felucca) + { + totalFame += totalFame / 10 * 3; + totalKarma += totalKarma / 10 * 3; + } + + var list = GetLootingRights(DamageEntries, HitsMax); + var titles = new List(); + var fame = new List(); + var karma = new List(); + + var givenQuestKill = false; + var givenFactionKill = false; + var givenToTKill = false; + + for (var i = 0; i < list.Count; ++i) + { + var ds = list[i]; + + if (!ds.m_HasRight) { - totalFame += totalFame / 10 * 3; - totalKarma += totalKarma / 10 * 3; + continue; } - var list = GetLootingRights(DamageEntries, HitsMax); - var titles = new List(); - var fame = new List(); - var karma = new List(); + var party = Engines.PartySystem.Party.Get(ds.m_Mobile); - var givenQuestKill = false; - var givenFactionKill = false; - var givenToTKill = false; - - for (var i = 0; i < list.Count; ++i) + if (party != null) { - var ds = list[i]; + var divedFame = totalFame / party.Members.Count; + var divedKarma = totalKarma / party.Members.Count; - if (!ds.m_HasRight) + for (var j = 0; j < party.Members.Count; ++j) + { + var info = party.Members[j]; + + if (info?.Mobile != null) + { + var index = titles.IndexOf(info.Mobile); + + if (index == -1) + { + titles.Add(info.Mobile); + fame.Add(divedFame); + karma.Add(divedKarma); + } + else + { + fame[index] += divedFame; + karma[index] += divedKarma; + } + } + } + } + else + { + titles.Add(ds.m_Mobile); + fame.Add(totalFame); + karma.Add(totalKarma); + } + + OnKilledBy(ds.m_Mobile); + + if (!givenFactionKill) + { + givenFactionKill = true; + Faction.HandleDeath(this, ds.m_Mobile); + } + + var region = ds.m_Mobile.Region; + + if (!givenToTKill && (Map == Map.Tokuno || region.IsPartOf("Yomotsu Mines") || + region.IsPartOf("Fan Dancer's Dojo"))) + { + givenToTKill = true; + TreasuresOfTokuno.HandleKill(this, ds.m_Mobile); + } + + if (ds.m_Mobile is PlayerMobile pm) + { + if (MLQuestSystem.Enabled) + { + MLQuestSystem.HandleKill(pm, this); + } + + if (givenQuestKill) { continue; } - var party = Engines.PartySystem.Party.Get(ds.m_Mobile); + var qs = pm.Quest; - if (party != null) + if (qs != null) { - var divedFame = totalFame / party.Members.Count; - var divedKarma = totalKarma / party.Members.Count; - - for (var j = 0; j < party.Members.Count; ++j) - { - var info = party.Members[j]; - - if (info?.Mobile != null) - { - var index = titles.IndexOf(info.Mobile); - - if (index == -1) - { - titles.Add(info.Mobile); - fame.Add(divedFame); - karma.Add(divedKarma); - } - else - { - fame[index] += divedFame; - karma[index] += divedKarma; - } - } - } + qs.OnKill(this, c); + givenQuestKill = true; } - else - { - titles.Add(ds.m_Mobile); - fame.Add(totalFame); - karma.Add(totalKarma); - } - - OnKilledBy(ds.m_Mobile); - - if (!givenFactionKill) - { - givenFactionKill = true; - Faction.HandleDeath(this, ds.m_Mobile); - } - - var region = ds.m_Mobile.Region; - - if (!givenToTKill && (Map == Map.Tokuno || region.IsPartOf("Yomotsu Mines") || - region.IsPartOf("Fan Dancer's Dojo"))) - { - givenToTKill = true; - TreasuresOfTokuno.HandleKill(this, ds.m_Mobile); - } - - if (ds.m_Mobile is PlayerMobile pm) - { - if (MLQuestSystem.Enabled) - { - MLQuestSystem.HandleKill(pm, this); - } - - if (givenQuestKill) - { - continue; - } - - var qs = pm.Quest; - - if (qs != null) - { - qs.OnKill(this, c); - givenQuestKill = true; - } - } - } - - for (var i = 0; i < titles.Count; ++i) - { - Titles.AwardFame(titles[i], fame[i], true); - Titles.AwardKarma(titles[i], karma[i], true); } } - base.OnDeath(c); - - if (DeleteCorpseOnDeath) + for (var i = 0; i < titles.Count; ++i) { - c.Delete(); + Titles.AwardFame(titles[i], fame[i], true); + Titles.AwardKarma(titles[i], karma[i], true); } } + + base.OnDeath(c); + + if (DeleteCorpseOnDeath) + { + c.Delete(); + } } public override void OnDelete() @@ -3642,17 +3614,25 @@ namespace Server.Mobiles public virtual bool Rummage() { - var eable = GetItemsInRange(2); - var toRummage = eable.FirstOrDefault(item => item.Items.Count > 0); - - eable.Free(); - - if (toRummage == null) + if (Backpack == null) { return false; } - if (Backpack == null) + var eable = GetItemsInRange(2); + Corpse toRummage = null; + foreach (var c in eable) + { + if (c.Items.Count > 0) + { + toRummage = c; + break; + } + } + + eable.Free(); + + if (toRummage == null) { return false; } @@ -3788,27 +3768,24 @@ namespace Server.Mobiles public static void TeleportPets(Mobile master, Point3D loc, Map map, bool onlyBonded = false) { - var move = new List(); + using var queue = PooledRefQueue.Create(); - foreach (var m in master.GetMobilesInRange(3)) + var eable = master.GetMobilesInRange(3); + foreach (var m in eable) { - if ( - m is BaseCreature { - Controlled: true, - ControlOrder: OrderType.Guard or OrderType.Follow or OrderType.Come - } pet - ) + if (m is BaseCreature + { Controlled: true, ControlOrder: OrderType.Guard or OrderType.Follow or OrderType.Come } pet && + pet.ControlMaster == master && (!onlyBonded || pet.IsBonded)) { - if (pet.ControlMaster == master && (!onlyBonded || pet.IsBonded)) - { - move.Add(pet); - } + queue.Enqueue(pet); } } - foreach (var m in move) + eable.Free(); + + while (queue.Count > 0) { - m.MoveToWorld(loc, map); + queue.Dequeue().MoveToWorld(loc, map); } } @@ -3844,18 +3821,14 @@ namespace Server.Mobiles var owner = ControlMaster; - if (owner?.Deleted != false || owner.Map != Map || !owner.InRange(this, 12) || !CanSee(owner) || - !InLOS(owner)) - { - if (OwnerAbandonTime == DateTime.MinValue) - { - OwnerAbandonTime = Core.Now; - } - } - else + if (owner?.Deleted == false && owner.Map == Map && owner.InRange(this, 12) && CanSee(owner) && InLOS(owner)) { OwnerAbandonTime = DateTime.MinValue; } + else if (OwnerAbandonTime == DateTime.MinValue) + { + OwnerAbandonTime = Core.Now; + } CheckStatTimers(); } @@ -3961,7 +3934,7 @@ namespace Server.Mobiles public void BeginDeleteTimer() { - if (!(this is BaseEscortable) && !Summoned && !Deleted && !IsStabled) + if (this is not BaseEscortable && !Summoned && !Deleted && !IsStabled) { StopDeleteTimer(); m_DeleteTimer = new DeleteTimer(this, TimeSpan.FromDays(3.0)); @@ -4261,40 +4234,13 @@ namespace Server.Mobiles { } - public virtual bool CheckFoodPreference(Item f) - { - if (CheckFoodPreference(f, FoodType.Eggs, m_Eggs)) - { - return true; - } - - if (CheckFoodPreference(f, FoodType.Fish, m_Fish)) - { - return true; - } - - if (CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay)) - { - return true; - } - - if (CheckFoodPreference(f, FoodType.Meat, m_Meat)) - { - return true; - } - - if (CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies)) - { - return true; - } - - if (CheckFoodPreference(f, FoodType.Gold, m_Gold)) - { - return true; - } - - return false; - } + public virtual bool CheckFoodPreference(Item f) => + CheckFoodPreference(f, FoodType.Eggs, m_Eggs) || + CheckFoodPreference(f, FoodType.Fish, m_Fish) || + CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay) || + CheckFoodPreference(f, FoodType.Meat, m_Meat) || + CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies) || + CheckFoodPreference(f, FoodType.Gold, m_Gold); public virtual bool CheckFoodPreference(Item fed, FoodType type, Type[] types) { @@ -4396,9 +4342,8 @@ namespace Server.Mobiles } else if (Core.ML) { - from.SendLocalizedMessage( - 1075268 - ); // Your pet cannot form a bond with you until your animal taming ability has risen. + // Your pet cannot form a bond with you until your animal taming ability has risen. + from.SendLocalizedMessage(1075268); } } } @@ -4454,12 +4399,7 @@ namespace Server.Mobiles return false; } - if (!Core.AOS && (skill == SkillName.Focus || skill == SkillName.Chivalry || skill == SkillName.Necromancy)) - { - return false; - } - - return true; + return Core.AOS || skill != SkillName.Focus && skill != SkillName.Chivalry && skill != SkillName.Necromancy; } public virtual TeachResult CheckTeachSkills( @@ -5033,8 +4973,8 @@ namespace Server.Mobiles return false; } - Cap(ref minLevel, 0, 5); - Cap(ref maxLevel, 0, 5); + minLevel = Math.Clamp(minLevel, 0, 5); + maxLevel = Math.Clamp(maxLevel, 0, 5); if (Core.AOS) { @@ -5121,9 +5061,7 @@ namespace Server.Mobiles if (min > max) { - var hold = min; - min = max; - max = hold; + (min, max) = (max, min); } /* Example: @@ -5204,8 +5142,8 @@ namespace Server.Mobiles return false; } - Cap(ref minLevel, 0, 5); - Cap(ref maxLevel, 0, 5); + minLevel = Math.Clamp(minLevel, 0, 5); + maxLevel = Math.Clamp(maxLevel, 0, 5); if (Core.AOS) { @@ -5481,15 +5419,21 @@ namespace Server.Mobiles } var eable = GetMobilesInRange(AuraRange); - - var list = eable.Where( - m => - m != this && CanBeHarmful(m, false) && (Core.AOS || InLOS(m)) && - (m is BaseCreature bc && (bc.Controlled || bc.Summoned || bc.Team != Team) || m.Player) - ); - - foreach (var m in list) + using var queue = PooledRefQueue.Create(); + foreach (var m in eable) { + if (m != this && CanBeHarmful(m, false) && (Core.AOS || InLOS(m)) && + (m is BaseCreature bc && (bc.Controlled || bc.Summoned || bc.Team != Team) || m.Player)) + { + queue.Enqueue(m); + } + } + eable.Free(); + + while (queue.Count > 0) + { + var m = queue.Dequeue(); + AOS.Damage( m, this, @@ -5503,8 +5447,6 @@ namespace Server.Mobiles ); AuraEffect(m); } - - eable.Free(); } public virtual void AuraEffect(Mobile m) @@ -5599,10 +5541,8 @@ namespace Server.Mobiles private DateTime m_NextHourlyCheck; - public LoyaltyTimer() : base(InternalDelay, InternalDelay) - { + public LoyaltyTimer() : base(InternalDelay, InternalDelay) => m_NextHourlyCheck = Core.Now + TimeSpan.FromHours(1.0); - } public static void Initialize() { @@ -5618,14 +5558,14 @@ namespace Server.Mobiles m_NextHourlyCheck = Core.Now + TimeSpan.FromHours(1.0); - var toRelease = new List(); + using var toRelease = PooledRefQueue.Create(); // added array for wild creatures in house regions to be removed - var toRemove = new List(); + using var toRemove = PooledRefQueue.Create(); foreach (var m in World.Mobiles.Values) { - if (!(m is BaseCreature c)) + if (m is not BaseCreature c) { continue; } @@ -5649,7 +5589,7 @@ namespace Server.Mobiles } else if (c.OwnerAbandonTime + c.BondingAbandonDelay <= Core.Now) { - toRemove.Add(c); + toRemove.Enqueue(c); } } else @@ -5673,7 +5613,7 @@ namespace Server.Mobiles if (c.Loyalty <= 0) { - toRelease.Add(c); + toRelease.Enqueue(c); } } } @@ -5686,7 +5626,7 @@ namespace Server.Mobiles if (c.RemoveStep >= 20) { - toRemove.Add(c); + toRemove.Enqueue(c); } } else @@ -5695,22 +5635,24 @@ namespace Server.Mobiles } } - foreach (var c in toRelease) + while (toRelease.Count > 0) { - c.Say(1043255, c.Name); // ~1_NAME~ appears to have decided that is better off without a master! + var c = toRelease.Dequeue(); + + c.Say(1043255, c.Name); // ~1_NAME~ appears to have decided that is better off without a master! c.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy c.IsBonded = false; c.BondingBegin = DateTime.MinValue; c.OwnerAbandonTime = DateTime.MinValue; c.ControlTarget = null; - c.AIObject - .DoOrderRelease(); // this will prevent no release of creatures left alone with AI disabled (and consequent bug of Followers) + // This will prevent no release of creatures left alone with AI disabled (and consequent bug of Followers) + c.AIObject.DoOrderRelease(); c.DropBackpack(); } - foreach (var c in toRemove) + while (toRemove.Count > 0) { - c.Delete(); + toRemove.Dequeue().Delete(); } } }