ModernUO/Projects/UOContent/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs
Kamron Batman 6c4308bce6
fix(core): Caches DateTime.NowUtc (#548)
- [X] Caches DateTime.NowUtc on the game loop (not other threads)
- [X] Replaces all locations where it makes sense
- [X] Adds Min/Max for `IComparable` (TimeSpan, DateTimes, etc)

Closes #261
2021-03-13 01:32:04 -08:00

250 lines
7.3 KiB
C#

using System;
using System.Collections.Generic;
namespace Server.Mobiles
{
public class Satyr : BaseCreature
{
private static readonly Dictionary<Mobile, Timer> 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);
}
}
}
}
}