* 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
445 lines
13 KiB
C#
445 lines
13 KiB
C#
using System.Collections.Generic;
|
||
using Server.Items;
|
||
using Server.Multis;
|
||
using Server.Network;
|
||
using Server.Spells.Chivalry;
|
||
using Server.Spells.Fourth;
|
||
using Server.Spells.Seventh;
|
||
|
||
namespace Server.Gumps
|
||
{
|
||
public class RunebookGump : Gump
|
||
{
|
||
public RunebookGump(Mobile from, Runebook book) : base(150, 200)
|
||
{
|
||
Book = book;
|
||
|
||
AddBackground();
|
||
AddIndex();
|
||
|
||
for (int page = 0; page < 8; ++page)
|
||
{
|
||
AddPage(2 + page);
|
||
|
||
AddButton(125, 14, 2205, 2205, 0, GumpButtonType.Page, 1 + page);
|
||
|
||
if (page < 7)
|
||
AddButton(393, 14, 2206, 2206, 0, GumpButtonType.Page, 3 + page);
|
||
|
||
for (int half = 0; half < 2; ++half)
|
||
AddDetails(page * 2 + half, half);
|
||
}
|
||
}
|
||
|
||
public Runebook Book{ get; }
|
||
|
||
public int GetMapHue(Map map)
|
||
{
|
||
if (map == Map.Trammel)
|
||
return 10;
|
||
if (map == Map.Felucca)
|
||
return 81;
|
||
if (map == Map.Ilshenar)
|
||
return 1102;
|
||
if (map == Map.Malas)
|
||
return 1102;
|
||
if (map == Map.Tokuno)
|
||
return 1154;
|
||
|
||
return 0;
|
||
}
|
||
|
||
public string GetName(string name)
|
||
{
|
||
if (name == null || (name = name.Trim()).Length <= 0)
|
||
return "(indescript)";
|
||
|
||
return name;
|
||
}
|
||
|
||
private void AddBackground()
|
||
{
|
||
AddPage(0);
|
||
|
||
// Background image
|
||
AddImage(100, 10, 2200);
|
||
|
||
// Two separators
|
||
for (int i = 0; i < 2; ++i)
|
||
{
|
||
int xOffset = 125 + i * 165;
|
||
|
||
AddImage(xOffset, 50, 57);
|
||
xOffset += 20;
|
||
|
||
for (int j = 0; j < 6; ++j, xOffset += 15)
|
||
AddImage(xOffset, 50, 58);
|
||
|
||
AddImage(xOffset - 5, 50, 59);
|
||
}
|
||
|
||
// First four page buttons
|
||
for (int i = 0, xOffset = 130, gumpID = 2225; i < 4; ++i, xOffset += 35, ++gumpID)
|
||
AddButton(xOffset, 187, gumpID, gumpID, 0, GumpButtonType.Page, 2 + i);
|
||
|
||
// Next four page buttons
|
||
for (int i = 0, xOffset = 300, gumpID = 2229; i < 4; ++i, xOffset += 35, ++gumpID)
|
||
AddButton(xOffset, 187, gumpID, gumpID, 0, GumpButtonType.Page, 6 + i);
|
||
|
||
// Charges
|
||
AddHtmlLocalized(140, 40, 80, 18, 1011296); // Charges:
|
||
AddHtml(220, 40, 30, 18, Book.CurCharges.ToString());
|
||
|
||
// Max charges
|
||
AddHtmlLocalized(300, 40, 100, 18, 1011297); // Max Charges:
|
||
AddHtml(400, 40, 30, 18, Book.MaxCharges.ToString());
|
||
}
|
||
|
||
private void AddIndex()
|
||
{
|
||
// Index
|
||
AddPage(1);
|
||
|
||
// Rename button
|
||
AddButton(125, 15, 2472, 2473, 1);
|
||
AddHtmlLocalized(158, 22, 100, 18, 1011299); // Rename book
|
||
|
||
// List of entries
|
||
List<RunebookEntry> entries = Book.Entries;
|
||
|
||
for (int i = 0; i < 16; ++i)
|
||
{
|
||
string desc;
|
||
int hue;
|
||
|
||
if (i < entries.Count)
|
||
{
|
||
desc = GetName(entries[i].Description);
|
||
hue = GetMapHue(entries[i].Map);
|
||
}
|
||
else
|
||
{
|
||
desc = "Empty";
|
||
hue = 0;
|
||
}
|
||
|
||
// Use charge button
|
||
AddButton(130 + i / 8 * 160, 65 + i % 8 * 15, 2103, 2104, 2 + i * 6 + 0);
|
||
|
||
// Description label
|
||
AddLabelCropped(145 + i / 8 * 160, 60 + i % 8 * 15, 115, 17, hue, desc);
|
||
}
|
||
|
||
// Turn page button
|
||
AddButton(393, 14, 2206, 2206, 0, GumpButtonType.Page, 2);
|
||
}
|
||
|
||
private void AddDetails(int index, int half)
|
||
{
|
||
// Use charge button
|
||
AddButton(130 + half * 160, 65, 2103, 2104, 2 + index * 6 + 0);
|
||
|
||
string desc;
|
||
int hue;
|
||
|
||
if (index < Book.Entries.Count)
|
||
{
|
||
RunebookEntry e = Book.Entries[index];
|
||
|
||
desc = GetName(e.Description);
|
||
hue = GetMapHue(e.Map);
|
||
|
||
// Location labels
|
||
int xLong = 0, yLat = 0;
|
||
int xMins = 0, yMins = 0;
|
||
bool xEast = false, ySouth = false;
|
||
|
||
if (Sextant.Format(e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth))
|
||
{
|
||
AddLabel(135 + half * 160, 80, 0, $"{yLat}<7D> {yMins}'{(ySouth ? "S" : "N")}");
|
||
AddLabel(135 + half * 160, 95, 0, $"{xLong}<7D> {xMins}'{(xEast ? "E" : "W")}");
|
||
}
|
||
|
||
// Drop rune button
|
||
AddButton(135 + half * 160, 115, 2437, 2438, 2 + index * 6 + 1);
|
||
AddHtmlLocalized(150 + half * 160, 115, 100, 18, 1011298); // Drop rune
|
||
|
||
// Set as default button
|
||
int defButtonID = e != Book.Default ? 2361 : 2360;
|
||
|
||
AddButton(160 + half * 140, 20, defButtonID, defButtonID, 2 + index * 6 + 2);
|
||
AddHtmlLocalized(175 + half * 140, 15, 100, 18, 1011300); // Set default
|
||
|
||
if (Core.AOS)
|
||
{
|
||
AddButton(135 + half * 160, 140, 2103, 2104, 2 + index * 6 + 3);
|
||
AddHtmlLocalized(150 + half * 160, 136, 110, 20, 1062722); // Recall
|
||
|
||
AddButton(135 + half * 160, 158, 2103, 2104, 2 + index * 6 + 4);
|
||
AddHtmlLocalized(150 + half * 160, 154, 110, 20, 1062723); // Gate Travel
|
||
|
||
AddButton(135 + half * 160, 176, 2103, 2104, 2 + index * 6 + 5);
|
||
AddHtmlLocalized(150 + half * 160, 172, 110, 20, 1062724); // Sacred Journey
|
||
}
|
||
else
|
||
{
|
||
// Recall button
|
||
AddButton(135 + half * 160, 140, 2271, 2271, 2 + index * 6 + 3);
|
||
|
||
// Gate button
|
||
AddButton(205 + half * 160, 140, 2291, 2291, 2 + index * 6 + 4);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
desc = "Empty";
|
||
hue = 0;
|
||
}
|
||
|
||
// Description label
|
||
AddLabelCropped(145 + half * 160, 60, 115, 17, hue, desc);
|
||
}
|
||
|
||
public static bool HasSpell(Mobile from, int spellID) => Spellbook.Find(from, spellID)?.HasSpell(spellID) == true;
|
||
|
||
public override void OnResponse(NetState sender, RelayInfo info)
|
||
{
|
||
Mobile from = sender.Mobile;
|
||
|
||
if (Book.Deleted || !from.InRange(Book.GetWorldLocation(), Core.ML ? 3 : 1) || !DesignContext.Check(from))
|
||
{
|
||
Book.Openers.Remove(from);
|
||
return;
|
||
}
|
||
|
||
int buttonID = info.ButtonID;
|
||
|
||
if (buttonID == 1) // Rename book
|
||
{
|
||
if (!Book.IsLockedDown || from.AccessLevel >= AccessLevel.GameMaster)
|
||
{
|
||
from.SendLocalizedMessage(502414); // Please enter a title for the runebook:
|
||
from.Prompt = new InternalPrompt(Book);
|
||
}
|
||
else
|
||
{
|
||
Book.Openers.Remove(from);
|
||
|
||
from.SendLocalizedMessage(502413, null, 0x35); // That cannot be done while the book is locked down.
|
||
}
|
||
}
|
||
else
|
||
{
|
||
buttonID -= 2;
|
||
|
||
int index = buttonID / 6;
|
||
int type = buttonID % 6;
|
||
|
||
if (index >= 0 && index < Book.Entries.Count)
|
||
{
|
||
RunebookEntry e = Book.Entries[index];
|
||
|
||
switch (type)
|
||
{
|
||
case 0: // Use charges
|
||
{
|
||
if (Book.CurCharges <= 0)
|
||
{
|
||
from.CloseGump<RunebookGump>();
|
||
from.SendGump(new RunebookGump(from, Book));
|
||
|
||
from.SendLocalizedMessage(502412); // There are no charges left on that item.
|
||
}
|
||
else
|
||
{
|
||
int xLong = 0, yLat = 0;
|
||
int xMins = 0, yMins = 0;
|
||
bool xEast = false, ySouth = false;
|
||
|
||
if (Sextant.Format(e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast,
|
||
ref ySouth))
|
||
{
|
||
string location =
|
||
$"{yLat}<7D> {yMins}'{(ySouth ? "S" : "N")}, {xLong}<7D> {xMins}'{(xEast ? "E" : "W")}";
|
||
from.SendMessage(location);
|
||
}
|
||
|
||
Book.OnTravel();
|
||
new RecallSpell(from, e, Book, Book).Cast();
|
||
|
||
Book.Openers.Remove(from);
|
||
}
|
||
|
||
break;
|
||
}
|
||
case 1: // Drop rune
|
||
{
|
||
if (!Book.IsLockedDown || from.AccessLevel >= AccessLevel.GameMaster)
|
||
{
|
||
Book.DropRune(from, e, index);
|
||
|
||
from.CloseGump<RunebookGump>();
|
||
if (!Core.ML)
|
||
from.SendGump(new RunebookGump(from, Book));
|
||
}
|
||
else
|
||
{
|
||
Book.Openers.Remove(from);
|
||
|
||
from.SendLocalizedMessage(502413, null,
|
||
0x35); // That cannot be done while the book is locked down.
|
||
}
|
||
|
||
break;
|
||
}
|
||
case 2: // Set default
|
||
{
|
||
if (Book.CheckAccess(from))
|
||
{
|
||
Book.Default = e;
|
||
|
||
from.CloseGump<RunebookGump>();
|
||
from.SendGump(new RunebookGump(from, Book));
|
||
|
||
from.SendLocalizedMessage(502417); // New default location set.
|
||
}
|
||
|
||
break;
|
||
}
|
||
case 3: // Recall
|
||
{
|
||
if (HasSpell(from, 31))
|
||
{
|
||
int xLong = 0, yLat = 0;
|
||
int xMins = 0, yMins = 0;
|
||
bool xEast = false, ySouth = false;
|
||
|
||
if (Sextant.Format(e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast,
|
||
ref ySouth))
|
||
{
|
||
string location =
|
||
$"{yLat}<7D> {yMins}'{(ySouth ? "S" : "N")}, {xLong}<7D> {xMins}'{(xEast ? "E" : "W")}";
|
||
from.SendMessage(location);
|
||
}
|
||
|
||
Book.OnTravel();
|
||
new RecallSpell(from, e).Cast();
|
||
}
|
||
else
|
||
{
|
||
from.SendLocalizedMessage(500015); // You do not have that spell!
|
||
}
|
||
|
||
Book.Openers.Remove(from);
|
||
|
||
break;
|
||
}
|
||
case 4: // Gate
|
||
{
|
||
if (HasSpell(from, 51))
|
||
{
|
||
int xLong = 0, yLat = 0;
|
||
int xMins = 0, yMins = 0;
|
||
bool xEast = false, ySouth = false;
|
||
|
||
if (Sextant.Format(e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast,
|
||
ref ySouth))
|
||
{
|
||
string location =
|
||
$"{yLat}<7D> {yMins}'{(ySouth ? "S" : "N")}, {xLong}<7D> {xMins}'{(xEast ? "E" : "W")}";
|
||
from.SendMessage(location);
|
||
}
|
||
|
||
Book.OnTravel();
|
||
new GateTravelSpell(from, e).Cast();
|
||
}
|
||
else
|
||
{
|
||
from.SendLocalizedMessage(500015); // You do not have that spell!
|
||
}
|
||
|
||
Book.Openers.Remove(from);
|
||
|
||
break;
|
||
}
|
||
case 5: // Sacred Journey
|
||
{
|
||
if (Core.AOS)
|
||
{
|
||
if (HasSpell(from, 209))
|
||
{
|
||
int xLong = 0, yLat = 0;
|
||
int xMins = 0, yMins = 0;
|
||
bool xEast = false, ySouth = false;
|
||
|
||
if (Sextant.Format(e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins,
|
||
ref xEast, ref ySouth))
|
||
{
|
||
string location =
|
||
$"{yLat}<7D> {yMins}'{(ySouth ? "S" : "N")}, {xLong}<7D> {xMins}'{(xEast ? "E" : "W")}";
|
||
from.SendMessage(location);
|
||
}
|
||
|
||
Book.OnTravel();
|
||
new SacredJourneySpell(from, e).Cast();
|
||
}
|
||
else
|
||
{
|
||
from.SendLocalizedMessage(500015); // You do not have that spell!
|
||
}
|
||
}
|
||
|
||
Book.Openers.Remove(from);
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Book.Openers.Remove(from);
|
||
}
|
||
}
|
||
}
|
||
|
||
private class InternalPrompt : Prompt
|
||
{
|
||
private Runebook m_Book;
|
||
|
||
public InternalPrompt(Runebook book) => m_Book = book;
|
||
|
||
public override void OnResponse(Mobile from, string text)
|
||
{
|
||
if (m_Book.Deleted || !from.InRange(m_Book.GetWorldLocation(), Core.ML ? 3 : 1))
|
||
return;
|
||
|
||
if (m_Book.CheckAccess(from))
|
||
{
|
||
m_Book.Description = Utility.FixHtml(text.Trim());
|
||
|
||
from.CloseGump<RunebookGump>();
|
||
from.SendGump(new RunebookGump(from, m_Book));
|
||
|
||
from.SendMessage("The book's title has been changed.");
|
||
}
|
||
else
|
||
{
|
||
m_Book.Openers.Remove(from);
|
||
|
||
from.SendLocalizedMessage(502416); // That cannot be done while the book is locked down.
|
||
}
|
||
}
|
||
|
||
public override void OnCancel(Mobile from)
|
||
{
|
||
from.SendLocalizedMessage(502415); // Request cancelled.
|
||
|
||
if (!m_Book.Deleted && from.InRange(m_Book.GetWorldLocation(), Core.ML ? 3 : 1))
|
||
{
|
||
from.CloseGump<RunebookGump>();
|
||
from.SendGump(new RunebookGump(from, m_Book));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|