perf: Migrate ConPVP game board gumps to DynamicGump (#2419)

## Summary

Migrates the four ConPVP game board (scoreboard) gumps from legacy `Gump` to `DynamicGump`:

- **`BRBoardGump`** (Bombing Run) — variable layout: row-per-team based on `Participants.Count`. Migrated to `DynamicGump`, `Singleton`, private constructor + `DisplayTo`, `SetNoClose()`.
- **`CTFBoardGump`** (Capture the Flag) — variable layout: row-per-team filtered to only teams with a flag. Same migration shape.
- **`DDBoardGump`** (Double Domination) — variable layout: row-per-team. Same migration shape.
- **`KHBoardGump`** (King of the Hill) — variable layout: row-per-team. `sealed`. Same migration shape.

### Refresh-via-this decision

For all four boards, **score data lives on the `*Game` / `*TeamInfo` objects, not the gump**. The gump just renders a snapshot of those values at the moment it is sent. The three call sites per board are:

1. `OnDoubleClick` on the in-world scoreboard item — one-shot manual open.
2. After death/kill score events (in `OnDeath`) — game logic pushes a fresh board to the dying player so they see updated scores.
3. End-of-game broadcast loop — sends final results to every participant.

None of these are button-driven refreshes from inside the gump, and the gump owns no mutable state. Therefore each event allocates a fresh gump (now via `DisplayTo(...)`) rather than calling `SendGump(this)` on a long-lived instance — that pattern doesn't fit when the data source is external. The win comes from `DynamicGump`'s ref-struct builder writing directly to buffers, eliminating the legacy `GumpEntry` list allocations on every send.

### Mechanics

- `: Gump` → `: DynamicGump`; layout moved from constructor to `BuildLayout(ref DynamicGumpBuilder)`.
- `Closable = false` → `builder.SetNoClose()`.
- Constructors are `private`; static `DisplayTo(Mobile, *Game, ...)` validates `mob?.NetState != null && game != null` before constructing.
- Team-section-mode parameter (`section`) preserved on BR / CTF / DD as an optional `DisplayTo` param even though no current caller uses it.
- The four `m_Game` / similar fields are renamed to `_game`; new fields use `_camelCase` per CLAUDE.md §12.
- `AddBorderedText` / `AddColoredText` helpers became `static` and take `ref DynamicGumpBuilder`.
- Updated all 12 internal call sites (3 per file) to go through `DisplayTo`. No external callers.
- No `OnResponse` was defined on any of these gumps (the only button is a close button), so no `RelayInfo` signature changes were needed.

Touches 4 game files, but only the gump classes — game logic (BR death/scoring, CTF flag handling, DD domination, KH king timer) is untouched.
This commit is contained in:
Kamron Batman 2026-04-26 09:55:46 -07:00 committed by GitHub
parent 802849bebc
commit 70a69d3efe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 291 additions and 326 deletions

View file

@ -63,10 +63,7 @@ public partial class BRBomb : Item
var mob = FindOwner(parent);
if (mob != null)
{
mob.SolidHueOverride = 0x0499;
}
mob?.SolidHueOverride = 0x0499;
}
public override void OnRemoved(IEntity parent)
@ -989,32 +986,51 @@ public sealed partial class BRBoard : Item
{
if (m_TeamInfo?.Game != null)
{
from.SendGump(new BRBoardGump(from, m_TeamInfo.Game));
BRBoardGump.DisplayTo(from, m_TeamInfo.Game);
}
}
}
public class BRBoardGump : Gump
public class BRBoardGump : DynamicGump
{
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000000;
private readonly Mobile _mob;
private readonly BRGame _game;
private readonly BRTeamInfo _section;
public override bool Singleton => true;
public BRBoardGump(Mobile mob, BRGame game, BRTeamInfo section = null) : base(60, 60)
private BRBoardGump(Mobile mob, BRGame game, BRTeamInfo section) : base(60, 60)
{
// m_Game = game;
_mob = mob;
_game = game;
_section = section;
}
var ourTeam = game.GetTeamInfo(mob);
public static void DisplayTo(Mobile mob, BRGame game, BRTeamInfo section = null)
{
if (mob?.NetState == null || game == null)
{
return;
}
mob.SendGump(new BRBoardGump(mob, game, section));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
var ourTeam = _game.GetTeamInfo(_mob);
var entries = new List<BRTeamInfo>();
var total = 0;
if (section == null)
if (_section == null)
{
for (var i = 0; i < game.Context.Participants.Count; ++i)
for (var i = 0; i < _game.Context.Participants.Count; ++i)
{
var teamInfo = game.Controller.TeamInfo[i % game.Controller.TeamInfo.Length];
var teamInfo = _game.Controller.TeamInfo[i % _game.Controller.TeamInfo.Length];
if (teamInfo == null)
{
@ -1028,7 +1044,7 @@ public class BRBoardGump : Gump
}
else
{
foreach (var player in section.Players.Values)
foreach (var player in _section.Players.Values)
{
if (player.Score > 0)
{
@ -1041,46 +1057,45 @@ public class BRBoardGump : Gump
var height = 0;
if (section == null)
if (_section == null)
{
height = 73 + entries.Count * 75 + 28;
}
Closable = false;
builder.SetNoClose();
AddPage(0);
builder.AddPage();
AddBackground(1, 1, 398, height, 3600);
builder.AddBackground(1, 1, 398, height, 3600);
AddImageTiled(16, 15, 369, height - 29, 3604);
builder.AddImageTiled(16, 15, 369, height - 29, 3604);
for (var i = 0; i < total; i += 1)
{
AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430);
builder.AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430);
}
AddAlphaRegion(16, 15, 369, height - 29);
builder.AddAlphaRegion(16, 15, 369, height - 29);
AddImage(215, -45, 0xEE40);
// AddImage( 330, 141, 0x8BA );
builder.AddImage(215, -45, 0xEE40);
AddBorderedText(22, 22, 294, 20, "BR Scoreboard".Center(), LabelColor32, BlackColor32);
AddBorderedText(ref builder, 22, 22, 294, 20, "BR Scoreboard".Center(), LabelColor32, BlackColor32);
AddImageTiled(32, 50, 264, 1, 9107);
AddImageTiled(42, 52, 264, 1, 9157);
builder.AddImageTiled(32, 50, 264, 1, 9107);
builder.AddImageTiled(42, 52, 264, 1, 9157);
if (section == null)
if (_section == null)
{
for (var i = 0; i < entries.Count; ++i)
{
var teamInfo = entries[i];
AddImage(30, 70 + i * 75, 10152);
AddImage(30, 85 + i * 75, 10151);
AddImage(30, 100 + i * 75, 10151);
AddImage(30, 106 + i * 75, 10154);
builder.AddImage(30, 70 + i * 75, 10152);
builder.AddImage(30, 85 + i * 75, 10151);
builder.AddImage(30, 100 + i * 75, 10151);
builder.AddImage(30, 106 + i * 75, 10154);
AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1);
builder.AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1);
var borderColor = teamInfo.Color == 0x455 ? LabelColor32 : BlackColor32;
var nameColor = teamInfo.Color switch
@ -1096,6 +1111,7 @@ public class BRBoardGump : Gump
};
AddBorderedText(
ref builder,
60,
65 + i * 75,
250,
@ -1105,50 +1121,52 @@ public class BRBoardGump : Gump
borderColor
);
AddBorderedText(50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32);
AddBorderedText(50 + 15, 105 + i * 75, 100, 20, teamInfo.Score.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 50 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Score:N0}", 0xFFC000, BlackColor32);
AddBorderedText(110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32);
AddBorderedText(110 + 15, 105 + i * 75, 100, 20, teamInfo.Kills.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 110 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Kills:N0}", 0xFFC000, BlackColor32);
AddBorderedText(160 + 10, 85 + i * 75, 100, 20, "Points:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 160 + 10, 85 + i * 75, 100, 20, "Points:", 0xFFC000, BlackColor32);
AddBorderedText(
ref builder,
160 + 15,
105 + i * 75,
100,
20,
teamInfo.Captures.ToString("N0"),
$"{teamInfo.Captures:N0}",
0xFFC000,
BlackColor32
);
var pl = teamInfo.Leader;
AddBorderedText(235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32);
if (pl != null)
{
AddBorderedText(235 + 15, 105 + i * 75, 250, 20, pl.Player.Name, 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 235 + 15, 105 + i * 75, 250, 20, pl.Player.Name, 0xFFC000, BlackColor32);
}
}
}
AddButton(314, height - 42, 247, 248, 1);
builder.AddButton(314, height - 42, 247, 248, 1);
}
private void AddBorderedText(int x, int y, int width, int height, string text, int color, int borderColor)
private static void AddBorderedText(
ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color, int borderColor
)
{
AddColoredText(x - 1, y - 1, width, height, text, borderColor);
AddColoredText(x - 1, y + 1, width, height, text, borderColor);
AddColoredText(x + 1, y - 1, width, height, text, borderColor);
AddColoredText(x + 1, y + 1, width, height, text, borderColor);
AddColoredText(x, y, width, height, text, color);
AddColoredText(ref builder, x - 1, y - 1, width, height, text, borderColor);
AddColoredText(ref builder, x - 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x + 1, y - 1, width, height, text, borderColor);
AddColoredText(ref builder, x + 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x, y, width, height, text, color);
}
private void AddColoredText(int x, int y, int width, int height, string text, int color)
{
AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
}
private static void AddColoredText(
ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color
) => builder.AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
}
public sealed class BRPlayerInfo : IRankedCTF, IComparable<BRPlayerInfo>
@ -1297,10 +1315,7 @@ public sealed class BRTeamInfo : IRankedCTF, IComparable<BRTeamInfo>
set
{
m_Goal = value;
if (m_Goal != null)
{
m_Goal.Team = this;
}
m_Goal?.Team = this;
}
}
@ -1338,15 +1353,9 @@ public sealed class BRTeamInfo : IRankedCTF, IComparable<BRTeamInfo>
Players.Clear();
if (Board != null)
{
Board.m_TeamInfo = this;
}
Board?.m_TeamInfo = this;
if (m_Goal != null)
{
m_Goal.Team = this;
}
m_Goal?.Team = this;
}
public void Serialize(IGenericWriter op)
@ -1362,15 +1371,7 @@ public sealed class BRTeamInfo : IRankedCTF, IComparable<BRTeamInfo>
op.Write(m_Goal);
}
public override string ToString()
{
if (TeamName != null)
{
return $"({Name}) ...";
}
return "...";
}
public override string ToString() => TeamName != null ? $"({Name}) ..." : "...";
}
public sealed class BRController : EventController
@ -1640,7 +1641,7 @@ public sealed class BRGame : EventGame
}
}
mob.SendGump(new BRBoardGump(mob, this));
BRBoardGump.DisplayTo(mob, this);
m_Context.Requip(mob, corpse);
DelayBounce(TimeSpan.FromSeconds(30.0), mob, corpse);
@ -1839,7 +1840,7 @@ public sealed class BRGame : EventGame
if (dp?.Mobile != null)
{
dp.Mobile.SendGump(new BRBoardGump(dp.Mobile, this));
BRBoardGump.DisplayTo(dp.Mobile, this);
}
}
@ -1852,10 +1853,7 @@ public sealed class BRGame : EventGame
{
for (var j = 0; j < p.Players.Length; ++j)
{
if (p.Players[j] != null)
{
p.Players[j].Eliminated = true;
}
p.Players[j]?.Eliminated = true;
}
}
}
@ -1872,10 +1870,7 @@ public sealed class BRGame : EventGame
{
var teamInfo = Controller.TeamInfo[i];
if (teamInfo.Board != null)
{
teamInfo.Board.m_TeamInfo = null;
}
teamInfo.Board?.m_TeamInfo = null;
teamInfo.Game = null;
}

