From 34c085a7777b84d61544fe4a615e7837e2c36331 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Thu, 2 Jul 2026 23:52:58 -0700 Subject: [PATCH] feat: add TailSwipe monster ability and give it to StoneSlith Port StoneSlith's TailSwipe from ServUO as a proper ModernUO MonsterAbility (MonsterAbilitySingleTarget, on GiveMeleeDamage, 30s cooldown like ServUO's SpecialAbility base). On hit it plays the tail-swipe effect and either stuns (3s paralyze) or confuses (-20 Dex/Int for 5s). Uses the OSI/Stratics-reported ~90% stun / ~10% confuse split rather than ServUO's incorrect even 50/50. StoneSlith now runs GraspingClaw + TailSwipe, closing the last ability gap from the port. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Mobiles/Abilities/MonsterAbilities.cs | 1 + .../Mobiles/Abilities/MonsterAbilityType.cs | 3 +- .../UOContent/Mobiles/Abilities/TailSwipe.cs | 35 +++++++++++++++++++ .../Mobiles/Monsters/Reptile/StoneSlith.cs | 7 ++-- 4 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 Projects/UOContent/Mobiles/Abilities/TailSwipe.cs diff --git a/Projects/UOContent/Mobiles/Abilities/MonsterAbilities.cs b/Projects/UOContent/Mobiles/Abilities/MonsterAbilities.cs index 652bc5b05..0afdf05de 100644 --- a/Projects/UOContent/Mobiles/Abilities/MonsterAbilities.cs +++ b/Projects/UOContent/Mobiles/Abilities/MonsterAbilities.cs @@ -13,6 +13,7 @@ public static class MonsterAbilities // Resistance Debuffs public static GraspingClaw GraspingClaw => new(); + public static TailSwipe TailSwipe => new(); public static RuneCorruption RuneCorruption => new(); public static FanningFire FanningFire => new(0.05, -10, 35, 45); diff --git a/Projects/UOContent/Mobiles/Abilities/MonsterAbilityType.cs b/Projects/UOContent/Mobiles/Abilities/MonsterAbilityType.cs index 9f188243d..fe0fe46f4 100644 --- a/Projects/UOContent/Mobiles/Abilities/MonsterAbilityType.cs +++ b/Projects/UOContent/Mobiles/Abilities/MonsterAbilityType.cs @@ -20,5 +20,6 @@ public enum MonsterAbilityType FanningFire, // Fire debuff RuneCorruption, FanThrow, - BloodBath + BloodBath, + TailSwipe } diff --git a/Projects/UOContent/Mobiles/Abilities/TailSwipe.cs b/Projects/UOContent/Mobiles/Abilities/TailSwipe.cs new file mode 100644 index 000000000..9982355b2 --- /dev/null +++ b/Projects/UOContent/Mobiles/Abilities/TailSwipe.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.Mobiles; + +public class TailSwipe : MonsterAbilitySingleTarget +{ + public override MonsterAbilityType AbilityType => MonsterAbilityType.TailSwipe; + public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.GiveMeleeDamage; + public override double ChanceToTrigger => 0.3; + + // ServUO's SpecialAbility base cooldown; TailSwipe does not override it. + public override TimeSpan MinTriggerCooldown => TimeSpan.FromSeconds(30); + public override TimeSpan MaxTriggerCooldown => TimeSpan.FromSeconds(30); + + protected override void OnTarget(MonsterAbilityTrigger trigger, BaseCreature source, Mobile defender) + { + source.DoHarmful(defender); + + defender.PlaySound(0x204); + defender.FixedEffect(0x376A, 6, 1); + + // OSI/Stratics reports roughly a 90% stun / 10% confuse split (ServUO's even 50/50 is incorrect). + if (Utility.RandomDouble() < 0.10) + { + defender.SendLocalizedMessage(1112555); // You're left confused as the creature's tail catches you right in the face! + defender.AddStatMod(new StatMod(StatType.Dex, "[TailSwipe] Dex", -20, TimeSpan.FromSeconds(5.0))); + defender.AddStatMod(new StatMod(StatType.Int, "[TailSwipe] Int", -20, TimeSpan.FromSeconds(5.0))); + } + else + { + defender.SendLocalizedMessage(1112554); // You're stunned as the creature's tail knocks the wind out of you. + defender.Paralyze(TimeSpan.FromSeconds(3.0)); + } + } +} diff --git a/Projects/UOContent/Mobiles/Monsters/Reptile/StoneSlith.cs b/Projects/UOContent/Mobiles/Monsters/Reptile/StoneSlith.cs index 94605c7e2..c7a3d7a45 100644 --- a/Projects/UOContent/Mobiles/Monsters/Reptile/StoneSlith.cs +++ b/Projects/UOContent/Mobiles/Monsters/Reptile/StoneSlith.cs @@ -6,7 +6,7 @@ namespace Server.Mobiles; [SerializationGenerator(0)] public partial class StoneSlith : BaseCreature { - private static readonly MonsterAbility[] _abilities = [MonsterAbilities.GraspingClaw]; + private static readonly MonsterAbility[] _abilities = [MonsterAbilities.GraspingClaw, MonsterAbilities.TailSwipe]; [Constructible] public StoneSlith() : base(AIType.AI_Melee) @@ -40,9 +40,8 @@ public partial class StoneSlith : BaseCreature MinTameSkill = 65.1; ControlSlots = 2; - // TODO(SA-creatures): unported vs ServUO — SpecialAbility.TailSwipe (no ModernUO equivalent), - // DragonBlood carving, and the minor drops SlithEye / TatteredAncientScroll / AncientPotteryFragments - // (item classes not yet in ModernUO). + // TODO(SA-creatures): unported vs ServUO — DragonBlood carving, and the minor drops + // SlithEye / TatteredAncientScroll / AncientPotteryFragments (item classes not yet in ModernUO). } public override string CorpseName => "a slith corpse";