using System; using System.Collections.Generic; namespace Server.Mobiles { public class Satyr : BaseCreature { private static readonly Dictionary m_Suppressed = new(); private DateTime m_NextPeace; private DateTime m_NextProvoke; private DateTime m_NextSuppress; private DateTime m_NextUndress; [Constructible] public Satyr() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) { Body = 271; BaseSoundID = 0x586; SetStr(177, 195); SetDex(251, 269); SetInt(153, 170); SetHits(350, 400); SetDamage(13, 24); SetDamageType(ResistanceType.Physical, 100); SetResistance(ResistanceType.Physical, 55, 60); SetResistance(ResistanceType.Fire, 25, 35); SetResistance(ResistanceType.Cold, 30, 40); SetResistance(ResistanceType.Poison, 30, 40); SetResistance(ResistanceType.Energy, 30, 40); SetSkill(SkillName.MagicResist, 55.0, 65.0); SetSkill(SkillName.Tactics, 80.0, 100.0); SetSkill(SkillName.Wrestling, 80.0, 100.0); Fame = 5000; Karma = 0; VirtualArmor = 28; // Don't know what it should be PackArcanceScroll(0.05); } public Satyr(Serial serial) : base(serial) { } public override string CorpseName => "a satyr's corpse"; public override string DefaultName => "a satyr"; public override OppositionGroup OppositionGroup => OppositionGroup.FeyAndUndead; public override int Meat => 1; public override void GenerateLoot() { AddLoot(LootPack.MlRich); } public override void OnThink() { base.OnThink(); Peace(Combatant); Undress(Combatant); Suppress(Combatant); Provoke(Combatant); } 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(); } public void Peace(Mobile target) { if (target == null || Deleted || !Alive || m_NextPeace > Core.Now || Utility.RandomDouble() > 0.1) { return; } if (target is PlayerMobile p && p.PeacedUntil < Core.Now && !p.Hidden && CanBeHarmful(p)) { p.PeacedUntil = Core.Now + TimeSpan.FromMinutes(1); p.SendLocalizedMessage(500616); // You hear lovely music, and forget to continue battling! p.FixedParticles(0x376A, 1, 32, 0x15BD, EffectLayer.Waist); p.Combatant = null; PlaySound(0x58D); } m_NextPeace = Core.Now + TimeSpan.FromSeconds(10); } public void Suppress(Mobile target) { if (target == null || m_Suppressed.ContainsKey(target) || Deleted || !Alive || m_NextSuppress > Core.Now || Utility.RandomDouble() > 0.1) { return; } var delay = TimeSpan.FromSeconds(Utility.RandomMinMax(20, 80)); if (!target.Hidden && CanBeHarmful(target)) { target.SendLocalizedMessage(1072061); // You hear jarring music, suppressing your strength. for (var i = 0; i < target.Skills.Length; i++) { var s = target.Skills[i]; target.AddSkillMod(new TimedSkillMod(s.SkillName, true, s.Base * -0.28, delay)); } var count = (int)Math.Round(delay.TotalSeconds / 1.25); Timer timer = new AnimateTimer(target, count); m_Suppressed.Add(target, timer); timer.Start(); PlaySound(0x58C); } m_NextSuppress = Core.Now + TimeSpan.FromSeconds(10); } public static void SuppressRemove(Mobile target) { if (target == null) { return; } if (m_Suppressed.TryGetValue(target, out var t)) { if (t.Running) { t.Stop(); } m_Suppressed.Remove(target); } } public void Undress(Mobile target) { if (target == null || Deleted || !Alive || m_NextUndress > Core.Now || Utility.RandomDouble() > 0.005) { return; } if (target.Player && target.Female && !target.Hidden && CanBeHarmful(target)) { UndressItem(target, Layer.OuterTorso); UndressItem(target, Layer.InnerTorso); UndressItem(target, Layer.MiddleTorso); UndressItem(target, Layer.Pants); UndressItem(target, Layer.Shirt); target.SendLocalizedMessage( 1072196 ); // The satyr's music makes your blood race. Your clothing is too confining. } m_NextUndress = Core.Now + TimeSpan.FromMinutes(1); } public void UndressItem(Mobile m, Layer layer) { var item = m.FindItemOnLayer(layer); if (item?.Movable == true) { m.PlaceInBackpack(item); } } public void Provoke(Mobile target) { if (target == null || Deleted || !Alive || m_NextProvoke > Core.Now || Utility.RandomDouble() > 0.05) { return; } foreach (var m in GetMobilesInRange(RangePerception)) { if (m is BaseCreature c) { if (c == this || c == target || c.Unprovokable || c.IsParagon || c.BardProvoked || c.AccessLevel != AccessLevel.Player || !c.CanBeHarmful(target)) { continue; } c.Provoke(this, target, true); if (target.Player) { target.SendLocalizedMessage(1072062); // You hear angry music, and start to fight. } PlaySound(0x58A); break; } } m_NextProvoke = Core.Now + TimeSpan.FromSeconds(10); } private class AnimateTimer : Timer { private readonly Mobile m_Owner; private int m_Count; public AnimateTimer(Mobile owner, int count) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1.25)) { m_Owner = owner; m_Count = count; } protected override void OnTick() { if (m_Owner.Deleted || !m_Owner.Alive || m_Count-- < 0) { SuppressRemove(m_Owner); } else { m_Owner.FixedParticles(0x376A, 1, 32, 0x15BD, EffectLayer.Waist); } } } } }