Updates Packets & Randomizer (#43)

* Fixes a bug with the main loop. Removes unnecessary optimizations for RDRand.

* WIP - Rewriting packets.

* Cleanup and updates README

* Converts more packets

* Fixes header

* Converts Effects packets.

* Forgot the send command

* Adds the start of containers packets.

* Adds message packets with caching

* Extends the send methods

* Starts to add Acquire methods

* Converted the packets

* Cleanup

* Cleanup

* Adds more packets

* Adds more packets

* Fixes clearing arrays from pool. Adds Mobile Incoming

* Converts more packets.

* Moves more packets

* Moves more packets

* Test compression

* Merges

* Migrating to an idiomatic syntax that also supports compression, and proxying.

* Optimize the stack alloc. Changes attributes

* Converted container packets

* Visual Studio doesn't auto save files. I am still getting used to subpar IDEs.

* Adds static packet caching. Will profile later. Converts more packets

* Fixes packets and changes how compression is configured

* WIP - Adds basics for Gumps. Not finished though.

* Fix file

* Fixes formatting

* Changed SpanWriter to be more idiomatic.

* Fixes Span vs RawSpan and missing stackallocs

* Converts over some more gumps

* WIP - Deletes 32bit support.

* Drops RDRand32 support.

* Fixes gump compilation

* Converting gump components

* Removes old huffman compression function

* Revert signature for backwards compatibility

* WIP - Converting more gump components

* Creates ArraySet for the strings. Updates AppendTo to reference that.

* Converts the maining gump components

* Cleans up gump components

* Cleans up directives

* Cleans up ArraySet and moves it. Adds null-coalescing-assignment

* Cleanup, Target Packets, and C# 8 changes.

* Removed OPL Packet

* World packets

* Fixing packet uses

* Cleans up code. Fixes packet uses in various places.

* More cleanup for packets

* Code cleanup

* Converts more packet uses and cleans up more code

* More code cleanup

* Finishes fixing the packets in Item

* Updates secure trade packets

* Updates core and gets it to compile.

* Moved packets to scripts. Fixed account handler use of packets

* Code cleanup

* Updates chat packets

* Code cleanuo

* Adds party packets, but need to implement them.

* Party packets WIP

* Finishes party packets

* Rearrange movement namespaces and classes

* Finishes plant packets

* Code Formatting

* Fixes moving effects

* Code cleanup, eliminates equipinfo

* Adds more packets. Fixes bugs with various packets.

* Finishes mahjon packets

* Fixes mahjong packet

* Code cleanup

* Finishes mahjong packets

* Adds Map packets

* Add multifacet maps and charts

* Cleans up some packets with UTF8

* Optimizes packets

* Cleans up more packets. Moves the MessageHelper

* Removes assistant support. Removes extended protocol. Incorporates MapUO packets as normal packets.

* Updates protocol extensions packet receiver

* Fixes a few bugs. Fixes a few more packets.

* Code cleanup and fixing more packets

* Fixes packet effects

* Cleaned up more code

* Buff Icon cleanup

* Removed unused constructors

* Code Cleanup. Adds BoatHS Packets

* Moves house files. Updates house foundation packets.

* Deployment cleanup

* Fixes:

* Code cleanup

* More code cleanup

* More code cleanup

* Cleaned up BaseHouse

* Enforces styling

* Converts foreach to linq where possible.

* Dont need that

* Goals/Readme updates

* Removes 32bit support at the highest level. Turns on HRT by default.

* Code cleanup. Fixes extended features packet.

* Fixes various bugs

* Code cleanup

* Code cleanup

* Code cleanup. Fixes gump X/Y assignment.

* Code cleanup using |= operator

* More code cleanup

* Cleanup

* Fixes spacing issues. Thanks Visual Studio. You suck.

* Compiler error

* Fixes NPE from RunUO 2.7

* Renames ScriptCompiler to AssemblyHandler. Fixes packets. Updates README

* Fixes more packets. Stupid trailing nulls.

* Fixes various bugs.

* Fixes for gumps

* Fixes more gump stuff. Going to split it out later since it is getting insane

* Recoded the gump writing

* WIP

* *Added output path of scripts project to dev branch
*Activated debugging in code
This commit is contained in:
Kamron Batman 2019-11-11 03:40:16 -08:00 committed by 3HMonkey
parent 7aa8fd3df1
commit 179cb50557
588 changed files with 10843 additions and 16177 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,809 @@
using System.Collections.Generic;
using Server.Regions;
using Server.Targeting;
namespace Server.Multis.Deeds
{
public class HousePlacementTarget : MultiTarget
{
private HouseDeed m_Deed;
public HousePlacementTarget(HouseDeed deed) : base(deed.MultiID, deed.Offset) => m_Deed = deed;
protected override void OnTarget(Mobile from, object o)
{
if (o is IPoint3D ip)
{
if (ip is Item item)
ip = item.GetWorldTop();
Point3D p = new Point3D(ip);
Region reg = Region.Find(new Point3D(p), from.Map);
if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p))
m_Deed.OnPlacement(from, p);
else if (reg.IsPartOf<TempNoHousingRegion>())
from.SendLocalizedMessage(
501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
else if (reg.IsPartOf<TreasureRegion>() || reg.IsPartOf<HouseRegion>())
from.SendLocalizedMessage(
1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
else if (reg.IsPartOf<HouseRaffleRegion>())
from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here.
else
from.SendLocalizedMessage(501265); // Housing can not be created in this area.
}
}
}
public abstract class HouseDeed : Item
{
public HouseDeed(int id, Point3D offset) : base(0x14F0)
{
Weight = 1.0;
LootType = LootType.Newbied;
MultiID = id;
Offset = offset;
}
public HouseDeed(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public int MultiID{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public Point3D Offset{ get; set; }
public abstract Rectangle2D[] Area{ get; }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
writer.Write(Offset);
writer.Write(MultiID);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 1:
{
Offset = reader.ReadPoint3D();
goto case 0;
}
case 0:
{
MultiID = reader.ReadInt();
break;
}
}
if (Weight == 0.0)
Weight = 1.0;
}
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from.Backpack))
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
else if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from))
from.SendLocalizedMessage(501271); // You already own a house, you may not place another!
else
{
from.SendLocalizedMessage(1010433);
/* House placement cancellation could result in a
* 60 second delay in the return of your deed.
*/
from.Target = new HousePlacementTarget(this);
}
}
public abstract BaseHouse GetHouse(Mobile owner);
public void OnPlacement(Mobile from, Point3D p)
{
if (Deleted)
return;
if (!IsChildOf(from.Backpack))
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
else if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from))
from.SendLocalizedMessage(501271); // You already own a house, you may not place another!
else
{
Point3D center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z);
HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List<IEntity> toMove);
switch (res)
{
case HousePlacementResult.Valid:
{
BaseHouse house = GetHouse(from);
house.MoveToWorld(center, from.Map);
Delete();
for (int i = 0; i < toMove.Count; ++i)
{
object o = toMove[i];
if (o is Mobile mobile)
mobile.Location = house.BanLocation;
else if (o is Item item)
item.Location = house.BanLocation;
}
break;
}
case HousePlacementResult.BadItem:
case HousePlacementResult.BadLand:
case HousePlacementResult.BadStatic:
case HousePlacementResult.BadRegionHidden:
{
from.SendLocalizedMessage(
1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
break;
}
case HousePlacementResult.NoSurface:
{
from.SendMessage(
"The house could not be created here. Part of the foundation would not be on any surface.");
break;
}
case HousePlacementResult.BadRegion:
{
from.SendLocalizedMessage(501265); // Housing cannot be created in this area.
break;
}
case HousePlacementResult.BadRegionTemp:
{
from.SendLocalizedMessage(
501270); //Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
break;
}
case HousePlacementResult.BadRegionRaffle:
{
from.SendLocalizedMessage(
1150493); // You must have a deed for this plot of land in order to build here.
break;
}
}
}
}
}
public class StonePlasterHouseDeed : HouseDeed
{
[Constructible]
public StonePlasterHouseDeed() : base(0x64, new Point3D(0, 4, 0))
{
}
public StonePlasterHouseDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041211;
public override Rectangle2D[] Area => SmallOldHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x64);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class FieldStoneHouseDeed : HouseDeed
{
[Constructible]
public FieldStoneHouseDeed() : base(0x66, new Point3D(0, 4, 0))
{
}
public FieldStoneHouseDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041212;
public override Rectangle2D[] Area => SmallOldHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x66);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SmallBrickHouseDeed : HouseDeed
{
[Constructible]
public SmallBrickHouseDeed() : base(0x68, new Point3D(0, 4, 0))
{
}
public SmallBrickHouseDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041213;
public override Rectangle2D[] Area => SmallOldHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x68);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class WoodHouseDeed : HouseDeed
{
[Constructible]
public WoodHouseDeed() : base(0x6A, new Point3D(0, 4, 0))
{
}
public WoodHouseDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041214;
public override Rectangle2D[] Area => SmallOldHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6A);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class WoodPlasterHouseDeed : HouseDeed
{
[Constructible]
public WoodPlasterHouseDeed() : base(0x6C, new Point3D(0, 4, 0))
{
}
public WoodPlasterHouseDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041215;
public override Rectangle2D[] Area => SmallOldHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6C);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class ThatchedRoofCottageDeed : HouseDeed
{
[Constructible]
public ThatchedRoofCottageDeed() : base(0x6E, new Point3D(0, 4, 0))
{
}
public ThatchedRoofCottageDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041216;
public override Rectangle2D[] Area => SmallOldHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new SmallOldHouse(owner, 0x6E);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class BrickHouseDeed : HouseDeed
{
[Constructible]
public BrickHouseDeed() : base(0x74, new Point3D(-1, 7, 0))
{
}
public BrickHouseDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041219;
public override Rectangle2D[] Area => GuildHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new GuildHouse(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class TwoStoryWoodPlasterHouseDeed : HouseDeed
{
[Constructible]
public TwoStoryWoodPlasterHouseDeed() : base(0x76, new Point3D(-3, 7, 0))
{
}
public TwoStoryWoodPlasterHouseDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041220;
public override Rectangle2D[] Area => TwoStoryHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new TwoStoryHouse(owner, 0x76);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class TwoStoryStonePlasterHouseDeed : HouseDeed
{
[Constructible]
public TwoStoryStonePlasterHouseDeed() : base(0x78, new Point3D(-3, 7, 0))
{
}
public TwoStoryStonePlasterHouseDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041221;
public override Rectangle2D[] Area => TwoStoryHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new TwoStoryHouse(owner, 0x78);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class TowerDeed : HouseDeed
{
[Constructible]
public TowerDeed() : base(0x7A, new Point3D(0, 7, 0))
{
}
public TowerDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041222;
public override Rectangle2D[] Area => Tower.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new Tower(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class KeepDeed : HouseDeed
{
[Constructible]
public KeepDeed() : base(0x7C, new Point3D(0, 11, 0))
{
}
public KeepDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041223;
public override Rectangle2D[] Area => Keep.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new Keep(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class CastleDeed : HouseDeed
{
[Constructible]
public CastleDeed() : base(0x7E, new Point3D(0, 16, 0))
{
}
public CastleDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041224;
public override Rectangle2D[] Area => Castle.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new Castle(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class LargePatioDeed : HouseDeed
{
[Constructible]
public LargePatioDeed() : base(0x8C, new Point3D(-4, 7, 0))
{
}
public LargePatioDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041231;
public override Rectangle2D[] Area => LargePatioHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new LargePatioHouse(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class LargeMarbleDeed : HouseDeed
{
[Constructible]
public LargeMarbleDeed() : base(0x96, new Point3D(-4, 7, 0))
{
}
public LargeMarbleDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041236;
public override Rectangle2D[] Area => LargeMarbleHouse.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new LargeMarbleHouse(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SmallTowerDeed : HouseDeed
{
[Constructible]
public SmallTowerDeed() : base(0x98, new Point3D(3, 4, 0))
{
}
public SmallTowerDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041237;
public override Rectangle2D[] Area => SmallTower.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new SmallTower(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class LogCabinDeed : HouseDeed
{
[Constructible]
public LogCabinDeed() : base(0x9A, new Point3D(1, 6, 0))
{
}
public LogCabinDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041238;
public override Rectangle2D[] Area => LogCabin.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new LogCabin(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SandstonePatioDeed : HouseDeed
{
[Constructible]
public SandstonePatioDeed() : base(0x9C, new Point3D(-1, 4, 0))
{
}
public SandstonePatioDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041239;
public override Rectangle2D[] Area => SandStonePatio.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new SandStonePatio(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class VillaDeed : HouseDeed
{
[Constructible]
public VillaDeed() : base(0x9E, new Point3D(3, 6, 0))
{
}
public VillaDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041240;
public override Rectangle2D[] Area => TwoStoryVilla.AreaArray;
public override BaseHouse GetHouse(Mobile owner) => new TwoStoryVilla(owner);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class StoneWorkshopDeed : HouseDeed
{
[Constructible]
public StoneWorkshopDeed() : base(0xA0, new Point3D(-1, 4, 0))
{
}
public StoneWorkshopDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041241;
public override Rectangle2D[] Area => SmallShop.AreaArray2;
public override BaseHouse GetHouse(Mobile owner) => new SmallShop(owner, 0xA0);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class MarbleWorkshopDeed : HouseDeed
{
[Constructible]
public MarbleWorkshopDeed() : base(0xA2, new Point3D(-1, 4, 0))
{
}
public MarbleWorkshopDeed(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041242;
public override Rectangle2D[] Area => SmallShop.AreaArray1;
public override BaseHouse GetHouse(Mobile owner) => new SmallShop(owner, 0xA2);
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,339 @@
using System.Collections.Generic;
using System.Linq;
using Server.Regions;
using Server.Spells;
namespace Server.Multis
{
public enum HousePlacementResult
{
Valid,
BadRegion,
BadLand,
BadStatic,
BadItem,
NoSurface,
BadRegionHidden,
BadRegionTemp,
InvalidCastleKeep,
BadRegionRaffle
}
public class HousePlacement
{
private const int YardSize = 5;
// Any land tile which matches one of these ID numbers is considered a road and cannot be placed over.
private static int[] m_RoadIDs =
{
0x0071, 0x0078,
0x00E8, 0x00EB,
0x07AE, 0x07B1,
0x3FF4, 0x3FF4,
0x3FF8, 0x3FFB,
0x0442, 0x0479, // Sand stones
0x0501, 0x0510, // Sand stones
0x0009, 0x0015, // Furrows
0x0150, 0x015C // Furrows
};
public static HousePlacementResult Check(Mobile from, int multiID, Point3D center, out List<IEntity> toMove)
{
// If this spot is considered valid, every item and mobile in this list will be moved under the house sign
toMove = new List<IEntity>();
Map map = from.Map;
if (map == null || map == Map.Internal)
return HousePlacementResult.BadLand; // A house cannot go here
if (from.AccessLevel >= AccessLevel.GameMaster)
return HousePlacementResult.Valid; // Staff can place anywhere
if (map == Map.Ilshenar || SpellHelper.IsFeluccaT2A(map, center))
return HousePlacementResult.BadRegion; // No houses in Ilshenar/T2A
if (map == Map.Malas && (multiID == 0x007C || multiID == 0x007E))
return HousePlacementResult.InvalidCastleKeep;
if (Region.Find(center, map).IsPartOf<NoHousingRegion>())
return HousePlacementResult.BadRegion;
// This holds data describing the internal structure of the house
MultiComponentList mcl = MultiData.GetComponents(multiID);
if (multiID >= 0x13EC && multiID < 0x1D00)
HouseFoundation.AddStairsTo(ref mcl); // this is a AOS house, add the stairs
// Location of the nortwest-most corner of the house
Point3D 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
List<Item> items = new List<Item>();
List<Mobile> mobiles = new List<Mobile>();
// These are also storage lists. They hold location values indicating the yard and border locations.
List<Point2D> yard = new List<Point2D>(), borders = new List<Point2D>();
/* RULES:
*
* 1) All tiles which are around the -outside- of the foundation must not have anything impassable.
* 2) No impassable object or land tile may come in direct contact with any part of the house.
* 3) Five tiles from the front and back of the house must be completely clear of all house tiles.
* 4) The foundation must rest flatly on a surface. Any bumps around the foundation are not allowed.
* 5) No foundation tile may reside over terrain which is viewed as a road.
*/
for (int x = 0; x < mcl.Width; ++x)
for (int y = 0; y < mcl.Height; ++y)
{
int tileX = start.X + x;
int tileY = start.Y + y;
StaticTile[] addTiles = mcl.Tiles[x][y];
if (addTiles.Length == 0)
continue; // There are no tiles here, continue checking somewhere else
Point3D testPoint = new Point3D(tileX, tileY, center.Z);
Region reg = Region.Find(testPoint, map);
if (!reg.AllowHousing(from, testPoint)) // Cannot place houses in dungeons, towns, treasure map areas etc
{
if (reg.IsPartOf<TempNoHousingRegion>())
return HousePlacementResult.BadRegionTemp;
if (reg.IsPartOf<TreasureRegion>() || reg.IsPartOf<HouseRegion>())
return HousePlacementResult.BadRegionHidden;
if (reg.IsPartOf<HouseRaffleRegion>())
return HousePlacementResult.BadRegionRaffle;
return HousePlacementResult.BadRegion;
}
LandTile landTile = map.Tiles.GetLandTile(tileX, tileY);
int landID = landTile.ID & TileData.MaxLandValue;
StaticTile[] oldTiles = map.Tiles.GetStaticTiles(tileX, tileY, true);
Sector sector = map.GetSector(tileX, tileY);
items.Clear();
for (int i = 0; i < sector.Items.Count; ++i)
{
Item item = sector.Items[i];
if (item.Visible && item.X == tileX && item.Y == tileY)
items.Add(item);
}
mobiles.Clear();
for (int i = 0; i < sector.Mobiles.Count; ++i)
{
Mobile m = sector.Mobiles[i];
if (m.X == tileX && m.Y == tileY)
mobiles.Add(m);
}
int landStartZ = 0, landAvgZ = 0, landTopZ = 0;
map.GetAverageZ(tileX, tileY, ref landStartZ, ref landAvgZ, ref landTopZ);
bool hasFoundation = false;
for (int i = 0; i < addTiles.Length; ++i)
{
StaticTile addTile = addTiles[i];
if (addTile.ID == 0x1) // Nodraw
continue;
TileFlag addTileFlags = TileData.ItemTable[addTile.ID & TileData.MaxItemValue].Flags;
bool isFoundation = addTile.Z == 0 && (addTileFlags & TileFlag.Wall) != 0;
bool hasSurface = false;
hasFoundation |= isFoundation;
int addTileZ = center.Z + addTile.Z;
int addTileTop = addTileZ + addTile.Height;
if ((addTileFlags & TileFlag.Surface) != 0)
addTileTop += 16;
if (addTileTop > landStartZ && landAvgZ > addTileZ)
return HousePlacementResult.BadLand; // Broke rule #2
if (isFoundation &&
(TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) == 0 &&
landAvgZ == center.Z)
hasSurface = true;
for (int j = 0; j < oldTiles.Length; ++j)
{
StaticTile oldTile = oldTiles[j];
ItemData id = TileData.ItemTable[oldTile.ID & TileData.MaxItemValue];
if ((id.Impassable || id.Surface && (id.Flags & TileFlag.Background) == 0) &&
addTileTop > oldTile.Z && oldTile.Z + id.CalcHeight > addTileZ)
return HousePlacementResult.BadStatic; // Broke rule #2
/*else if ( isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (oldTile.Z + id.CalcHeight) == center.Z )
hasSurface = true;*/
}
for (int j = 0; j < items.Count; ++j)
{
Item item = items[j];
ItemData id = item.ItemData;
if (addTileTop > item.Z && item.Z + id.CalcHeight > addTileZ)
{
if (item.Movable)
toMove.Add(item);
else if (id.Impassable || id.Surface && (id.Flags & TileFlag.Background) == 0)
return HousePlacementResult.BadItem; // Broke rule #2
}
/*else if ( isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (item.Z + id.CalcHeight) == center.Z )
{
hasSurface = true;
}*/
}
if (isFoundation && !hasSurface)
return HousePlacementResult.NoSurface; // Broke rule #4
for (int j = 0; j < mobiles.Count; ++j)
{
Mobile m = mobiles[j];
if (addTileTop > m.Z && m.Z + 16 > addTileZ)
toMove.Add(m);
}
}
for (int i = 0; i < m_RoadIDs.Length; i += 2)
if (landID >= m_RoadIDs[i] && landID <= m_RoadIDs[i + 1])
return HousePlacementResult.BadLand; // Broke rule #5
if (hasFoundation)
{
for (int xOffset = -1; xOffset <= 1; ++xOffset)
for (int yOffset = -YardSize; yOffset <= YardSize; ++yOffset)
{
Point2D yardPoint = new Point2D(tileX + xOffset, tileY + yOffset);
if (!yard.Contains(yardPoint))
yard.Add(yardPoint);
}
for (int xOffset = -1; xOffset <= 1; ++xOffset)
for (int yOffset = -1; yOffset <= 1; ++yOffset)
{
if (xOffset == 0 && yOffset == 0)
continue;
// To ease this rule, we will not add to the border list if the tile here is under a base floor (z<=8)
int vx = x + xOffset;
int vy = y + yOffset;
if (vx >= 0 && vx < mcl.Width && vy >= 0 && vy < mcl.Height)
{
StaticTile[] breakTiles = mcl.Tiles[vx][vy];
bool shouldBreak = false;
for (int i = 0; !shouldBreak && i < breakTiles.Length; ++i)
{
StaticTile breakTile = breakTiles[i];
if (breakTile.Height == 0 && breakTile.Z <= 8 &&
TileData.ItemTable[breakTile.ID & TileData.MaxItemValue].Surface)
shouldBreak = true;
}
if (shouldBreak)
continue;
}
Point2D borderPoint = new Point2D(tileX + xOffset, tileY + yOffset);
if (!borders.Contains(borderPoint))
borders.Add(borderPoint);
}
}
}
for (int i = 0; i < borders.Count; ++i)
{
Point2D borderPoint = borders[i];
LandTile landTile = map.Tiles.GetLandTile(borderPoint.X, borderPoint.Y);
int landID = landTile.ID & TileData.MaxLandValue;
if ((TileData.LandTable[landID].Flags & TileFlag.Impassable) != 0)
return HousePlacementResult.BadLand;
for (int j = 0; j < m_RoadIDs.Length; j += 2)
if (landID >= m_RoadIDs[j] && landID <= m_RoadIDs[j + 1])
return HousePlacementResult.BadLand; // Broke rule #5
StaticTile[] tiles = map.Tiles.GetStaticTiles(borderPoint.X, borderPoint.Y, true);
for (int j = 0; j < tiles.Length; ++j)
{
StaticTile tile = tiles[j];
ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
if (id.Impassable || id.Surface && (id.Flags & TileFlag.Background) == 0 &&
tile.Z + id.CalcHeight > center.Z + 2)
return HousePlacementResult.BadStatic; // Broke rule #1
}
Sector sector = map.GetSector(borderPoint.X, borderPoint.Y);
List<Item> sectorItems = sector.Items;
for (int j = 0; j < sectorItems.Count; ++j)
{
Item item = sectorItems[j];
if (item.X != borderPoint.X || item.Y != borderPoint.Y || item.Movable)
continue;
ItemData id = item.ItemData;
if (id.Impassable || id.Surface && (id.Flags & TileFlag.Background) == 0 &&
item.Z + id.CalcHeight > center.Z + 2)
return HousePlacementResult.BadItem; // Broke rule #1
}
}
List<Sector> _sectors = new List<Sector>();
List<BaseHouse> _houses = new List<BaseHouse>();
for (int i = 0; i < yard.Count; i++)
{
Sector sector = map.GetSector(yard[i]);
if (!_sectors.Contains(sector))
{
_sectors.Add(sector);
for (int j = 0; j < sector.Multis?.Count; j++)
if (sector.Multis[j] is BaseHouse)
{
BaseHouse _house = (BaseHouse)sector.Multis[j];
if (!_houses.Contains(_house)) _houses.Add(_house);
}
}
}
return yard.Any(t => _houses.Any(b => b.Contains(t))) ? HousePlacementResult.BadStatic : HousePlacementResult.Valid;
}
}
}

View file

@ -0,0 +1,842 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Gumps;
using Server.Mobiles;
using Server.Multis;
using Server.Network;
using Server.Regions;
using Server.Targeting;
namespace Server.Items
{
public class HousePlacementTool : Item
{
[Constructible]
public HousePlacementTool() : base(0x14F6)
{
Weight = 3.0;
LootType = LootType.Blessed;
}
public HousePlacementTool(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1060651; // a house placement tool
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
from.SendGump(new HousePlacementCategoryGump(from));
else
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (Weight == 0.0)
Weight = 3.0;
}
}
public class HousePlacementCategoryGump : Gump
{
private const int LabelColor = 0x7FFF;
private const int LabelColorDisabled = 0x4210;
private Mobile m_From;
public HousePlacementCategoryGump(Mobile from) : base(50, 50)
{
m_From = from;
from.CloseGump<HousePlacementCategoryGump>();
from.CloseGump<HousePlacementListGump>();
AddPage(0);
AddBackground(0, 0, 270, 145, 5054);
AddImageTiled(10, 10, 250, 125, 2624);
AddAlphaRegion(10, 10, 250, 125);
AddHtmlLocalized(10, 10, 250, 20, 1060239, LabelColor); // <CENTER>HOUSE PLACEMENT TOOL</CENTER>
AddButton(10, 110, 4017, 4019, 0);
AddHtmlLocalized(45, 110, 150, 20, 3000363, LabelColor); // Close
AddButton(10, 40, 4005, 4007, 1);
AddHtmlLocalized(45, 40, 200, 20, 1060390, LabelColor); // Classic Houses
AddButton(10, 60, 4005, 4007, 2);
AddHtmlLocalized(45, 60, 200, 20, 1060391, LabelColor); // 2-Story Customizable Houses
AddButton(10, 80, 4005, 4007, 3);
AddHtmlLocalized(45, 80, 200, 20, 1060392, LabelColor); // 3-Story Customizable Houses
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (!m_From.CheckAlive() || m_From.Backpack?.FindItemByType<HousePlacementTool>() == null)
return;
switch (info.ButtonID)
{
case 1: // Classic Houses
{
m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.ClassicHouses));
break;
}
case 2: // 2-Story Customizable Houses
{
m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.TwoStoryFoundations));
break;
}
case 3: // 3-Story Customizable Houses
{
m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.ThreeStoryFoundations));
break;
}
}
}
}
public class HousePlacementListGump : Gump
{
private const int LabelColor = 0x7FFF;
private const int LabelHue = 0x480;
private HousePlacementEntry[] m_Entries;
private Mobile m_From;
public HousePlacementListGump(Mobile from, HousePlacementEntry[] entries) : base(50, 50)
{
m_From = from;
m_Entries = entries;
from.CloseGump<HousePlacementCategoryGump>();
from.CloseGump<HousePlacementListGump>();
AddPage(0);
AddBackground(0, 0, 520, 420, 5054);
AddImageTiled(10, 10, 500, 20, 2624);
AddAlphaRegion(10, 10, 500, 20);
AddHtmlLocalized(10, 10, 500, 20, 1060239, LabelColor); // <CENTER>HOUSE PLACEMENT TOOL</CENTER>
AddImageTiled(10, 40, 500, 20, 2624);
AddAlphaRegion(10, 40, 500, 20);
AddHtmlLocalized(50, 40, 225, 20, 1060235, LabelColor); // House Description
AddHtmlLocalized(275, 40, 75, 20, 1060236, LabelColor); // Storage
AddHtmlLocalized(350, 40, 75, 20, 1060237, LabelColor); // Lockdowns
AddHtmlLocalized(425, 40, 75, 20, 1060034, LabelColor); // Cost
AddImageTiled(10, 70, 500, 280, 2624);
AddAlphaRegion(10, 70, 500, 280);
AddImageTiled(10, 360, 500, 20, 2624);
AddAlphaRegion(10, 360, 500, 20);
AddHtmlLocalized(10, 360, 250, 20, 1060645, LabelColor); // Bank Balance:
AddLabel(250, 360, LabelHue, Banker.GetBalance(from).ToString());
AddImageTiled(10, 390, 500, 20, 2624);
AddAlphaRegion(10, 390, 500, 20);
AddButton(10, 390, 4017, 4019, 0);
AddHtmlLocalized(50, 390, 100, 20, 3000363, LabelColor); // Close
for (int i = 0; i < entries.Length; ++i)
{
int page = 1 + i / 14;
int index = i % 14;
if (index == 0)
{
if (page > 1)
{
AddButton(450, 390, 4005, 4007, 0, GumpButtonType.Page, page);
AddHtmlLocalized(400, 390, 100, 20, 3000406, LabelColor); // Next
}
AddPage(page);
if (page > 1)
{
AddButton(200, 390, 4014, 4016, 0, GumpButtonType.Page, page - 1);
AddHtmlLocalized(250, 390, 100, 20, 3000405, LabelColor); // Previous
}
}
HousePlacementEntry entry = entries[i];
int y = 70 + index * 20;
AddButton(10, y, 4005, 4007, 1 + i);
AddHtmlLocalized(50, y, 225, 20, entry.Description, LabelColor);
AddLabel(275, y, LabelHue, entry.Storage.ToString());
AddLabel(350, y, LabelHue, entry.Lockdowns.ToString());
AddLabel(425, y, LabelHue, entry.Cost.ToString());
}
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (!m_From.CheckAlive() || m_From.Backpack?.FindItemByType<HousePlacementTool>() == null)
return;
int index = info.ButtonID - 1;
if (index >= 0 && index < m_Entries.Length)
{
if (m_From.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(m_From))
m_From.SendLocalizedMessage(501271); // You already own a house, you may not place another!
else
m_From.Target = new NewHousePlacementTarget(m_Entries, m_Entries[index]);
}
else
{
m_From.SendGump(new HousePlacementCategoryGump(m_From));
}
}
}
public class NewHousePlacementTarget : MultiTarget
{
private HousePlacementEntry[] m_Entries;
private HousePlacementEntry m_Entry;
private bool m_Placed;
public NewHousePlacementTarget(HousePlacementEntry[] entries, HousePlacementEntry entry) : base(entry.MultiID,
entry.Offset)
{
Range = 14;
m_Entries = entries;
m_Entry = entry;
}
protected override void OnTarget(Mobile from, object o)
{
if (!from.CheckAlive() || from.Backpack?.FindItemByType<HousePlacementTool>() == null)
return;
if (o is IPoint3D ip)
{
if (ip is Item item)
ip = item.GetWorldTop();
Point3D p = new Point3D(ip);
Region reg = Region.Find(new Point3D(p), from.Map);
if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p))
m_Placed = m_Entry.OnPlacement(from, p);
else if (reg.IsPartOf<TempNoHousingRegion>())
from.SendLocalizedMessage(
501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
else if (reg.IsPartOf<TreasureRegion>() || reg.IsPartOf<HouseRegion>())
from.SendLocalizedMessage(
1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
else if (reg.IsPartOf<HouseRaffleRegion>())
from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here.
else
from.SendLocalizedMessage(501265); // Housing can not be created in this area.
}
}
protected override void OnTargetFinish(Mobile from)
{
if (!from.CheckAlive() || from.Backpack?.FindItemByType<HousePlacementTool>() == null)
return;
if (!m_Placed)
from.SendGump(new HousePlacementListGump(from, m_Entries));
}
}
public class HousePlacementEntry
{
private static Dictionary<Type, object> m_Table;
private int m_Lockdowns;
private int m_NewLockdowns;
private int m_NewStorage;
private int m_Storage;
static HousePlacementEntry()
{
m_Table = new Dictionary<Type, object>();
FillTable(ClassicHouses);
FillTable(TwoStoryFoundations);
FillTable(ThreeStoryFoundations);
}
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)
{
Type = type;
Description = description;
m_Storage = storage;
m_Lockdowns = lockdowns;
m_NewStorage = newStorage;
m_NewLockdowns = newLockdowns;
Vendors = vendors;
Cost = cost;
Offset = new Point3D(xOffset, yOffset, zOffset);
MultiID = multiID;
}
public Type Type{ get; }
public int Description{ get; }
public int Storage => BaseHouse.NewVendorSystem ? m_NewStorage : m_Storage;
public int Lockdowns => BaseHouse.NewVendorSystem ? m_NewLockdowns : m_Lockdowns;
public int Vendors{ get; }
public int Cost{ get; }
public int MultiID{ get; }
public Point3D Offset{ get; }
public static HousePlacementEntry[] ClassicHouses{ get; } =
{
new HousePlacementEntry(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0064),
new HousePlacementEntry(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0066),
new HousePlacementEntry(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0068),
new HousePlacementEntry(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35250, 0, 4, 0, 0x006A),
new HousePlacementEntry(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006C),
new HousePlacementEntry(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006E),
new HousePlacementEntry(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50500, -1, 4, 0, 0x00A0),
new HousePlacementEntry(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52500, 0, 4, 0, 0x00A2),
new HousePlacementEntry(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73500, 3, 4, 0, 0x0098),
new HousePlacementEntry(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113750, 3, 6, 0, 0x009E),
new HousePlacementEntry(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76500, -1, 4, 0, 0x009C),
new HousePlacementEntry(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81750, 1, 6, 0, 0x009A),
new HousePlacementEntry(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131500, -1, 7, 0, 0x0074),
new HousePlacementEntry(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0076),
new HousePlacementEntry(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162000, -3, 7, 0, 0x0078),
new HousePlacementEntry(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129250, -4, 7, 0, 0x008C),
new HousePlacementEntry(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160500, -4, 7, 0, 0x0096),
new HousePlacementEntry(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366500, 0, 7, 0, 0x007A),
new HousePlacementEntry(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 572750, 0, 11, 0, 0x007C),
new HousePlacementEntry(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865250, 0, 16, 0, 0x007E)
};
public static HousePlacementEntry[] TwoStoryFoundations{ get; } =
{
new HousePlacementEntry(typeof(HouseFoundation), 1060241, 425, 212, 489, 244, 10, 30500, 0, 4, 0,
0x13EC), // 7x7 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060242, 580, 290, 667, 333, 14, 34500, 0, 5, 0,
0x13ED), // 7x8 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060243, 650, 325, 748, 374, 16, 38500, 0, 5, 0,
0x13EE), // 7x9 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060244, 700, 350, 805, 402, 16, 42500, 0, 6, 0,
0x13EF), // 7x10 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060245, 750, 375, 863, 431, 16, 46500, 0, 6, 0,
0x13F0), // 7x11 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060246, 800, 400, 920, 460, 18, 50500, 0, 7, 0,
0x13F1), // 7x12 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060253, 580, 290, 667, 333, 14, 34500, 0, 4, 0,
0x13F8), // 8x7 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060254, 650, 325, 748, 374, 16, 39000, 0, 5, 0,
0x13F9), // 8x8 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060255, 700, 350, 805, 402, 16, 43500, 0, 5, 0,
0x13FA), // 8x9 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060256, 750, 375, 863, 431, 16, 48000, 0, 6, 0,
0x13FB), // 8x10 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060257, 800, 400, 920, 460, 18, 52500, 0, 6, 0,
0x13FC), // 8x11 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060258, 850, 425, 1265, 632, 24, 57000, 0, 7, 0,
0x13FD), // 8x12 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060259, 1100, 550, 1265, 632, 24, 61500, 0, 7, 0,
0x13FE), // 8x13 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060265, 650, 325, 748, 374, 16, 38500, 0, 4, 0,
0x1404), // 9x7 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060266, 700, 350, 805, 402, 16, 43500, 0, 5, 0,
0x1405), // 9x8 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060267, 750, 375, 863, 431, 16, 48500, 0, 5, 0,
0x1406), // 9x9 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060268, 800, 400, 920, 460, 18, 53500, 0, 6, 0,
0x1407), // 9x10 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060269, 850, 425, 1265, 632, 24, 58500, 0, 6, 0,
0x1408), // 9x11 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060270, 1100, 550, 1265, 632, 24, 63500, 0, 7, 0,
0x1409), // 9x12 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060271, 1100, 550, 1265, 632, 24, 68500, 0, 7, 0,
0x140A), // 9x13 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060277, 700, 350, 805, 402, 16, 42500, 0, 4, 0,
0x1410), // 10x7 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060278, 750, 375, 863, 431, 16, 48000, 0, 5, 0,
0x1411), // 10x8 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060279, 800, 400, 920, 460, 18, 53500, 0, 5, 0,
0x1412), // 10x9 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060280, 850, 425, 1265, 632, 24, 59000, 0, 6, 0,
0x1413), // 10x10 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060281, 1100, 550, 1265, 632, 24, 64500, 0, 6, 0,
0x1414), // 10x11 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060282, 1100, 550, 1265, 632, 24, 70000, 0, 7, 0,
0x1415), // 10x12 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060283, 1150, 575, 1323, 661, 24, 75500, 0, 7, 0,
0x1416), // 10x13 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060289, 750, 375, 863, 431, 16, 46500, 0, 4, 0,
0x141C), // 11x7 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060290, 800, 400, 920, 460, 18, 52500, 0, 5, 0,
0x141D), // 11x8 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060291, 850, 425, 1265, 632, 24, 58500, 0, 5, 0,
0x141E), // 11x9 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060292, 1100, 550, 1265, 632, 24, 64500, 0, 6, 0,
0x141F), // 11x10 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060293, 1100, 550, 1265, 632, 24, 70500, 0, 6, 0,
0x1420), // 11x11 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060294, 1150, 575, 1323, 661, 24, 76500, 0, 7, 0,
0x1421), // 11x12 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060295, 1200, 600, 1380, 690, 26, 82500, 0, 7, 0,
0x1422), // 11x13 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060301, 800, 400, 920, 460, 18, 50500, 0, 4, 0,
0x1428), // 12x7 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060302, 850, 425, 1265, 632, 24, 57000, 0, 5, 0,
0x1429), // 12x8 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060303, 1100, 550, 1265, 632, 24, 63500, 0, 5, 0,
0x142A), // 12x9 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060304, 1100, 550, 1265, 632, 24, 70000, 0, 6, 0,
0x142B), // 12x10 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060305, 1150, 575, 1323, 661, 24, 76500, 0, 6, 0,
0x142C), // 12x11 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060306, 1200, 600, 1380, 690, 26, 83000, 0, 7, 0,
0x142D), // 12x12 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060307, 1250, 625, 1438, 719, 26, 89500, 0, 7, 0,
0x142E), // 12x13 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060314, 1100, 550, 1265, 632, 24, 61500, 0, 5, 0,
0x1435), // 13x8 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060315, 1100, 550, 1265, 632, 24, 68500, 0, 5, 0,
0x1436), // 13x9 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060316, 1150, 575, 1323, 661, 24, 75500, 0, 6, 0,
0x1437), // 13x10 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060317, 1200, 600, 1380, 690, 26, 82500, 0, 6, 0,
0x1438), // 13x11 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060318, 1250, 625, 1438, 719, 26, 89500, 0, 7, 0,
0x1439), // 13x12 2-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060319, 1300, 650, 1495, 747, 28, 96500, 0, 7, 0,
0x143A) // 13x13 2-Story Customizable House
};
public static HousePlacementEntry[] ThreeStoryFoundations{ get; } =
{
new HousePlacementEntry(typeof(HouseFoundation), 1060272, 1150, 575, 1323, 661, 24, 73500, 0, 8, 0,
0x140B), // 9x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060284, 1200, 600, 1380, 690, 26, 81000, 0, 8, 0,
0x1417), // 10x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060285, 1250, 625, 1438, 719, 26, 86500, 0, 8, 0,
0x1418), // 10x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060296, 1250, 625, 1438, 719, 26, 88500, 0, 8, 0,
0x1423), // 11x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060297, 1300, 650, 1495, 747, 28, 94500, 0, 8, 0,
0x1424), // 11x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060298, 1350, 675, 1553, 776, 28, 100500, 0, 9, 0,
0x1425), // 11x16 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060308, 1300, 650, 1495, 747, 28, 96000, 0, 8, 0,
0x142F), // 12x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060309, 1350, 675, 1553, 776, 28, 102500, 0, 8, 0,
0x1430), // 12x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060310, 1370, 685, 1576, 788, 28, 109000, 0, 9, 0,
0x1431), // 12x16 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060311, 1370, 685, 1576, 788, 28, 115500, 0, 9, 0,
0x1432), // 12x17 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060320, 1350, 675, 1553, 776, 28, 103500, 0, 8, 0,
0x143B), // 13x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060321, 1370, 685, 1576, 788, 28, 110500, 0, 8, 0,
0x143C), // 13x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060322, 1370, 685, 1576, 788, 28, 117500, 0, 9, 0,
0x143D), // 13x16 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060323, 2119, 1059, 2437, 1218, 42, 124500, 0, 9, 0,
0x143E), // 13x17 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060324, 2119, 1059, 2437, 1218, 42, 131500, 0, 10, 0,
0x143F), // 13x18 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060327, 1150, 575, 1323, 661, 24, 73500, 0, 5, 0,
0x1442), // 14x9 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060328, 1200, 600, 1380, 690, 26, 81000, 0, 6, 0,
0x1443), // 14x10 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060329, 1250, 625, 1438, 719, 26, 88500, 0, 6, 0,
0x1444), // 14x11 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060330, 1300, 650, 1495, 747, 28, 96000, 0, 7, 0,
0x1445), // 14x12 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060331, 1350, 675, 1553, 776, 28, 103500, 0, 7, 0,
0x1446), // 14x13 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060332, 1370, 685, 1576, 788, 28, 111000, 0, 8, 0,
0x1447), // 14x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060333, 1370, 685, 1576, 788, 28, 118500, 0, 8, 0,
0x1448), // 14x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060334, 2119, 1059, 2437, 1218, 42, 126000, 0, 9, 0,
0x1449), // 14x16 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060335, 2119, 1059, 2437, 1218, 42, 133500, 0, 9, 0,
0x144A), // 14x17 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060336, 2119, 1059, 2437, 1218, 42, 141000, 0, 10, 0,
0x144B), // 14x18 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060340, 1250, 625, 1438, 719, 26, 86500, 0, 6, 0,
0x144F), // 15x10 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060341, 1300, 650, 1495, 747, 28, 94500, 0, 6, 0,
0x1450), // 15x11 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060342, 1350, 675, 1553, 776, 28, 102500, 0, 7, 0,
0x1451), // 15x12 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060343, 1370, 685, 1576, 788, 28, 110500, 0, 7, 0,
0x1452), // 15x13 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060344, 1370, 685, 1576, 788, 28, 118500, 0, 8, 0,
0x1453), // 15x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060345, 2119, 1059, 2437, 1218, 42, 126500, 0, 8, 0,
0x1454), // 15x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060346, 2119, 1059, 2437, 1218, 42, 134500, 0, 9, 0,
0x1455), // 15x16 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060347, 2119, 1059, 2437, 1218, 42, 142500, 0, 9, 0,
0x1456), // 15x17 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060348, 2119, 1059, 2437, 1218, 42, 150500, 0, 10, 0,
0x1457), // 15x18 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060353, 1350, 675, 1553, 776, 28, 100500, 0, 6, 0,
0x145C), // 16x11 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060354, 1370, 685, 1576, 788, 28, 109000, 0, 7, 0,
0x145D), // 16x12 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060355, 1370, 685, 1576, 788, 28, 117500, 0, 7, 0,
0x145E), // 16x13 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060356, 2119, 1059, 2437, 1218, 42, 126000, 0, 8, 0,
0x145F), // 16x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060357, 2119, 1059, 2437, 1218, 42, 134500, 0, 8, 0,
0x1460), // 16x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060358, 2119, 1059, 2437, 1218, 42, 143000, 0, 9, 0,
0x1461), // 16x16 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060359, 2119, 1059, 2437, 1218, 42, 151500, 0, 9, 0,
0x1462), // 16x17 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060360, 2119, 1059, 2437, 1218, 42, 160000, 0, 10, 0,
0x1463), // 16x18 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060366, 1370, 685, 1576, 788, 28, 115500, 0, 7, 0,
0x1469), // 17x12 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060367, 2119, 1059, 2437, 1218, 42, 124500, 0, 7, 0,
0x146A), // 17x13 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060368, 2119, 1059, 2437, 1218, 42, 133500, 0, 8, 0,
0x146B), // 17x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060369, 2119, 1059, 2437, 1218, 42, 142500, 0, 8, 0,
0x146C), // 17x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060370, 2119, 1059, 2437, 1218, 42, 151500, 0, 9, 0,
0x146D), // 17x16 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060371, 2119, 1059, 2437, 1218, 42, 160500, 0, 9, 0,
0x146E), // 17x17 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060372, 2119, 1059, 2437, 1218, 42, 169500, 0, 10, 0,
0x146F), // 17x18 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060379, 2119, 1059, 2437, 1218, 42, 131500, 0, 7, 0,
0x1476), // 18x13 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060380, 2119, 1059, 2437, 1218, 42, 141000, 0, 8, 0,
0x1477), // 18x14 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060381, 2119, 1059, 2437, 1218, 42, 150500, 0, 8, 0,
0x1478), // 18x15 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060382, 2119, 1059, 2437, 1218, 42, 160000, 0, 9, 0,
0x1479), // 18x16 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060383, 2119, 1059, 2437, 1218, 42, 169500, 0, 9, 0,
0x147A), // 18x17 3-Story Customizable House
new HousePlacementEntry(typeof(HouseFoundation), 1060384, 2119, 1059, 2437, 1218, 42, 179000, 0, 10, 0,
0x147B) // 18x18 3-Story Customizable House
};
public BaseHouse ConstructHouse(Mobile from)
{
try
{
object[] args;
if (Type == typeof(HouseFoundation))
args = new object[] { from, MultiID, m_Storage, m_Lockdowns };
else if (Type == typeof(SmallOldHouse) || Type == typeof(SmallShop) || Type == typeof(TwoStoryHouse))
args = new object[] { from, MultiID };
else
args = new object[] { from };
return Activator.CreateInstance(Type, args) as BaseHouse;
}
catch
{
// ignored
}
return null;
}
public void PlacementWarning_Callback(Mobile from, bool okay, PreviewHouse prevHouse)
{
if (!from.CheckAlive() || from.Backpack?.FindItemByType<HousePlacementTool>() == null)
return;
if (!okay)
{
prevHouse.Delete();
return;
}
if (prevHouse.Deleted)
{
/* Too much time has passed and the test house you created has been deleted.
* Please try again!
*/
from.SendGump(new NoticeGump(1060637, 30720, 1060647, 32512, 320, 180));
return;
}
Point3D center = prevHouse.Location;
prevHouse.Delete();
//Point3D center = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z );
HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List<IEntity> toMove);
switch (res)
{
case HousePlacementResult.Valid:
{
if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from))
from.SendLocalizedMessage(501271); // You already own a house, you may not place another!
else
{
BaseHouse house = ConstructHouse(from);
if (house == null)
return;
house.Price = Cost;
if (from.AccessLevel >= AccessLevel.GameMaster)
from.SendMessage("{0} gold would have been withdrawn from your bank if you were not a GM.",
Cost.ToString());
else
{
if (Banker.Withdraw(from, Cost))
from.SendLocalizedMessage(1060398,
Cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box.
else
{
house.RemoveKeys(from);
house.Delete();
from.SendLocalizedMessage(
1060646); // 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.
return;
}
}
house.MoveToWorld(center, from.Map);
for (int i = 0; i < toMove.Count; ++i)
{
object o = toMove[i];
if (o is Mobile mobile)
mobile.Location = house.BanLocation;
else if (o is Item item)
item.Location = house.BanLocation;
}
}
break;
}
case HousePlacementResult.BadItem:
case HousePlacementResult.BadLand:
case HousePlacementResult.BadStatic:
case HousePlacementResult.BadRegionHidden:
case HousePlacementResult.NoSurface:
{
from.SendLocalizedMessage(
1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
break;
}
case HousePlacementResult.BadRegion:
{
from.SendLocalizedMessage(501265); // Housing cannot be created in this area.
break;
}
case HousePlacementResult.BadRegionTemp:
{
from.SendLocalizedMessage(
501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
break;
}
case HousePlacementResult.BadRegionRaffle:
{
from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here.
break;
}
case HousePlacementResult.InvalidCastleKeep:
{
from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here.
break;
}
}
}
public bool OnPlacement(Mobile from, Point3D p)
{
if (!from.CheckAlive() || from.Backpack?.FindItemByType<HousePlacementTool>() == null)
return false;
Point3D center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z);
HousePlacementResult res = HousePlacement.Check(from, MultiID, center, out List<IEntity> toMove);
switch (res)
{
case HousePlacementResult.Valid:
{
if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from))
from.SendLocalizedMessage(501271); // You already own a house, you may not place another!
else
{
from.SendLocalizedMessage(1011576); // This is a valid location.
PreviewHouse prev = new PreviewHouse(MultiID);
MultiComponentList mcl = prev.Components;
Point3D banLoc = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Max.Y + 1, center.Z);
for (int i = 0; i < mcl.List.Length; ++i)
{
MultiTileEntry entry = mcl.List[i];
int itemID = entry.m_ItemID;
if (itemID >= 0xBA3 && itemID <= 0xC0E)
{
banLoc = new Point3D(center.X + entry.m_OffsetX, center.Y + entry.m_OffsetY, center.Z);
break;
}
}
for (int i = 0; i < toMove.Count; ++i)
{
object o = toMove[i];
if (o is Mobile mobile)
mobile.Location = banLoc;
else if (o is Item item)
item.Location = banLoc;
}
prev.MoveToWorld(center, from.Map);
/* You are about to place a new house.
* Placing this house will condemn any and all of your other houses that you may have.
* All of your houses on all shards will be affected.
*
* In addition, you will not be able to place another house or have one transferred to you for one (1) real-life week.
*
* Once you accept these terms, these effects cannot be reversed.
* Re-deeding or transferring your new house will not uncondemn your other house(s) nor will the one week timer be removed.
*
* If you are absolutely certain you wish to proceed, click the button next to OKAY below.
* If you do not wish to trade for this house, click CANCEL.
*/
from.SendGump(new WarningGump(1060635, 30720, 1049583, 32512, 420, 280, okay => PlacementWarning_Callback(from, okay, prev)));
return true;
}
break;
}
case HousePlacementResult.BadItem:
case HousePlacementResult.BadLand:
case HousePlacementResult.BadStatic:
case HousePlacementResult.BadRegionHidden:
case HousePlacementResult.NoSurface:
{
from.SendLocalizedMessage(
1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain.
break;
}
case HousePlacementResult.BadRegion:
{
from.SendLocalizedMessage(501265); // Housing cannot be created in this area.
break;
}
case HousePlacementResult.BadRegionTemp:
{
from.SendLocalizedMessage(
501270); //Lord British has decreed a 'no build' period, thus you cannot build this house at this time.
break;
}
case HousePlacementResult.BadRegionRaffle:
{
from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here.
break;
}
case HousePlacementResult.InvalidCastleKeep:
{
from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here.
break;
}
}
return false;
}
public static HousePlacementEntry Find(BaseHouse house)
{
m_Table.TryGetValue(house.GetType(), out object obj);
return obj switch
{
HousePlacementEntry entry => entry,
List<HousePlacementEntry> list => list.FirstOrDefault(e => e.MultiID == house.ItemID),
Dictionary<int, HousePlacementEntry> table => table[house.ItemID],
_ => null
};
}
private static void FillTable(HousePlacementEntry[] entries)
{
for (int i = 0; i < entries.Length; ++i)
{
HousePlacementEntry e = entries[i];
if (!m_Table.TryGetValue(e.Type, out object obj))
m_Table[e.Type] = e;
else if (obj is HousePlacementEntry entry)
{
List<HousePlacementEntry> list = new List<HousePlacementEntry> { entry, e };
m_Table[e.Type] = list;
}
else if (obj is List<HousePlacementEntry> list)
{
if (list.Count == 8)
{
Dictionary<int, HousePlacementEntry> table = new Dictionary<int, HousePlacementEntry>();
foreach (HousePlacementEntry t in list)
table[t.MultiID] = t;
table[e.MultiID] = e;
m_Table[e.Type] = table;
}
else
list.Add(e);
}
else if (obj is Dictionary<int, HousePlacementEntry> table) table[e.MultiID] = e;
}
}
}
}

