diff --git a/Projects/Scripts/Gumps/ViewHousesGump.cs b/Projects/Scripts/Gumps/ViewHousesGump.cs index e44842f95..05c45a688 100644 --- a/Projects/Scripts/Gumps/ViewHousesGump.cs +++ b/Projects/Scripts/Gumps/ViewHousesGump.cs @@ -270,7 +270,7 @@ namespace Server.Gumps { public static readonly IComparer Instance = new HouseComparer(); - public int Compare(BaseHouse x, BaseHouse y) => x.BuiltOn.CompareTo(y.BuiltOn); + public int Compare(BaseHouse x, BaseHouse y) => x?.BuiltOn.CompareTo(y?.BuiltOn) ?? 0; } } } diff --git a/Projects/Scripts/Multis/BaseHouse.cs b/Projects/Scripts/Multis/BaseHouse.cs index f80e95403..c75687e4c 100644 --- a/Projects/Scripts/Multis/BaseHouse.cs +++ b/Projects/Scripts/Multis/BaseHouse.cs @@ -589,17 +589,11 @@ namespace Server.Multis return fromSecures + fromVendors + fromLockdowns + fromMovingCrate; } - public bool InRange(IPoint2D from, int range) + public override bool InRange(IPoint2D from, int range) { - if (Region == null) - return false; - - foreach (Rectangle3D rect in Region.Area) - if (from.X >= rect.Start.X - range && from.Y >= rect.Start.Y - range && from.X < rect.End.X + range && - from.Y < rect.End.Y + range) - return true; - - return false; + return Region?.Area.Any(rect => + from.X >= rect.Start.X - range && from.Y >= rect.Start.Y - range && from.X < rect.End.X + range && from.Y < rect.End.Y + range + ) == true; } public virtual int GetNewVendorSystemMaxVendors() @@ -651,25 +645,11 @@ namespace Server.Multis eable.Free(); } - public List AvailableVendorsFor(Mobile m) - { - List list = new List(); + public List AvailableVendorsFor(Mobile m) => + PlayerVendors.Where(vendor => vendor.CanInteractWith(m, false)).Cast().ToList(); - foreach (PlayerVendor vendor in PlayerVendors) - if (vendor.CanInteractWith(m, false)) - list.Add(vendor); - - return list; - } - - public bool AreThereAvailableVendorsFor(Mobile m) - { - foreach (PlayerVendor vendor in PlayerVendors) - if (vendor.CanInteractWith(m, false)) - return true; - - return false; - } + public bool AreThereAvailableVendorsFor(Mobile m) => + PlayerVendors.Any(vendor => vendor.CanInteractWith(m, false)); public void MoveAllToCrate() { @@ -811,25 +791,10 @@ namespace Server.Multis if (m_Trash != null && m_Trash.Map != Map.Internal) list.Add(m_Trash); - foreach (Item item in LockDowns) - if (item.Parent == null && item.Map != Map.Internal) - list.Add(item); - - foreach (Item item in VendorRentalContracts) - if (item.Parent == null && item.Map != Map.Internal) - list.Add(item); - - foreach (SecureInfo info in Secures) - { - Item item = info.Item; - - if (item.Parent == null && item.Map != Map.Internal) - list.Add(item); - } - - foreach (Item item in Addons) - if (item.Parent == null && item.Map != Map.Internal) - list.Add(item); + list.AddRange(LockDowns.Where(item => item.Parent == null && item.Map != Map.Internal)); + list.AddRange(VendorRentalContracts.Where(item => item.Parent == null && item.Map != Map.Internal)); + list.AddRange(Secures.Select(info => info.Item).Where(item => item.Parent == null && item.Map != Map.Internal)); + list.AddRange(Addons.Where(item => item.Parent == null && item.Map != Map.Internal)); foreach (PlayerVendor mobile in PlayerVendors) { @@ -839,9 +804,7 @@ namespace Server.Multis list.Add(mobile); } - foreach (Mobile mobile in PlayerBarkeepers) - if (mobile.Map != Map.Internal) - list.Add(mobile); + list.AddRange(PlayerBarkeepers.Where(mobile => mobile.Map != Map.Internal)); return list; } @@ -1409,6 +1372,216 @@ namespace Server.Multis return new[] { westDoor, eastDoor }; } + protected BaseDoor AddDoor(int itemID, int xOffset, int yOffset, int zOffset) => + AddDoor(null, itemID, xOffset, yOffset, zOffset); + + protected BaseDoor AddDoor(Mobile from, int itemID, int xOffset, int yOffset, int zOffset) + { + BaseDoor door = null; + + if (itemID >= 0x675 && itemID < 0x6F5) + { + int type = (itemID - 0x675) / 16; + DoorFacing facing = (DoorFacing)(((itemID - 0x675) / 2) % 8); + + door = type switch + { + 0 => new GenericHouseDoor(facing, 0x675, 0xEC, 0xF3), + 1 => new GenericHouseDoor(facing, 0x685, 0xEC, 0xF3), + 2 => new GenericHouseDoor(facing, 0x695, 0xEB, 0xF2), + 3 => new GenericHouseDoor(facing, 0x6A5, 0xEA, 0xF1), + 4 => new GenericHouseDoor(facing, 0x6B5, 0xEA, 0xF1), + 5 => new GenericHouseDoor(facing, 0x6C5, 0xEC, 0xF3), + 6 => new GenericHouseDoor(facing, 0x6D5, 0xEA, 0xF1), + 7 => new GenericHouseDoor(facing, 0x6E5, 0xEA, 0xF1), + _ => null + }; + } + else if (itemID >= 0x314 && itemID < 0x364) + { + int type = (itemID - 0x314) / 16; + DoorFacing facing = (DoorFacing)(((itemID - 0x314) / 2) % 8); + door = new GenericHouseDoor(facing, 0x314 + (type * 16), 0xED, 0xF4); + } + else if (itemID >= 0x824 && itemID < 0x834) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x824) / 2) % 8); + door = new GenericHouseDoor(facing, 0x824, 0xEC, 0xF3); + } + else if (itemID >= 0x839 && itemID < 0x849) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x839) / 2) % 8); + door = new GenericHouseDoor(facing, 0x839, 0xEB, 0xF2); + } + else if (itemID >= 0x84C && itemID < 0x85C) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x84C) / 2) % 8); + door = new GenericHouseDoor(facing, 0x84C, 0xEC, 0xF3); + } + else if (itemID >= 0x866 && itemID < 0x876) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x866) / 2) % 8); + door = new GenericHouseDoor(facing, 0x866, 0xEB, 0xF2); + } + else if (itemID >= 0xE8 && itemID < 0xF8) + { + DoorFacing facing = (DoorFacing)(((itemID - 0xE8) / 2) % 8); + door = new GenericHouseDoor(facing, 0xE8, 0xED, 0xF4); + } + else if (itemID >= 0x1FED && itemID < 0x1FFD) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x1FED) / 2) % 8); + door = new GenericHouseDoor(facing, 0x1FED, 0xEC, 0xF3); + } + else if (itemID >= 0x241F && itemID < 0x2421) + { + //DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); + door = new GenericHouseDoor(DoorFacing.NorthCCW, 0x2415, -1, -1); + } + else if (itemID >= 0x2423 && itemID < 0x2425) + { + //DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); + //This one and the above one are 'special' cases, ie: OSI had the ItemID pattern discombobulated for these + door = new GenericHouseDoor(DoorFacing.WestCW, 0x2423, -1, -1); + } + else if (itemID >= 0x2A05 && itemID < 0x2A1D) + { + DoorFacing facing = (DoorFacing)((((itemID - 0x2A05) / 2) % 4) + 8); + + int sound = (itemID >= 0x2A0D && itemID < 0x2a15) ? 0x539 : -1; + + door = new GenericHouseDoor(facing, 0x29F5 + (8 * ((itemID - 0x2A05) / 8)), sound, sound); + } + else if (itemID == 0x2D46) + { + door = new GenericHouseDoor(DoorFacing.NorthCW, 0x2D46, 0xEA, 0xF1, false); + } + else if (itemID == 0x2D48 || itemID == 0x2FE2) + { + door = new GenericHouseDoor(DoorFacing.SouthCCW, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x2D63 && itemID < 0x2D70) + { + int mod = (itemID - 0x2D63) / 2 % 2; + DoorFacing facing = ((mod == 0) ? DoorFacing.SouthCCW : DoorFacing.WestCCW); + + int type = (itemID - 0x2D63) / 4; + + door = new GenericHouseDoor(facing, 0x2D63 + 4 * type + mod * 2, 0xEA, 0xF1, false); + } + else if (itemID == 0x2FE4 || itemID == 0x31AE) + { + door = new GenericHouseDoor(DoorFacing.WestCCW, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x319C && itemID < 0x31AE) + { + //special case for 0x31aa <-> 0x31a8 (a9) + int mod = (itemID - 0x319C) / 2 % 2; + + var facing = itemID switch + { + 0x31AA => ((mod == 0) ? DoorFacing.NorthCW : DoorFacing.EastCW), + 0x31A8 => ((mod == 0) ? DoorFacing.NorthCW : DoorFacing.EastCW), + _ => ((mod == 0) ? DoorFacing.EastCW : DoorFacing.NorthCW) + }; + + int type = (itemID - 0x319C) / 4; + + door = new GenericHouseDoor(facing, 0x319C + 4 * type + mod * 2, 0xEA, 0xF1, false); + } + else if (itemID >= 0x367B && itemID < 0x369B) + { + int type = (itemID - 0x367B) / 16; + DoorFacing facing = (DoorFacing)(((itemID - 0x367B) / 2) % 8); + + door = type switch + { + 0 => new GenericHouseDoor(facing, 0x367B, 0xED, 0xF4), + 1 => new GenericHouseDoor(facing, 0x368B, 0xEC, 0x3E7), + _ => null + }; + } + else if (itemID >= 0x409B && itemID < 0x40A3) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x409B), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x410C && itemID < 0x4114) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x410C), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x41C2 && itemID < 0x41CA) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41C2), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x41CF && itemID < 0x41D7) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41CF), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x436E && itemID < 0x437E) + { + /* These ones had to be different... + * Offset 0 2 4 6 8 10 12 14 + * DoorFacing 2 3 2 3 6 7 6 7 + */ + int offset = itemID - 0x436E; + DoorFacing facing = (DoorFacing)((offset / 2 + 2 * ((1 + offset / 4) % 2)) % 8); + door = new GenericHouseDoor(facing, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x46DD && itemID < 0x46E5) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x46DD), itemID, 0xEB, 0xF2, false); + } + else if (itemID >= 0x4D22 && itemID < 0x4D2A) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x4D22), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x50C8 && itemID < 0x50D0) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50C8), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x50D0 && itemID < 0x50D8) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50D0), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x5142 && itemID < 0x514A) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x5142), itemID, 0xF0, 0xEF, false); + } + else if (itemID >= 0x9AD7 && itemID <= 0x9AE6) + { + int type = (itemID - 0x9AD7) / 16; + DoorFacing facing = (DoorFacing)(((itemID - 0x9AD7) / 2) % 8); + door = new GenericHouseDoor(facing, 0x9AD7 + (type * 16), 0xED, 0xF4); + } + else if (itemID >= 0x9B3C && itemID <= 0x9B4B) + { + int type = (itemID - 0x9B3C) / 16; + DoorFacing facing = (DoorFacing)(((itemID - 0x9B3C) / 2) % 8); + door = new GenericHouseDoor(facing, 0x9B3C + (type * 16), 0xED, 0xF4); + } + + if (door != null) + { + if (from != null) door.KeyValue = CreateKeys(@from); + + AddDoor(door, xOffset, yOffset, zOffset); + } + else + { + Console.WriteLine("BaseHouse: Door ItemID {0} not supported.", itemID); + } + + return door; + } + + private static DoorFacing GetSADoorFacing(int offset) + { + /* Offset 0 2 4 6 + * DoorFacing 2 3 6 7 + */ + return (DoorFacing)((offset / 2 + 2 * (1 + offset / 4)) % 8); + } + public uint CreateKeys(Mobile m) { uint value = Key.RandomValue(); @@ -1581,8 +1754,8 @@ namespace Server.Multis m.SendLocalizedMessage(501736); // You must lockdown the container first! } else if (!(item is VendorRentalContract) && (IsAosRules - ? !CheckAosLockdowns(amt) || !CheckAosStorage(amt) - : LockDownCount + amt > MaxLockDowns)) + ? !CheckAosLockdowns(amt) || !CheckAosStorage(amt) + : LockDownCount + amt > MaxLockDowns)) { m.SendLocalizedMessage(1005379); //That would exceed the maximum lock down limit for this house } @@ -2950,7 +3123,7 @@ namespace Server.Multis bool xEast = false, ySouth = false; bool valid = m_House != null && Sextant.Format(m_House.Location, m_House.Map, ref xLong, ref yLat, ref xMins, - ref yMins, ref xEast, ref ySouth); + ref yMins, ref xEast, ref ySouth); string location = valid ? $"{yLat}° {yMins}'{(ySouth ? "S" : "N")}, {xLong}° {xMins}'{(xEast ? "E" : "W")}" : "unknown"; diff --git a/Projects/Scripts/Multis/ContestHouses.cs b/Projects/Scripts/Multis/ContestHouses.cs new file mode 100644 index 000000000..6362da749 --- /dev/null +++ b/Projects/Scripts/Multis/ContestHouses.cs @@ -0,0 +1,711 @@ +using System; +using System.Linq; +using System.Collections.Generic; + +using Server.Items; + +namespace Server.Multis +{ + public enum ContestHouseType + { + Keep, + Castle, + Other + } + + public class BaseContestHouse : BaseHouse + { + public ContestHouseType HouseType { get; set; } + public List Fixtures { get; private set; } + + public virtual int SignPostID => 9; + + public override Point3D BaseBanLocation => new Point3D(Components.Min.X, Components.Height - 1 - Components.Center.Y, 0); + + public override Rectangle2D[] Area + { + get + { + MultiComponentList mcl = Components; + return new[] { new Rectangle2D(mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height) }; + } + } + + public BaseContestHouse(ContestHouseType type, int multiID, Mobile owner, int MaxLockDown, int MaxSecure) + : base(multiID, owner, MaxLockDown, MaxSecure) + { + HouseType = type; + + AutoAddFixtures(); + } + + protected void SetSign(int xOffset, int yOffset, int zOffset, bool post) + { + SetSign(xOffset, yOffset, zOffset); + + var hanger = new Static(0xB9E); + hanger.MoveToWorld(new Point3D(X + xOffset, Y + yOffset, Z + zOffset), Map); + + AddFixture(hanger); + + if (post) + { + var signPost = new Static(SignPostID); + signPost.MoveToWorld(new Point3D(X + xOffset, Y + yOffset - 1, Z + zOffset), Map); + + AddFixture(signPost); + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (Fixtures == null) return; + + foreach (var item in Fixtures) + item.Delete(); + } + + public override void OnLocationChange(Point3D oldLocation) + { + base.OnLocationChange(oldLocation); + + int x = base.Location.X - oldLocation.X; + int y = base.Location.Y - oldLocation.Y; + int z = base.Location.Z - oldLocation.Z; + + if (Fixtures == null) return; + + foreach (var item in Fixtures) + item.Location = new Point3D(item.X + x, item.Y + y, item.Z + z); + } + + public override void OnMapChange() + { + base.OnMapChange(); + + if (Fixtures == null) return; + + foreach (var item in Fixtures) + item.Map = Map; + } + + public void AddTeleporters(int id, Point3D offset1, Point3D offset2) + { + var tele1 = new HouseTeleporter(id); + var tele2 = new HouseTeleporter(id); + + tele1.Target = tele2; + tele2.Target = tele1; + + tele1.MoveToWorld(new Point3D(X + offset1.X, Y + offset1.Y, offset1.Z), Map); + tele2.MoveToWorld(new Point3D(X + offset2.X, Y + offset2.Y, offset2.Z), Map); + + AddFixture(tele1); + AddFixture(tele2); + } + + public void AddFixture(Item item) + { + Fixtures ??= new List(); + + Fixtures.Add(item); + } + + public override bool IsInside(Point3D p, int height) => + base.IsInside(p, height) || Fixtures?.OfType().Any(fix => fix.Location == p) == true; + + public virtual void AutoAddFixtures() + { + var components = MultiData.GetComponents(ItemID); + + var teleporters = new Dictionary>(); + + foreach (var entry in components.List.Where(e => e.m_Flags == 0)) + // Teleporters + if (entry.m_ItemID >= 0x181D && entry.m_ItemID <= 0x1828) + { + if (teleporters.ContainsKey(entry.m_ItemID)) + teleporters[entry.m_ItemID].Add(entry); + else + teleporters[entry.m_ItemID] = new List { entry }; + } + else + { + ItemData data = TileData.ItemTable[entry.m_ItemID & TileData.MaxItemValue]; + + // door + if ((data.Flags & TileFlag.Door) != 0) + AddDoor(entry.m_ItemID, entry.m_OffsetX, entry.m_OffsetY, entry.m_OffsetZ); + else + { + Item st = new Static((int)entry.m_ItemID); + + st.MoveToWorld(new Point3D(X + entry.m_OffsetX, Y + entry.m_OffsetY, entry.m_OffsetZ), Map); + AddFixture(st); + } + } + + foreach (var door in Doors) + foreach (var check in Doors.Where(d => d != door)) + if (door.InRange(check.Location, 1)) + { + door.Link = check; + check.Link = door; + } + + foreach (var (key, value) in teleporters) + { + if (value.Count > 2) + Console.WriteLine("Warning: More than 2 teleporters detected for {0:X}!", key); + else if (value.Count <= 1) + { + Console.WriteLine("Warning: 1 or less teleporters detected for {0:X}!", key); + + continue; + } + + AddTeleporters( + key, + new Point3D(value[0].m_OffsetX, value[0].m_OffsetY, value[0].m_OffsetZ), + new Point3D(value[1].m_OffsetX, value[1].m_OffsetY, value[1].m_OffsetZ) + ); + } + + teleporters.Clear(); + } + + public BaseContestHouse(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + + writer.Write((int)HouseType); + + if (Fixtures != null) + writer.WriteItemList(Fixtures, true); + else + writer.Write(0); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + HouseType = (ContestHouseType)reader.ReadInt(); + + int count = reader.ReadInt(); + + for(int i = 0; i < count; i++) + AddFixture(reader.ReadItem()); + } + } + + public class TrinsicKeep : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-11, -11, 23, 23), new Rectangle2D(-10, 13, 6, 1), + new Rectangle2D(-2, 13, 6, 1), new Rectangle2D(6, 13, 7, 1) + }; + + public TrinsicKeep(Mobile owner) + : base(ContestHouseType.Keep, 0x147E, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public TrinsicKeep(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => AreaArray; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GothicRoseCastle : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-15, -15, 31, 31), + new Rectangle2D(-14, 16, 11, 1), + new Rectangle2D(-2, 16, 6, 1), + new Rectangle2D(5, 16, 11, 1) + }; + + public GothicRoseCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x147F, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public GothicRoseCastle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class ElsaCastle : BaseContestHouse + { + public ElsaCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x1480, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public ElsaCastle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class Spires : BaseContestHouse + { + public Spires(Mobile owner) + : base(ContestHouseType.Castle, 0x1481, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public Spires(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class CastleOfOceania : BaseContestHouse + { + public CastleOfOceania(Mobile owner) + : base(ContestHouseType.Castle, 0x1482, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public CastleOfOceania(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class FeudalCastle : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-15, -15, 31, 31), + new Rectangle2D(5, 16, 1, 1), + new Rectangle2D(7, 16, 4, 1), + new Rectangle2D(12, 16, 1, 1) + }; + + public FeudalCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x1483, owner, 3281, 28) + { + SetSign(-15, 16, 7, true); + } + + public FeudalCastle(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => AreaArray; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class RobinsNest : BaseContestHouse + { + public RobinsNest(Mobile owner) + : base(ContestHouseType.Keep, 0x1484, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public RobinsNest(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class TraditionalKeep : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-11, -11, 23, 23), + new Rectangle2D(-10, 13, 6, 1), + new Rectangle2D(-2, 13, 6, 1), + new Rectangle2D(6, 13, 7, 1), + }; + + public TraditionalKeep(Mobile owner) + : base(ContestHouseType.Keep, 0x1485, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public TraditionalKeep(Serial serial) : base(serial) + { + } + + public override Rectangle2D[] Area => AreaArray; + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class VillaCrowley : BaseContestHouse + { + public VillaCrowley(Mobile owner) + : base(ContestHouseType.Keep, 0x1486, owner, 2113, 18) + { + SetSign(-11, 13, 7, true); + } + + public VillaCrowley(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class DarkthornKeep : BaseContestHouse + { + public DarkthornKeep(Mobile owner) + : base(ContestHouseType.Keep, 0x1487, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public DarkthornKeep(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class SandalwoodKeep : BaseContestHouse + { + public override int SignPostID => 353; + + public SandalwoodKeep(Mobile owner) + : base(ContestHouseType.Keep, 0x1488, owner, 2113, 18) + { + SetSign(-11, 13, 7, true); + } + + public SandalwoodKeep(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class CasaMoga : BaseContestHouse + { + public CasaMoga(Mobile owner) + : base(ContestHouseType.Keep, 0x1489, owner, 2113, 18) + { + SetSign(-11, 13, 7, false); + } + + public CasaMoga(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class RobinsRoost : BaseContestHouse + { + public RobinsRoost(Mobile owner) + : base(ContestHouseType.Castle, 0x148A, owner, 3281, 28) + { + SetSign(-15, 16, 7, true); + } + + public RobinsRoost(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class Camelot : BaseContestHouse + { + public Camelot(Mobile owner) + : base(ContestHouseType.Castle, 0x148B, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public Camelot(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class LacrimaeInCaelo : BaseContestHouse + { + public LacrimaeInCaelo(Mobile owner) + : base(ContestHouseType.Castle, 0x148C, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public LacrimaeInCaelo(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class OkinawaSweetDreamCastle : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-15, -15, 31, 31), + new Rectangle2D(-14, 16, 6, 1), + new Rectangle2D(-7, 16, 8, 1), + new Rectangle2D(10, 16, 5, 1) + }; + + public override Rectangle2D[] Area => AreaArray; + + public OkinawaSweetDreamCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x148D, owner, 3281, 28) + { + SetSign(-15, 16, 7, true); + } + + public OkinawaSweetDreamCastle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class TheSandstoneCastle : BaseContestHouse + { + public TheSandstoneCastle(Mobile owner) + : base(ContestHouseType.Castle, 0x148E, owner, 3281, 28) + { + SetSign(-15, 16, 7, true); + } + + public TheSandstoneCastle(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GrimswindSisters : BaseContestHouse + { + public static Rectangle2D[] AreaArray = { + new Rectangle2D(-15, -15, 31, 31), + new Rectangle2D(-14, 16, 9, 1), + new Rectangle2D(-3, 16, 8, 1), + new Rectangle2D(7, 16, 9, 1) + }; + + public override Rectangle2D[] Area => AreaArray; + + public GrimswindSisters(Mobile owner) + : base(ContestHouseType.Castle, 0x148F, owner, 3281, 28) + { + SetSign(-15, 16, 7, false); + } + + public GrimswindSisters(Serial serial) : base(serial) + { + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Projects/Scripts/Multis/HousePlacementTool.cs b/Projects/Scripts/Multis/HousePlacementTool.cs index 137623b7e..6bac50918 100644 --- a/Projects/Scripts/Multis/HousePlacementTool.cs +++ b/Projects/Scripts/Multis/HousePlacementTool.cs @@ -96,7 +96,8 @@ namespace Server.Items { case 1: // Classic Houses { - m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.ClassicHouses)); + // TODO: Add flag to use ClassicHouses or EJ + m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.HousesEJ)); break; } case 2: // 2-Story Customizable Houses @@ -318,7 +319,7 @@ namespace Server.Items public Point3D Offset{ get; } - public static HousePlacementEntry[] ClassicHouses{ 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), @@ -342,8 +343,51 @@ namespace Server.Items new HousePlacementEntry(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865250, 0, 16, 0, 0x007E) }; + public static HousePlacementEntry[] HousesEJ { get; } = { + new HousePlacementEntry(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0064), + new HousePlacementEntry(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0066), + new HousePlacementEntry(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x0068), + new HousePlacementEntry(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35000, 0, 4, 0, 0x006A), + new HousePlacementEntry(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006C), + new HousePlacementEntry(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006E), + new HousePlacementEntry(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50250, -1, 4, 0, 0x00A0), + new HousePlacementEntry(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52250, 0, 4, 0, 0x00A2), + new HousePlacementEntry(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73250, 3, 4, 0, 0x0098), + new HousePlacementEntry(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113500, 3, 6, 0, 0x009E), + new HousePlacementEntry(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76250, -1, 4, 0, 0x009C), + new HousePlacementEntry(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81250, 1, 6, 0, 0x009A), + new HousePlacementEntry(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131250, -1, 7, 0, 0x0074), + new HousePlacementEntry(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162500, -3, 7, 0, 0x0076), + new HousePlacementEntry(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0078), + new HousePlacementEntry(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129000, -4, 7, 0, 0x008C), + new HousePlacementEntry(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160250, -4, 7, 0, 0x0096), + new HousePlacementEntry(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366250, 0, 7, 0, 0x007A), + new HousePlacementEntry(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 562500, 0, 11, 0, 0x007C), + new HousePlacementEntry(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865000, 0, 16, 0, 0x007E), - public static HousePlacementEntry[] TwoStoryFoundations{ get; } = + new HousePlacementEntry(typeof(TrinsicKeep), 1158748, 2625, 1312, 3019, 1509, 52, 29643750, 0, 11, 0, 0x147E), + new HousePlacementEntry(typeof(GothicRoseCastle), 1158749, 4076, 2038, 4688, 2344, 78, 44808750, 0, 16, 0, 0x147F), + new HousePlacementEntry(typeof(ElsaCastle), 1158750, 4076, 2038, 4688, 2344, 78, 45450000, 0, 16, 0, 0x1480), + new HousePlacementEntry(typeof(Spires), 1158761, 4076, 2038, 4688, 2344, 78, 47025000, 0, 16, 0, 0x1481), + new HousePlacementEntry(typeof(CastleOfOceania), 1158760, 4076, 2038, 4688, 2344, 78, 48971250, 0, 16, 0, 0x1482), + new HousePlacementEntry(typeof(FeudalCastle), 1158762, 4076, 2038, 4688, 2344, 78, 27337500, 0, 16, 0, 0x1483), + new HousePlacementEntry(typeof(RobinsNest), 1158850, 2625, 1312, 3019, 1509, 52, 25301250, 0, 11, 0, 0x1484), + new HousePlacementEntry(typeof(TraditionalKeep), 1158851, 2625, 1312, 3019, 1509, 52, 26685000, 0, 11, 0, 0x1485), + new HousePlacementEntry(typeof(VillaCrowley), 1158852, 2625, 1312, 3019, 1509, 52, 21813750, 0, 11, 0, 0x1486), + new HousePlacementEntry(typeof(DarkthornKeep), 1158853, 2625, 1312, 3019, 1509, 52, 27990000, 0, 11, 0, 0x1487), + new HousePlacementEntry(typeof(SandalwoodKeep), 1158854, 2625, 1312, 3019, 1509, 52, 23456250, 0, 11, 0, 0x1488), + new HousePlacementEntry(typeof(CasaMoga), 1158855, 2625, 1312, 3019, 1509, 52, 26313750, 0, 11, 0, 0x1489), + + new HousePlacementEntry(typeof(RobinsRoost), 1158960, 4076, 2038, 4688, 2344, 78, 43863750, 0, 16, 0, 0x148A), + new HousePlacementEntry(typeof(Camelot), 1158961, 4076, 2038, 4688, 2344, 78, 47092500, 0, 16, 0, 0x148B), + new HousePlacementEntry(typeof(LacrimaeInCaelo), 1158962, 4076, 2038, 4688, 2344, 78, 45315000, 0, 16, 0, 0x148C), + new HousePlacementEntry(typeof(OkinawaSweetDreamCastle), 1158963, 4076, 2038, 4688, 2344, 78, 40128750, 0, 16, 0, 0x148D), + new HousePlacementEntry(typeof(TheSandstoneCastle), 1158964, 4076, 2038, 4688, 2344, 78, 48690000, 0, 16, 0, 0x148E), + new HousePlacementEntry(typeof(GrimswindSisters), 1158965, 4076, 2038, 4688, 2344, 78, 42142500, 0, 16, 0, 0x148F) + }; + + + 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 @@ -442,7 +486,7 @@ namespace Server.Items }; - public static HousePlacementEntry[] ThreeStoryFoundations{ get; } = + 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 diff --git a/Projects/Server/ExpansionInfo.cs b/Projects/Server/ExpansionInfo.cs index d5770fd26..c04f891ad 100644 --- a/Projects/Server/ExpansionInfo.cs +++ b/Projects/Server/ExpansionInfo.cs @@ -34,7 +34,8 @@ namespace Server ML, SA, HS, - TOL + TOL, + EJ } [Flags] @@ -79,6 +80,7 @@ namespace Server Jungle = 0x00100000, Shadowguard = 0x00200000, TOL = 0x00400000, + EJ = 0x00800000, ExpansionNone = None, ExpansionT2A = T2A, @@ -90,7 +92,8 @@ namespace Server ExpansionML = ExpansionSE | ML | NinthAge, ExpansionSA = ExpansionML | SA | Gothic | Rustic, ExpansionHS = ExpansionSA | HS, - ExpansionTOL = ExpansionHS | TOL | Jungle | Shadowguard + ExpansionTOL = ExpansionHS | TOL | Jungle | Shadowguard, + ExpansionEJ = ExpansionTOL | EJ } [Flags] @@ -124,7 +127,8 @@ namespace Server ExpansionML = ExpansionSE | ML, ExpansionSA = ExpansionML, ExpansionHS = ExpansionSA, - ExpansionTOL = ExpansionHS + ExpansionTOL = ExpansionHS, + ExpansionEJ = ExpansionTOL } [Flags] @@ -142,13 +146,15 @@ namespace Server Jungle = 0x100000, Shadowguard = 0x200000, TOL = 0x400000, + EJ = 0x800000, HousingAOS = AOS, HousingSE = HousingAOS | SE, HousingML = HousingSE | ML | Crystal, HousingSA = HousingML | SA | Gothic | Rustic, HousingHS = HousingSA | HS, - HousingTOL = HousingHS | TOL | Jungle | Shadowguard + HousingTOL = HousingHS | TOL | Jungle | Shadowguard, + HousingEJ = HousingTOL | EJ } public class ExpansionInfo @@ -163,77 +169,96 @@ namespace Server ClientFlags.None, FeatureFlags.ExpansionNone, CharacterListFlags.ExpansionNone, - HousingFlags.None), + HousingFlags.None + ), new ExpansionInfo( 1, "The Second Age", ClientFlags.Felucca, FeatureFlags.ExpansionT2A, CharacterListFlags.ExpansionT2A, - HousingFlags.None), + HousingFlags.None + ), new ExpansionInfo( 2, "Renaissance", ClientFlags.Trammel, FeatureFlags.ExpansionUOR, CharacterListFlags.ExpansionUOR, - HousingFlags.None), + HousingFlags.None + ), new ExpansionInfo( 3, "Third Dawn", ClientFlags.Ilshenar, FeatureFlags.ExpansionUOTD, CharacterListFlags.ExpansionUOTD, - HousingFlags.None), + HousingFlags.None + ), new ExpansionInfo( 4, "Blackthorn's Revenge", ClientFlags.Ilshenar, FeatureFlags.ExpansionLBR, CharacterListFlags.ExpansionLBR, - HousingFlags.None), + HousingFlags.None + ), new ExpansionInfo( 5, "Age of Shadows", ClientFlags.Malas, FeatureFlags.ExpansionAOS, CharacterListFlags.ExpansionAOS, - HousingFlags.HousingAOS), + HousingFlags.HousingAOS + ), new ExpansionInfo( 6, "Samurai Empire", ClientFlags.Tokuno, FeatureFlags.ExpansionSE, CharacterListFlags.ExpansionSE, - HousingFlags.HousingSE), + HousingFlags.HousingSE + ), new ExpansionInfo( 7, "Mondain's Legacy", new ClientVersion("5.0.0a"), FeatureFlags.ExpansionML, CharacterListFlags.ExpansionML, - HousingFlags.HousingML), + HousingFlags.HousingML + ), new ExpansionInfo( 8, "Stygian Abyss", ClientFlags.TerMur, FeatureFlags.ExpansionSA, CharacterListFlags.ExpansionSA, - HousingFlags.HousingSA), + HousingFlags.HousingSA + ), new ExpansionInfo( 9, "High Seas", new ClientVersion("7.0.9.0"), FeatureFlags.ExpansionHS, CharacterListFlags.ExpansionHS, - HousingFlags.HousingHS), + HousingFlags.HousingHS + ), new ExpansionInfo( 10, "Time of Legends", new ClientVersion("7.0.45.65"), FeatureFlags.ExpansionTOL, CharacterListFlags.ExpansionTOL, - HousingFlags.HousingTOL) + HousingFlags.HousingTOL + ), + new ExpansionInfo( + 11, + "Endless Journey", + new ClientVersion("7.0.61.0"), + FeatureFlags.ExpansionEJ, + CharacterListFlags.ExpansionEJ, + HousingFlags.HousingEJ + ) }; } @@ -304,6 +329,7 @@ namespace Server Expansion.SA => FeatureFlags.ExpansionSA, Expansion.HS => FeatureFlags.ExpansionHS, Expansion.TOL => FeatureFlags.ExpansionTOL, + Expansion.EJ => FeatureFlags.EJ, _ => FeatureFlags.ExpansionNone }; } @@ -321,4 +347,4 @@ namespace Server public override string ToString() => Name; } -} \ No newline at end of file +} diff --git a/Projects/Server/IEntity.cs b/Projects/Server/IEntity.cs index 7900dae1d..9e63739f9 100644 --- a/Projects/Server/IEntity.cs +++ b/Projects/Server/IEntity.cs @@ -32,6 +32,12 @@ namespace Server void Delete(); void ProcessDelta(); + + bool InRange(Point2D p, int range); + + bool InRange(Point3D p, int range); + + bool InRange(IPoint2D p, int range); } public class Entity : IEntity, IComparable @@ -75,5 +81,23 @@ namespace Server public void ProcessDelta() { } + + public bool InRange(Point2D p, int range) => + p.m_X >= Location.m_X - range + && p.m_X <= Location.m_X + range + && p.m_Y >= Location.m_Y - range + && p.m_Y <= Location.m_Y + range; + + public bool InRange(Point3D p, int range) => + p.m_X >= Location.m_X - range + && p.m_X <= Location.m_X + range + && p.m_Y >= Location.m_Y - range + && p.m_Y <= Location.m_Y + range; + + public bool InRange(IPoint2D p, int range) => + p.X >= Location.m_X - range + && p.X <= Location.m_X + range + && p.Y >= Location.m_Y - range + && p.Y <= Location.m_Y + range; } } diff --git a/Projects/Server/Item.cs b/Projects/Server/Item.cs index c153dd27b..1bf318018 100644 --- a/Projects/Server/Item.cs +++ b/Projects/Server/Item.cs @@ -3762,6 +3762,26 @@ namespace Server #endregion + #region InRange + public virtual bool InRange(Point2D p, int range) => + p.m_X >= Location.m_X - range + && p.m_X <= Location.m_X + range + && p.m_Y >= Location.m_Y - range + && p.m_Y <= Location.m_Y + range; + + public virtual bool InRange(Point3D p, int range) => + p.m_X >= Location.m_X - range + && p.m_X <= Location.m_X + range + && p.m_Y >= Location.m_Y - range + && p.m_Y <= Location.m_Y + range; + + public virtual bool InRange(IPoint2D p, int range) => + p.X >= Location.m_X - range + && p.X <= Location.m_X + range + && p.Y >= Location.m_Y - range + && p.Y <= Location.m_Y + range; + #endregion + #region OnDoubleClick[...] public virtual void OnDoubleClick(Mobile from) diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 291742a68..25a9b2d16 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -607,6 +607,8 @@ namespace Server public static bool TOL => Expansion >= Expansion.TOL; + public static bool EJ => Expansion >= Expansion.EJ; + #endregion } diff --git a/Projects/Server/Mobile.cs b/Projects/Server/Mobile.cs index 451116626..ec0a5e42a 100644 --- a/Projects/Server/Mobile.cs +++ b/Projects/Server/Mobile.cs @@ -9558,25 +9558,23 @@ namespace Server #endregion #region InRange + public virtual bool InRange(Point2D p, int range) => + p.m_X >= Location.m_X - range + && p.m_X <= Location.m_X + range + && p.m_Y >= Location.m_Y - range + && p.m_Y <= Location.m_Y + range; - public bool InRange(Point2D p, int range) => - p.m_X >= m_Location.m_X - range - && p.m_X <= m_Location.m_X + range - && p.m_Y >= m_Location.m_Y - range - && p.m_Y <= m_Location.m_Y + range; - - public bool InRange(Point3D p, int range) => - p.m_X >= m_Location.m_X - range - && p.m_X <= m_Location.m_X + range - && p.m_Y >= m_Location.m_Y - range - && p.m_Y <= m_Location.m_Y + range; - - public bool InRange(IPoint2D p, int range) => - p.X >= m_Location.m_X - range - && p.X <= m_Location.m_X + range - && p.Y >= m_Location.m_Y - range - && p.Y <= m_Location.m_Y + range; + public virtual bool InRange(Point3D p, int range) => + p.m_X >= Location.m_X - range + && p.m_X <= Location.m_X + range + && p.m_Y >= Location.m_Y - range + && p.m_Y <= Location.m_Y + range; + public virtual bool InRange(IPoint2D p, int range) => + p.X >= Location.m_X - range + && p.X <= Location.m_X + range + && p.Y >= Location.m_Y - range + && p.Y <= Location.m_Y + range; #endregion #region OnDoubleClick[..] diff --git a/Projects/Server/Serialization/AsyncWriter.cs b/Projects/Server/Serialization/AsyncWriter.cs index 6125dbf19..c8cfd2c55 100644 --- a/Projects/Server/Serialization/AsyncWriter.cs +++ b/Projects/Server/Serialization/AsyncWriter.cs @@ -1,612 +1,602 @@ -/*************************************************************************** - * Serialization.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Threading; -using Server.Guilds; - -namespace Server -{ - public sealed class AsyncWriter : IGenericWriter - { - private int BufferSize; - private BinaryWriter m_Bin; - private bool m_Closed; - private FileStream m_File; - - private long m_LastPos, m_CurPos; - - private MemoryStream m_Mem; - private Thread m_WorkerThread; - - private Queue m_WriteQueue; - private bool PrefixStrings; - - public AsyncWriter(string filename, bool prefix) - : this(filename, 1048576, prefix) //1 mb buffer - { - } - - public AsyncWriter(string filename, int buffSize, bool prefix) - { - PrefixStrings = prefix; - m_Closed = false; - m_WriteQueue = new Queue(); - BufferSize = buffSize; - - m_File = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None); - m_Mem = new MemoryStream(BufferSize + 1024); - m_Bin = new BinaryWriter(m_Mem, Utility.UTF8WithEncoding); - } - - public static int ThreadCount{ get; private set; } - - public MemoryStream MemStream - { - get => m_Mem; - set - { - if (m_Mem.Length > 0) - Enqueue(m_Mem); - - m_Mem = value; - m_Bin = new BinaryWriter(m_Mem, Utility.UTF8WithEncoding); - m_LastPos = 0; - m_CurPos = m_Mem.Length; - m_Mem.Seek(0, SeekOrigin.End); - } - } - - public long Position => m_CurPos; - - private void Enqueue(MemoryStream mem) - { - lock (m_WriteQueue) - { - m_WriteQueue.Enqueue(mem); - } - - if (m_WorkerThread.IsAlive != true) - { - m_WorkerThread = new Thread(new WorkerThread(this).Worker) { Priority = ThreadPriority.BelowNormal }; - m_WorkerThread.Start(); - } - } - - private void OnWrite() - { - long curlen = m_Mem.Length; - m_CurPos += curlen - m_LastPos; - m_LastPos = curlen; - if (curlen >= BufferSize) - { - Enqueue(m_Mem); - m_Mem = new MemoryStream(BufferSize + 1024); - m_Bin = new BinaryWriter(m_Mem, Utility.UTF8WithEncoding); - m_LastPos = 0; - } - } - - public void Close() - { - Enqueue(m_Mem); - m_Closed = true; - } - - public void Write(IPAddress value) - { - m_Bin.Write(Utility.GetLongAddressValue(value)); - OnWrite(); - } - - public void Write(string value) - { - if (PrefixStrings) - { - if (value == null) - { - m_Bin.Write((byte)0); - } - else - { - m_Bin.Write((byte)1); - m_Bin.Write(value); - } - } - else - { - m_Bin.Write(value); - } - - OnWrite(); - } - - public void WriteDeltaTime(DateTime value) - { - long ticks = value.Ticks; - long now = DateTime.UtcNow.Ticks; - - TimeSpan d; - - try - { - d = new TimeSpan(ticks - now); - } - catch - { - d = TimeSpan.MaxValue; - } - - Write(d); - } - - public void Write(DateTime value) - { - m_Bin.Write(value.Ticks); - OnWrite(); - } - - public void Write(DateTimeOffset value) - { - m_Bin.Write(value.Ticks); - m_Bin.Write(value.Offset.Ticks); - OnWrite(); - } - - public void Write(TimeSpan value) - { - m_Bin.Write(value.Ticks); - OnWrite(); - } - - public void Write(decimal value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(long value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(ulong value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void WriteEncodedInt(int value) - { - uint v = (uint)value; - - while (v >= 0x80) - { - m_Bin.Write((byte)(v | 0x80)); - v >>= 7; - } - - m_Bin.Write((byte)v); - OnWrite(); - } - - public void Write(int value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(uint value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(short value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(ushort value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(double value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(float value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(char value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(byte value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(byte[] value) - { - Write(value, value.Length); - } - - public void Write(byte[] value, int length) - { - m_Bin.Write(value, 0, length); - OnWrite(); - } - public void Write(sbyte value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(bool value) - { - m_Bin.Write(value); - OnWrite(); - } - - public void Write(Point3D value) - { - Write(value.m_X); - Write(value.m_Y); - Write(value.m_Z); - } - - public void Write(Point2D value) - { - Write(value.m_X); - Write(value.m_Y); - } - - public void Write(Rectangle2D value) - { - Write(value.Start); - Write(value.End); - } - - public void Write(Rectangle3D value) - { - Write(value.Start); - Write(value.End); - } - - public void Write(Map value) - { - if (value != null) - Write((byte)value.MapIndex); - else - Write((byte)0xFF); - } - - public void Write(Race value) - { - if (value != null) - Write((byte)value.RaceIndex); - else - Write((byte)0xFF); - } - - public void WriteEntity(IEntity value) - { - if (value?.Deleted != false) - Write(Serial.MinusOne); - else - Write(value.Serial); - } - - public void Write(Item value) - { - if (value?.Deleted != false) - Write(Serial.MinusOne); - else - Write(value.Serial); - } - - public void Write(Mobile value) - { - if (value?.Deleted != false) - Write(Serial.MinusOne); - else - Write(value.Serial); - } - - public void Write(BaseGuild value) - { - if (value == null) - Write(0); - else - Write(value.Id); - } - - public void WriteItem(T value) where T : Item - { - Write(value); - } - - public void WriteMobile(T value) where T : Mobile - { - Write(value); - } - - public void WriteGuild(T value) where T : BaseGuild - { - Write(value); - } - - public void Write(List list) - { - Write(list, false); - } - - public void Write(List list, bool tidy) - { - if (tidy) - for (int i = 0; i < list.Count;) - if (list[i].Deleted) - list.RemoveAt(i); - else - ++i; - - Write(list.Count); - - for (int i = 0; i < list.Count; ++i) - Write(list[i]); - } - - public void WriteItemList(List list) where T : Item - { - WriteItemList(list, false); - } - - public void WriteItemList(List list, bool tidy) where T : Item - { - if (tidy) - for (int i = 0; i < list.Count;) - if (list[i].Deleted) - list.RemoveAt(i); - else - ++i; - - Write(list.Count); - - for (int i = 0; i < list.Count; ++i) - Write(list[i]); - } - - public void Write(HashSet set) - { - Write(set, false); - } - - public void Write(HashSet set, bool tidy) - { - if (tidy) set.RemoveWhere(item => item.Deleted); - - Write(set.Count); - - foreach (Item item in set) Write(item); - } - - public void WriteItemSet(HashSet set) where T : Item - { - WriteItemSet(set, false); - } - - public void WriteItemSet(HashSet set, bool tidy) where T : Item - { - if (tidy) set.RemoveWhere(item => item.Deleted); - - Write(set.Count); - - foreach (T item in set) Write(item); - } - - public void Write(List list) - { - Write(list, false); - } - - public void Write(List list, bool tidy) - { - if (tidy) - for (int i = 0; i < list.Count;) - if (list[i].Deleted) - list.RemoveAt(i); - else - ++i; - - Write(list.Count); - - for (int i = 0; i < list.Count; ++i) - Write(list[i]); - } - - public void WriteMobileList(List list) where T : Mobile - { - WriteMobileList(list, false); - } - - public void WriteMobileList(List list, bool tidy) where T : Mobile - { - if (tidy) - for (int i = 0; i < list.Count;) - if (list[i].Deleted) - list.RemoveAt(i); - else - ++i; - - Write(list.Count); - - for (int i = 0; i < list.Count; ++i) - Write(list[i]); - } - - public void Write(HashSet set) - { - Write(set, false); - } - - public void Write(HashSet set, bool tidy) - { - if (tidy) set.RemoveWhere(mobile => mobile.Deleted); - - Write(set.Count); - - foreach (Mobile mob in set) Write(mob); - } - - public void WriteMobileSet(HashSet set) where T : Mobile - { - WriteMobileSet(set, false); - } - - public void WriteMobileSet(HashSet set, bool tidy) where T : Mobile - { - if (tidy) set.RemoveWhere(mob => mob.Deleted); - - Write(set.Count); - - foreach (T mob in set) Write(mob); - } - - public void Write(List list) - { - Write(list, false); - } - - public void Write(List list, bool tidy) - { - if (tidy) - for (int i = 0; i < list.Count;) - if (list[i].Disbanded) - list.RemoveAt(i); - else - ++i; - - Write(list.Count); - - for (int i = 0; i < list.Count; ++i) - Write(list[i]); - } - - public void WriteGuildList(List list) where T : BaseGuild - { - WriteGuildList(list, false); - } - - public void WriteGuildList(List list, bool tidy) where T : BaseGuild - { - if (tidy) - for (int i = 0; i < list.Count;) - if (list[i].Disbanded) - list.RemoveAt(i); - else - ++i; - - Write(list.Count); - - for (int i = 0; i < list.Count; ++i) - Write(list[i]); - } - - public void Write(HashSet set) - { - Write(set, false); - } - - public void Write(HashSet set, bool tidy) - { - if (tidy) set.RemoveWhere(guild => guild.Disbanded); - - Write(set.Count); - - foreach (BaseGuild guild in set) Write(guild); - } - - public void WriteGuildSet(HashSet set) where T : BaseGuild - { - WriteGuildSet(set, false); - } - - public void WriteGuildSet(HashSet set, bool tidy) where T : BaseGuild - { - if (tidy) set.RemoveWhere(guild => guild.Disbanded); - - Write(set.Count); - - foreach (T guild in set) Write(guild); - } - - private class WorkerThread - { - private AsyncWriter m_Owner; - - public WorkerThread(AsyncWriter owner) => m_Owner = owner; - - public void Worker() - { - ThreadCount++; - - int lastCount; - - do - { - MemoryStream mem = null; - - lock (m_Owner.m_WriteQueue) - { - if ((lastCount = m_Owner.m_WriteQueue.Count) > 0) - mem = m_Owner.m_WriteQueue.Dequeue(); - } - - if (mem?.Length > 0) - mem.WriteTo(m_Owner.m_File); - } while (lastCount > 1); - - if (m_Owner.m_Closed) - m_Owner.m_File.Close(); - - ThreadCount--; - - if (ThreadCount <= 0) - World.NotifyDiskWriteComplete(); - } - } - } -} +/*************************************************************************** + * Serialization.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Threading; +using Server.Guilds; + +namespace Server +{ + public sealed class AsyncWriter : IGenericWriter + { + private int BufferSize; + private BinaryWriter m_Bin; + private bool m_Closed; + private FileStream m_File; + + private long m_LastPos, m_CurPos; + + private MemoryStream m_Mem; + private Thread m_WorkerThread; + + private Queue m_WriteQueue; + private bool PrefixStrings; + + public AsyncWriter(string filename, bool prefix) + : this(filename, 1048576, prefix) //1 mb buffer + { + } + + public AsyncWriter(string filename, int buffSize, bool prefix) + { + PrefixStrings = prefix; + m_Closed = false; + m_WriteQueue = new Queue(); + BufferSize = buffSize; + + m_File = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None); + m_Mem = new MemoryStream(BufferSize + 1024); + m_Bin = new BinaryWriter(m_Mem, Utility.UTF8WithEncoding); + } + + public static int ThreadCount{ get; private set; } + + public MemoryStream MemStream + { + get => m_Mem; + set + { + if (m_Mem.Length > 0) + Enqueue(m_Mem); + + m_Mem = value; + m_Bin = new BinaryWriter(m_Mem, Utility.UTF8WithEncoding); + m_LastPos = 0; + m_CurPos = m_Mem.Length; + m_Mem.Seek(0, SeekOrigin.End); + } + } + + public long Position => m_CurPos; + + private void Enqueue(MemoryStream mem) + { + lock (m_WriteQueue) + { + m_WriteQueue.Enqueue(mem); + } + + if (m_WorkerThread.IsAlive != true) + { + m_WorkerThread = new Thread(new WorkerThread(this).Worker) { Priority = ThreadPriority.BelowNormal }; + m_WorkerThread.Start(); + } + } + + private void OnWrite() + { + long curlen = m_Mem.Length; + m_CurPos += curlen - m_LastPos; + m_LastPos = curlen; + if (curlen >= BufferSize) + { + Enqueue(m_Mem); + m_Mem = new MemoryStream(BufferSize + 1024); + m_Bin = new BinaryWriter(m_Mem, Utility.UTF8WithEncoding); + m_LastPos = 0; + } + } + + public void Close() + { + Enqueue(m_Mem); + m_Closed = true; + } + + public void Write(IPAddress value) + { + m_Bin.Write(Utility.GetLongAddressValue(value)); + OnWrite(); + } + + public void Write(string value) + { + if (PrefixStrings) + { + if (value == null) + { + m_Bin.Write((byte)0); + } + else + { + m_Bin.Write((byte)1); + m_Bin.Write(value); + } + } + else + { + m_Bin.Write(value); + } + + OnWrite(); + } + + public void WriteDeltaTime(DateTime value) + { + long ticks = value.Ticks; + long now = DateTime.UtcNow.Ticks; + + TimeSpan d; + + try + { + d = new TimeSpan(ticks - now); + } + catch + { + d = TimeSpan.MaxValue; + } + + Write(d); + } + + public void Write(DateTime value) + { + m_Bin.Write(value.Ticks); + OnWrite(); + } + + public void Write(DateTimeOffset value) + { + m_Bin.Write(value.Ticks); + m_Bin.Write(value.Offset.Ticks); + OnWrite(); + } + + public void Write(TimeSpan value) + { + m_Bin.Write(value.Ticks); + OnWrite(); + } + + public void Write(decimal value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(long value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(ulong value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void WriteEncodedInt(int value) + { + uint v = (uint)value; + + while (v >= 0x80) + { + m_Bin.Write((byte)(v | 0x80)); + v >>= 7; + } + + m_Bin.Write((byte)v); + OnWrite(); + } + + public void Write(int value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(uint value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(short value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(ushort value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(double value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(float value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(char value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(byte value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(byte[] value) + { + Write(value, value.Length); + } + + public void Write(byte[] value, int length) + { + m_Bin.Write(value, 0, length); + OnWrite(); + } + public void Write(sbyte value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(bool value) + { + m_Bin.Write(value); + OnWrite(); + } + + public void Write(Point3D value) + { + Write(value.m_X); + Write(value.m_Y); + Write(value.m_Z); + } + + public void Write(Point2D value) + { + Write(value.m_X); + Write(value.m_Y); + } + + public void Write(Rectangle2D value) + { + Write(value.Start); + Write(value.End); + } + + public void Write(Rectangle3D value) + { + Write(value.Start); + Write(value.End); + } + + public void Write(Map value) + { + if (value != null) + Write((byte)value.MapIndex); + else + Write((byte)0xFF); + } + + public void Write(Race value) + { + if (value != null) + Write((byte)value.RaceIndex); + else + Write((byte)0xFF); + } + + public void WriteEntity(IEntity value) + { + if (value?.Deleted != false) + Write(Serial.MinusOne); + else + Write(value.Serial); + } + + public void Write(Item value) + { + if (value?.Deleted != false) + Write(Serial.MinusOne); + else + Write(value.Serial); + } + + public void Write(Mobile value) + { + if (value?.Deleted != false) + Write(Serial.MinusOne); + else + Write(value.Serial); + } + + public void Write(BaseGuild value) + { + if (value == null) + Write(0); + else + Write(value.Id); + } + + public void WriteItem(T value) where T : Item + { + Write(value); + } + + public void WriteMobile(T value) where T : Mobile + { + Write(value); + } + + public void WriteGuild(T value) where T : BaseGuild + { + Write(value); + } + + public void Write(List list) + { + WriteItemList(list); + } + + public void Write(List list, bool tidy) + { + WriteItemList(list, tidy); + } + + public void WriteItemList(List list) where T : Item + { + WriteItemList(list, false); + } + + public void WriteItemList(List list, bool tidy) where T : Item + { + if (tidy) + for (int i = 0; i < list.Count;) + if (list[i].Deleted) + list.RemoveAt(i); + else + ++i; + + Write(list.Count); + + for (int i = 0; i < list.Count; ++i) + Write(list[i]); + } + + public void Write(HashSet set) + { + Write(set, false); + } + + public void Write(HashSet set, bool tidy) + { + if (tidy) set.RemoveWhere(item => item.Deleted); + + Write(set.Count); + + foreach (Item item in set) Write(item); + } + + public void WriteItemSet(HashSet set) where T : Item + { + WriteItemSet(set, false); + } + + public void WriteItemSet(HashSet set, bool tidy) where T : Item + { + if (tidy) set.RemoveWhere(item => item.Deleted); + + Write(set.Count); + + foreach (T item in set) Write(item); + } + + public void Write(List list) + { + Write(list, false); + } + + public void Write(List list, bool tidy) + { + if (tidy) + for (int i = 0; i < list.Count;) + if (list[i].Deleted) + list.RemoveAt(i); + else + ++i; + + Write(list.Count); + + for (int i = 0; i < list.Count; ++i) + Write(list[i]); + } + + public void WriteMobileList(List list) where T : Mobile + { + WriteMobileList(list, false); + } + + public void WriteMobileList(List list, bool tidy) where T : Mobile + { + if (tidy) + for (int i = 0; i < list.Count;) + if (list[i].Deleted) + list.RemoveAt(i); + else + ++i; + + Write(list.Count); + + for (int i = 0; i < list.Count; ++i) + Write(list[i]); + } + + public void Write(HashSet set) + { + Write(set, false); + } + + public void Write(HashSet set, bool tidy) + { + if (tidy) set.RemoveWhere(mobile => mobile.Deleted); + + Write(set.Count); + + foreach (Mobile mob in set) Write(mob); + } + + public void WriteMobileSet(HashSet set) where T : Mobile + { + WriteMobileSet(set, false); + } + + public void WriteMobileSet(HashSet set, bool tidy) where T : Mobile + { + if (tidy) set.RemoveWhere(mob => mob.Deleted); + + Write(set.Count); + + foreach (T mob in set) Write(mob); + } + + public void Write(List list) + { + Write(list, false); + } + + public void Write(List list, bool tidy) + { + if (tidy) + for (int i = 0; i < list.Count;) + if (list[i].Disbanded) + list.RemoveAt(i); + else + ++i; + + Write(list.Count); + + for (int i = 0; i < list.Count; ++i) + Write(list[i]); + } + + public void WriteGuildList(List list) where T : BaseGuild + { + WriteGuildList(list, false); + } + + public void WriteGuildList(List list, bool tidy) where T : BaseGuild + { + if (tidy) + for (int i = 0; i < list.Count;) + if (list[i].Disbanded) + list.RemoveAt(i); + else + ++i; + + Write(list.Count); + + for (int i = 0; i < list.Count; ++i) + Write(list[i]); + } + + public void Write(HashSet set) + { + Write(set, false); + } + + public void Write(HashSet set, bool tidy) + { + if (tidy) set.RemoveWhere(guild => guild.Disbanded); + + Write(set.Count); + + foreach (BaseGuild guild in set) Write(guild); + } + + public void WriteGuildSet(HashSet set) where T : BaseGuild + { + WriteGuildSet(set, false); + } + + public void WriteGuildSet(HashSet set, bool tidy) where T : BaseGuild + { + if (tidy) set.RemoveWhere(guild => guild.Disbanded); + + Write(set.Count); + + foreach (T guild in set) Write(guild); + } + + private class WorkerThread + { + private AsyncWriter m_Owner; + + public WorkerThread(AsyncWriter owner) => m_Owner = owner; + + public void Worker() + { + ThreadCount++; + + int lastCount; + + do + { + MemoryStream mem = null; + + lock (m_Owner.m_WriteQueue) + { + if ((lastCount = m_Owner.m_WriteQueue.Count) > 0) + mem = m_Owner.m_WriteQueue.Dequeue(); + } + + if (mem?.Length > 0) + mem.WriteTo(m_Owner.m_File); + } while (lastCount > 1); + + if (m_Owner.m_Closed) + m_Owner.m_File.Close(); + + ThreadCount--; + + if (ThreadCount <= 0) + World.NotifyDiskWriteComplete(); + } + } + } +} diff --git a/Projects/Server/Serialization/BinaryFileWriter.cs b/Projects/Server/Serialization/BinaryFileWriter.cs index 33e18a801..9cb205354 100644 --- a/Projects/Server/Serialization/BinaryFileWriter.cs +++ b/Projects/Server/Serialization/BinaryFileWriter.cs @@ -475,22 +475,12 @@ namespace Server public void Write(List list) { - Write(list, false); + WriteItemList(list); } public void Write(List list, bool tidy) { - if (tidy) - for (int i = 0; i < list.Count;) - if (list[i].Deleted) - list.RemoveAt(i); - else - ++i; - - Write(list.Count); - - for (int i = 0; i < list.Count; ++i) - Write(list[i]); + WriteItemList(list, tidy); } public void WriteItemList(List list) where T : Item @@ -502,7 +492,7 @@ namespace Server { if (tidy) for (int i = 0; i < list.Count;) - if (list[i].Deleted) + if (list[i]?.Deleted != false) list.RemoveAt(i); else ++i; diff --git a/Projects/Server/Serialization/BufferWriter.cs b/Projects/Server/Serialization/BufferWriter.cs index 82a3a4972..0462a21a9 100644 --- a/Projects/Server/Serialization/BufferWriter.cs +++ b/Projects/Server/Serialization/BufferWriter.cs @@ -440,22 +440,12 @@ namespace Server public void Write(List list) { - Write(list, false); + WriteItemList(list); } public void Write(List list, bool tidy) { - if (tidy) - for (int i = 0; i < list.Count;) - if (list[i].Deleted) - list.RemoveAt(i); - else - ++i; - - Write(list.Count); - - for (int i = 0; i < list.Count; ++i) - Write(list[i]); + WriteItemList(list, tidy); } public void WriteItemList(List list) where T : Item