perf: Migrates ConPVP lobby gumps from legacy Gump. (#2423)

## Summary

Migrates 14 ConPVP lobby/tournament gumps from legacy `Gump` to modern `DynamicGump`/`StaticGump<T>`. Layouts move into `BuildLayout(ref DynamicGumpBuilder)`, constructors become private, and validation moves into static `DisplayTo` entry points (empty-gump rule).

**Per-gump base type decisions:**

- `BeginGump` → `StaticGump<BeginGump>`: layout is fully fixed (no dynamic content). All other gumps below are `DynamicGump` because they bake dynamic player names, guild abbreviations, ruleset titles, arena names, tournament participant names, ladder rankings, or per-instance rule modifications. Per the cliloc/dynamic-text rule, dynamic content forces `DynamicGump`.
- `ReadyGump`, `ReadyUpGump` → `DynamicGump` (per-instance participant rosters).
- `AcceptDuelGump`, `AcceptTeamGump`, `ConfirmSignupGump` → `DynamicGump` (challenger/registrar/team names, dynamic rule modifications).
- `PickRulesetGump`, `RulesetGump` → `DynamicGump` (ruleset titles and option labels per instance).
- `ParticipantGump`, `DuelContextGump` → `DynamicGump` (player rosters/team labels).
- `LadderGump` → `DynamicGump` (ladder entries: ranks, levels, guild abbrs, names, wins/losses).
- `ArenaGump` → `DynamicGump` (arena names with active player names).
- `PreferencesGump` → `DynamicGump` (arena name list).
- `TournamentBracketGump` (~1k LOC) → `DynamicGump`. The whole gump is one type-switched view that re-renders on every button press across `Index`, `Rules_Info`, `Participant_List`, `Participant_Info`, `Round_List`, `Round_Info`, `Match_Info`, `Player_Info`. All branches bake per-instance content.

**Refresh-via-this conversions (the big perf wins):**

- `LadderGump`: page +/- now mutates `_page` and calls `from.SendGump(this)` instead of allocating a new `LadderGump`.
- `PickRulesetGump`: ruleset apply / flavor toggle now refreshes via `this`.
- `ParticipantGump`: increase/decrease team size, remove player, target failure all refresh via `this`.
- `DuelContextGump`: failed-start and add-participant refresh via `this`.
- `ConfirmSignupGump`: every signup-validation rejection branch in `OnResponse` and every `AddPlayer_OnTarget` rejection branch refreshes via `this` (was allocating a new gump per branch).
- `TournamentBracketGump`: every navigation button (back/forward, type change, page change, drill-down) mutates `_type`/`_object`/`_list`/`_page` and refreshes via `this`. Previously each click allocated a new 1k LOC gump.

All gumps are `Singleton`, use private constructors with static `DisplayTo` entry points that null-check `NetState` before allocation. External callers in `DuelContext`, `TournamentBracketItem`, `TournamentController`, `TournamentSignupItem`, and the cross-references between `AcceptDuelGump`/`ParticipantGump`/`AcceptTeamGump`/`ConfirmSignupGump` are all updated to use `DisplayTo`. Legacy `m_X` fields renamed to `_x` per coding standards.
This commit is contained in:
Kamron Batman 2026-05-03 01:06:04 -07:00 committed by GitHub
parent 9c2ac2b8ea
commit a74c7f9d4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 3203 additions and 3226 deletions

View file

@ -4,314 +4,319 @@ using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class AcceptDuelGump : DynamicGump
{
public class AcceptDuelGump : Gump
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000008;
private static readonly Dictionary<Mobile, List<IgnoreEntry>> _ignoreLists = new();
private readonly Mobile _challenged;
private readonly Mobile _challenger;
private readonly DuelContext _context;
private readonly Participant _participant;
private readonly int _slot;
private bool _active = true;
public override bool Singleton => true;
private AcceptDuelGump(Mobile challenger, Mobile challenged, DuelContext context, Participant p, int slot)
: base(50, 50)
{
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000008;
_challenger = challenger;
_challenged = challenged;
_context = context;
_participant = p;
_slot = slot;
private static readonly Dictionary<Mobile, List<IgnoreEntry>> m_IgnoreLists =
new();
Timer.StartTimer(TimeSpan.FromSeconds(15.0), AutoReject);
}
private readonly Mobile m_Challenged;
private readonly Mobile m_Challenger;
private readonly DuelContext m_Context;
private readonly Participant m_Participant;
private readonly int m_Slot;
private bool m_Active = true;
public override bool Singleton => true;
public AcceptDuelGump(Mobile challenger, Mobile challenged, DuelContext context, Participant p, int slot) : base(
50,
50
)
public static void DisplayTo(Mobile challenger, Mobile challenged, DuelContext context, Participant p, int slot)
{
if (challenged?.NetState == null || challenger == null || context == null || p == null)
{
m_Challenger = challenger;
m_Challenged = challenged;
m_Context = context;
m_Participant = p;
m_Slot = slot;
Closable = false;
AddPage(0);
// AddBackground( 0, 0, 400, 220, 9150 );
AddBackground(1, 1, 398, 218, 3600);
// AddBackground( 16, 15, 369, 189, 9100 );
AddImageTiled(16, 15, 369, 189, 3604);
AddAlphaRegion(16, 15, 369, 189);
AddImage(215, -43, 0xEE40);
// AddImage( 330, 141, 0x8BA );
var duelChallengeBlack = "Duel Challenge".Center(BlackColor32);
AddHtml(22 - 1, 22, 294, 20, duelChallengeBlack);
AddHtml(22 + 1, 22, 294, 20, duelChallengeBlack);
AddHtml(22, 22 - 1, 294, 20, duelChallengeBlack);
AddHtml(22, 22 + 1, 294, 20, duelChallengeBlack);
AddHtml(22, 22, 294, 20, "Duel Challenge".Center(LabelColor32));
var accept = p.Contains(challenger)
? $"You have been asked to join sides with {challenger.Name} in a duel. Do you accept?"
: $"You have been challenged to a duel from {challenger.Name}. Do you accept?";
var acceptBlack = accept.Color(BlackColor32);
AddHtml(22 - 1, 50, 294, 40, acceptBlack);
AddHtml(22 + 1, 50, 294, 40, acceptBlack);
AddHtml(22, 50 - 1, 294, 40, acceptBlack);
AddHtml(22, 50 + 1, 294, 40, acceptBlack);
AddHtml(22, 50, 294, 40, accept.Color(0xB0C868));
AddImageTiled(32, 88, 264, 1, 9107);
AddImageTiled(42, 90, 264, 1, 9157);
var yesBlack = "Yes, I will fight this duel.".Color(BlackColor32);
AddRadio(24, 100, 9727, 9730, true, 1);
AddHtml(60 - 1, 105, 250, 20, yesBlack);
AddHtml(60 + 1, 105, 250, 20, yesBlack);
AddHtml(60, 105 - 1, 250, 20, yesBlack);
AddHtml(60, 105 + 1, 250, 20, yesBlack);
AddHtml(60, 105, 250, 20, "Yes, I will fight this duel.".Color(LabelColor32));
var noBlack = "No, I do not wish to fight.".Color(BlackColor32);
AddRadio(24, 135, 9727, 9730, false, 2);
AddHtml(60 - 1, 140, 250, 20, noBlack);
AddHtml(60 + 1, 140, 250, 20, noBlack);
AddHtml(60, 140 - 1, 250, 20, noBlack);
AddHtml(60, 140 + 1, 250, 20, noBlack);
AddHtml(60, 140, 250, 20, "No, I do not wish to fight.".Color(LabelColor32));
var noAskBlack = "No, knave. Do not ask again.".Color(BlackColor32);
AddRadio(24, 170, 9727, 9730, false, 3);
AddHtml(60 - 1, 175, 250, 20, noAskBlack);
AddHtml(60 + 1, 175, 250, 20, noAskBlack);
AddHtml(60, 175 - 1, 250, 20, noAskBlack);
AddHtml(60, 175 + 1, 250, 20, noAskBlack);
AddHtml(60, 175, 250, 20, "No, knave. Do not ask again.".Color(LabelColor32));
AddButton(314, 173, 247, 248, 1);
Timer.StartTimer(TimeSpan.FromSeconds(15.0), AutoReject);
return;
}
public void AutoReject()
challenged.SendGump(new AcceptDuelGump(challenger, challenged, context, p, slot));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
builder.SetNoClose();
builder.AddPage();
builder.AddBackground(1, 1, 398, 218, 3600);
builder.AddImageTiled(16, 15, 369, 189, 3604);
builder.AddAlphaRegion(16, 15, 369, 189);
builder.AddImage(215, -43, 0xEE40);
var duelChallengeBlack = "Duel Challenge".Center(BlackColor32);
builder.AddHtml(22 - 1, 22, 294, 20, duelChallengeBlack);
builder.AddHtml(22 + 1, 22, 294, 20, duelChallengeBlack);
builder.AddHtml(22, 22 - 1, 294, 20, duelChallengeBlack);
builder.AddHtml(22, 22 + 1, 294, 20, duelChallengeBlack);
builder.AddHtml(22, 22, 294, 20, "Duel Challenge".Center(LabelColor32));
var accept = _participant.Contains(_challenger)
? $"You have been asked to join sides with {_challenger.Name} in a duel. Do you accept?"
: $"You have been challenged to a duel from {_challenger.Name}. Do you accept?";
var acceptBlack = accept.Color(BlackColor32);
builder.AddHtml(22 - 1, 50, 294, 40, acceptBlack);
builder.AddHtml(22 + 1, 50, 294, 40, acceptBlack);
builder.AddHtml(22, 50 - 1, 294, 40, acceptBlack);
builder.AddHtml(22, 50 + 1, 294, 40, acceptBlack);
builder.AddHtml(22, 50, 294, 40, accept.Color(0xB0C868));
builder.AddImageTiled(32, 88, 264, 1, 9107);
builder.AddImageTiled(42, 90, 264, 1, 9157);
var yesBlack = "Yes, I will fight this duel.".Color(BlackColor32);
builder.AddRadio(24, 100, 9727, 9730, true, 1);
builder.AddHtml(60 - 1, 105, 250, 20, yesBlack);
builder.AddHtml(60 + 1, 105, 250, 20, yesBlack);
builder.AddHtml(60, 105 - 1, 250, 20, yesBlack);
builder.AddHtml(60, 105 + 1, 250, 20, yesBlack);
builder.AddHtml(60, 105, 250, 20, "Yes, I will fight this duel.".Color(LabelColor32));
var noBlack = "No, I do not wish to fight.".Color(BlackColor32);
builder.AddRadio(24, 135, 9727, 9730, false, 2);
builder.AddHtml(60 - 1, 140, 250, 20, noBlack);
builder.AddHtml(60 + 1, 140, 250, 20, noBlack);
builder.AddHtml(60, 140 - 1, 250, 20, noBlack);
builder.AddHtml(60, 140 + 1, 250, 20, noBlack);
builder.AddHtml(60, 140, 250, 20, "No, I do not wish to fight.".Color(LabelColor32));
var noAskBlack = "No, knave. Do not ask again.".Color(BlackColor32);
builder.AddRadio(24, 170, 9727, 9730, false, 3);
builder.AddHtml(60 - 1, 175, 250, 20, noAskBlack);
builder.AddHtml(60 + 1, 175, 250, 20, noAskBlack);
builder.AddHtml(60, 175 - 1, 250, 20, noAskBlack);
builder.AddHtml(60, 175 + 1, 250, 20, noAskBlack);
builder.AddHtml(60, 175, 250, 20, "No, knave. Do not ask again.".Color(LabelColor32));
builder.AddButton(314, 173, 247, 248, 1);
}
public void AutoReject()
{
if (!_active)
{
if (!m_Active)
return;
}
_active = false;
_challenged.CloseGump<AcceptDuelGump>();
_challenger.SendMessage($"{_challenged.Name} seems unresponsive.");
_challenged.SendMessage("You decline the challenge.");
}
public static void BeginIgnore(Mobile source, Mobile toIgnore)
{
if (!_ignoreLists.TryGetValue(source, out var list))
{
_ignoreLists[source] = list = new List<IgnoreEntry>();
}
for (var i = 0; i < list.Count; ++i)
{
var ie = list[i];
if (ie.Ignored == toIgnore)
{
ie.Refresh();
return;
}
m_Active = false;
m_Challenged.CloseGump<AcceptDuelGump>();
m_Challenger.SendMessage($"{m_Challenged.Name} seems unresponsive.");
m_Challenged.SendMessage("You decline the challenge.");
if (ie.Expired)
{
list.RemoveAt(i--);
}
}
public static void BeginIgnore(Mobile source, Mobile toIgnore)
list.Add(new IgnoreEntry(toIgnore));
}
public static bool IsIgnored(Mobile source, Mobile check)
{
if (!_ignoreLists.TryGetValue(source, out var list))
{
if (!m_IgnoreLists.TryGetValue(source, out var list))
{
m_IgnoreLists[source] = list = new List<IgnoreEntry>();
}
for (var i = 0; i < list.Count; ++i)
{
var ie = list[i];
if (ie.Ignored == toIgnore)
{
ie.Refresh();
return;
}
if (ie.Expired)
{
list.RemoveAt(i--);
}
}
list.Add(new IgnoreEntry(toIgnore));
}
public static bool IsIgnored(Mobile source, Mobile check)
{
if (!m_IgnoreLists.TryGetValue(source, out var list))
{
return false;
}
for (var i = 0; i < list.Count; ++i)
{
var ie = list[i];
if (ie.Expired)
{
list.RemoveAt(i--);
}
else if (ie.Ignored == check)
{
return true;
}
}
return false;
}
public override void OnResponse(NetState sender, in RelayInfo info)
for (var i = 0; i < list.Count; ++i)
{
if (info.ButtonID != 1 || !m_Active || !m_Context.Registered)
var ie = list[i];
if (ie.Expired)
{
list.RemoveAt(i--);
}
else if (ie.Ignored == check)
{
return true;
}
}
return false;
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (info.ButtonID != 1 || !_active || !_context.Registered)
{
return;
}
_active = false;
if (!_context.Participants.Contains(_participant))
{
return;
}
if (info.IsSwitched(1))
{
if (_challenged is not PlayerMobile pm)
{
return;
}
m_Active = false;
if (!m_Context.Participants.Contains(m_Participant))
if (pm.DuelContext != null)
{
return;
}
if (info.IsSwitched(1))
{
if (m_Challenged is not PlayerMobile pm)
if (pm.DuelContext.Initiator == pm)
{
return;
}
if (pm.DuelContext != null)
{
if (pm.DuelContext.Initiator == pm)
{
pm.SendMessage(0x22, "You have already started a duel.");
}
else
{
pm.SendMessage(0x22, "You have already been challenged in a duel.");
}
m_Challenger.SendMessage($"{pm.Name} cannot fight because they are already assigned to another duel.");
}
else if (DuelContext.CheckCombat(pm))
{
pm.SendMessage(
0x22,
"You have recently been in combat with another player and must wait before starting a duel."
);
m_Challenger.SendMessage(
$"{pm.Name} cannot fight because they have recently been in combat with another player."
);
}
else if (TournamentController.IsActive)
{
pm.SendMessage(0x22, "A tournament is currently active and you may not duel.");
m_Challenger.SendMessage(0x22, "A tournament is currently active and you may not duel.");
pm.SendMessage(0x22, "You have already started a duel.");
}
else
{
var added = false;
if (m_Slot >= 0 && m_Slot < m_Participant.Players.Length && m_Participant.Players[m_Slot] == null)
{
added = true;
m_Participant.Players[m_Slot] = new DuelPlayer(m_Challenged, m_Participant);
}
else
{
for (var i = 0; i < m_Participant.Players.Length; ++i)
{
if (m_Participant.Players[i] == null)
{
added = true;
m_Participant.Players[i] = new DuelPlayer(m_Challenged, m_Participant);
break;
}
}
}
if (added)
{
m_Challenger.SendMessage($"{m_Challenged.Name} has accepted the request.");
m_Challenged.SendMessage($"You have accepted the request from {m_Challenger.Name}.");
foreach (var g in m_Challenger.GetGumps())
{
if (g is ParticipantGump pg && pg.Participant == m_Participant)
{
m_Challenger.SendGump(new ParticipantGump(m_Challenger, m_Context, m_Participant));
break;
}
if (g is DuelContextGump dcg && dcg.Context == m_Context)
{
m_Challenger.SendGump(new DuelContextGump(m_Challenger, m_Context));
break;
}
}
}
else
{
m_Challenger.SendMessage(
$"The participant list was full and so {m_Challenged.Name} could not join."
);
if (m_Participant.Contains(m_Challenger))
{
m_Challenged.SendMessage($"The participant list was full and so you could not join the fight with {m_Challenger.Name}.");
}
else
{
m_Challenged.SendMessage($"The participant list was full and so you could not join the fight against {m_Challenger.Name}.");
}
}
pm.SendMessage(0x22, "You have already been challenged in a duel.");
}
_challenger.SendMessage($"{pm.Name} cannot fight because they are already assigned to another duel.");
}
else if (DuelContext.CheckCombat(pm))
{
pm.SendMessage(
0x22,
"You have recently been in combat with another player and must wait before starting a duel."
);
_challenger.SendMessage(
$"{pm.Name} cannot fight because they have recently been in combat with another player."
);
}
else if (TournamentController.IsActive)
{
pm.SendMessage(0x22, "A tournament is currently active and you may not duel.");
_challenger.SendMessage(0x22, "A tournament is currently active and you may not duel.");
}
else
{
if (info.IsSwitched(3))
{
BeginIgnore(m_Challenged, m_Challenger);
}
var added = false;
m_Challenger.SendMessage($"{m_Challenged.Name} does not wish to fight.");
if (m_Participant.Contains(m_Challenger))
if (_slot >= 0 && _slot < _participant.Players.Length && _participant.Players[_slot] == null)
{
m_Challenged.SendMessage($"You chose not to fight with {m_Challenger.Name}.");
added = true;
_participant.Players[_slot] = new DuelPlayer(_challenged, _participant);
}
else
{
m_Challenged.SendMessage($"You chose not to fight against {m_Challenger.Name}.");
for (var i = 0; i < _participant.Players.Length; ++i)
{
if (_participant.Players[i] == null)
{
added = true;
_participant.Players[i] = new DuelPlayer(_challenged, _participant);
break;
}
}
}
if (added)
{
_challenger.SendMessage($"{_challenged.Name} has accepted the request.");
_challenged.SendMessage($"You have accepted the request from {_challenger.Name}.");
foreach (var g in _challenger.GetGumps())
{
if (g is ParticipantGump pg && pg.Participant == _participant)
{
ParticipantGump.DisplayTo(_challenger, _context, _participant);
break;
}
if (g is DuelContextGump dcg && dcg.Context == _context)
{
DuelContextGump.DisplayTo(_challenger, _context);
break;
}
}
}
else
{
_challenger.SendMessage(
$"The participant list was full and so {_challenged.Name} could not join."
);
if (_participant.Contains(_challenger))
{
_challenged.SendMessage($"The participant list was full and so you could not join the fight with {_challenger.Name}.");
}
else
{
_challenged.SendMessage($"The participant list was full and so you could not join the fight against {_challenger.Name}.");
}
}
}
}
private class IgnoreEntry
else
{
private static readonly TimeSpan ExpireDelay = TimeSpan.FromMinutes(15.0);
public readonly Mobile m_Ignored;
public DateTime m_Expire;
public IgnoreEntry(Mobile ignored)
if (info.IsSwitched(3))
{
m_Ignored = ignored;
Refresh();
BeginIgnore(_challenged, _challenger);
}
public Mobile Ignored => m_Ignored;
public bool Expired => Core.Now >= m_Expire;
_challenger.SendMessage($"{_challenged.Name} does not wish to fight.");
public void Refresh() => m_Expire = Core.Now + ExpireDelay;
if (_participant.Contains(_challenger))
{
_challenged.SendMessage($"You chose not to fight with {_challenger.Name}.");
}
else
{
_challenged.SendMessage($"You chose not to fight against {_challenger.Name}.");
}
}
}
private class IgnoreEntry
{
private static readonly TimeSpan ExpireDelay = TimeSpan.FromMinutes(15.0);
private DateTime _expire;
public IgnoreEntry(Mobile ignored)
{
Ignored = ignored;
Refresh();
}
public Mobile Ignored { get; }
public bool Expired => Core.Now >= _expire;
public void Refresh() => _expire = Core.Now + ExpireDelay;
}
}

View file

@ -1307,19 +1307,19 @@ public partial class DuelContext
{
if (dc.m_Tournament == null)
{
pm.SendGump(new ReadyGump(pm, dc, dc.ReadyCount));
ReadyGump.DisplayTo(pm, dc, dc.ReadyCount);
}
}
else if (dc.ReadyWait && !dc.StartedBeginCountdown && !dc.Started && !dc.Finished)
{
if (dc.m_Tournament == null)
{
pm.SendGump(new ReadyUpGump(pm, dc));
ReadyUpGump.DisplayTo(pm, dc);
}
}
else if (dc.Initiator == pm && !dc.ReadyWait && !dc.StartedBeginCountdown && !dc.Started && !dc.Finished)
{
pm.SendGump(new DuelContextGump(pm, dc));
DuelContextGump.DisplayTo(pm, dc);
}
}
@ -1418,7 +1418,7 @@ public partial class DuelContext
}
else
{
pm.SendGump(new DuelContextGump(pm, new DuelContext(pm, RulesetLayout.Root)));
DuelContextGump.DisplayTo(pm, new DuelContext(pm, RulesetLayout.Root));
e.Handled = true;
}
}
@ -1433,7 +1433,7 @@ public partial class DuelContext
if (prefs != null)
{
e.Mobile.SendGump(new PreferencesGump(e.Mobile, prefs));
PreferencesGump.DisplayTo(e.Mobile, prefs);
}
}
}
@ -1547,13 +1547,13 @@ public partial class DuelContext
{
if (g is ParticipantGump pg && pg.Participant == p)
{
init.SendGump(new ParticipantGump(init, dc, p));
ParticipantGump.DisplayTo(init, dc, p);
break;
}
if (g is DuelContextGump dcg && dcg.Context == dc)
{
init.SendGump(new DuelContextGump(init, dc));
DuelContextGump.DisplayTo(init, dc);
break;
}
}
@ -1582,14 +1582,14 @@ public partial class DuelContext
{
if (g is ParticipantGump pg && pg.Participant == p)
{
init.SendGump(new ParticipantGump(init, dc, p));
ParticipantGump.DisplayTo(init, dc, p);
send = false;
break;
}
if (g is DuelContextGump dcg && dcg.Context == dc)
{
init.SendGump(new DuelContextGump(init, dc));
DuelContextGump.DisplayTo(init, dc);
send = false;
break;
}
@ -1597,7 +1597,7 @@ public partial class DuelContext
if (send)
{
init.SendGump(new DuelContextGump(init, dc));
DuelContextGump.DisplayTo(init, dc);
}
}
}
@ -1626,14 +1626,14 @@ public partial class DuelContext
{
if (g is ParticipantGump pg && pg.Participant == p)
{
init.SendGump(new ParticipantGump(init, dc, p));
ParticipantGump.DisplayTo(init, dc, p);
send = false;
break;
}
if (g is DuelContextGump dcg && dcg.Context == dc)
{
init.SendGump(new DuelContextGump(init, dc));
DuelContextGump.DisplayTo(init, dc);
send = false;
break;
}
@ -1641,7 +1641,7 @@ public partial class DuelContext
if (send)
{
init.SendGump(new DuelContextGump(init, dc));
DuelContextGump.DisplayTo(init, dc);
}
}
}
@ -1801,7 +1801,7 @@ public partial class DuelContext
}
else if (!m_Yielding)
{
Initiator.SendGump(new DuelContextGump(Initiator, this));
DuelContextGump.DisplayTo(Initiator, this);
}
ReadyWait = false;
@ -2195,7 +2195,7 @@ public partial class DuelContext
gumps.Close<ReadyGump>();
gumps.Close<ReadyUpGump>();
gumps.Close<BeginGump>();
gumps.Send(new BeginGump(count));
BeginGump.DisplayTo(mob, count);
}
mob.Frozen = true;
@ -2254,7 +2254,7 @@ public partial class DuelContext
if (mob != null && m_Tournament == null)
{
mob.SendGump(new ReadyUpGump(mob, this), true);
ReadyUpGump.DisplayTo(mob, this);
}
}
}
@ -2509,7 +2509,7 @@ public partial class DuelContext
{
if (m_Tournament == null)
{
mob.SendGump(new ReadyGump(mob, this, count), true);
ReadyGump.DisplayTo(mob, this, count);
}
}
else