View file

@ -0,0 +1,256 @@
using System;
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Gumps;
namespace Server.Multis
{
public class HouseSign : Item
{
public HouseSign(BaseHouse owner) : base(0xBD2)
{
Owner = owner;
OriginalOwner = Owner.Owner;
Movable = false;
}
public HouseSign(Serial serial) : base(serial)
{
}
public BaseHouse Owner{ get; private set; }
[CommandProperty(AccessLevel.GameMaster)]
public bool RestrictDecay
{
get => Owner?.RestrictDecay == true;
set
{
if (Owner != null)
Owner.RestrictDecay = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public Mobile OriginalOwner{ get; private set; }
public override bool ForceShowProperties => ObjectPropertyList.Enabled;
public bool GettingProperties{ get; private set; }
public string GetName() => Name ?? "An Unnamed House";
public override void OnAfterDelete()
{
base.OnAfterDelete();
if (Owner?.Deleted == false)
Owner.Delete();
}
public override void AddNameProperty(ObjectPropertyList list)
{
list.Add(1061638); // A House Sign
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
list.Add(1061639, Utility.FixHtml(GetName())); // Name: ~1_NAME~
list.Add(1061640, Owner?.Owner == null ? "nobody" : Owner.Owner.Name); // Owner: ~1_OWNER~
if (Owner != null)
{
list.Add(Owner.Public ? 1061641 : 1061642); // This House is Open to the Public : This is a Private Home
GettingProperties = true;
DecayLevel level = Owner.DecayLevel;
GettingProperties = false;
if (level == DecayLevel.DemolitionPending)
{
list.Add(1062497); // Demolition Pending
}
else if (level != DecayLevel.Ageless)
{
if (level == DecayLevel.Collapsed)
level = DecayLevel.IDOC;
list.Add(1062028, $"#{1043009 + (int)level}"); // Condition: This structure is ...
}
}
}
public override void OnSingleClick(Mobile from)
{
if (Owner != null && BaseHouse.DecayEnabled && Owner.DecayPeriod != TimeSpan.Zero)
{
var message = Owner.DecayLevel switch
{
DecayLevel.Ageless => "ageless",
DecayLevel.Fairly => "fairly worn",
DecayLevel.Greatly => "greatly worn",
DecayLevel.LikeNew => "like new",
DecayLevel.Slightly => "slightly worn",
DecayLevel.Somewhat => "somewhat worn",
_ => "in danger of collapsing"
};
LabelTo(from, "This house is {0}.", message);
}
base.OnSingleClick(from);
}
public void ShowSign(Mobile m)
{
if (Owner != null)
{
if (Owner.IsFriend(m) && m.AccessLevel < AccessLevel.GameMaster)
{
#region Mondain's Legacy
if (Core.ML && Owner.IsOwner(m) || !Core.ML)
Owner.RefreshDecay();
#endregion
if (!Core.AOS)
m.SendLocalizedMessage(501293); // Welcome back to the house, friend!
}
if (Owner.IsAosRules)
m.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Information, m, Owner));
else
m.SendGump(new HouseGump(m, Owner));
}
}
public void ClaimGump_Callback(Mobile from, bool okay)
{
if (okay && Owner != null && Owner.Owner == null && Owner.DecayLevel != DecayLevel.DemolitionPending)
{
bool canClaim = Owner.CoOwners?.Count > 0 && Owner.IsCoOwner(from) || Owner.IsFriend(from);
if (canClaim && !BaseHouse.HasAccountHouse(from))
{
Owner.Owner = from;
Owner.LastTraded = DateTime.UtcNow;
}
}
ShowSign(from);
}
public override void OnDoubleClick(Mobile m)
{
if (Owner == null)
return;
if (m.AccessLevel < AccessLevel.GameMaster && Owner.Owner == null &&
Owner.DecayLevel != DecayLevel.DemolitionPending)
{
bool canClaim = Owner?.CoOwners.Count > 0 && Owner.IsCoOwner(m) || Owner.IsFriend(m);
if (canClaim && !BaseHouse.HasAccountHouse(m))
m.SendGump(new WarningGump(501036, 32512, 1049719, 32512, 420, 280, okay => ClaimGump_Callback(m, okay)));
}
ShowSign(m);
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
if (!BaseHouse.NewVendorSystem || !from.Alive || Owner?.IsAosRules != true)
return;
if (Owner.AreThereAvailableVendorsFor(from))
list.Add(new VendorsEntry(this));
if (Owner.VendorInventories.Count > 0)
list.Add(new ReclaimVendorInventoryEntry(this));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(Owner);
writer.Write(OriginalOwner);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
Owner = reader.ReadItem() as BaseHouse;
OriginalOwner = reader.ReadMobile();
break;
}
}
if (Name == "a house sign")
Name = null;
}
private class VendorsEntry : ContextMenuEntry
{
private HouseSign m_Sign;
public VendorsEntry(HouseSign sign) : base(6211) => m_Sign = sign;
public override void OnClick()
{
Mobile from = Owner.From;
if (!from.CheckAlive() || m_Sign.Deleted || m_Sign.Owner?.AreThereAvailableVendorsFor(from) != true)
return;
if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5))
from.SendLocalizedMessage(
1062429); // You must be within five paces of the house sign to use this option.
else
from.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Vendors, from, m_Sign.Owner));
}
}
private class ReclaimVendorInventoryEntry : ContextMenuEntry
{
private HouseSign m_Sign;
public ReclaimVendorInventoryEntry(HouseSign sign) : base(6213) => m_Sign = sign;
public override void OnClick()
{
Mobile from = Owner.From;
if (m_Sign.Deleted || m_Sign.Owner == null || m_Sign.Owner.VendorInventories.Count == 0 ||
!from.CheckAlive())
return;
if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5))
{
from.SendLocalizedMessage(
1062429); // You must be within five paces of the house sign to use this option.
}
else
{
from.CloseGump<VendorInventoryGump>();
from.SendGump(new VendorInventoryGump(m_Sign.Owner, from));
}
}
}
}
}

