perf: Migrate Veteran Reward gumps to DynamicGump/StaticGump (#2415)

## Summary

Migrates 16 player-facing legacy `Gump` subclasses in the Veteran Rewards system to `DynamicGump` or `StaticGump<T>`, renames every nested `InternalGump`/`ConfirmGump` to system-prefixed names, and updates external callers to use new static `DisplayTo` entry points.

### Reward chain (Engines/Veteran Rewards)

| Gump | Base type | Reasoning |
|---|---|---|
| `RewardNoticeGump` | `StaticGump<T>` | Fixed layout |
| `RewardChoiceGump` | `DynamicGump` | Layout shape varies (per-player categories, entries, pages) |
| `RewardConfirmGump` | `DynamicGump` | `entry.Name` is a dynamic cliloc per reward (cliloc rule) |
| `RewardOptionGump` | `DynamicGump` | Title cliloc and per-option clilocs are dynamic (cliloc rule) |
| `RewardDemolitionGump` | `DynamicGump` | `question` cliloc is dynamic per caller (cliloc rule) |

### Statue (Engines/Veteran Rewards/Character Statue Maker)

| Gump | Base type | Reasoning |
|---|---|---|
| `CharacterStatueGump` | `DynamicGump` | Pose/Direction/Material labels are dynamic clilocs (cliloc rule) |
| `CharacterPlinthGump` | `DynamicGump` | `statue.Name`, sculpted-on date, and statue-type cliloc are dynamic (cliloc rule) |

### Decorations (Items/Special/Veteran Rewards) — every `InternalGump` renamed

| Original | New name | Base type | Reasoning |
|---|---|---|---|
| `Banner.InternalGump` | `BannerGump` | `StaticGump<T>` | Fully fixed item-id picker over `Start..End` range |
| `Brazier.InternalGump` | `BrazierGump` | `StaticGump<T>` | Fixed two-item picker |
| `Cannon.InternalGump` | `CannonGump` | `DynamicGump` | `keg.Validate()` value passed as `~1_CHARGES~` arg (cliloc-arg rule) |
| `DecorativeShield.InternalGump` | `DecorativeShieldGump` | `StaticGump<T>` | Fixed item picker over a constant range |
| `DecorativeShield.FacingGump` | `DecorativeShieldFacingGump` | `DynamicGump` | Item ids depend on instance state |
| `HangingSkeleton.InternalGump` | `HangingSkeletonGump` | `StaticGump<T>` | Fixed item picker (5 hard-coded ids) |
| `PottedCactus.InternalGump` | `PottedCactusGump` | `StaticGump<T>` | Fixed 6-item picker |
| `StoneAnkh.InternalGump` | `StoneAnkhGump` | `StaticGump<T>` | Fixed two-direction picker |
| `WallBanner.InternalGump` | `WallBannerGump` | `StaticGump<T>` | Fixed 30-banner picker across 5 pages |
| `WeaponEngravingTool.InternalGump` | `WeaponEngravingToolGump` | `StaticGump<T>` | Fixed text-entry dialog |
| `WeaponEngravingTool.ConfirmGump` | `WeaponEngravingToolConfirmGump` | `DynamicGump` | Layout branches on `guildmaster != null` |

### External callers updated

`RewardSystem`, `CharacterStatue`, `FireFliesDeed`, `FlamingHead`, `Banner`, `DecorativeShield`, `HangingSkeleton`, `StoneAnkh` (RewardDemolitionGump callers); `AnkhOfSacrifice`, `Cannon`, `MiningCart`, `MinotaurStatue`, `TreeStump` (RewardOptionGump callers); `TinkerGuildmaster` (engraver confirm gump).

The pre-existing `FacingGump` inside `Banner.cs` (already `DynamicGump`) was left as-is — it is private, nested inside `InternalTarget`, and never referenced outside.
This commit is contained in:
Kamron Batman 2026-04-25 20:09:27 -07:00 • committed by GitHub
parent 50599e0453
commit ab5f615840
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1065 additions and 944 deletions

View file

@ -592,7 +592,7 @@ public class CharacterStatueTarget : Target
_maker.Delete();
statue.Sculpt(from);
from.SendGump(new CharacterStatueGump(_maker, statue, from), true);
CharacterStatueGump.DisplayTo(from, _maker, statue);
return;
}

View file

@ -77,7 +77,7 @@ public partial class CharacterStatuePlinth : Static, IAddon
{
if (_statue != null)
{
from.SendGump(new CharacterPlinthGump(_statue));
CharacterPlinthGump.DisplayTo(from, _statue);
}
}
@ -98,31 +98,40 @@ public partial class CharacterStatuePlinth : Static, IAddon
}
}
private class CharacterPlinthGump : Gump
private class CharacterPlinthGump : DynamicGump
{
public CharacterPlinthGump(CharacterStatue statue) : base(60, 30)
{
Closable = true;
Disposable = true;
Draggable = true;
Resizable = false;
private readonly CharacterStatue _statue;
AddPage(0);
AddImage(0, 0, 0x24F4);
AddHtml(55, 50, 150, 20, statue.Name);
AddHtml(55, 75, 150, 20, statue.SculptedOn.ToString());
AddHtmlLocalized(55, 100, 150, 20, GetTypeNumber(statue.StatueType), 0);
public override bool Singleton => true;
private CharacterPlinthGump(CharacterStatue statue) : base(60, 30) => _statue = statue;
public static void DisplayTo(Mobile from, CharacterStatue statue)
{
if (from?.NetState == null || statue == null || statue.Deleted)
{
return;
}
from.SendGump(new CharacterPlinthGump(statue));
}
public static int GetTypeNumber(StatueType type)
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
return type switch
builder.AddPage();
builder.AddImage(0, 0, 0x24F4);
builder.AddHtml(55, 50, 150, 20, _statue.Name);
builder.AddHtml(55, 75, 150, 20, _statue.SculptedOn.ToString());
builder.AddHtmlLocalized(55, 100, 150, 20, GetTypeNumber(_statue.StatueType), 0);
}
public static int GetTypeNumber(StatueType type) =>
type switch
{
StatueType.Marble => 1076181,
StatueType.Jade => 1076180,
StatueType.Bronze => 1076230,
_ => 1076181
};
}
}
}

