522 lines
16 KiB
C#
522 lines
16 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using ModernUO.Serialization;
|
|
using Server.Collections;
|
|
using Server.Factions;
|
|
using Server.Gumps;
|
|
using Server.Maps;
|
|
using Server.Mobiles;
|
|
using Server.Network;
|
|
using Server.Spells;
|
|
|
|
namespace Server.Items;
|
|
|
|
[SerializationGenerator(0, false)]
|
|
public partial class PublicMoongate : Item
|
|
{
|
|
[Constructible]
|
|
public PublicMoongate() : base(0xF6C)
|
|
{
|
|
Movable = false;
|
|
Light = LightType.Circle300;
|
|
}
|
|
|
|
public override bool ForceShowProperties => ObjectPropertyList.Enabled;
|
|
|
|
public override bool HandlesOnMovement => true;
|
|
|
|
public override void OnDoubleClick(Mobile from)
|
|
{
|
|
if (!from.Player)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (from.InRange(GetWorldLocation(), 1))
|
|
{
|
|
UseGate(from);
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(500446); // That is too far away.
|
|
}
|
|
}
|
|
|
|
public override bool OnMoveOver(Mobile m)
|
|
{
|
|
// Changed so criminals are not blocked by it.
|
|
if (m.Player)
|
|
{
|
|
UseGate(m);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void OnMovement(Mobile m, Point3D oldLocation)
|
|
{
|
|
if (m is PlayerMobile)
|
|
{
|
|
if (!Utility.InRange(m.Location, Location, 1) && Utility.InRange(oldLocation, Location, 1))
|
|
{
|
|
m.CloseGump<MoongateGump>();
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool UseGate(Mobile m)
|
|
{
|
|
if (m.Criminal)
|
|
{
|
|
m.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily.
|
|
return false;
|
|
}
|
|
|
|
if (SpellHelper.CheckCombat(m))
|
|
{
|
|
m.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle??
|
|
return false;
|
|
}
|
|
|
|
if (m.Spell != null)
|
|
{
|
|
m.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
|
|
return false;
|
|
}
|
|
|
|
MoongateGump.DisplayTo(m, this);
|
|
|
|
if (!m.Hidden || m.AccessLevel == AccessLevel.Player)
|
|
{
|
|
Effects.PlaySound(m.Location, m.Map, 0x20E);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static void Configure()
|
|
{
|
|
CommandSystem.Register("MoonGen", AccessLevel.Developer, MoonGen_OnCommand);
|
|
}
|
|
|
|
[Usage("MoonGen"), Description("Generates public moongates. Removes all old moongates.")]
|
|
public static void MoonGen_OnCommand(CommandEventArgs e)
|
|
{
|
|
DeleteAll();
|
|
|
|
var count = 0;
|
|
|
|
count += MoonGen(PMList.Trammel, MapSelectionFlags.Trammel);
|
|
count += MoonGen(PMList.Veridia, MapSelectionFlags.Veridia);
|
|
count += MoonGen(PMList.Ilshenar, MapSelectionFlags.Ilshenar);
|
|
count += MoonGen(PMList.Malas, MapSelectionFlags.Malas);
|
|
count += MoonGen(PMList.Tokuno, MapSelectionFlags.Tokuno);
|
|
|
|
World.Broadcast(0x35, true, $"{count} moongates generated.");
|
|
}
|
|
|
|
private static void DeleteAll()
|
|
{
|
|
var list = new List<Item>();
|
|
|
|
foreach (var item in World.Items.Values)
|
|
{
|
|
if (item is PublicMoongate)
|
|
{
|
|
list.Add(item);
|
|
}
|
|
}
|
|
|
|
foreach (var item in list)
|
|
{
|
|
item.Delete();
|
|
}
|
|
|
|
if (list.Count > 0)
|
|
{
|
|
World.Broadcast(0x35, true, $"{list.Count} moongates removed.");
|
|
}
|
|
}
|
|
|
|
private static int MoonGen(PMList list, MapSelectionFlags flag)
|
|
{
|
|
if (!ExpansionInfo.CoreExpansion.MapSelectionFlags.Includes(flag))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
foreach (var entry in list.Entries)
|
|
{
|
|
var item = new PublicMoongate();
|
|
|
|
item.MoveToWorld(entry.Location, list.Map);
|
|
|
|
if (entry.Number == 1060642) // Umbra
|
|
{
|
|
item.Hue = 0x497;
|
|
}
|
|
}
|
|
|
|
return list.Entries.Length;
|
|
}
|
|
}
|
|
|
|
public class PMEntry
|
|
{
|
|
public PMEntry(Point3D loc, int number)
|
|
{
|
|
Location = loc;
|
|
Number = number;
|
|
}
|
|
|
|
public Point3D Location { get; }
|
|
|
|
public int Number { get; }
|
|
}
|
|
|
|
public class PMList
|
|
{
|
|
public static readonly PMList Trammel =
|
|
new(
|
|
1012000,
|
|
1012012,
|
|
Map.Trammel,
|
|
[
|
|
new PMEntry(new Point3D(4467, 1283, 5), 1012003), // Moonglow
|
|
new PMEntry(new Point3D(1336, 1997, 5), 1012004), // Britain
|
|
new PMEntry(new Point3D(1499, 3771, 5), 1012005), // Jhelom
|
|
new PMEntry(new Point3D(771, 752, 5), 1012006), // Yew
|
|
new PMEntry(new Point3D(2701, 692, 5), 1012007), // Minoc
|
|
new PMEntry(new Point3D(1828, 2948, -20), 1012008), // Trinsic
|
|
new PMEntry(new Point3D(643, 2067, 5), 1012009), // Skara Brae
|
|
/* Dynamic Z for Magincia to support both old and new maps. */
|
|
new PMEntry(new Point3D(3563, 2139, Map.Trammel.GetAverageZ(3563, 2139)), 1012010), // (New) Magincia
|
|
new PMEntry(new Point3D(3450, 2677, 25), 1078098) // New Haven
|
|
]
|
|
);
|
|
|
|
public static readonly PMList Veridia =
|
|
new(
|
|
1012001,
|
|
1012013,
|
|
Map.Veridia,
|
|
[
|
|
new PMEntry(new Point3D(4467, 1283, 5), 1012003), // Moonglow
|
|
new PMEntry(new Point3D(1336, 1997, 5), 1012004), // Britain
|
|
new PMEntry(new Point3D(1499, 3771, 5), 1012005), // Jhelom
|
|
new PMEntry(new Point3D(771, 752, 5), 1012006), // Yew
|
|
new PMEntry(new Point3D(2701, 692, 5), 1012007), // Minoc
|
|
new PMEntry(new Point3D(1828, 2948, -20), 1012008), // Trinsic
|
|
new PMEntry(new Point3D(643, 2067, 5), 1012009), // Skara Brae
|
|
/* Dynamic Z for Magincia to support both old and new maps. */
|
|
new PMEntry(new Point3D(3563, 2139, Map.Veridia.GetAverageZ(3563, 2139)), 1012010), // (New) Magincia
|
|
new PMEntry(new Point3D(2711, 2234, 0), 1019001) // Buccaneer's Den
|
|
]
|
|
);
|
|
|
|
public static readonly PMList Ilshenar =
|
|
new(
|
|
1012002,
|
|
1012014,
|
|
Map.Ilshenar,
|
|
[
|
|
new PMEntry(new Point3D(1215, 467, -13), 1012015), // Compassion
|
|
new PMEntry(new Point3D(722, 1366, -60), 1012016), // Honesty
|
|
new PMEntry(new Point3D(744, 724, -28), 1012017), // Honor
|
|
new PMEntry(new Point3D(281, 1016, 0), 1012018), // Humility
|
|
new PMEntry(new Point3D(987, 1011, -32), 1012019), // Justice
|
|
new PMEntry(new Point3D(1174, 1286, -30), 1012020), // Sacrifice
|
|
new PMEntry(new Point3D(1532, 1340, -3), 1012021), // Spirituality
|
|
new PMEntry(new Point3D(528, 216, -45), 1012022), // Valor
|
|
new PMEntry(new Point3D(1721, 218, 96), 1019000) // Chaos
|
|
]
|
|
);
|
|
|
|
public static readonly PMList Malas =
|
|
new(
|
|
1060643,
|
|
1062039,
|
|
Map.Malas,
|
|
[
|
|
new PMEntry(new Point3D(1015, 527, -65), 1060641), // Luna
|
|
new PMEntry(new Point3D(1997, 1386, -85), 1060642) // Umbra
|
|
]
|
|
);
|
|
|
|
public static readonly PMList Tokuno =
|
|
new(
|
|
1063258,
|
|
1063415,
|
|
Map.Tokuno,
|
|
[
|
|
new PMEntry(new Point3D(1169, 998, 41), 1063412), // Isamu-Jima
|
|
new PMEntry(new Point3D(802, 1204, 25), 1063413), // Makoto-Jima
|
|
new PMEntry(new Point3D(270, 628, 15), 1063414) // Homare-Jima
|
|
]
|
|
);
|
|
|
|
public static readonly PMList TerMur =
|
|
new(
|
|
1113602,
|
|
1113604,
|
|
Map.TerMur,
|
|
[
|
|
new PMEntry(new Point3D(850, 3525, -38), 1113603) // Royal City
|
|
]
|
|
);
|
|
|
|
public static readonly PMList TerMurEodon =
|
|
new(
|
|
1113602,
|
|
1113604,
|
|
Map.TerMur,
|
|
[
|
|
new PMEntry(new Point3D(850, 3525, -38), 1113603), // Royal City
|
|
new PMEntry(new Point3D(719, 1863, 40), 1156262) // Valley of Eodon
|
|
]
|
|
);
|
|
|
|
public static readonly PMList[] NoTrammelLists = [Veridia];
|
|
public static readonly PMList[] T2ALists = [Trammel, Veridia];
|
|
public static readonly PMList[] T2AListsYoung = [Trammel];
|
|
public static readonly PMList[] LBRLists = [Trammel, Veridia, Ilshenar];
|
|
public static readonly PMList[] LBRListsYoung = [Trammel, Ilshenar];
|
|
public static readonly PMList[] AOSLists = [Trammel, Veridia, Ilshenar, Malas];
|
|
public static readonly PMList[] AOSListsYoung = [Trammel, Ilshenar, Malas];
|
|
public static readonly PMList[] SELists = [Trammel, Veridia, Ilshenar, Malas, Tokuno];
|
|
public static readonly PMList[] SEListsYoung = [Trammel, Ilshenar, Malas, Tokuno];
|
|
public static readonly PMList[] SALists = [Trammel, Veridia, Ilshenar, Malas, Tokuno, TerMur];
|
|
public static readonly PMList[] SAListsYoung = [Trammel, Ilshenar, Malas, Tokuno, TerMur];
|
|
public static readonly PMList[] TOLLists = [Trammel, Veridia, Ilshenar, Malas, Tokuno, TerMurEodon];
|
|
public static readonly PMList[] TOLListsYoung = [Trammel, Ilshenar, Malas, Tokuno, TerMurEodon];
|
|
public static readonly PMList[] RedLists = [Veridia];
|
|
public static readonly PMList[] SigilLists = [Veridia];
|
|
|
|
public PMList(int number, int selNumber, Map map, PMEntry[] entries)
|
|
{
|
|
Number = number;
|
|
SelNumber = selNumber;
|
|
Map = map;
|
|
Entries = entries;
|
|
}
|
|
|
|
public int Number { get; }
|
|
|
|
public int SelNumber { get; }
|
|
|
|
public Map Map { get; }
|
|
|
|
public PMEntry[] Entries { get; }
|
|
}
|
|
|
|
public class MoongateGump : DynamicGump
|
|
{
|
|
private readonly PMList[] _lists;
|
|
private readonly PMList[] _tabOrder;
|
|
private readonly Item _moongate;
|
|
|
|
public override bool Singleton => true;
|
|
|
|
private MoongateGump(Item moongate, PMList[] lists, PMList[] tabOrder) : base(100, 100)
|
|
{
|
|
_moongate = moongate;
|
|
_lists = lists;
|
|
_tabOrder = tabOrder;
|
|
}
|
|
|
|
public static void DisplayTo(Mobile mobile, Item moongate)
|
|
{
|
|
if (mobile?.NetState == null || moongate == null || moongate.Deleted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PMList[] checkLists;
|
|
|
|
if (!mobile.Player)
|
|
{
|
|
checkLists = PMList.SELists;
|
|
}
|
|
else if (Sigil.ExistsOn(mobile))
|
|
{
|
|
checkLists = PMList.SigilLists;
|
|
}
|
|
else if (mobile.Murderer)
|
|
{
|
|
checkLists = PMList.RedLists;
|
|
}
|
|
else
|
|
{
|
|
var flags = mobile.NetState?.Flags ?? ClientFlags.None;
|
|
var young = mobile is PlayerMobile { Young: true };
|
|
|
|
checkLists = Core.Expansion switch
|
|
{
|
|
>= Expansion.TOL when (flags & ClientFlags.TerMur) != 0 =>
|
|
young ? PMList.TOLListsYoung : PMList.TOLLists,
|
|
>= Expansion.SA when (flags & ClientFlags.TerMur) != 0 => young ? PMList.SAListsYoung : PMList.SALists,
|
|
>= Expansion.SE when (flags & ClientFlags.Tokuno) != 0 => young ? PMList.SEListsYoung : PMList.SELists,
|
|
>= Expansion.AOS when (flags & ClientFlags.Malas) != 0 => young ? PMList.AOSListsYoung : PMList.AOSLists,
|
|
>= Expansion.LBR when (flags & ClientFlags.Ilshenar) != 0 =>
|
|
young ? PMList.LBRListsYoung : PMList.LBRLists,
|
|
>= Expansion.T2A when (flags & ClientFlags.Trammel) != 0 =>
|
|
young ? PMList.T2AListsYoung : PMList.T2ALists,
|
|
_ => PMList.NoTrammelLists
|
|
};
|
|
}
|
|
|
|
var availableMaps = ExpansionInfo.CoreExpansion.MapSelectionFlags;
|
|
using var filteredBySelectedMaps = PooledRefList<PMList>.Create();
|
|
|
|
for (var i = 0; i < checkLists.Length; ++i)
|
|
{
|
|
var pmList = checkLists[i];
|
|
if (availableMaps.Includes(pmList.Map.ToSelectionFlag()))
|
|
{
|
|
filteredBySelectedMaps.Add(pmList);
|
|
}
|
|
}
|
|
|
|
var mapCount = filteredBySelectedMaps.Count;
|
|
if (mapCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var lists = filteredBySelectedMaps.ToArray();
|
|
var tabOrder = filteredBySelectedMaps.ToArray();
|
|
|
|
for (var i = 0; i < lists.Length; ++i)
|
|
{
|
|
if (lists[i].Map == mobile.Map)
|
|
{
|
|
(lists[i], lists[0]) = (lists[0], lists[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
mobile.SendGump(new MoongateGump(moongate, lists, tabOrder));
|
|
}
|
|
|
|
protected override void BuildLayout(ref DynamicGumpBuilder builder)
|
|
{
|
|
builder.AddPage();
|
|
|
|
builder.AddBackground(0, 0, 380, 280, 5054);
|
|
|
|
builder.AddButton(10, 210, 4005, 4007, 1);
|
|
builder.AddHtmlLocalized(45, 210, 140, 25, 1011036); // OKAY
|
|
|
|
builder.AddButton(10, 235, 4005, 4007, 0);
|
|
builder.AddHtmlLocalized(45, 235, 140, 25, 1011012); // CANCEL
|
|
|
|
builder.AddHtmlLocalized(5, 5, 200, 20, 1012011); // Pick your destination:
|
|
|
|
// Tab buttons on page 0 — rendered in original (pre-swap) order so the active map appears at its expected slot.
|
|
for (var i = 0; i < _tabOrder.Length; ++i)
|
|
{
|
|
builder.AddButton(10, 35 + i * 25, 2117, 2118, 0, GumpButtonType.Page, Array.IndexOf(_lists, _tabOrder[i]) + 1);
|
|
builder.AddHtmlLocalized(30, 35 + i * 25, 150, 20, _tabOrder[i].Number);
|
|
}
|
|
|
|
for (var i = 0; i < _lists.Length; ++i)
|
|
{
|
|
RenderPage(ref builder, i, Array.IndexOf(_tabOrder, _lists[i]));
|
|
}
|
|
}
|
|
|
|
private void RenderPage(ref DynamicGumpBuilder builder, int index, int offset)
|
|
{
|
|
var list = _lists[index];
|
|
|
|
builder.AddPage(index + 1);
|
|
|
|
builder.AddButton(10, 35 + offset * 25, 2117, 2118, 0, GumpButtonType.Page, index + 1);
|
|
builder.AddHtmlLocalized(30, 35 + offset * 25, 150, 20, list.SelNumber);
|
|
|
|
var entries = list.Entries;
|
|
|
|
for (var i = 0; i < entries.Length; ++i)
|
|
{
|
|
builder.AddRadio(200, 35 + i * 25, 210, 211, false, index * 100 + i);
|
|
builder.AddHtmlLocalized(225, 35 + i * 25, 150, 20, entries[i].Number);
|
|
}
|
|
}
|
|
|
|
public override void OnResponse(NetState state, in RelayInfo info)
|
|
{
|
|
if (info.ButtonID == 0 || _moongate.Deleted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var from = state.Mobile;
|
|
if (from.Map == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var switches = info.Switches;
|
|
|
|
if (switches.Length == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var switchID = switches[0];
|
|
var listIndex = switchID / 100;
|
|
var listEntry = switchID % 100;
|
|
|
|
if (listIndex < 0 || listIndex >= _lists.Length)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var list = _lists[listIndex];
|
|
|
|
if (listEntry < 0 || listEntry >= list.Entries.Length)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var entry = list.Entries[listEntry];
|
|
|
|
if (!from.InRange(_moongate.GetWorldLocation(), 1) || from.Map != _moongate.Map)
|
|
{
|
|
from.SendLocalizedMessage(1019002); // You are too far away to use the gate.
|
|
}
|
|
else if (from.Player && from.Murderer && list.Map != Map.Veridia ||
|
|
Sigil.ExistsOn(from) && list.Map != Faction.Facet)
|
|
{
|
|
from.SendLocalizedMessage(1019004); // You are not allowed to travel there.
|
|
}
|
|
else if (from.Criminal)
|
|
{
|
|
from.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily.
|
|
}
|
|
else if (SpellHelper.CheckCombat(from))
|
|
{
|
|
from.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle??
|
|
}
|
|
else if (from.Spell != null)
|
|
{
|
|
from.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
|
|
}
|
|
else if (from.Map == list.Map && from.InRange(entry.Location, 1))
|
|
{
|
|
from.SendLocalizedMessage(1019003); // You are already there.
|
|
}
|
|
else
|
|
{
|
|
BaseCreature.TeleportPets(from, entry.Location, list.Map);
|
|
|
|
from.Combatant = null;
|
|
from.Warmode = false;
|
|
from.Hidden = true;
|
|
|
|
from.MoveToWorld(entry.Location, list.Map);
|
|
|
|
Effects.PlaySound(entry.Location, list.Map, 0x1FE);
|
|
}
|
|
}
|
|
}
|