diff --git a/Projects/UOContent/Multis/Deeds.cs b/Projects/UOContent/Multis/Deeds.cs index b537cec5e..1120a0b55 100644 --- a/Projects/UOContent/Multis/Deeds.cs +++ b/Projects/UOContent/Multis/Deeds.cs @@ -71,6 +71,8 @@ namespace Server.Multis.Deeds [CommandProperty(AccessLevel.GameMaster)] public Point3D Offset { get; set; } + public virtual Direction HouseDirection => Direction.South; + public abstract Rectangle2D[] Area { get; } public override void Serialize(IGenericWriter writer) @@ -153,7 +155,7 @@ namespace Server.Multis.Deeds else { var center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); - var res = HousePlacement.Check(from, MultiID, center, out var toMove); + var res = HousePlacement.Check(from, MultiID, center, out var toMove, HouseDirection); switch (res) { diff --git a/Projects/UOContent/Multis/Houses/BaseHouse.cs b/Projects/UOContent/Multis/Houses/BaseHouse.cs index d49062d01..f1d3954d9 100644 --- a/Projects/UOContent/Multis/Houses/BaseHouse.cs +++ b/Projects/UOContent/Multis/Houses/BaseHouse.cs @@ -100,6 +100,8 @@ namespace Server.Multis [CommandProperty(AccessLevel.GameMaster)] public bool RestrictDecay { get; set; } + public virtual Direction HouseDirection => Direction.South; + public virtual TimeSpan DecayPeriod => TimeSpan.FromDays(5.0); public virtual DecayType DecayType diff --git a/Projects/UOContent/Multis/Houses/HousePlacement.cs b/Projects/UOContent/Multis/Houses/HousePlacement.cs index d97f734ab..972b43f2e 100644 --- a/Projects/UOContent/Multis/Houses/HousePlacement.cs +++ b/Projects/UOContent/Multis/Houses/HousePlacement.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Server.Collections; using Server.Regions; @@ -37,7 +38,9 @@ namespace Server.Multis 0x0150, 0x015C // Furrows }; - public static HousePlacementResult Check(Mobile from, int multiID, Point3D center, out List toMove) + public static HousePlacementResult Check( + Mobile from, int multiID, Point3D center, out List toMove, Direction houseFacing = Direction.South + ) { // If this spot is considered valid, every item and mobile in this list will be moved under the house sign toMove = new List(); @@ -77,7 +80,7 @@ namespace Server.Multis HouseFoundation.AddStairsTo(ref mcl); // this is a AOS house, add the stairs } - // Location of the nortwest-most corner of the house + // Location of the northwest-most corner of the house var start = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Min.Y, center.Z); // These are storage lists. They hold items and mobiles found in the map for further processing @@ -85,7 +88,7 @@ namespace Server.Multis var mobiles = new List(); // These are also storage lists. They hold location values indicating the yard and border locations. - List yard = new(), borders = new(); + List borders = []; /* RULES: * @@ -121,7 +124,7 @@ namespace Server.Multis return HousePlacementResult.BadRegionTemp; } - if (reg.IsPartOf() || reg.IsPartOf()) + if (reg.IsPartOf()) { return HousePlacementResult.BadRegionHidden; } @@ -218,16 +221,18 @@ namespace Server.Multis { var id = item.ItemData; - if (addTileTop > item.Z && item.Z + id.CalcHeight > addTileZ) + if (addTileTop <= item.Z || item.Z + id.CalcHeight <= addTileZ) { - if (item.Movable) - { - toMove.Add(item); - } - else if (id.Impassable || id.Surface && !id.Background) - { - return HousePlacementResult.BadItem; // Broke rule #2 - } + continue; + } + + if (item.Movable) + { + toMove.Add(item); + } + else if (id.Impassable || id.Surface && !id.Background) + { + return HousePlacementResult.BadItem; // Broke rule #2 } } @@ -257,17 +262,9 @@ namespace Server.Multis if (hasFoundation) { - for (var xOffset = -1; xOffset <= 1; ++xOffset) + if (!CheckYard(map, tileX, tileY, YardSize, houseFacing)) { - for (var yOffset = -YardSize; yOffset <= YardSize; ++yOffset) - { - var yardPoint = new Point2D(tileX + xOffset, tileY + yOffset); - - if (!yard.Contains(yardPoint)) - { - yard.Add(yardPoint); - } - } + return HousePlacementResult.BadStatic; // Broke rule #3 } for (var xOffset = -1; xOffset <= 1; ++xOffset) @@ -364,37 +361,73 @@ namespace Server.Multis } } - for (var i = 0; i < yard.Count; i++) - { - var yardPoint = yard[i]; + return HousePlacementResult.Valid; + } - foreach (var house in map.GetMultisInSector(yardPoint)) + private static bool CheckYard(Map map, int tileX, int tileY, int yardSize, Direction houseFacing) + { + var isSouthFacing = (houseFacing & Direction.South) != 0; + var isEastFacing = (houseFacing & Direction.East) != 0; + + for (var xOffset = -yardSize; xOffset <= yardSize; ++xOffset) + { + var absXOffset = Math.Abs(xOffset); + for (var yOffset = -yardSize; yOffset <= yardSize; ++yOffset) { - if (house.Contains(yard[i])) + var absYOffset = Math.Abs(yOffset); + var yardPoint = new Point2D(tileX + xOffset, tileY + yOffset); + + bool inSouthYard = yOffset > 0 && yOffset <= yardSize && absXOffset <= 1; + bool inEastYard = xOffset > 0 && xOffset <= yardSize && absYOffset <= 1; + bool inNorthYard = yOffset < 0 && yOffset >= -yardSize && absXOffset <= 1; + bool inWestYard = xOffset < 0 && xOffset >= -yardSize && absYOffset <= 1; + + // Check each house at this point + foreach (var house in map.GetMultisInSector(yardPoint)) { - return HousePlacementResult.BadStatic; // Broke rule #3 + if (!house.Contains(yardPoint)) + { + continue; + } + + var existingHouseFacing = house.HouseDirection; + var existingHouseIsSouthFacing = (existingHouseFacing & Direction.South) != 0; + var existingHouseIsEastFacing = (existingHouseFacing & Direction.East) != 0; + + // Sub-Rule 1: No houses within immediate proximity (1 tile radius) + if (absXOffset <= 1 && absYOffset <= 1) + { + return false; + } + + // Sub-Rule 2: If we're south facing, protect our south yard + if (isSouthFacing && inSouthYard) + { + return false; + } + + // Sub-Rule 3: If we're east facing, protect our east yard + if (isEastFacing && inEastYard) + { + return false; + } + + // Sub-Rule 4: If there's a south-facing house to our north, respect its yard + if (inNorthYard && existingHouseIsSouthFacing) + { + return false; + } + + // Sub-Rule 5: If there's an east-facing house to our west, respect its yard + if (inWestYard && existingHouseIsEastFacing) + { + return false; + } } } } - // TODO: Should we check for MultiTilesAt each yard point? - // for (var i = 0; i < yard.Count; i++) - // { - // var yardPoint = yard[i]; - // - // foreach (var tiles in map.GetMultiTilesAt(yardPoint)) - // { - // for (int j = 0; j < tiles.Length; ++j) - // { - // if ((TileData.ItemTable[tiles[j].ID & TileData.MaxItemValue].Flags & (TileFlag.Impassable | TileFlag.Surface)) != 0) - // { - // return HousePlacementResult.BadStatic; // Broke rule #3 - // } - // } - // } - // } - - return HousePlacementResult.Valid; + return true; } } } diff --git a/Projects/UOContent/Multis/Houses/HousePlacementTool.cs b/Projects/UOContent/Multis/Houses/HousePlacementTool.cs index c0842066c..be254b01c 100644 --- a/Projects/UOContent/Multis/Houses/HousePlacementTool.cs +++ b/Projects/UOContent/Multis/Houses/HousePlacementTool.cs @@ -303,7 +303,7 @@ public class HousePlacementEntry public HousePlacementEntry( Type type, int description, int storage, int lockdowns, int newStorage, int newLockdowns, - int vendors, int cost, int xOffset, int yOffset, int zOffset, int multiID + int vendors, int cost, int xOffset, int yOffset, int zOffset, int multiID, Direction direction = Direction.South ) { Type = type; @@ -318,6 +318,7 @@ public class HousePlacementEntry Offset = new Point3D(xOffset, yOffset, zOffset); MultiID = multiID; + HouseDirection = direction; } public Type Type { get; } @@ -334,6 +335,8 @@ public class HousePlacementEntry public Point3D Offset { get; } + public Direction HouseDirection { get; } + public static HousePlacementEntry[] ClassicHouses { get; } = { new(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0064), @@ -1981,7 +1984,7 @@ public class HousePlacementEntry prevHouse.Delete(); - var res = HousePlacement.Check(from, MultiID, center, out var toMove); + var res = HousePlacement.Check(from, MultiID, center, out var toMove, HouseDirection); switch (res) { @@ -2008,21 +2011,18 @@ public class HousePlacementEntry $"{Cost} gold would have been withdrawn from your bank if you were not a GM." ); } + else if (Banker.Withdraw(from, Cost)) + { + // ~1_AMOUNT~ gold has been withdrawn from your bank box. + from.SendLocalizedMessage(1060398, Cost.ToString()); + } else { - if (Banker.Withdraw(from, Cost)) - { - // ~1_AMOUNT~ gold has been withdrawn from your bank box. - from.SendLocalizedMessage(1060398, Cost.ToString()); - } - else - { - house.RemoveKeys(from); - house.Delete(); - // You do not have the funds available in your bank box to purchase this house. Try placing a smaller house, or adding gold or checks to your bank box. - from.SendLocalizedMessage(1060646); - return; - } + house.RemoveKeys(from); + house.Delete(); + // You do not have the funds available in your bank box to purchase this house. Try placing a smaller house, or adding gold or checks to your bank box. + from.SendLocalizedMessage(1060646); + return; } house.MoveToWorld(center, from.Map); @@ -2087,7 +2087,7 @@ public class HousePlacementEntry } var center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); - var res = HousePlacement.Check(from, MultiID, center, out var toMove); + var res = HousePlacement.Check(from, MultiID, center, out var toMove, HouseDirection); switch (res) {