From 520f15e46ca1d835dc440bbd692c6b63e005f44e Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Wed, 23 Nov 2022 12:33:27 -0800 Subject: [PATCH] feat: Adds ability groups, DOT abilities, and combat abilities (#1264) - [X] Adds `MonsterAbilitySingleTarget` - [X] Adds `MonsterAbilitySingleTargetDoT` - [X] Adds monster ability groups with weighted abilities - [X] Adds rune corruption ability - [X] Adds poison gas counter ability - [X] Adds stun attack ability - [X] Adds throw hatchet counter ability - [X] Adds fanning fire ability - [X] Fixes destroy equipment to skip spell channel items --- .../Ethics/Evil/Mobiles/UnholySteed.cs | 2 +- .../Engines/Ethics/Hero/Mobiles/HolySteed.cs | 2 +- Projects/UOContent/Misc/AOS.cs | 6 +- .../Mobiles/Abilities/DestroyEquipment.cs | 19 +- .../Mobiles/Abilities/EnergyBoltCounter.cs | 6 +- .../Mobiles/Abilities/FanThrowCounter.cs | 43 +++ .../Mobiles/Abilities/FanningFire.cs | 68 ++++ .../{ => Fire Breath}/ChaosBreath.cs | 0 .../Abilities/{ => Fire Breath}/ColdBreath.cs | 0 .../Abilities/{ => Fire Breath}/FireBreath.cs | 2 +- .../Mobiles/Abilities/GraspingClaw.cs | 66 +--- ...ility.Abilities.cs => MonsterAbilities.cs} | 12 +- ...ttack.cs => MonsterAbilitySingleTarget.cs} | 6 +- .../MonsterAbilitySingleTargetDoT.cs | 79 ++++ .../Mobiles/Abilities/MonsterAbilityType.cs | 5 +- .../Mobiles/Abilities/PoisonGasCounter.cs | 4 +- .../Mobiles/Abilities/RuneCorruption.cs | 162 ++++++++ .../SummonLesserUndeadCounter.cs} | 2 +- .../SummonSkeletonsCounter.cs} | 2 +- .../SummonUndeadCounter.cs} | 2 +- .../Mobiles/Abilities/ThrowHatchetCounter.cs | 4 +- .../Mobiles/Animals/Felines/HellCat.cs | 2 +- .../Animals/Felines/PredatorHellCat.cs | 2 +- .../Mobiles/Animals/Mounts/FireSteed.cs | 2 +- .../Mobiles/Animals/Mounts/HellSteed.cs | 2 +- .../UOContent/Mobiles/Animals/Mounts/Hiryu.cs | 2 +- .../Mobiles/Animals/Mounts/LesserHiryu.cs | 2 +- .../Mobiles/Animals/Mounts/Nightmare.cs | 2 +- .../Mobiles/Animals/Reptiles/LavaLizard.cs | 2 +- .../Mobiles/Animals/Reptiles/LavaSerpent.cs | 2 +- .../Mobiles/Animals/Reptiles/LavaSnake.cs | 2 +- .../Monsters/Humanoid/Magic/AncientLich.cs | 2 +- .../Monsters/Humanoid/Magic/Betrayer.cs | 8 +- .../Monsters/Humanoid/Magic/FireGargoyle.cs | 2 +- .../Humanoid/Magic/GargoyleDestroyer.cs | 2 +- .../Monsters/Humanoid/Magic/LichLord.cs | 2 +- .../Monsters/Humanoid/Magic/Succubus.cs | 2 +- .../Monsters/Humanoid/Melee/Juggernaut.cs | 2 +- .../Monsters/LBR/Exodus/ExodusMinion.cs | 2 +- .../Monsters/LBR/Exodus/ExodusOverseer.cs | 2 +- .../Monsters/LBR/Jukas/ChaosDragoon.cs | 2 +- .../Monsters/LBR/Jukas/ChaosDragoonElite.cs | 2 +- .../Mobiles/Monsters/ML/Bedlam/RedDeath.cs | 2 +- .../Monsters/ML/Blighted Grove/Hydra.cs | 2 +- .../Monsters/ML/Misc/Magic/GreaterDragon.cs | 2 +- .../Monsters/ML/Misc/Melee/Reptalon.cs | 2 +- .../Monsters/Mammal/Melee/HellHound.cs | 2 +- .../Mobiles/Monsters/Misc/Melee/Golem.cs | 2 +- .../Ore Elementals/BronzeElemental.cs | 2 +- .../Ore Elementals/DullCopperElemental.cs | 2 +- .../Ore Elementals/ValoriteElemental.cs | 2 +- .../Ore Elementals/VeriteElemental.cs | 2 +- .../Monsters/Reptile/Magic/AncientWyrm.cs | 2 +- .../Monsters/Reptile/Magic/DeepSeaSerpent.cs | 2 +- .../Mobiles/Monsters/Reptile/Magic/Dragon.cs | 2 +- .../Monsters/Reptile/Magic/SeaSerpent.cs | 2 +- .../Reptile/Magic/SerpentineDragon.cs | 2 +- .../Monsters/Reptile/Magic/ShadowWyrm.cs | 2 +- .../Monsters/Reptile/Magic/SkeletalDragon.cs | 2 +- .../Mobiles/Monsters/Reptile/Melee/Drake.cs | 2 +- .../Mobiles/Monsters/SE/FanDancer.cs | 250 ++++-------- .../Mobiles/Monsters/SE/RuneBeetle.cs | 364 +++++------------- 62 files changed, 644 insertions(+), 546 deletions(-) create mode 100644 Projects/UOContent/Mobiles/Abilities/FanThrowCounter.cs create mode 100644 Projects/UOContent/Mobiles/Abilities/FanningFire.cs rename Projects/UOContent/Mobiles/Abilities/{ => Fire Breath}/ChaosBreath.cs (100%) rename Projects/UOContent/Mobiles/Abilities/{ => Fire Breath}/ColdBreath.cs (100%) rename Projects/UOContent/Mobiles/Abilities/{ => Fire Breath}/FireBreath.cs (99%) rename Projects/UOContent/Mobiles/Abilities/{MonsterAbility.Abilities.cs => MonsterAbilities.cs} (66%) rename Projects/UOContent/Mobiles/Abilities/{MonsterAbilityAttack.cs => MonsterAbilitySingleTarget.cs} (75%) create mode 100644 Projects/UOContent/Mobiles/Abilities/MonsterAbilitySingleTargetDoT.cs create mode 100644 Projects/UOContent/Mobiles/Abilities/RuneCorruption.cs rename Projects/UOContent/Mobiles/Abilities/{SummonLesserUndead.cs => Summon Undead/SummonLesserUndeadCounter.cs} (92%) rename Projects/UOContent/Mobiles/Abilities/{SummonSkeletons.cs => Summon Undead/SummonSkeletonsCounter.cs} (67%) rename Projects/UOContent/Mobiles/Abilities/{SummonUndead.cs => Summon Undead/SummonUndeadCounter.cs} (97%) diff --git a/Projects/UOContent/Engines/Ethics/Evil/Mobiles/UnholySteed.cs b/Projects/UOContent/Engines/Ethics/Evil/Mobiles/UnholySteed.cs index b20cfb1bd..3388af223 100644 --- a/Projects/UOContent/Engines/Ethics/Evil/Mobiles/UnholySteed.cs +++ b/Projects/UOContent/Engines/Ethics/Evil/Mobiles/UnholySteed.cs @@ -49,7 +49,7 @@ namespace Server.Mobiles public override bool IsBondable => false; public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override string ApplyNameSuffix(string suffix) diff --git a/Projects/UOContent/Engines/Ethics/Hero/Mobiles/HolySteed.cs b/Projects/UOContent/Engines/Ethics/Hero/Mobiles/HolySteed.cs index 1f9c06a18..1999d3f70 100644 --- a/Projects/UOContent/Engines/Ethics/Hero/Mobiles/HolySteed.cs +++ b/Projects/UOContent/Engines/Ethics/Hero/Mobiles/HolySteed.cs @@ -48,7 +48,7 @@ namespace Server.Mobiles public override bool IsBondable => false; public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override string ApplyNameSuffix(string suffix) diff --git a/Projects/UOContent/Misc/AOS.cs b/Projects/UOContent/Misc/AOS.cs index 381a9ea6f..eadddc2b1 100644 --- a/Projects/UOContent/Misc/AOS.cs +++ b/Projects/UOContent/Misc/AOS.cs @@ -199,10 +199,10 @@ namespace Server if (from is { Deleted: false, Alive: true }) { var reflectPhys = AosAttributes.GetValue(m, AosAttribute.ReflectPhysical); - var reflectPhysAbility = bcFrom?.GetAbility(MonsterAbilityType.ReflectPhysicalDamage) as ReflectPhysicalDamage; + var reflectPhysAbility = bcFrom + ?.GetAbility(MonsterAbilityType.ReflectPhysicalDamage) as ReflectPhysicalDamage; - if (reflectPhysAbility - ?.CanTrigger(bcFrom, MonsterAbilityTrigger.CombatAction) == true) + if (reflectPhysAbility?.CanTrigger(bcFrom, MonsterAbilityTrigger.CombatAction) == true) { reflectPhys += reflectPhysAbility.PercentReflected; m.SendLocalizedMessage(1070844); // The creature repels the attack back at you. diff --git a/Projects/UOContent/Mobiles/Abilities/DestroyEquipment.cs b/Projects/UOContent/Mobiles/Abilities/DestroyEquipment.cs index 3a6d40282..e193add32 100644 --- a/Projects/UOContent/Mobiles/Abilities/DestroyEquipment.cs +++ b/Projects/UOContent/Mobiles/Abilities/DestroyEquipment.cs @@ -4,7 +4,7 @@ using Server.Network; namespace Server.Mobiles; -public class DestroyEquipment : MonsterAbilityAttack +public class DestroyEquipment : MonsterAbilitySingleTarget { public override MonsterAbilityType AbilityType => MonsterAbilityType.DestroyEquipment; public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.GiveMeleeDamage; @@ -12,9 +12,9 @@ public class DestroyEquipment : MonsterAbilityAttack public virtual int AttackRange => 1; - protected override void OnAttack(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + protected override void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) { - base.OnAttack(trigger, source, defender); + base.OnTarget(trigger, source, defender); using var queue = PooledRefQueue.Create(); for (var i = 0; i < defender.Items.Count; i++) @@ -25,7 +25,18 @@ public class DestroyEquipment : MonsterAbilityAttack continue; } - if (!(Mobile.InsuranceEnabled && item.Insured) && item is IDurability { MaxHitPoints: > 0 }) + if (Mobile.InsuranceEnabled && item.Insured) + { + continue; + } + + // Late publish AOS, do not destroy equipment that mages use + if (item is IAosItem { Attributes.SpellChanneling: > 0 }) + { + continue; + } + + if (item is IDurability { MaxHitPoints: > 0 }) { queue.Enqueue(item); } diff --git a/Projects/UOContent/Mobiles/Abilities/EnergyBoltCounter.cs b/Projects/UOContent/Mobiles/Abilities/EnergyBoltCounter.cs index 6a2c84816..a1d0b3491 100644 --- a/Projects/UOContent/Mobiles/Abilities/EnergyBoltCounter.cs +++ b/Projects/UOContent/Mobiles/Abilities/EnergyBoltCounter.cs @@ -2,15 +2,15 @@ namespace Server.Mobiles; -public class EnergyBoltCounter : MonsterAbilityAttack +public class EnergyBoltCounter : MonsterAbilitySingleTarget { public override MonsterAbilityType AbilityType => MonsterAbilityType.EnergyBoltCounter; public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.TakeDamage; // Ranged attackers public override double ChanceToTrigger => 0.4; - protected override void OnAttack(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + protected override void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) { - base.OnAttack(trigger, source, defender); + base.OnTarget(trigger, source, defender); source.MovingParticles(defender, 0x379F, 7, 0, false, true, 0xBE3, 0xFCB, 0x211); defender.PlaySound(0x229); diff --git a/Projects/UOContent/Mobiles/Abilities/FanThrowCounter.cs b/Projects/UOContent/Mobiles/Abilities/FanThrowCounter.cs new file mode 100644 index 000000000..0fb12219b --- /dev/null +++ b/Projects/UOContent/Mobiles/Abilities/FanThrowCounter.cs @@ -0,0 +1,43 @@ +namespace Server.Mobiles; + +public class FanThrowCounter : MonsterAbilitySingleTarget +{ + public override MonsterAbilityType AbilityType => MonsterAbilityType.EnergyBoltCounter; + public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.TakeDamage; + public override double ChanceToTrigger => 0.2; + + protected override void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + { + base.OnTarget(trigger, source, defender); + + /* Fan Throw + * Effect: + * - To: "0x57D4F5B" + * - ItemId: "0x27A3" + * - ItemIdName: "Tessen" + * - FromLocation: "(992 299, 24)" + * - ToLocation: "(992 308, 22)" + * - Speed: "10" + * - Duration: "0" + * - FixedDirection: "False" + * - Explode: "False" + * - Hue: "0x0" + * - Render: "0x0" + * Damage: 50-65 + */ + Effects.SendMovingEffect( + defender.Location, + defender.Map, + 0x27A3, + source.Location, + defender.Location, + 10, + 0 + ); + + AOS.Damage(defender, source, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); + } + + protected override bool CanEffectTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) => + base.CanEffectTarget(trigger, source, defender) && !defender.InRange(source, 1); +} diff --git a/Projects/UOContent/Mobiles/Abilities/FanningFire.cs b/Projects/UOContent/Mobiles/Abilities/FanningFire.cs new file mode 100644 index 000000000..4014acbe8 --- /dev/null +++ b/Projects/UOContent/Mobiles/Abilities/FanningFire.cs @@ -0,0 +1,68 @@ +namespace Server.Mobiles; + +public class FanningFire : MonsterAbilitySingleTargetDoT +{ + public override MonsterAbilityType AbilityType => MonsterAbilityType.FanningFire; + public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.GiveDamage; + public override double ChanceToTrigger => 0.05; + + public const string Name = "FanningFire"; + + protected override void StartEffect(BaseCreature source, Mobile defender) + { + /** + * Fanning Fire + * Start cliloc: 1070833 + * Effect: Fire res -10% for 10 seconds. Does not stack. + * Damage: 35-45, 100% fire + * End cliloc: 1070834 + * Sound: 0x208 + * Graphic: + * - Type: "3" + * - From: "0x57D4F5B" + * - To: "0x0" + * - ItemId: "0x3709" + * - ItemIdName: "fire column" + * - FromLocation: "(994 325, 16)" + * - ToLocation: "(994 325, 16)" + * - Speed: "10" + * - Duration: "30" + * - FixedDirection: "True" + * - Explode: "False" + * - Hue: "0x0" + * - RenderMode: "0x0" + * - Effect: "0x34" + * - ExplodeEffect: "0x1" + * - ExplodeSound: "0x0" + * - Layer: "5" + * - Unknown: "0x0" + */ + + RemoveEffect(source, defender); + + // The creature fans you with fire, reducing your resistance to fire attacks. + defender.SendLocalizedMessage(1070833); + + var effect = -(defender.FireResistance / 10); + + var mod = new ResistanceMod(ResistanceType.Fire, Name, effect); + defender.AddResistanceMod(mod); + + defender.FixedParticles(0x37B9, 10, 30, 0x34, EffectLayer.RightFoot); + defender.PlaySound(0x208); + + // TODO: Trigger replaces a normal attack. + AOS.Damage(defender, source, Utility.RandomMinMax(35, 45), 0, 100, 0, 0, 0); + } + + protected override void EndEffect(BaseCreature source, Mobile defender) + { + defender.RemoveResistanceMod(Name); + } + + protected override void OnEffectExpired(BaseCreature source, Mobile defender) + { + // Your resistance to fire attacks has returned. + defender.SendLocalizedMessage(1070834); + } +} diff --git a/Projects/UOContent/Mobiles/Abilities/ChaosBreath.cs b/Projects/UOContent/Mobiles/Abilities/Fire Breath/ChaosBreath.cs similarity index 100% rename from Projects/UOContent/Mobiles/Abilities/ChaosBreath.cs rename to Projects/UOContent/Mobiles/Abilities/Fire Breath/ChaosBreath.cs diff --git a/Projects/UOContent/Mobiles/Abilities/ColdBreath.cs b/Projects/UOContent/Mobiles/Abilities/Fire Breath/ColdBreath.cs similarity index 100% rename from Projects/UOContent/Mobiles/Abilities/ColdBreath.cs rename to Projects/UOContent/Mobiles/Abilities/Fire Breath/ColdBreath.cs diff --git a/Projects/UOContent/Mobiles/Abilities/FireBreath.cs b/Projects/UOContent/Mobiles/Abilities/Fire Breath/FireBreath.cs similarity index 99% rename from Projects/UOContent/Mobiles/Abilities/FireBreath.cs rename to Projects/UOContent/Mobiles/Abilities/Fire Breath/FireBreath.cs index d5c17f755..cfdb6307c 100644 --- a/Projects/UOContent/Mobiles/Abilities/FireBreath.cs +++ b/Projects/UOContent/Mobiles/Abilities/Fire Breath/FireBreath.cs @@ -5,7 +5,7 @@ namespace Server.Mobiles; public class FireBreath : MonsterAbility { - public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.Think; + public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.CombatAction; public override MonsterAbilityType AbilityType => MonsterAbilityType.FireBreath; public override double ChanceToTrigger => 0.5; diff --git a/Projects/UOContent/Mobiles/Abilities/GraspingClaw.cs b/Projects/UOContent/Mobiles/Abilities/GraspingClaw.cs index a1eccb911..d5b35bfe0 100644 --- a/Projects/UOContent/Mobiles/Abilities/GraspingClaw.cs +++ b/Projects/UOContent/Mobiles/Abilities/GraspingClaw.cs @@ -1,27 +1,23 @@ -using System; -using System.Collections.Generic; +namespace Server.Mobiles; -namespace Server.Mobiles; - -public class GraspingClaw : MonsterAbility +public class GraspingClaw : MonsterAbilitySingleTargetDoT { - private Dictionary _table; - public override MonsterAbilityType AbilityType => MonsterAbilityType.GraspingClaw; public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.GiveMeleeDamage; public override double ChanceToTrigger => 0.10; - public override void Trigger(MonsterAbilityTrigger trigger, BaseCreature source, Mobile target) + private const string Name = "GraspingClaw"; + + protected override void StartEffect(BaseCreature source, Mobile defender) { - if (_table.Remove(target, out var timer)) + if (RemoveEffect(source, defender)) { - timer.DoExpire(); - target.SendLocalizedMessage(1070837); // The creature lands another blow in your weakened state. + defender.SendLocalizedMessage(1070837); // The creature lands another blow in your weakened state. } else { // The blow from the creature's claws has made you more susceptible to physical attacks. - target.SendLocalizedMessage(1070836); + defender.SendLocalizedMessage(1070836); } /** @@ -30,7 +26,7 @@ public class GraspingClaw : MonsterAbility * Effect: Physical resistance -15% for 5 seconds * Refresh Cliloc: 1070837 * End cliloc: 1070838 - * Effect: + * Graphic: * - Type: "3" * - From: Player * - To: 0x0 @@ -42,46 +38,20 @@ public class GraspingClaw : MonsterAbility * - FixedDirection: "True" * - Explode: "False" */ - var effect = -(target.PhysicalResistance * 15 / 100); - var mod = new ResistanceMod(ResistanceType.Physical, "GraspingClaw", effect); + var mod = new ResistanceMod(ResistanceType.Physical, Name, -(defender.PhysicalResistance * 15 / 100)); + defender.AddResistanceMod(mod); - target.FixedEffect(0x37B9, 10, 5); - target.AddResistanceMod(mod); - - timer = new ExpireTimer(this, target, mod, TimeSpan.FromSeconds(5.0)); - timer.Start(); - - _table ??= new Dictionary(); - _table[target] = timer; - - base.Trigger(trigger, source, target); + defender.FixedEffect(0x37B9, 10, 5); } - private class ExpireTimer : Timer + protected override void EndEffect(BaseCreature source, Mobile defender) { - private GraspingClaw _graspingClaw; - private Mobile _mobile; - private ResistanceMod _mod; + defender.RemoveResistanceMod(Name); + } - public ExpireTimer(GraspingClaw claw, Mobile m, ResistanceMod mod, TimeSpan delay) : base(delay) - { - _mobile = m; - _mod = mod; - _graspingClaw = claw; - } - - public void DoExpire() - { - _mobile.RemoveResistanceMod(_mod); - Stop(); - _graspingClaw._table?.Remove(_mobile); - } - - protected override void OnTick() - { - _mobile.SendLocalizedMessage(1070838); // Your resistance to physical attacks has returned. - DoExpire(); - } + protected override void OnEffectExpired(BaseCreature source, Mobile defender) + { + defender.SendLocalizedMessage(1070838); // Your resistance to physical attacks has returned. } } diff --git a/Projects/UOContent/Mobiles/Abilities/MonsterAbility.Abilities.cs b/Projects/UOContent/Mobiles/Abilities/MonsterAbilities.cs similarity index 66% rename from Projects/UOContent/Mobiles/Abilities/MonsterAbility.Abilities.cs rename to Projects/UOContent/Mobiles/Abilities/MonsterAbilities.cs index 44e8a8c5f..470d3c46a 100644 --- a/Projects/UOContent/Mobiles/Abilities/MonsterAbility.Abilities.cs +++ b/Projects/UOContent/Mobiles/Abilities/MonsterAbilities.cs @@ -1,17 +1,20 @@ namespace Server.Mobiles; -public abstract partial class MonsterAbility +public static class MonsterAbilities { // Fire Breath public static FireBreath FireBreath => new(); public static ChaosBreath ChaosBreath => new(); public static ColdBreath ColdBreath => new(); + // Resistance Debuffs public static GraspingClaw GraspingClaw => new(); + public static RuneCorruption RuneCorruption => new(); + public static FanningFire FanningFire => new(); // Summon Undead - public static SummonSkeletons SummonSkeletons => new(); - public static SummonLesserUndead SummonLesserUndead => new(); + public static SummonSkeletonsCounter SummonSkeletonsCounter => new(); + public static SummonLesserUndeadCounter SummonLesserUndeadCounter => new(); // Stun public static ColossalBlow ColossalBlow => new(); @@ -26,10 +29,13 @@ public abstract partial class MonsterAbility // Direct attack counters public static ThrowHatchetCounter ThrowHatchetCounter => new(); public static EnergyBoltCounter EnergyBoltCounter => new(); + public static FanThrowCounter FanThrowCounter => new(); public static DestroyEquipment DestroyEquipment => new(); public static DrainLifeAreaAttack DrainLifeAreaAttack => new(); public static MagicalBarrier MagicalBarrier => new(); + + public static ReflectPhysicalDamage ReflectPhysicalDamage => new(); } diff --git a/Projects/UOContent/Mobiles/Abilities/MonsterAbilityAttack.cs b/Projects/UOContent/Mobiles/Abilities/MonsterAbilitySingleTarget.cs similarity index 75% rename from Projects/UOContent/Mobiles/Abilities/MonsterAbilityAttack.cs rename to Projects/UOContent/Mobiles/Abilities/MonsterAbilitySingleTarget.cs index 0d7a27ebc..54313d3bc 100644 --- a/Projects/UOContent/Mobiles/Abilities/MonsterAbilityAttack.cs +++ b/Projects/UOContent/Mobiles/Abilities/MonsterAbilitySingleTarget.cs @@ -1,18 +1,18 @@ namespace Server.Mobiles; -public abstract class MonsterAbilityAttack : MonsterAbility +public abstract class MonsterAbilitySingleTarget : MonsterAbility { public override void Trigger(MonsterAbilityTrigger trigger, BaseCreature source, Mobile target) { if (CanEffectTarget(trigger, source, target)) { - OnAttack(trigger, source, target); + OnTarget(trigger, source, target); } base.Trigger(trigger, source, target); } - protected virtual void OnAttack(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + protected virtual void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) { source.DoHarmful(defender); } diff --git a/Projects/UOContent/Mobiles/Abilities/MonsterAbilitySingleTargetDoT.cs b/Projects/UOContent/Mobiles/Abilities/MonsterAbilitySingleTargetDoT.cs new file mode 100644 index 000000000..4d162a6a2 --- /dev/null +++ b/Projects/UOContent/Mobiles/Abilities/MonsterAbilitySingleTargetDoT.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; + +namespace Server.Mobiles; + +public abstract class MonsterAbilitySingleTargetDoT : MonsterAbilitySingleTarget +{ + private Dictionary _table; + + public virtual TimeSpan MinDelay => TimeSpan.FromSeconds(10.0); + public virtual TimeSpan MaxDelay => TimeSpan.FromSeconds(10.0); + + protected override void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + { + _table ??= new Dictionary(); + + var duration = Utility.RandomMinMax(MinDelay, MaxDelay); + var count = GetCount(source, defender); + var timer = _table[defender] = new ExpireTimer(this, source, defender, duration, count); + timer.Start(); + + StartEffect(source, defender); + } + + protected virtual int GetCount(BaseCreature source, Mobile defender) => 1; + + protected abstract void StartEffect(BaseCreature source, Mobile defender); + + protected virtual void EffectTick(BaseCreature source, Mobile defender, out TimeSpan nextDelay) + { + nextDelay = Utility.RandomMinMax(MinDelay, MaxDelay); + } + + protected abstract void EndEffect(BaseCreature source, Mobile defender); + protected abstract void OnEffectExpired(BaseCreature source, Mobile defender); + + public bool IsUnderEffect(Mobile defender) => _table?.ContainsKey(defender) == true; + + protected bool RemoveEffect(BaseCreature source, Mobile defender) + { + if (_table?.Remove(defender, out var timer) == true) + { + timer.Stop(); + EndEffect(source, defender); + return true; + } + + return false; + } + + private class ExpireTimer : Timer + { + private BaseCreature _source; + private Mobile _defender; + private MonsterAbilitySingleTargetDoT _ability; + + public ExpireTimer( + MonsterAbilitySingleTargetDoT ability, + BaseCreature source, + Mobile defender, + TimeSpan delay, + int count + ) : base(delay, delay, count) + { + _ability = ability; + _source = source; + _defender = defender; + } + + protected override void OnTick() + { + _ability.EffectTick(_source, _defender, out var delay); + Delay = delay; + + _ability.RemoveEffect(_source, _defender); + _ability.OnEffectExpired(_source, _defender); + } + } +} diff --git a/Projects/UOContent/Mobiles/Abilities/MonsterAbilityType.cs b/Projects/UOContent/Mobiles/Abilities/MonsterAbilityType.cs index 9a2c7fdb4..30e230103 100644 --- a/Projects/UOContent/Mobiles/Abilities/MonsterAbilityType.cs +++ b/Projects/UOContent/Mobiles/Abilities/MonsterAbilityType.cs @@ -15,5 +15,8 @@ public enum MonsterAbilityType MassDrainLife, MagicalBarrier, EnergyBoltCounter, - ReflectPhysicalDamage + ReflectPhysicalDamage, + FanningFire, // Fire debuff + RuneCorruption, + FanThrow } diff --git a/Projects/UOContent/Mobiles/Abilities/PoisonGasCounter.cs b/Projects/UOContent/Mobiles/Abilities/PoisonGasCounter.cs index 96dac201e..8a3da763d 100644 --- a/Projects/UOContent/Mobiles/Abilities/PoisonGasCounter.cs +++ b/Projects/UOContent/Mobiles/Abilities/PoisonGasCounter.cs @@ -1,6 +1,6 @@ namespace Server.Mobiles; -public class PoisonGasCounter : MonsterAbilityAttack +public class PoisonGasCounter : MonsterAbilitySingleTarget { public override MonsterAbilityType AbilityType => MonsterAbilityType.Poison; public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.TakeDamage; @@ -11,7 +11,7 @@ public class PoisonGasCounter : MonsterAbilityAttack protected override bool CanEffectTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) => source.InRange(defender, AttackRange) && defender is not BaseCreature { BardProvoked: true }; - protected override void OnAttack(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + protected override void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) { source.Animate(10, 4, 1, true, false, 0); AOS.Damage(defender, source, 50, 100, 0, 0, 0, 0, 0); diff --git a/Projects/UOContent/Mobiles/Abilities/RuneCorruption.cs b/Projects/UOContent/Mobiles/Abilities/RuneCorruption.cs new file mode 100644 index 000000000..552c5da26 --- /dev/null +++ b/Projects/UOContent/Mobiles/Abilities/RuneCorruption.cs @@ -0,0 +1,162 @@ +namespace Server.Mobiles; + +public class RuneCorruption : MonsterAbilitySingleTargetDoT +{ + public override MonsterAbilityType AbilityType => MonsterAbilityType.RuneCorruption; + public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.GiveMeleeDamage; + public override double ChanceToTrigger => 0.05; + + private const string Name = "RuneCorruption"; + + protected override void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + { + if (RemoveEffect(source, defender)) + { + defender.SendLocalizedMessage(1070845); // The creature continues to corrupt your armor! + } + else + { + defender.SendLocalizedMessage(1070846); // The creature magically corrupts your armor! + } + + base.OnTarget(trigger, source, defender); + } + + protected override void StartEffect(BaseCreature source, Mobile defender) + { + /** + * Rune Corruption + * Start cliloc: 1070846 "The creature magically corrupts your armor!" + * Effect: All resistances -70 (lowest 0) for 5 seconds + * End ASCII: "The corruption of your armor has worn off" + */ + + if (Core.ML) + { + if (defender.PhysicalResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Physical, + Name, + -(defender.PhysicalResistance / 2) + ) + ); + } + + if (defender.FireResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Fire, + Name, + -(defender.FireResistance / 2) + ) + ); + } + + if (defender.ColdResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Cold, + Name, + -(defender.ColdResistance / 2) + ) + ); + } + + if (defender.PoisonResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Poison, + Name, + -(defender.PoisonResistance / 2) + ) + ); + } + + if (defender.EnergyResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Energy, + Name, + -(defender.EnergyResistance / 2) + ) + ); + } + } + else + { + if (defender.PhysicalResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Physical, + Name, + defender.PhysicalResistance > 70 ? -70 : -defender.PhysicalResistance + ) + ); + } + + if (defender.FireResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Fire, + Name, + defender.FireResistance > 70 ? -70 : -defender.FireResistance + ) + ); + } + + if (defender.ColdResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Cold, + Name, + defender.ColdResistance > 70 ? -70 : -defender.ColdResistance + ) + ); + } + + if (defender.PoisonResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Poison, + Name, + defender.PoisonResistance > 70 ? -70 : -defender.PoisonResistance + ) + ); + } + + if (defender.EnergyResistance > 0) + { + defender.AddResistanceMod( + new ResistanceMod( + ResistanceType.Energy, + Name, + defender.EnergyResistance > 70 ? -70 : -defender.EnergyResistance + ) + ); + } + } + + defender.FixedEffect(0x37B9, 10, 5); + } + + protected override void EndEffect(BaseCreature source, Mobile defender) + { + defender.RemoveResistanceMod(Name); + } + + protected override void OnEffectExpired(BaseCreature source, Mobile defender) + { + + defender.SendLocalizedMessage(1071967); // The corruption of your armor has worn off + } +} diff --git a/Projects/UOContent/Mobiles/Abilities/SummonLesserUndead.cs b/Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonLesserUndeadCounter.cs similarity index 92% rename from Projects/UOContent/Mobiles/Abilities/SummonLesserUndead.cs rename to Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonLesserUndeadCounter.cs index 346fccb75..8181294fe 100644 --- a/Projects/UOContent/Mobiles/Abilities/SummonLesserUndead.cs +++ b/Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonLesserUndeadCounter.cs @@ -1,6 +1,6 @@ namespace Server.Mobiles; -public class SummonLesserUndead : SummonUndead +public class SummonLesserUndeadCounter : SummonUndeadCounter { private int _group; diff --git a/Projects/UOContent/Mobiles/Abilities/SummonSkeletons.cs b/Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonSkeletonsCounter.cs similarity index 67% rename from Projects/UOContent/Mobiles/Abilities/SummonSkeletons.cs rename to Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonSkeletonsCounter.cs index 187008428..20d4e7827 100644 --- a/Projects/UOContent/Mobiles/Abilities/SummonSkeletons.cs +++ b/Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonSkeletonsCounter.cs @@ -1,6 +1,6 @@ namespace Server.Mobiles; -public class SummonSkeletons : SummonUndead +public class SummonSkeletonsCounter : SummonUndeadCounter { public override BaseCreature CreateSummon(BaseCreature source) => new Skeleton(); } diff --git a/Projects/UOContent/Mobiles/Abilities/SummonUndead.cs b/Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonUndeadCounter.cs similarity index 97% rename from Projects/UOContent/Mobiles/Abilities/SummonUndead.cs rename to Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonUndeadCounter.cs index 3412dafb7..29c1f900d 100644 --- a/Projects/UOContent/Mobiles/Abilities/SummonUndead.cs +++ b/Projects/UOContent/Mobiles/Abilities/Summon Undead/SummonUndeadCounter.cs @@ -2,7 +2,7 @@ namespace Server.Mobiles; -public abstract class SummonUndead : MonsterAbility +public abstract class SummonUndeadCounter : MonsterAbility { public override MonsterAbilityType AbilityType => MonsterAbilityType.SummonUndead; public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.TakeDamage; diff --git a/Projects/UOContent/Mobiles/Abilities/ThrowHatchetCounter.cs b/Projects/UOContent/Mobiles/Abilities/ThrowHatchetCounter.cs index ef09a5e88..a64360737 100644 --- a/Projects/UOContent/Mobiles/Abilities/ThrowHatchetCounter.cs +++ b/Projects/UOContent/Mobiles/Abilities/ThrowHatchetCounter.cs @@ -2,13 +2,13 @@ namespace Server.Mobiles; -public class ThrowHatchetCounter : MonsterAbilityAttack +public class ThrowHatchetCounter : MonsterAbilitySingleTarget { public override MonsterAbilityType AbilityType => MonsterAbilityType.ThrowWeapon; public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.TakeDamage; public override double ChanceToTrigger => 0.4; - protected override void OnAttack(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + protected override void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) { source.MovingEffect(defender, 0xF43, 10, 0, false, false); AOS.Damage(defender, source, 50, 100, 0, 0, 0, 0, 0); diff --git a/Projects/UOContent/Mobiles/Animals/Felines/HellCat.cs b/Projects/UOContent/Mobiles/Animals/Felines/HellCat.cs index bd707049f..abdc73de0 100644 --- a/Projects/UOContent/Mobiles/Animals/Felines/HellCat.cs +++ b/Projects/UOContent/Mobiles/Animals/Felines/HellCat.cs @@ -51,7 +51,7 @@ namespace Server.Mobiles public override FoodType FavoriteFood => FoodType.Meat; public override PackInstinct PackInstinct => PackInstinct.Feline; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Animals/Felines/PredatorHellCat.cs b/Projects/UOContent/Mobiles/Animals/Felines/PredatorHellCat.cs index fd08af802..40bd2e08e 100644 --- a/Projects/UOContent/Mobiles/Animals/Felines/PredatorHellCat.cs +++ b/Projects/UOContent/Mobiles/Animals/Felines/PredatorHellCat.cs @@ -49,7 +49,7 @@ namespace Server.Mobiles public override FoodType FavoriteFood => FoodType.Meat; public override PackInstinct PackInstinct => PackInstinct.Feline; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/FireSteed.cs b/Projects/UOContent/Mobiles/Animals/Mounts/FireSteed.cs index ec3cf46cb..6419ebc2f 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/FireSteed.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/FireSteed.cs @@ -52,7 +52,7 @@ namespace Server.Mobiles public override FoodType FavoriteFood => FoodType.Meat; public override PackInstinct PackInstinct => PackInstinct.Daemon | PackInstinct.Equine; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/HellSteed.cs b/Projects/UOContent/Mobiles/Animals/Mounts/HellSteed.cs index d6a127aae..169cf87b6 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/HellSteed.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/HellSteed.cs @@ -17,7 +17,7 @@ namespace Server.Mobiles public override string CorpseName => "a hellsteed corpse"; public override Poison PoisonImmune => Poison.Lethal; - private static MonsterAbility[] _abilities = { MonsterAbility.ChaosBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.ChaosBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public static void SetStats(BaseCreature steed) diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Hiryu.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Hiryu.cs index dacf3d919..59194cb59 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Hiryu.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Hiryu.cs @@ -68,7 +68,7 @@ public class Hiryu : BaseMount public override FoodType FavoriteFood => FoodType.Meat; public override bool CanAngerOnTame => true; - private static MonsterAbility[] _abilities = { MonsterAbility.GraspingClaw }; + private static MonsterAbility[] _abilities = { MonsterAbilities.GraspingClaw }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/LesserHiryu.cs b/Projects/UOContent/Mobiles/Animals/Mounts/LesserHiryu.cs index a172e5f35..976e96f72 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/LesserHiryu.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/LesserHiryu.cs @@ -65,7 +65,7 @@ public class LesserHiryu : BaseMount public override WeaponAbility GetWeaponAbility() => WeaponAbility.Dismount; - private static MonsterAbility[] _abilities = { MonsterAbility.GraspingClaw }; + private static MonsterAbility[] _abilities = { MonsterAbilities.GraspingClaw }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; private static int GetHue() diff --git a/Projects/UOContent/Mobiles/Animals/Mounts/Nightmare.cs b/Projects/UOContent/Mobiles/Animals/Mounts/Nightmare.cs index 6ac0e4d15..f001e7c25 100644 --- a/Projects/UOContent/Mobiles/Animals/Mounts/Nightmare.cs +++ b/Projects/UOContent/Mobiles/Animals/Mounts/Nightmare.cs @@ -98,7 +98,7 @@ namespace Server.Mobiles public override FoodType FavoriteFood => FoodType.Meat; public override bool CanAngerOnTame => true; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaLizard.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaLizard.cs index 41c64e24f..06e6b1990 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaLizard.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaLizard.cs @@ -53,7 +53,7 @@ namespace Server.Mobiles public override int Hides => 12; public override HideType HideType => HideType.Spined; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSerpent.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSerpent.cs index 8a6610fbf..bcf22e135 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSerpent.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSerpent.cs @@ -54,7 +54,7 @@ namespace Server.Mobiles public override int Hides => 15; public override HideType HideType => HideType.Spined; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSnake.cs b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSnake.cs index 22e40f010..c99c80679 100644 --- a/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSnake.cs +++ b/Projects/UOContent/Mobiles/Animals/Reptiles/LavaSnake.cs @@ -50,7 +50,7 @@ namespace Server.Mobiles public override bool DeathAdderCharmable => true; public override int Meat => 1; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs index 79ec5e21c..3b1f15390 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs @@ -73,7 +73,7 @@ namespace Server.Mobiles AddLoot(LootPack.MedScrolls, 2); } - private static MonsterAbility[] _abilities = { MonsterAbility.SummonLesserUndead }; + private static MonsterAbility[] _abilities = { MonsterAbilities.SummonLesserUndeadCounter }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void Serialize(IGenericWriter writer) diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs index 026ddd579..9e86619e1 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs @@ -98,7 +98,13 @@ public class Betrayer : BaseCreature AddLoot(LootPack.Gems, 1); } - private static MonsterAbility[] _abilities = { MonsterAbility.ColossalBlow, MonsterAbility.PoisonGasAreaAttack }; + private static MonsterAbility[] _abilities = + { + new MonsterAbilityGroup( + (1, MonsterAbilities.ColossalBlow), + (1, MonsterAbilities.PoisonGasAreaAttack) + ) + }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void Serialize(IGenericWriter writer) diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs index de159d11d..a0d083680 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs @@ -49,7 +49,7 @@ namespace Server.Mobiles public override int Meat => 1; public override bool CanFly => true; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs index 7059e5480..e4cb35ae0 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs @@ -57,7 +57,7 @@ public class GargoyleDestroyer : BaseCreature public override int Meat => 1; public override bool CanFly => true; - private static MonsterAbility[] _abilities = { MonsterAbility.ThrowHatchetCounter }; + private static MonsterAbility[] _abilities = { MonsterAbilities.ThrowHatchetCounter }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/LichLord.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/LichLord.cs index cd25ef79e..ddc18011b 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/LichLord.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/LichLord.cs @@ -59,7 +59,7 @@ namespace Server.Mobiles public override Poison PoisonImmune => Poison.Lethal; public override int TreasureMapLevel => 4; - private static MonsterAbility[] _abilities = { MonsterAbility.SummonSkeletons }; + private static MonsterAbility[] _abilities = { MonsterAbilities.SummonSkeletonsCounter }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Succubus.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Succubus.cs index 2cf3ff74c..1809a2af2 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Succubus.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Magic/Succubus.cs @@ -54,7 +54,7 @@ namespace Server.Mobiles AddLoot(LootPack.MedScrolls, 2); } - private static MonsterAbility[] _abilities = { MonsterAbility.DrainLifeAreaAttack }; + private static MonsterAbility[] _abilities = { MonsterAbilities.DrainLifeAreaAttack }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void Serialize(IGenericWriter writer) diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs index 37a22df75..e3041786d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs @@ -63,7 +63,7 @@ public class Juggernaut : BaseCreature public override int Meat => 1; public override int TreasureMapLevel => 5; - private static MonsterAbility[] _abilities = { MonsterAbility.ColossalBlow }; + private static MonsterAbility[] _abilities = { MonsterAbilities.ColossalBlow }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void OnDeath(Container c) diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs index 3e5d2573c..d4d71edd9 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs @@ -88,7 +88,7 @@ public class ExodusMinion : BaseCreature private static MonsterAbility[] _abilities = { // OSI changed the ability some time around UOML - Core.ML ? MonsterAbility.EnergyBoltCounter : MonsterAbility.MagicalBarrier + Core.ML ? MonsterAbilities.EnergyBoltCounter : MonsterAbilities.MagicalBarrier }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs index c5f3ecb6c..7631dd71d 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs @@ -77,7 +77,7 @@ public class ExodusOverseer : BaseCreature private static MonsterAbility[] _abilities = { // OSI changed the ability some time around UOML - Core.ML ? MonsterAbility.EnergyBoltCounter : MonsterAbility.MagicalBarrier + Core.ML ? MonsterAbilities.EnergyBoltCounter : MonsterAbilities.MagicalBarrier }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs index 0a1a3020f..87f1c690a 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs @@ -102,7 +102,7 @@ namespace Server.Mobiles public override bool AlwaysMurderer => true; public override bool ShowFameTitle => false; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override int GetIdleSound() => 0x2CE; diff --git a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs index 66f9443d1..486685fcc 100644 --- a/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs +++ b/Projects/UOContent/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs @@ -115,7 +115,7 @@ namespace Server.Mobiles public override bool AlwaysMurderer => true; public override bool ShowFameTitle => false; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override int GetIdleSound() => 0x2CE; diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/RedDeath.cs b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/RedDeath.cs index e9b0d1584..021e06a0c 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/RedDeath.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Bedlam/RedDeath.cs @@ -62,7 +62,7 @@ namespace Server.Mobiles public override bool GivesMLMinorArtifact => true; public override bool AlwaysMurderer => true; - private static MonsterAbility[] _abilities = { MonsterAbility.ChaosBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.ChaosBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs index 13c1304de..96e0ab1d5 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs @@ -48,7 +48,7 @@ namespace Server.Mobiles public override int Meat => 19; public override int TreasureMapLevel => 5; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs index 573958c81..b3c0ce765 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs @@ -66,7 +66,7 @@ namespace Server.Mobiles public override bool CanAngerOnTame => true; public override bool CanFly => true; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs index 99bb3244d..c8f0e128b 100644 --- a/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs +++ b/Projects/UOContent/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs @@ -53,7 +53,7 @@ namespace Server.Mobiles public override FoodType FavoriteFood => FoodType.Meat; public override bool CanFly => true; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/HellHound.cs b/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/HellHound.cs index 60d8cfb31..268c1f380 100644 --- a/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/HellHound.cs +++ b/Projects/UOContent/Mobiles/Monsters/Mammal/Melee/HellHound.cs @@ -48,7 +48,7 @@ namespace Server.Mobiles public override FoodType FavoriteFood => FoodType.Meat; public override PackInstinct PackInstinct => PackInstinct.Canine; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Golem.cs b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Golem.cs index e61858540..80c81a13e 100644 --- a/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Golem.cs +++ b/Projects/UOContent/Mobiles/Monsters/Misc/Melee/Golem.cs @@ -107,7 +107,7 @@ public class Golem : BaseCreature public override bool BardImmune => !Core.AOS || Controlled; public override Poison PoisonImmune => Poison.Lethal; - private static MonsterAbility[] _abilities = { MonsterAbility.ColossalBlow }; + private static MonsterAbility[] _abilities = { MonsterAbilities.ColossalBlow }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void OnDeath(Container c) diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs index 545a208d0..9b921422a 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs @@ -52,7 +52,7 @@ public class BronzeElemental : BaseCreature public override bool AutoDispel => true; public override int TreasureMapLevel => 1; - private static MonsterAbility[] _abilities = { MonsterAbility.PoisonGasCounter }; + private static MonsterAbility[] _abilities = { MonsterAbilities.PoisonGasCounter }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs index 2edd12e15..ccfa1deaa 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs @@ -51,7 +51,7 @@ public class DullCopperElemental : BaseCreature public override bool BleedImmune => true; public override int TreasureMapLevel => 1; - private static MonsterAbility[] _abilities = { MonsterAbility.DeathExplosion }; + private static MonsterAbility[] _abilities = { MonsterAbilities.DeathExplosion }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs index 396f0d799..f299426d4 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs @@ -54,7 +54,7 @@ public class ValoriteElemental : BaseCreature public override bool BleedImmune => true; public override int TreasureMapLevel => 1; - private static MonsterAbility[] _abilities = { MonsterAbility.PoisonGasCounter, MonsterAbility.DestroyEquipment }; + private static MonsterAbility[] _abilities = { MonsterAbilities.PoisonGasCounter, MonsterAbilities.DestroyEquipment }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs index 5690fd287..492ada251 100644 --- a/Projects/UOContent/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs +++ b/Projects/UOContent/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs @@ -52,7 +52,7 @@ public class VeriteElemental : BaseCreature public override bool BleedImmune => true; public override int TreasureMapLevel => 1; - private static MonsterAbility[] _abilities = { MonsterAbility.DestroyEquipment }; + private static MonsterAbility[] _abilities = { MonsterAbilities.DestroyEquipment }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs index 9a3085fdb..ad72864c5 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs @@ -57,7 +57,7 @@ namespace Server.Mobiles public override int TreasureMapLevel => 5; public override bool CanFly => true; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs index d3185222a..42f828f23 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs @@ -61,7 +61,7 @@ namespace Server.Mobiles public override int Scales => 8; public override ScaleType ScaleType => ScaleType.Blue; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Dragon.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Dragon.cs index 54656f74a..0816d8bc8 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Dragon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/Dragon.cs @@ -59,7 +59,7 @@ namespace Server.Mobiles public override bool CanAngerOnTame => true; public override bool CanFly => true; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs index 9ee164381..7a2a4fb9d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs @@ -67,7 +67,7 @@ namespace Server.Mobiles public override int Scales => 8; public override ScaleType ScaleType => ScaleType.Blue; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs index 27c7c9d5c..66f414981 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs @@ -62,7 +62,7 @@ namespace Server.Mobiles public override ScaleType ScaleType => Utility.RandomBool() ? ScaleType.Black : ScaleType.White; public override int TreasureMapLevel => 4; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs index 10aac995b..e3731481d 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs @@ -57,7 +57,7 @@ namespace Server.Mobiles public override HideType HideType => HideType.Barbed; public override bool CanFly => true; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs index e3d5ebb6f..83c96b5df 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs @@ -58,7 +58,7 @@ namespace Server.Mobiles public override int Hides => 20; public override HideType HideType => HideType.Barbed; - private static MonsterAbility[] _abilities = { MonsterAbility.ColdBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.ColdBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Drake.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Drake.cs index 7b4348d38..28bdf6672 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Drake.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/Melee/Drake.cs @@ -58,7 +58,7 @@ namespace Server.Mobiles public override FoodType FavoriteFood => FoodType.Meat | FoodType.Fish; public override bool CanFly => true; - private static MonsterAbility[] _abilities = { MonsterAbility.FireBreath }; + private static MonsterAbility[] _abilities = { MonsterAbilities.FireBreath }; public override MonsterAbility[] GetMonsterAbilities() => _abilities; public override void GenerateLoot() diff --git a/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs b/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs index 99887f0f3..4828b5737 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs @@ -1,185 +1,91 @@ -using System; -using System.Collections.Generic; using Server.Engines.Plants; using Server.Items; -namespace Server.Mobiles +namespace Server.Mobiles; + +public class FanDancer : BaseCreature { - public class FanDancer : BaseCreature + [Constructible] + public FanDancer() : base(AIType.AI_Melee) { - private static readonly HashSet m_Table = new(); + Body = 247; + BaseSoundID = 0x372; - [Constructible] - public FanDancer() : base(AIType.AI_Melee) + SetStr(301, 375); + SetDex(201, 255); + SetInt(21, 25); + + SetHits(351, 430); + + SetDamage(12, 17); + + SetDamageType(ResistanceType.Physical, 70); + SetDamageType(ResistanceType.Fire, 10); + SetDamageType(ResistanceType.Cold, 10); + SetDamageType(ResistanceType.Poison, 10); + + SetResistance(ResistanceType.Physical, 40, 60); + SetResistance(ResistanceType.Fire, 50, 70); + SetResistance(ResistanceType.Cold, 50, 70); + SetResistance(ResistanceType.Poison, 50, 70); + SetResistance(ResistanceType.Energy, 40, 60); + + SetSkill(SkillName.MagicResist, 100.1, 110.0); + SetSkill(SkillName.Tactics, 85.1, 95.0); + SetSkill(SkillName.Wrestling, 85.1, 95.0); + SetSkill(SkillName.Anatomy, 85.1, 95.0); + + Fame = 9000; + Karma = -9000; + + if (Utility.RandomDouble() < .33) { - Body = 247; - BaseSoundID = 0x372; - - SetStr(301, 375); - SetDex(201, 255); - SetInt(21, 25); - - SetHits(351, 430); - - SetDamage(12, 17); - - SetDamageType(ResistanceType.Physical, 70); - SetDamageType(ResistanceType.Fire, 10); - SetDamageType(ResistanceType.Cold, 10); - SetDamageType(ResistanceType.Poison, 10); - - SetResistance(ResistanceType.Physical, 40, 60); - SetResistance(ResistanceType.Fire, 50, 70); - SetResistance(ResistanceType.Cold, 50, 70); - SetResistance(ResistanceType.Poison, 50, 70); - SetResistance(ResistanceType.Energy, 40, 60); - - SetSkill(SkillName.MagicResist, 100.1, 110.0); - SetSkill(SkillName.Tactics, 85.1, 95.0); - SetSkill(SkillName.Wrestling, 85.1, 95.0); - SetSkill(SkillName.Anatomy, 85.1, 95.0); - - Fame = 9000; - Karma = -9000; - - if (Utility.RandomDouble() < .33) - { - PackItem(Seed.RandomBonsaiSeed()); - } - - AddItem(new Tessen()); - - if (Utility.RandomDouble() < 0.02) - { - PackItem(new OrigamiPaper()); - } + PackItem(Seed.RandomBonsaiSeed()); } - public FanDancer(Serial serial) : base(serial) + AddItem(new Tessen()); + + if (Utility.RandomDouble() < 0.02) { - } - - public override string CorpseName => "a fan dancer corpse"; - public override string DefaultName => "a fan dancer"; - - public override bool Uncalmable => true; - - private static MonsterAbility[] _abilities = { new ReflectPhysicalDamage() }; - public override MonsterAbility[] GetMonsterAbilities() => _abilities; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich); - AddLoot(LootPack.Rich); - AddLoot(LootPack.Gems, 2); - } - - private void ThrowFan(Mobile to) - { - if (!(Utility.RandomDouble() < 0.8) || to.InRange(this, 1)) - { - return; - } - - /* Fan Throw - * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" - * Damage: 50-65 - */ - Effects.SendMovingEffect( - to.Location, - to.Map, - 0x27A3, - Location, - to.Location, - 10, - 0 - ); - - AOS.Damage(to, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); - } - - public override void OnDamagedBySpell(Mobile attacker, int damage) - { - base.OnDamagedBySpell(attacker, damage); - ThrowFan(attacker); - } - - public override void OnGotMeleeAttack(Mobile attacker, int damage) - { - base.OnGotMeleeAttack(attacker, damage); - ThrowFan(attacker); - } - - public override void OnGaveMeleeAttack(Mobile defender, int damage) - { - base.OnGaveMeleeAttack(defender, damage); - - if (m_Table.Add(defender) && Utility.RandomDouble() < 0.05) - { - /* Fanning Fire - * Graphic: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x3709" ItemIdName: "fire column" FromLocation: "(994 325, 16)" ToLocation: "(994 325, 16)" Speed: "10" Duration: "30" FixedDirection: "True" Explode: "False" Hue: "0x0" RenderMode: "0x0" Effect: "0x34" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x57D4F5B" Layer: "5" Unknown: "0x0" - * Sound: 0x208 - * Start cliloc: 1070833 - * Effect: Fire res -10% for 10 seconds - * Damage: 35-45, 100% fire - * End cliloc: 1070834 - * Effect does not stack - */ - - // The creature fans you with fire, reducing your resistance to fire attacks. - defender.SendLocalizedMessage(1070833); - - var effect = -(defender.FireResistance / 10); - - var mod = new ResistanceMod(ResistanceType.Fire, "FireResistFanningFire", effect); - - defender.FixedParticles(0x37B9, 10, 30, 0x34, EffectLayer.RightFoot); - defender.PlaySound(0x208); - - // This should be done in place of the normal attack damage. - // AOS.Damage( defender, this, Utility.RandomMinMax( 35, 45 ), 0, 100, 0, 0, 0 ); - - defender.AddResistanceMod(mod); - - var timer = new ExpireTimer(defender, mod, TimeSpan.FromSeconds(10.0)); - timer.Start(); - } - } - - public static bool IsFanned(Mobile m) => m_Table.Contains(m); - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly ResistanceMod m_Mod; - - public ExpireTimer(Mobile m, ResistanceMod mod, TimeSpan delay) : base(delay) - { - m_Mobile = m; - m_Mod = mod; - } - - protected override void OnTick() - { - m_Mobile.SendLocalizedMessage(1070834); // Your resistance to fire attacks has returned. - m_Mobile.RemoveResistanceMod(m_Mod); - Stop(); - m_Table.Remove(m_Mobile); - } + PackItem(new OrigamiPaper()); } } + + public FanDancer(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a fan dancer corpse"; + public override string DefaultName => "a fan dancer"; + + public override bool Uncalmable => true; + + private static MonsterAbility[] _abilities = + { + MonsterAbilities.ReflectPhysicalDamage, + MonsterAbilities.FanningFire, + MonsterAbilities.FanThrowCounter + }; + public override MonsterAbility[] GetMonsterAbilities() => _abilities; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich); + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems, 2); + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + var version = reader.ReadInt(); + } } diff --git a/Projects/UOContent/Mobiles/Monsters/SE/RuneBeetle.cs b/Projects/UOContent/Mobiles/Monsters/SE/RuneBeetle.cs index 04bed601c..3b623ba30 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/RuneBeetle.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/RuneBeetle.cs @@ -1,278 +1,122 @@ using System; -using System.Collections.Generic; using Server.Engines.Plants; using Server.Items; -namespace Server.Mobiles +namespace Server.Mobiles; + +public class RuneBeetle : BaseCreature { - public class RuneBeetle : BaseCreature + [Constructible] + public RuneBeetle() : base(AIType.AI_Mage) { - private static readonly Dictionary m_Table = new(); + Body = 244; - [Constructible] - public RuneBeetle() : base(AIType.AI_Mage) + SetStr(401, 460); + SetDex(121, 170); + SetInt(376, 450); + + SetHits(301, 360); + + SetDamage(15, 22); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Poison, 10); + SetDamageType(ResistanceType.Energy, 70); + + SetResistance(ResistanceType.Physical, 40, 65); + SetResistance(ResistanceType.Fire, 35, 50); + SetResistance(ResistanceType.Cold, 35, 50); + SetResistance(ResistanceType.Poison, 75, 95); + SetResistance(ResistanceType.Energy, 40, 60); + + SetSkill(SkillName.EvalInt, 100.1, 125.0); + SetSkill(SkillName.Magery, 100.1, 110.0); + SetSkill(SkillName.Poisoning, 120.1, 140.0); + SetSkill(SkillName.MagicResist, 95.1, 110.0); + SetSkill(SkillName.Tactics, 78.1, 93.0); + SetSkill(SkillName.Wrestling, 70.1, 77.5); + + Fame = 15000; + Karma = -15000; + + if (Utility.RandomDouble() < .25) { - Body = 244; - - SetStr(401, 460); - SetDex(121, 170); - SetInt(376, 450); - - SetHits(301, 360); - - SetDamage(15, 22); - - SetDamageType(ResistanceType.Physical, 20); - SetDamageType(ResistanceType.Poison, 10); - SetDamageType(ResistanceType.Energy, 70); - - SetResistance(ResistanceType.Physical, 40, 65); - SetResistance(ResistanceType.Fire, 35, 50); - SetResistance(ResistanceType.Cold, 35, 50); - SetResistance(ResistanceType.Poison, 75, 95); - SetResistance(ResistanceType.Energy, 40, 60); - - SetSkill(SkillName.EvalInt, 100.1, 125.0); - SetSkill(SkillName.Magery, 100.1, 110.0); - SetSkill(SkillName.Poisoning, 120.1, 140.0); - SetSkill(SkillName.MagicResist, 95.1, 110.0); - SetSkill(SkillName.Tactics, 78.1, 93.0); - SetSkill(SkillName.Wrestling, 70.1, 77.5); - - Fame = 15000; - Karma = -15000; - - if (Utility.RandomDouble() < .25) - { - PackItem(Seed.RandomBonsaiSeed()); - } - - PackItem( - Utility.Random(10) switch - { - 0 => new LeftArm(), - 1 => new RightArm(), - 2 => new Torso(), - 3 => new Bone(), - 4 => new RibCage(), - 5 => new RibCage(), - _ => new BonePile() // 6-9 - } - ); - - Tamable = true; - ControlSlots = 3; - MinTameSkill = 93.9; + PackItem(Seed.RandomBonsaiSeed()); } - public RuneBeetle(Serial serial) : base(serial) + PackItem( + Utility.Random(10) switch + { + 0 => new LeftArm(), + 1 => new RightArm(), + 2 => new Torso(), + 3 => new Bone(), + 4 => new RibCage(), + 5 => new RibCage(), + _ => new BonePile() // 6-9 + } + ); + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 93.9; + } + + public RuneBeetle(Serial serial) : base(serial) + { + } + + public override string CorpseName => "a rune beetle corpse"; + public override string DefaultName => "a rune beetle"; + + public override Poison PoisonImmune => Poison.Greater; + public override Poison HitPoison => Poison.Greater; + public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; + public override bool CanAngerOnTame => true; + + public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; + + public override int GetAngerSound() => 0x4E8; + + public override int GetIdleSound() => 0x4E7; + + public override int GetAttackSound() => 0x4E6; + + public override int GetHurtSound() => 0x4E9; + + public override int GetDeathSound() => 0x4E5; + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 2); + AddLoot(LootPack.MedScrolls, 1); + } + + private static MonsterAbility[] _abilities = { MonsterAbilities.RuneCorruption }; + public override MonsterAbility[] GetMonsterAbilities() => _abilities; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + var version = reader.ReadInt(); + + if (version < 1) { - } - - public override string CorpseName => "a rune beetle corpse"; - public override string DefaultName => "a rune beetle"; - - public override Poison PoisonImmune => Poison.Greater; - public override Poison HitPoison => Poison.Greater; - public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay; - public override bool CanAngerOnTame => true; - - public override WeaponAbility GetWeaponAbility() => WeaponAbility.BleedAttack; - - public override int GetAngerSound() => 0x4E8; - - public override int GetIdleSound() => 0x4E7; - - public override int GetAttackSound() => 0x4E6; - - public override int GetHurtSound() => 0x4E9; - - public override int GetDeathSound() => 0x4E5; - - public override void GenerateLoot() - { - AddLoot(LootPack.FilthyRich, 2); - AddLoot(LootPack.MedScrolls, 1); - } - - public override void OnGaveMeleeAttack(Mobile defender, int damage) - { - base.OnGaveMeleeAttack(defender, damage); - - if (Utility.RandomDouble() < 0.95) + for (var i = 0; i < Skills.Length; ++i) { - return; - } + var skill = Skills[i]; + skill.Cap = Math.Max(100.0, skill.Cap * 0.9); - /* Rune Corruption - * Start cliloc: 1070846 "The creature magically corrupts your armor!" - * Effect: All resistances -70 (lowest 0) for 5 seconds - * End ASCII: "The corruption of your armor has worn off" - */ - - if (m_Table.Remove(defender, out var timer)) - { - timer.DoExpire(); - defender.SendLocalizedMessage(1070845); // The creature continues to corrupt your armor! - } - else - { - defender.SendLocalizedMessage(1070846); // The creature magically corrupts your armor! - } - - if (Core.ML) - { - if (defender.PhysicalResistance > 0) + if (skill.Base > skill.Cap) { - defender.AddResistanceMod( - new ResistanceMod( - ResistanceType.Physical, - "RuneCorruption", - -(defender.PhysicalResistance / 2) - ) - ); + skill.Base = skill.Cap; } - - if (defender.FireResistance > 0) - { - defender.AddResistanceMod(new ResistanceMod(ResistanceType.Fire, "RuneCorruption", -(defender.FireResistance / 2))); - } - - if (defender.ColdResistance > 0) - { - defender.AddResistanceMod(new ResistanceMod(ResistanceType.Cold, "RuneCorruption", -(defender.ColdResistance / 2))); - } - - if (defender.PoisonResistance > 0) - { - defender.AddResistanceMod( - new ResistanceMod( - ResistanceType.Poison, - "RuneCorruption", - -(defender.PoisonResistance / 2) - ) - ); - } - - if (defender.EnergyResistance > 0) - { - defender.AddResistanceMod( - new ResistanceMod( - ResistanceType.Energy, - "RuneCorruption", - -(defender.EnergyResistance / 2) - ) - ); - } - } - else - { - if (defender.PhysicalResistance > 0) - { - defender.AddResistanceMod( - new ResistanceMod( - ResistanceType.Physical, - "RuneCorruption", - defender.PhysicalResistance > 70 ? -70 : -defender.PhysicalResistance - ) - ); - } - - if (defender.FireResistance > 0) - { - defender.AddResistanceMod( - new ResistanceMod( - ResistanceType.Fire, - "RuneCorruption", - defender.FireResistance > 70 ? -70 : -defender.FireResistance - ) - ); - } - - if (defender.ColdResistance > 0) - { - defender.AddResistanceMod( - new ResistanceMod( - ResistanceType.Cold, - "RuneCorruption", - defender.ColdResistance > 70 ? -70 : -defender.ColdResistance - ) - ); - } - - if (defender.PoisonResistance > 0) - { - defender.AddResistanceMod( - new ResistanceMod( - ResistanceType.Poison, - "RuneCorruption", - defender.PoisonResistance > 70 ? -70 : -defender.PoisonResistance - ) - ); - } - - if (defender.EnergyResistance > 0) - { - defender.AddResistanceMod( - new ResistanceMod( - ResistanceType.Energy, - "RuneCorruption", - defender.EnergyResistance > 70 ? -70 : -defender.EnergyResistance - ) - ); - } - } - - defender.FixedEffect(0x37B9, 10, 5); - - timer = new ExpireTimer(defender, TimeSpan.FromSeconds(5.0)); - timer.Start(); - m_Table[defender] = timer; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - writer.Write(1); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - var version = reader.ReadInt(); - - if (version < 1) - { - for (var i = 0; i < Skills.Length; ++i) - { - var skill = Skills[i]; - skill.Cap = Math.Max(100.0, skill.Cap * 0.9); - - if (skill.Base > skill.Cap) - { - skill.Base = skill.Cap; - } - } - } - } - - private class ExpireTimer : Timer - { - private readonly Mobile m_Mobile; - - public ExpireTimer(Mobile m, TimeSpan delay) : base(delay) => m_Mobile = m; - - public void DoExpire() - { - m_Mobile.RemoveResistanceMod("RuneCorruption"); - Stop(); - } - - protected override void OnTick() - { - m_Mobile.SendMessage("The corruption of your armor has worn off"); - DoExpire(); - m_Table.Remove(m_Mobile); } } }