Files
abysmal-isle/Scripts/Multis/BaseHouse.cs
Unstable Kitsune b918192e4e Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
2023-11-28 23:20:26 -05:00

5020 lines
158 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Server.Accounting;
using Server.ContextMenus;
using Server.Guilds;
using Server.Gumps;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Multis.Deeds;
using Server.Network;
using Server.Regions;
using Server.Targeting;
using Server.Engines.Auction;
using Server.Engines.NewMagincia;
namespace Server.Multis
{
public abstract class BaseHouse : BaseMulti
{
public static int AccountHouseLimit { get; } = Config.Get("Housing.AccountHouseLimit", 1);
public static bool NewVendorSystem { get { return Core.AOS; } } // Is new player vendor system enabled?
public static double GlobalBonusStorageScalar { get { return Core.ML ? Core.SA ? 1.4 : 1.2 : 1.0; } }
public const int MaxCoOwners = 15;
public static int MaxFriends { get { return !Core.AOS ? 50 : 140; } }
public static int MaxBans { get { return !Core.AOS ? 50 : 140; } }
#region Dynamic decay system
private DecayLevel m_CurrentStage;
[CommandProperty(AccessLevel.GameMaster)]
public DateTime NextDecayStage { get; set; }
public void ResetDynamicDecay()
{
m_CurrentStage = DecayLevel.Ageless;
NextDecayStage = DateTime.MinValue;
}
public void SetDynamicDecay(DecayLevel level)
{
m_CurrentStage = level;
if (DynamicDecay.Decays(level))
NextDecayStage = DateTime.UtcNow + DynamicDecay.GetRandomDuration(level);
else
NextDecayStage = DateTime.MinValue;
}
#endregion
public const bool DecayEnabled = true;
public static void Decay_OnTick()
{
for (int i = 0; i < AllHouses.Count; ++i)
AllHouses[i].CheckDecay();
}
[CommandProperty(AccessLevel.GameMaster)]
public DateTime LastRefreshed { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public bool RestrictDecay { get; set; }
public virtual TimeSpan DecayPeriod { get { return TimeSpan.FromDays(5.0); } }
public virtual DecayType DecayType
{
get
{
if (RestrictDecay || !DecayEnabled || DecayPeriod == TimeSpan.Zero)
return DecayType.Ageless;
if (m_Owner == null)
return Core.AOS ? DecayType.Condemned : DecayType.ManualRefresh;
Account acct = m_Owner.Account as Account;
if (acct == null)
return Core.AOS ? DecayType.Condemned : DecayType.ManualRefresh;
if (acct.AccessLevel >= AccessLevel.GameMaster)
return DecayType.Ageless;
for (int i = 0; i < acct.Length; ++i)
{
Mobile mob = acct[i];
if (mob != null && mob.AccessLevel >= AccessLevel.GameMaster)
return DecayType.Ageless;
}
if (!Core.AOS)
return DecayType.ManualRefresh;
if (acct.Inactive)
return DecayType.Condemned;
List<BaseHouse> allHouses = GetHouses(m_Owner);
BaseHouse newest = null;
for (int i = 0; i < allHouses.Count; ++i)
{
BaseHouse check = allHouses[i];
if (newest == null || IsNewer(check, newest))
newest = check;
}
ColUtility.Free(allHouses);
if (this == newest)
return DecayType.AutoRefresh;
return DecayType.ManualRefresh;
}
}
public bool IsNewer(BaseHouse check, BaseHouse house)
{
DateTime checkTime = check.LastTraded > check.BuiltOn ? check.LastTraded : check.BuiltOn;
DateTime houseTime = house.LastTraded > house.BuiltOn ? house.LastTraded : house.BuiltOn;
return checkTime > houseTime;
}
private DecayType _CurrentDecay;
public virtual bool CanDecay
{
get
{
var decay = DecayType;
if (!World.Loading)
{
if (_CurrentDecay != DecayType.Condemned)
{
if (decay == DecayType.Condemned)
{
OnCondemned();
}
}
_CurrentDecay = decay;
}
return decay == DecayType.Condemned || decay == DecayType.ManualRefresh;
}
}
private DecayLevel m_LastDecayLevel;
[CommandProperty(AccessLevel.GameMaster)]
public virtual DecayLevel DecayLevel
{
get
{
DecayLevel result;
if (!CanDecay)
{
if (DynamicDecay.Enabled)
ResetDynamicDecay();
LastRefreshed = DateTime.UtcNow;
result = DecayLevel.Ageless;
}
else if (DynamicDecay.Enabled)
{
DecayLevel stage = m_CurrentStage;
if (stage == DecayLevel.Ageless || (DynamicDecay.Decays(stage) && NextDecayStage <= DateTime.UtcNow))
SetDynamicDecay(++stage);
if (stage == DecayLevel.Collapsed && (HasRentedVendors || VendorInventories.Count > 0))
result = DecayLevel.DemolitionPending;
else
result = stage;
}
else
{
result = GetOldDecayLevel();
}
if (result != m_LastDecayLevel)
{
m_LastDecayLevel = result;
if (Sign != null && !Sign.GettingProperties)
Sign.InvalidateProperties();
}
return result;
}
}
public DecayLevel GetOldDecayLevel()
{
TimeSpan timeAfterRefresh = DateTime.UtcNow - LastRefreshed;
int percent = (int)(timeAfterRefresh.Ticks * 1000 / DecayPeriod.Ticks);
if (percent >= 1000) // 100.0%
return (HasRentedVendors || VendorInventories.Count > 0) ? DecayLevel.DemolitionPending : DecayLevel.Collapsed;
else if (percent >= 950) // 95.0% - 99.9%
return DecayLevel.IDOC;
else if (percent >= 750) // 75.0% - 94.9%
return DecayLevel.Greatly;
else if (percent >= 500) // 50.0% - 74.9%
return DecayLevel.Fairly;
else if (percent >= 250) // 25.0% - 49.9%
return DecayLevel.Somewhat;
else if (percent >= 005) // 00.5% - 24.9%
return DecayLevel.Slightly;
return DecayLevel.LikeNew;
}
public virtual bool RefreshDecay()
{
if (DecayType == DecayType.Condemned)
return false;
DecayLevel oldLevel = DecayLevel;
LastRefreshed = DateTime.UtcNow;
if (DynamicDecay.Enabled)
ResetDynamicDecay();
if (Sign != null)
Sign.InvalidateProperties();
return oldLevel > DecayLevel.LikeNew;
}
public virtual bool CheckDecay()
{
if (!Deleted && DecayLevel == DecayLevel.Collapsed)
{
Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Decay_Sandbox));
return true;
}
return false;
}
public virtual void KillVendors()
{
PlayerVendors.OfType<PlayerVendor>().IterateReverse(o => o.Destroy(true));
PlayerBarkeepers.IterateReverse(o => o.Delete());
}
public virtual void Decay_Sandbox()
{
if (Deleted)
return;
if (Core.ML)
new TempNoHousingRegion(this, null);
if (Core.SA)
{
Rectangle3D[] recs = m_Region.Area;
Map map = Map;
Timer.DelayCall(TimeSpan.FromMilliseconds(250), () => OnAfterDecay(recs, map));
}
KillVendors();
Delete();
}
public virtual void OnAfterDecay(Rectangle3D[] recs, Map map)
{
if (map != null && recs.Length > 0)
{
int count = Utility.RandomMinMax(1, 4);
for (int i = 0; i < count; i++)
{
var rec3D = recs[Utility.Random(recs.Length)];
var rec2D = new Rectangle2D(rec3D.Start, rec3D.End);
var eable = map.GetItemsInBounds(rec2D);
var list = new List<Item>();
foreach (Item item in eable)
{
if (item.RootParent == null && item.Movable && item.LootType != LootType.Blessed)
{
list.Add(item);
}
}
if (list.Count > 0)
{
Item item = list[Utility.Random(list.Count)];
if (item != null)
{
var grubber = new Grubber();
grubber.MoveToWorld(item.Location, item.Map);
grubber.PackItem(item);
}
}
eable.Free();
ColUtility.Free(list);
}
}
}
public virtual TimeSpan RestrictedPlacingTime { get { return TimeSpan.FromHours(1.0); } }
[CommandProperty(AccessLevel.GameMaster)]
public virtual double BonusStorageScalar
{
get
{
return GlobalBonusStorageScalar;
}
}
private bool m_Public;
private HouseRegion m_Region;
private TrashBarrel m_Trash;
private Mobile m_Owner;
private Point3D m_RelativeBanLocation;
private static readonly Dictionary<Mobile, List<BaseHouse>> m_Table = new Dictionary<Mobile, List<BaseHouse>>();
public virtual bool IsAosRules { get { return Core.AOS; } }
public virtual bool IsActive { get { return true; } }
public virtual HousePlacementEntry GetAosEntry()
{
return HousePlacementEntry.Find(this);
}
public virtual int GetAosMaxSecures()
{
HousePlacementEntry hpe = GetAosEntry();
if (hpe == null)
return 0;
return (int)(hpe.Storage * BonusStorageScalar);
}
public virtual int GetAosMaxLockdowns()
{
HousePlacementEntry hpe = GetAosEntry();
if (hpe == null)
return 0;
return (int)(hpe.Lockdowns * BonusStorageScalar);
}
private Type[] _NoItemCountTable = new Type[]
{
typeof(Engines.Plants.SeedBox), typeof(GardenShedAddon),
typeof(GardenShedBarrel), typeof(BaseSpecialScrollBook),
typeof(JewelryBox)
};
private Type[] _NoDecayItems = new Type[]
{
typeof(BaseBoard), typeof(Aquarium),
typeof(FishBowl), typeof(BaseSpecialScrollBook),
typeof(Engines.Plants.SeedBox), typeof(JewelryBox),
};
// Not Included Storage
public virtual bool CheckCounts(Item item)
{
if (_NoItemCountTable.Any(x => item.GetType() == x || item.GetType().IsSubclassOf(x)))
{
return false;
}
return true;
}
// Contents will not decay
public virtual bool CheckContentsDecay(Item item)
{
if (_NoDecayItems.Any(x => item.GetType() == x ||item.GetType().IsSubclassOf(x)))
{
return false;
}
return true;
}
public virtual int GetAosCurSecures(out int fromSecures, out int fromVendors, out int fromLockdowns, out int fromMovingCrate)
{
/* Secured container, container counts as fromLockdowns, items count as fromSecures
* Locked Down Container, container and items count as fromLockdowns */
fromSecures = 0;
fromVendors = 0;
fromLockdowns = 0;
fromMovingCrate = 0;
List<SecureInfo> list = Secures;
if (list != null)
{
for (int i = 0; i < list.Count; ++i)
{
SecureInfo si = (SecureInfo)list[i];
if (CheckCounts(si.Item) && !LockDowns.ContainsKey(si.Item))
{
fromSecures += si.Item.TotalItems;
}
}
fromLockdowns += list.Where(x => !LockDowns.ContainsKey(x.Item)).Count();
}
fromLockdowns += GetLockdowns();
fromLockdowns += GetCommissionVendorLockdowns();
if (!NewVendorSystem)
{
foreach (var vendor in PlayerVendors)
{
if (vendor.Backpack != null)
{
fromVendors += vendor.Backpack.TotalItems;
}
}
}
if (MovingCrate != null)
{
fromMovingCrate += MovingCrate.TotalItems;
foreach (Item item in MovingCrate.Items)
{
if (item is PackingBox)
fromMovingCrate--;
}
}
return fromSecures + fromVendors + fromLockdowns + fromMovingCrate;
}
public bool InRange(IPoint2D from, int range)
{
if (Region == null)
return false;
foreach (Rectangle3D rect in Region.Area)
{
if (from.X >= rect.Start.X - range && from.Y >= rect.Start.Y - range && from.X < rect.End.X + range && from.Y < rect.End.Y + range)
return true;
}
return false;
}
public virtual int GetNewVendorSystemMaxVendors()
{
HousePlacementEntry hpe = GetAosEntry();
if (hpe == null)
return 0;
return (int)(hpe.Vendors * BonusStorageScalar);
}
public virtual bool CanPlaceNewVendor()
{
if (!IsAosRules)
return true;
if (!NewVendorSystem)
return CheckAosLockdowns(10);
return (PlayerVendors.Count + VendorRentalContracts.Count) < GetNewVendorSystemMaxVendors();
}
public const int MaximumBarkeepCount = 2;
public virtual bool CanPlaceNewBarkeep()
{
return PlayerBarkeepers.Count < MaximumBarkeepCount;
}
public static void IsThereVendor(Point3D location, Map map, out bool vendor, out bool rentalContract)
{
vendor = false;
rentalContract = false;
IPooledEnumerable eable = map.GetObjectsInRange(location, 0);
foreach (IEntity entity in eable)
{
if (Math.Abs(location.Z - entity.Z) <= 16)
{
if (entity is PlayerVendor || entity is PlayerBarkeeper || entity is PlayerVendorPlaceholder)
{
vendor = true;
break;
}
if (entity is VendorRentalContract)
{
rentalContract = true;
break;
}
}
}
eable.Free();
}
public bool HasPersonalVendors
{
get
{
foreach (var vendor in PlayerVendors)
{
if (!(vendor is RentedVendor))
return true;
}
return false;
}
}
public bool HasRentedVendors
{
get
{
foreach (var vendor in PlayerVendors)
{
if (vendor is RentedVendor)
return true;
}
return false;
}
}
#region Mondain's Legacy
public bool HasAddonContainers
{
get
{
foreach (Item item in Addons.Keys)
{
if (item is BaseAddonContainer || item is RaisedGardenAddon || item is WallSafe)
return true;
}
return false;
}
}
#endregion
#region TOL
public bool HasActiveAuction
{
get
{
foreach (Item item in Addons.Keys)
{
if (item is AuctionSafe && ((AuctionSafe)item).Auction != null && ((AuctionSafe)item).Auction.OnGoing)
return true;
}
return false;
}
}
#endregion
public List<Mobile> AvailableVendorsFor(Mobile m)
{
List<Mobile> list = new List<Mobile>();
foreach (var vendor in PlayerVendors.OfType<PlayerVendor>())
{
if (vendor.CanInteractWith(m, false))
list.Add(vendor);
}
return list;
}
public bool AreThereAvailableVendorsFor(Mobile m)
{
foreach (var vendor in PlayerVendors.OfType<PlayerVendor>())
{
if (vendor.CanInteractWith(m, false))
return true;
}
return false;
}
public void MoveAllToCrate()
{
RelocatedEntities.Clear();
if (MovingCrate != null)
MovingCrate.Hide();
if (m_Trash != null)
{
m_Trash.Delete();
m_Trash = null;
}
foreach (Item item in LockDowns.Keys)
{
if (!item.Deleted)
{
item.IsLockedDown = false;
item.IsSecure = false;
item.Movable = true;
if (item.Parent == null)
DropToMovingCrate(item);
}
}
LockDowns.Clear();
foreach (Item item in VendorRentalContracts)
{
if (!item.Deleted)
{
item.IsLockedDown = false;
item.IsSecure = false;
item.Movable = true;
if (item.Parent == null)
DropToMovingCrate(item);
}
}
VendorRentalContracts.Clear();
foreach (SecureInfo info in Secures)
{
Item item = info.Item;
if (!item.Deleted)
{
if (item is StrongBox)
item = ((StrongBox)item).ConvertToStandardContainer();
item.IsLockedDown = false;
item.IsSecure = false;
item.Movable = true;
if (item.Parent == null)
DropToMovingCrate(item);
}
}
Secures.Clear();
foreach (Item addon in Addons.Keys)
{
if (!addon.Deleted)
{
Item deed = null;
bool retainDeedHue = false; //if the items aren't hued but the deed itself is
int hue = 0;
if (addon is IAddon)
{
deed = ((IAddon)addon).Deed;
if (addon is BaseAddon && ((BaseAddon)addon).RetainDeedHue) //There are things that are IAddon which aren't BaseAddon
{
BaseAddon ba = (BaseAddon)addon;
retainDeedHue = true;
for (int i = 0; hue == 0 && i < ba.Components.Count; ++i)
{
AddonComponent c = ba.Components[i];
if (c.Hue != 0)
hue = c.Hue;
}
}
}
if (deed != null)
{
#region Mondain's Legacy
if (deed is BaseAddonContainerDeed && addon is BaseAddonContainer)
{
BaseAddonContainer c = (BaseAddonContainer)addon;
c.DropItemsToGround();
((BaseAddonContainerDeed)deed).Resource = c.Resource;
}
else if (deed is BaseAddonDeed && addon is BaseAddon)
((BaseAddonDeed)deed).Resource = ((BaseAddon)addon).Resource;
#endregion
addon.Delete();
if (retainDeedHue)
deed.Hue = hue;
DropToMovingCrate(deed);
}
else
{
DropToMovingCrate(addon);
}
}
}
Addons.Clear();
foreach (var mobile in PlayerVendors.OfType<PlayerVendor>())
{
mobile.Return();
mobile.Internalize();
InternalizedVendors.Add(mobile);
}
foreach (Mobile mobile in PlayerBarkeepers)
{
mobile.Internalize();
InternalizedVendors.Add(mobile);
}
}
public Dictionary<IEntity, Mobile> GetHouseEntities()
{
Dictionary<IEntity, Mobile> list = new Dictionary<IEntity, Mobile>();
if (MovingCrate != null)
MovingCrate.Hide();
if (m_Trash != null && m_Trash.Map != Map.Internal)
list[m_Trash] = Owner;
foreach (Item item in LockDowns.Keys)
{
if (item.Parent == null && item.Map != Map.Internal)
list[item] = LockDowns[item];
}
foreach (Item item in VendorRentalContracts)
{
if (item.Parent == null && item.Map != Map.Internal)
list[item] = Owner;
}
foreach (SecureInfo info in Secures.Where(i => !LockDowns.ContainsKey(i.Item)))
{
Item item = info.Item;
if (item.Parent == null && item.Map != Map.Internal)
list[item] = Owner;
}
foreach (Item item in Addons.Keys)
{
if (item.Parent == null && item.Map != Map.Internal)
list[item] = Owner;
}
foreach (var mobile in PlayerVendors.OfType<PlayerVendor>())
{
mobile.Return();
if (mobile.Map != Map.Internal)
list[mobile] = Owner;
}
foreach (Mobile mobile in PlayerBarkeepers)
{
if (mobile.Map != Map.Internal)
list[mobile] = Owner;
}
return list;
}
public void RelocateEntities()
{
Dictionary<IEntity, Mobile> entities = GetHouseEntities();
foreach (IEntity entity in entities.Keys)
{
Point3D relLoc = new Point3D(entity.X - X, entity.Y - Y, entity.Z - Z);
RelocatedEntity relocEntity = new RelocatedEntity(entity, relLoc, entities[entity]);
RelocatedEntities.Add(relocEntity);
if (entity is Item)
((Item)entity).Internalize();
else
((Mobile)entity).Internalize();
}
}
public void RestoreRelocatedEntities()
{
foreach (RelocatedEntity relocEntity in RelocatedEntities)
{
Point3D relLoc = relocEntity.RelativeLocation;
Point3D location = new Point3D(relLoc.X + X, relLoc.Y + Y, relLoc.Z + Z);
IEntity entity = relocEntity.Entity;
if (entity is Item)
{
Item item = (Item)entity;
if (!item.Deleted)
{
if (item is IAddon)
{
if (((IAddon)item).CouldFit(location, Map))
{
item.MoveToWorld(location, Map);
continue;
}
}
else
{
int height;
bool requireSurface;
if (item is VendorRentalContract)
{
height = 16;
requireSurface = true;
}
else
{
height = item.ItemData.Height;
requireSurface = false;
}
if (Map.CanFit(location.X, location.Y, location.Z, height, false, false, requireSurface))
{
item.MoveToWorld(location, Map);
continue;
}
}
// The item can't fit
if (item is TrashBarrel)
{
item.Delete(); // Trash barrels don't go to the moving crate
}
else
{
SetLockdown(relocEntity.Owner, item, false);
item.IsSecure = false;
item.Movable = true;
Item relocateItem = item;
if (item is StrongBox)
relocateItem = ((StrongBox)item).ConvertToStandardContainer();
if (item is IAddon)
{
Item deed;
if (item is FishTrophy)
{
deed = ((FishTrophy)item).TrophyDeed;
}
else
{
deed = ((IAddon)item).Deed;
}
bool retainDeedHue = false; //if the items aren't hued but the deed itself is
int hue = 0;
if (item is BaseAddon && ((BaseAddon)item).RetainDeedHue) //There are things that are IAddon which aren't BaseAddon
{
BaseAddon ba = (BaseAddon)item;
retainDeedHue = true;
for (int i = 0; hue == 0 && i < ba.Components.Count; ++i)
{
AddonComponent c = ba.Components[i];
if (c.Hue != 0)
hue = c.Hue;
}
}
#region Mondain's Legacy
if (deed != null)
{
if (deed is BaseAddonContainerDeed && item is BaseAddonContainer)
{
BaseAddonContainer c = (BaseAddonContainer)item;
c.DropItemsToGround();
((BaseAddonContainerDeed)deed).Resource = c.Resource;
}
else if (deed is BaseAddonDeed && item is BaseAddon)
((BaseAddonDeed)deed).Resource = ((BaseAddon)item).Resource;
if (retainDeedHue)
deed.Hue = hue;
}
#endregion
relocateItem = deed;
item.Delete();
}
if (relocateItem != null)
DropToMovingCrate(relocateItem);
}
}
if (m_Trash == item)
m_Trash = null;
LockDowns.Remove(item);
VendorRentalContracts.Remove(item);
Addons.Remove(item);
for (int i = Secures.Count - 1; i >= 0; i--)
{
if (((SecureInfo)Secures[i]).Item == item)
Secures.RemoveAt(i);
}
}
else
{
Mobile mobile = (Mobile)entity;
if (!mobile.Deleted)
{
if (Map.CanFit(location, 16, false, false))
{
mobile.MoveToWorld(location, Map);
}
else
{
InternalizedVendors.Add(mobile);
}
}
}
}
RelocatedEntities.Clear();
}
public void DropToMovingCrate(Item item)
{
if (MovingCrate == null)
MovingCrate = new MovingCrate(this);
MovingCrate.DropItem(item);
}
public List<Item> GetItems()
{
if (Map == null || Map == Map.Internal)
return new List<Item>();
Point2D start = new Point2D(X + Components.Min.X, Y + Components.Min.Y);
Point2D end = new Point2D(X + Components.Max.X + 1, Y + Components.Max.Y + 1);
Rectangle2D rect = new Rectangle2D(start, end);
List<Item> list = new List<Item>();
IPooledEnumerable eable = Map.GetItemsInBounds(rect);
foreach (Item item in eable)
if (item.Movable && IsInside(item))
list.Add(item);
eable.Free();
return list;
}
public List<Mobile> GetMobiles()
{
if (Map == null || Map == Map.Internal)
return new List<Mobile>();
List<Mobile> list = new List<Mobile>();
foreach (Mobile mobile in Region.GetMobiles())
if (IsInside(mobile))
list.Add(mobile);
return list;
}
public virtual bool CheckAosLockdowns(int need)
{
return (GetAosCurLockdowns() + need) <= GetAosMaxLockdowns();
}
public virtual bool CheckAosStorage(int need)
{
int fromSecures, fromVendors, fromLockdowns, fromMovingCrate;
return (GetAosCurSecures(out fromSecures, out fromVendors, out fromLockdowns, out fromMovingCrate) + need) <= GetAosMaxSecures();
}
public static void Configure()
{
LockedDownFlag = 1;
SecureFlag = 2;
Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), new TimerCallback(Decay_OnTick));
}
public virtual int GetAosCurLockdowns()
{
int v = 0;
v += GetLockdowns();
v += GetCommissionVendorLockdowns();
if (Secures != null)
v += Secures.Where(x => !LockDowns.ContainsKey(x.Item)).Count();
if (!NewVendorSystem)
v += PlayerVendors.Count * 10;
return v;
}
public static bool CheckLockedDown(Item item)
{
BaseHouse house = FindHouseAt(item);
return house != null && house.IsLockedDown(item);
}
public static bool CheckSecured(Item item)
{
BaseHouse house = FindHouseAt(item);
return house != null && house.IsSecure(item);
}
public static bool CheckLockedDownOrSecured(Item item)
{
BaseHouse house = FindHouseAt(item);
return house != null && (house.IsSecure(item) || house.IsLockedDown(item));
}
public static List<BaseHouse> GetHouses(Mobile m)
{
List<BaseHouse> list = new List<BaseHouse>();
if (m != null)
{
m_Table.TryGetValue(m, out List<BaseHouse> exists);
if (exists != null)
{
for (int i = 0; i < exists.Count; ++i)
{
BaseHouse house = exists[i];
if (house != null && !house.Deleted && house.Owner == m)
list.Add(house);
}
}
}
return list;
}
public static bool CheckHold(Mobile m, Container cont, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
{
BaseHouse house = FindHouseAt(cont);
if (house == null || !house.IsAosRules)
return true;
if (house.IsSecure(cont) && !house.CheckAosStorage(1 + item.TotalItems + plusItems))
{
if (message)
m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house.
return false;
}
return true;
}
public static bool CheckAccessible(Mobile m, Item item)
{
if (m.AccessLevel >= AccessLevel.GameMaster)
return true; // Staff can access anything
BaseHouse house = FindHouseAt(item);
if (house == null)
return true;
SecureAccessResult res = house.CheckSecureAccess(m, item);
switch ( res )
{
case SecureAccessResult.Insecure:
break;
case SecureAccessResult.Accessible:
return true;
case SecureAccessResult.Inaccessible:
return false;
}
if (house.IsLockedDown(item))
return house.IsCoOwner(m) && (item is Container);
return true;
}
public static BaseHouse FindHouseAt(Mobile m)
{
if (m == null || m.Deleted)
return null;
return FindHouseAt(m.Location, m.Map, 16);
}
public static BaseHouse FindHouseAt(Item item)
{
if (item == null || item.Deleted)
return null;
return FindHouseAt(item.GetWorldLocation(), item.Map, item.ItemData.Height);
}
public static BaseHouse FindHouseAt(Point3D loc, Map map, int height)
{
if (map == null || map == Map.Internal)
return null;
Sector sector = map.GetSector(loc);
for (int i = 0; i < sector.Multis.Count; ++i)
{
BaseHouse house = sector.Multis[i] as BaseHouse;
if (house != null && house.IsInside(loc, height))
return house;
}
return null;
}
public bool IsInside(Mobile m)
{
if (m == null || m.Deleted || m.Map != Map)
return false;
return IsInside(m.Location, 16);
}
public bool IsInside(Item item)
{
if (item == null || item.Deleted || item.Map != Map)
return false;
return IsInside(item.Location, item.ItemData.Height);
}
public bool CheckAccessibility(Item item, Mobile from)
{
SecureAccessResult res = CheckSecureAccess(from, item);
switch ( res )
{
case SecureAccessResult.Insecure:
break;
case SecureAccessResult.Accessible:
return true;
case SecureAccessResult.Inaccessible:
return false;
}
// staff or not locked down
if (from.AccessLevel >= AccessLevel.GameMaster || IsOwner(from) || !IsLockedDown(item))
return true;
bool lockedDown = LockDowns.ContainsKey(item);
// lockdown owner can access it
if (lockedDown && CheckLockdownOwnership(from, item))
return true;
// ISecurable will set its own rules
if (item is ISecurable)
return HasSecureAccess(from, ((ISecurable)item).Level);
if (item.Stackable)
return true;
// locked down
if (lockedDown)
{
// non friend, but item is on friends only list
if (!IsFriend(from) && IsInList(item, _AccessibleToFriends))
return false;
// anyone can use list, house must be public or player must have access to house
if (IsInList(item, _AccessibleToAll) && (m_Public || Access.Contains(from)))
return true;
return false;
}
return true;
}
private bool IsInList(Item item, Type[] list)
{
foreach (var t in list)
{
if (t == item.GetType() || item.GetType().IsSubclassOf(t))
return true;
}
return false;
}
private Type[] _AccessibleToAll =
{
typeof(TenthAnniversarySculpture), typeof(RewardBrazier), typeof(VendorRentalContract), typeof(Dyes), typeof(DyeTub),
typeof(BaseInstrument), typeof(Clock), typeof(TreasureMap), typeof(RecallRune), typeof(Dices), typeof(BaseBoard),
typeof(Runebook)
};
private Type[] _AccessibleToFriends =
{
typeof(PotionKeg)
};
public virtual bool IsInside(Point3D p, int height)
{
if (Deleted)
return false;
MultiComponentList mcl = Components;
int x = p.X - (X + mcl.Min.X);
int y = p.Y - (Y + mcl.Min.Y);
if (x < 0 || x >= mcl.Width || y < 0 || y >= mcl.Height)
return false;
if (this is HouseFoundation && y < (mcl.Height - 1) && p.Z >= Z)
return true;
StaticTile[] tiles = mcl.Tiles[x][y];
for (int j = 0; j < tiles.Length; ++j)
{
StaticTile tile = tiles[j];
int id = tile.ID & TileData.MaxItemValue;
ItemData data = TileData.ItemTable[id];
// Slanted roofs do not count; they overhang blocking south and east sides of the multi
if ((data.Flags & TileFlag.Roof) != 0)
continue;
// Signs and signposts are not considered part of the multi
if ((id >= 0xB95 && id <= 0xC0E) || (id >= 0xC43 && id <= 0xC44))
continue;
int tileZ = tile.Z + Z;
if (p.Z == tileZ || (p.Z + height) > tileZ)
return true;
}
return IsInsideSpecial(p, tiles);
}
protected virtual bool IsInsideSpecial(Point3D p, StaticTile[] tiles)
{
return false;
}
public SecureAccessResult CheckSecureAccess(Mobile m, Item item)
{
if (Secures == null || !(item is Container))
return SecureAccessResult.Insecure;
for (int i = 0; i < Secures.Count; ++i)
{
SecureInfo info = (SecureInfo)Secures[i];
if (info.Item == item)
return HasSecureAccess(m, info) ? SecureAccessResult.Accessible : SecureAccessResult.Inaccessible;
}
return SecureAccessResult.Insecure;
}
public static List<BaseHouse> AllHouses { get; } = new List<BaseHouse>();
public BaseHouse(int multiID, Mobile owner, int MaxLockDown, int MaxSecure)
: base(multiID)
{
AllHouses.Add(this);
LastRefreshed = DateTime.UtcNow;
BuiltOn = DateTime.UtcNow;
LastTraded = DateTime.MinValue;
Doors = new List<Item>();
LockDowns = new Dictionary<Item, Mobile>();
Secures = new List<SecureInfo>();
Addons = new Dictionary<Item, Mobile>();
Carpets = new List<Item>();
CoOwners = new List<Mobile>();
Friends = new List<Mobile>();
Bans = new List<Mobile>();
Access = new List<Mobile>();
VendorRentalContracts = new List<Item>();
InternalizedVendors = new List<Mobile>();
Visits = new Dictionary<Mobile, DateTime>();
m_Owner = owner;
MaxLockDowns = MaxLockDown;
MaxSecures = MaxSecure;
m_RelativeBanLocation = BaseBanLocation;
UpdateRegion();
if (owner != null)
{
List<BaseHouse> list = null;
m_Table.TryGetValue(owner, out list);
if (list == null)
m_Table[owner] = list = new List<BaseHouse>();
list.Add(this);
}
Movable = false;
}
public BaseHouse(Serial serial)
: base(serial)
{
AllHouses.Add(this);
}
public override void OnMapChange()
{
if (LockDowns == null)
return;
UpdateRegion();
if (Sign != null && !Sign.Deleted)
Sign.Map = Map;
if (Doors != null)
{
foreach (Item item in Doors)
item.Map = Map;
}
foreach (IEntity entity in GetHouseEntities().Keys)
{
if (entity is Item)
((Item)entity).Map = Map;
else
((Mobile)entity).Map = Map;
}
}
public virtual void ChangeSignType(int itemID)
{
if (Sign != null)
Sign.ItemID = itemID;
}
public abstract Rectangle2D[] Area { get; }
public abstract Point3D BaseBanLocation { get; }
public virtual void UpdateRegion()
{
if (m_Region != null)
m_Region.Unregister();
if (Map != null)
{
m_Region = new HouseRegion(this);
m_Region.Register();
}
else
{
m_Region = null;
}
}
public override void OnLocationChange(Point3D oldLocation)
{
if (LockDowns == null)
return;
int x = base.Location.X - oldLocation.X;
int y = base.Location.Y - oldLocation.Y;
int z = base.Location.Z - oldLocation.Z;
if (Sign != null && !Sign.Deleted)
Sign.Location = new Point3D(Sign.X + x, Sign.Y + y, Sign.Z + z);
UpdateRegion();
if (Doors != null)
{
foreach (Item item in Doors)
{
if (!item.Deleted)
item.Location = new Point3D(item.X + x, item.Y + y, item.Z + z);
}
}
foreach (IEntity entity in GetHouseEntities().Keys)
{
Point3D newLocation = new Point3D(entity.X + x, entity.Y + y, entity.Z + z);
if (entity is Item)
((Item)entity).Location = newLocation;
else
((Mobile)entity).Location = newLocation;
}
}
public BaseDoor AddEastDoor(int x, int y, int z)
{
return AddEastDoor(true, x, y, z);
}
public BaseDoor AddEastDoor(bool wood, int x, int y, int z)
{
BaseDoor door = MakeDoor(wood, DoorFacing.SouthCW);
AddDoor(door, x, y, z);
return door;
}
public BaseDoor AddSouthDoor(int x, int y, int z)
{
return AddSouthDoor(true, x, y, z);
}
public BaseDoor AddSouthDoor(bool wood, int x, int y, int z)
{
BaseDoor door = MakeDoor(wood, DoorFacing.WestCW);
AddDoor(door, x, y, z);
return door;
}
public BaseDoor AddEastDoor(int x, int y, int z, uint k)
{
return AddEastDoor(true, x, y, z, k);
}
public BaseDoor AddEastDoor(bool wood, int x, int y, int z, uint k)
{
BaseDoor door = MakeDoor(wood, DoorFacing.SouthCW);
door.KeyValue = k;
AddDoor(door, x, y, z);
return door;
}
public BaseDoor AddSouthDoor(int x, int y, int z, uint k)
{
return AddSouthDoor(true, x, y, z, k);
}
public BaseDoor AddSouthDoor(bool wood, int x, int y, int z, uint k)
{
BaseDoor door = MakeDoor(wood, DoorFacing.WestCW);
door.KeyValue = k;
AddDoor(door, x, y, z);
return door;
}
public BaseDoor[] AddSouthDoors(int x, int y, int z, uint k)
{
return AddSouthDoors(true, x, y, z, k);
}
public BaseDoor[] AddSouthDoors(bool wood, int x, int y, int z, uint k)
{
BaseDoor westDoor = MakeDoor(wood, DoorFacing.WestCW);
BaseDoor eastDoor = MakeDoor(wood, DoorFacing.EastCCW);
westDoor.KeyValue = k;
eastDoor.KeyValue = k;
westDoor.Link = eastDoor;
eastDoor.Link = westDoor;
AddDoor(westDoor, x, y, z);
AddDoor(eastDoor, x + 1, y, z);
return new BaseDoor[2] { westDoor, eastDoor };
}
public BaseDoor[] AddEastDoors(int x, int y, int z, uint k)
{
return AddEastDoors(true, x, y, z, k, false);
}
public BaseDoor[] AddEastDoors(bool wood, int x, int y, int z, uint k)
{
return AddEastDoors(wood, x, y, z, k, false, false);
}
public BaseDoor[] AddEastDoors(bool wood, int x, int y, int z, uint k, bool invert)
{
return AddEastDoors(wood, x, y, z, k, invert, false);
}
public BaseDoor[] AddEastDoors(bool wood, int x, int y, int z)
{
return AddEastDoors(wood, x, y, z, 0, false, false);
}
public BaseDoor[] AddEastDoors(bool wood, int x, int y, int z, bool invert, bool altopen)
{
return AddEastDoors(wood, x, y, z, 0, invert, altopen);
}
public BaseDoor[] AddEastDoors(bool wood, int x, int y, int z, uint k, bool invert, bool altopen)
{
BaseDoor northDoor = MakeDoor(wood, invert ? DoorFacing.SouthCCW : altopen ? DoorFacing.NorthCCW : DoorFacing.NorthCW);
BaseDoor southDoor = MakeDoor(wood, invert ? DoorFacing.NorthCW : altopen ? DoorFacing.SouthCW : DoorFacing.SouthCCW);
northDoor.KeyValue = k;
southDoor.KeyValue = k;
northDoor.Link = southDoor;
southDoor.Link = northDoor;
AddDoor(northDoor, x, y, z);
AddDoor(southDoor, x, y + 1, z);
return new BaseDoor[2] { northDoor, southDoor };
}
protected void ConvertDoor(BaseDoor door, int closedID, bool invert)
{
door.ItemID = closedID;
door.ClosedID = closedID;
door.OpenedID = closedID + 1;
}
protected BaseDoor AddDoor(int itemID, int xOffset, int yOffset, int zOffset)
{
return AddDoor(null, itemID, xOffset, yOffset, zOffset);
}
protected BaseDoor AddDoor(Mobile from, int itemID, int xOffset, int yOffset, int zOffset)
{
BaseDoor door = null;
if (itemID >= 0x675 && itemID < 0x6F5)
{
int type = (itemID - 0x675) / 16;
DoorFacing facing = (DoorFacing)(((itemID - 0x675) / 2) % 8);
switch (type)
{
case 0:
door = new GenericHouseDoor(facing, 0x675, 0xEC, 0xF3);
break;
case 1:
door = new GenericHouseDoor(facing, 0x685, 0xEC, 0xF3);
break;
case 2:
door = new GenericHouseDoor(facing, 0x695, 0xEB, 0xF2);
break;
case 3:
door = new GenericHouseDoor(facing, 0x6A5, 0xEA, 0xF1);
break;
case 4:
door = new GenericHouseDoor(facing, 0x6B5, 0xEA, 0xF1);
break;
case 5:
door = new GenericHouseDoor(facing, 0x6C5, 0xEC, 0xF3);
break;
case 6:
door = new GenericHouseDoor(facing, 0x6D5, 0xEA, 0xF1);
break;
case 7:
door = new GenericHouseDoor(facing, 0x6E5, 0xEA, 0xF1);
break;
}
}
else if (itemID >= 0x314 && itemID < 0x364)
{
int type = (itemID - 0x314) / 16;
DoorFacing facing = (DoorFacing)(((itemID - 0x314) / 2) % 8);
door = new GenericHouseDoor(facing, 0x314 + (type * 16), 0xED, 0xF4);
}
else if (itemID >= 0x824 && itemID < 0x834)
{
DoorFacing facing = (DoorFacing)(((itemID - 0x824) / 2) % 8);
door = new GenericHouseDoor(facing, 0x824, 0xEC, 0xF3);
}
else if (itemID >= 0x839 && itemID < 0x849)
{
DoorFacing facing = (DoorFacing)(((itemID - 0x839) / 2) % 8);
door = new GenericHouseDoor(facing, 0x839, 0xEB, 0xF2);
}
else if (itemID >= 0x84C && itemID < 0x85C)
{
DoorFacing facing = (DoorFacing)(((itemID - 0x84C) / 2) % 8);
door = new GenericHouseDoor(facing, 0x84C, 0xEC, 0xF3);
}
else if (itemID >= 0x866 && itemID < 0x876)
{
DoorFacing facing = (DoorFacing)(((itemID - 0x866) / 2) % 8);
door = new GenericHouseDoor(facing, 0x866, 0xEB, 0xF2);
}
else if (itemID >= 0xE8 && itemID < 0xF8)
{
DoorFacing facing = (DoorFacing)(((itemID - 0xE8) / 2) % 8);
door = new GenericHouseDoor(facing, 0xE8, 0xED, 0xF4);
}
else if (itemID >= 0x1FED && itemID < 0x1FFD)
{
DoorFacing facing = (DoorFacing)(((itemID - 0x1FED) / 2) % 8);
door = new GenericHouseDoor(facing, 0x1FED, 0xEC, 0xF3);
}
else if (itemID >= 0x241F && itemID < 0x2421)
{
//DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8);
door = new GenericHouseDoor(DoorFacing.NorthCCW, 0x2415, -1, -1);
}
else if (itemID >= 0x2423 && itemID < 0x2425)
{
//DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8);
//This one and the above one are 'special' cases, ie: OSI had the ItemID pattern discombobulated for these
door = new GenericHouseDoor(DoorFacing.WestCW, 0x2423, -1, -1);
}
else if (itemID >= 0x2A05 && itemID < 0x2A1D)
{
DoorFacing facing = (DoorFacing)((((itemID - 0x2A05) / 2) % 4) + 8);
int sound = (itemID >= 0x2A0D && itemID < 0x2a15) ? 0x539 : -1;
door = new GenericHouseDoor(facing, 0x29F5 + (8 * ((itemID - 0x2A05) / 8)), sound, sound);
}
else if (itemID == 0x2D46)
{
door = new GenericHouseDoor(DoorFacing.NorthCW, 0x2D46, 0xEA, 0xF1, false);
}
else if (itemID == 0x2D48 || itemID == 0x2FE2)
{
door = new GenericHouseDoor(DoorFacing.SouthCCW, itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x2D63 && itemID < 0x2D70)
{
int mod = (itemID - 0x2D63) / 2 % 2;
DoorFacing facing = ((mod == 0) ? DoorFacing.SouthCCW : DoorFacing.WestCCW);
int type = (itemID - 0x2D63) / 4;
door = new GenericHouseDoor(facing, 0x2D63 + 4 * type + mod * 2, 0xEA, 0xF1, false);
}
else if (itemID == 0x2FE4 || itemID == 0x31AE)
{
door = new GenericHouseDoor(DoorFacing.WestCCW, itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x319C && itemID < 0x31AE)
{
//special case for 0x31aa <-> 0x31a8 (a9)
int mod = (itemID - 0x319C) / 2 % 2;
//bool specialCase = (itemID == 0x31AA || itemID == 0x31A8);
DoorFacing facing;
if (itemID == 0x31AA || itemID == 0x31A8)
facing = ((mod == 0) ? DoorFacing.NorthCW : DoorFacing.EastCW);
else
facing = ((mod == 0) ? DoorFacing.EastCW : DoorFacing.NorthCW);
int type = (itemID - 0x319C) / 4;
door = new GenericHouseDoor(facing, 0x319C + 4 * type + mod * 2, 0xEA, 0xF1, false);
}
else if (itemID >= 0x367B && itemID < 0x369B)
{
int type = (itemID - 0x367B) / 16;
DoorFacing facing = (DoorFacing)(((itemID - 0x367B) / 2) % 8);
switch (type)
{
case 0:
door = new GenericHouseDoor(facing, 0x367B, 0xED, 0xF4);
break; //crystal
case 1:
door = new GenericHouseDoor(facing, 0x368B, 0xEC, 0x3E7);
break; //shadow
}
}
else if (itemID >= 0x409B && itemID < 0x40A3)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x409B), itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x410C && itemID < 0x4114)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x410C), itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x41C2 && itemID < 0x41CA)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41C2), itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x41CF && itemID < 0x41D7)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41CF), itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x436E && itemID < 0x437E)
{
/* These ones had to be different...
* Offset 0 2 4 6 8 10 12 14
* DoorFacing 2 3 2 3 6 7 6 7
*/
int offset = itemID - 0x436E;
DoorFacing facing = (DoorFacing)((offset / 2 + 2 * ((1 + offset / 4) % 2)) % 8);
door = new GenericHouseDoor(facing, itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x46DD && itemID < 0x46E5)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x46DD), itemID, 0xEB, 0xF2, false);
}
else if (itemID >= 0x4D22 && itemID < 0x4D2A)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x4D22), itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x50C8 && itemID < 0x50D0)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50C8), itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x50D0 && itemID < 0x50D8)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50D0), itemID, 0xEA, 0xF1, false);
}
else if (itemID >= 0x5142 && itemID < 0x514A)
{
door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x5142), itemID, 0xF0, 0xEF, false);
}
else if (itemID >= 0x9AD7 && itemID <= 0x9AE6)
{
int type = (itemID - 0x9AD7) / 16;
DoorFacing facing = (DoorFacing)(((itemID - 0x9AD7) / 2) % 8);
door = new GenericHouseDoor(facing, 0x9AD7 + (type * 16), 0xED, 0xF4);
}
else if (itemID >= 0x9B3C && itemID <= 0x9B4B)
{
int type = (itemID - 0x9B3C) / 16;
DoorFacing facing = (DoorFacing)(((itemID - 0x9B3C) / 2) % 8);
door = new GenericHouseDoor(facing, 0x9B3C + (type * 16), 0xED, 0xF4);
}
if (door != null)
{
if (from != null)
{
door.KeyValue = CreateKeys(from);
}
AddDoor(door, xOffset, yOffset, zOffset);
}
else
{
Console.WriteLine("Warning: Unsupported DoorID: {0}", itemID);
}
return door;
}
private static DoorFacing GetSADoorFacing(int offset)
{
/* Offset 0 2 4 6
* DoorFacing 2 3 6 7
*/
return (DoorFacing)((offset / 2 + 2 * (1 + offset / 4)) % 8);
}
public uint CreateKeys(Mobile m)
{
uint value = Key.RandomValue();
if (!IsAosRules)
{
Key packKey = new Key(KeyType.Gold);
Key bankKey = new Key(KeyType.Gold);
packKey.KeyValue = value;
bankKey.KeyValue = value;
packKey.LootType = LootType.Newbied;
bankKey.LootType = LootType.Newbied;
BankBox box = m.BankBox;
if (!box.TryDropItem(m, bankKey, false))
bankKey.Delete();
m.AddToBackpack(packKey);
}
return value;
}
public BaseDoor[] AddSouthDoors(int x, int y, int z)
{
return AddSouthDoors(true, x, y, z, false);
}
public BaseDoor[] AddSouthDoors(bool wood, int x, int y, int z)
{
return AddSouthDoors(wood, x, y, z, false);
}
public BaseDoor[] AddSouthDoors(bool wood, int x, int y, int z, bool inv)
{
BaseDoor westDoor = MakeDoor(wood, inv ? DoorFacing.WestCCW : DoorFacing.WestCW);
BaseDoor eastDoor = MakeDoor(wood, inv ? DoorFacing.EastCW : DoorFacing.EastCCW);
westDoor.Link = eastDoor;
eastDoor.Link = westDoor;
AddDoor(westDoor, x, y, z);
AddDoor(eastDoor, x + 1, y, z);
return new BaseDoor[2] { westDoor, eastDoor };
}
public BaseDoor MakeDoor(bool wood, DoorFacing facing)
{
if (wood)
return new DarkWoodHouseDoor(facing);
else
return new MetalHouseDoor(facing);
}
public void AddDoor(BaseDoor door, int xoff, int yoff, int zoff)
{
door.Locked = true;
door.MoveToWorld(new Point3D(xoff + X, yoff + Y, zoff + Z), Map);
Doors.Add(door);
}
public void AddTrashBarrel(Mobile from)
{
if (!IsActive)
return;
for (int i = 0; Doors != null && i < Doors.Count; ++i)
{
BaseDoor door = Doors[i] as BaseDoor;
Point3D p = door.Location;
if (door.Open)
p = new Point3D(p.X - door.Offset.X, p.Y - door.Offset.Y, p.Z - door.Offset.Z);
if ((from.Z + 16) >= p.Z && (p.Z + 16) >= from.Z)
{
if (from.InRange(p, 1))
{
from.SendLocalizedMessage(502120); // You cannot place a trash barrel near a door or near steps.
return;
}
}
}
if (m_Trash == null || m_Trash.Deleted)
{
m_Trash = new TrashBarrel();
m_Trash.Movable = false;
m_Trash.MoveToWorld(from.Location, from.Map);
from.SendLocalizedMessage(502121); /* You have a new trash barrel.
* Three minutes after you put something in the barrel, the trash will be emptied.
* Be forewarned, this is permanent! */
}
else
{
from.SendLocalizedMessage(502117); // You already have a trash barrel!
}
}
public void SetSign(int xoff, int yoff, int zoff)
{
Sign = new HouseSign(this);
Sign.MoveToWorld(new Point3D(X + xoff, Y + yoff, Z + zoff), Map);
}
public void SetLockdown(Item i, bool locked)
{
SetLockdown(null, i, locked);
}
public void SetLockdown(Mobile m, Item i, bool locked)
{
if (LockDowns == null || (locked && LockDowns.ContainsKey(i)) || (!locked && !LockDowns.ContainsKey(i)))
return;
if (i is BaseAddonContainer)
i.Movable = false;
else
i.Movable = !locked;
i.IsLockedDown = locked;
if (i is BaseContainer)
{
if (!locked)
{
var secure = GetSecureInfoFor(i);
if (secure != null)
Secures.Remove(secure);
}
else
{
Secures.Add(new SecureInfo(i, SecureLevel.Owner, m, true));
}
}
if (m == null)
m = Owner;
Timer.DelayCall(() =>
i.PrivateOverheadMessage(MessageType.Regular, 0, locked ? 501721 : 501657, m.NetState)); // locked down! : [no longer locked down]
if (locked)
{
if (i is VendorRentalContract && i.RootParent == null)
{
if (!VendorRentalContracts.Contains(i))
VendorRentalContracts.Add(i);
}
else
{
LockDowns[i] = m;
}
}
else
{
VendorRentalContracts.Remove(i);
LockDowns.Remove(i);
var secure = GetSecureInfoFor(i);
if (secure != null)
Secures.Remove(secure);
}
if (!locked)
i.SetLastMoved();
if (i is Container && CheckContentsDecay(i))
{
foreach (Item c in i.Items)
SetLockdown(m, c, locked);
}
}
public bool LockDown(Mobile m, Item item)
{
return LockDown(m, item, true);
}
public bool LockDown(Mobile m, Item item, bool checkIsInside)
{
if (!IsFriend(m) || !IsActive)
return false;
if ((item is BaseAddonContainer || item.Movable) && !IsSecure(item))
{
int amt = 1 + item.TotalItems;
Item rootItem = item.RootParent as Item;
Item parentItem = item.Parent as Item;
if (checkIsInside && item.RootParent is Mobile)
{
m.SendLocalizedMessage(1005525);//That is not in your house
}
else if (checkIsInside && !IsInside(item.GetWorldLocation(), item.ItemData.Height))
{
m.SendLocalizedMessage(1005525);//That is not in your house
}
else if (Ethics.Ethic.IsImbued(item))
{
m.SendLocalizedMessage(1005377);//You cannot lock that down
}
else if (IsSecure(rootItem))
{
m.SendLocalizedMessage(501737); // You need not lock down items in a secure container.
}
else if (parentItem != null && !IsLockedDown(parentItem))
{
m.SendLocalizedMessage(501736); // You must lockdown the container first!
}
else if (!(item is VendorRentalContract) && (IsAosRules ? (!CheckAosLockdowns(amt) || !CheckAosStorage(amt)) : (LockDownCount + amt) > MaxLockDowns))
{
m.SendLocalizedMessage(1005379);//That would exceed the maximum lock down limit for this house
}
else
{
SetLockdown(m, item, true);
return true;
}
}
else if (LockDowns.ContainsKey(item))
{
m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1005526); //That is already locked down
return true;
}
else if (item is HouseSign || item is Static)
{
m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1005526); // This is already locked down.
}
else
{
m.SendLocalizedMessage(1005377);//You cannot lock that down
}
return false;
}
private class TransferItem : Item
{
private readonly BaseHouse m_House;
public override string DefaultName
{
get
{
return "a house transfer contract";
}
}
public TransferItem(BaseHouse house)
: base(0x14F0)
{
m_House = house;
Hue = 0x480;
Movable = false;
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
string houseName, owner, location;
houseName = (m_House == null ? "an unnamed house" : m_House.Sign.GetName());
Mobile houseOwner = (m_House == null ? null : m_House.Owner);
if (houseOwner == null)
owner = "nobody";
else
owner = houseOwner.Name;
int xLong = 0, yLat = 0, xMins = 0, yMins = 0;
bool xEast = false, ySouth = false;
bool valid = m_House != null && Sextant.Format(m_House.Location, m_House.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth);
if (valid)
location = String.Format("{0}° {1}'{2}, {3}° {4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W");
else
location = "unknown";
list.Add(1061112, Utility.FixHtml(houseName)); // House Name: ~1_val~
list.Add(1061113, owner); // Owner: ~1_val~
list.Add(1061114, location); // Location: ~1_val~
}
public TransferItem(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Delete();
}
public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted)
{
if (!base.AllowSecureTrade(from, to, newOwner, accepted))
return false;
else if (!accepted)
return true;
if (Deleted || m_House == null || m_House.Deleted || !m_House.IsOwner(from) || !from.CheckAlive() || !to.CheckAlive())
return false;
if (AtAccountHouseLimit(to))
{
from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner!
return false;
}
return m_House.CheckTransferPosition(from, to);
}
public override void OnSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted)
{
if (Deleted)
return;
Delete();
if (m_House == null || m_House.Deleted || !m_House.IsOwner(from) || !from.CheckAlive() || !to.CheckAlive())
return;
if (!accepted)
return;
from.SendLocalizedMessage(501338); // You have transferred ownership of the house.
to.SendLocalizedMessage(501339); /* You are now the owner of this house.
* The house's co-owner, friend, ban, and access lists have been cleared.
* You should double-check the security settings on any doors and teleporters in the house.
*/
m_House.RemoveKeys(from);
m_House.Owner = to;
m_House.Bans.Clear();
m_House.Friends.Clear();
m_House.CoOwners.Clear();
m_House.ChangeLocks(to);
m_House.LastTraded = DateTime.UtcNow;
m_House.OnTransfer();
}
}
public bool CheckTransferPosition(Mobile from, Mobile to)
{
bool isValid = true;
Item sign = Sign;
Point3D p = (sign == null ? Point3D.Zero : sign.GetWorldLocation());
if (from.Map != Map || to.Map != Map)
isValid = false;
else if (sign == null)
isValid = false;
else if (from.Map != sign.Map || to.Map != sign.Map)
isValid = false;
else if (IsInside(from))
isValid = false;
else if (IsInside(to))
isValid = false;
else if (!from.InRange(p, 2))
isValid = false;
else if (!to.InRange(p, 2))
isValid = false;
if (!isValid)
from.SendLocalizedMessage(1062067); // In order to transfer the house, you and the recipient must both be outside the building and within two paces of the house sign.
return isValid;
}
public void BeginConfirmTransfer(Mobile from, Mobile to)
{
if (Deleted || !from.CheckAlive() || !IsOwner(from))
return;
if (NewVendorSystem && HasPersonalVendors)
{
from.SendLocalizedMessage(1062467); // You cannot trade this house while you still have personal vendors inside.
}
else if (DecayLevel == DecayLevel.DemolitionPending)
{
from.SendLocalizedMessage(1005321); // This house has been marked for demolition, and it cannot be transferred.
}
else if (from == to)
{
from.SendLocalizedMessage(1005330); // You cannot transfer a house to yourself, silly.
}
else if (to.Player)
{
if (AtAccountHouseLimit(to))
{
from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner!
}
else if (CheckTransferPosition(from, to))
{
from.SendLocalizedMessage(1005326); // Please wait while the other player verifies the transfer.
if (HasRentedVendors)
{
/* You are about to be traded a home that has active vendor contracts.
* While there are active vendor contracts in this house, you
* <strong>cannot</strong> demolish <strong>OR</strong> customize the home.
* When you accept this house, you also accept landlordship for every
* contract vendor in the house.
*/
to.SendGump(new WarningGump(1060635, 30720, 1062487, 32512, 420, 280, new WarningGumpCallback(ConfirmTransfer_Callback), from));
}
else
{
to.CloseGump(typeof(HouseTransferGump));
to.SendGump(new HouseTransferGump(from, to, this));
}
}
}
else
{
from.SendLocalizedMessage(501384); // Only a player can own a house!
}
}
private void ConfirmTransfer_Callback(Mobile to, bool ok, object state)
{
Mobile from = (Mobile)state;
if (!ok || Deleted || !from.CheckAlive() || !IsOwner(from))
return;
if (CheckTransferPosition(from, to))
{
to.CloseGump(typeof(HouseTransferGump));
to.SendGump(new HouseTransferGump(from, to, this));
}
}
public void EndConfirmTransfer(Mobile from, Mobile to)
{
if (Deleted || !from.CheckAlive() || !IsOwner(from))
return;
if (NewVendorSystem && HasPersonalVendors)
{
from.SendLocalizedMessage(1062467); // You cannot trade this house while you still have personal vendors inside.
}
else if (DecayLevel == DecayLevel.DemolitionPending)
{
from.SendLocalizedMessage(1005321); // This house has been marked for demolition, and it cannot be transferred.
}
else if (from == to)
{
from.SendLocalizedMessage(1005330); // You cannot transfer a house to yourself, silly.
}
else if (to.Player)
{
if (AtAccountHouseLimit(to))
{
from.SendLocalizedMessage(501388); // You cannot transfer ownership to another house owner or co-owner!
}
else if (CheckTransferPosition(from, to))
{
NetState fromState = from.NetState, toState = to.NetState;
if (fromState != null && toState != null)
{
if (from.HasTrade)
{
from.SendLocalizedMessage(1062071); // You cannot trade a house while you have other trades pending.
}
else if (to.HasTrade)
{
to.SendLocalizedMessage(1062071); // You cannot trade a house while you have other trades pending.
}
else if (!to.Alive)
{
// TODO: Check if the message is correct.
from.SendLocalizedMessage(1062069); // You cannot transfer this house to that person.
}
else
{
Container c = fromState.AddTrade(toState);
c.DropItem(new TransferItem(this));
}
}
}
}
else
{
from.SendLocalizedMessage(501384); // Only a player can own a house!
}
}
public virtual void OnTransfer()
{
foreach (var vendor in PlayerVendors.OfType<RentedVendor>())
{
vendor.RenterRenew = false;
vendor.LandlordRenew = false;
}
}
public void OnCondemned()
{
foreach (var vendor in PlayerVendors.OfType<RentedVendor>())
{
string name = Sign == null || Sign.Name == null ? "An Unnamed House" : Sign.Name;
var message = new NewMaginciaMessage(null, new TextDefinition(1154338), string.Format("{0}\t{1}", vendor.ShopName, name));
/* Your rental vendor named ~1_VENDOR~ located in house: ~2_HOUSE~ is in danger of deletion.
* This house has been condemned and you should remove everything on your vendor AS SOON AS
* POSSIBLE or risk possible deletion.*/
MaginciaLottoSystem.SendMessageTo(vendor.Owner, message);
}
}
public bool CheckLockdownOwnership(Mobile m, Item item)
{
if(item == null)
return false;
if(IsOwner(m))
return true;
if(item is BaseContainer || item.Parent is BaseContainer)
{
Item check = item.Parent is BaseContainer ? (Item)item.Parent : item;
return Secures.FirstOrDefault(i => i.Item == check && HasSecureAccess(m, i)) != null;
}
return LockDowns.ContainsKey(item) && IsSameAccount(m, LockDowns[item]);
}
public bool IsSameAccount(Mobile one, Mobile two)
{
if (one == null || two == null)
return false;
if (one == two)
return true;
Account acct = one.Account as Account;
for (int i = 0; i < acct.Length; ++i)
{
if (acct[i] != null && acct[i] == two)
return true;
}
return false;
}
public bool Release(Mobile m, Item item)
{
if (!IsFriend(m) || !IsActive)
return false;
if (IsLockedDown(item))
{
if (!CheckLockdownOwnership(m, item))
{
m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1010418); // You did not lock this down, and you are not able to release this.
}
else if (CanRelease(m, item))
{
SetLockdown(m, item, false);
if (item is RewardBrazier)
((RewardBrazier)item).TurnOff();
return true;
}
return false;
}
else if (IsSecure(item))
{
return ReleaseSecure(m, item);
}
else
{
m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1010416); // This is not locked down or secured.
}
return false;
}
public void AddSecure(Mobile m, Item item)
{
if (Secures == null || !IsCoOwner(m) || !IsActive)
return;
if (!IsInside(item))
{
m.SendLocalizedMessage(1005525); // That is not in your house
}
else if (IsLockedDown(item))
{
m.SendLocalizedMessage(1010550); // This is already locked down and cannot be secured.
}
else if (!(item is Container) || item is BaseSpecialScrollBook)
{
LockDown(m, item);
}
else
{
SecureInfo info = null;
for (int i = 0; info == null && i < Secures.Count; ++i)
if (((SecureInfo)Secures[i]).Item == item)
info = (SecureInfo)Secures[i];
if (info != null)
{
m.CloseGump(typeof (SetSecureLevelGump));
m.SendGump(new SetSecureLevelGump(m, info, this));
}
else if (item.Parent != null)
{
m.SendLocalizedMessage(1010423); // You cannot secure this, place it on the ground first.
}
// Mondain's Legacy mod
else if (!(item is BaseAddonContainer) && !item.Movable)
{
m.SendLocalizedMessage(1010424); // You cannot secure
}
else if (!IsAosRules && SecureCount >= MaxSecures)
{
// The maximum number of secure items has been reached :
m.SendLocalizedMessage(1008142, true, MaxSecures.ToString());
}
else if (IsAosRules ? !CheckAosLockdowns(1) : ((LockDownCount + 125) >= MaxLockDowns))
{
m.SendLocalizedMessage(1005379); // That would exceed the maximum lock down limit for this house
}
else if (IsAosRules && !CheckAosStorage(item.TotalItems))
{
m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house.
}
else
{
info = new SecureInfo((Container)item, SecureLevel.Owner, m);
item.IsLockedDown = false;
item.IsSecure = true;
Secures.Add(info);
if(LockDowns.ContainsKey(item))
LockDowns.Remove(item);
item.Movable = false;
if (item is GardenShedAddon)
{
GardenShedBarrel ad = ((GardenShedAddon)item).SecondContainer as GardenShedBarrel;
SecureInfo info2 = new SecureInfo((Container)ad, SecureLevel.Owner, m);
ad.IsLockedDown = false;
ad.IsSecure = true;
Secures.Add(info2);
if (LockDowns.ContainsKey(ad))
LockDowns.Remove(ad);
ad.Movable = false;
}
m.CloseGump(typeof (SetSecureLevelGump));
m.SendGump(new SetSecureLevelGump(m, info, this));
}
}
}
public virtual bool IsCombatRestricted(Mobile m)
{
if (m == null || !m.Player || m.AccessLevel >= AccessLevel.GameMaster || !IsAosRules || (m_Owner != null && m_Owner.AccessLevel >= AccessLevel.GameMaster))
return false;
for (int i = 0; i < m.Aggressed.Count; ++i)
{
AggressorInfo info = m.Aggressed[i];
Guild attackerGuild = m.Guild as Guild;
Guild defenderGuild = info.Defender.Guild as Guild;
if (info.Defender.Player && info.Defender.Alive && (DateTime.UtcNow - info.LastCombatTime) < HouseRegion.CombatHeatDelay && (attackerGuild == null || defenderGuild == null || defenderGuild != attackerGuild && !defenderGuild.IsEnemy(attackerGuild)))
return true;
}
return false;
}
public bool HasSecureAccess(Mobile m, SecureInfo info)
{
if (info.Owner == m)
return true;
return HasSecureAccess(m, info.Level);
}
public bool HasSecureAccess(Mobile m, SecureLevel level)
{
if (m.AccessLevel >= AccessLevel.GameMaster)
return true;
if (IsCombatRestricted(m))
return false;
switch (level)
{
case SecureLevel.Owner:
return IsOwner(m);
case SecureLevel.CoOwners:
return IsCoOwner(m);
case SecureLevel.Friends:
return IsFriend(m);
case SecureLevel.Anyone:
return true;
case SecureLevel.Guild:
return IsGuildMember(m) | IsOwner(m);
}
return false;
}
public SecureLevel GetSecureAccess(Mobile m)
{
if (IsOwner(m) || m.AccessLevel > AccessLevel.Player)
return SecureLevel.Owner;
if (IsCoOwner(m))
return SecureLevel.CoOwners;
if (IsFriend(m))
return SecureLevel.Friends;
if (IsGuildMember(m))
return SecureLevel.Guild;
return SecureLevel.Anyone;
}
public SecureInfo GetSecureInfoFor(Item item)
{
return Secures.FirstOrDefault(info => info.Item == item);
}
public SecureInfo GetSecureInfoFor(Mobile from, Item item)
{
return Secures.FirstOrDefault(info => info.Item == item && (info.Owner == from || IsOwner(from)));
}
public List<SecureInfo> GetSecureInfosFor(Mobile from)
{
return Secures.Where(s => s.Owner == from).ToList();
}
public bool ReleaseSecure(Mobile m, Item item)
{
if (Secures == null || item is StrongBox || !IsActive || !CanRelease(m, item))
return false;
var info = GetSecureInfoFor(item);
if (info != null)
{
if ((IsOwner(m) || info.Owner == m) /*&& HasSecureAccess(m, info.Level)*/)
{
item.IsLockedDown = false;
item.IsSecure = false;
if (item is BaseAddonContainer)
item.Movable = false;
else
item.Movable = true;
item.SetLastMoved();
item.PublicOverheadMessage(MessageType.Label, 0x3B2, 501656); // [no longer secure]
Secures.Remove(info);
return true;
}
else
{
m.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1010418); // You did not lock this down, and you are not able to release this.
}
return false;
}
m.SendLocalizedMessage(501717); //This isn't secure...
return false;
}
private bool CanRelease(Mobile from, Item item)
{
if (item is Container && item.Items.Any(i => i is CraftableHouseItem || i is CraftableMetalHouseDoor || i is CraftableStoneHouseDoor))
{
from.SendLocalizedMessage(1010417); // You may not release this at this time.
return false;
}
return true;
}
public override bool Decays { get { return false; } }
public void AddStrongBox(Mobile from)
{
if (!IsCoOwner(from) || !IsActive)
return;
if (from == Owner)
{
from.SendLocalizedMessage(502109); // Owners don't get a strong box
return;
}
if (IsAosRules ? !CheckAosLockdowns(1) : ((LockDownCount + 1) > MaxLockDowns))
{
from.SendLocalizedMessage(1005379);//That would exceed the maximum lock down limit for this house
return;
}
foreach (SecureInfo info in Secures)
{
StrongBox c = info.Item as StrongBox;
if (c != null && !c.Deleted && c.Owner == from)
{
from.SendLocalizedMessage(502112);//You already have a strong box
return;
}
}
for (int i = 0; Doors != null && i < Doors.Count; ++i)
{
BaseDoor door = Doors[i] as BaseDoor;
Point3D p = door.Location;
if (door.Open)
p = new Point3D(p.X - door.Offset.X, p.Y - door.Offset.Y, p.Z - door.Offset.Z);
if ((from.Z + 16) >= p.Z && (p.Z + 16) >= from.Z)
{
if (from.InRange(p, 1))
{
from.SendLocalizedMessage(502113); // You cannot place a strongbox near a door or near steps.
return;
}
}
}
StrongBox sb = new StrongBox(from, this);
sb.Movable = false;
sb.IsLockedDown = false;
sb.IsSecure = true;
Secures.Add(new SecureInfo(sb, SecureLevel.CoOwners, from));
sb.MoveToWorld(from.Location, from.Map);
}
public void Kick(Mobile from, Mobile targ)
{
if (!IsFriend(from) || Friends == null)
return;
if (targ.IsStaff() && from.AccessLevel <= targ.AccessLevel)
{
from.SendLocalizedMessage(501346); // Uh oh...a bigger boot may be required!
}
else if (IsFriend(targ) && !Core.ML)
{
from.SendLocalizedMessage(501348); // You cannot eject a friend of the house!
}
else if (targ is PlayerVendor)
{
from.SendLocalizedMessage(501351); // You cannot eject a vendor.
}
else if (!IsInside(targ))
{
from.SendLocalizedMessage(501352); // You may not eject someone who is not in your house!
}
else if (targ is BaseCreature && ((BaseCreature)targ).NoHouseRestrictions)
{
from.SendLocalizedMessage(501347); // You cannot eject that from the house!
}
else
{
targ.MoveToWorld(BanLocation, Map);
from.SendLocalizedMessage(1042840, targ.Name); // ~1_PLAYER NAME~ has been ejected from this house.
targ.SendLocalizedMessage(501341); /* You have been ejected from this house.
* If you persist in entering, you may be banned from the house.
*/
}
}
public void RemoveAccess(Mobile from, Mobile targ)
{
if (!IsFriend(from) || Access == null)
return;
if (Access.Contains(targ))
{
Access.Remove(targ);
if (!HasAccess(targ) && IsInside(targ))
{
targ.Location = BanLocation;
targ.SendLocalizedMessage(1060734); // Your access to this house has been revoked.
}
from.SendLocalizedMessage(1050051); // The invitation has been revoked.
}
}
public void RemoveBan(Mobile from, Mobile targ)
{
if (!IsCoOwner(from) || Bans == null)
return;
if (Bans.Contains(targ))
{
Bans.Remove(targ);
from.SendLocalizedMessage(501297); // The ban is lifted.
}
}
public void Ban(Mobile from, Mobile targ)
{
if (!IsFriend(from) || Bans == null)
return;
if (targ.IsStaff() && from.AccessLevel <= targ.AccessLevel)
{
from.SendLocalizedMessage(501354); // Uh oh...a bigger boot may be required.
}
else if (IsFriend(targ))
{
from.SendLocalizedMessage(501348); // You cannot eject a friend of the house!
}
else if (targ is PlayerVendor)
{
from.SendLocalizedMessage(501351); // You cannot eject a vendor.
}
else if (Bans.Count >= MaxBans)
{
from.SendLocalizedMessage(501355); // The ban limit for this house has been reached!
}
else if (IsBanned(targ))
{
from.SendLocalizedMessage(501356); // This person is already banned!
}
else if (!IsInside(targ))
{
from.SendLocalizedMessage(501352); // You may not eject someone who is not in your house!
}
else if (!Public && IsAosRules)
{
from.SendLocalizedMessage(1062521); // You cannot ban someone from a private house. Revoke their access instead.
}
else if (targ is BaseCreature && ((BaseCreature)targ).NoHouseRestrictions)
{
from.SendLocalizedMessage(1062040); // You cannot ban that.
}
else
{
Bans.Add(targ);
from.SendLocalizedMessage(1042839, targ.Name); // ~1_PLAYER_NAME~ has been banned from this house.
targ.SendLocalizedMessage(501340); // You have been banned from this house.
targ.MoveToWorld(BanLocation, Map);
}
}
public void GrantAccess(Mobile from, Mobile targ)
{
if (!IsFriend(from) || Access == null)
return;
if (HasAccess(targ))
{
from.SendLocalizedMessage(1060729); // That person already has access to this house.
}
else if (!targ.Player)
{
from.SendLocalizedMessage(1060712); // That is not a player.
}
else if (IsBanned(targ))
{
from.SendLocalizedMessage(501367); // This person is banned! Unban them first.
}
else
{
Access.Add(targ);
targ.SendLocalizedMessage(1060735); // You have been granted access to this house.
}
}
public void AddCoOwner(Mobile from, Mobile targ)
{
if (!IsOwner(from) || CoOwners == null || Friends == null)
return;
if (IsOwner(targ))
{
from.SendLocalizedMessage(501360); // This person is already the house owner!
}
else if (Friends.Contains(targ))
{
from.SendLocalizedMessage(501361); // This person is a friend of the house. Remove them first.
}
else if (!targ.Player)
{
from.SendLocalizedMessage(501362); // That can't be a co-owner of the house.
}
else if (IsBanned(targ))
{
from.SendLocalizedMessage(501367); // This person is banned! Unban them first.
}
else if (CoOwners.Count >= MaxCoOwners)
{
from.SendLocalizedMessage(501368); // Your co-owner list is full!
}
else if (CoOwners.Contains(targ))
{
from.SendLocalizedMessage(501369); // This person is already on your co-owner list!
}
else
{
AddCoOwner(targ);
targ.Delta(MobileDelta.Noto);
targ.SendLocalizedMessage(501343); // You have been made a co-owner of this house.
}
}
public void AddCoOwner(Mobile targ)
{
CoOwners.Add(targ);
List<Mobile> remove = new List<Mobile>();
foreach(Mobile m in CoOwners)
{
if (AccountHandler.CheckAccount(m, targ) && m != targ)
remove.Add(m);
}
foreach (Mobile m in remove)
CoOwners.Remove(m);
remove.Clear();
foreach (Mobile m in Friends)
{
if (AccountHandler.CheckAccount(m, targ))
remove.Add(m);
}
foreach (Mobile m in remove)
Friends.Remove(m);
remove.Clear();
remove.TrimExcess();
}
public void RemoveCoOwner(Mobile from, Mobile targ)
{
RemoveCoOwner(from, targ, true);
}
public void RemoveCoOwner(Mobile from, Mobile targ, bool fromMessage)
{
if (!IsOwner(from) || CoOwners == null)
return;
if (CoOwners.Contains(targ))
{
CoOwners.Remove(targ);
targ.Delta(MobileDelta.Noto);
if(fromMessage)
from.SendLocalizedMessage(501299); // Co-owner removed from list.
targ.SendLocalizedMessage(501300); // You have been removed as a house co-owner.
var infos = GetSecureInfosFor(targ);
foreach (var info in infos)
{
if (info.Item is StrongBox)
{
StrongBox c = info.Item as StrongBox;
c.IsLockedDown = false;
c.IsSecure = false;
c.Destroy();
Secures.Remove(info);
}
else
{
info.Owner = from;
}
}
}
}
public void AddFriend(Mobile from, Mobile targ)
{
if (!IsCoOwner(from) || Friends == null || CoOwners == null)
return;
if (IsOwner(targ))
{
from.SendLocalizedMessage(501370); // This person is already an owner of the house!
}
else if (CoOwners.Contains(targ))
{
from.SendLocalizedMessage(501369); // This person is already on your co-owner list!
}
else if (!targ.Player)
{
from.SendLocalizedMessage(501371); // That can't be a friend of the house.
}
else if (IsBanned(targ))
{
from.SendLocalizedMessage(501374); // This person is banned! Unban them first.
}
else if (Friends.Count >= MaxFriends)
{
from.SendLocalizedMessage(501375); // Your friends list is full!
}
else if (Friends.Contains(targ))
{
from.SendLocalizedMessage(501376); // This person is already on your friends list!
}
else
{
Friends.Add(targ);
targ.Delta(MobileDelta.Noto);
targ.SendLocalizedMessage(501337); // You have been made a friend of this house.
}
}
public void RemoveFriend(Mobile from, Mobile targ)
{
RemoveFriend(from, targ, true);
}
public void RemoveFriend(Mobile from, Mobile targ, bool fromMessage)
{
if (!IsCoOwner(from) || Friends == null)
return;
if (Friends.Contains(targ))
{
Friends.Remove(targ);
targ.Delta(MobileDelta.Noto);
if(fromMessage)
from.SendLocalizedMessage(501298); // Friend removed from list.
targ.SendLocalizedMessage(1060751); // You are no longer a friend of this house.
var infos = GetSecureInfosFor(targ);
foreach (var info in infos)
{
info.Owner = from;
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)22); // version
writer.Write((int)_CurrentDecay);
writer.WriteItemList(Carpets, true);
if (!DynamicDecay.Enabled)
{
writer.Write((int)-1);
}
else
{
writer.Write((int)m_CurrentStage);
writer.Write(NextDecayStage);
}
writer.Write((Point3D)m_RelativeBanLocation);
writer.WriteItemList(VendorRentalContracts, true);
writer.WriteMobileList(InternalizedVendors, true);
writer.WriteEncodedInt(RelocatedEntities.Count);
foreach (RelocatedEntity relEntity in RelocatedEntities)
{
writer.Write(relEntity.Owner);
writer.Write((Point3D)relEntity.RelativeLocation);
if ((relEntity.Entity is Item && ((Item)relEntity.Entity).Deleted) || (relEntity.Entity is Mobile && ((Mobile)relEntity.Entity).Deleted))
writer.Write((int)Serial.MinusOne);
else
writer.Write((int)relEntity.Entity.Serial);
}
writer.WriteEncodedInt(VendorInventories.Count);
for (int i = 0; i < VendorInventories.Count; i++)
{
VendorInventory inventory = VendorInventories[i];
inventory.Serialize(writer);
}
writer.Write((DateTime)LastRefreshed);
writer.Write((bool)RestrictDecay);
writer.Write(Visits.Count);
foreach (var kvp in Visits)
{
writer.Write(kvp.Key);
writer.Write(kvp.Value);
}
writer.Write((int)Price);
writer.WriteMobileList(Access);
writer.Write(BuiltOn);
writer.Write(LastTraded);
//writer.WriteItemList(m_Addons, true);
writer.Write(Addons.Count);
foreach (var kvp in Addons)
{
writer.Write(kvp.Key);
writer.Write(kvp.Value);
}
writer.Write(Secures.Count);
for (int i = 0; i < Secures.Count; ++i)
((SecureInfo)Secures[i]).Serialize(writer);
writer.Write(m_Public);
writer.Write(m_Owner);
writer.WriteMobileList(CoOwners, true);
writer.WriteMobileList(Friends, true);
writer.WriteMobileList(Bans, true);
writer.Write(Sign);
writer.Write(m_Trash);
writer.WriteItemList(Doors, true);
writer.Write(LockDowns.Count);
ColUtility.ForEach(LockDowns, (key, value) =>
{
writer.Write(key);
writer.Write(value);
});
writer.Write((int)MaxLockDowns);
writer.Write((int)MaxSecures);
// Items in locked down containers that aren't locked down themselves must decay!
foreach(KeyValuePair<Item, Mobile> kvp in LockDowns)
{
Item item = kvp.Key;
if (item is Container && CheckContentsDecay(item))
{
Container cont = (Container)item;
List<Item> children = cont.Items;
for (int j = 0; j < children.Count; ++j)
{
Item child = children[j];
if (child.Decays && !child.IsLockedDown && !child.IsSecure && (child.LastMoved + child.DecayTime) <= DateTime.UtcNow)
Timer.DelayCall(TimeSpan.Zero, new TimerCallback(child.Delete));
}
}
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
int count;
bool loadedDynamicDecay = false;
Visits = new Dictionary<Mobile, DateTime>();
if (version < 21)
{
SecureInfo.VersionInsertion = true;
}
switch (version)
{
case 22:
{
_CurrentDecay = (DecayType)reader.ReadInt();
goto case 21;
}
case 21: // version 21, version insertion for secureinfo
case 20: // version 20, Addons resulted in version 18 bug added to dictionary
case 19: // version 19, Visit change to dictionary
case 18: // version 18, converted addons list to dictionary
case 17:
{
Carpets = reader.ReadStrongItemList();
goto case 16;
}
case 16: // version 16, converted lockdown list to dictionary
case 15:
{
int stage = reader.ReadInt();
if (stage != -1)
{
m_CurrentStage = (DecayLevel)stage;
NextDecayStage = reader.ReadDateTime();
loadedDynamicDecay = true;
}
goto case 14;
}
case 14:
{
m_RelativeBanLocation = reader.ReadPoint3D();
goto case 13;
}
case 13: // removed ban location serialization
case 12:
{
VendorRentalContracts = reader.ReadStrongItemList();
InternalizedVendors = reader.ReadStrongMobileList();
int relocatedCount = reader.ReadEncodedInt();
for (int i = 0; i < relocatedCount; i++)
{
Mobile m;
if (version > 15)
m = reader.ReadMobile();
else
m = Owner;
Point3D relLocation = reader.ReadPoint3D();
IEntity entity = World.FindEntity(reader.ReadInt());
if (entity != null)
RelocatedEntities.Add(new RelocatedEntity(entity, relLocation, m));
}
int inventoryCount = reader.ReadEncodedInt();
for (int i = 0; i < inventoryCount; i++)
{
VendorInventory inventory = new VendorInventory(this, reader);
VendorInventories.Add(inventory);
}
goto case 11;
}
case 11:
{
LastRefreshed = reader.ReadDateTime();
RestrictDecay = reader.ReadBool();
goto case 10;
}
case 10: // just a signal for updates
case 9:
{
if (version <= 18)
{
reader.ReadInt();
}
else
{
int c = reader.ReadInt();
for (int i = 0; i < c; i++)
{
Mobile visitor = reader.ReadMobile();
DateTime lastVisit = reader.ReadDateTime();
if (visitor != null)
Visits[visitor] = lastVisit;
}
}
goto case 8;
}
case 8:
{
Price = reader.ReadInt();
goto case 7;
}
case 7:
{
Access = reader.ReadStrongMobileList();
goto case 6;
}
case 6:
{
BuiltOn = reader.ReadDateTime();
LastTraded = reader.ReadDateTime();
goto case 5;
}
case 5: // just removed fields
case 4:
{
Addons = new Dictionary<Item, Mobile>();
if (version < 18)
{
var list = reader.ReadStrongItemList();
foreach (var item in list)
{
Addons[item] = Owner;
}
}
else
{
int c = reader.ReadInt();
for (int i = 0; i < c; i++)
{
var item = reader.ReadItem();
var mob = reader.ReadMobile();
if (item != null)
{
Addons[item] = mob != null ? mob : Owner;
}
}
}
goto case 3;
}
case 3:
{
count = reader.ReadInt();
Secures = new List<SecureInfo>(count);
for (int i = 0; i < count; ++i)
{
SecureInfo info = new SecureInfo(reader);
if (info.Item != null)
{
info.Item.IsSecure = info.IsLockdown ? false : true;
Secures.Add(info);
}
}
goto case 2;
}
case 2:
{
m_Public = reader.ReadBool();
goto case 1;
}
case 1:
{
if (version < 13)
reader.ReadPoint3D(); // house ban location
goto case 0;
}
case 0:
{
if (version < 17)
Carpets = new List<Item>();
if (version < 14)
m_RelativeBanLocation = BaseBanLocation;
if (version < 12)
{
VendorRentalContracts = new List<Item>();
InternalizedVendors = new List<Mobile>();
}
if (version < 4)
Addons = new Dictionary<Item, Mobile>();
if (version < 7)
Access = new List<Mobile>();
if (version < 8)
Price = DefaultPrice;
m_Owner = reader.ReadMobile();
if (version < 5)
{
count = reader.ReadInt();
for (int i = 0; i < count; i++)
reader.ReadRect2D();
}
UpdateRegion();
CoOwners = reader.ReadStrongMobileList();
Friends = reader.ReadStrongMobileList();
Bans = reader.ReadStrongMobileList();
Sign = reader.ReadItem() as HouseSign;
m_Trash = reader.ReadItem() as TrashBarrel;
Doors = reader.ReadStrongItemList();
LockDowns = new Dictionary<Item, Mobile>();
if (version < 16)
{
List<Item> list = reader.ReadStrongItemList();
foreach (Item item in list)
{
item.IsLockedDown = true;
LockDowns[item] = Owner;
}
}
else
{
int c = reader.ReadInt();
for (int i = 0; i < c; i++)
{
Item item = reader.ReadItem();
Mobile m = reader.ReadMobile();
if (item != null)
{
item.IsLockedDown = true;
LockDowns[item] = m != null ? m : Owner;
}
}
}
for (int i = 0; i < VendorRentalContracts.Count; ++i)
((Item)VendorRentalContracts[i]).IsLockedDown = true;
if (version < 3)
{
List<Item> items = reader.ReadStrongItemList();
Secures = new List<SecureInfo>(items.Count);
for (int i = 0; i < items.Count; ++i)
{
Container c = items[i] as Container;
if (c != null)
{
c.IsSecure = true;
Secures.Add(new SecureInfo(c, SecureLevel.CoOwners, Owner));
}
}
}
MaxLockDowns = reader.ReadInt();
MaxSecures = reader.ReadInt();
if ((Map == null || Map == Map.Internal) && Location == Point3D.Zero)
Delete();
if (m_Owner != null)
{
List<BaseHouse> list = null;
m_Table.TryGetValue(m_Owner, out list);
if (list == null)
m_Table[m_Owner] = list = new List<BaseHouse>();
list.Add(this);
}
break;
}
}
if (version <= 1)
ChangeSignType(0xBD2);//private house, plain brass sign
if (version < 10)
{
/* NOTE: This can exceed the house lockdown limit. It must be this way, because
* we do not want players' items to decay without them knowing. Or not even
* having a chance to fix it themselves.
*/
Timer.DelayCall(TimeSpan.Zero, new TimerCallback(FixLockdowns_Sandbox));
}
if (version < 11)
LastRefreshed = DateTime.UtcNow + TimeSpan.FromHours(24 * Utility.RandomDouble());
if (DynamicDecay.Enabled && !loadedDynamicDecay)
{
DecayLevel old = GetOldDecayLevel();
if (old == DecayLevel.DemolitionPending)
old = DecayLevel.Collapsed;
SetDynamicDecay(old);
}
if (!CheckDecay())
{
if (RelocatedEntities.Count > 0)
Timer.DelayCall(TimeSpan.Zero, new TimerCallback(RestoreRelocatedEntities));
//if (m_Owner == null && m_Friends.Count == 0 && m_CoOwners.Count == 0)
// Timer.DelayCall(TimeSpan.FromSeconds(10.0), new TimerCallback(Delete));
}
if (version == 19)
{
Timer.DelayCall(CheckUnregisteredAddons);
}
}
private void CheckUnregisteredAddons()
{
if (Region == null || Addons == null)
return;
foreach (var item in Region.GetEnumeratedItems().Where(i => i is IAddon))
{
if(Addons.ContainsKey(item))
continue;
Addons[item] = Owner;
}
foreach (var item in Region.GetEnumeratedItems().Where(i => i is AddonComponent && ((AddonComponent)i).Addon == null))
{
item.Delete();
}
}
private void FixLockdowns_Sandbox()
{
Dictionary<Item, Mobile> lockDowns = new Dictionary<Item, Mobile>();
foreach(KeyValuePair<Item, Mobile> kvp in LockDowns)
{
if (kvp.Key is Container)
lockDowns.Add(kvp.Key, kvp.Value);
}
foreach (KeyValuePair<Item, Mobile> kvp in lockDowns)
SetLockdown(kvp.Value, kvp.Key, true);
}
public static void HandleDeletion(Mobile mob)
{
List<BaseHouse> houses = GetHouses(mob);
if (houses.Count == 0)
return;
Account acct = mob.Account as Account;
Mobile trans = null;
for (int i = 0; i < acct.Length; ++i)
{
if (acct[i] != null && acct[i] != mob)
trans = acct[i];
}
for (int i = 0; i < houses.Count; ++i)
{
BaseHouse house = houses[i];
bool canClaim = false;
if (trans == null)
canClaim = house.CoOwners.Count > 0;
if (trans == null && !canClaim)
Timer.DelayCall(TimeSpan.Zero, new TimerCallback(house.Delete));
else
house.Owner = trans;
}
ColUtility.Free(houses);
}
[CommandProperty(AccessLevel.GameMaster)]
public Mobile Owner
{
get
{
return m_Owner;
}
set
{
if (m_Owner != null)
{
m_Table.TryGetValue(m_Owner, out List<BaseHouse> list);
if (list == null)
m_Table[m_Owner] = list = new List<BaseHouse>();
list.Remove(this);
m_Owner.Delta(MobileDelta.Noto);
}
m_Owner = value;
if (m_Owner != null)
{
List<BaseHouse> list = null;
m_Table.TryGetValue(m_Owner, out list);
if (list == null)
m_Table[m_Owner] = list = new List<BaseHouse>();
list.Add(this);
m_Owner.Delta(MobileDelta.Noto);
}
if (Sign != null)
Sign.InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Dictionary<Mobile, DateTime> Visits { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int TotalVisits
{
get { return Visits.Count; }
}
[CommandProperty(AccessLevel.GameMaster)]
public bool Public
{
get
{
return m_Public;
}
set
{
if (m_Public != value)
{
m_Public = value;
if (!m_Public) // Privatizing the house, change to brass sign
ChangeSignType(0xBD2);
if (Sign != null)
Sign.InvalidateProperties();
}
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int MaxSecures { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public Point3D BanLocation
{
get
{
if (m_Region != null)
return m_Region.GoLocation;
Point3D rel = m_RelativeBanLocation;
return new Point3D(X + rel.X, Y + rel.Y, Z + rel.Z);
}
set
{
RelativeBanLocation = new Point3D(value.X - X, value.Y - Y, value.Z - Z);
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Point3D RelativeBanLocation
{
get
{
return m_RelativeBanLocation;
}
set
{
m_RelativeBanLocation = value;
if (m_Region != null)
m_Region.GoLocation = new Point3D(X + value.X, Y + value.Y, Z + value.Z);
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int MaxLockDowns { get; set; }
public Region Region
{
get
{
return m_Region;
}
}
public List<Mobile> CoOwners { get; set; }
public List<Mobile> Friends { get; set; }
public List<Mobile> Access { get; set; }
public List<Mobile> Bans { get; set; }
public List<Item> Doors { get; set; }
public int GetLockdowns()
{
int count = 0;
if (LockDowns != null)
{
foreach(KeyValuePair<Item, Mobile> kvp in LockDowns)
{
Item item = kvp.Key;
if (!(item is Container))
count += item.TotalItems;
count++;
}
}
return count;
}
public int GetCommissionVendorLockdowns()
{
int count = 0;
foreach (var vendor in PlayerVendors.OfType<CommissionPlayerVendor>())
{
if (vendor.Backpack != null)
{
count += vendor.Backpack.TotalItems;
}
}
return count;
}
public int LockDownCount
{
get
{
int count = 0;
count += GetLockdowns();
if (Secures != null)
{
for (int i = 0; i < Secures.Count; ++i)
{
SecureInfo info = Secures[i];
if (info.Item.Deleted)
continue;
else if (info.Item is StrongBox)
count += 1;
else
count += 125;
}
}
return count;
}
}
public int SecureCount
{
get
{
int count = 0;
if (Secures != null)
{
for (int i = 0; i < Secures.Count; i++)
{
SecureInfo info = Secures[i];
if (info.Item.Deleted)
continue;
else if (!(info.Item is StrongBox))
count += 1;
}
}
return count;
}
}
public List<Item> Carpets { get; set; }
public Dictionary<Item, Mobile> Addons { get; set; }
public Dictionary<Item, Mobile> LockDowns { get; private set; }
public List<SecureInfo> Secures { get; private set; }
public HouseSign Sign { get; set; }
public List<Mobile> PlayerVendors { get; } = new List<Mobile>();
public List<Mobile> PlayerBarkeepers { get; } = new List<Mobile>();
public List<Item> VendorRentalContracts { get; private set; }
public List<VendorInventory> VendorInventories { get; } = new List<VendorInventory>();
public List<RelocatedEntity> RelocatedEntities { get; } = new List<RelocatedEntity>();
public MovingCrate MovingCrate { get; set; }
public List<Mobile> InternalizedVendors { get; private set; }
public DateTime BuiltOn { get; set; }
public DateTime LastTraded { get; set; }
public override void OnDelete()
{
RestoreRelocatedEntities();
new FixColumnTimer(this).Start();
base.OnDelete();
}
private class FixColumnTimer : Timer
{
private readonly Map m_Map;
private readonly int m_StartX;
private readonly int m_StartY;
private readonly int m_EndX;
private readonly int m_EndY;
public FixColumnTimer(BaseMulti multi)
: base(TimeSpan.Zero)
{
m_Map = multi.Map;
MultiComponentList mcl = multi.Components;
m_StartX = multi.X + mcl.Min.X;
m_StartY = multi.Y + mcl.Min.Y;
m_EndX = multi.X + mcl.Max.X;
m_EndY = multi.Y + mcl.Max.Y;
}
protected override void OnTick()
{
if (m_Map == null)
return;
for (int x = m_StartX; x <= m_EndX; ++x)
for (int y = m_StartY; y <= m_EndY; ++y)
m_Map.FixColumn(x, y);
}
}
public DateTime LastVisit(Mobile m)
{
if (Visits.ContainsKey(m))
{
return Visits[m];
}
return DateTime.MinValue;
}
public void AddVisit(Mobile m)
{
if (m is PlayerMobile && !IsOwner(m))
{
Visits[m] = DateTime.Now;
}
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if (m_Owner != null)
{
List<BaseHouse> list = null;
m_Table.TryGetValue(m_Owner, out list);
if (list == null)
m_Table[m_Owner] = list = new List<BaseHouse>();
list.Remove(this);
}
CheckUnregisteredAddons();
foreach (var m in GetMobiles().Where(m => m is Mannequin || m is Steward))
{
Mannequin.ForceRedeed(m);
}
if (m_Region != null)
{
m_Region.Unregister();
m_Region = null;
}
if (Sign != null)
Sign.Delete();
if (m_Trash != null)
m_Trash.Delete();
if (Doors != null)
{
for (int i = 0; i < Doors.Count; ++i)
{
Item item = (Item)Doors[i];
if (item != null)
item.Delete();
}
Doors.Clear();
}
if (LockDowns != null)
{
foreach(KeyValuePair<Item, Mobile> kvp in LockDowns)
{
Item item = kvp.Key;
if (item != null)
{
item.IsLockedDown = false;
item.IsSecure = false;
item.Movable = true;
item.SetLastMoved();
item.SendLocalizedMessage(501657, ""); // [no longer locked down]
}
}
LockDowns.Clear();
}
if (VendorRentalContracts != null)
{
for (int i = 0; i < VendorRentalContracts.Count; ++i)
{
Item item = (Item)VendorRentalContracts[i];
if (item != null)
{
item.IsLockedDown = false;
item.IsSecure = false;
item.Movable = true;
item.SetLastMoved();
item.SendLocalizedMessage(501657, ""); // [no longer locked down]
}
}
VendorRentalContracts.Clear();
}
if (Secures != null)
{
for (int i = 0; i < Secures.Count; ++i)
{
SecureInfo info = Secures[i];
if (info.Item is StrongBox)
{
((StrongBox)info.Item).Destroy();
}
else
{
info.Item.IsLockedDown = false;
info.Item.IsSecure = false;
info.Item.Movable = true;
info.Item.SetLastMoved();
info.Item.SendLocalizedMessage(501718, ""); // no longer secure!
}
}
Secures.Clear();
}
if (Addons != null)
{
foreach(var kvp in Addons)
{
Item item = kvp.Key;
if (item != null)
{
if (!item.Deleted && item is IAddon)
{
Item deed = ((IAddon)item).Deed;
bool retainDeedHue = false; //if the items aren't hued but the deed itself is
int hue = 0;
if (item is BaseAddon && ((BaseAddon)item).RetainDeedHue) //There are things that are IAddon which aren't BaseAddon
{
BaseAddon ba = (BaseAddon)item;
retainDeedHue = true;
for (int j = 0; hue == 0 && j < ba.Components.Count; ++j)
{
AddonComponent c = ba.Components[j];
if (c.Hue != 0)
hue = c.Hue;
}
}
if (deed != null)
{
if (retainDeedHue)
deed.Hue = hue;
deed.MoveToWorld(item.Location, item.Map);
deed.SendLocalizedMessage(501657, ""); // [no longer locked down]
}
}
item.Delete();
}
}
Addons.Clear();
}
if (Carpets != null)
{
for (int i = 0; i < Carpets.Count; ++i)
{
Item carpet = (Item)Carpets[i];
if (carpet != null)
{
carpet.Movable = true;
carpet.SetLastMoved();
carpet.InvalidateProperties();
}
}
}
VendorInventories.IterateReverse(o => o.Delete());
if (MovingCrate != null)
MovingCrate.Delete();
KillVendors();
AllHouses.Remove(this);
}
public static int GetAccountHouseCount(Mobile m)
{
Account a = m.Account as Account;
if (a == null)
return 0;
int count = 0;
for (int i = 0; i < a.Length; ++i)
{
if (a[i] != null)
{
count += GetHouseCount(a[i]);
}
}
return count;
}
public static int GetHouseCount(Mobile m)
{
if (m == null)
return 0;
List<BaseHouse> list = null;
m_Table.TryGetValue(m, out list);
if (list == null)
return 0;
int count = 0;
for (int i = 0; i < list.Count; ++i)
{
BaseHouse h = list[i];
if (!h.Deleted)
count++;
}
return count;
}
public static bool HasHouse(Mobile m)
{
return GetHouseCount(m) > 0;
}
public static bool AtAccountHouseLimit(Mobile m)
{
return GetAccountHouseCount(m) >= GetAccountHouseLimit(m);
}
public static int GetAccountHouseLimit(Mobile m)
{
var max = AccountHouseLimit;
return max;
}
public static bool CheckAccountHouseLimit(Mobile m, bool message = true)
{
if (AtAccountHouseLimit(m))
{
if (message)
{
if (AccountHouseLimit == 1)
{
m.SendLocalizedMessage(501271); // You already own a house, you may not place another!
}
else
{
m.SendMessage("You already own {0} houses, you may not place any more!", BaseHouse.AccountHouseLimit.ToString());
}
}
return false;
}
return true;
}
public bool IsOwner(Mobile m)
{
if (m == null)
return false;
if (m == m_Owner || m.AccessLevel >= AccessLevel.GameMaster)
return true;
return IsAosRules && AccountHandler.CheckAccount(m, m_Owner);
}
public bool IsCoOwner(Mobile m)
{
if (m == null || CoOwners == null)
return false;
if (IsOwner(m) || CoOwners.Contains(m))
return true;
foreach (Mobile mob in CoOwners)
{
if (AccountHandler.CheckAccount(mob, m))
return true;
}
return !IsAosRules && AccountHandler.CheckAccount(m, m_Owner);
}
public bool IsGuildMember(Mobile m)
{
if (m == null || Owner == null || Owner.Guild == null)
return false;
return (m.Guild == Owner.Guild);
}
public void RemoveKeys(Mobile m)
{
if (Doors != null)
{
uint keyValue = 0;
for (int i = 0; keyValue == 0 && i < Doors.Count; ++i)
{
BaseDoor door = Doors[i] as BaseDoor;
if (door != null)
keyValue = door.KeyValue;
}
Key.RemoveKeys(m, keyValue);
}
}
public void ChangeLocks(Mobile m)
{
uint keyValue = CreateKeys(m);
if (Doors != null)
{
for (int i = 0; i < Doors.Count; ++i)
{
BaseDoor door = Doors[i] as BaseDoor;
if (door != null)
door.KeyValue = keyValue;
}
}
}
public void RemoveLocks()
{
if (Doors != null)
{
for (int i = 0; i < Doors.Count; ++i)
{
BaseDoor door = Doors[i] as BaseDoor;
if (door != null)
{
door.KeyValue = 0;
door.Locked = false;
}
}
}
}
public virtual HousePlacementEntry ConvertEntry { get { return null; } }
public virtual int ConvertOffsetX { get { return 0; } }
public virtual int ConvertOffsetY { get { return 0; } }
public virtual int ConvertOffsetZ { get { return 0; } }
public virtual int DefaultPrice { get { return 0; } }
[CommandProperty(AccessLevel.GameMaster)]
public int Price { get; set; }
public virtual HouseDeed GetDeed()
{
return null;
}
public bool IsFriend(Mobile m)
{
if (m == null || Friends == null)
return false;
return IsCoOwner(m) || Friends.Contains(m);
}
public bool IsBanned(Mobile m)
{
if (m == null || m == Owner || m.IsStaff() || Bans == null)
return false;
Account theirAccount = m.Account as Account;
for (int i = 0; i < Bans.Count; ++i)
{
Mobile c = (Mobile)Bans[i];
if (c == m)
return true;
Account bannedAccount = c.Account as Account;
if (bannedAccount != null && bannedAccount == theirAccount)
return true;
}
return false;
}
public bool HasAccess(Mobile m)
{
if (m == null)
return false;
if (m.IsStaff() || IsFriend(m) || (Access != null && Access.Contains(m)))
return true;
if (m is BaseCreature)
{
BaseCreature bc = (BaseCreature)m;
if (bc.NoHouseRestrictions)
return true;
if (bc.Controlled || bc.Summoned)
{
m = bc.ControlMaster;
if (m == null)
m = bc.SummonMaster;
if (m == null)
return false;
if (m.IsStaff() || IsFriend(m) || (Access != null && Access.Contains(m)))
return true;
}
}
return false;
}
public new bool IsLockedDown(Item check)
{
if (check == null)
return false;
if (LockDowns == null)
return false;
return (LockDowns.ContainsKey(check) || VendorRentalContracts.Contains(check));
}
public new bool IsSecure(Item item)
{
if (item == null)
return false;
if (Secures == null)
return false;
bool contains = false;
for (int i = 0; !contains && i < Secures.Count; ++i)
contains = Secures[i].Item == item;
return contains;
}
public virtual Guildstone FindGuildstone()
{
Map map = Map;
if (map == null)
return null;
MultiComponentList mcl = Components;
IPooledEnumerable eable = map.GetItemsInBounds(new Rectangle2D(X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height));
foreach (Item item in eable)
{
if (item is Guildstone && Contains(item))
{
eable.Free();
return (Guildstone)item;
}
}
eable.Free();
return null;
}
}
public enum DecayType
{
Ageless,
AutoRefresh,
ManualRefresh,
Condemned
}
public enum DecayLevel
{
Ageless,
LikeNew,
Slightly,
Somewhat,
Fairly,
Greatly,
IDOC,
Collapsed,
DemolitionPending
}
public enum SecureAccessResult
{
Insecure,
Accessible,
Inaccessible
}
public enum SecureLevel
{
Owner,
CoOwners,
Friends,
Anyone,
Guild
}
public class SecureInfo : ISecurable
{
public Item Item { get; }
public SecureLevel Level { get; set; }
public Mobile Owner { get; set; }
public bool IsLockdown { get; set; }
#region *ONLY USED IN BASEHOUSE VERSION 21*
public static bool VersionInsertion { get; set; }
#endregion
public SecureInfo(Item item, SecureLevel level, Mobile owner, bool isLockdown = false)
{
Item = item;
Level = level;
Owner = owner;
IsLockdown = isLockdown;
}
public SecureInfo(GenericReader reader)
{
int version = VersionInsertion ? 0 : reader.ReadInt();
switch (version)
{
case 1:
{
IsLockdown = reader.ReadBool();
Owner = reader.ReadMobile();
goto case 0;
}
case 0:
{
Item = reader.ReadItem();
Level = (SecureLevel)reader.ReadByte();
break;
}
}
}
public void Serialize(GenericWriter writer)
{
writer.Write(1); // version
writer.Write(IsLockdown);
writer.Write(Owner);
writer.Write(Item);
writer.Write((byte)Level);
}
}
public class RelocatedEntity
{
public IEntity Entity { get; }
public Point3D RelativeLocation { get; }
public Mobile Owner { get; }
public RelocatedEntity(IEntity entity, Point3D relativeLocation, Mobile owner)
{
Entity = entity;
RelativeLocation = relativeLocation;
Owner = owner;
}
}
#region Targets
public class LockdownTarget : Target
{
private readonly bool m_Release;
private readonly BaseHouse m_House;
public LockdownTarget(bool release, BaseHouse house)
: base(12, false, TargetFlags.None)
{
CheckLOS = false;
m_Release = release;
m_House = house;
}
protected override void OnTargetNotAccessible(Mobile from, object targeted)
{
OnTarget(from, targeted);
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from))
return;
if (targeted is Item)
{
Item item = targeted as Item;
if (m_Release)
{
#region Mondain's legacy
if (targeted is AddonContainerComponent)
{
AddonContainerComponent component = (AddonContainerComponent)targeted;
if (component.Addon != null)
m_House.Release(from, component.Addon);
}
#endregion
else if (item.Parent is Container)
{
from.SendLocalizedMessage(1080387); // You may not release this while it is in a container.
}
else
{
m_House.Release(from, (Item)targeted);
}
}
else
{
if (targeted is VendorRentalContract)
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1062392); // You must double click the contract in your pack to lock it down.
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501732); // I cannot lock this down!
}
else if ((Item)targeted is AddonComponent)
{
from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 501727); // You cannot lock that down!
from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 501732); // I cannot lock this down!
}
else
{
#region Mondain's legacy
if (targeted is AddonContainerComponent)
{
AddonContainerComponent component = (AddonContainerComponent)targeted;
if (component.Addon != null)
m_House.LockDown(from, component.Addon);
}
else
#endregion
{
m_House.LockDown(from, (Item)targeted);
}
}
}
}
else if (targeted is StaticTarget)
{
return;
}
else
{
from.SendLocalizedMessage(1005377); //You cannot lock that down
}
}
}
public class SecureTarget : Target
{
private readonly bool m_Release;
private readonly BaseHouse m_House;
public SecureTarget(bool release, BaseHouse house)
: base(12, false, TargetFlags.None)
{
CheckLOS = false;
m_Release = release;
m_House = house;
}
protected override void OnTargetNotAccessible(Mobile from, object targeted)
{
OnTarget(from, targeted);
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!from.Alive || m_House.Deleted || !m_House.IsCoOwner(from))
return;
if (targeted is Item)
{
if (m_Release)
{
#region Mondain's legacy
if (targeted is AddonContainerComponent)
{
AddonContainerComponent component = (AddonContainerComponent)targeted;
if (component.Addon != null)
m_House.ReleaseSecure(from, component.Addon);
}
else
#endregion
m_House.ReleaseSecure(from, (Item)targeted);
}
else
{
if (targeted is VendorRentalContract)
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1062392); // You must double click the contract in your pack to lock it down.
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501732); // I cannot lock this down!
}
else
{
#region Mondain's legacy
if (targeted is AddonContainerComponent)
{
AddonContainerComponent component = (AddonContainerComponent)targeted;
if (component.Addon != null)
m_House.AddSecure(from, component.Addon);
}
else
#endregion
m_House.AddSecure(from, (Item)targeted);
}
}
}
else
{
from.SendLocalizedMessage(1010424);//You cannot secure this
}
}
}
public class HouseKickTarget : Target
{
private readonly BaseHouse m_House;
public HouseKickTarget(BaseHouse house)
: base(-1, false, TargetFlags.None)
{
CheckLOS = false;
m_House = house;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from))
return;
if (targeted is Mobile)
{
m_House.Kick(from, (Mobile)targeted);
}
else
{
from.SendLocalizedMessage(501347);//You cannot eject that from the house!
}
}
}
public class HouseBanTarget : Target
{
private readonly BaseHouse m_House;
private readonly bool m_Banning;
public HouseBanTarget(bool ban, BaseHouse house)
: base(-1, false, TargetFlags.None)
{
CheckLOS = false;
m_House = house;
m_Banning = ban;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from))
return;
if (targeted is Mobile)
{
if (m_Banning)
m_House.Ban(from, (Mobile)targeted);
else
m_House.RemoveBan(from, (Mobile)targeted);
}
else
{
from.SendLocalizedMessage(501347);//You cannot eject that from the house!
}
}
}
public class HouseAccessTarget : Target
{
private readonly BaseHouse m_House;
public HouseAccessTarget(BaseHouse house)
: base(-1, false, TargetFlags.None)
{
CheckLOS = false;
m_House = house;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!from.Alive || m_House.Deleted || !m_House.IsFriend(from))
return;
if (targeted is Mobile)
m_House.GrantAccess(from, (Mobile)targeted);
else
from.SendLocalizedMessage(1060712); // That is not a player.
}
}
public class CoOwnerTarget : Target
{
private readonly BaseHouse m_House;
private readonly bool m_Add;
public CoOwnerTarget(bool add, BaseHouse house)
: base(12, false, TargetFlags.None)
{
CheckLOS = false;
m_House = house;
m_Add = add;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!from.Alive || m_House.Deleted || !m_House.IsOwner(from))
return;
if (targeted is Mobile)
{
if (m_Add)
m_House.AddCoOwner(from, (Mobile)targeted);
else
m_House.RemoveCoOwner(from, (Mobile)targeted);
}
else
{
from.SendLocalizedMessage(501362);//That can't be a coowner
}
}
}
public class HouseFriendTarget : Target
{
private readonly BaseHouse m_House;
private readonly bool m_Add;
public HouseFriendTarget(bool add, BaseHouse house)
: base(12, false, TargetFlags.None)
{
CheckLOS = false;
m_House = house;
m_Add = add;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!from.Alive || m_House.Deleted || !m_House.IsCoOwner(from))
return;
if (targeted is Mobile)
{
if (m_Add)
m_House.AddFriend(from, (Mobile)targeted);
else
m_House.RemoveFriend(from, (Mobile)targeted);
}
else
{
from.SendLocalizedMessage(501371); // That can't be a friend
}
}
}
public class HouseOwnerTarget : Target
{
private readonly BaseHouse m_House;
public HouseOwnerTarget(BaseHouse house)
: base(12, false, TargetFlags.None)
{
CheckLOS = false;
m_House = house;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is Mobile)
m_House.BeginConfirmTransfer(from, (Mobile)targeted);
else
from.SendLocalizedMessage(501384); // Only a player can own a house!
}
}
#endregion
public class SetSecureLevelEntry : ContextMenuEntry
{
private readonly Item m_Item;
private readonly ISecurable m_Securable;
public SetSecureLevelEntry(Item item, ISecurable securable)
: base(6203, 6)
{
m_Item = item;
m_Securable = securable;
}
public static ISecurable GetSecurable(Mobile from, Item item)
{
BaseHouse house = BaseHouse.FindHouseAt(item);
if (house == null || !house.IsAosRules)
return null;
bool owner = house.IsOwner(from) || (house.IsLockedDown(item) && house.CheckLockdownOwnership(from, item));
ISecurable sec = null;
if (item is ISecurable)
{
if (!owner)
return null;
bool isOwned = house.Doors.Contains(item);
if (!isOwned)
isOwned = (house is HouseFoundation && ((HouseFoundation)house).IsFixture(item));
if (!isOwned)
isOwned = house.IsLockedDown(item);
if (!isOwned)
isOwned = item is BaseAddon;
if (isOwned)
sec = (ISecurable)item;
}
else
{
sec = house.GetSecureInfoFor(from, item);
}
return sec;
}
public static void AddTo(Mobile from, Item item, List<ContextMenuEntry> list)
{
ISecurable sec = GetSecurable(from, item);
if (sec != null)
list.Add(new SetSecureLevelEntry(item, sec));
}
public override void OnClick()
{
if (m_Item is AuctionSafe)
{
AuctionSafe safe = (AuctionSafe)m_Item;
if (safe.Auction != null && !safe.Auction.CanModify)
{
Owner.From.SendLocalizedMessage(1156431); // You cannot modify this while an auction is in progress.
return;
}
}
ISecurable sec = GetSecurable(Owner.From, m_Item);
BaseHouse house = BaseHouse.FindHouseAt(m_Item);
if (house != null && sec != null)
{
Owner.From.CloseGump(typeof (SetSecureLevelGump));
Owner.From.SendGump(new SetSecureLevelGump(Owner.From, sec, house));
}
}
}
public class ReLocateEntry : ContextMenuEntry
{
public Mobile Mobile { get; set; }
public Item Item { get; set; }
public BaseHouse House { get; set; }
public ReLocateEntry(Mobile m, Item item, BaseHouse house)
: base(1159158, 8) // Relocate Container
{
Item = item;
Mobile = m;
House = house;
Enabled = Mobile.Alive;
}
public override void OnClick()
{
if (Mobile.Alive && BaseHouse.FindHouseAt(Mobile) == House && House.IsOwner(Mobile))
{
Mobile.Target = new InternalTarget(Item, House);
Mobile.SendLocalizedMessage(1159160); // Target the location that you wish to relocate this container. Once selected the container will no longer be secured.
}
else
{
Mobile.SendLocalizedMessage(1153882); // You do not own that.
}
}
public static AddonFitResult CouldFit(Point3D p, Map map, Mobile from, ref BaseHouse house)
{
if (!map.CanFit(p.X, p.Y, p.Z, 20, true, true, true))
return AddonFitResult.Blocked;
else if (!BaseAddon.CheckHouse(from, p, map, 20, ref house))
return AddonFitResult.NotInHouse;
else
return CheckDoors(p, 20, house);
}
public static AddonFitResult CheckDoors(Point3D p, int height, BaseHouse house)
{
List<Item> doors = house.Doors;
for (int i = 0; i < doors.Count; i++)
{
BaseDoor door = doors[i] as BaseDoor;
Point3D doorLoc = door.GetWorldLocation();
int doorHeight = door.ItemData.CalcHeight;
if (Utility.InRange(doorLoc, p, 1) && (p.Z == doorLoc.Z || ((p.Z + height) > doorLoc.Z && (doorLoc.Z + doorHeight) > p.Z)))
return AddonFitResult.DoorTooClose;
}
return AddonFitResult.Valid;
}
private class InternalTarget : Target
{
public Item Item { get; set; }
public BaseHouse House { get; set; }
public InternalTarget(Item item, BaseHouse house)
: base(8, true, TargetFlags.None)
{
Item = item;
House = house;
}
protected override void OnTarget(Mobile from, object targeted)
{
IPoint3D p = targeted as IPoint3D;
Point3D point = new Point3D(p.X, p.Y, p.Z);
BaseHouse house = BaseHouse.FindHouseAt(point, from.Map, 0);
AddonFitResult result = CouldFit(point, from.Map, from, ref house);
if (house != null && house == House && house.Owner == from && result == AddonFitResult.Valid)
{
if (House.Release(from, Item))
{
Item.MoveToWorld(point, from.Map);
Item.Movable = true;
from.SendLocalizedMessage(1159159); // This container has been released and is no longer secure.
}
}
else
{
from.SendLocalizedMessage(1149667); // Invalid target.
}
}
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
{
from.SendLocalizedMessage(500979); // You cannot see that location.
}
}
}
public class ReleaseEntry : ContextMenuEntry
{
public Mobile Mobile { get; set; }
public Item Item { get; set; }
public BaseHouse House { get; set; }
public ReleaseEntry(Mobile m, Item item, BaseHouse house)
: base(1153880, 8) // Retrieve
{
Item = item;
Mobile = m;
House = house;
Enabled = Mobile.Alive;
}
public override void OnClick()
{
if (Mobile.Alive && BaseHouse.FindHouseAt(Mobile) == House && House.IsOwner(Mobile))
{
if (Mobile.Backpack == null || !Mobile.Backpack.CheckHold(Mobile, Item, false))
{
Mobile.SendLocalizedMessage(1153881); // Your pack cannot hold this
}
else if (House.Release(Mobile, Item))
{
Mobile.Backpack.DropItem(Item);
if (Item.IsLockedDown)
{
Item.IsLockedDown = false;
Item.Movable = true;
}
}
}
else
{
Mobile.SendLocalizedMessage(1153882); // You do not own that.
}
}
}
public class TempNoHousingRegion : BaseRegion
{
private readonly Mobile m_RegionOwner;
public TempNoHousingRegion(BaseHouse house, Mobile regionowner)
: base(null, house.Map, DefaultPriority, house.Region.Area)
{
Register();
m_RegionOwner = regionowner;
Timer.DelayCall(house.RestrictedPlacingTime, Unregister);
}
public override bool AllowHousing(Mobile from, Point3D p)
{
return from == m_RegionOwner || AccountHandler.CheckAccount(from, m_RegionOwner);
}
}
}