View file

@ -6,421 +6,434 @@ using Server.Mobiles;
using Server.Network;
using Server.Text;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class AcceptTeamGump : DynamicGump
{
public class AcceptTeamGump : Gump
private const int BlackColor32 = 0x000008;
private const int LabelColor32 = 0xFFFFFF;
private readonly Mobile _from;
private readonly List<Mobile> _players;
private readonly Mobile _registrar;
private readonly Mobile _requested;
private readonly Tournament _tournament;
private bool _active;
public override bool Singleton => true;
private AcceptTeamGump(
Mobile from, Mobile requested, Tournament tourney, Mobile registrar, List<Mobile> players
) : base(50, 50)
{
private const int BlackColor32 = 0x000008;
private const int LabelColor32 = 0xFFFFFF;
_from = from;
_requested = requested;
_tournament = tourney;
_registrar = registrar;
_players = players;
private readonly Mobile m_From;
private readonly List<Mobile> m_Players;
private readonly Mobile m_Registrar;
private readonly Mobile m_Requested;
private readonly Tournament m_Tournament;
private bool m_Active;
_active = true;
public AcceptTeamGump(
Mobile from, Mobile requested, Tournament tourney, Mobile registrar, List<Mobile> players
) : base(50, 50)
Timer.StartTimer(TimeSpan.FromSeconds(15.0), AutoReject);
}
public static void DisplayTo(Mobile from, Mobile requested, Tournament tourney, Mobile registrar, List<Mobile> players)
{
if (requested?.NetState != null && from != null && tourney != null && players != null)
{
m_From = from;
m_Requested = requested;
m_Tournament = tourney;
m_Registrar = registrar;
m_Players = players;
requested.SendGump(new AcceptTeamGump(from, requested, tourney, registrar, players));
}
}
m_Active = true;
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
builder.SetNoClose();
var ruleset = tourney.Ruleset;
var basedef = ruleset.Base;
var ruleset = _tournament.Ruleset;
var basedef = ruleset.Base;
var height = 185 + 35 + 60 + 12;
var height = 185 + 35 + 60 + 12;
var changes = 0;
var changes = 0;
BitArray defs;
BitArray defs;
if (ruleset.Flavors.Count > 0)
if (ruleset.Flavors.Count > 0)
{
defs = new BitArray(basedef.Options);
for (var i = 0; i < ruleset.Flavors.Count; ++i)
{
defs = new BitArray(basedef.Options);
defs.Or(ruleset.Flavors[i].Options);
}
for (var i = 0; i < ruleset.Flavors.Count; ++i)
height += ruleset.Flavors.Count * 18;
}
else
{
defs = basedef.Options;
}
var opts = ruleset.Options;
for (var i = 0; i < opts.Length; ++i)
{
if (defs[i] != opts[i])
{
++changes;
}
}
height += changes * 22;
height += 10 + 22 + 25 + 25;
builder.AddPage();
builder.AddBackground(1, 1, 398, height, 3600);
builder.AddImageTiled(16, 15, 369, height - 29, 3604);
builder.AddAlphaRegion(16, 15, 369, height - 29);
builder.AddImage(215, -43, 0xEE40);
using var sb = new ValueStringBuilder(stackalloc char[64]);
if (_tournament.TourneyType == TourneyType.FreeForAll)
{
sb.Append("FFA");
}
else if (_tournament.TourneyType == TourneyType.RandomTeam)
{
sb.Append($"{_tournament.ParticipantsPerMatch}-Team");
}
else if (_tournament.TourneyType == TourneyType.Faction)
{
sb.Append($"{_tournament.ParticipantsPerMatch}-Team Faction");
}
else if (_tournament.TourneyType == TourneyType.RedVsBlue)
{
sb.Append("Red v Blue");
}
else
{
for (var i = 0; i < _tournament.ParticipantsPerMatch; ++i)
{
if (sb.Length > 0)
{
defs.Or(ruleset.Flavors[i].Options);
sb.Append('v');
}
height += ruleset.Flavors.Count * 18;
}
else
{
defs = basedef.Options;
sb.Append(_tournament.PlayersPerParticipant);
}
}
var opts = ruleset.Options;
if (_tournament.EventController != null)
{
sb.Append($" {_tournament.EventController.Title}");
}
sb.Append(" Tournament Invitation");
AddBorderedText(ref builder, 22, 22, 294, 20, sb.AsSpan().Center(), LabelColor32, BlackColor32);
AddBorderedText(
ref builder,
22,
50,
294,
40,
$"You have been asked to partner with {_from.Name} in a tournament. Do you accept?",
0xB0C868,
BlackColor32
);
builder.AddImageTiled(32, 88, 264, 1, 9107);
builder.AddImageTiled(42, 90, 264, 1, 9157);
var y = 100;
var groupText = _tournament.GroupType switch
{
GroupingType.HighVsLow => "High vs Low",
GroupingType.Nearest => "Closest opponent",
GroupingType.Random => "Random",
_ => null
};
AddBorderedText(ref builder, 35, y, 190, 20, $"Grouping: {groupText}", LabelColor32, BlackColor32);
y += 20;
var tieText = _tournament.TieType switch
{
TieType.Random => "Random",
TieType.Highest => "Highest advances",
TieType.Lowest => "Lowest advances",
TieType.FullAdvancement => _tournament.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances",
TieType.FullElimination => _tournament.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated",
_ => null
};
AddBorderedText(ref builder, 35, y, 190, 20, $"Tiebreaker: {tieText}", LabelColor32, BlackColor32);
y += 20;
string sdText;
if (_tournament.SuddenDeath > TimeSpan.Zero)
{
sdText = _tournament.SuddenDeathRounds > 0 ?
$"Sudden Death: {(int)_tournament.SuddenDeath.TotalMinutes}:{_tournament.SuddenDeath.Seconds:D2} (first {_tournament.SuddenDeathRounds} rounds)" :
$"Sudden Death: {(int)_tournament.SuddenDeath.TotalMinutes}:{_tournament.SuddenDeath.Seconds:D2} (all rounds)";
}
else
{
sdText = "Sudden Death: Off";
}
AddBorderedText(ref builder, 35, y, 240, 20, sdText, LabelColor32, BlackColor32);
y += 20;
y += 6;
builder.AddImageTiled(32, y - 1, 264, 1, 9107);
builder.AddImageTiled(42, y + 1, 264, 1, 9157);
y += 6;
AddBorderedText(ref builder, 35, y, 190, 20, $"Ruleset: {basedef.Title}", LabelColor32, BlackColor32);
y += 20;
for (var i = 0; i < ruleset.Flavors.Count; ++i, y += 18)
{
AddBorderedText(ref builder, 35, y, 190, 20, $" + {ruleset.Flavors[i].Title}", LabelColor32, BlackColor32);
}
y += 4;
if (changes > 0)
{
AddBorderedText(ref builder, 35, y, 190, 20, "Modifications:", LabelColor32, BlackColor32);
y += 20;
for (var i = 0; i < opts.Length; ++i)
{
if (defs[i] != opts[i])
{
++changes;
}
}
var name = ruleset.Layout.FindByIndex(i);
height += changes * 22;
height += 10 + 22 + 25 + 25;
Closable = false;
AddPage(0);
AddBackground(1, 1, 398, height, 3600);
AddImageTiled(16, 15, 369, height - 29, 3604);
AddAlphaRegion(16, 15, 369, height - 29);
AddImage(215, -43, 0xEE40);
using var sb = new ValueStringBuilder(stackalloc char[64]);
if (tourney.TourneyType == TourneyType.FreeForAll)
{
sb.Append("FFA");
}
else if (tourney.TourneyType == TourneyType.RandomTeam)
{
sb.Append($"{tourney.ParticipantsPerMatch}-Team");
}
else if (tourney.TourneyType == TourneyType.Faction)
{
sb.Append($"{tourney.ParticipantsPerMatch}-Team Faction");
}
else if (tourney.TourneyType == TourneyType.RedVsBlue)
{
sb.Append("Red v Blue");
}
else
{
for (var i = 0; i < tourney.ParticipantsPerMatch; ++i)
{
if (sb.Length > 0)
if (name != null) // sanity
{
sb.Append('v');
builder.AddImage(35, y, opts[i] ? 0xD3 : 0xD2);
AddBorderedText(ref builder, 60, y, 165, 22, name, LabelColor32, BlackColor32);
}
sb.Append(tourney.PlayersPerParticipant);
y += 22;
}
}
}
else
{
AddBorderedText(ref builder, 35, y, 190, 20, "Modifications: None", LabelColor32, BlackColor32);
y += 20;
}
if (tourney.EventController != null)
{
sb.Append($" {tourney.EventController.Title}");
}
y += 8;
builder.AddImageTiled(32, y - 1, 264, 1, 9107);
builder.AddImageTiled(42, y + 1, 264, 1, 9157);
y += 8;
sb.Append(" Tournament Invitation");
builder.AddRadio(24, y, 9727, 9730, true, 1);
AddBorderedText(ref builder, 60, y + 5, 250, 20, "Yes, I will join them.", LabelColor32, BlackColor32);
y += 35;
AddBorderedText(22, 22, 294, 20, sb.AsSpan().Center(), LabelColor32, BlackColor32);
builder.AddRadio(24, y, 9727, 9730, false, 2);
AddBorderedText(ref builder, 60, y + 5, 250, 20, "No, I do not wish to fight.", LabelColor32, BlackColor32);
y += 35;
AddBorderedText(
22,
50,
294,
40,
$"You have been asked to partner with {from.Name} in a tournament. Do you accept?",
0xB0C868,
BlackColor32
builder.AddRadio(24, y, 9727, 9730, false, 3);
AddBorderedText(ref builder, 60, y + 5, 270, 20, "No, most certainly not. Do not ask again.", LabelColor32, BlackColor32);
y += 35;
y -= 3;
builder.AddButton(314, y, 247, 248, 1);
}
private static void AddBorderedText(ref DynamicGumpBuilder builder, int x, int y, int width, int height, string text, int color, int 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 + 1, y + 1, width, height, text, borderColor);
AddColoredText(ref builder, x, y, width, height, text, 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 void AutoReject()
{
if (!_active)
{
return;
}
_active = false;
_requested.CloseGump<AcceptTeamGump>();
ConfirmSignupGump.DisplayTo(_from, _registrar, _tournament, _players);
if (_registrar != null)
{
_registrar.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
$"{_requested.Name} seems unresponsive.",
_from.NetState
);
AddImageTiled(32, 88, 264, 1, 9107);
AddImageTiled(42, 90, 264, 1, 9157);
_registrar.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
$"You have declined the partnership with {_from.Name}.",
_requested.NetState
);
}
}
var y = 100;
public override void OnResponse(NetState sender, in RelayInfo info)
{
var from = _from;
var mob = _requested;
var groupText = tourney.GroupType switch
{
GroupingType.HighVsLow => "High vs Low",
GroupingType.Nearest => "Closest opponent",
GroupingType.Random => "Random",
_ => null
};
AddBorderedText(35, y, 190, 20, $"Grouping: {groupText}", LabelColor32, BlackColor32);
y += 20;
var tieText = tourney.TieType switch
{
TieType.Random => "Random",
TieType.Highest => "Highest advances",
TieType.Lowest => "Lowest advances",
TieType.FullAdvancement => tourney.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances",
TieType.FullElimination => tourney.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated",
_ => null
};
AddBorderedText(35, y, 190, 20, $"Tiebreaker: {tieText}", LabelColor32, BlackColor32);
y += 20;
string sdText;
if (tourney.SuddenDeath > TimeSpan.Zero)
{
sdText = tourney.SuddenDeathRounds > 0 ?
$"Sudden Death: {(int)tourney.SuddenDeath.TotalMinutes}:{tourney.SuddenDeath.Seconds:D2} (first {tourney.SuddenDeathRounds} rounds)" :
$"Sudden Death: {(int)tourney.SuddenDeath.TotalMinutes}:{tourney.SuddenDeath.Seconds:D2} (all rounds)";
}
else
{
sdText = "Sudden Death: Off";
}
AddBorderedText(35, y, 240, 20, sdText, LabelColor32, BlackColor32);
y += 20;
y += 6;
AddImageTiled(32, y - 1, 264, 1, 9107);
AddImageTiled(42, y + 1, 264, 1, 9157);
y += 6;
AddBorderedText(35, y, 190, 20, $"Ruleset: {basedef.Title}", LabelColor32, BlackColor32);
y += 20;
for (var i = 0; i < ruleset.Flavors.Count; ++i, y += 18)
{
AddBorderedText(35, y, 190, 20, $" + {ruleset.Flavors[i].Title}", LabelColor32, BlackColor32);
}
y += 4;
if (changes > 0)
{
AddBorderedText(35, y, 190, 20, "Modifications:", LabelColor32, BlackColor32);
y += 20;
for (var i = 0; i < opts.Length; ++i)
{
if (defs[i] != opts[i])
{
var name = ruleset.Layout.FindByIndex(i);
if (name != null) // sanity
{
AddImage(35, y, opts[i] ? 0xD3 : 0xD2);
AddBorderedText(60, y, 165, 22, name, LabelColor32, BlackColor32);
}
y += 22;
}
}
}
else
{
AddBorderedText(35, y, 190, 20, "Modifications: None", LabelColor32, BlackColor32);
y += 20;
}
y += 8;
AddImageTiled(32, y - 1, 264, 1, 9107);
AddImageTiled(42, y + 1, 264, 1, 9157);
y += 8;
AddRadio(24, y, 9727, 9730, true, 1);
AddBorderedText(60, y + 5, 250, 20, "Yes, I will join them.", LabelColor32, BlackColor32);
y += 35;
AddRadio(24, y, 9727, 9730, false, 2);
AddBorderedText(60, y + 5, 250, 20, "No, I do not wish to fight.", LabelColor32, BlackColor32);
y += 35;
AddRadio(24, y, 9727, 9730, false, 3);
AddBorderedText(60, y + 5, 270, 20, "No, most certainly not. Do not ask again.", LabelColor32, BlackColor32);
y += 35;
y -= 3;
AddButton(314, y, 247, 248, 1);
Timer.StartTimer(TimeSpan.FromSeconds(15.0), AutoReject);
if (info.ButtonID != 1 || !_active)
{
return;
}
private void AddBorderedText(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);
}
_active = false;
private void AddColoredText(int x, int y, int width, int height, string text, int color)
if (info.IsSwitched(1))
{
AddHtml(x, y, width, height, color == 0 ? text : text.Color(color));
}
public void AutoReject()
{
if (!m_Active)
if (mob is not PlayerMobile pm)
{
return;
}
m_Active = false;
m_Requested.CloseGump<AcceptTeamGump>();
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
if (m_Registrar != null)
if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
{
m_Registrar.PrivateOverheadMessage(
ConfirmSignupGump.DisplayTo(_from, _registrar, _tournament, _players);
_registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
$"{m_Requested.Name} seems unresponsive.",
m_From.NetState
"They ignore your invitation.",
from.NetState
);
}
else if (pm.DuelContext != null)
{
ConfirmSignupGump.DisplayTo(_from, _registrar, _tournament, _players);
m_Registrar.PrivateOverheadMessage(
_registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
$"You have declined the partnership with {m_From.Name}.",
m_Requested.NetState
"They are already assigned to another duel.",
from.NetState
);
}
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
var from = m_From;
var mob = m_Requested;
if (info.ButtonID != 1 || !m_Active)
else if (_players.Contains(mob))
{
return;
ConfirmSignupGump.DisplayTo(_from, _registrar, _tournament, _players);
_registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
"You have already named them as a team member.",
from.NetState
);
}
m_Active = false;
if (info.IsSwitched(1))
else if (_tournament.HasParticipant(mob))
{
if (mob is not PlayerMobile pm)
{
return;
}
ConfirmSignupGump.DisplayTo(_from, _registrar, _tournament, _players);
if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
_registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
"They have already entered this tournament.",
from.NetState
);
}
else if (_players.Count >= _tournament.PlayersPerParticipant)
{
ConfirmSignupGump.DisplayTo(_from, _registrar, _tournament, _players);
m_Registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
"They ignore your invitation.",
from.NetState
);
}
else if (pm.DuelContext != null)
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
m_Registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
"They are already assigned to another duel.",
from.NetState
);
}
else if (m_Players.Contains(mob))
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
m_Registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
"You have already named them as a team member.",
from.NetState
);
}
else if (m_Tournament.HasParticipant(mob))
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
m_Registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
"They have already entered this tournament.",
from.NetState
);
}
else if (m_Players.Count >= m_Tournament.PlayersPerParticipant)
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
m_Registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
"Your team is full.",
from.NetState
);
}
else
{
m_Players.Add(mob);
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
if (m_Registrar != null)
{
m_Registrar.PrivateOverheadMessage(
MessageType.Regular,
0x59,
false,
$"{mob.Name} has accepted your offer of partnership.",
from.NetState
);
m_Registrar.PrivateOverheadMessage(
MessageType.Regular,
0x59,
false,
$"You have accepted the partnership with {from.Name}.",
mob.NetState
);
}
}
_registrar?.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
"Your team is full.",
from.NetState
);
}
else
{
if (info.IsSwitched(3))
{
AcceptDuelGump.BeginIgnore(m_Requested, m_From);
}
_players.Add(mob);
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
ConfirmSignupGump.DisplayTo(_from, _registrar, _tournament, _players);
if (m_Registrar != null)
if (_registrar != null)
{
m_Registrar.PrivateOverheadMessage(
_registrar.PrivateOverheadMessage(
MessageType.Regular,
0x22,
0x59,
false,
$"{mob.Name} has declined your offer of partnership.",
$"{mob.Name} has accepted your offer of partnership.",
from.NetState
);
m_Registrar.PrivateOverheadMessage(
_registrar.PrivateOverheadMessage(
MessageType.Regular,
0x22,
0x59,
false,
$"You have declined the partnership with {from.Name}.",
$"You have accepted the partnership with {from.Name}.",
mob.NetState
);
}
}
}
else
{
if (info.IsSwitched(3))
{
AcceptDuelGump.BeginIgnore(_requested, _from);
}
ConfirmSignupGump.DisplayTo(_from, _registrar, _tournament, _players);
if (_registrar != null)
{
_registrar.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
$"{mob.Name} has declined your offer of partnership.",
from.NetState
);
_registrar.PrivateOverheadMessage(
MessageType.Regular,
0x22,
false,
$"You have declined the partnership with {from.Name}.",
mob.NetState
);
}
}
}
}