View file

@ -1,207 +1,195 @@
using Server.Mobiles;
using Server.Network;
namespace Server.Gumps
namespace Server.Gumps;
public class CharacterStatueGump : DynamicGump
{
public class CharacterStatueGump : Gump
private readonly Item _maker;
private readonly CharacterStatue _statue;
public override bool Singleton => true;
private CharacterStatueGump(Item maker, CharacterStatue statue) : base(60, 36)
{
private readonly Item m_Maker;
private readonly Mobile m_Owner;
private readonly CharacterStatue m_Statue;
_maker = maker;
_statue = statue;
}
public CharacterStatueGump(Item maker, CharacterStatue statue, Mobile owner) : base(60, 36)
public static void DisplayTo(Mobile from, Item maker, CharacterStatue statue)
{
if (from?.NetState == null || statue == null || statue.Deleted)
{
m_Maker = maker;
m_Statue = statue;
m_Owner = owner;
if (m_Statue == null)
{
return;
}
Closable = true;
Disposable = true;
Draggable = true;
Resizable = false;
AddPage(0);
AddBackground(0, 0, 327, 324, 0x13BE);
AddImageTiled(10, 10, 307, 20, 0xA40);
AddImageTiled(10, 40, 307, 244, 0xA40);
AddImageTiled(10, 294, 307, 20, 0xA40);
AddAlphaRegion(10, 10, 307, 304);
AddHtmlLocalized(14, 12, 327, 20, 1076156, 0x7FFF); // Character Statue Maker
// pose
AddHtmlLocalized(133, 41, 120, 20, 1076168, 0x7FFF); // Choose Pose
AddHtmlLocalized(133, 61, 120, 20, 1076208 + (int)m_Statue.Pose, 0x77E);
AddButton(163, 81, 0xFA5, 0xFA7, (int)Buttons.PoseNext);
AddButton(133, 81, 0xFAE, 0xFB0, (int)Buttons.PosePrev);
// direction
AddHtmlLocalized(133, 126, 120, 20, 1076170, 0x7FFF); // Choose Direction
AddHtmlLocalized(133, 146, 120, 20, GetDirectionNumber(m_Statue.Direction), 0x77E);
AddButton(163, 167, 0xFA5, 0xFA7, (int)Buttons.DirNext);
AddButton(133, 167, 0xFAE, 0xFB0, (int)Buttons.DirPrev);
// material
AddHtmlLocalized(133, 211, 120, 20, 1076171, 0x7FFF); // Choose Material
AddHtmlLocalized(133, 231, 120, 20, GetMaterialNumber(m_Statue.StatueType, m_Statue.Material), 0x77E);
AddButton(163, 253, 0xFA5, 0xFA7, (int)Buttons.MatNext);
AddButton(133, 253, 0xFAE, 0xFB0, (int)Buttons.MatPrev);
// cancel
AddButton(10, 294, 0xFB1, 0xFB2, (int)Buttons.Close);
AddHtmlLocalized(45, 294, 80, 20, 1006045, 0x7FFF); // Cancel
// sculpt
AddButton(234, 294, 0xFB7, 0xFB9, (int)Buttons.Sculpt);
AddHtmlLocalized(269, 294, 80, 20, 1076174, 0x7FFF); // Sculpt
// restore
if (m_Maker is CharacterStatueDeed)
{
AddButton(107, 294, 0xFAB, 0xFAD, (int)Buttons.Restore);
AddHtmlLocalized(142, 294, 80, 20, 1076193, 0x7FFF); // Restore
}
return;
}
private static int GetMaterialNumber(StatueType type, StatueMaterial material)
from.SendGump(new CharacterStatueGump(maker, statue));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
builder.AddPage();
builder.AddBackground(0, 0, 327, 324, 0x13BE);
builder.AddImageTiled(10, 10, 307, 20, 0xA40);
builder.AddImageTiled(10, 40, 307, 244, 0xA40);
builder.AddImageTiled(10, 294, 307, 20, 0xA40);
builder.AddAlphaRegion(10, 10, 307, 304);
builder.AddHtmlLocalized(14, 12, 327, 20, 1076156, 0x7FFF); // Character Statue Maker
// pose
builder.AddHtmlLocalized(133, 41, 120, 20, 1076168, 0x7FFF); // Choose Pose
builder.AddHtmlLocalized(133, 61, 120, 20, 1076208 + (int)_statue.Pose, 0x77E);
builder.AddButton(163, 81, 0xFA5, 0xFA7, (int)Buttons.PoseNext);
builder.AddButton(133, 81, 0xFAE, 0xFB0, (int)Buttons.PosePrev);
// direction
builder.AddHtmlLocalized(133, 126, 120, 20, 1076170, 0x7FFF); // Choose Direction
builder.AddHtmlLocalized(133, 146, 120, 20, GetDirectionNumber(_statue.Direction), 0x77E);
builder.AddButton(163, 167, 0xFA5, 0xFA7, (int)Buttons.DirNext);
builder.AddButton(133, 167, 0xFAE, 0xFB0, (int)Buttons.DirPrev);
// material
builder.AddHtmlLocalized(133, 211, 120, 20, 1076171, 0x7FFF); // Choose Material
builder.AddHtmlLocalized(133, 231, 120, 20, GetMaterialNumber(_statue.StatueType, _statue.Material), 0x77E);
builder.AddButton(163, 253, 0xFA5, 0xFA7, (int)Buttons.MatNext);
builder.AddButton(133, 253, 0xFAE, 0xFB0, (int)Buttons.MatPrev);
// cancel
builder.AddButton(10, 294, 0xFB1, 0xFB2, (int)Buttons.Close);
builder.AddHtmlLocalized(45, 294, 80, 20, 1006045, 0x7FFF); // Cancel
// sculpt
builder.AddButton(234, 294, 0xFB7, 0xFB9, (int)Buttons.Sculpt);
builder.AddHtmlLocalized(269, 294, 80, 20, 1076174, 0x7FFF); // Sculpt
// restore
if (_maker is CharacterStatueDeed)
{
switch (material)
{
case StatueMaterial.Antique:
return type switch
{
StatueType.Bronze => 1076187,
StatueType.Jade => 1076186,
StatueType.Marble => 1076182,
_ => 1076187
};
case StatueMaterial.Dark:
if (type == StatueType.Marble)
{
return 1076183;
}
return 1076182;
case StatueMaterial.Medium: return 1076184;
case StatueMaterial.Light: return 1076185;
default: return 1076187;
}
}
private static int GetDirectionNumber(Direction direction)
{
return direction switch
{
Direction.North => 1075389,
Direction.Right => 1075388,
Direction.East => 1075387,
Direction.Down => 1076204,
Direction.South => 1075386,
Direction.Left => 1075391,
Direction.West => 1075390,
Direction.Up => 1076205,
_ => 1075386
};
}
public override void OnResponse(NetState state, in RelayInfo info)
{
if (m_Statue?.Deleted != false)
{
return;
}
var sendGump = false;
if (info.ButtonID == (int)Buttons.Sculpt)
{
if (m_Maker is CharacterStatueDeed deed)
{
var backup = deed.Statue;
backup?.Delete();
}
m_Maker?.Delete();
m_Statue.Sculpt(state.Mobile);
}
else if (info.ButtonID == (int)Buttons.PosePrev)
{
m_Statue.Pose = (StatuePose)(((int)m_Statue.Pose + 5) % 6);
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.PoseNext)
{
m_Statue.Pose = (StatuePose)(((int)m_Statue.Pose + 1) % 6);
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.DirPrev)
{
m_Statue.Direction = (Direction)(((int)m_Statue.Direction + 7) % 8);
m_Statue.InvalidatePose();
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.DirNext)
{
m_Statue.Direction = (Direction)(((int)m_Statue.Direction + 1) % 8);
m_Statue.InvalidatePose();
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.MatPrev)
{
m_Statue.Material = (StatueMaterial)(((int)m_Statue.Material + 3) % 4);
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.MatNext)
{
m_Statue.Material = (StatueMaterial)(((int)m_Statue.Material + 1) % 4);
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.Restore)
{
if (m_Maker is CharacterStatueDeed deed)
{
var backup = deed.Statue;
if (backup != null)
{
m_Statue.Restore(backup);
}
}
sendGump = true;
}
else // Close
{
sendGump = !m_Statue.Demolish(state.Mobile);
}
if (sendGump)
{
state.Mobile.SendGump(new CharacterStatueGump(m_Maker, m_Statue, m_Owner));
}
}
private enum Buttons
{
Close,
Sculpt,
PosePrev,
PoseNext,
DirPrev,
DirNext,
MatPrev,
MatNext,
Restore
builder.AddButton(107, 294, 0xFAB, 0xFAD, (int)Buttons.Restore);
builder.AddHtmlLocalized(142, 294, 80, 20, 1076193, 0x7FFF); // Restore
}
}
private static int GetMaterialNumber(StatueType type, StatueMaterial material) =>
material switch
{
StatueMaterial.Antique => type switch
{
StatueType.Bronze => 1076187,
StatueType.Jade => 1076186,
StatueType.Marble => 1076182,
_ => 1076187
},
StatueMaterial.Dark => type == StatueType.Marble ? 1076183 : 1076182,
StatueMaterial.Medium => 1076184,
StatueMaterial.Light => 1076185,
_ => 1076187
};
private static int GetDirectionNumber(Direction direction) =>
direction switch
{
Direction.North => 1075389,
Direction.Right => 1075388,
Direction.East => 1075387,
Direction.Down => 1076204,
Direction.South => 1075386,
Direction.Left => 1075391,
Direction.West => 1075390,
Direction.Up => 1076205,
_ => 1075386
};
public override void OnResponse(NetState state, in RelayInfo info)
{
if (_statue?.Deleted != false)
{
return;
}
var sendGump = false;
if (info.ButtonID == (int)Buttons.Sculpt)
{
if (_maker is CharacterStatueDeed deed)
{
var backup = deed.Statue;
backup?.Delete();
}
_maker?.Delete();
_statue.Sculpt(state.Mobile);
}
else if (info.ButtonID == (int)Buttons.PosePrev)
{
_statue.Pose = (StatuePose)(((int)_statue.Pose + 5) % 6);
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.PoseNext)
{
_statue.Pose = (StatuePose)(((int)_statue.Pose + 1) % 6);
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.DirPrev)
{
_statue.Direction = (Direction)(((int)_statue.Direction + 7) % 8);
_statue.InvalidatePose();
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.DirNext)
{
_statue.Direction = (Direction)(((int)_statue.Direction + 1) % 8);
_statue.InvalidatePose();
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.MatPrev)
{
_statue.Material = (StatueMaterial)(((int)_statue.Material + 3) % 4);
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.MatNext)
{
_statue.Material = (StatueMaterial)(((int)_statue.Material + 1) % 4);
sendGump = true;
}
else if (info.ButtonID == (int)Buttons.Restore)
{
if (_maker is CharacterStatueDeed deed)
{
var backup = deed.Statue;
if (backup != null)
{
_statue.Restore(backup);
}
}
sendGump = true;
}
else // Close
{
sendGump = !_statue.Demolish(state.Mobile);
}
if (sendGump)
{
state.Mobile.SendGump(this);
}
}
private enum Buttons
{
Close,
Sculpt,
PosePrev,
PoseNext,
DirPrev,
DirNext,
MatPrev,
MatNext,
Restore
}
}

