diff --git a/Data/Locations/felucca.xml b/Data/Locations/felucca.xml
index 890b786..6d4594c 100644
--- a/Data/Locations/felucca.xml
+++ b/Data/Locations/felucca.xml
@@ -3,19 +3,9 @@
-
-
-
-
-
-
-
-
+
-
-
-
-
+
@@ -276,4 +266,4 @@
-
\ No newline at end of file
+
diff --git a/Scripts/Commands/BuildWorld.cs b/Scripts/Commands/BuildWorld.cs
index c236055..7ad5d98 100644
--- a/Scripts/Commands/BuildWorld.cs
+++ b/Scripts/Commands/BuildWorld.cs
@@ -79,14 +79,15 @@ namespace Server.Scripts.Commands
public static void DoDecorate( Mobile m )
{
- m.SendMessage( "Generating World Decorations, Signs & Teleporters..." );
+ m.SendMessage( "Generating World Decorations, Signs & Teleporters, Inn Room Doors..." );
Console.WriteLine( "Decorating the world...");
CommandSystem.Handle(m, String.Format("{0}Decorate", CommandSystem.Prefix));
CommandSystem.Handle(m, String.Format("{0}SignGen", CommandSystem.Prefix));
CommandSystem.Handle(m, String.Format("{0}TelGen", CommandSystem.Prefix));
+ CommandSystem.Handle(m, String.Format("{0}InnGen", CommandSystem.Prefix));
- m.SendMessage( "Decorations, Signs, and Teleporters generated!" );
+ m.SendMessage( "Decorations, Signs, Inn Room Doors, and Teleporters generated!" );
}
public static void DoSpawns( Mobile m )
diff --git a/Scripts/Engines/InnRooms/InnDoor.cs b/Scripts/Engines/InnRooms/InnDoor.cs
new file mode 100644
index 0000000..38a4d13
--- /dev/null
+++ b/Scripts/Engines/InnRooms/InnDoor.cs
@@ -0,0 +1,345 @@
+using System;
+using Server;
+using Server.Items;
+using Server.Mobiles;
+using Server.Custom.InnRooms;
+using Server.Multis;
+using System.Collections.Generic;
+using Server.ContextMenus;
+
+namespace Server.Custom.InnRooms
+{
+ public class InnDoor : Item
+ {
+ private Mobile m_Renter;
+ private InnRoomHouse m_House;
+ private DateTime m_RentExpires;
+ private Point3D m_RoomLocation;
+ private Map m_RoomMap;
+
+ // --- NEW VARIABLES ---
+ private bool m_AutoRenew;
+ private int m_RentCost = 5000;
+ private TimeSpan m_RentDuration = TimeSpan.FromDays(7);
+
+ // --- PUBLIC PROPERTIES EXPOSED FOR THE GUMP ---
+ [CommandProperty(AccessLevel.GameMaster)]
+ public bool AutoRenew { get { return m_AutoRenew; } set { m_AutoRenew = value; } }
+
+ public DateTime RentExpires { get { return m_RentExpires; } set { m_RentExpires = value; } }
+ public int RentCost { get { return m_RentCost; } }
+ public TimeSpan RentDuration { get { return m_RentDuration; } }
+ public InnRoomHouse House { get { return m_House; } }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public bool ForceEviction { get { return false; } set { if (value == true) { EvictTenant(); } } }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public Mobile Renter { get { return m_Renter; } set { m_Renter = value; InvalidateProperties(); } }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public Point3D RoomLocation { get { return m_RoomLocation; } set { m_RoomLocation = value; } }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public Map RoomMap { get { return m_RoomMap; } set { m_RoomMap = value; } }
+
+ [Constructable]
+ public InnDoor() : this(0x6E5)
+ {
+ }
+
+ [Constructable]
+ public InnDoor(int itemID) : base(itemID)
+ {
+ Movable = false;
+ Name = "A Vacant Inn Room";
+ }
+
+ public InnDoor(Serial serial) : base(serial)
+ {
+ }
+
+ public override void OnDoubleClick(Mobile from)
+ {
+ if (!from.InRange(GetWorldLocation(), 2))
+ {
+ from.LocalOverheadMessage(Server.Network.MessageType.Regular, 0x3B2, 1019045);
+ return;
+ }
+
+ // SCENARIO A: The room is VACANT
+ if (m_Renter == null)
+ {
+ if (RoomLocation == Point3D.Zero || RoomMap == null)
+ {
+ from.SendMessage(33, "This door is out of order (No Room Linked).");
+ return;
+ }
+
+ // Swapped to Banker.Withdraw to support AccountGold out of the gate
+ if (Banker.Withdraw(from, m_RentCost))
+ {
+ m_Renter = from;
+ m_RentExpires = DateTime.UtcNow + m_RentDuration;
+ m_AutoRenew = true; // Automatically turn it on for new renters!
+ Name = from.Name + "'s Inn Room";
+
+ m_House = new InnRoomHouse(from);
+ Point3D buriedLocation = new Point3D(RoomLocation.X, RoomLocation.Y, RoomLocation.Z - 20);
+ m_House.MoveToWorld(buriedLocation, RoomMap);
+
+ from.PlaySound(0x249);
+ from.SendMessage(68, $"You have rented this room for {m_RentDuration.Days} days.");
+ TeleportToRoom(from);
+ }
+ else
+ {
+ from.SendMessage(33, $"You need {m_RentCost} gold in your bank to rent this room.");
+ }
+ }
+ // SCENARIO B: The room is RENTED
+ else
+ {
+ // Check if the rent has expired
+ if (DateTime.UtcNow > m_RentExpires)
+ {
+ // MAGIC AUTO-RENEW CHECK
+ if (m_AutoRenew && m_Renter != null && Banker.Withdraw(m_Renter, m_RentCost))
+ {
+ m_RentExpires += m_RentDuration;
+ InvalidateProperties();
+
+ // Let them know it silently renewed behind the scenes
+ if (from == m_Renter)
+ from.SendMessage(68, $"Your auto-renew just processed {m_RentCost} gold from your bank!");
+ }
+ else
+ {
+ EvictTenant();
+ from.SendMessage(33, "The rent expired and the room has been cleared. It is now vacant.");
+ return;
+ }
+ }
+
+ if (m_House != null && (m_House.IsOwner(from) || m_House.IsFriend(from) || m_House.HasAccess(from)))
+ {
+ TeleportToRoom(from);
+ }
+ else
+ {
+ from.SendMessage(33, "The door is locked and you do not have permission to enter.");
+ }
+ }
+ }
+
+ private void TeleportToRoom(Mobile m)
+ {
+ m.PlaySound(0x1EA);
+ m.MoveToWorld(RoomLocation, RoomMap);
+ m.SendMessage(0x3B2, "You enter the inn room.");
+ }
+
+ public void EvictTenant()
+ {
+ if (m_Renter != null && m_House != null && !m_House.Deleted)
+ {
+ BankBox bank = m_Renter.BankBox;
+
+ if (bank != null)
+ {
+ InnEvictionCrate crate = new InnEvictionCrate();
+
+ for (int i = m_House.Secures.Count - 1; i >= 0; --i)
+ {
+ SecureInfo info = m_House.Secures[i] as SecureInfo;
+ if (info != null && info.Item != null)
+ {
+ Container secureContainer = info.Item;
+ secureContainer.IsSecure = false;
+ secureContainer.IsLockedDown = false;
+ secureContainer.Movable = true;
+ crate.DropItem(secureContainer);
+ }
+ }
+ m_House.Secures.Clear();
+
+ for (int i = m_House.LockDowns.Count - 1; i >= 0; --i)
+ {
+ Item item = m_House.LockDowns[i] as Item;
+ if (item != null)
+ {
+ item.IsLockedDown = false;
+ item.Movable = true;
+ crate.DropItem(item);
+ }
+ }
+ m_House.LockDowns.Clear();
+
+ if (crate.Items.Count > 0)
+ {
+ bank.DropItem(crate);
+ m_Renter.SendMessage(33, "Your inn room rent has expired. Your belongings have been packed into a crate and placed in your bank box.");
+ }
+ else
+ {
+ crate.Delete();
+ }
+ }
+
+ m_House.Delete();
+ }
+
+ m_Renter = null;
+ m_House = null;
+ m_AutoRenew = false;
+ Name = "A Vacant Inn Room";
+ }
+
+ public override void GetProperties(ObjectPropertyList list)
+ {
+ base.GetProperties(list);
+
+ if (m_Renter != null)
+ {
+ list.Add(1060658, "Rent Cost\tPaid");
+ list.Add(1060659, "Expires\t{0}", m_RentExpires.ToString("g"));
+ }
+ else
+ {
+ list.Add(1060658, "Rent Cost\t{0} Gold", m_RentCost);
+ }
+ }
+
+ public override void Serialize(GenericWriter writer)
+ {
+ base.Serialize(writer);
+ // Bumped to version 1 to safely save the AutoRenew toggle!
+ writer.Write((int)1);
+
+ writer.Write(m_AutoRenew);
+
+ writer.Write(m_Renter);
+ writer.WriteItem(m_House);
+ writer.Write(m_RentExpires);
+ writer.Write(m_RoomLocation);
+ writer.Write(m_RoomMap);
+ }
+
+ public override void Deserialize(GenericReader reader)
+ {
+ base.Deserialize(reader);
+ int version = reader.ReadInt();
+
+ if (version >= 1)
+ {
+ m_AutoRenew = reader.ReadBool();
+ }
+
+ m_Renter = reader.ReadMobile();
+ m_House = reader.ReadItem() as InnRoomHouse;
+ m_RentExpires = reader.ReadDateTime();
+ m_RoomLocation = reader.ReadPoint3D();
+ m_RoomMap = reader.ReadMap();
+ }
+
+ // --- NEW CONTEXT MENU FOR THE GUMP ---
+ public override void GetContextMenuEntries(Mobile from, List list)
+ {
+ base.GetContextMenuEntries(from, list);
+
+ if (from.Alive && m_Renter == from)
+ {
+ // Cliloc 1063490 is "Manage"
+ list.Add(new ManageRoomEntry(from, this));
+ }
+ }
+
+ private class ManageRoomEntry : ContextMenuEntry
+ {
+ private Mobile m_From;
+ private InnDoor m_Door;
+
+ public ManageRoomEntry(Mobile from, InnDoor door) : base(1063490, 2)
+ {
+ m_From = from;
+ m_Door = door;
+ }
+
+ public override void OnClick()
+ {
+ if (m_Door.Deleted || m_Door.Renter != m_From)
+ return;
+
+ m_From.SendGump(new InnRoomManagementGump((PlayerMobile)m_From, m_Door));
+ }
+ }
+
+ // --- BONUS: DRAG AND DROP RENEWAL ---
+ public override bool OnDragDrop(Mobile from, Item dropped)
+ {
+ if (from == m_Renter && dropped is Gold)
+ {
+ if (dropped.Amount == m_RentCost)
+ {
+ dropped.Delete();
+ m_RentExpires += m_RentDuration;
+
+ from.PlaySound(0x249);
+ from.SendMessage(68, $"You hand the gold to the landlord and extend your rent.");
+ from.SendMessage(68, $"Your room is now paid until: {m_RentExpires.ToString("g")}");
+ InvalidateProperties();
+
+ return true;
+ }
+ else
+ {
+ from.SendMessage(33, $"You must drop exactly {m_RentCost} gold on the door to renew it.");
+ return false;
+ }
+ }
+
+ return base.OnDragDrop(from, dropped);
+ }
+ }
+
+ 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(); }
+ }
+}
diff --git a/Scripts/Engines/InnDoor.cs b/Scripts/Engines/InnRooms/InnDoor.cs.bak
similarity index 100%
rename from Scripts/Engines/InnDoor.cs
rename to Scripts/Engines/InnRooms/InnDoor.cs.bak
diff --git a/Scripts/Engines/InnRoomHouse.cs b/Scripts/Engines/InnRooms/InnRoomHouse.cs
similarity index 70%
rename from Scripts/Engines/InnRoomHouse.cs
rename to Scripts/Engines/InnRooms/InnRoomHouse.cs
index cd91c9a..bb7851b 100644
--- a/Scripts/Engines/InnRoomHouse.cs
+++ b/Scripts/Engines/InnRooms/InnRoomHouse.cs
@@ -16,26 +16,38 @@ namespace Server.Custom.InnRooms
get { return new Point3D(this.X, this.Y - 5, this.Z + 20); }
}
- public InnRoomHouse(Mobile owner) : base(0x1DF3, owner, 50, 2)
+ // --- THE STORAGE FIXES ---
+
+ // 1. Negate the 20% Mondain's Legacy bonus so they get exactly 250 items!
+ public override double BonusStorageScalar { get { return 1.0; } }
+
+ // 2. Both base values are passed as 250
+ public InnRoomHouse(Mobile owner) : base(0xA26, owner, 250, 250)
{
RestrictDecay = true;
+
+ // Force the initial properties to 250
+ MaxLockDowns = 250;
+ MaxSecures = 250;
}
public InnRoomHouse(Serial serial) : base(serial)
{
}
- // --- THE LOCKDOWN FIX ---
+ // The absolute maximum number of floor items
public override int GetAosMaxLockdowns()
{
- return 50; // 50 floor items
+ return 250;
}
+ // The absolute maximum number of total items (chests + floor items + inside chests)
public override int GetAosMaxSecures()
{
- return 250; // 250 total items in the room
+ return 250;
}
- // ------------------------
+
+ // -------------------------
public override bool IsInside(Point3D p, int height)
{
diff --git a/Scripts/Engines/InnRooms/InnRoomManagementGump.cs b/Scripts/Engines/InnRooms/InnRoomManagementGump.cs
new file mode 100644
index 0000000..d7428cb
--- /dev/null
+++ b/Scripts/Engines/InnRooms/InnRoomManagementGump.cs
@@ -0,0 +1,117 @@
+using System;
+using Server;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Custom.InnRooms
+{
+ public class InnRoomManagementGump : Gump
+ {
+ private PlayerMobile m_Player;
+ private InnDoor m_Door;
+
+ public InnRoomManagementGump(PlayerMobile pm, InnDoor door) : base(150, 150)
+ {
+ m_Player = pm;
+ m_Door = door;
+
+ if (m_Door == null || m_Door.House == null || m_Door.Deleted)
+ return;
+
+ AddPage(0);
+ AddBackground(0, 0, 400, 350, 9270);
+ AddHtml(0, 15, 400, 20, "Room Management", false, false);
+
+ // --- STORAGE STATS ---
+ // Tapping into the core BaseHouse math to get exact counts!
+ int sec = 0, ven = 0, lck = 0, mc = 0;
+ int usedStorage = m_Door.House.GetAosCurSecures(out sec, out ven, out lck, out mc);
+ int maxStorage = m_Door.House.GetAosMaxSecures();
+
+ AddHtml(40, 60, 150, 20, "Storage Used:", false, false);
+ AddHtml(150, 60, 200, 20, $"{usedStorage} / {maxStorage} Items", false, false);
+
+ // --- RENT INFO ---
+ AddHtml(40, 110, 150, 20, "Rent Expires:", false, false);
+ AddHtml(150, 110, 200, 20, $"{m_Door.RentExpires.ToString("g")}", false, false);
+
+ // --- ACTIONS ---
+ // 1. Auto-Renew Toggle
+ AddHtml(75, 170, 250, 20, m_Door.AutoRenew ? "Auto-Renew is ON" : "Auto-Renew is OFF", false, false);
+ AddButton(40, 170, 4005, 4007, 1, GumpButtonType.Reply, 0);
+
+ // 2. Manual Renew
+ AddHtml(75, 210, 250, 20, $"Manual Renew ({m_Door.RentCost} Gold)", false, false);
+ AddButton(40, 210, 4005, 4007, 2, GumpButtonType.Reply, 0);
+
+ // 3. Cancel Button
+ AddHtml(75, 280, 250, 20, "Cancel Rental Contract", false, false);
+ AddButton(40, 280, 4005, 4007, 3, GumpButtonType.Reply, 0);
+ }
+
+ public override void OnResponse(NetState sender, RelayInfo info)
+ {
+ if (m_Door == null || m_Door.Deleted || m_Door.Renter != m_Player)
+ return;
+
+ switch (info.ButtonID)
+ {
+ case 1: // Toggle Auto-Renew
+ m_Door.AutoRenew = !m_Door.AutoRenew;
+ m_Player.SendMessage(68, m_Door.AutoRenew ? "Auto-Renew enabled." : "Auto-Renew disabled.");
+ m_Player.SendGump(new InnRoomManagementGump(m_Player, m_Door)); // Refresh Gump
+ break;
+
+ case 2: // Manual Renew
+ if (Banker.Withdraw(m_Player, m_Door.RentCost))
+ {
+ m_Door.RentExpires += m_Door.RentDuration;
+ m_Player.PlaySound(0x249);
+ m_Player.SendMessage(68, $"You paid {m_Door.RentCost} gold. Room paid until: {m_Door.RentExpires.ToString("g")}");
+ m_Door.InvalidateProperties();
+ }
+ else
+ {
+ m_Player.SendMessage(33, $"You need {m_Door.RentCost} gold in your bank to renew.");
+ }
+ m_Player.SendGump(new InnRoomManagementGump(m_Player, m_Door)); // Refresh Gump
+ break;
+
+ case 3: // Cancel Contract
+ m_Player.SendGump(new CancelRentGump(m_Door));
+ break;
+ }
+ }
+ }
+
+ // --- CANCELLATION CONFIRMATION GUMP ---
+ public class CancelRentGump : Gump
+ {
+ private InnDoor m_Door;
+
+ public CancelRentGump(InnDoor door) : base(200, 200)
+ {
+ m_Door = door;
+
+ AddPage(0);
+ AddBackground(0, 0, 300, 150, 9270);
+ AddHtml(0, 15, 300, 20, "Cancel Room Rental?", false, false);
+ AddHtml(20, 50, 260, 40, "This will instantly pack your items into your bank and evict you.", false, false);
+
+ AddButton(40, 100, 4005, 4007, 1, GumpButtonType.Reply, 0);
+ AddHtml(75, 100, 100, 20, "Confirm", false, false);
+
+ AddButton(160, 100, 4005, 4007, 0, GumpButtonType.Reply, 0);
+ AddHtml(195, 100, 100, 20, "Cancel", false, false);
+ }
+
+ public override void OnResponse(NetState sender, RelayInfo info)
+ {
+ if (info.ButtonID == 1 && m_Door != null && !m_Door.Deleted)
+ {
+ m_Door.EvictTenant();
+ }
+ }
+ }
+}
diff --git a/Scripts/Misc/CurrentExpansion.cs b/Scripts/Misc/CurrentExpansion.cs
index 27f9a81..9375933 100644
--- a/Scripts/Misc/CurrentExpansion.cs
+++ b/Scripts/Misc/CurrentExpansion.cs
@@ -7,7 +7,7 @@ namespace Server
{
public class CurrentExpansion
{
- private static readonly Expansion Expansion = Expansion.TOL;
+ private static readonly Expansion Expansion = Expansion.AOS;
public static void Configure()
{
@@ -20,7 +20,7 @@ namespace Server
bool Enabled = Core.AOS;
- Mobile.InsuranceEnabled = Enabled;
+ Mobile.InsuranceEnabled = !Enabled;
ObjectPropertyList.Enabled = Enabled;
Mobile.VisibleDamageType = Enabled ? VisibleDamageType.Related : VisibleDamageType.None;
Mobile.GuildClickMessage = !Enabled;