View file

@ -24,34 +24,51 @@ public sealed partial class CTFBoard : Item
{
if (m_TeamInfo?.Game != null)
{
from.SendGump(new CTFBoardGump(from, m_TeamInfo.Game));
CTFBoardGump.DisplayTo(from, m_TeamInfo.Game);
}
}
}
public class CTFBoardGump : Gump
public class CTFBoardGump : DynamicGump
{
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000000;
private CTFGame m_Game;
private readonly Mobile _mob;
private readonly CTFGame _game;
private readonly CTFTeamInfo _section;
public override bool Singleton => true;
public CTFBoardGump(Mobile mob, CTFGame game, CTFTeamInfo section = null)
private CTFBoardGump(Mobile mob, CTFGame game, CTFTeamInfo section)
: base(60, 60)
{
m_Game = game;
_mob = mob;
_game = game;
_section = section;
}
var ourTeam = game.GetTeamInfo(mob);
public static void DisplayTo(Mobile mob, CTFGame game, CTFTeamInfo section = null)
{
if (mob?.NetState == null || game == null)
{
return;
}
mob.SendGump(new CTFBoardGump(mob, game, section));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
var ourTeam = _game.GetTeamInfo(_mob);
var entries = new List<IRankedCTF>();
if (section == null)
if (_section == null)
{
for (var i = 0; i < game.Context.Participants.Count; ++i)
for (var i = 0; i < _game.Context.Participants.Count; ++i)
{
var teamInfo = game.Controller.TeamInfo[i % 8];
var teamInfo = _game.Controller.TeamInfo[i % 8];
if (teamInfo?.Flag == null)
{
@ -63,7 +80,7 @@ public class CTFBoardGump : Gump
}
else
{
foreach (var player in section.Players.Values)
foreach (var player in _section.Players.Values)
{
if (player.Score > 0)
{
@ -76,51 +93,48 @@ public class CTFBoardGump : Gump
var height = 0;
if (section == null)
if (_section == null)
{
height = 73 + entries.Count * 75 + 28;
}
Closable = false;
builder.SetNoClose();
AddPage(0);
builder.AddPage();
AddBackground(1, 1, 398, height, 3600);
builder.AddBackground(1, 1, 398, height, 3600);
AddImageTiled(16, 15, 369, height - 29, 3604);
builder.AddImageTiled(16, 15, 369, height - 29, 3604);
for (var i = 0; i < entries.Count; i += 1)
{
AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430);
builder.AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430);
}
AddAlphaRegion(16, 15, 369, height - 29);
builder.AddAlphaRegion(16, 15, 369, height - 29);
AddImage(215, -45, 0xEE40);
// AddImage( 330, 141, 0x8BA );
builder.AddImage(215, -45, 0xEE40);
AddBorderedText(22, 22, 294, 20, "CTF Scoreboard".Center(), LabelColor32, BlackColor32);
AddBorderedText(ref builder, 22, 22, 294, 20, "CTF Scoreboard".Center(), LabelColor32, BlackColor32);
AddImageTiled(32, 50, 264, 1, 9107);
AddImageTiled(42, 52, 264, 1, 9157);
builder.AddImageTiled(32, 50, 264, 1, 9107);
builder.AddImageTiled(42, 52, 264, 1, 9157);
if (section == null)
if (_section == null)
{
for (var i = 0; i < entries.Count; ++i)
{
var teamInfo = entries[i] as CTFTeamInfo;
if (teamInfo == null)
if (entries[i] is not CTFTeamInfo teamInfo)
{
continue;
}
AddImage(30, 70 + i * 75, 10152);
AddImage(30, 85 + i * 75, 10151);
AddImage(30, 100 + i * 75, 10151);
AddImage(30, 106 + i * 75, 10154);
builder.AddImage(30, 70 + i * 75, 10152);
builder.AddImage(30, 85 + i * 75, 10151);
builder.AddImage(30, 100 + i * 75, 10151);
builder.AddImage(30, 106 + i * 75, 10154);
AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1);
builder.AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1);
var borderColor = teamInfo.Color == 0x455 ? LabelColor32 : BlackColor32;
var nameColor = teamInfo.Color switch
@ -136,6 +150,7 @@ public class CTFBoardGump : Gump
};
AddBorderedText(
ref builder,
60,
65 + i * 75,
250,
@ -145,49 +160,50 @@ public class CTFBoardGump : Gump
borderColor
);
AddBorderedText(50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32);
AddBorderedText(50 + 15, 105 + i * 75, 100, 20, teamInfo.Score.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 50 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Score:N0}", 0xFFC000, BlackColor32);
AddBorderedText(110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32);
AddBorderedText(110 + 15, 105 + i * 75, 100, 20, teamInfo.Kills.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 110 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Kills:N0}", 0xFFC000, BlackColor32);
AddBorderedText(160 + 10, 85 + i * 75, 100, 20, "Captures:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 160 + 10, 85 + i * 75, 100, 20, "Captures:", 0xFFC000, BlackColor32);
AddBorderedText(
ref builder,
160 + 15,
105 + i * 75,
100,
20,
teamInfo.Captures.ToString("N0"),
$"{teamInfo.Captures:N0}",
0xFFC000,
BlackColor32
);
var pl = teamInfo.Leader;
AddBorderedText(235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32);
if (pl != null)
{
AddBorderedText(235 + 15, 105 + i * 75, 250, 20, pl.Player.Name, 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 235 + 15, 105 + i * 75, 250, 20, pl.Player.Name, 0xFFC000, BlackColor32);
}
}
}
AddButton(314, height - 42, 247, 248, 1);
builder.AddButton(314, height - 42, 247, 248, 1);
}
private void AddBorderedText(int x, int y, int width, int height, string text, int color, int borderColor)
private static void AddBorderedText(ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color, int borderColor)
{
AddColoredText(x - 1, y - 1, width, height, text, borderColor);
AddColoredText(x - 1, y + 1, width, height, text, borderColor);
AddColoredText(x + 1, y - 1, width, height, text, borderColor);
AddColoredText(x + 1, y + 1, width, height, text, borderColor);
AddColoredText(x, y, width, height, text, color);
AddColoredText(ref builder, x - 1, y - 1, width, height, text, borderColor);
AddColoredText(ref builder, x - 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x + 1, y - 1, width, height, text, borderColor);
AddColoredText(ref builder, x + 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x, y, width, height, text, color);
}
private void AddColoredText(int x, int y, int width, int height, string text, int color)
private static void AddColoredText(ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color)
{
AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
builder.AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
}
}
@ -249,10 +265,7 @@ public sealed partial class CTFFlag : Item
{
var playerInfo = useTeam[from];
if (playerInfo != null)
{
playerInfo.Score += 4; // return
}
playerInfo?.Score += 4; // return
m_Returner = from;
m_ReturnTime = Core.Now;
@ -401,10 +414,7 @@ public sealed partial class CTFFlag : Item
{
var assistInfo = useTeam[teamFlag.m_Fragger];
if (assistInfo != null)
{
assistInfo.Score += 6; // frag assist
}
assistInfo?.Score += 6; // frag assist
}
if (teamFlag.m_Returner != null &&
@ -412,10 +422,7 @@ public sealed partial class CTFFlag : Item
{
var assistInfo = useTeam[teamFlag.m_Returner];
if (assistInfo != null)
{
assistInfo.Score += 4; // return assist
}
assistInfo?.Score += 4; // return assist
}
}
}
@ -481,10 +488,7 @@ public sealed partial class CTFFlag : Item
var mob = FindOwner(parent);
if (mob != null)
{
mob.SolidHueOverride = 0x4001;
}
mob?.SolidHueOverride = 0x4001;
}
public override void OnRemoved(IEntity parent)
@ -493,10 +497,7 @@ public sealed partial class CTFFlag : Item
var mob = FindOwner(parent);
if (mob != null)
{
mob.SolidHueOverride = m_TeamInfo?.Game.GetColor(mob) ?? -1;
}
mob?.SolidHueOverride = m_TeamInfo?.Game.GetColor(mob) ?? -1;
}
}
@ -671,10 +672,7 @@ public sealed class CTFTeamInfo : IRankedCTF
Flag.SendHome();
}
if (Board != null)
{
Board.m_TeamInfo = this;
}
Board?.m_TeamInfo = this;
}
public void Serialize(IGenericWriter op)
@ -852,10 +850,7 @@ public sealed class CTFGame : EventGame
for (var j = 0; j < p.Players.Length; ++j)
{
if (p.Players[j] != null)
{
p.Players[j].Mobile.SendMessage(0x35, text);
}
p.Players[j]?.Mobile.SendMessage(0x35, text);
}
}
}
@ -908,10 +903,7 @@ public sealed class CTFGame : EventGame
{
for (var i = 0; i < p.Players.Length; ++i)
{
if (p.Players[i] != null)
{
p.Players[i].Mobile.SolidHueOverride = hueOverride;
}
p.Players[i]?.Mobile.SolidHueOverride = hueOverride;
}
}
@ -1025,7 +1017,7 @@ public sealed class CTFGame : EventGame
}
}
mob.SendGump(new CTFBoardGump(mob, this));
CTFBoardGump.DisplayTo(mob, this);
m_Context.Requip(mob, corpse);
DelayBounce(TimeSpan.FromSeconds(30.0), mob, corpse);
@ -1224,7 +1216,7 @@ public sealed class CTFGame : EventGame
if (dp?.Mobile != null)
{
dp.Mobile.SendGump(new CTFBoardGump(dp.Mobile, this));
CTFBoardGump.DisplayTo(dp.Mobile, this);
}
}
@ -1260,10 +1252,7 @@ public sealed class CTFGame : EventGame
teamInfo.Flag.m_TeamInfo = null;
}
if (teamInfo.Board != null)
{
teamInfo.Board.m_TeamInfo = null;
}
teamInfo.Board?.m_TeamInfo = null;
teamInfo.Game = null;
}