View file

@ -33,7 +33,7 @@ public partial class ArenasMoongate : Item
return false;
}
from.SendGump(new ArenaGump(from, this));
ArenaGump.DisplayTo(from, this);
if (!from.Hidden || from.AccessLevel == AccessLevel.Player)
{
@ -58,44 +58,55 @@ public partial class ArenasMoongate : Item
public override bool OnMoveOver(Mobile m) => !m.Player || UseGate(m);
}
public class ArenaGump : Gump
public class ArenaGump : DynamicGump
{
private readonly List<Arena> m_Arenas;
private readonly Mobile m_From;
private readonly ArenasMoongate m_Gate;
private readonly List<Arena> _arenas;
private readonly ArenasMoongate _gate;
private int m_ColumnX = 12;
private int _columnX;
public override bool Singleton => true;
public ArenaGump(Mobile from, ArenasMoongate gate) : base(50, 50)
private ArenaGump(ArenasMoongate gate) : base(50, 50)
{
m_From = from;
m_Gate = gate;
m_Arenas = Arena.Arenas;
_gate = gate;
_arenas = Arena.Arenas;
}
AddPage(0);
public static void DisplayTo(Mobile from, ArenasMoongate gate)
{
if (from?.NetState != null && gate != null)
{
from.SendGump(new ArenaGump(gate));
}
}
var height = 12 + 20 + m_Arenas.Count * 31 + 24 + 12;
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
_columnX = 12;
AddBackground(0, 0, 499 + 40, height, 0x2436);
builder.AddPage();
var list = m_Arenas;
var height = 12 + 20 + _arenas.Count * 31 + 24 + 12;
builder.AddBackground(0, 0, 499 + 40, height, 0x2436);
var list = _arenas;
for (var i = 1; i < list.Count; i += 2)
{
AddImageTiled(12, 32 + i * 31, 475 + 40, 30, 0x2430);
builder.AddImageTiled(12, 32 + i * 31, 475 + 40, 30, 0x2430);
}
AddAlphaRegion(10, 10, 479 + 40, height - 20);
builder.AddAlphaRegion(10, 10, 479 + 40, height - 20);
AddColumnHeader(35, null);
AddColumnHeader(115, "Arena");
AddColumnHeader(325, "Participants");
AddColumnHeader(40, "Obs");
AddColumnHeader(ref builder, 35, null);
AddColumnHeader(ref builder, 115, "Arena");
AddColumnHeader(ref builder, 325, "Participants");
AddColumnHeader(ref builder, 40, "Obs");
AddButton(499 + 40 - 12 - 63 - 4 - 63, height - 12 - 24, 247, 248, 1);
AddButton(499 + 40 - 12 - 63, height - 12 - 24, 241, 242, 2);
builder.AddButton(499 + 40 - 12 - 63 - 4 - 63, height - 12 - 24, 247, 248, 1);
builder.AddButton(499 + 40 - 12 - 63, height - 12 - 24, 241, 242, 2);
var sb = new ValueStringBuilder(stackalloc char[256]);
@ -108,10 +119,10 @@ public class ArenaGump : Gump
var color = ar.Players.Count > 0 ? 0xCCFFCC : 0xCCCCCC;
AddRadio(x + 3, y + 1, 9727, 9730, false, i);
builder.AddRadio(x + 3, y + 1, 9727, 9730, false, i);
x += 35;
AddBorderedText(x + 5, y + 5, 115 - 5, ar.Name ?? "(no name)", color, 0);
AddBorderedText(ref builder, x + 5, y + 5, 115 - 5, ar.Name ?? "(no name)", color);
x += 115;
sb.Reset();
@ -171,16 +182,16 @@ public class ArenaGump : Gump
sb.Append("Empty");
}
AddBorderedText(x + 5, y + 5, 325 - 5, sb.ToString(), color, 0);
AddBorderedText(ref builder, x + 5, y + 5, 325 - 5, sb.ToString(), color);
x += 325;
AddBorderedText(x, y + 5, 40, Html.Center($"{ar.Spectators}"), color, 0);
AddBorderedText(ref builder, x, y + 5, 40, Html.Center($"{ar.Spectators}"), color);
}
sb.Dispose();
}
private void Append(ref ValueStringBuilder sb, LadderEntry le)
private static void Append(ref ValueStringBuilder sb, LadderEntry le)
{
if (le == null)
{
@ -211,72 +222,63 @@ public class ArenaGump : Gump
var opt = switches[0];
if (opt < 0 || opt >= m_Arenas.Count)
if (opt < 0 || opt >= _arenas.Count)
{
return;
}
var arena = m_Arenas[opt];
var arena = _arenas[opt];
var from = sender.Mobile;
if (!m_From.InRange(m_Gate.GetWorldLocation(), 1) || m_From.Map != m_Gate.Map)
if (!from.InRange(_gate.GetWorldLocation(), 1) || from.Map != _gate.Map)
{
m_From.SendLocalizedMessage(1019002); // You are too far away to use the gate.
from.SendLocalizedMessage(1019002); // You are too far away to use the gate.
}
else if (DuelContext.CheckCombat(m_From))
else if (DuelContext.CheckCombat(from))
{
m_From.SendMessage(
from.SendMessage(
0x22,
"You have recently been in combat with another player and cannot use this moongate."
);
}
else if (m_From.Spell != null)
else if (from.Spell != null)
{
m_From.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
from.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
}
else if (m_From.Map == arena.Facet && arena.Zone.Contains(m_From.Location))
else if (from.Map == arena.Facet && arena.Zone.Contains(from.Location))
{
m_From.SendLocalizedMessage(1019003); // You are already there.
from.SendLocalizedMessage(1019003); // You are already there.
}
else
{
BaseCreature.TeleportPets(m_From, arena.GateIn, arena.Facet);
BaseCreature.TeleportPets(from, arena.GateIn, arena.Facet);
m_From.Combatant = null;
m_From.Warmode = false;
m_From.Hidden = true;
from.Combatant = null;
from.Warmode = false;
from.Hidden = true;
m_From.MoveToWorld(arena.GateIn, arena.Facet);
from.MoveToWorld(arena.GateIn, arena.Facet);
Effects.PlaySound(arena.GateIn, arena.Facet, 0x1FE);
}
}
private void AddBorderedText(int x, int y, int width, string text, int color, int borderColor)
{
/*AddColoredText( x - 1, y, width, text, borderColor );
AddColoredText( x + 1, y, width, text, borderColor );
AddColoredText( x, y - 1, width, text, borderColor );
AddColoredText( x, y + 1, width, text, borderColor );*/
/*AddColoredText( x - 1, y - 1, width, text, borderColor );
AddColoredText( x + 1, y + 1, width, text, borderColor );*/
AddColoredText(x, y, width, text, color);
}
private static void AddBorderedText(ref DynamicGumpBuilder builder, int x, int y, int width, string text, int color) =>
AddColoredText(ref builder, x, y, width, text, color);
private void AddColoredText(int x, int y, int width, string text, int color)
{
AddHtml(x, y, width, 20, color == 0 ? text : text.Color(color));
}
private static void AddColoredText(ref DynamicGumpBuilder builder, int x, int y, int width, string text, int color) =>
builder.AddHtml(x, y, width, 20, color == 0 ? text : text.Color(color));
private void AddColumnHeader(int width, string name)
private void AddColumnHeader(ref DynamicGumpBuilder builder, int width, string name)
{
AddBackground(m_ColumnX, 12, width, 20, 0x242C);
AddImageTiled(m_ColumnX + 2, 14, width - 4, 16, 0x2430);
builder.AddBackground(_columnX, 12, width, 20, 0x242C);
builder.AddImageTiled(_columnX + 2, 14, width - 4, 16, 0x2430);
if (name != null)
{
AddBorderedText(m_ColumnX, 13, width, name.Center(), 0xFFFFFF, 0);
AddBorderedText(ref builder, _columnX, 13, width, name.Center(), 0xFFFFFF);
}
m_ColumnX += width;
_columnX += width;
}
}

View file

@ -1,50 +1,65 @@
using Server.Gumps;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class BeginGump : StaticGump<BeginGump>
{
public class BeginGump : Gump
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000008;
public override bool Singleton => true;
private BeginGump() : base(50, 50)
{
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000008;
}
public BeginGump(int count) : base(50, 50)
public static void DisplayTo(Mobile from, int count)
{
if (from?.NetState == null)
{
AddPage(0);
const int offset = 50;
AddBackground(1, 1, 398, 202 - offset, 3600);
AddImageTiled(16, 15, 369, 173 - offset, 3604);
AddAlphaRegion(16, 15, 369, 173 - offset);
AddImage(215, -43, 0xEE40);
var duelCountdownBlack = "Duel Countdown".Center(BlackColor32);
AddHtml(22 - 1, 22, 294, 20, duelCountdownBlack);
AddHtml(22 + 1, 22, 294, 20, duelCountdownBlack);
AddHtml(22, 22 - 1, 294, 20, duelCountdownBlack);
AddHtml(22, 22 + 1, 294, 20, duelCountdownBlack);
AddHtml(22, 22, 294, 20, "Duel Countdown".Center(LabelColor32));
var beginMessageBlack =
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends."
.Color(BlackColor32);
AddHtml(22 - 1, 50, 294, 80, beginMessageBlack);
AddHtml(22 + 1, 50, 294, 80, beginMessageBlack);
AddHtml(22, 50 - 1, 294, 80, beginMessageBlack);
AddHtml(22, 50 + 1, 294, 80, beginMessageBlack);
AddHtml(
22,
50,
294,
80,
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends."
.Color(0xFFCC66)
);
AddButton(314 - 50, 157 - offset, 247, 248, 1);
return;
}
from.SendGump(new BeginGump());
}
protected override void BuildLayout(ref StaticGumpBuilder builder)
{
builder.AddPage();
const int offset = 50;
builder.AddBackground(1, 1, 398, 202 - offset, 3600);
builder.AddImageTiled(16, 15, 369, 173 - offset, 3604);
builder.AddAlphaRegion(16, 15, 369, 173 - offset);
builder.AddImage(215, -43, 0xEE40);
var duelCountdownBlack = "Duel Countdown".Center(BlackColor32);
builder.AddHtml(22 - 1, 22, 294, 20, duelCountdownBlack);
builder.AddHtml(22 + 1, 22, 294, 20, duelCountdownBlack);
builder.AddHtml(22, 22 - 1, 294, 20, duelCountdownBlack);
builder.AddHtml(22, 22 + 1, 294, 20, duelCountdownBlack);
builder.AddHtml(22, 22, 294, 20, "Duel Countdown".Center(LabelColor32));
var beginMessageBlack =
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends."
.Color(BlackColor32);
builder.AddHtml(22 - 1, 50, 294, 80, beginMessageBlack);
builder.AddHtml(22 + 1, 50, 294, 80, beginMessageBlack);
builder.AddHtml(22, 50 - 1, 294, 80, beginMessageBlack);
builder.AddHtml(22, 50 + 1, 294, 80, beginMessageBlack);
builder.AddHtml(
22,
50,
294,
80,
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends."
.Color(0xFFCC66)
);
builder.AddButton(314 - 50, 157 - offset, 247, 248, 1);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,160 +1,165 @@
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class DuelContextGump : DynamicGump
{
public class DuelContextGump : Gump
public override bool Singleton => true;
private DuelContextGump(DuelContext context) : base(50, 50) => Context = context;
public static void DisplayTo(Mobile from, DuelContext context)
{
public override bool Singleton => true;
public DuelContextGump(Mobile from, DuelContext context) : base(50, 50)
if (from?.NetState == null || context == null)
{
From = from;
Context = context;
var gumps = from.GetGumps();
gumps.Close<RulesetGump>();
gumps.Close<ParticipantGump>();
var count = context.Participants.Count;
if (count < 3)
{
count = 3;
}
var height = 35 + 10 + 22 + 30 + 22 + 22 + 2 + count * 22 + 2 + 30;
AddPage(0);
AddBackground(0, 0, 300, height, 9250);
AddBackground(10, 10, 280, height - 20, 0xDAC);
AddHtml(35, 25, 230, 20, Center("Duel Setup"));
var x = 35;
var y = 47;
AddGoldenButtonLabeled(x, y, 1, "Rules");
y += 22;
AddGoldenButtonLabeled(x, y, 2, "Start");
y += 22;
AddGoldenButtonLabeled(x, y, 3, "Add Participant");
y += 30;
AddHtml(35, y, 230, 20, Center("Participants"));
y += 22;
for (var i = 0; i < context.Participants.Count; ++i)
{
var p = context.Participants[i];
AddGoldenButtonLabeled(
x,
y,
4 + i,
string.Format(
p.Count == 1 ? "Player {0}: {3}" : "Team {0}: {1}/{2}: {3}",
1 + i,
p.FilledSlots,
p.Count,
p.NameList
)
);
y += 22;
}
return;
}
public Mobile From { get; }
var gumps = from.GetGumps();
gumps.Close<RulesetGump>();
gumps.Close<ParticipantGump>();
public DuelContext Context { get; }
from.SendGump(new DuelContextGump(context));
}
public string Center(string text) => $"<CENTER>{text}</CENTER>";
public DuelContext Context { get; }
public void AddGoldenButton(int x, int y, int bid)
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
var count = Context.Participants.Count;
if (count < 3)
{
AddButton(x, y, 0xD2, 0xD2, bid);
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
count = 3;
}
public void AddGoldenButtonLabeled(int x, int y, int bid, string text)
var height = 35 + 10 + 22 + 30 + 22 + 22 + 2 + count * 22 + 2 + 30;
builder.AddPage();
builder.AddBackground(0, 0, 300, height, 9250);
builder.AddBackground(10, 10, 280, height - 20, 0xDAC);
builder.AddHtml(35, 25, 230, 20, Center("Duel Setup"));
var x = 35;
var y = 47;
AddGoldenButtonLabeled(ref builder, x, y, 1, "Rules");
y += 22;
AddGoldenButtonLabeled(ref builder, x, y, 2, "Start");
y += 22;
AddGoldenButtonLabeled(ref builder, x, y, 3, "Add Participant");
y += 30;
builder.AddHtml(35, y, 230, 20, Center("Participants"));
y += 22;
for (var i = 0; i < Context.Participants.Count; ++i)
{
AddGoldenButton(x, y, bid);
AddHtml(x + 25, y, 200, 20, text);
var p = Context.Participants[i];
AddGoldenButtonLabeled(
ref builder,
x,
y,
4 + i,
string.Format(
p.Count == 1 ? "Player {0}: {3}" : "Team {0}: {1}/{2}: {3}",
1 + i,
p.FilledSlots,
p.Count,
p.NameList
)
);
y += 22;
}
}
private static string Center(string text) => $"<CENTER>{text}</CENTER>";
private static void AddGoldenButton(ref DynamicGumpBuilder builder, int x, int y, int bid)
{
builder.AddButton(x, y, 0xD2, 0xD2, bid);
builder.AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
}
private static void AddGoldenButtonLabeled(ref DynamicGumpBuilder builder, int x, int y, int bid, string text)
{
AddGoldenButton(ref builder, x, y, bid);
builder.AddHtml(x + 25, y, 200, 20, text);
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (!Context.Registered)
{
return;
}
public override void OnResponse(NetState sender, in RelayInfo info)
var from = sender.Mobile;
var index = info.ButtonID;
switch (index)
{
if (!Context.Registered)
{
return;
}
var index = info.ButtonID;
switch (index)
{
case -1: // CloseGump
case -1: // CloseGump
{
break;
}
case 0: // closed
{
Context.Unregister();
break;
}
case 1: // Rules
{
PickRulesetGump.DisplayTo(from, Context, Context.Ruleset);
break;
}
case 2: // Start
{
if (Context.CheckFull())
{
break;
Context.CloseAllGumps();
Context.SendReadyUpGump();
}
case 0: // closed
else
{
Context.Unregister();
break;
from.SendMessage(
"You cannot start the duel before all participating players have been assigned."
);
from.SendGump(this); // refresh-via-this
}
case 1: // Rules
break;
}
case 3: // New Participant
{
if (Context.Participants.Count < 10)
{
// m_From.SendGump( new RulesetGump( m_From, m_Context.Ruleset, m_Context.Ruleset.Layout, m_Context ) );
From.SendGump(new PickRulesetGump(From, Context, Context.Ruleset));
break;
Context.Participants.Add(new Participant(Context, 1));
}
case 2: // Start
else
{
if (Context.CheckFull())
{
Context.CloseAllGumps();
Context.SendReadyUpGump();
// m_Context.SendReadyGump();
}
else
{
From.SendMessage(
"You cannot start the duel before all participating players have been assigned."
);
From.SendGump(new DuelContextGump(From, Context));
}
break;
from.SendMessage("The number of participating parties may not be increased further.");
}
case 3: // New Participant
from.SendGump(this); // refresh-via-this
break;
}
default: // Participant
{
index -= 4;
if (index >= 0 && index < Context.Participants.Count)
{
if (Context.Participants.Count < 10)
{
Context.Participants.Add(new Participant(Context, 1));
}
else
{
From.SendMessage("The number of participating parties may not be increased further.");
}
From.SendGump(new DuelContextGump(From, Context));
break;
ParticipantGump.DisplayTo(from, Context, Context.Participants[index]);
}
default: // Participant
{
index -= 4;
if (index >= 0 && index < Context.Participants.Count)
{
From.SendGump(new ParticipantGump(From, Context, Context.Participants[index]));
}
break;
}
}
break;
}
}
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using ModernUO.Serialization;
using Server.Collections;
using Server.Gumps;
using Server.Network;
@ -26,7 +27,7 @@ public partial class LadderItem : Item
if (ladder != null)
{
from.SendGump(new LadderGump(ladder), true);
LadderGump.DisplayTo(from, ladder);
}
}
else
@ -36,26 +37,42 @@ public partial class LadderItem : Item
}
}
public class LadderGump : Gump
public class LadderGump : DynamicGump
{
private readonly Ladder m_Ladder;
private readonly Ladder _ladder;
private readonly List<LadderEntry> m_List;
private readonly int m_Page;
private int m_ColumnX = 12;
private int _page;
private int _columnX;
public LadderGump(Ladder ladder, int page = 0) : base(50, 50)
public override bool Singleton => true;
private LadderGump(Ladder ladder, int page) : base(50, 50)
{
m_Ladder = ladder;
m_Page = page;
_ladder = ladder;
_page = page;
}
AddPage(0);
public static void DisplayTo(Mobile from, Ladder ladder, int page = 0)
{
if (from?.NetState == null || ladder == null)
{
return;
}
m_List = new List<LadderEntry>(ladder.Entries);
from.SendGump(new LadderGump(ladder, page), true);
}
var lc = Math.Min(m_List.Count, 150);
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
_columnX = 12;
var start = page * 15;
builder.AddPage();
var list = _ladder.Entries;
var lc = Math.Min(list.Count, 150);
var start = _page * 15;
var end = start + 15;
if (end > lc)
@ -67,66 +84,59 @@ public class LadderGump : Gump
var height = 12 + 20 + ct * 20 + 23 + 12;
AddBackground(0, 0, 499, height, 0x2436);
builder.AddBackground(0, 0, 499, height, 0x2436);
for (var i = start + 1; i < end; i += 2)
{
AddImageTiled(12, 32 + (i - start) * 20, 475, 20, 0x2430);
builder.AddImageTiled(12, 32 + (i - start) * 20, 475, 20, 0x2430);
}
AddAlphaRegion(10, 10, 479, height - 20);
builder.AddAlphaRegion(10, 10, 479, height - 20);
if (page > 0)
if (_page > 0)
{
AddButton(446, height - 12 - 2 - 16, 0x15E3, 0x15E7, 1);
builder.AddButton(446, height - 12 - 2 - 16, 0x15E3, 0x15E7, 1);
}
else
{
AddImage(446, height - 12 - 2 - 16, 0x2626);
builder.AddImage(446, height - 12 - 2 - 16, 0x2626);
}
if ((page + 1) * 15 < lc)
if ((_page + 1) * 15 < lc)
{
AddButton(466, height - 12 - 2 - 16, 0x15E1, 0x15E5, 2);
builder.AddButton(466, height - 12 - 2 - 16, 0x15E1, 0x15E5, 2);
}
else
{
AddImage(466, height - 12 - 2 - 16, 0x2622);
builder.AddImage(466, height - 12 - 2 - 16, 0x2622);
}
AddHtml(
builder.AddHtml(
16,
height - 12 - 2 - 18,
400,
20,
Html.Color($"Top {lc} of {m_List.Count:N0} duelists, page {page + 1} of {(lc + 14) / 15}", 0xFFC000)
Html.Color($"Top {lc} of {list.Count:N0} duelists, page {_page + 1} of {(lc + 14) / 15}", 0xFFC000)
);
AddColumnHeader(75, "Rank");
AddColumnHeader(115, "Level");
AddColumnHeader(50, "Guild");
AddColumnHeader(115, "Name");
AddColumnHeader(60, "Wins");
AddColumnHeader(60, "Losses");
AddColumnHeader(ref builder, 75, "Rank");
AddColumnHeader(ref builder, 115, "Level");
AddColumnHeader(ref builder, 50, "Guild");
AddColumnHeader(ref builder, 115, "Name");
AddColumnHeader(ref builder, 60, "Wins");
AddColumnHeader(ref builder, 60, "Losses");
for (var i = start; i < end && i < lc; ++i)
{
var entry = m_List[i];
var entry = list[i];
var y = 32 + (i - start) * 20;
var x = 12;
AddBorderedText(x, y, 75, Rank(i + 1).Center(), 0xFFFFFF, 0);
AddBorderedText(ref builder, x, y, 75, Rank(i + 1).Center(), 0xFFFFFF);
x += 75;
/*AddImage( 20, y + 5, 0x2616, 0x96C );
AddImage( 22, y + 5, 0x2616, 0x96C );
AddImage( 20, y + 7, 0x2616, 0x96C );
AddImage( 22, y + 7, 0x2616, 0x96C );
AddImage( 21, y + 6, 0x2616, 0x454 );*/
AddImage(x + 3, y + 4, 0x805);
builder.AddImage(x + 3, y + 4, 0x805);
var xp = entry.Experience;
var level = Ladder.GetLevel(xp);
@ -146,30 +156,26 @@ public class LadderGump : Gump
width = (109 * xpOffset + xpAdvance / 2) / (xpAdvance - 1);
}
// AddImageTiled( 21, y + 6, width, 8, 0x2617 );
AddImageTiled(x + 3, y + 4, width, 11, 0x806);
AddBorderedText(x, y, 115, Html.Center($"{level}"), 0xFFFFFF, 0);
builder.AddImageTiled(x + 3, y + 4, width, 11, 0x806);
AddBorderedText(ref builder, x, y, 115, Html.Center($"{level}"), 0xFFFFFF);
x += 115;
var mob = entry.Mobile;
if (mob.Guild != null)
{
AddBorderedText(x, y, 50, mob.Guild.Abbreviation.Center(), 0xFFFFFF, 0);
AddBorderedText(ref builder, x, y, 50, mob.Guild.Abbreviation.Center(), 0xFFFFFF);
}
x += 50;
AddBorderedText(x + 5, y, 115 - 5, mob.Name, 0xFFFFFF, 0);
AddBorderedText(ref builder, x + 5, y, 115 - 5, mob.Name, 0xFFFFFF);
x += 115;
AddBorderedText(x, y, 60, Html.Center($"{entry.Wins}"), 0xFFFFFF, 0);
AddBorderedText(ref builder, x, y, 60, Html.Center($"{entry.Wins}"), 0xFFFFFF);
x += 60;
AddBorderedText(x, y, 60, Html.Center($"{entry.Losses}"), 0xFFFFFF, 0);
x += 60;
// AddBorderedText( 292 + 15, y, 115 - 30, String.Format( "{0} <DIV ALIGN=CENTER>/</DIV> <DIV ALIGN=RIGHT>{1}</DIV>", entry.Wins, entry.Losses ), 0xFFC000, 0 );
AddBorderedText(ref builder, x, y, 60, Html.Center($"{entry.Losses}"), 0xFFFFFF);
}
}
@ -195,38 +201,30 @@ public class LadderGump : Gump
{
var from = sender.Mobile;
if (info.ButtonID == 1 && m_Page > 0)
if (info.ButtonID == 1 && _page > 0)
{
from.SendGump(new LadderGump(m_Ladder, m_Page - 1));
_page--;
}
else if (info.ButtonID == 2 && (m_Page + 1) * 15 < Math.Min(m_List.Count, 150))
else if (info.ButtonID == 2 && (_page + 1) * 15 < Math.Min(_ladder.Entries.Count, 150))
{
from.SendGump(new LadderGump(m_Ladder, m_Page + 1));
_page++;
}
from.SendGump(this); // refresh-via-this
}
private void AddBorderedText(int x, int y, int width, string text, int color, int borderColor)
{
/*AddColoredText( x - 1, y, width, text, borderColor );
AddColoredText( x + 1, y, width, text, borderColor );
AddColoredText( x, y - 1, width, text, borderColor );
AddColoredText( x, y + 1, width, text, borderColor );*/
/*AddColoredText( x - 1, y - 1, width, text, borderColor );
AddColoredText( x + 1, y + 1, width, text, borderColor );*/
AddColoredText(x, y, width, text, color);
}
private static void AddBorderedText(ref DynamicGumpBuilder builder, int x, int y, int width, string text, int color) =>
AddColoredText(ref builder, x, y, width, text, color);
private void AddColoredText(int x, int y, int width, string text, int color)
{
AddHtml(x, y, width, 20, color == 0 ? text : text.Color(color));
}
private static void AddColoredText(ref DynamicGumpBuilder builder, int x, int y, int width, string text, int color) =>
builder.AddHtml(x, y, width, 20, color == 0 ? text : text.Color(color));
private void AddColumnHeader(int width, string name)
private void AddColumnHeader(ref DynamicGumpBuilder builder, int width, string name)
{
AddBackground(m_ColumnX, 12, width, 20, 0x242C);
AddImageTiled(m_ColumnX + 2, 14, width - 4, 16, 0x2430);
AddBorderedText(m_ColumnX, 13, width, name.Center(), 0xFFFFFF, 0);
builder.AddBackground(_columnX, 12, width, 20, 0x242C);
builder.AddImageTiled(_columnX + 2, 14, width - 4, 16, 0x2430);
AddBorderedText(ref builder, _columnX, 13, width, name.Center(), 0xFFFFFF);
m_ColumnX += width;
_columnX += width;
}
}

