using System; using System.Collections.Generic; using Server; using Server.Items; using Server.Mobiles; using Server.Multis; namespace Server.Custom.InnRooms { public class InnRoomHouse : BaseHouse { public int RoomIndex; private InnRoomSize m_RoomTier; [CommandProperty(AccessLevel.GameMaster)] public InnRoomSize RoomTier { get { return m_RoomTier; } set { m_RoomTier = value; MaxLockDowns = GetAosMaxLockdowns(); MaxSecures = GetAosMaxSecures(); } } // --- NEW EVICTION VARIABLES --- public Mobile Renter; public DateTime RentExpires; private RentTimer m_Timer; public override Rectangle2D[] Area { get { return new Rectangle2D[] { new Rectangle2D(-15, -15, 30, 30) }; } } public override Point3D BaseBanLocation { get { return new Point3D(this.X, this.Y - 5, this.Z + 20); } } public InnRoomHouse(Mobile owner) : base(0xA28, owner, 50, 2) { RestrictDecay = true; Renter = owner; // Start the internal clock! m_Timer = new RentTimer(this); m_Timer.Start(); } public InnRoomHouse(Serial serial) : base(serial) { } public override int GetAosMaxLockdowns() { switch (RoomTier) { case InnRoomSize.Small: return 350; // 125 Total Items case InnRoomSize.Medium: return 375; // 250 Total Items case InnRoomSize.Large: return 500; // 500 Total Items default: return 125; } } public override int GetAosMaxSecures() { switch (RoomTier) { case InnRoomSize.Small: return 2; // 2 Secure Chests case InnRoomSize.Medium: return 3; // 3 Secure Chests case InnRoomSize.Large: return 4; // 4 Secure Chests default: return 2; } } public override bool IsInside(Point3D p, int height) { if (Deleted) return false; int rx = p.X - this.X; int ry = p.Y - this.Y; bool inArea = false; foreach (Rectangle2D rect in Area) { if (rect.Contains(new Point2D(rx, ry))) { inArea = true; break; } } if (!inArea) return false; if (p.Z >= this.Z && (p.Z + height) <= this.Z + 40) return true; return false; } // --- EVICTION LOGIC --- public void Evict() { if (Deleted) return; // 1. Pack up items and send to bank if (Renter != null && Renter.BankBox != null) { InnEvictionCrate crate = new InnEvictionCrate(); for (int i = Secures.Count - 1; i >= 0; --i) { SecureInfo info = Secures[i] as SecureInfo; if (info != null && info.Item != null) { Container sec = info.Item; sec.IsSecure = false; sec.IsLockedDown = false; sec.Movable = true; crate.DropItem(sec); } } Secures.Clear(); for (int i = LockDowns.Count - 1; i >= 0; --i) { Item item = LockDowns[i] as Item; if (item != null) { item.IsLockedDown = false; item.Movable = true; crate.DropItem(item); } } LockDowns.Clear(); if (crate.Items.Count > 0) { Renter.BankBox.DropItem(crate); Renter.SendMessage(33, "Your inn room rent has expired. Your belongings were moved to your bank."); } else { crate.Delete(); } } // 2. Kick anyone currently inside the room back to town List insideMobiles = GetMobiles(); foreach (Mobile m in insideMobiles) { if (m is PlayerMobile) { PlayerMobile pm = (PlayerMobile)m; if (pm.LastInnMap != null && pm.LastInnLocation != Point3D.Zero) { pm.MoveToWorld(pm.LastInnLocation, pm.LastInnMap); pm.LastInnLocation = Point3D.Zero; pm.LastInnMap = null; } else { // Safe fallback if they don't have an anchor pm.MoveToWorld(new Point3D(865, 605, 0), Map.Trammel); // Britain Bank } pm.SendMessage(33, "The rent has expired and you have been evicted from the room."); } } // 3. Destroy the house (Freeing the slot for the Manager!) Delete(); } public override void OnDelete() { if (m_Timer != null) m_Timer.Stop(); base.OnDelete(); } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write((int)2); // Version bumped to 2! writer.Write(Renter); writer.Write(RentExpires); writer.Write((int)RoomTier); writer.Write(RoomIndex); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); int version = reader.ReadInt(); switch (version) { case 2: { Renter = reader.ReadMobile(); RentExpires = reader.ReadDateTime(); goto case 1; } case 1: { RoomTier = (InnRoomSize)reader.ReadInt(); RoomIndex = reader.ReadInt(); goto case 0; } case 0: { break; } } // Restart the internal clock on server boot m_Timer = new RentTimer(this); m_Timer.Start(); } // --- INTERNAL CLOCK --- private class RentTimer : Timer { private InnRoomHouse m_House; // Checks the expiration date every 1 minute public RentTimer(InnRoomHouse house) : base(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0)) { m_House = house; Priority = TimerPriority.FiveSeconds; } protected override void OnTick() { if (m_House == null || m_House.Deleted) { Stop(); return; } if (DateTime.UtcNow > m_House.RentExpires) { m_House.Evict(); Stop(); } } } } // --- READ-ONLY EVICTION CRATE --- public class InnEvictionCrate : WoodenBox { public override int DefaultMaxItems { get { return 500; } } public override int DefaultMaxWeight { get { return 5000; } } [Constructable] public InnEvictionCrate() { Name = "Evicted Inn Room Belongings"; Hue = 33; } public InnEvictionCrate(Serial serial) : base(serial) { } public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) { if (m.AccessLevel < AccessLevel.GameMaster) { if (message) m.SendLocalizedMessage(1061145); return false; } return base.CheckHold(m, item, message, checkItems, plusItems, plusWeight); } public override void OnItemRemoved(Item item) { base.OnItemRemoved(item); if (this.TotalItems == 0) Delete(); } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write((int)0); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); int version = reader.ReadInt(); } } }