using System; using Server; using Server.Mobiles; using Server.ContextMenus; using System.Collections.Generic; using Server.Network; namespace Server.Items { public class UndertakersStaff : GnarledStaff { private static Dictionary _Timers = new Dictionary(); private int _Charges; private bool _SummonAll; [CommandProperty(AccessLevel.GameMaster)] public int Charges { get { return _Charges; } set { _Charges = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] public bool SummonAll { get { return _SummonAll; } set { _SummonAll = value; InvalidateProperties(); } } public override int LabelNumber { get { return 1071498; } } // Undertaker's Staff public override bool IsArtifact { get { return true; } } public override int InitMinHits { get { return 255; } } public override int InitMaxHits { get { return 255; } } [Constructable] public UndertakersStaff() { if (!Siege.SiegeShard) LootType = LootType.Blessed; Charges = 100; SummonAll = true; } public override void GetProperties(ObjectPropertyList list) { base.GetProperties(list); list.Add(1071518, String.Format("#{0}", _SummonAll ? "1071508" : "1071507")); list.Add(1060584, _Charges.ToString()); } public override void GetContextMenuEntries(Mobile from, List entries) { base.GetContextMenuEntries(from, entries); if (IsChildOf(from.Backpack)) { var entry1 = new SimpleContextMenuEntry(from, 1071507, m => { SummonAll = false; InvalidateProperties(); }); // Summon Most Recent Corpse Only var entry2 = new SimpleContextMenuEntry(from, 1071508, m => { _SummonAll = true; InvalidateProperties(); }); // Summon All Corpses if(_SummonAll) entry2.Flags |= CMEFlags.Highlighted; else entry1.Flags |= CMEFlags.Highlighted; entry1.Enabled = !IsSummoning(); entry2.Enabled = !IsSummoning(); entries.Add(entry1); entries.Add(entry2); } } public override void OnDoubleClick(Mobile m) { if (!_Timers.ContainsKey(m) && (IsChildOf(m.Backpack) || m.FindItemOnLayer(Layer) == this)) { TryGetCorpse(m); } } private void TryGetCorpse(Mobile m) { if (CanGetCorpse(m)) { m.PlaySound(0xF5); if (_SummonAll) { var corpses = GetCorpses(m); if (corpses != null) { m.SendLocalizedMessage(1071527, corpses.Count.ToString()); // The staff reaches out to ~1_COUNT~ of your corpses and tries to draw them to you... _Timers[m] = new CorpseRetrieveTimer(m, corpses, this); } else { m.SendLocalizedMessage(1071511); // The staff glows slightly, then fades. Its magic is unable to locate a corpse of yours to recover. } } else { var corpse = GetCorpse(m); if (corpse != null) { m.SendLocalizedMessage(1071528); // The staff reaches out to your corpse and tries to draw it to you... _Timers[m] = new CorpseRetrieveTimer(m, new List { corpse }, this); } else { m.SendLocalizedMessage(1071511); // The staff glows slightly, then fades. Its magic is unable to locate a corpse of yours to recover. } } } } private bool CanGetCorpse(Mobile m, bool firstCheck = true) { if(m.Criminal) { m.SendLocalizedMessage(1071510); // You are a criminal and cannot use this item... return false; } else if (Spells.SpellHelper.CheckCombat(m)) { m.SendLocalizedMessage(1071514); // You cannot use this item during the heat of battle. return false; } return true; } public void TryEndSummon(Mobile m, List corpses) { if (_Timers.ContainsKey(m)) _Timers.Remove(m); if (corpses == null || corpses.Count == 0) { m.SendLocalizedMessage(1071511); // The staff glows slightly, then fades. Its magic is unable to locate a corpse of yours to recover. return; } bool tooFar = false; bool notEnoughTime = false; bool tooManySummons = false; bool success = true; if (_SummonAll) { List copy = new List(corpses); foreach (var c in copy) { bool remove = false; if (c.Map != m.Map) { remove = true; tooFar = true; } if (c.Killer is PlayerMobile && c.Killer != m && c.TimeOfDeath + TimeSpan.FromSeconds(180) > DateTime.UtcNow) { remove = true; notEnoughTime = true; } if (Corpse.PlayerCorpses.ContainsKey(c) && Corpse.PlayerCorpses[c] >= 3) { remove = true; tooManySummons = true; } if (remove) corpses.Remove(c); } if (corpses.Count == 0) success = false; } else { Corpse c = corpses[0]; if (c.Map != m.Map) tooFar = true; if (c.Killer is PlayerMobile && c.Killer != m && c.TimeOfDeath + TimeSpan.FromSeconds(180) > DateTime.UtcNow) notEnoughTime = true; if (Corpse.PlayerCorpses != null && Corpse.PlayerCorpses.ContainsKey(c) && Corpse.PlayerCorpses[c] >= 3) tooManySummons = true; if (tooFar || notEnoughTime || tooManySummons) { if (tooFar) m.SendLocalizedMessage(1071512); // ...but the corpse is too far away! else if (notEnoughTime) m.SendLocalizedMessage(1071515); // ...but not enough time has passed since you were slain in battle! else m.SendLocalizedMessage(1071517); // ...but the corpse has already been summoned too many times! success = false; } } if (success) { m.PlaySound(0xFA); foreach (var c in corpses) { c.MoveToWorld(m.Location, m.Map); if (Corpse.PlayerCorpses != null && Corpse.PlayerCorpses.ContainsKey(c)) Corpse.PlayerCorpses[c]++; } if (_SummonAll) { m.SendLocalizedMessage(1071530, corpses.Count.ToString()); // ...and succeeds in summoning ~1_COUNT~ of them! if (tooFar) m.SendLocalizedMessage(1071513); // ...but one of them is too far away! else if (notEnoughTime) m.SendLocalizedMessage(1071516); // ...but one of them deflects the magic because of the stain of war! else if (tooManySummons) m.SendLocalizedMessage(1071519); // ...but one of them has already been summoned too many times! } else m.SendLocalizedMessage(1071529); // ...and succeeds in the summoning of it! if (Charges <= 0) { m.SendLocalizedMessage(1071509); // The staff has been reduced to pieces! Delete(); } else { Charges--; } } } private int GetCorpseCount(Mobile m) { if (Corpse.PlayerCorpses == null) return 0; int count = 0; foreach (var kvp in Corpse.PlayerCorpses) { if (kvp.Key.Owner == m && kvp.Value < 3) count++; } return count; } private List GetCorpses(Mobile m) { if (Corpse.PlayerCorpses == null) return null; List list = null; foreach (var kvp in Corpse.PlayerCorpses) { if (kvp.Key.Owner == m && kvp.Value < 3) { if (list == null) list = new List(); if(!list.Contains(kvp.Key)) list.Add(kvp.Key); } if (list != null && list.Count >= 15) break; } return list; } private Corpse GetCorpse(Mobile m) { var corpse = m.Corpse as Corpse; if (corpse == null || Corpse.PlayerCorpses == null || !Corpse.PlayerCorpses.ContainsKey(corpse)) return null; return corpse; } public static bool TryRemoveTimer(Mobile m) { if (_Timers.ContainsKey(m)) { _Timers[m].Stop(); _Timers.Remove(m); m.FixedEffect(0x3735, 6, 30); m.PlaySound(0x5C); m.SendLocalizedMessage(1071525); // You have been disrupted while attempting to pull your corpse! return true; } return false; } public bool IsSummoning() { foreach (var timer in _Timers.Values) { if (timer.Staff == this) return true; } return false; } public class CorpseRetrieveTimer : Timer { public Mobile From { get; set; } public List Corpses { get; set; } public UndertakersStaff Staff { get; set; } public CorpseRetrieveTimer(Mobile from, List corpses, UndertakersStaff staff) : base(TimeSpan.FromSeconds(3)) { From = from; Corpses = corpses; Staff = staff; Start(); } protected override void OnTick() { Staff.TryEndSummon(From, Corpses); } } public UndertakersStaff(Serial serial) : base(serial) { } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write((int)0); // version writer.Write(_Charges); writer.Write(_SummonAll); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); reader.ReadInt(); _Charges = reader.ReadInt(); _SummonAll = reader.ReadBool(); } } }