View file

@ -3,283 +3,257 @@ using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class ParticipantGump : DynamicGump
{
public class ParticipantGump : Gump
public override bool Singleton => true;
private ParticipantGump(DuelContext context, Participant p) : base(50, 50)
{
public override bool Singleton => true;
Context = context;
Participant = p;
}
public ParticipantGump(Mobile from, DuelContext context, Participant p) : base(50, 50)
public static void DisplayTo(Mobile from, DuelContext context, Participant p)
{
if (from?.NetState == null || context == null || p == null)
{
From = from;
Context = context;
Participant = p;
var gumps = from.GetGumps();
gumps.Close<RulesetGump>();
gumps.Close<DuelContextGump>();
var count = p.Players.Length;
if (count < 4)
{
count = 4;
}
AddPage(0);
var height = 35 + 10 + 22 + 22 + 30 + 22 + 2 + count * 22 + 2 + 30;
AddBackground(0, 0, 300, height, 9250);
AddBackground(10, 10, 280, height - 20, 0xDAC);
AddButton(240, 25, 0xFB1, 0xFB3, 3);
// AddButton( 223, 54, 0x265A, 0x265A, 4, );
AddHtml(35, 25, 230, 20, Center("Participant Setup"));
var x = 35;
var y = 47;
AddHtml(x, y, 200, 20, $"Team Size: {p.Players.Length}");
y += 22;
AddGoldenButtonLabeled(x + 20, y, 1, "Increase");
y += 22;
AddGoldenButtonLabeled(x + 20, y, 2, "Decrease");
y += 30;
AddHtml(35, y, 230, 20, Center("Players"));
y += 22;
for (var i = 0; i < p.Players.Length; ++i)
{
var pl = p.Players[i];
AddGoldenButtonLabeled(x, y, 5 + i, $"{1 + i}: {(pl == null ? "Empty" : pl.Mobile.Name)}");
y += 22;
}
return;
}
public Mobile From { get; }
var gumps = from.GetGumps();
gumps.Close<RulesetGump>();
gumps.Close<DuelContextGump>();
public DuelContext Context { get; }
from.SendGump(new ParticipantGump(context, p));
}
public Participant Participant { get; }
public DuelContext Context { get; }
public string Center(string text) => $"<CENTER>{text}</CENTER>";
public Participant Participant { get; }
public void AddGoldenButton(int x, int y, int bid)
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
var count = Participant.Players.Length;
if (count < 4)
{
AddButton(x, y, 0xD2, 0xD2, bid);
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
count = 4;
}
public void AddGoldenButtonLabeled(int x, int y, int bid, string text)
builder.AddPage();
var height = 35 + 10 + 22 + 22 + 30 + 22 + 2 + count * 22 + 2 + 30;
builder.AddBackground(0, 0, 300, height, 9250);
builder.AddBackground(10, 10, 280, height - 20, 0xDAC);
builder.AddButton(240, 25, 0xFB1, 0xFB3, 3);
builder.AddHtml(35, 25, 230, 20, Center("Participant Setup"));
var x = 35;
var y = 47;
builder.AddHtml(x, y, 200, 20, $"Team Size: {Participant.Players.Length}");
y += 22;
AddGoldenButtonLabeled(ref builder, x + 20, y, 1, "Increase");
y += 22;
AddGoldenButtonLabeled(ref builder, x + 20, y, 2, "Decrease");
y += 30;
builder.AddHtml(35, y, 230, 20, Center("Players"));
y += 22;
for (var i = 0; i < Participant.Players.Length; ++i)
{
AddGoldenButton(x, y, bid);
AddHtml(x + 25, y, 200, 20, text);
var pl = Participant.Players[i];
AddGoldenButtonLabeled(ref builder, x, y, 5 + i, $"{1 + i}: {(pl == null ? "Empty" : pl.Mobile.Name)}");
y += 22;
}
}
private static string Center(string text) => $"<CENTER>{text}</CENTER>";
private static void AddGoldenButton(ref DynamicGumpBuilder builder, int x, int y, int bid)
{
builder.AddButton(x, y, 0xD2, 0xD2, bid);
builder.AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
}
private static void AddGoldenButtonLabeled(ref DynamicGumpBuilder builder, int x, int y, int bid, string text)
{
AddGoldenButton(ref builder, x, y, bid);
builder.AddHtml(x + 25, y, 200, 20, text);
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (!Context.Registered)
{
return;
}
public override void OnResponse(NetState sender, in RelayInfo info)
var from = sender.Mobile;
var bid = info.ButtonID;
switch (bid)
{
if (!Context.Registered)
{
return;
}
var bid = info.ButtonID;
if (bid == 0)
{
From.SendGump(new DuelContextGump(From, Context));
}
else if (bid == 1)
{
if (Participant.Count < 8)
case 0:
{
DuelContextGump.DisplayTo(from, Context);
return;
}
case 1 when Participant.Count < 8:
{
Participant.Resize(Participant.Count + 1);
break;
}
else
case 1:
{
From.SendMessage("You may not raise the team size any further.");
from.SendMessage("You may not raise the team size any further.");
break;
}
From.SendGump(new ParticipantGump(From, Context, Participant));
}
else if (bid == 2)
{
if (Participant.Count > 1 && Participant.Count > Participant.FilledSlots)
case 2 when Participant.Count > 1 && Participant.Count > Participant.FilledSlots:
{
Participant.Resize(Participant.Count - 1);
break;
}
else
case 2:
{
From.SendMessage("You may not lower the team size any further.");
from.SendMessage("You may not lower the team size any further.");
break;
}
From.SendGump(new ParticipantGump(From, Context, Participant));
}
else if (bid == 3)
{
if (Participant.FilledSlots > 0)
case 3 when Participant.FilledSlots > 0:
{
From.SendMessage("There is at least one currently active player. You must remove them first.");
From.SendGump(new ParticipantGump(From, Context, Participant));
from.SendMessage("There is at least one currently active player. You must remove them first.");
break;
}
else if (Context.Participants.Count > 2)
case 3 when Context.Participants.Count > 2:
{
/*Container cont = m_Participant.Stakes;
if (cont != null)
cont.Delete();*/
Context.Participants.Remove(Participant);
From.SendGump(new DuelContextGump(From, Context));
DuelContextGump.DisplayTo(from, Context);
return;
}
else
case 3:
{
From.SendMessage("Duels must have at least two participating parties.");
From.SendGump(new ParticipantGump(From, Context, Participant));
from.SendMessage("Duels must have at least two participating parties.");
break;
}
}
/*else if (bid == 4)
{
m_From.SendGump( new ParticipantGump( m_From, m_Context, m_Participant ) );
Container cont = m_Participant.Stakes;
if (cont != null && !cont.Deleted)
{
cont.DisplayTo( m_From );
Item[] checks = cont.FindItemsByType( typeof( BankCheck ) );
int gold = cont.TotalGold;
for ( int i = 0; i < checks.Length; ++i )
gold += ((BankCheck)checks[i]).Worth;
m_From.SendMessage( "This container has {0} item{1} and {2} stone{3}. In gold or check form there is a total of {4:D}gp.", cont.TotalItems, cont.TotalItems==1?"":"s", cont.TotalWeight, cont.TotalWeight==1?"":"s", gold );
}
}*/
else
{
bid -= 5;
if (bid >= 0 && bid < Participant.Players.Length)
default:
{
if (Participant.Players[bid] == null)
{
From.Target = new ParticipantTarget(Context, Participant, bid);
From.SendMessage("Target a player.");
}
else
bid -= 5;
if (bid >= 0 && bid < Participant.Players.Length)
{
if (Participant.Players[bid] == null)
{
from.Target = new ParticipantTarget(Context, Participant, bid);
from.SendMessage("Target a player.");
return;
}
Participant.Players[bid].Mobile.SendMessage("You have been removed from the duel.");
if (Participant.Players[bid].Mobile is PlayerMobile)
if (Participant.Players[bid].Mobile is PlayerMobile playerMobile)
{
((PlayerMobile)Participant.Players[bid].Mobile).DuelPlayer = null;
playerMobile.DuelPlayer = null;
}
Participant.Players[bid] = null;
From.SendMessage("They have been removed from the duel.");
From.SendGump(new ParticipantGump(From, Context, Participant));
}
}
}
}
private class ParticipantTarget : Target
{
private readonly DuelContext m_Context;
private readonly int m_Index;
private readonly Participant m_Participant;
public ParticipantTarget(DuelContext context, Participant p, int index) : base(12, false, TargetFlags.None)
{
m_Context = context;
m_Participant = p;
m_Index = index;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!m_Context.Registered)
{
return;
}
var index = m_Index;
if (index < 0 || index >= m_Participant.Players.Length)
{
return;
}
if (targeted is not Mobile mob)
{
from.SendMessage("That is not a player.");
}
else if (!mob.Player)
{
if (mob.Body.IsHuman)
{
mob.SayTo(from, 1005443); // Nay, I would rather stay here and watch a nail rust.
from.SendMessage("They have been removed from the duel.");
}
else
{
mob.SayTo(from, 1005444); // The creature ignores your offer.
}
}
else if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
{
from.SendMessage("They ignore your offer.");
}
else
{
if (mob is not PlayerMobile pm)
{
return;
}
if (pm.DuelContext != null)
{
from.SendMessage($"{pm.Name} cannot fight because they are already assigned to another duel.");
}
else if (DuelContext.CheckCombat(pm))
{
from.SendMessage(
$"{pm.Name} cannot fight because they have recently been in combat with another player."
);
}
else if (mob.HasGump<AcceptDuelGump>())
{
from.SendMessage($"{mob.Name} has already been offered a duel.");
}
else
{
if (m_Participant.Find(from) == null)
{
from.SendMessage($"You send a challenge to {mob.Name}.");
}
else
{
from.SendMessage($"You send an invitation to {mob.Name}.");
}
break;
}
}
mob.SendGump(new AcceptDuelGump(from, mob, m_Context, m_Participant, m_Index));
}
from.SendGump(this); // refresh-via-this
}
private class ParticipantTarget : Target
{
private readonly DuelContext _context;
private readonly int _index;
private readonly Participant _participant;
public ParticipantTarget(DuelContext context, Participant p, int index) : base(12, false, TargetFlags.None)
{
_context = context;
_participant = p;
_index = index;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (!_context.Registered)
{
return;
}
if (_index < 0 || _index >= _participant.Players.Length)
{
return;
}
if (targeted is not Mobile mob)
{
from.SendMessage("That is not a player.");
}
else if (!mob.Player)
{
if (mob.Body.IsHuman)
{
mob.SayTo(from, 1005443); // Nay, I would rather stay here and watch a nail rust.
}
else
{
mob.SayTo(from, 1005444); // The creature ignores your offer.
}
}
protected override void OnTargetFinish(Mobile from)
else if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
{
from.SendGump(new ParticipantGump(from, m_Context, m_Participant));
from.SendMessage("They ignore your offer.");
}
else if (mob is not PlayerMobile pm)
{
}
else if (pm.DuelContext != null)
{
from.SendMessage($"{pm.Name} cannot fight because they are already assigned to another duel.");
}
else if (DuelContext.CheckCombat(pm))
{
from.SendMessage(
$"{pm.Name} cannot fight because they have recently been in combat with another player."
);
}
else if (mob.HasGump<AcceptDuelGump>())
{
from.SendMessage($"{mob.Name} has already been offered a duel.");
}
else
{
if (_participant.Find(from) == null)
{
from.SendMessage($"You send a challenge to {mob.Name}.");
}
else
{
from.SendMessage($"You send an invitation to {mob.Name}.");
}
AcceptDuelGump.DisplayTo(from, mob, _context, _participant, _index);
}
}
protected override void OnTargetFinish(Mobile from) => DisplayTo(from, _context, _participant);
}
}

