feat: Adds SpecialAttack monster ability trigger. Fixes fanning fire. (#2186)

This commit is contained in:
Kamron Batman 2025-05-15 22:14:52 -07:00 committed by GitHub
parent 91b2912ee4
commit e468f79e18
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 89 additions and 119 deletions

View file

@ -890,6 +890,11 @@ public abstract partial class BaseWeapon
if (attacker is BaseCreature bc)
{
if (bc.TriggerAbility(MonsterAbilityTrigger.CombatAction, defender))
{
return GetDelay(attacker);
}
// Only change direction if they are not a player.
attacker.Direction = attacker.GetDirectionTo(defender);
var ab = bc.GetWeaponAbility();
@ -1350,7 +1355,7 @@ public abstract partial class BaseWeapon
theirValue = Math.Max(0.1, defValue + 50.0);
}
var chance = ourValue / (theirValue * 2.0) * 1.0 + (double)bonus / 100;;
var chance = ourValue / (theirValue * 2.0) * 1.0 + (double)bonus / 100;
if (Core.AOS && chance < 0.02)
{

View file

@ -70,6 +70,11 @@ namespace Server.Items
attacker.DisruptiveAction();
attacker.NetState.SendSwing(attacker.Serial, defender.Serial);
if (attacker is BaseCreature bc && bc.TriggerAbility(MonsterAbilityTrigger.CombatAction, defender))
{
return GetDelay(attacker);
}
if (OnFired(attacker, defender))
{
if (CheckHit(attacker, defender))

View file

@ -5,8 +5,23 @@ 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 override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.CombatAction;
public FanningFire(double chanceToTrigger, int fireResistMod, int minDamage, int maxDamage)
{
ChanceToTrigger = chanceToTrigger;
FireResistMod = fireResistMod;
MinDamage = minDamage;
MaxDamage = maxDamage;
}
public sealed override double ChanceToTrigger { get; }
public int FireResistMod { get; }
public int MinDamage { get; }
public int MaxDamage { get; }
public const string Name = "FanningFire";
@ -52,16 +67,12 @@ public class FanningFire : MonsterAbilitySingleTargetDoT
*/
source.DoHarmful(defender);
var effect = -(defender.FireResistance / 10);
defender.AddResistanceMod(new ResistanceMod(ResistanceType.Fire, Name, FireResistMod));
var mod = new ResistanceMod(ResistanceType.Fire, Name, effect);
defender.AddResistanceMod(mod);
defender.FixedParticles(0x37B9, 10, 30, 0x34, EffectLayer.RightFoot);
defender.FixedParticles(0x3709, 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);
AOS.Damage(defender, source, Utility.RandomMinMax(MinDamage, MaxDamage), 0, 100, 0, 0, 0);
}
protected override void EffectTick(BaseCreature source, Mobile defender, ref TimeSpan nextDelay)

View file

@ -14,7 +14,7 @@ public static class MonsterAbilities
// Resistance Debuffs
public static GraspingClaw GraspingClaw => new();
public static RuneCorruption RuneCorruption => new();
public static FanningFire FanningFire => new();
public static FanningFire FanningFire => new(0.05, -10, 35, 45);
// Summon Undead
public static SummonSkeletonsCounter SummonSkeletonsCounter => new();

View file

@ -1,122 +1,71 @@
using ModernUO.Serialization;
using System;
using System.Collections.Generic;
namespace Server.Mobiles
namespace Server.Mobiles;
[SerializationGenerator(0, false)]
public partial class LadyJennifyr : SkeletalKnight
{
[SerializationGenerator(0, false)]
public partial class LadyJennifyr : SkeletalKnight
[Constructible]
public LadyJennifyr()
{
private static readonly Dictionary<Mobile, ExpireTimer> m_Table = new();
IsParagon = true;
[Constructible]
public LadyJennifyr()
{
IsParagon = true;
Hue = 0x76D;
Hue = 0x76D;
SetStr(208, 309);
SetDex(91, 118);
SetInt(44, 101);
SetStr(208, 309);
SetDex(91, 118);
SetInt(44, 101);
SetHits(1113, 1285);
SetHits(1113, 1285);
SetDamage(15, 25);
SetDamage(15, 25);
SetDamageType(ResistanceType.Physical, 40);
SetDamageType(ResistanceType.Cold, 60);
SetDamageType(ResistanceType.Physical, 40);
SetDamageType(ResistanceType.Cold, 60);
SetResistance(ResistanceType.Physical, 56, 65);
SetResistance(ResistanceType.Fire, 41, 49);
SetResistance(ResistanceType.Cold, 71, 80);
SetResistance(ResistanceType.Poison, 41, 50);
SetResistance(ResistanceType.Energy, 50, 58);
SetResistance(ResistanceType.Physical, 56, 65);
SetResistance(ResistanceType.Fire, 41, 49);
SetResistance(ResistanceType.Cold, 71, 80);
SetResistance(ResistanceType.Poison, 41, 50);
SetResistance(ResistanceType.Energy, 50, 58);
SetSkill(SkillName.Wrestling, 127.9, 137.1);
SetSkill(SkillName.Tactics, 128.4, 141.9);
SetSkill(SkillName.MagicResist, 102.1, 119.5);
SetSkill(SkillName.Anatomy, 129.0, 137.5);
SetSkill(SkillName.Wrestling, 127.9, 137.1);
SetSkill(SkillName.Tactics, 128.4, 141.9);
SetSkill(SkillName.MagicResist, 102.1, 119.5);
SetSkill(SkillName.Anatomy, 129.0, 137.5);
Fame = 18000;
Karma = -18000;
}
public override string CorpseName => "a Lady Jennifyr corpse";
public override string DefaultName => "Lady Jennifyr";
/*
// TODO: Uncomment once added
public override void OnDeath( Container c )
{
base.OnDeath( c );
if (Utility.RandomDouble() < 0.15)
c.DropItem( new DisintegratingThesisNotes() );
if (Utility.RandomDouble() < 0.1)
c.DropItem( new ParrotItem() );
}
*/
public override bool GivesMLMinorArtifact => true;
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 3);
}
public override void OnGaveMeleeAttack(Mobile defender, int damage)
{
base.OnGaveMeleeAttack(defender, damage);
if (Utility.RandomDouble() < 0.9)
{
return;
}
if (m_Table.Remove(defender, out var timer))
{
timer.DoExpire();
}
defender.FixedParticles(0x3709, 10, 30, 5052, EffectLayer.LeftFoot);
defender.PlaySound(0x208);
// The creature fans you with fire, reducing your resistance to fire attacks.
defender.SendLocalizedMessage(1070833);
var mod = new ResistanceMod(ResistanceType.Fire, "FireResistFanningFire", -10);
defender.AddResistanceMod(mod);
m_Table[defender] = timer = new ExpireTimer(defender, mod);
timer.Start();
}
private class ExpireTimer : Timer
{
private readonly Mobile m_Mobile;
private readonly ResistanceMod m_Mod;
public ExpireTimer(Mobile m, ResistanceMod mod)
: base(TimeSpan.FromSeconds(10))
{
m_Mobile = m;
m_Mod = mod;
}
public void DoExpire()
{
m_Mobile.RemoveResistanceMod(m_Mod);
Stop();
}
protected override void OnTick()
{
m_Mobile.SendLocalizedMessage(1070834); // Your resistance to fire attacks has returned.
DoExpire();
m_Table.Remove(m_Mobile);
}
}
Fame = 18000;
Karma = -18000;
}
public override string CorpseName => "a Lady Jennifyr corpse";
public override string DefaultName => "Lady Jennifyr";
/*
// TODO: Uncomment once added
public override void OnDeath( Container c )
{
base.OnDeath( c );
if (Utility.RandomDouble() < 0.15)
c.DropItem( new DisintegratingThesisNotes() );
if (Utility.RandomDouble() < 0.1)
c.DropItem( new ParrotItem() );
}
*/
public override bool GivesMLMinorArtifact => true;
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 3);
}
private static readonly MonsterAbility[] _abilities =
[
new FanningFire(0.10, -10, 35, 45)
];
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
}