View file

@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Gumps;
using Server.Mobiles;
using Server.Multis;
namespace Server.Items
{
public class HouseTeleporter : Item, ISecurable
{
public HouseTeleporter(int itemID, Item target = null) : base(itemID)
{
Movable = false;
Level = SecureLevel.Anyone;
Target = target;
}
public HouseTeleporter(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public Item Target{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public SecureLevel Level{ get; set; }
public bool CheckAccess(Mobile m)
{
BaseHouse house = BaseHouse.FindHouseAt(this);
return (house == null || house.Public && !house.IsBanned(m) || house.HasAccess(m)) &&
house?.HasSecureAccess(m, Level) == true;
}
public override bool OnMoveOver(Mobile m)
{
if (Target?.Deleted == false)
{
if (CheckAccess(m))
{
if (!m.Hidden || m.AccessLevel == AccessLevel.Player)
new EffectTimer(Location, Map, 2023, 0x1F0, TimeSpan.FromSeconds(0.4)).Start();
new DelayTimer(this, m).Start();
}
else
{
m.SendLocalizedMessage(1061637); // You are not allowed to access this.
}
}
return true;
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
SetSecureLevelEntry.AddTo(from, this, list);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
writer.Write((int)Level);
writer.Write(Target);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 1:
{
Level = (SecureLevel)reader.ReadInt();
goto case 0;
}
case 0:
{
Target = reader.ReadItem();
if (version < 0)
Level = SecureLevel.Anyone;
break;
}
}
}
private class EffectTimer : Timer
{
private int m_EffectID;
private Point3D m_Location;
private Map m_Map;
private int m_SoundID;
public EffectTimer(Point3D p, Map map, int effectID, int soundID, TimeSpan delay) : base(delay)
{
m_Location = p;
m_Map = map;
m_EffectID = effectID;
m_SoundID = soundID;
}
protected override void OnTick()
{
Effects.SendLocationParticles(EffectItem.Create(m_Location, m_Map, EffectItem.DefaultDuration), 0x3728, 10,
10, m_EffectID, 0);
if (m_SoundID != -1)
Effects.PlaySound(m_Location, m_Map, m_SoundID);
}
}
private class DelayTimer : Timer
{
private Mobile m_Mobile;
private HouseTeleporter m_Teleporter;
public DelayTimer(HouseTeleporter tp, Mobile m) : base(TimeSpan.FromSeconds(1.0))
{
m_Teleporter = tp;
m_Mobile = m;
}
protected override void OnTick()
{
Item target = m_Teleporter.Target;
if (target?.Deleted != false)
return;
Mobile m = m_Mobile;
if (m.Location != m_Teleporter.Location || m.Map != m_Teleporter.Map)
return;
Point3D p = target.GetWorldTop();
Map map = target.Map;
BaseCreature.TeleportPets(m, p, map);
m.MoveToWorld(p, map);
if (m.Hidden && m.AccessLevel != AccessLevel.Player)
return;
Effects.PlaySound(target.Location, target.Map, 0x1FE);
Effects.SendLocationParticles(
EffectItem.Create(m_Teleporter.Location, m_Teleporter.Map, EffectItem.DefaultDuration),
0x3728, 10, 10, 2023, 0);
Effects.SendLocationParticles(
EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 10, 10,
5023, 0);
new EffectTimer(target.Location, target.Map, 2023, -1, TimeSpan.FromSeconds(0.4)).Start();
}
}
}
}

View file

@ -0,0 +1,584 @@
using Server.Items;
using Server.Multis.Deeds;
namespace Server.Multis
{
public class SmallOldHouse : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-1, 4, 3, 1) };
public SmallOldHouse(Mobile owner, int id) : base(id, owner, 425, 3)
{
uint keyValue = CreateKeys(owner);
AddSouthDoor(0, 3, 7, keyValue);
SetSign(2, 4, 5);
}
public SmallOldHouse(Serial serial) : base(serial)
{
}
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(2, 4, 0);
public override int DefaultPrice => 43800;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[0];
public override HouseDeed GetDeed()
{
return ItemID switch
{
0x64 => (HouseDeed)new StonePlasterHouseDeed(),
0x66 => new FieldStoneHouseDeed(),
0x68 => new SmallBrickHouseDeed(),
0x6A => new WoodHouseDeed(),
0x6C => new WoodPlasterHouseDeed(),
0x6E => new ThatchedRoofCottageDeed(),
_ => new ThatchedRoofCottageDeed()
};
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class GuildHouse : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 14, 14), new Rectangle2D(-2, 7, 4, 1) };
public GuildHouse(Mobile owner) : base(0x74, owner, 1100, 8)
{
uint keyValue = CreateKeys(owner);
AddSouthDoors(-1, 6, 7, keyValue);
SetSign(4, 8, 16);
AddSouthDoor(-3, -1, 7);
AddSouthDoor(3, -1, 7);
}
public GuildHouse(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 144500;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[20];
public override int ConvertOffsetX => -1;
public override int ConvertOffsetY => -1;
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(4, 8, 0);
public override HouseDeed GetDeed() => new BrickHouseDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class TwoStoryHouse : BaseHouse
{
public static Rectangle2D[] AreaArray =
{ new Rectangle2D(-7, 0, 14, 7), new Rectangle2D(-7, -7, 9, 7), new Rectangle2D(-4, 7, 4, 1) };
public TwoStoryHouse(Mobile owner, int id) : base(id, owner, 1370, 10)
{
uint keyValue = CreateKeys(owner);
AddSouthDoors(-3, 6, 7, keyValue);
SetSign(2, 8, 16);
AddSouthDoor(-3, 0, 7);
AddSouthDoor(id == 0x76 ? -2 : -3, 0, 27);
}
public TwoStoryHouse(Serial serial) : base(serial)
{
}
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(2, 8, 0);
public override int DefaultPrice => 192400;
public override HouseDeed GetDeed()
{
return ItemID switch
{
0x76 => (HouseDeed)new TwoStoryWoodPlasterHouseDeed(),
0x78 => new TwoStoryStonePlasterHouseDeed(),
_ => new TwoStoryStonePlasterHouseDeed()
};
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class Tower : BaseHouse
{
public static Rectangle2D[] AreaArray =
{
new Rectangle2D(-7, -7, 16, 14), new Rectangle2D(-1, 7, 4, 2), new Rectangle2D(-11, 0, 4, 7),
new Rectangle2D(9, 0, 4, 7)
};
public Tower(Mobile owner) : base(0x7A, owner, 2119, 15)
{
uint keyValue = CreateKeys(owner);
AddSouthDoors(false, 0, 6, 6, keyValue);
SetSign(5, 8, 16);
AddSouthDoor(false, 3, -2, 6);
AddEastDoor(false, 1, 4, 26);
AddEastDoor(false, 1, 4, 46);
}
public Tower(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 433200;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[37];
public override int ConvertOffsetY => -1;
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(5, 8, 0);
public override HouseDeed GetDeed() => new TowerDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class Keep : BaseHouse //warning: ODD shape!
{
public static Rectangle2D[] AreaArray =
{
new Rectangle2D(-11, -11, 7, 8), new Rectangle2D(-11, 5, 7, 8), new Rectangle2D(6, -11, 7, 8),
new Rectangle2D(6, 5, 7, 8), new Rectangle2D(-9, -3, 5, 8), new Rectangle2D(6, -3, 5, 8),
new Rectangle2D(-4, -9, 10, 20), new Rectangle2D(-1, 11, 4, 1)
};
public Keep(Mobile owner) : base(0x7C, owner, 2625, 18)
{
uint keyValue = CreateKeys(owner);
AddSouthDoors(false, 0, 10, 6, keyValue);
SetSign(5, 12, 16);
}
public Keep(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 665200;
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(5, 13, 0);
public override HouseDeed GetDeed() => new KeepDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class Castle : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-15, -15, 31, 31), new Rectangle2D(-1, 16, 4, 1) };
public Castle(Mobile owner) : base(0x7E, owner, 4076, 28)
{
uint keyValue = CreateKeys(owner);
AddSouthDoors(false, 0, 15, 6, keyValue);
SetSign(5, 17, 16);
AddSouthDoors(false, 0, 11, 6, true);
AddSouthDoors(false, 0, 5, 6, false);
AddSouthDoors(false, -1, -11, 6, false);
}
public Castle(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 1022800;
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(5, 17, 0);
public override HouseDeed GetDeed() => new CastleDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class LargePatioHouse : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 15, 14), new Rectangle2D(-5, 7, 4, 1) };
public LargePatioHouse(Mobile owner) : base(0x8C, owner, 1100, 8)
{
uint keyValue = CreateKeys(owner);
AddSouthDoors(-4, 6, 7, keyValue);
SetSign(1, 8, 16);
AddEastDoor(1, 4, 7);
AddEastDoor(1, -4, 7);
AddSouthDoor(4, -1, 7);
}
public LargePatioHouse(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 152800;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[29];
public override int ConvertOffsetY => -1;
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(1, 8, 0);
public override HouseDeed GetDeed() => new LargePatioDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class LargeMarbleHouse : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-7, -7, 15, 14), new Rectangle2D(-6, 7, 6, 1) };
public LargeMarbleHouse(Mobile owner) : base(0x96, owner, 1370, 10)
{
uint keyValue = CreateKeys(owner);
AddSouthDoors(false, -4, 3, 4, keyValue);
SetSign(1, 8, 11);
}
public LargeMarbleHouse(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 192000;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.ThreeStoryFoundations[29];
public override int ConvertOffsetY => -1;
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(1, 8, 0);
public override HouseDeed GetDeed() => new LargeMarbleDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SmallTower : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -3, 8, 7), new Rectangle2D(2, 4, 3, 1) };
public SmallTower(Mobile owner) : base(0x98, owner, 580, 4)
{
uint keyValue = CreateKeys(owner);
AddSouthDoor(false, 3, 3, 6, keyValue);
SetSign(1, 4, 5);
}
public SmallTower(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 88500;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[6];
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(1, 4, 0);
public override HouseDeed GetDeed() => new SmallTowerDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class LogCabin : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-3, -6, 8, 13) };
public LogCabin(Mobile owner) : base(0x9A, owner, 1100, 8)
{
uint keyValue = CreateKeys(owner);
AddSouthDoor(1, 4, 8, keyValue);
SetSign(5, 8, 20);
AddSouthDoor(1, 0, 29);
}
public LogCabin(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 97800;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[12];
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(5, 8, 0);
public override HouseDeed GetDeed() => new LogCabinDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SandStonePatio : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-5, -4, 12, 8), new Rectangle2D(-2, 4, 3, 1) };
public SandStonePatio(Mobile owner) : base(0x9C, owner, 850, 6)
{
uint keyValue = CreateKeys(owner);
AddSouthDoor(-1, 3, 6, keyValue);
SetSign(4, 6, 24);
}
public SandStonePatio(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 90900;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[35];
public override int ConvertOffsetY => -1;
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(4, 6, 0);
public override HouseDeed GetDeed() => new SandstonePatioDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class TwoStoryVilla : BaseHouse
{
public static Rectangle2D[] AreaArray = { new Rectangle2D(-5, -5, 11, 11), new Rectangle2D(2, 6, 4, 1) };
public TwoStoryVilla(Mobile owner) : base(0x9E, owner, 1100, 8)
{
uint keyValue = CreateKeys(owner);
AddSouthDoors(3, 1, 5, keyValue);
SetSign(3, 8, 24);
AddEastDoor(1, 0, 25);
AddSouthDoor(-3, -1, 25);
}
public TwoStoryVilla(Serial serial) : base(serial)
{
}
public override int DefaultPrice => 136500;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[31];
public override Rectangle2D[] Area => AreaArray;
public override Point3D BaseBanLocation => new Point3D(3, 8, 0);
public override HouseDeed GetDeed() => new VillaDeed();
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SmallShop : BaseHouse
{
public static Rectangle2D[] AreaArray1 = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-1, 4, 4, 1) };
public static Rectangle2D[] AreaArray2 = { new Rectangle2D(-3, -3, 7, 7), new Rectangle2D(-2, 4, 3, 1) };
public SmallShop(Mobile owner, int id) : base(id, owner, 425, 3)
{
uint keyValue = CreateKeys(owner);
BaseDoor door = MakeDoor(false, DoorFacing.EastCW);
door.Locked = true;
door.KeyValue = keyValue;
if (door is BaseHouseDoor houseDoor)
houseDoor.Facing = DoorFacing.EastCCW;
AddDoor(door, -2, 0, id == 0xA2 ? 24 : 27);
//AddSouthDoor( false, -2, 0, 27 - (id == 0xA2 ? 3 : 0), keyValue );
SetSign(3, 4, 7 - (id == 0xA2 ? 2 : 0));
}
public SmallShop(Serial serial) : base(serial)
{
}
public override Rectangle2D[] Area => ItemID == 0x40A2 ? AreaArray1 : AreaArray2;
public override Point3D BaseBanLocation => new Point3D(3, 4, 0);
public override int DefaultPrice => 63000;
public override HousePlacementEntry ConvertEntry => HousePlacementEntry.TwoStoryFoundations[0];
public override HouseDeed GetDeed()
{
return ItemID switch
{
0xA0 => (HouseDeed)new StoneWorkshopDeed(),
0xA2 => new MarbleWorkshopDeed(),
_ => new MarbleWorkshopDeed()
};
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); //version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,290 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Network;
namespace Server.Multis
{
public class MovingCrate : Container
{
public static readonly int MaxItemsPerSubcontainer = 20;
public static readonly int Rows = 3;
public static readonly int Columns = 5;
public static readonly int HorizontalSpacing = 25;
public static readonly int VerticalSpacing = 25;
private Timer m_InternalizeTimer;
public MovingCrate(BaseHouse house) : base(0xE3D)
{
Hue = 0x8A5;
Movable = false;
House = house;
}
public MovingCrate(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1061690; // Packing Crate
public BaseHouse House{ get; set; }
public override int DefaultMaxItems => 0;
public override int DefaultMaxWeight => 0;
public override bool IsDecoContainer => false;
/*
public override void AddNameProperties( ObjectPropertyList list )
{
base.AddNameProperties( list );
if ( House != null && House.InternalizedVendors.Count > 0 )
list.Add( 1061833, House.InternalizedVendors.Count.ToString() ); // This packing crate contains ~1_COUNT~ vendors/barkeepers.
}
*/
public override void DropItem(Item dropped)
{
// 1. Try to stack the item
if (Items.Any(item => item is PackingBox && item.Items.Any(subItem => !(subItem is Container) && subItem.StackWith(null, dropped, false))))
return;
// 2. Try to drop the item into an existing container
foreach (Item item in Items)
if (item is PackingBox packingBox)
{
Container box = packingBox;
List<Item> subItems = box.Items;
if (subItems.Count < MaxItemsPerSubcontainer)
{
box.DropItem(dropped);
return;
}
}
// 3. Drop the item into a new container
Container subContainer = new PackingBox();
subContainer.DropItem(dropped);
Point3D location = GetFreeLocation();
if (location != Point3D.Zero)
{
AddItem(subContainer);
subContainer.Location = location;
}
else
{
base.DropItem(subContainer);
}
}
private Point3D GetFreeLocation()
{
bool[,] positions = new bool[Rows, Columns];
foreach (Item item in Items)
if (item is PackingBox)
{
int i = (item.Y - Bounds.Y) / VerticalSpacing;
if (i < 0)
i = 0;
else if (i >= Rows)
i = Rows - 1;
int j = (item.X - Bounds.X) / HorizontalSpacing;
if (j < 0)
j = 0;
else if (j >= Columns)
j = Columns - 1;
positions[i, j] = true;
}
for (int i = 0; i < Rows; i++)
for (int j = 0; j < Columns; j++)
if (!positions[i, j])
{
int x = Bounds.X + j * HorizontalSpacing;
int y = Bounds.Y + i * VerticalSpacing;
return new Point3D(x, y, 0);
}
return Point3D.Zero;
}
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
{
if (m.AccessLevel < AccessLevel.GameMaster)
{
m.SendLocalizedMessage(1061145); // You cannot place items into a house moving crate.
return false;
}
return base.CheckHold(m, item, message, checkItems, plusItems, plusWeight);
}
public override bool CheckLift(Mobile from, Item item, ref LRReason reject) => House?.Deleted == false && base.CheckLift(from, item, ref reject) && House.IsOwner(from);
public override bool CheckItemUse(Mobile from, Item item) => House?.Deleted == false && base.CheckItemUse(from, item) && House.IsOwner(from);
public override void OnItemRemoved(Item item)
{
base.OnItemRemoved(item);
if (TotalItems == 0)
Delete();
}
public void RestartTimer()
{
if (m_InternalizeTimer == null)
{
m_InternalizeTimer = new InternalizeTimer(this);
m_InternalizeTimer.Start();
}
else
{
m_InternalizeTimer.Stop();
m_InternalizeTimer.Start();
}
}
public void Hide()
{
if (m_InternalizeTimer != null)
{
m_InternalizeTimer.Stop();
m_InternalizeTimer = null;
}
foreach (Item item in Items.Where(item => item is PackingBox && item.Items.Count == 0))
item.Delete();
if (TotalItems == 0)
Delete();
else
Internalize();
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if (House?.MovingCrate == this)
House.MovingCrate = null;
m_InternalizeTimer?.Stop();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(1);
writer.Write(House);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
House = reader.ReadItem() as BaseHouse;
if (House != null)
{
House.MovingCrate = this;
Timer.DelayCall(TimeSpan.Zero, Hide);
}
else
{
Timer.DelayCall(TimeSpan.Zero, Delete);
}
if (version == 0)
MaxItems = -1; // reset to default
}
public class InternalizeTimer : Timer
{
private MovingCrate m_Crate;
public InternalizeTimer(MovingCrate crate) : base(TimeSpan.FromMinutes(5.0))
{
m_Crate = crate;
Priority = TimerPriority.FiveSeconds;
}
protected override void OnTick()
{
m_Crate.Hide();
}
}
}
public class PackingBox : BaseContainer
{
public PackingBox() : base(0x9A8) => Movable = false;
public PackingBox(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1061690; // Packing Crate
public override int DefaultGumpID => 0x4B;
public override int DefaultDropSound => 0x42;
public override Rectangle2D Bounds => new Rectangle2D(16, 51, 168, 73);
public override int DefaultMaxItems => 0;
public override int DefaultMaxWeight => 0;
public override void SendCantStoreMessage(Mobile to, Item item)
{
to.SendLocalizedMessage(1061145); // You cannot place items into a house moving crate.
}
public override void OnItemRemoved(Item item)
{
base.OnItemRemoved(item);
if (item.GetBounce() == null && TotalItems == 0)
Delete();
}
public override void OnItemBounceCleared(Item item)
{
base.OnItemBounceCleared(item);
if (TotalItems == 0)
Delete();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(1); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
if (version == 0)
MaxItems = -1; // reset to default
}
}
}

View file

@ -0,0 +1,366 @@
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Server.Buffers;
using Server.Multis;
namespace Server.Network
{
public static class HouseFoundationPackets
{
public static void SendBeginHouseCustomization(NetState ns, Serial house)
{
if (ns == null)
return;
SpanWriter writer = new SpanWriter(stackalloc byte[17]);
writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)17); // Dynamic Length
writer.Write((short)0x20); // House Customization
writer.Write(house);
writer.Write((byte)0x04); // Start customization
writer.Position += 2;
writer.Write(0xFFFFFFFF);
writer.Write((byte)0xFF);
ns.Send(writer.Span);
}
public static void SendEndHouseCustomization(NetState ns, Serial house)
{
if (ns == null)
return;
SpanWriter writer = new SpanWriter(stackalloc byte[17]);
writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)17); // Dynamic Length
writer.Write((short)0x20); // House Customization
writer.Write(house);
writer.Write((byte)0x05); // End customization
writer.Position += 2;
writer.Write(0xFFFFFFFF);
writer.Write((byte)0xFF);
ns.Send(writer.Span);
}
public static void SendDesignStateGeneral(NetState ns, Serial house, int revision)
{
if (ns == null)
return;
SpanWriter writer = new SpanWriter(stackalloc byte[13]);
writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)13); // Dynamic Length
writer.Write((short)0x1D); // Design
writer.Write(house);
writer.Write(revision);
ns.Send(writer.Span);
}
private const int MaxItemsPerStairBuffer = 750;
private static ConcurrentQueue<SendQueueEntry> m_SendQueue;
private static AutoResetEvent m_Sync;
static HouseFoundationPackets()
{
m_SendQueue = new ConcurrentQueue<SendQueueEntry>();
m_Sync = new AutoResetEvent(false);
Task.Run(ProcessDesignStates);
}
public static void ProcessDesignStates()
{
while (!Core.Closing)
{
m_Sync.WaitOne();
int count = m_SendQueue.Count;
while (count > 0 && m_SendQueue.TryDequeue(out SendQueueEntry sqe))
try
{
byte[] packet = sqe.m_DesignState.Packet;
if (packet == null)
{
packet = CreateDesignDetailsPacket(sqe.m_Serial, sqe.m_Revision, sqe.m_xMin, sqe.m_yMin, sqe.m_xMax,
sqe.m_yMax, sqe.m_Tiles);
sqe.m_DesignState.Packet = packet;
return;
}
sqe.m_NetState.Send(packet);
}
catch (Exception e)
{
Console.WriteLine(e);
try
{
using StreamWriter op = new StreamWriter("dsd_exceptions.txt", true);
op.WriteLine(e);
}
catch
{
// ignored
}
}
finally
{
count = m_SendQueue.Count;
}
}
}
public static byte[] CreateDesignDetailsPacket(Serial serial, int revision, int xMin, int yMin, int xMax, int yMax,
MultiTileEntry[] tiles)
{
ArrayBufferWriter<byte> bufferWriter = new ArrayBufferWriter<byte>(0x10000);
SpanWriter headWriter = new SpanWriter(stackalloc byte[18]);
headWriter.Write((byte)0xD8); // Packet ID
headWriter.Position += 2; // Dynamic Length
headWriter.Write((byte)0x03); // Compression Type
headWriter.Position++;
headWriter.Write(serial);
headWriter.Write(revision);
headWriter.Write((short)tiles.Length);
headWriter.Position += 3; // Buffer/Plane count
int bufferLength = 1; // includes plane count
int width = xMax - xMin + 1;
int height = yMax - yMin + 1;
Span<bool> planeUsed = stackalloc bool[9];
Span<byte> planeBuffers = stackalloc byte[9216];
Span<byte> stairBuffers = stackalloc byte[MaxItemsPerStairBuffer * 30];
int totalStairsUsed = 0;
for (int i = 0; i < tiles.Length; ++i)
{
MultiTileEntry mte = tiles[i];
int x = mte.m_OffsetX - xMin;
int y = mte.m_OffsetY - yMin;
int z = mte.m_OffsetZ;
bool floor = TileData.ItemTable[mte.m_ItemID & TileData.MaxItemValue].Height <= 0;
int plane, size;
switch (z)
{
case 0:
plane = 0;
break;
case 7:
plane = 1;
break;
case 27:
plane = 2;
break;
case 47:
plane = 3;
break;
case 67:
plane = 4;
break;
default:
{
int stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
Span<byte> stairBuffer = stairBuffers.Slice(stairBufferIndex, MaxItemsPerStairBuffer);
int byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
stairBuffer[byteIndex++] = (byte)(mte.m_ItemID >> 8);
stairBuffer[byteIndex++] = (byte)mte.m_ItemID;
stairBuffer[byteIndex++] = (byte)mte.m_OffsetX;
stairBuffer[byteIndex++] = (byte)mte.m_OffsetY;
stairBuffer[byteIndex] = (byte)mte.m_OffsetZ;
++totalStairsUsed;
continue;
}
}
if (plane == 0)
size = height;
else if (floor)
{
size = height - 2;
x -= 1;
y -= 1;
}
else
{
size = height - 1;
plane += 4;
}
int index = (x * size + y) * 2;
if (x < 0 || y < 0 || y >= size || index + 1 >= 0x400)
{
int stairBufferIndex = totalStairsUsed / MaxItemsPerStairBuffer;
Span<byte> stairBuffer = stairBuffers.Slice(stairBufferIndex, MaxItemsPerStairBuffer);
int byteIndex = totalStairsUsed % MaxItemsPerStairBuffer * 5;
stairBuffer[byteIndex++] = (byte)(mte.m_ItemID >> 8);
stairBuffer[byteIndex++] = (byte)mte.m_ItemID;
stairBuffer[byteIndex++] = (byte)mte.m_OffsetX;
stairBuffer[byteIndex++] = (byte)mte.m_OffsetY;
stairBuffer[byteIndex] = (byte)mte.m_OffsetZ;
++totalStairsUsed;
}
else
{
planeUsed[plane] = true;
planeBuffers[plane * 0x400 + index] = (byte)(mte.m_ItemID >> 8);
planeBuffers[plane * 0x400 + index + 1] = (byte)mte.m_ItemID;
}
}
int planeCount = 0;
int bound = (int)Compression.Compressor.CompressBound(0x400);
for (int i = 0; i < 9; ++i)
{
if (!planeUsed[i])
continue;
++planeCount;
int size;
if (i == 0)
size = width * height * 2;
else if (i < 5)
size = (width - 1) * (height - 2) * 2;
else
size = width * (height - 1) * 2;
Span<byte> inflatedBuffer = planeBuffers.Slice(i * 0x400, 0x400);
Span<byte> deflatedBuffer = bufferWriter.GetSpan(bound + 4);
ulong deflatedLength = (ulong)bound;
ZLibError ce = Compression.Pack(deflatedBuffer.Slice(4), ref deflatedLength, inflatedBuffer, (ulong)size, ZLibQuality.Default);
if (ce != ZLibError.Okay)
{
Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce);
size = 0;
}
int length = (int)deflatedLength;
deflatedBuffer[0] = (byte)(0x20 | i);
deflatedBuffer[1] = (byte)size;
deflatedBuffer[2] = (byte)length;
deflatedBuffer[3] = (byte)(((size >> 4) & 0xF0) | ((length >> 8) & 0xF));
bufferLength += 4 + length;
bufferWriter.Advance(length + 4);
}
int totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer;
bound = (int)Compression.Compressor.CompressBound(MaxItemsPerStairBuffer);
for (int i = 0; i < totalStairBuffersUsed; ++i)
{
++planeCount;
int count = totalStairsUsed - i * MaxItemsPerStairBuffer;
if (count > MaxItemsPerStairBuffer)
count = MaxItemsPerStairBuffer;
int size = count * 5;
Span<byte> inflatedBuffer = stairBuffers.Slice(i * MaxItemsPerStairBuffer, MaxItemsPerStairBuffer);
Span<byte> deflatedBuffer = bufferWriter.GetSpan(bound + 4);
ulong deflatedLength = (ulong)bound;
ZLibError ce = Compression.Pack(deflatedBuffer.Slice(4), ref deflatedLength, inflatedBuffer, (ulong)size, ZLibQuality.Default);
if (ce != ZLibError.Okay)
{
Console.WriteLine("ZLib error: {0} (#{1})", ce, (int)ce);
deflatedLength = 0;
size = 0;
}
int length = (int)deflatedLength;
deflatedBuffer[0] = (byte)(9 + i);
deflatedBuffer[1] = (byte)size;
deflatedBuffer[2] = (byte)length;
deflatedBuffer[3] = (byte)(((size >> 4) & 0xF0) | ((length >> 8) & 0xF));
bufferLength += 4 + length;
bufferWriter.Advance(length + 4);
}
headWriter.Position = 15;
headWriter.Write((short)bufferLength); // Buffer length
headWriter.Write((byte)planeCount); // Plane count
headWriter.Position = 1;
int written = headWriter.WrittenCount + bufferWriter.WrittenCount;
headWriter.Write((ushort)written);
byte[] packet = new byte[written];
headWriter.CopyTo(packet);
bufferWriter.WrittenSpan.CopyTo(packet.AsSpan(headWriter.WrittenCount));
return packet;
}
private class SendQueueEntry
{
public NetState m_NetState;
public DesignState m_DesignState;
public int m_Revision;
public uint m_Serial;
public MultiTileEntry[] m_Tiles;
public int m_xMin, m_yMin, m_xMax, m_yMax;
public SendQueueEntry(NetState ns, HouseFoundation foundation, DesignState state)
{
m_NetState = ns;
m_Serial = foundation.Serial;
m_Revision = state.Revision;
m_DesignState = state;
MultiComponentList mcl = state.Components;
m_xMin = mcl.Min.X;
m_yMin = mcl.Min.Y;
m_xMax = mcl.Max.X;
m_yMax = mcl.Max.Y;
m_Tiles = mcl.List;
}
}
public static void SendDesignDetails(NetState ns, HouseFoundation house, DesignState state)
{
m_SendQueue.Enqueue(new SendQueueEntry(ns, house, state));
m_Sync.Set();
}
}
}