View file

@ -1,141 +1,154 @@
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class PickRulesetGump : DynamicGump
{
public class PickRulesetGump : Gump
private readonly DuelContext _context;
private readonly Ruleset[] _defaults;
private readonly Ruleset[] _flavors;
private readonly Ruleset _ruleset;
public override bool Singleton => true;
private PickRulesetGump(DuelContext context, Ruleset ruleset) : base(50, 50)
{
private readonly DuelContext m_Context;
private readonly Ruleset[] m_Defaults;
private readonly Ruleset[] m_Flavors;
private readonly Mobile m_From;
private readonly Ruleset m_Ruleset;
_context = context;
_ruleset = ruleset;
_defaults = ruleset.Layout.Defaults;
_flavors = ruleset.Layout.Flavors;
}
public PickRulesetGump(Mobile from, DuelContext context, Ruleset ruleset) : base(50, 50)
public static void DisplayTo(Mobile from, DuelContext context, Ruleset ruleset)
{
if (from?.NetState == null || ruleset == null)
{
m_From = from;
m_Context = context;
m_Ruleset = ruleset;
m_Defaults = ruleset.Layout.Defaults;
m_Flavors = ruleset.Layout.Flavors;
var height = 25 + 20 + (m_Defaults.Length + 1) * 22 + 6 + 20 + m_Flavors.Length * 22 + 25;
AddPage(0);
AddBackground(0, 0, 260, height, 9250);
AddBackground(10, 10, 240, height - 20, 0xDAC);
AddHtml(35, 25, 190, 20, Center("Rules"));
var y = 25 + 20;
for (var i = 0; i < m_Defaults.Length; ++i)
{
var cur = m_Defaults[i];
AddHtml(35 + 14, y, 176, 20, cur.Title);
if (ruleset.Base == cur && !ruleset.Changed)
{
AddImage(35, y + 4, 0x939);
}
else if (ruleset.Base == cur)
{
AddButton(35, y + 4, 0x93A, 0x939, 2 + i);
}
else
{
AddButton(35, y + 4, 0x938, 0x939, 2 + i);
}
y += 22;
}
AddHtml(35 + 14, y, 176, 20, "Custom");
AddButton(35, y + 4, ruleset.Changed ? 0x939 : 0x938, 0x939, 1);
y += 22;
y += 6;
AddHtml(35, y, 190, 20, Center("Flavors"));
y += 20;
for (var i = 0; i < m_Flavors.Length; ++i)
{
var cur = m_Flavors[i];
AddHtml(35 + 14, y, 176, 20, cur.Title);
if (ruleset.Flavors.Contains(cur))
{
AddButton(35, y + 4, 0x939, 0x938, 2 + m_Defaults.Length + i);
}
else
{
AddButton(35, y + 4, 0x938, 0x939, 2 + m_Defaults.Length + i);
}
y += 22;
}
return;
}
public string Center(string text) => $"<CENTER>{text}</CENTER>";
from.SendGump(new PickRulesetGump(context, ruleset));
}
public override void OnResponse(NetState sender, in RelayInfo info)
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
var height = 25 + 20 + (_defaults.Length + 1) * 22 + 6 + 20 + _flavors.Length * 22 + 25;
builder.AddPage();
builder.AddBackground(0, 0, 260, height, 9250);
builder.AddBackground(10, 10, 240, height - 20, 0xDAC);
builder.AddHtml(35, 25, 190, 20, Center("Rules"));
var y = 25 + 20;
for (var i = 0; i < _defaults.Length; ++i)
{
if (m_Context?.Registered == false)
var cur = _defaults[i];
builder.AddHtml(35 + 14, y, 176, 20, cur.Title);
if (_ruleset.Base == cur && !_ruleset.Changed)
{
return;
builder.AddImage(35, y + 4, 0x939);
}
else if (_ruleset.Base == cur)
{
builder.AddButton(35, y + 4, 0x93A, 0x939, 2 + i);
}
else
{
builder.AddButton(35, y + 4, 0x938, 0x939, 2 + i);
}
switch (info.ButtonID)
y += 22;
}
builder.AddHtml(35 + 14, y, 176, 20, "Custom");
builder.AddButton(35, y + 4, _ruleset.Changed ? 0x939 : 0x938, 0x939, 1);
y += 22;
y += 6;
builder.AddHtml(35, y, 190, 20, Center("Flavors"));
y += 20;
for (var i = 0; i < _flavors.Length; ++i)
{
var cur = _flavors[i];
builder.AddHtml(35 + 14, y, 176, 20, cur.Title);
if (_ruleset.Flavors.Contains(cur))
{
case 0: // closed
{
if (m_Context != null)
{
m_From.SendGump(new DuelContextGump(m_From, m_Context));
}
builder.AddButton(35, y + 4, 0x939, 0x938, 2 + _defaults.Length + i);
}
else
{
builder.AddButton(35, y + 4, 0x938, 0x939, 2 + _defaults.Length + i);
}
break;
y += 22;
}
}
private static string Center(string text) => $"<CENTER>{text}</CENTER>";
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (_context?.Registered == false)
{
return;
}
var from = sender.Mobile;
switch (info.ButtonID)
{
case 0: // closed
{
if (_context != null)
{
DuelContextGump.DisplayTo(from, _context);
}
case 1: // customize
break;
}
case 1: // customize
{
RulesetGump.DisplayTo(from, _ruleset, _ruleset.Layout, _context);
break;
}
default:
{
var idx = info.ButtonID - 2;
if (idx >= 0 && idx < _defaults.Length)
{
m_From.SendGump(new RulesetGump(m_From, m_Ruleset, m_Ruleset.Layout, m_Context));
break;
_ruleset.ApplyDefault(_defaults[idx]);
from.SendGump(this); // refresh-via-this
}
default:
else
{
var idx = info.ButtonID - 2;
idx -= _defaults.Length;
if (idx >= 0 && idx < m_Defaults.Length)
if (idx >= 0 && idx < _flavors.Length)
{
m_Ruleset.ApplyDefault(m_Defaults[idx]);
m_From.SendGump(new PickRulesetGump(m_From, m_Context, m_Ruleset));
}
else
{
idx -= m_Defaults.Length;
if (idx >= 0 && idx < m_Flavors.Length)
if (_ruleset.Flavors.Contains(_flavors[idx]))
{
if (m_Ruleset.Flavors.Contains(m_Flavors[idx]))
{
m_Ruleset.RemoveFlavor(m_Flavors[idx]);
}
else
{
m_Ruleset.AddFlavor(m_Flavors[idx]);
}
m_From.SendGump(new PickRulesetGump(m_From, m_Context, m_Ruleset));
_ruleset.RemoveFlavor(_flavors[idx]);
}
else
{
_ruleset.AddFlavor(_flavors[idx]);
}
}
break;
from.SendGump(this); // refresh-via-this
}
}
}
break;
}
}
}
}

