ModernUO/Projects/UOContent/Misc/DoorGenerator.cs

592 lines
13 KiB
C#

using System;
using Server.Items;
using Server.Logging;
using Server.Network;
namespace Server;
public static class DoorGenerator
{
private static readonly ILogger logger = LogFactory.GetLogger(typeof(DoorGenerator));
private static readonly Rectangle2D[] _britRegions =
{
new(new Point2D(250, 750), new Point2D(775, 1330)),
new(new Point2D(525, 2095), new Point2D(925, 2430)),
new(new Point2D(1025, 2155), new Point2D(1265, 2310)),
new(new Point2D(1635, 2430), new Point2D(1705, 2508)),
new(new Point2D(1775, 2605), new Point2D(2165, 2975)),
new(new Point2D(1055, 3520), new Point2D(1570, 4075)),
new(new Point2D(2860, 3310), new Point2D(3120, 3630)),
new(new Point2D(2470, 1855), new Point2D(3950, 3045)),
new(new Point2D(3425, 990), new Point2D(3900, 1455)),
new(new Point2D(4175, 735), new Point2D(4840, 1600)),
new(new Point2D(2375, 330), new Point2D(3100, 1045)),
new(new Point2D(2100, 1090), new Point2D(2310, 1450)),
new(new Point2D(1495, 1400), new Point2D(1550, 1475)),
new(new Point2D(1085, 1520), new Point2D(1415, 1910)),
new(new Point2D(1410, 1500), new Point2D(1745, 1795)),
new(new Point2D(5120, 2300), new Point2D(6143, 4095))
};
private static readonly Rectangle2D[] _ilshRegions =
{
new(new Point2D(0, 0), new Point2D(288 * 8, 200 * 8))
};
private static readonly Rectangle2D[] _malasRegions =
{
new(new Point2D(0, 0), new Point2D(320 * 8, 256 * 8))
};
private static readonly int[] _southFrames =
{
0x0006,
0x0008,
0x000B,
0x001A,
0x001B,
0x001F,
0x0038,
0x0057,
0x0059,
0x005B,
0x005D,
0x0080,
0x0081,
0x0082,
0x0084,
0x0090,
0x0091,
0x0094,
0x0096,
0x0099,
0x00A6,
0x00A7,
0x00AA,
0x00AE,
0x00B0,
0x00B3,
0x00C7,
0x00C9,
0x00F8,
0x00FA,
0x00FD,
0x00FE,
0x0100,
0x0103,
0x0104,
0x0106,
0x0109,
0x0127,
0x0129,
0x012B,
0x012D,
0x012F,
0x0131,
0x0132,
0x0134,
0x0135,
0x0137,
0x0139,
0x013B,
0x014C,
0x014E,
0x014F,
0x0151,
0x0153,
0x0155,
0x0157,
0x0158,
0x015A,
0x015D,
0x015E,
0x015F,
0x0162,
0x01CF,
0x01D1,
0x01D4,
0x01FF,
0x0204,
0x0206,
0x0208,
0x020A
};
private static readonly int[] _northFrames =
{
0x0006,
0x0008,
0x000D,
0x001A,
0x001B,
0x0020,
0x003A,
0x0057,
0x0059,
0x005B,
0x005D,
0x0080,
0x0081,
0x0082,
0x0084,
0x0090,
0x0091,
0x0094,
0x0096,
0x0099,
0x00A6,
0x00A7,
0x00AC,
0x00AE,
0x00B0,
0x00C7,
0x00C9,
0x00F8,
0x00FA,
0x00FD,
0x00FE,
0x0100,
0x0103,
0x0104,
0x0106,
0x0109,
0x0127,
0x0129,
0x012B,
0x012D,
0x012F,
0x0131,
0x0132,
0x0134,
0x0135,
0x0137,
0x0139,
0x013B,
0x014C,
0x014E,
0x014F,
0x0151,
0x0153,
0x0155,
0x0157,
0x0158,
0x015A,
0x015D,
0x015E,
0x015F,
0x0162,
0x01CF,
0x01D1,
0x01D4,
0x01FF,
0x0201,
0x0204,
0x0208,
0x020A
};
private static readonly int[] _eastFrames =
{
0x0007,
0x000A,
0x001A,
0x001C,
0x001E,
0x0037,
0x0058,
0x0059,
0x005C,
0x005E,
0x0080,
0x0081,
0x0082,
0x0084,
0x0090,
0x0092,
0x0095,
0x0097,
0x0098,
0x00A6,
0x00A8,
0x00AB,
0x00AE,
0x00AF,
0x00B2,
0x00C7,
0x00C8,
0x00EA,
0x00F8,
0x00F9,
0x00FC,
0x00FE,
0x00FF,
0x0102,
0x0104,
0x0105,
0x0108,
0x0127,
0x0128,
0x012B,
0x012C,
0x012E,
0x0130,
0x0132,
0x0133,
0x0135,
0x0136,
0x0138,
0x013A,
0x014C,
0x014D,
0x014F,
0x0150,
0x0152,
0x0154,
0x0156,
0x0158,
0x0159,
0x015C,
0x015E,
0x0160,
0x0163,
0x01CF,
0x01D0,
0x01D3,
0x01FF,
0x0203,
0x0205,
0x0207,
0x0209
};
private static readonly int[] _westFrames =
{
0x0007,
0x000C,
0x001A,
0x001C,
0x0021,
0x0039,
0x0058,
0x0059,
0x005C,
0x005E,
0x0080,
0x0081,
0x0082,
0x0084,
0x0090,
0x0092,
0x0095,
0x0097,
0x0098,
0x00A6,
0x00A8,
0x00AD,
0x00AE,
0x00AF,
0x00B5,
0x00C7,
0x00C8,
0x00EA,
0x00F8,
0x00F9,
0x00FC,
0x00FE,
0x00FF,
0x0102,
0x0104,
0x0105,
0x0108,
0x0127,
0x0128,
0x012C,
0x012E,
0x0130,
0x0132,
0x0133,
0x0135,
0x0136,
0x0138,
0x013A,
0x014C,
0x014D,
0x014F,
0x0150,
0x0152,
0x0154,
0x0156,
0x0158,
0x0159,
0x015C,
0x015E,
0x0160,
0x0163,
0x01CF,
0x01D0,
0x01D3,
0x01FF,
0x0200,
0x0203,
0x0207,
0x0209
};
private static Map m_Map;
private static int m_Count;
public static void Configure()
{
CommandSystem.Register("DoorGen", AccessLevel.Developer, DoorGen_OnCommand);
}
[Usage("DoorGen"), Description("Generates doors by analyzing the map. Slow.")]
public static void DoorGen_OnCommand(CommandEventArgs e)
{
Generate();
}
public static void Generate()
{
World.Broadcast(0x35, true, "Generating doors, please wait.");
NetState.FlushAll();
m_Map = Map.Underworld;
m_Count = 0;
for (var i = 0; i < _britRegions.Length; ++i)
{
Generate(_britRegions[i]);
}
var UnderworldCount = m_Count;
m_Map = Map.Veridia;
m_Count = 0;
for (var i = 0; i < _britRegions.Length; ++i)
{
Generate(_britRegions[i]);
}
var VeridiaCount = m_Count;
m_Map = Map.Ilshenar;
m_Count = 0;
for (var i = 0; i < _ilshRegions.Length; ++i)
{
Generate(_ilshRegions[i]);
}
var ilshenarCount = m_Count;
m_Map = Map.Malas;
m_Count = 0;
for (var i = 0; i < _malasRegions.Length; ++i)
{
Generate(_malasRegions[i]);
}
var malasCount = m_Count;
World.Broadcast(
0x35,
true,
$"Door generation complete. Underworld: {UnderworldCount}; Veridia: {VeridiaCount}; Ilshenar: {ilshenarCount}; Malas: {malasCount};"
);
}
public static bool IsFrame(int id, int[] list)
{
if (id > list[^1])
{
return false;
}
for (var i = 0; i < list.Length; ++i)
{
var delta = id - list[i];
if (delta < 0)
{
return false;
}
if (delta == 0)
{
return true;
}
}
return false;
}
public static bool IsNorthFrame(int id) => IsFrame(id, _northFrames);
public static bool IsSouthFrame(int id) => IsFrame(id, _southFrames);
public static bool IsWestFrame(int id) => IsFrame(id, _westFrames);
public static bool IsEastFrame(int id) => IsFrame(id, _eastFrames);
public static bool IsEastFrame(int x, int y, int z, out int newZ)
{
foreach (var tile in m_Map.Tiles.GetStaticTiles(x, y))
{
if (!IsEastFrame(tile.ID))
{
continue;
}
var delta = tile.Z - z;
if (delta is >= -1 and <= 1)
{
newZ = tile.Z;
return true;
}
}
newZ = -1;
return false;
}
public static bool IsSouthFrame(int x, int y, int z, out int newZ)
{
foreach (var tile in m_Map.Tiles.GetStaticTiles(x, y))
{
if (!IsSouthFrame(tile.ID))
{
continue;
}
var delta = tile.Z - z;
if (delta is >= -1 and <= 1)
{
newZ = tile.Z;
return true;
}
}
newZ = -1;
return false;
}
public static BaseDoor AddDoor(int x, int y, int z, int newZ, DoorFacing facing)
{
var minZ = Math.Min(z, newZ);
if (!m_Map.CanFit(x, y, minZ, 16, false, false))
{
return null;
}
if (y == 1743 && x is >= 1343 and <= 1344)
{
return null;
}
if (y == 1679 && x is >= 1392 and <= 1393)
{
return null;
}
if (x == 1320 && y is >= 1618 and <= 1640)
{
return null;
}
if (x == 1383 && y is >= 1642 and <= 1643)
{
return null;
}
// Ilshenar ruins
if (m_Map == Map.Ilshenar && x is >= 644 and <= 670 && y is >= 925 and <= 941 || x == 985 && y == 994)
{
return null;
}
if (z != newZ)
{
logger.Warning($"Door at {x}, {y}, {z} ({m_Map}) has mismatched Z levels: {z} != {newZ}");
}
BaseDoor door = new DarkWoodDoor(facing);
door.MoveToWorld(new Point3D(x, y, minZ), m_Map);
++m_Count;
return door;
}
public static void Generate(Rectangle2D region)
{
for (var rx = 0; rx < region.Width; ++rx)
{
for (var ry = 0; ry < region.Height; ++ry)
{
var vx = rx + region.X;
var vy = ry + region.Y;
foreach (var tile in m_Map.Tiles.GetStaticTiles(vx, vy))
{
var id = tile.ID;
var z = tile.Z;
int newZ;
if (IsWestFrame(id))
{
if (IsEastFrame(vx + 2, vy, z, out newZ))
{
AddDoor(vx + 1, vy, z, newZ, DoorFacing.WestCW);
}
else if (IsEastFrame(vx + 3, vy, z, out newZ))
{
var first = AddDoor(vx + 1, vy, z, newZ, DoorFacing.WestCW);
var second = AddDoor(vx + 2, vy, z, newZ, DoorFacing.EastCCW);
if (first != null && second != null)
{
first.Link = second;
second.Link = first;
}
else
{
first?.Delete();
second?.Delete();
}
}
}
else if (IsNorthFrame(id))
{
if (IsSouthFrame(vx, vy + 2, z, out newZ))
{
AddDoor(vx, vy + 1, z, newZ, DoorFacing.SouthCW);
}
else if (IsSouthFrame(vx, vy + 3, z, out newZ))
{
var first = AddDoor(vx, vy + 1, z, newZ, DoorFacing.NorthCCW);
var second = AddDoor(vx, vy + 2, z, newZ, DoorFacing.SouthCW);
if (first != null && second != null)
{
first.Link = second;
second.Link = first;
}
else
{
first?.Delete();
second?.Delete();
}
}
}
}
}
}
}
}