diff --git a/Distribution/Data/Decoration/Overworld/Moongates.cfg b/Distribution/Data/Decoration/Overworld/Moongates.cfg
new file mode 100644
index 000000000..516ceedd9
--- /dev/null
+++ b/Distribution/Data/Decoration/Overworld/Moongates.cfg
@@ -0,0 +1,31 @@
+# Bastion
+CustomMoonGate 0xF6C
+1920 2111 0
+
+# Rivermouth
+CustomMoonGate 0xF6C
+1075 1793 2
+
+# Myrish
+CustomMoonGate 0xF6C
+1338 2791 2
+
+# Peninsula
+CustomMoonGate 0xF6C
+2037 1398 0
+
+#Trails
+CustomMoonGate 0xF6C
+3169 2871 0
+
+# Coldbarrow
+CustomMoonGate 0xF6C
+3285 2331 0
+
+# Draco
+CustomMoonGate 0xF6C
+3495 3491 2
+
+# Piece Island
+CustomMoonGate 0xF6C
+754 3458 0
diff --git a/Projects/UOContent/Gumps/MoongateGump.cs b/Projects/UOContent/Gumps/MoongateGump.cs
new file mode 100644
index 000000000..d2651a7ce
--- /dev/null
+++ b/Projects/UOContent/Gumps/MoongateGump.cs
@@ -0,0 +1,101 @@
+using System;
+using Server;
+using Server.Gumps;
+using Server.Network;
+
+namespace Server.Gumps;
+
+public class CustomMoongateGump : Gump
+{
+ // ======================================================================
+ // FILL IN YOUR DESTINATIONS HERE
+ // Map placeholders are set to Trammel. Update them to Trammel, Ilshenar, etc. as needed.
+ // ======================================================================
+ private static readonly Destination[] _destinations =
+ {
+ new("Bastion Moongate", new Point3D(1920, 2111, 0), Map.Trammel),
+ new("Rivermouth Moongate", new Point3D(1075, 1793, 2), Map.Trammel),
+ new("Myrish Moongate", new Point3D(1338, 2791, 2), Map.Trammel),
+ new("Peninsula Moongate", new Point3D(2037, 1398, 0), Map.Trammel),
+ new("Trails Moongate", new Point3D(3169, 2871, 0), Map.Trammel),
+ new("Coldbarrow Moongate", new Point3D(3285, 2331, 0), Map.Trammel),
+ new("Draco Island Moongate", new Point3D(3495, 3491, 2), Map.Trammel),
+ new("Piece Island Moongate", new Point3D(754, 3458, 0), Map.Trammel)
+ };
+
+ public CustomMoongateGump() : base(100, 100)
+ {
+ Closable = true;
+ Disposable = true;
+ Resizable = false;
+
+ AddPage(0);
+
+ // Background and Alpha Region for a clean, modern look
+ AddBackground(0, 0, 250, 320, 9270);
+ AddAlphaRegion(10, 10, 230, 300);
+
+ AddHtml(0, 15, 250, 20, "
Select Destination", false, false);
+
+ // Dynamically build the 8 buttons based on the array above
+ int yOffset = 50;
+ for (int i = 0; i < _destinations.Length; i++)
+ {
+ // ButtonID is offset by 1 because ButtonID 0 is always reserved for right-click/close
+ AddButton(25, yOffset, 4005, 4007, i + 1, GumpButtonType.Reply, 0);
+ AddLabel(60, yOffset, 1152, _destinations[i].Name); // 1152 is a crisp white text hue
+
+ yOffset += 30; // Spacing between buttons
+ }
+ }
+
+ public override void OnResponse(NetState sender, in RelayInfo info)
+ {
+ var mobile = sender.Mobile;
+
+ if (mobile == null || mobile.Deleted || !mobile.Alive)
+ return;
+
+ var buttonId = info.ButtonID;
+
+ // If they right-clicked to close the gump, do nothing
+ if (buttonId == 0)
+ return;
+
+ // Subtract 1 from the ButtonID to get the actual array index (0 through 7)
+ var index = buttonId - 1;
+
+ if (index >= 0 && index < _destinations.Length)
+ {
+ var dest = _destinations[index];
+
+ if (dest.Map == null || dest.Map == Map.Internal)
+ {
+ mobile.SendMessage("That destination is currently unavailable.");
+ return;
+ }
+
+ // Move the player to the selected destination
+ mobile.MoveToWorld(dest.Location, dest.Map);
+
+ // Play teleport sound and standard moongate visual effect
+ mobile.PlaySound(0x1FE);
+ Effects.SendLocationEffect(mobile.Location, mobile.Map, 0x3728, 10, 10);
+ }
+ }
+
+ // Helper class to neatly store the destination data
+ private class Destination
+ {
+ public string Name { get; }
+ public Point3D Location { get; }
+ public Map Map { get; }
+
+ public Destination(string name, Point3D loc, Map map)
+ {
+ Name = name;
+ Location = loc;
+ Map = map;
+ }
+ }
+}
diff --git a/Projects/UOContent/Items/CustomMoonGate.cs b/Projects/UOContent/Items/CustomMoonGate.cs
new file mode 100644
index 000000000..f6583657c
--- /dev/null
+++ b/Projects/UOContent/Items/CustomMoonGate.cs
@@ -0,0 +1,62 @@
+using System;
+using ModernUO.Serialization;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Items;
+
+[SerializationGenerator(0, false)]
+public partial class CustomMoongate : Item
+{
+ [Constructible]
+ public CustomMoongate() : base(0xF6C)
+ {
+ Movable = false;
+ Light = LightType.Circle300;
+ Name = "a moongate";
+ }
+
+ // Required for ModernUO Serialization
+ public CustomMoongate(Serial serial) : base(serial)
+ {
+ }
+
+ // Triggers when a player walks onto the gate
+ public override bool OnMoveOver(Mobile m)
+ {
+ if (m.Player && m.Alive)
+ {
+ SendGateGump(m);
+ }
+ return true; // Return true to allow the player to step onto the tile
+ }
+
+ // Triggers when a player double-clicks the gate
+ public override void OnDoubleClick(Mobile from)
+ {
+ if (!from.Player || !from.Alive)
+ {
+ return;
+ }
+
+ if (from.InRange(GetWorldLocation(), 2))
+ {
+ SendGateGump(from);
+ }
+ else
+ {
+ from.SendLocalizedMessage(500446); // That is too far away.
+ }
+ }
+
+ private void SendGateGump(Mobile m)
+ {
+ if (m is PlayerMobile pm)
+ {
+ // Close any existing moongate gumps before opening a new one
+ pm.CloseGump();
+ pm.SendGump(new CustomMoongateGump());
+ }
+ }
+}