View file

@ -22,32 +22,51 @@ public sealed partial class DDBoard : Item
{
if (m_TeamInfo?.Game != null)
{
from.SendGump(new DDBoardGump(from, m_TeamInfo.Game));
DDBoardGump.DisplayTo(from, m_TeamInfo.Game);
}
}
}
public class DDBoardGump : Gump
public class DDBoardGump : DynamicGump
{
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000000;
private readonly Mobile _mob;
private readonly DDGame _game;
private readonly DDTeamInfo _section;
public override bool Singleton => true;
public DDBoardGump(Mobile mob, DDGame game, DDTeamInfo section = null)
private DDBoardGump(Mobile mob, DDGame game, DDTeamInfo section)
: base(60, 60)
{
// m_Game = game;
_mob = mob;
_game = game;
_section = section;
}
var ourTeam = game.GetTeamInfo(mob);
public static void DisplayTo(Mobile mob, DDGame game, DDTeamInfo section = null)
{
if (mob?.NetState == null || game == null)
{
return;
}
mob.SendGump(new DDBoardGump(mob, game, section));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
var ourTeam = _game.GetTeamInfo(_mob);
var entries = new List<IRankedCTF>();
if (section == null)
if (_section == null)
{
for (var i = 0; i < game.Context.Participants.Count; ++i)
for (var i = 0; i < _game.Context.Participants.Count; ++i)
{
var teamInfo = game.Controller.TeamInfo[i % game.Controller.TeamInfo.Length];
var teamInfo = _game.Controller.TeamInfo[i % _game.Controller.TeamInfo.Length];
if (teamInfo != null)
{
@ -57,7 +76,7 @@ public class DDBoardGump : Gump
}
else
{
foreach (var player in section.Players.Values)
foreach (var player in _section.Players.Values)
{
if (player.Score > 0)
{
@ -70,35 +89,34 @@ public class DDBoardGump : Gump
var height = 0;
if (section == null)
if (_section == null)
{
height = 73 + entries.Count * 75 + 28;
}
Closable = false;
builder.SetNoClose();
AddPage(0);
builder.AddPage();
AddBackground(1, 1, 398, height, 3600);
builder.AddBackground(1, 1, 398, height, 3600);
AddImageTiled(16, 15, 369, height - 29, 3604);
builder.AddImageTiled(16, 15, 369, height - 29, 3604);
for (var i = 0; i < entries.Count; i += 1)
{
AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430);
builder.AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430);
}
AddAlphaRegion(16, 15, 369, height - 29);
builder.AddAlphaRegion(16, 15, 369, height - 29);
AddImage(215, -45, 0xEE40);
// AddImage( 330, 141, 0x8BA );
builder.AddImage(215, -45, 0xEE40);
AddBorderedText(22, 22, 294, 20, "DD Scoreboard".Center(), LabelColor32, BlackColor32);
AddBorderedText(ref builder, 22, 22, 294, 20, "DD Scoreboard".Center(), LabelColor32, BlackColor32);
AddImageTiled(32, 50, 264, 1, 9107);
AddImageTiled(42, 52, 264, 1, 9157);
builder.AddImageTiled(32, 50, 264, 1, 9107);
builder.AddImageTiled(42, 52, 264, 1, 9157);
if (section == null)
if (_section == null)
{
for (var i = 0; i < entries.Count; ++i)
{
@ -107,12 +125,12 @@ public class DDBoardGump : Gump
continue;
}
AddImage(30, 70 + i * 75, 10152);
AddImage(30, 85 + i * 75, 10151);
AddImage(30, 100 + i * 75, 10151);
AddImage(30, 106 + i * 75, 10154);
builder.AddImage(30, 70 + i * 75, 10152);
builder.AddImage(30, 85 + i * 75, 10151);
builder.AddImage(30, 100 + i * 75, 10151);
builder.AddImage(30, 106 + i * 75, 10154);
AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1);
builder.AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1);
var borderColor = teamInfo.Color == 0x455 ? LabelColor32 : BlackColor32;
var nameColor = teamInfo.Color switch
@ -128,6 +146,7 @@ public class DDBoardGump : Gump
};
AddBorderedText(
ref builder,
60,
65 + i * 75,
250,
@ -137,49 +156,50 @@ public class DDBoardGump : Gump
borderColor
);
AddBorderedText(50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32);
AddBorderedText(50 + 15, 105 + i * 75, 100, 20, teamInfo.Score.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 50 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Score:N0}", 0xFFC000, BlackColor32);
AddBorderedText(110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32);
AddBorderedText(110 + 15, 105 + i * 75, 100, 20, teamInfo.Kills.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 110 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Kills:N0}", 0xFFC000, BlackColor32);
AddBorderedText(160 + 10, 85 + i * 75, 100, 20, "Captures:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 160 + 10, 85 + i * 75, 100, 20, "Captures:", 0xFFC000, BlackColor32);
AddBorderedText(
ref builder,
160 + 15,
105 + i * 75,
100,
20,
teamInfo.Captures.ToString("N0"),
$"{teamInfo.Captures:N0}",
0xFFC000,
BlackColor32
);
var pl = teamInfo.Leader;
AddBorderedText(235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32);
if (pl != null)
{
AddBorderedText(235 + 15, 105 + i * 75, 250, 20, pl.Player.Name, 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 235 + 15, 105 + i * 75, 250, 20, pl.Player.Name, 0xFFC000, BlackColor32);
}
}
}
AddButton(314, height - 42, 247, 248, 1);
builder.AddButton(314, height - 42, 247, 248, 1);
}
private void AddBorderedText(int x, int y, int width, int height, string text, int color, int borderColor)
private static void AddBorderedText(ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color, int borderColor)
{
AddColoredText(x - 1, y - 1, width, height, text, borderColor);
AddColoredText(x - 1, y + 1, width, height, text, borderColor);
AddColoredText(x + 1, y - 1, width, height, text, borderColor);
AddColoredText(x + 1, y + 1, width, height, text, borderColor);
AddColoredText(x, y, width, height, text, color);
AddColoredText(ref builder, x - 1, y - 1, width, height, text, borderColor);
AddColoredText(ref builder, x - 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x + 1, y - 1, width, height, text, borderColor);
AddColoredText(ref builder, x + 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x, y, width, height, text, color);
}
private void AddColoredText(int x, int y, int width, int height, string text, int color)
private static void AddColoredText(ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color)
{
AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
builder.AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
}
}
@ -324,10 +344,7 @@ public sealed class DDTeamInfo : IRankedCTF
Players.Clear();
if (Board != null)
{
Board.m_TeamInfo = this;
}
Board?.m_TeamInfo = this;
}
public void Serialize(IGenericWriter op)
@ -462,10 +479,7 @@ public sealed class DDGame : EventGame
for (var j = 0; j < p.Players.Length; ++j)
{
if (p.Players[j] != null)
{
p.Players[j].Mobile.SendMessage(0x35, text);
}
p.Players[j]?.Mobile.SendMessage(0x35, text);
}
}
}
@ -508,10 +522,7 @@ public sealed class DDGame : EventGame
{
for (var i = 0; i < p.Players.Length; ++i)
{
if (p.Players[i] != null)
{
p.Players[i].Mobile.SolidHueOverride = hueOverride;
}
p.Players[i]?.Mobile.SolidHueOverride = hueOverride;
}
}
@ -578,14 +589,11 @@ public sealed class DDGame : EventGame
}
playerInfo = victInfo[mob];
if (playerInfo != null)
{
playerInfo.Score -= 1;
}
playerInfo?.Score -= 1;
}
}
mob.SendGump(new DDBoardGump(mob, this));
DDBoardGump.DisplayTo(mob, this);
m_Context.Requip(mob, corpse);
DelayBounce(TimeSpan.FromSeconds(30.0), mob, corpse);
@ -608,15 +616,9 @@ public sealed class DDGame : EventGame
teamInfo.Reset();
}
if (Controller.PointA != null)
{
Controller.PointA.Game = this;
}
Controller.PointA?.Game = this;
if (Controller.PointB != null)
{
Controller.PointB.Game = this;
}
Controller.PointB?.Game = this;
for (var i = 0; i < m_Context.Participants.Count; ++i)
{
@ -800,7 +802,7 @@ public sealed class DDGame : EventGame
if (dp?.Mobile != null)
{
dp.Mobile.SendGump(new DDBoardGump(dp.Mobile, this));
DDBoardGump.DisplayTo(dp.Mobile, this);
}
}
@ -811,10 +813,7 @@ public sealed class DDGame : EventGame
for (var j = 0; j < p.Players.Length; ++j)
{
if (p.Players[j] != null)
{
p.Players[j].Eliminated = true;
}
p.Players[j]?.Eliminated = true;
}
}
@ -830,23 +829,14 @@ public sealed class DDGame : EventGame
{
var teamInfo = Controller.TeamInfo[i];
if (teamInfo.Board != null)
{
teamInfo.Board.m_TeamInfo = null;
}
teamInfo.Board?.m_TeamInfo = null;
teamInfo.Game = null;
}
if (Controller.PointA != null)
{
Controller.PointA.Game = null;
}
Controller.PointA?.Game = null;
if (Controller.PointB != null)
{
Controller.PointB.Game = null;
}
Controller.PointB?.Game = null;
m_Capturable = false;