View file

@ -1,109 +1,119 @@
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class ReadyGump : DynamicGump
{
public class ReadyGump : Gump
private readonly DuelContext _context;
private readonly int _count;
public override bool Singleton => true;
private ReadyGump(DuelContext context, int count) : base(50, 50)
{
private DuelContext m_Context;
private int m_Count;
private Mobile m_From;
_context = context;
_count = count;
}
public ReadyGump(Mobile from, DuelContext context, int count) : base(50, 50)
public static void DisplayTo(Mobile from, DuelContext context, int count)
{
if (from?.NetState == null || context == null)
{
m_From = from;
m_Context = context;
m_Count = count;
var parts = context.Participants;
var height = 25 + 20;
for (var i = 0; i < parts.Count; ++i)
{
var p = parts[i];
height += 4;
if (p.Players.Length > 1)
{
height += 22;
}
height += p.Players.Length * 22;
}
height += 25;
Closable = false;
Draggable = false;
AddPage(0);
AddBackground(0, 0, 260, height, 9250);
AddBackground(10, 10, 240, height - 20, 0xDAC);
if (count == -1)
{
AddHtml(35, 25, 190, 20, Center("Ready"));
}
else
{
AddHtml(35, 25, 190, 20, Center("Starting"));
AddHtml(35, 25, 190, 20, $"<DIV ALIGN=RIGHT>{count}");
}
var y = 25 + 20;
for (var i = 0; i < parts.Count; ++i)
{
var p = parts[i];
y += 4;
var isAllReady = true;
var yStore = y;
var offset = 0;
if (p.Players.Length > 1)
{
AddHtml(35 + 14, y, 176, 20, $"Participant #{i + 1}");
y += 22;
offset = 10;
}
for (var j = 0; j < p.Players.Length; ++j)
{
var pl = p.Players[j];
if (pl?.Ready == true)
{
AddImage(35 + offset, y + 4, 0x939);
}
else
{
AddImage(35 + offset, y + 4, 0x938);
isAllReady = false;
}
var name = pl == null ? "(Empty)" : pl.Mobile.Name;
AddHtml(35 + offset + 14, y, 166, 20, name);
y += 22;
}
if (p.Players.Length > 1)
{
AddImage(35, yStore + 4, isAllReady ? 0x939 : 0x938);
}
}
return;
}
public string Center(string text) => $"<CENTER>{text}</CENTER>";
from.SendGump(new ReadyGump(context, count), true);
}
public override void OnResponse(NetState sender, in RelayInfo info)
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
builder.SetNoClose();
builder.SetNoMove();
builder.AddPage();
var parts = _context.Participants;
var height = 25 + 20;
for (var i = 0; i < parts.Count; ++i)
{
var p = parts[i];
height += 4;
if (p.Players.Length > 1)
{
height += 22;
}
height += p.Players.Length * 22;
}
height += 25;
builder.AddBackground(0, 0, 260, height, 9250);
builder.AddBackground(10, 10, 240, height - 20, 0xDAC);
if (_count == -1)
{
builder.AddHtml(35, 25, 190, 20, "Ready".Center());
}
else
{
builder.AddHtml(35, 25, 190, 20, "Starting".Center());
builder.AddHtml(35, 25, 190, 20, $"<DIV ALIGN=RIGHT>{_count}");
}
var y = 25 + 20;
for (var i = 0; i < parts.Count; ++i)
{
var p = parts[i];
y += 4;
var isAllReady = true;
var yStore = y;
var offset = 0;
if (p.Players.Length > 1)
{
builder.AddHtml(35 + 14, y, 176, 20, $"Participant #{i + 1}");
y += 22;
offset = 10;
}
for (var j = 0; j < p.Players.Length; ++j)
{
var pl = p.Players[j];
if (pl?.Ready == true)
{
builder.AddImage(35 + offset, y + 4, 0x939);
}
else
{
builder.AddImage(35 + offset, y + 4, 0x938);
isAllReady = false;
}
var name = pl == null ? "(Empty)" : pl.Mobile.Name;
builder.AddHtml(35 + offset + 14, y, 166, 20, name);
y += 22;
}
if (p.Players.Length > 1)
{
builder.AddImage(35, yStore + 4, isAllReady ? 0x939 : 0x938);
}
}
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
}
}

