using System; using System.Runtime.CompilerServices; using ModernUO.Serialization; using Server.Engines.VeteranRewards; namespace Server.Items { [SerializationGenerator(0, false)] public abstract partial class BaseOuterTorso : BaseClothing { public BaseOuterTorso(int itemID, int hue = 0) : base(itemID, Layer.OuterTorso, hue) { } } [SerializationGenerator(0, false)] [Flippable(0x230E, 0x230D)] public partial class GildedDress : BaseOuterTorso { [Constructible] public GildedDress(int hue = 0) : base(0x230E, hue) { } public override double DefaultWeight => 3.0; } [SerializationGenerator(0, false)] [Flippable(0x1F00, 0x1EFF)] public partial class FancyDress : BaseOuterTorso { [Constructible] public FancyDress(int hue = 0) : base(0x1F00, hue) { } public override double DefaultWeight => 3.0; } [SerializationGenerator(4, false)] public partial class DeathRobe : Robe { private static readonly TimeSpan m_DefaultDecayTime = TimeSpan.FromMinutes(1.0); [SerializableField(0)] [DeserializeTimer(nameof(DeserializeDecayTimer))] private Timer _decayTimer; private void DeserializeDecayTimer(TimeSpan delay) => BeginDecay(delay); private void MigrateFrom(V3Content content) { if (content.DecayTimerDelay != TimeSpan.MinValue) { DeserializeDecayTimer(content.DecayTimerDelay); } } [Constructible] public DeathRobe() { LootType = LootType.Newbied; Hue = 2301; BeginDecay(m_DefaultDecayTime); } public override bool DisplayLootType => false; public new bool Scissor(Mobile from, Scissors scissors) { from.SendLocalizedMessage(502440); // Scissors can not be used on that to produce anything. return false; } public void BeginDecay() { BeginDecay(m_DefaultDecayTime); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void StopTimer() { _decayTimer?.Stop(); _decayTimer = null; } private void BeginDecay(TimeSpan delay) { StopTimer(); _decayTimer = new InternalTimer(this, delay); _decayTimer.Start(); } public override bool OnDroppedToWorld(Mobile from, Point3D p) { BeginDecay(m_DefaultDecayTime); return true; } public override bool OnDroppedInto(Mobile from, Container target, Point3D p) { if (base.OnDroppedInto(from, target, p)) { StopTimer(); return true; } return false; } public override bool OnDroppedToMobile(Mobile from, Mobile target) { StopTimer(); return true; } public override void OnAfterDelete() { StopTimer(); } private void Deserialize(IGenericReader reader, int version) { if (reader.ReadBool()) { var delay = reader.ReadDeltaTime(); BeginDecay(delay - Core.Now); } } private class InternalTimer : Timer { private readonly DeathRobe _robe; public InternalTimer(DeathRobe c, TimeSpan delay) : base(delay) => _robe = c; protected override void OnTick() { if (_robe.Parent != null || _robe.IsLockedDown) { Stop(); _robe._decayTimer = null; } else { _robe.Delete(); } } } } [Flippable] [SerializationGenerator(0, false)] public partial class RewardRobe : BaseOuterTorso, IRewardItem { [InvalidateProperties] [SerializableField(0)] [SerializedCommandProperty(AccessLevel.GameMaster)] private int _number; [SerializableField(1)] [SerializedCommandProperty(AccessLevel.GameMaster)] private bool _isRewardItem; [Constructible] public RewardRobe(int hue = 0, int labelNumber = 0) : base(0x1F03, hue) { LootType = LootType.Blessed; _number = labelNumber; } public override double DefaultWeight => 3.0; public override int LabelNumber => _number > 0 ? _number : base.LabelNumber; public override int BasePhysicalResistance => 3; public override void OnAdded(IEntity parent) { base.OnAdded(parent); if (parent is Mobile mobile) { mobile.VirtualArmorMod += 2; } } public override void OnRemoved(IEntity parent) { base.OnRemoved(parent); if (parent is Mobile mobile) { mobile.VirtualArmorMod -= 2; } } public override bool Dye(Mobile from, DyeTub sender) { from.SendLocalizedMessage(sender.FailMessage); return false; } public override void GetProperties(IPropertyList list) { base.GetProperties(list); if (Core.ML && IsRewardItem) { // X Year Veteran Reward list.Add( RewardSystem.GetRewardYearLabel( this, new object[] { Hue, _number } ) ); } } public override bool CanEquip(Mobile m) => base.CanEquip(m) && (!IsRewardItem || RewardSystem.CheckIsUsableBy(m, this, new object[] { Hue, _number })); [AfterDeserialization] private void AfterDeserialization() { if (Parent is Mobile mobile) { mobile.VirtualArmorMod += 2; } } } [Flippable] [SerializationGenerator(0, false)] public partial class RewardDress : BaseOuterTorso, IRewardItem { [InvalidateProperties] [SerializableField(0)] [SerializedCommandProperty(AccessLevel.GameMaster)] private int _number; [SerializableField(1)] [SerializedCommandProperty(AccessLevel.GameMaster)] private bool _isRewardItem; [Constructible] public RewardDress(int hue = 0, int labelNumber = 0) : base(0x1F01, hue) { LootType = LootType.Blessed; _number = labelNumber; } public override double DefaultWeight => 2.0; public override int LabelNumber => _number > 0 ? _number : base.LabelNumber; public override int BasePhysicalResistance => 3; public override void OnAdded(IEntity parent) { base.OnAdded(parent); if (parent is Mobile mobile) { mobile.VirtualArmorMod += 2; } } public override void OnRemoved(IEntity parent) { base.OnRemoved(parent); if (parent is Mobile mobile) { mobile.VirtualArmorMod -= 2; } } public override bool Dye(Mobile from, DyeTub sender) { from.SendLocalizedMessage(sender.FailMessage); return false; } public override void GetProperties(IPropertyList list) { base.GetProperties(list); if (_isRewardItem) { // X Year Veteran Reward list.Add( RewardSystem.GetRewardYearLabel( this, new object[] { Hue, _number } ) ); } } public override bool CanEquip(Mobile m) => base.CanEquip(m) && (!_isRewardItem || RewardSystem.CheckIsUsableBy(m, this, new object[] { Hue, _number })); [AfterDeserialization] private void AfterDeserialization() { if (Parent is Mobile mobile) { mobile.VirtualArmorMod += 2; } } } [Flippable] [SerializationGenerator(2, false)] public partial class Robe : BaseOuterTorso, IArcaneEquip { [Constructible] public Robe(int hue = 0) : base(0x1F03, hue) { } public override double DefaultWeight => 3.0; [SerializableField(0, fieldChanged: nameof(OnCurArcaneChargesChanged))] [EncodedInt] [SerializedCommandProperty(AccessLevel.GameMaster)] [InvalidateProperties] private int _curArcaneCharges; private void OnCurArcaneChargesChanged(int oldValue, int newValue) { Update(); } [SerializableField(1, fieldChanged: nameof(OnMaxArcaneChargesChanged))] [EncodedInt] [SerializedCommandProperty(AccessLevel.GameMaster)] [InvalidateProperties] private int _maxArcaneCharges; private void OnMaxArcaneChargesChanged(int oldValue, int newValue) { Update(); } [CommandProperty(AccessLevel.GameMaster)] public bool IsArcane => _maxArcaneCharges > 0 && _curArcaneCharges >= 0; private void Deserialize(IGenericReader reader, int version) { if (reader.ReadBool()) { _curArcaneCharges = reader.ReadInt(); _maxArcaneCharges = reader.ReadInt(); } } public void Update() { if (IsArcane) { ItemID = 0x26AE; } else if (ItemID == 0x26AE) { ItemID = 0x1F04; } if (IsArcane && CurArcaneCharges == 0) { Hue = 0; } } public override void GetProperties(IPropertyList list) { base.GetProperties(list); if (IsArcane) { list.Add(1061837, $"{_curArcaneCharges}\t{_maxArcaneCharges}"); // arcane charges: ~1_val~ / ~2_val~ } } public override void OnSingleClick(Mobile from) { base.OnSingleClick(from); if (IsArcane) { LabelTo(from, 1061837, $"{_curArcaneCharges}\t{_maxArcaneCharges}"); } } public void Flip() { ItemID = ItemID switch { 0x1F03 => 0x1F04, 0x1F04 => 0x1F03, _ => ItemID }; } } [SerializationGenerator(0, false)] public partial class MonkRobe : BaseOuterTorso { [Constructible] public MonkRobe(int hue = 0x21E) : base(0x2687, hue) => StrRequirement = 0; public override double DefaultWeight => 1.0; public override int LabelNumber => 1076584; // A monk's robe public override bool CanBeBlessed => false; public override bool Dye(Mobile from, DyeTub sender) { from.SendLocalizedMessage(sender.FailMessage); return false; } } [Flippable(0x1f01, 0x1f02)] [SerializationGenerator(0, false)] public partial class PlainDress : BaseOuterTorso { [Constructible] public PlainDress(int hue = 0) : base(0x1F01, hue) { } public override double DefaultWeight => 2.0; } [Flippable(0x2799, 0x27E4)] [SerializationGenerator(0, false)] public partial class Kamishimo : BaseOuterTorso { [Constructible] public Kamishimo(int hue = 0) : base(0x2799, hue) { } public override double DefaultWeight => 3.0; } [Flippable(0x279C, 0x27E7)] [SerializationGenerator(0, false)] public partial class HakamaShita : BaseOuterTorso { [Constructible] public HakamaShita(int hue = 0) : base(0x279C, hue) { } public override double DefaultWeight => 3.0; } [Flippable(0x2782, 0x27CD)] [SerializationGenerator(0, false)] public partial class MaleKimono : BaseOuterTorso { [Constructible] public MaleKimono(int hue = 0) : base(0x2782, hue) { } public override double DefaultWeight => 3.0; } [Flippable(0x2783, 0x27CE)] [SerializationGenerator(0, false)] public partial class FemaleKimono : BaseOuterTorso { [Constructible] public FemaleKimono(int hue = 0) : base(0x2783, hue) { } public override double DefaultWeight => 3.0; } [Flippable(0x2FB9, 0x3173)] [SerializationGenerator(0)] public partial class MaleElvenRobe : BaseOuterTorso { [Constructible] public MaleElvenRobe(int hue = 0) : base(0x2FB9, hue) { } public override double DefaultWeight => 2.0; } [Flippable(0x2FBA, 0x3174)] [SerializationGenerator(0)] public partial class FemaleElvenRobe : BaseOuterTorso { [Constructible] public FemaleElvenRobe(int hue = 0) : base(0x2FBA, hue) { } public override double DefaultWeight => 2.0; public override int RequiredRaces => Race.AllowElvesOnly; public override bool AllowMaleWearer => false; } }