View file

@ -275,7 +275,7 @@ public partial class KHBoard : Item
{
if (m_Game != null)
{
from.SendGump(new KHBoardGump(from, m_Game));
KHBoardGump.DisplayTo(from, m_Game);
}
else
{
@ -284,27 +284,41 @@ public partial class KHBoard : Item
}
}
public sealed class KHBoardGump : Gump
public sealed class KHBoardGump : DynamicGump
{
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000000;
private KHGame m_Game;
private readonly Mobile _mob;
private readonly KHGame _game;
public override bool Singleton => true;
public KHBoardGump(Mobile mob, KHGame game)
: base(60, 60)
private KHBoardGump(Mobile mob, KHGame game) : base(60, 60)
{
m_Game = game;
_mob = mob;
_game = game;
}
var ourTeam = game.GetTeamInfo(mob);
public static void DisplayTo(Mobile mob, KHGame game)
{
if (mob?.NetState == null || game == null)
{
return;
}
mob.SendGump(new KHBoardGump(mob, game));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
var ourTeam = _game.GetTeamInfo(_mob);
var entries = new List<KHTeamInfo>();
for (var i = 0; i < game.Context.Participants.Count; ++i)
for (var i = 0; i < _game.Context.Participants.Count; ++i)
{
var teamInfo = game.Controller.TeamInfo[i % game.Controller.TeamInfo.Length];
var teamInfo = _game.Controller.TeamInfo[i % _game.Controller.TeamInfo.Length];
if (teamInfo != null)
{
@ -313,47 +327,41 @@ public sealed class KHBoardGump : Gump
}
entries.Sort();
/*
delegate( IRankedCTF a, IRankedCTF b )
{
return b.Score - a.Score;
} );*/
var height = 73 + entries.Count * 75 + 28;
Closable = false;
builder.SetNoClose();
AddPage(0);
builder.AddPage();
AddBackground(1, 1, 398, height, 3600);
builder.AddBackground(1, 1, 398, height, 3600);
AddImageTiled(16, 15, 369, height - 29, 3604);
builder.AddImageTiled(16, 15, 369, height - 29, 3604);
for (var i = 0; i < entries.Count; i += 1)
{
AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430);
builder.AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430);
}
AddAlphaRegion(16, 15, 369, height - 29);
builder.AddAlphaRegion(16, 15, 369, height - 29);
AddImage(215, -45, 0xEE40);
// AddImage( 330, 141, 0x8BA );
builder.AddImage(215, -45, 0xEE40);
AddBorderedText(22, 22, 294, 20, "King of the Hill Scoreboard".Center(), LabelColor32, BlackColor32);
AddBorderedText(ref builder, 22, 22, 294, 20, "King of the Hill Scoreboard".Center(), LabelColor32, BlackColor32);
AddImageTiled(32, 50, 264, 1, 9107);
AddImageTiled(42, 52, 264, 1, 9157);
builder.AddImageTiled(32, 50, 264, 1, 9107);
builder.AddImageTiled(42, 52, 264, 1, 9157);
for (var i = 0; i < entries.Count; ++i)
{
var teamInfo = entries[i];
AddImage(30, 70 + i * 75, 10152);
AddImage(30, 85 + i * 75, 10151);
AddImage(30, 100 + i * 75, 10151);
AddImage(30, 106 + i * 75, 10154);
builder.AddImage(30, 70 + i * 75, 10152);
builder.AddImage(30, 85 + i * 75, 10151);
builder.AddImage(30, 100 + i * 75, 10151);
builder.AddImage(30, 106 + i * 75, 10154);
AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1);
builder.AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1);
var borderColor = teamInfo.Color == 0x455 ? LabelColor32 : BlackColor32;
var nameColor = teamInfo.Color switch
@ -369,6 +377,7 @@ public sealed class KHBoardGump : Gump
};
AddBorderedText(
ref builder,
60,
65 + i * 75,
250,
@ -378,36 +387,36 @@ public sealed class KHBoardGump : Gump
borderColor
);
AddBorderedText(50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32);
AddBorderedText(50 + 15, 105 + i * 75, 100, 20, teamInfo.Score.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 50 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Score:N0}", 0xFFC000, BlackColor32);
AddBorderedText(110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32);
AddBorderedText(110 + 15, 105 + i * 75, 100, 20, teamInfo.Kills.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 110 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Kills:N0}", 0xFFC000, BlackColor32);
AddBorderedText(160 + 10, 85 + i * 75, 100, 20, "Captures:", 0xFFC000, BlackColor32);
AddBorderedText(160 + 15, 105 + i * 75, 100, 20, teamInfo.Captures.ToString("N0"), 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 160 + 10, 85 + i * 75, 100, 20, "Captures:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 160 + 15, 105 + i * 75, 100, 20, $"{teamInfo.Captures:N0}", 0xFFC000, BlackColor32);
var leader = teamInfo.Leader?.Name ?? "(none)";
AddBorderedText(235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32);
AddBorderedText(235 + 15, 105 + i * 75, 250, 20, leader, 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32);
AddBorderedText(ref builder, 235 + 15, 105 + i * 75, 250, 20, leader, 0xFFC000, BlackColor32);
}
AddButton(314, height - 42, 247, 248, 1);
builder.AddButton(314, height - 42, 247, 248, 1);
}
private void AddBorderedText(int x, int y, int width, int height, string text, int color, int borderColor)
private static void AddBorderedText(ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color, int borderColor)
{
AddColoredText(x - 1, y - 1, width, height, text, borderColor);
AddColoredText(x - 1, y + 1, width, height, text, borderColor);
AddColoredText(x + 1, y - 1, width, height, text, borderColor);
AddColoredText(x + 1, y + 1, width, height, text, borderColor);
AddColoredText(x, y, width, height, text, color);
AddColoredText(ref builder, x - 1, y - 1, width, height, text, borderColor);
AddColoredText(ref builder, x - 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x + 1, y - 1, width, height, text, borderColor);
AddColoredText(ref builder, x + 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x, y, width, height, text, color);
}
private void AddColoredText(int x, int y, int width, int height, string text, int color)
private static void AddColoredText(ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color)
{
AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
builder.AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
}
}
@ -803,10 +812,7 @@ public sealed class KHGame : EventGame
for (var j = 0; j < p.Players.Length; ++j)
{
if (p.Players[j] != null)
{
p.Players[j].Mobile.SendMessage(0x35, text);
}
p.Players[j]?.Mobile.SendMessage(0x35, text);
}
}
}
@ -849,10 +855,7 @@ public sealed class KHGame : EventGame
{
for (var i = 0; i < p.Players.Length; ++i)
{
if (p.Players[i] != null)
{
p.Players[i].Mobile.SolidHueOverride = hueOverride;
}
p.Players[i]?.Mobile.SolidHueOverride = hueOverride;
}
}
@ -929,7 +932,7 @@ public sealed class KHGame : EventGame
}
}
mob.SendGump(new KHBoardGump(mob, this));
KHBoardGump.DisplayTo(mob, this);
m_Context.Requip(mob, corpse);
DelayBounce(TimeSpan.FromSeconds(30.0), mob, corpse);
@ -957,10 +960,7 @@ public sealed class KHGame : EventGame
for (var i = 0; i < Controller.Hills.Length; i++)
{
if (Controller.Hills[i] != null)
{
Controller.Hills[i].Game = this;
}
Controller.Hills[i]?.Game = this;
}
foreach (var board in Controller.Boards)
@ -1139,7 +1139,7 @@ public sealed class KHGame : EventGame
if (dp?.Mobile != null)
{
dp.Mobile.SendGump(new KHBoardGump(dp.Mobile, this));
KHBoardGump.DisplayTo(dp.Mobile, this);
}
}
@ -1152,10 +1152,7 @@ public sealed class KHGame : EventGame
{
for (var j = 0; j < p.Players.Length; ++j)
{
if (p.Players[j] != null)
{
p.Players[j].Eliminated = true;
}
p.Players[j]?.Eliminated = true;
}
}
}
@ -1175,18 +1172,12 @@ public sealed class KHGame : EventGame
for (var i = 0; i < Controller.Hills.Length; ++i)
{
if (Controller.Hills[i] != null)
{
Controller.Hills[i].Game = null;
}
Controller.Hills[i]?.Game = null;
}
foreach (var board in Controller.Boards)
{
if (board != null)
{
board.m_Game = null;
}
board?.m_Game = null;
}
for (var i = 0; i < m_Context.Participants.Count; ++i)