View file

@ -3,235 +3,239 @@ using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class ReadyUpGump : DynamicGump
{
public class ReadyUpGump : Gump
private readonly DuelContext _context;
public override bool Singleton => true;
private ReadyUpGump(DuelContext context) : base(50, 50) => _context = context;
public static void DisplayTo(Mobile from, DuelContext context)
{
private readonly DuelContext m_Context;
private readonly Mobile m_From;
public ReadyUpGump(Mobile from, DuelContext context) : base(50, 50)
if (from?.NetState == null || context == null)
{
m_From = from;
m_Context = context;
return;
}
Closable = false;
AddPage(0);
from.SendGump(new ReadyUpGump(context), true);
}
if (context.Rematch)
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
builder.SetNoClose();
builder.AddPage();
if (_context.Rematch)
{
var height = 25 + 20 + 10 + 22 + 25;
builder.AddBackground(0, 0, 210, height, 9250);
builder.AddBackground(10, 10, 190, height - 20, 0xDAC);
builder.AddHtml(35, 25, 140, 20, "Rematch?".Center());
builder.AddButton(35, 55, 247, 248, 1);
builder.AddButton(115, 55, 242, 241, 2);
}
else
{
builder.AddPage(1);
var parts = _context.Participants;
var height = 25 + 20;
for (var i = 0; i < parts.Count; ++i)
{
var height = 25 + 20 + 10 + 22 + 25;
var p = parts[i];
AddBackground(0, 0, 210, height, 9250);
AddBackground(10, 10, 190, height - 20, 0xDAC);
height += 4;
AddHtml(35, 25, 140, 20, Center("Rematch?"));
if (p.Players.Length > 1)
{
height += 22;
}
AddButton(35, 55, 247, 248, 1);
AddButton(115, 55, 242, 241, 2);
height += p.Players.Length * 22;
}
height += 10 + 22 + 25;
builder.AddBackground(0, 0, 260, height, 9250);
builder.AddBackground(10, 10, 240, height - 20, 0xDAC);
builder.AddHtml(35, 25, 190, 20, "Participants".Center());
var y = 20 + 25;
for (var i = 0; i < parts.Count; ++i)
{
var p = parts[i];
y += 4;
var offset = 0;
if (p.Players.Length > 1)
{
builder.AddHtml(35, y, 176, 20, $"Team #{i + 1}");
y += 22;
offset = 10;
}
for (var j = 0; j < p.Players.Length; ++j)
{
var pl = p.Players[j];
var name = pl == null ? "(Empty)" : pl.Mobile.Name;
builder.AddHtml(35 + offset, y, 166, 20, name);
y += 22;
}
}
y += 8;
builder.AddHtml(35, y, 176, 20, "Continue?");
y -= 2;
builder.AddButton(102, y, 247, 248, 0, GumpButtonType.Page, 2);
builder.AddButton(169, y, 242, 241, 2);
builder.AddPage(2);
var ruleset = _context.Ruleset;
var basedef = ruleset.Base;
height = 25 + 20 + 5 + 20 + 20 + 4;
var changes = 0;
BitArray defs;
if (ruleset.Flavors.Count > 0)
{
defs = new BitArray(basedef.Options);
for (var i = 0; i < ruleset.Flavors.Count; ++i)
{
defs.Or(ruleset.Flavors[i].Options);
}
height += ruleset.Flavors.Count * 18;
}
else
{
AddPage(1);
defs = basedef.Options;
}
var parts = context.Participants;
var opts = ruleset.Options;
var height = 25 + 20;
for (var i = 0; i < parts.Count; ++i)
for (var i = 0; i < opts.Length; ++i)
{
if (defs[i] != opts[i])
{
var p = parts[i];
height += 4;
if (p.Players.Length > 1)
{
height += 22;
}
height += p.Players.Length * 22;
++changes;
}
}
height += 10 + 22 + 25;
height += changes * 22;
AddBackground(0, 0, 260, height, 9250);
AddBackground(10, 10, 240, height - 20, 0xDAC);
height += 10 + 22 + 25;
AddHtml(35, 25, 190, 20, Center("Participants"));
builder.AddBackground(0, 0, 260, height, 9250);
builder.AddBackground(10, 10, 240, height - 20, 0xDAC);
var y = 20 + 25;
builder.AddHtml(35, 25, 190, 20, "Rules".Center());
for (var i = 0; i < parts.Count; ++i)
{
var p = parts[i];
builder.AddHtml(35, 50, 190, 20, $"Set: {basedef.Title}");
y += 4;
y = 70;
var offset = 0;
for (var i = 0; i < ruleset.Flavors.Count; ++i, y += 18)
{
builder.AddHtml(35, y, 190, 20, $" + {ruleset.Flavors[i].Title}");
}
if (p.Players.Length > 1)
{
AddHtml(35, y, 176, 20, $"Team #{i + 1}");
y += 22;
offset = 10;
}
y += 4;
for (var j = 0; j < p.Players.Length; ++j)
{
var pl = p.Players[j];
var name = pl == null ? "(Empty)" : pl.Mobile.Name;
AddHtml(35 + offset, y, 166, 20, name);
y += 22;
}
}
y += 8;
AddHtml(35, y, 176, 20, "Continue?");
y -= 2;
AddButton(102, y, 247, 248, 0, GumpButtonType.Page, 2);
AddButton(169, y, 242, 241, 2);
AddPage(2);
var ruleset = context.Ruleset;
var basedef = ruleset.Base;
height = 25 + 20 + 5 + 20 + 20 + 4;
var changes = 0;
BitArray defs;
if (ruleset.Flavors.Count > 0)
{
defs = new BitArray(basedef.Options);
for (var i = 0; i < ruleset.Flavors.Count; ++i)
{
defs.Or(ruleset.Flavors[i].Options);
}
height += ruleset.Flavors.Count * 18;
}
else
{
defs = basedef.Options;
}
var opts = ruleset.Options;
if (changes > 0)
{
builder.AddHtml(35, y, 190, 20, "Modifications:");
y += 20;
for (var i = 0; i < opts.Length; ++i)
{
if (defs[i] != opts[i])
{
++changes;
}
}
var name = ruleset.Layout.FindByIndex(i);
height += changes * 22;
height += 10 + 22 + 25;
AddBackground(0, 0, 260, height, 9250);
AddBackground(10, 10, 240, height - 20, 0xDAC);
AddHtml(35, 25, 190, 20, Center("Rules"));
AddHtml(35, 50, 190, 20, $"Set: {basedef.Title}");
y = 70;
for (var i = 0; i < ruleset.Flavors.Count; ++i, y += 18)
{
AddHtml(35, y, 190, 20, $" + {ruleset.Flavors[i].Title}");
}
y += 4;
if (changes > 0)
{
AddHtml(35, y, 190, 20, "Modifications:");
y += 20;
for (var i = 0; i < opts.Length; ++i)
{
if (defs[i] != opts[i])
if (name != null) // sanity
{
var name = ruleset.Layout.FindByIndex(i);
if (name != null) // sanity
{
AddImage(35, y, opts[i] ? 0xD3 : 0xD2);
AddHtml(60, y, 165, 22, name);
}
y += 22;
}
}
}
else
{
AddHtml(35, y, 190, 20, "Modifications: None");
y += 20;
}
y += 8;
AddHtml(35, y, 176, 20, "Continue?");
y -= 2;
AddButton(102, y, 247, 248, 1);
AddButton(169, y, 242, 241, 3);
}
}
public string Center(string text) => $"<CENTER>{text}</CENTER>";
public void AddGoldenButton(int x, int y, int bid)
{
AddButton(x, y, 0xD2, 0xD2, bid);
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (!m_Context.Registered || !m_Context.ReadyWait)
{
return;
}
switch (info.ButtonID)
{
case 1: // okay
{
if (m_From is not PlayerMobile pm)
{
break;
builder.AddImage(35, y, opts[i] ? 0xD3 : 0xD2);
builder.AddHtml(60, y, 165, 22, name);
}
pm.DuelPlayer.Ready = true;
m_Context.SendReadyGump();
break;
}
case 2: // reject participants
{
m_Context.RejectReady(m_From, "participants");
break;
}
case 3: // reject rules
{
m_Context.RejectReady(m_From, "rules");
break;
y += 22;
}
}
}
else
{
builder.AddHtml(35, y, 190, 20, "Modifications: None");
y += 20;
}
y += 8;
builder.AddHtml(35, y, 176, 20, "Continue?");
y -= 2;
builder.AddButton(102, y, 247, 248, 1);
builder.AddButton(169, y, 242, 241, 3);
}
}
private static string Center(string text) => $"<CENTER>{text}</CENTER>";
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (!_context.Registered || !_context.ReadyWait)
{
return;
}
var from = sender.Mobile;
switch (info.ButtonID)
{
case 1: // okay
{
if (from is not PlayerMobile pm)
{
break;
}
pm.DuelPlayer.Ready = true;
_context.SendReadyGump();
break;
}
case 2: // reject participants
{
_context.RejectReady(from, "participants");
break;
}
case 3: // reject rules
{
_context.RejectReady(from, "rules");
break;
}
}
}
}