View file

@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using Server.Items;
namespace Server.Multis
{
public class PreviewHouse : BaseMulti
{
private List<Item> m_Components;
private Timer m_Timer;
public PreviewHouse(int multiID) : base(multiID)
{
m_Components = new List<Item>();
MultiComponentList mcl = Components;
for (int i = 1; i < mcl.List.Length; ++i)
{
MultiTileEntry entry = mcl.List[i];
if (entry.m_Flags == 0)
{
Item item = new Static((int)entry.m_ItemID);
item.MoveToWorld(new Point3D(X + entry.m_OffsetX, Y + entry.m_OffsetY, Z + entry.m_OffsetZ), Map);
m_Components.Add(item);
}
}
m_Timer = new DecayTimer(this);
m_Timer.Start();
}
public PreviewHouse(Serial serial) : base(serial)
{
}
public override void OnLocationChange(Point3D oldLocation)
{
base.OnLocationChange(oldLocation);
if (m_Components == null)
return;
int xOffset = X - oldLocation.X;
int yOffset = Y - oldLocation.Y;
int zOffset = Z - oldLocation.Z;
for (int i = 0; i < m_Components.Count; ++i)
{
Item item = m_Components[i];
item.MoveToWorld(new Point3D(item.X + xOffset, item.Y + yOffset, item.Z + zOffset), Map);
}
}
public override void OnMapChange()
{
base.OnMapChange();
if (m_Components == null)
return;
for (int i = 0; i < m_Components.Count; ++i)
{
Item item = m_Components[i];
item.Map = Map;
}
}
public override void OnDelete()
{
base.OnDelete();
if (m_Components == null)
return;
for (int i = 0; i < m_Components.Count; ++i)
{
Item item = m_Components[i];
item.Delete();
}
}
public override void OnAfterDelete()
{
m_Timer?.Stop();
m_Timer = null;
base.OnAfterDelete();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_Components);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
m_Components = reader.ReadStrongItemList();
break;
}
}
Timer.DelayCall(TimeSpan.Zero, Delete);
}
private class DecayTimer : Timer
{
private Item m_Item;
public DecayTimer(Item item) : base(TimeSpan.FromSeconds(20.0))
{
m_Item = item;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
m_Item.Delete();
}
}
}
}