View file

@ -2,217 +2,227 @@ using System;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.VeteranRewards
namespace Server.Engines.VeteranRewards;
public class RewardChoiceGump : DynamicGump
{
public class RewardChoiceGump : Gump
private readonly Mobile _from;
public override bool Singleton => true;
private RewardChoiceGump(Mobile from) : base(0, 0) => _from = from;
public static void DisplayTo(Mobile from)
{
private readonly Mobile m_From;
public override bool Singleton => true;
public RewardChoiceGump(Mobile from) : base(0, 0)
if (from?.NetState == null)
{
m_From = from;
RenderBackground();
RenderCategories();
return;
}
private void RenderBackground()
from.SendGump(new RewardChoiceGump(from));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
RenderBackground(ref builder);
RenderCategories(ref builder);
}
private static void RenderBackground(ref DynamicGumpBuilder builder)
{
builder.AddPage();
builder.AddBackground(10, 10, 600, 450, 2600);
builder.AddButton(530, 415, 4017, 4019, 0);
builder.AddButton(60, 415, 4014, 4016, 0, GumpButtonType.Page, 1);
builder.AddHtmlLocalized(95, 415, 200, 20, 1049755); // Main Menu
}
private void RenderCategories(ref DynamicGumpBuilder builder)
{
var rewardInterval = RewardSystem.RewardInterval;
string intervalAsString;
if (rewardInterval == TimeSpan.FromDays(30.0))
{
AddPage(0);
AddBackground(10, 10, 600, 450, 2600);
AddButton(530, 415, 4017, 4019, 0);
AddButton(60, 415, 4014, 4016, 0, GumpButtonType.Page, 1);
AddHtmlLocalized(95, 415, 200, 20, 1049755); // Main Menu
intervalAsString = "month";
}
else if (rewardInterval == TimeSpan.FromDays(60.0))
{
intervalAsString = "two months";
}
else if (rewardInterval == TimeSpan.FromDays(90.0))
{
intervalAsString = "three months";
}
else if (rewardInterval == TimeSpan.FromDays(365.0))
{
intervalAsString = "year";
}
else
{
intervalAsString = $"{rewardInterval.TotalDays} day{(rewardInterval.TotalDays == 1 ? "" : "s")}";
}
private void RenderCategories()
builder.AddPage(1);
builder.AddHtml(
60,
35,
500,
70,
$"<B>Ultima Online Rewards Program</B><BR>Thank you for being a part of the Ultima Online community for a full {intervalAsString}. As a token of our appreciation, you may select from the following in-game reward items listed below. The gift items will be attributed to the character you have logged-in with on the shard you are on when you chose the item(s). The number of rewards you are entitled to are listed below and are for your entire account. To read more about these rewards before making a selection, feel free to visit the uo.com site at <A HREF=\"https://uo.com/wiki/ultima-online-wiki/items/veteran-rewards\">https://uo.com/wiki/ultima-online-wiki/items/veteran-rewards</A>.",
background: true,
scrollbar: true
);
RewardSystem.ComputeRewardInfo(_from, out var cur, out var max);
builder.AddHtmlLocalized(60, 105, 300, 35, 1006006); // Your current total of rewards to choose:
builder.AddLabel(370, 107, 50, $"{max - cur}");
builder.AddHtmlLocalized(60, 140, 300, 35, 1006007); // You have already chosen:
builder.AddLabel(370, 142, 50, $"{cur}");
var categories = RewardSystem.Categories;
var page = 2;
for (var i = 0; i < categories.Length; ++i)
{
var rewardInterval = RewardSystem.RewardInterval;
var cat = categories[i];
if (!RewardSystem.HasAccess(_from, cat))
{
page += 1;
continue;
}
string intervalAsString;
builder.AddButton(100, 180 + i * 40, 4005, 4005, 0, GumpButtonType.Page, page);
if (rewardInterval == TimeSpan.FromDays(30.0))
page += PagesPerCategory(cat);
if (cat.NameString != null)
{
intervalAsString = "month";
}
else if (rewardInterval == TimeSpan.FromDays(60.0))
{
intervalAsString = "two months";
}
else if (rewardInterval == TimeSpan.FromDays(90.0))
{
intervalAsString = "three months";
}
else if (rewardInterval == TimeSpan.FromDays(365.0))
{
intervalAsString = "year";
builder.AddHtml(135, 180 + i * 40, 300, 20, cat.NameString);
}
else
{
intervalAsString = $"{rewardInterval.TotalDays} day{(rewardInterval.TotalDays == 1 ? "" : "s")}";
builder.AddHtmlLocalized(135, 180 + i * 40, 300, 20, cat.Name);
}
}
page = 2;
for (var i = 0; i < categories.Length; ++i)
{
RenderCategory(ref builder, categories[i], i, ref page);
}
}
private int PagesPerCategory(RewardCategory category)
{
var entries = category.Entries;
var i = 0;
for (var j = 0; j < entries.Count; j++)
{
if (RewardSystem.HasAccess(_from, entries[j]))
{
i++;
}
}
return (int)Math.Ceiling(i / 24.0);
}
private static int GetButtonID(int type, int index) => 2 + index * 20 + type;
private void RenderCategory(ref DynamicGumpBuilder builder, RewardCategory category, int index, ref int page)
{
builder.AddPage(page);
var entries = category.Entries;
var i = 0;
for (var j = 0; j < entries.Count; ++j)
{
var entry = entries[j];
if (!RewardSystem.HasAccess(_from, entry))
{
continue;
}
AddPage(1);
if (i == 24)
{
builder.AddButton(305, 415, 0xFA5, 0xFA7, 0, GumpButtonType.Page, ++page);
builder.AddHtmlLocalized(340, 415, 200, 20, 1011066); // Next page
AddHtml(
60,
35,
500,
70,
$"<B>Ultima Online Rewards Program</B><BR>Thank you for being a part of the Ultima Online community for a full {intervalAsString}. As a token of our appreciation, you may select from the following in-game reward items listed below. The gift items will be attributed to the character you have logged-in with on the shard you are on when you chose the item(s). The number of rewards you are entitled to are listed below and are for your entire account. To read more about these rewards before making a selection, feel free to visit the uo.com site at <A HREF=\"http://www.uo.com/rewards\">http://www.uo.com/rewards</A>.",
true,
true
);
builder.AddPage(page);
RewardSystem.ComputeRewardInfo(m_From, out var cur, out var max);
builder.AddButton(270, 415, 0xFAE, 0xFB0, 0, GumpButtonType.Page, page - 1);
builder.AddHtmlLocalized(185, 415, 200, 20, 1011067); // Previous page
AddHtmlLocalized(60, 105, 300, 35, 1006006); // Your current total of rewards to choose:
AddLabel(370, 107, 50, (max - cur).ToString());
i = 0;
}
AddHtmlLocalized(60, 140, 300, 35, 1006007); // You have already chosen:
AddLabel(370, 142, 50, cur.ToString());
builder.AddButton(55 + i / 12 * 250, 80 + i % 12 * 25, 5540, 5541, GetButtonID(index, j));
if (entry.NameString != null)
{
builder.AddHtml(80 + i / 12 * 250, 80 + i % 12 * 25, 250, 20, entry.NameString);
}
else
{
builder.AddHtmlLocalized(80 + i / 12 * 250, 80 + i % 12 * 25, 250, 20, entry.Name);
}
++i;
}
page += 1;
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
var buttonID = info.ButtonID - 1;
if (buttonID == 0)
{
RewardSystem.ComputeRewardInfo(_from, out var cur, out var max);
if (cur < max)
{
RewardNoticeGump.DisplayTo(_from);
}
}
else
{
--buttonID;
var type = buttonID % 20;
var index = buttonID / 20;
var categories = RewardSystem.Categories;
var page = 2;
for (var i = 0; i < categories.Length; ++i)
if (type >= 0 && type < categories.Length)
{
if (!RewardSystem.HasAccess(m_From, categories[i]))
var category = categories[type];
if (index >= 0 && index < category.Entries.Count)
{
page += 1;
continue;
}
var entry = category.Entries[index];
AddButton(100, 180 + i * 40, 4005, 4005, 0, GumpButtonType.Page, page);
page += PagesPerCategory(categories[i]);
if (categories[i].NameString != null)
{
AddHtml(135, 180 + i * 40, 300, 20, categories[i].NameString);
}
else
{
AddHtmlLocalized(135, 180 + i * 40, 300, 20, categories[i].Name);
}
}
page = 2;
for (var i = 0; i < categories.Length; ++i)
{
RenderCategory(categories[i], i, ref page);
}
}
private int PagesPerCategory(RewardCategory category)
{
var entries = category.Entries;
var i = 0;
for (var j = 0; j < entries.Count; j++)
{
if (RewardSystem.HasAccess(m_From, entries[j]))
{
i++;
}
}
return (int)Math.Ceiling(i / 24.0);
}
private int GetButtonID(int type, int index) => 2 + index * 20 + type;
private void RenderCategory(RewardCategory category, int index, ref int page)
{
AddPage(page);
var entries = category.Entries;
var i = 0;
for (var j = 0; j < entries.Count; ++j)
{
var entry = entries[j];
if (!RewardSystem.HasAccess(m_From, entry))
{
continue;
}
if (i == 24)
{
AddButton(305, 415, 0xFA5, 0xFA7, 0, GumpButtonType.Page, ++page);
AddHtmlLocalized(340, 415, 200, 20, 1011066); // Next page
AddPage(page);
AddButton(270, 415, 0xFAE, 0xFB0, 0, GumpButtonType.Page, page - 1);
AddHtmlLocalized(185, 415, 200, 20, 1011067); // Previous page
i = 0;
}
AddButton(55 + i / 12 * 250, 80 + i % 12 * 25, 5540, 5541, GetButtonID(index, j));
if (entry.NameString != null)
{
AddHtml(80 + i / 12 * 250, 80 + i % 12 * 25, 250, 20, entry.NameString);
}
else
{
AddHtmlLocalized(80 + i / 12 * 250, 80 + i % 12 * 25, 250, 20, entry.Name);
}
++i;
}
page += 1;
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
var buttonID = info.ButtonID - 1;
if (buttonID == 0)
{
RewardSystem.ComputeRewardInfo(m_From, out var cur, out var max);
if (cur < max)
{
m_From.SendGump(new RewardNoticeGump(m_From));
}
}
else
{
--buttonID;
var type = buttonID % 20;
var index = buttonID / 20;
var categories = RewardSystem.Categories;
if (type >= 0 && type < categories.Length)
{
var category = categories[type];
if (index >= 0 && index < category.Entries.Count)
if (!RewardSystem.HasAccess(_from, entry))
{
var entry = category.Entries[index];
if (!RewardSystem.HasAccess(m_From, entry))
{
return;
}
m_From.SendGump(new RewardConfirmGump(m_From, entry));
return;
}
RewardConfirmGump.DisplayTo(_from, entry);
}
}
}

View file

@ -2,90 +2,97 @@ using Server.Gumps;
using Server.Items;
using Server.Network;
namespace Server.Engines.VeteranRewards
namespace Server.Engines.VeteranRewards;
public class RewardConfirmGump : DynamicGump
{
public class RewardConfirmGump : Gump
private readonly RewardEntry _entry;
private readonly Mobile _from;
public override bool Singleton => true;
private RewardConfirmGump(Mobile from, RewardEntry entry) : base(0, 0)
{
private readonly RewardEntry m_Entry;
private readonly Mobile m_From;
_from = from;
_entry = entry;
}
public override bool Singleton => true;
public RewardConfirmGump(Mobile from, RewardEntry entry) : base(0, 0)
public static void DisplayTo(Mobile from, RewardEntry entry)
{
if (from?.NetState == null || entry == null)
{
m_From = from;
m_Entry = entry;
AddPage(0);
AddBackground(10, 10, 500, 300, 2600);
AddHtmlLocalized(30, 55, 300, 35, 1006000); // You have selected:
if (entry.NameString != null)
{
AddHtml(335, 55, 150, 35, entry.NameString);
}
else
{
AddHtmlLocalized(335, 55, 150, 35, entry.Name);
}
AddHtmlLocalized(30, 95, 300, 35, 1006001); // This will be assigned to this character:
AddLabel(335, 95, 0, from.Name);
AddHtmlLocalized(
35,
160,
450,
90,
1006002,
true,
true
); // Are you sure you wish to select this reward for this character? You will not be able to transfer this reward to another character on another shard. Click 'ok' below to confirm your selection or 'cancel' to go back to the selection screen.
AddButton(60, 265, 4005, 4007, 1);
AddHtmlLocalized(95, 266, 150, 35, 1006044); // Ok
AddButton(295, 265, 4017, 4019, 0);
AddHtmlLocalized(330, 266, 150, 35, 1006045); // Cancel
return;
}
public override void OnResponse(NetState sender, in RelayInfo info)
from.SendGump(new RewardConfirmGump(from, entry));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
builder.AddPage();
builder.AddBackground(10, 10, 500, 300, 2600);
builder.AddHtmlLocalized(30, 55, 300, 35, 1006000); // You have selected:
if (_entry.NameString != null)
{
if (info.ButtonID == 1)
builder.AddHtml(335, 55, 150, 35, _entry.NameString);
}
else
{
builder.AddHtmlLocalized(335, 55, 150, 35, _entry.Name);
}
builder.AddHtmlLocalized(30, 95, 300, 35, 1006001); // This will be assigned to this character:
builder.AddLabel(335, 95, 0, _from.RawName);
// Are you sure you wish to select this reward for this character?
// You will not be able to transfer this reward to another character on another shard.
// Click 'ok' below to confirm your selection or 'cancel' to go back to the selection screen.
builder.AddHtmlLocalized(35, 160, 450, 90, 1006002, true, true);
builder.AddButton(60, 265, 4005, 4007, 1);
builder.AddHtmlLocalized(95, 266, 150, 35, 1006044); // Ok
builder.AddButton(295, 265, 4017, 4019, 0);
builder.AddHtmlLocalized(330, 266, 150, 35, 1006045); // Cancel
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (info.ButtonID == 1)
{
if (!RewardSystem.HasAccess(_from, _entry))
{
if (!RewardSystem.HasAccess(m_From, m_Entry))
{
return;
}
var item = m_Entry.Construct();
if (item != null)
{
if (item is RedSoulstone soulstone)
{
soulstone.Account = m_From.Account.Username;
}
if (RewardSystem.ConsumeRewardPoint(m_From))
{
m_From.AddToBackpack(item);
}
else
{
item.Delete();
}
}
return;
}
RewardSystem.ComputeRewardInfo(m_From, out var cur, out var max);
var item = _entry.Construct();
if (cur < max)
if (item != null)
{
m_From.SendGump(new RewardNoticeGump(m_From));
if (item is RedSoulstone soulstone)
{
soulstone.Account = _from.Account.Username;
}
if (RewardSystem.ConsumeRewardPoint(_from))
{
_from.AddToBackpack(item);
}
else
{
item.Delete();
}
}
}
RewardSystem.ComputeRewardInfo(_from, out var cur, out var max);
if (cur < max)
{
RewardNoticeGump.DisplayTo(_from);
}
}
}

View file

@ -2,78 +2,89 @@ using Server.Items;
using Server.Multis;
using Server.Network;
namespace Server.Gumps
namespace Server.Gumps;
public class RewardDemolitionGump : DynamicGump
{
public class RewardDemolitionGump : Gump
private readonly IAddon _addon;
private readonly int _question;
public override bool Singleton => true;
private RewardDemolitionGump(IAddon addon, int question) : base(150, 50)
{
private readonly IAddon m_Addon;
_addon = addon;
_question = question;
}
public override bool Singleton => true;
public RewardDemolitionGump(IAddon addon, int question) : base(150, 50)
public static void DisplayTo(Mobile from, IAddon addon, int question)
{
if (from?.NetState == null || addon is not Item item || item.Deleted)
{
m_Addon = addon;
Closable = true;
Disposable = true;
Draggable = true;
Resizable = false;
AddBackground(0, 0, 220, 170, 0x13BE);
AddBackground(10, 10, 200, 150, 0xBB8);
AddHtmlLocalized(20, 30, 180, 60, question); // Do you wish to re-deed this decoration?
AddHtmlLocalized(55, 100, 150, 25, 1011011); // CONTINUE
AddButton(20, 100, 0xFA5, 0xFA7, (int)Buttons.Confirm);
AddHtmlLocalized(55, 125, 150, 25, 1011012); // CANCEL
AddButton(20, 125, 0xFA5, 0xFA7, (int)Buttons.Cancel);
return;
}
public override void OnResponse(NetState sender, in RelayInfo info)
from.SendGump(new RewardDemolitionGump(addon, question));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
builder.AddPage();
builder.AddBackground(0, 0, 220, 170, 0x13BE);
builder.AddBackground(10, 10, 200, 150, 0xBB8);
builder.AddHtmlLocalized(20, 30, 180, 60, _question); // Do you wish to re-deed this decoration?
builder.AddHtmlLocalized(55, 100, 150, 25, 1011011); // CONTINUE
builder.AddButton(20, 100, 0xFA5, 0xFA7, (int)Buttons.Confirm);
builder.AddHtmlLocalized(55, 125, 150, 25, 1011012); // CANCEL
builder.AddButton(20, 125, 0xFA5, 0xFA7, (int)Buttons.Cancel);
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (_addon is not Item item || item.Deleted)
{
if (m_Addon is not Item item || item.Deleted)
{
return;
}
if (info.ButtonID != (int)Buttons.Confirm)
{
return;
}
var m = sender.Mobile;
var house = BaseHouse.FindHouseAt(m);
if (house?.IsOwner(m) != true)
{
// You can only re-deed this decoration if you are the house owner or originally placed the decoration.
m.SendLocalizedMessage(1049784);
return;
}
if (m.InRange(item.Location, 2))
{
var deed = m_Addon.Deed;
if (deed != null)
{
m.AddToBackpack(deed);
house.Addons.Remove(item);
item.Delete();
}
}
else
{
m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
}
return;
}
private enum Buttons
if (info.ButtonID != (int)Buttons.Confirm)
{
Cancel,
Confirm
return;
}
var m = sender.Mobile;
var house = BaseHouse.FindHouseAt(m);
if (house?.IsOwner(m) != true)
{
// You can only re-deed this decoration if you are the house owner or originally placed the decoration.
m.SendLocalizedMessage(1049784);
return;
}
if (m.InRange(item.Location, 2))
{
var deed = _addon.Deed;
if (deed != null)
{
m.AddToBackpack(deed);
house.Addons.Remove(item);
item.Delete();
}
}
else
{
m.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
}
}
private enum Buttons
{
Cancel,
Confirm
}
}

View file

@ -1,40 +1,49 @@
using Server.Gumps;
using Server.Network;
namespace Server.Engines.VeteranRewards
namespace Server.Engines.VeteranRewards;
public class RewardNoticeGump : StaticGump<RewardNoticeGump>
{
public class RewardNoticeGump : Gump
public override bool Singleton => true;
private RewardNoticeGump() : base(0, 0)
{
private readonly Mobile m_From;
}
public override bool Singleton => true;
public RewardNoticeGump(Mobile from) : base(0, 0)
public static void DisplayTo(Mobile from)
{
if (from?.NetState == null)
{
m_From = from;
AddPage(0);
AddBackground(10, 10, 500, 135, 2600);
/* You have reward items available.
* Click 'ok' below to get the selection menu or 'cancel' to be prompted upon your next login.
*/
AddHtmlLocalized(52, 35, 420, 55, 1006046, true, true);
AddButton(60, 95, 4005, 4007, 1);
AddHtmlLocalized(95, 96, 150, 35, 1006044); // Ok
AddButton(285, 95, 4017, 4019, 0);
AddHtmlLocalized(320, 96, 150, 35, 1006045); // Cancel
return;
}
public override void OnResponse(NetState sender, in RelayInfo info)
from.SendGump(new RewardNoticeGump());
}
protected override void BuildLayout(ref StaticGumpBuilder builder)
{
builder.AddPage();
builder.AddBackground(10, 10, 500, 135, 2600);
/* You have reward items available.
* Click 'ok' below to get the selection menu or 'cancel' to be prompted upon your next login.
*/
builder.AddHtmlLocalized(52, 35, 420, 55, 1006046, true, true);
builder.AddButton(60, 95, 4005, 4007, 1);
builder.AddHtmlLocalized(95, 96, 150, 35, 1006044); // Ok
builder.AddButton(285, 95, 4017, 4019, 0);
builder.AddHtmlLocalized(320, 96, 150, 35, 1006045); // Cancel
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (info.ButtonID == 1)
{
if (info.ButtonID == 1)
{
m_From.SendGump(new RewardChoiceGump(m_From));
}
RewardChoiceGump.DisplayTo(sender.Mobile);
}
}
}

View file

@ -1,101 +1,115 @@
using System.Collections.Generic;
using Server.Network;
namespace Server.Gumps
namespace Server.Gumps;
public interface IRewardOption
{
public interface IRewardOption
void GetOptions(RewardOptionList list);
void OnOptionSelected(Mobile from, int choice);
}
public class RewardOptionGump : DynamicGump
{
private readonly IRewardOption _option;
private readonly RewardOptionList _options = new();
private readonly int _title;
public override bool Singleton => true;
private RewardOptionGump(IRewardOption option, int title) : base(60, 36)
{
void GetOptions(RewardOptionList list);
void OnOptionSelected(Mobile from, int choice);
_option = option;
_title = title;
_option?.GetOptions(_options);
}
public class RewardOptionGump : Gump
public static void DisplayTo(Mobile from, IRewardOption option, int title = 0)
{
private readonly IRewardOption m_Option;
private readonly RewardOptionList m_Options = new();
public override bool Singleton => true;
public RewardOptionGump(IRewardOption option, int title = 0) : base(60, 36)
if (from?.NetState == null || option == null)
{
m_Option = option;
m_Option?.GetOptions(m_Options);
AddPage(0);
AddBackground(0, 0, 273, 324, 0x13BE);
AddImageTiled(10, 10, 253, 20, 0xA40);
AddImageTiled(10, 40, 253, 244, 0xA40);
AddImageTiled(10, 294, 253, 20, 0xA40);
AddAlphaRegion(10, 10, 253, 304);
AddButton(10, 294, 0xFB1, 0xFB2, 0);
AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL
if (title > 0)
{
AddHtmlLocalized(14, 12, 273, 20, title, 0x7FFF);
}
else
{
AddHtmlLocalized(14, 12, 273, 20, 1080392, 0x7FFF); // Select your choice from the menu below.
}
AddPage(1);
for (var i = 0; i < m_Options.Count; i++)
{
AddButton(19, 49 + i * 24, 0x845, 0x846, m_Options[i].ID);
AddHtmlLocalized(44, 47 + i * 24, 213, 20, m_Options[i].Cliloc, 0x7FFF);
}
return;
}
public override void OnResponse(NetState sender, in RelayInfo info)
from.SendGump(new RewardOptionGump(option, title));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
builder.AddPage();
builder.AddBackground(0, 0, 273, 324, 0x13BE);
builder.AddImageTiled(10, 10, 253, 20, 0xA40);
builder.AddImageTiled(10, 40, 253, 244, 0xA40);
builder.AddImageTiled(10, 294, 253, 20, 0xA40);
builder.AddAlphaRegion(10, 10, 253, 304);
builder.AddButton(10, 294, 0xFB1, 0xFB2, 0);
builder.AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF); // CANCEL
if (_title > 0)
{
if (m_Option != null && Contains(info.ButtonID))
{
m_Option.OnOptionSelected(sender.Mobile, info.ButtonID);
}
builder.AddHtmlLocalized(14, 12, 273, 20, _title, 0x7FFF);
}
else
{
builder.AddHtmlLocalized(14, 12, 273, 20, 1080392, 0x7FFF); // Select your choice from the menu below.
}
private bool Contains(int chosen)
builder.AddPage(1);
for (var i = 0; i < _options.Count; i++)
{
if (m_Options == null)
{
return false;
}
builder.AddButton(19, 49 + i * 24, 0x845, 0x846, _options[i].ID);
builder.AddHtmlLocalized(44, 47 + i * 24, 213, 20, _options[i].Cliloc, 0x7FFF);
}
}
foreach (var option in m_Options)
{
if (option.ID == chosen)
{
return true;
}
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (_option != null && Contains(info.ButtonID))
{
_option.OnOptionSelected(sender.Mobile, info.ButtonID);
}
}
private bool Contains(int chosen)
{
if (_options == null)
{
return false;
}
}
public class RewardOption
{
public RewardOption(int id, int cliloc)
foreach (var option in _options)
{
ID = id;
Cliloc = cliloc;
if (option.ID == chosen)
{
return true;
}
}
public int ID { get; }
public int Cliloc { get; }
}
public class RewardOptionList : List<RewardOption>
{
public void Add(int id, int cliloc)
{
Add(new RewardOption(id, cliloc));
}
return false;
}
}
public class RewardOption
{
public RewardOption(int id, int cliloc)
{
ID = id;
Cliloc = cliloc;
}
public int ID { get; }
public int Cliloc { get; }
}
public class RewardOptionList : List<RewardOption>
{
public void Add(int id, int cliloc)
{
Add(new RewardOption(id, cliloc));
}
}

View file

@ -595,7 +595,7 @@ namespace Server.Engines.VeteranRewards
if (cur < max)
{
pm.SendGump(new RewardNoticeGump(pm));
RewardNoticeGump.DisplayTo(pm);
}
}
}