View file

@ -2,143 +2,156 @@ using System.Collections;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
namespace Server.Engines.ConPVP;
public class RulesetGump : DynamicGump
{
public class RulesetGump : Gump
private readonly DuelContext _duelContext;
private readonly RulesetLayout _page;
private readonly bool _readOnly;
private readonly Ruleset _ruleset;
public override bool Singleton => true;
private RulesetGump(Ruleset ruleset, RulesetLayout page, DuelContext duelContext, bool readOnly)
: base(readOnly ? 310 : 50, 50)
{
private readonly DuelContext m_DuelContext;
private readonly Mobile m_From;
private readonly RulesetLayout m_Page;
private readonly bool m_ReadOnly;
private readonly Ruleset m_Ruleset;
_ruleset = ruleset;
_page = page;
_duelContext = duelContext;
_readOnly = readOnly;
}
public override bool Singleton => true;
public RulesetGump(Mobile from, Ruleset ruleset, RulesetLayout page, DuelContext duelContext, bool readOnly = false)
: base(readOnly ? 310 : 50, 50)
public static void DisplayTo(
Mobile from, Ruleset ruleset, RulesetLayout page, DuelContext duelContext, bool readOnly = false
)
{
if (from?.NetState == null || ruleset == null || page == null)
{
m_From = from;
m_Ruleset = ruleset;
m_Page = page;
m_DuelContext = duelContext;
m_ReadOnly = readOnly;
Draggable = !readOnly;
var gumps = from.GetGumps();
gumps.Close<DuelContextGump>();
gumps.Close<ParticipantGump>();
var depthCounter = page;
while (depthCounter != null)
{
depthCounter = depthCounter.Parent;
}
var count = page.Children.Length + page.Options.Length;
AddPage(0);
var height = 35 + 10 + 2 + count * 22 + 2 + 30;
AddBackground(0, 0, 260, height, 9250);
AddBackground(10, 10, 240, height - 20, 0xDAC);
AddHtml(35, 25, 190, 20, Center(page.Title));
var x = 35;
var y = 47;
for (var i = 0; i < page.Children.Length; ++i)
{
AddGoldenButton(x, y, 1 + i);
AddHtml(x + 25, y, 250, 22, page.Children[i].Title);
y += 22;
}
for (var i = 0; i < page.Options.Length; ++i)
{
var enabled = ruleset.Options[page.Offset + i];
if (readOnly)
{
AddImage(x, y, enabled ? 0xD3 : 0xD2);
}
else
{
AddCheck(x, y, 0xD2, 0xD3, enabled, i);
}
AddHtml(x + 25, y, 250, 22, page.Options[i]);
y += 22;
}
return;
}
public string Center(string text) => $"<CENTER>{text}</CENTER>";
var gumps = from.GetGumps();
gumps.Close<DuelContextGump>();
gumps.Close<ParticipantGump>();
public void AddGoldenButton(int x, int y, int bid)
from.SendGump(new RulesetGump(ruleset, page, duelContext, readOnly));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
if (_readOnly)
{
AddButton(x, y, 0xD2, 0xD2, bid);
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
builder.SetNoMove();
}
public override void OnResponse(NetState sender, in RelayInfo info)
var depthCounter = _page;
while (depthCounter != null)
{
if (m_DuelContext?.Registered == false)
depthCounter = depthCounter.Parent;
}
var count = _page.Children.Length + _page.Options.Length;
builder.AddPage();
var height = 35 + 10 + 2 + count * 22 + 2 + 30;
builder.AddBackground(0, 0, 260, height, 9250);
builder.AddBackground(10, 10, 240, height - 20, 0xDAC);
builder.AddHtml(35, 25, 190, 20, _page.Title.Center());
var x = 35;
var y = 47;
for (var i = 0; i < _page.Children.Length; ++i)
{
AddGoldenButton(ref builder, x, y, 1 + i);
builder.AddHtml(x + 25, y, 250, 22, _page.Children[i].Title);
y += 22;
}
for (var i = 0; i < _page.Options.Length; ++i)
{
var enabled = _ruleset.Options[_page.Offset + i];
if (_readOnly)
{
return;
}
if (!m_ReadOnly)
{
var opts = new BitArray(m_Page.Options.Length);
for (var i = 0; i < info.Switches.Length; ++i)
{
var sid = info.Switches[i];
if (sid >= 0 && sid < m_Page.Options.Length)
{
opts[sid] = true;
}
}
for (var i = 0; i < opts.Length; ++i)
{
if (m_Ruleset.Options[m_Page.Offset + i] != opts[i])
{
m_Ruleset.Options[m_Page.Offset + i] = opts[i];
m_Ruleset.Changed = true;
}
}
}
var bid = info.ButtonID;
if (bid == 0)
{
if (m_Page.Parent != null)
{
m_From.SendGump(new RulesetGump(m_From, m_Ruleset, m_Page.Parent, m_DuelContext, m_ReadOnly));
}
else if (!m_ReadOnly)
{
m_From.SendGump(new PickRulesetGump(m_From, m_DuelContext, m_Ruleset));
}
builder.AddImage(x, y, enabled ? 0xD3 : 0xD2);
}
else
{
bid -= 1;
builder.AddCheckbox(x, y, 0xD2, 0xD3, enabled, i);
}
if (bid >= 0 && bid < m_Page.Children.Length)
builder.AddHtml(x + 25, y, 250, 22, _page.Options[i]);
y += 22;
}
}
private static void AddGoldenButton(ref DynamicGumpBuilder builder, int x, int y, int bid)
{
builder.AddButton(x, y, 0xD2, 0xD2, bid);
builder.AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (_duelContext?.Registered == false)
{
return;
}
if (!_readOnly)
{
var opts = new BitArray(_page.Options.Length);
for (var i = 0; i < info.Switches.Length; ++i)
{
var sid = info.Switches[i];
if (sid >= 0 && sid < _page.Options.Length)
{
m_From.SendGump(new RulesetGump(m_From, m_Ruleset, m_Page.Children[bid], m_DuelContext, m_ReadOnly));
opts[sid] = true;
}
}
for (var i = 0; i < opts.Length; ++i)
{
if (_ruleset.Options[_page.Offset + i] != opts[i])
{
_ruleset.Options[_page.Offset + i] = opts[i];
_ruleset.Changed = true;
}
}
}
var from = sender.Mobile;
var bid = info.ButtonID;
if (bid == 0)
{
if (_page.Parent != null)
{
DisplayTo(from, _ruleset, _page.Parent, _duelContext, _readOnly);
}
else if (!_readOnly)
{
PickRulesetGump.DisplayTo(from, _duelContext, _ruleset);
}
}
else
{
bid -= 1;
if (bid >= 0 && bid < _page.Children.Length)
{
DisplayTo(from, _ruleset, _page.Children[bid], _duelContext, _readOnly);
}
}
}
}

View file

@ -174,42 +174,56 @@ namespace Server.Engines.ConPVP
}
}
public class PreferencesGump : Gump
public class PreferencesGump : DynamicGump
{
private readonly PreferencesEntry m_Entry;
private int m_ColumnX = 12;
private readonly PreferencesEntry _entry;
private int _columnX;
public override bool Singleton => true;
public PreferencesGump(Mobile from, Preferences prefs) : base(50, 50)
{
m_Entry = prefs.Find(from);
private PreferencesGump(PreferencesEntry entry) : base(50, 50) => _entry = entry;
if (m_Entry == null)
public static void DisplayTo(Mobile from, Preferences prefs)
{
if (from?.NetState == null || prefs == null)
{
return;
}
var entry = prefs.Find(from);
if (entry == null)
{
return;
}
from.SendGump(new PreferencesGump(entry));
}
protected override void BuildLayout(ref DynamicGumpBuilder builder)
{
_columnX = 12;
var arenas = Arena.Arenas;
AddPage(0);
builder.AddPage();
var height = 12 + 20 + arenas.Count * 31 + 24 + 12;
AddBackground(0, 0, 499 + 40 - 365, height, 0x2436);
builder.AddBackground(0, 0, 499 + 40 - 365, height, 0x2436);
for (var i = 1; i < arenas.Count; i += 2)
{
AddImageTiled(12, 32 + i * 31, 475 + 40 - 365, 30, 0x2430);
builder.AddImageTiled(12, 32 + i * 31, 475 + 40 - 365, 30, 0x2430);
}
AddAlphaRegion(10, 10, 479 + 40 - 365, height - 20);
builder.AddAlphaRegion(10, 10, 479 + 40 - 365, height - 20);
AddColumnHeader(35, null);
AddColumnHeader(115, "Arena");
AddColumnHeader(ref builder, 35, null);
AddColumnHeader(ref builder, 115, "Arena");
AddButton(499 + 40 - 365 - 12 - 63 - 4 - 63, height - 12 - 24, 247, 248, 1);
AddButton(499 + 40 - 365 - 12 - 63, height - 12 - 24, 241, 242, 2);
builder.AddButton(499 + 40 - 365 - 12 - 63 - 4 - 63, height - 12 - 24, 247, 248, 1);
builder.AddButton(499 + 40 - 365 - 12 - 63, height - 12 - 24, 241, 242, 2);
for (var i = 0; i < arenas.Count; ++i)
{
@ -222,16 +236,16 @@ namespace Server.Engines.ConPVP
var color = 0xCCFFCC;
AddCheck(x + 3, y + 1, 9730, 9727, m_Entry.Disliked.Contains(name), i);
builder.AddCheckbox(x + 3, y + 1, 9730, 9727, _entry.Disliked.Contains(name), i);
x += 35;
AddBorderedText(x + 5, y + 5, 115 - 5, name, color, 0);
AddBorderedText(ref builder, x + 5, y + 5, 115 - 5, name, color, 0);
}
}
public override void OnResponse(NetState sender, in RelayInfo info)
{
if (m_Entry == null)
if (_entry == null)
{
return;
}
@ -241,7 +255,7 @@ namespace Server.Engines.ConPVP
return;
}
m_Entry.Disliked.Clear();
_entry.Disliked.Clear();
var arenas = Arena.Arenas;
@ -251,32 +265,32 @@ namespace Server.Engines.ConPVP
if (idx >= 0 && idx < arenas.Count)
{
m_Entry.Disliked.Add(arenas[idx].Name);
_entry.Disliked.Add(arenas[idx].Name);
}
}
}
private void AddBorderedText(int x, int y, int width, string text, int color, int borderColor)
private static void AddBorderedText(ref DynamicGumpBuilder builder, int x, int y, int width, string text, int color, int borderColor)
{
AddColoredText(x, y, width, text, color);
AddColoredText(ref builder, x, y, width, text, color);
}
private void AddColoredText(int x, int y, int width, string text, int color)
private static void AddColoredText(ref DynamicGumpBuilder builder, int x, int y, int width, string text, int color)
{
AddHtml(x, y, width, 20, color == 0 ? text : text.Color(color));
builder.AddHtml(x, y, width, 20, color == 0 ? text : text.Color(color));
}
private void AddColumnHeader(int width, string name)
private void AddColumnHeader(ref DynamicGumpBuilder builder, int width, string name)
{
AddBackground(m_ColumnX, 12, width, 20, 0x242C);
AddImageTiled(m_ColumnX + 2, 14, width - 4, 16, 0x2430);
builder.AddBackground(_columnX, 12, width, 20, 0x242C);
builder.AddImageTiled(_columnX + 2, 14, width - 4, 16, 0x2430);
if (name != null)
{
AddBorderedText(m_ColumnX, 13, width, name.Center(), 0xFFFFFF, 0);
AddBorderedText(ref builder, _columnX, 13, width, name.Center(), 0xFFFFFF, 0);
}
m_ColumnX += width;
_columnX += width;
}
}
}

View file

@ -27,7 +27,7 @@ public partial class TournamentBracketItem : Item
if (tourney != null)
{
from.SendGump(new TournamentBracketGump(from, tourney, TourneyBracketGumpType.Index), true);
TournamentBracketGump.DisplayTo(from, tourney, TourneyBracketGumpType.Index);
}
}
}

View file

@ -70,7 +70,7 @@ namespace Server.Engines.ConPVP
gumps.Close<RulesetGump>();
gumps.Close<PickRulesetGump>();
gumps.Send(new PickRulesetGump(from, null, Tournament.Ruleset));
PickRulesetGump.DisplayTo(from, null, Tournament.Ruleset);
}
}

View file

@ -144,7 +144,7 @@ public partial class TournamentSignupItem : Item
}
else if (!tourney.HasParticipant(from))
{
from.SendGump(new ConfirmSignupGump(from, Registrar, tourney, new List<Mobile> { from }));
ConfirmSignupGump.DisplayTo(from, Registrar, tourney, new List<Mobile> { from });
}
else
{