v0.0.1-Alpha (#42)

This commit is contained in:
Kamron Batman 2019-08-02 18:16:11 -07:00 • committed by GitHub
parent d30f93c454
commit a36796c2c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3552 changed files with 2476 additions and 15223 deletions

View file

@ -0,0 +1,382 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.ConPVP
{
public class AcceptTeamGump : Gump
{
private const int BlackColor32 = 0x000008;
private const int LabelColor32 = 0xFFFFFF;
private bool m_Active;
private Mobile m_From;
private List<Mobile> m_Players;
private Mobile m_Registrar;
private Mobile m_Requested;
private Tournament m_Tournament;
public AcceptTeamGump(Mobile from, Mobile requested, Tournament tourney, Mobile registrar, List<Mobile> players) :
base(50, 50)
{
m_From = from;
m_Requested = requested;
m_Tournament = tourney;
m_Registrar = registrar;
m_Players = players;
m_Active = true;
#region Rules
Ruleset ruleset = tourney.Ruleset;
Ruleset basedef = ruleset.Base;
int height = 185 + 35 + 60 + 12;
int changes = 0;
BitArray defs;
if (ruleset.Flavors.Count > 0)
{
defs = new BitArray(basedef.Options);
for (int i = 0; i < ruleset.Flavors.Count; ++i)
defs.Or(ruleset.Flavors[i].Options);
height += ruleset.Flavors.Count * 18;
}
else
{
defs = basedef.Options;
}
BitArray opts = ruleset.Options;
for (int i = 0; i < opts.Length; ++i)
if (defs[i] != opts[i])
++changes;
height += changes * 22;
height += 10 + 22 + 25 + 25;
#endregion
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);
StringBuilder sb = new StringBuilder();
if (tourney.TourneyType == TourneyType.FreeForAll)
{
sb.Append("FFA");
}
else if (tourney.TourneyType == TourneyType.RandomTeam)
{
sb.Append(tourney.ParticipantsPerMatch);
sb.Append("-Team");
}
else if (tourney.TourneyType == TourneyType.Faction)
{
sb.Append(tourney.ParticipantsPerMatch);
sb.Append("-Team Faction");
}
else if (tourney.TourneyType == TourneyType.RedVsBlue)
{
sb.Append("Red v Blue");
}
else
{
for (int i = 0; i < tourney.ParticipantsPerMatch; ++i)
{
if (sb.Length > 0)
sb.Append('v');
sb.Append(tourney.PlayersPerParticipant);
}
}
if (tourney.EventController != null)
sb.Append(' ').Append(tourney.EventController.Title);
sb.Append(" Tournament Invitation");
AddBorderedText(22, 22, 294, 20, Center(sb.ToString()), LabelColor32, BlackColor32);
AddBorderedText(22, 50, 294, 40,
$"You have been asked to partner with {from.Name} in a tournament. Do you accept?",
0xB0C868, BlackColor32);
AddImageTiled(32, 88, 264, 1, 9107);
AddImageTiled(42, 90, 264, 1, 9157);
#region Rules
int y = 100;
string groupText = null;
switch (tourney.GroupType)
{
case GroupingType.HighVsLow:
groupText = "High vs Low";
break;
case GroupingType.Nearest:
groupText = "Closest opponent";
break;
case GroupingType.Random:
groupText = "Random";
break;
}
AddBorderedText(35, y, 190, 20, $"Grouping: {groupText}", LabelColor32, BlackColor32);
y += 20;
string tieText = null;
switch (tourney.TieType)
{
case TieType.Random:
tieText = "Random";
break;
case TieType.Highest:
tieText = "Highest advances";
break;
case TieType.Lowest:
tieText = "Lowest advances";
break;
case TieType.FullAdvancement:
tieText = tourney.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances";
break;
case TieType.FullElimination:
tieText = tourney.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated";
break;
}
AddBorderedText(35, y, 190, 20, $"Tiebreaker: {tieText}", LabelColor32, BlackColor32);
y += 20;
string sdText = "Off";
if (tourney.SuddenDeath > TimeSpan.Zero)
{
sdText = $"{(int)tourney.SuddenDeath.TotalMinutes}:{tourney.SuddenDeath.Seconds:D2}";
if (tourney.SuddenDeathRounds > 0)
sdText = $"{sdText} (first {tourney.SuddenDeathRounds} rounds)";
else
sdText = $"{sdText} (all rounds)";
}
AddBorderedText(35, y, 240, 20, $"Sudden Death: {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 (int 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 (int i = 0; i < opts.Length; ++i)
if (defs[i] != opts[i])
{
string 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;
}
#endregion
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.DelayCall(TimeSpan.FromSeconds(15.0), AutoReject);
}
public string Center(string text)
{
return $"<CENTER>{text}</CENTER>";
}
public string Color(string text, int color)
{
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
}
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);
}
private void AddColoredText(int x, int y, int width, int height, string text, int color)
{
if (color == 0)
AddHtml(x, y, width, height, text);
else
AddHtml(x, y, width, height, Color(text, color));
}
public void AutoReject()
{
if (!m_Active)
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)
{
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x22, false, $"{m_Requested.Name} seems unresponsive.", m_From.NetState);
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x22, false, $"You have declined the partnership with {m_From.Name}.", m_Requested.NetState);
}
}
public override void OnResponse(NetState sender, RelayInfo info)
{
Mobile from = m_From;
Mobile mob = m_Requested;
if (info.ButtonID != 1 || !m_Active)
return;
m_Active = false;
if (info.IsSwitched(1))
{
if (!(mob is PlayerMobile pm))
return;
if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_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);
}
}
}
else
{
if (info.IsSwitched(3))
AcceptDuelGump.BeginIgnore(m_Requested, m_From);
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
if (m_Registrar != null)
{
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x22, false, $"{mob.Name} has declined your offer of partnership.", from.NetState);
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x22, false, $"You have declined the partnership with {from.Name}.", mob.NetState);
}
}
}
}
}

View file

@ -0,0 +1,285 @@
using System.Collections.Generic;
using System.Text;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.ConPVP
{
public class ArenasMoongate : Item
{
[Constructible]
public ArenasMoongate() : base(0x1FD4)
{
Movable = false;
Light = LightType.Circle300;
}
public ArenasMoongate(Serial serial) : base(serial)
{
}
public override string DefaultName => "arena moongate";
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Light = LightType.Circle300;
}
public bool UseGate(Mobile from)
{
if (DuelContext.CheckCombat(from))
{
from.SendMessage(0x22, "You have recently been in combat with another player and cannot use this moongate.");
return false;
}
if (from.Spell != null)
{
from.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
return false;
}
from.CloseGump<ArenaGump>();
from.SendGump(new ArenaGump(from, this));
if (!from.Hidden || from.AccessLevel == AccessLevel.Player)
Effects.PlaySound(from.Location, from.Map, 0x20E);
return true;
}
public override void OnDoubleClick(Mobile from)
{
if (from.InRange(GetWorldLocation(), 1))
UseGate(from);
else
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
}
public override bool OnMoveOver(Mobile m)
{
return !m.Player || UseGate(m);
}
}
public class ArenaGump : Gump
{
private List<Arena> m_Arenas;
private int m_ColumnX = 12;
private Mobile m_From;
private ArenasMoongate m_Gate;
public ArenaGump(Mobile from, ArenasMoongate gate) : base(50, 50)
{
m_From = from;
m_Gate = gate;
m_Arenas = Arena.Arenas;
AddPage(0);
int height = 12 + 20 + m_Arenas.Count * 31 + 24 + 12;
AddBackground(0, 0, 499 + 40, height, 0x2436);
List<Arena> list = m_Arenas;
for (int i = 1; i < list.Count; i += 2)
AddImageTiled(12, 32 + i * 31, 475 + 40, 30, 0x2430);
AddAlphaRegion(10, 10, 479 + 40, height - 20);
AddColumnHeader(35, null);
AddColumnHeader(115, "Arena");
AddColumnHeader(325, "Participants");
AddColumnHeader(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);
for (int i = 0; i < list.Count; ++i)
{
Arena ar = list[i];
int x = 12;
int y = 32 + i * 31;
int color = ar.Players.Count > 0 ? 0xCCFFCC : 0xCCCCCC;
AddRadio(x + 3, y + 1, 9727, 9730, false, i);
x += 35;
AddBorderedText(x + 5, y + 5, 115 - 5, ar.Name ?? "(no name)", color, 0);
x += 115;
StringBuilder sb = new StringBuilder();
if (ar.Players.Count > 0)
{
Ladder ladder = Ladder.Instance;
if (ladder == null)
continue;
LadderEntry p1 = null, p2 = null, p3 = null, p4 = null;
for (int j = 0; j < ar.Players.Count; ++j)
{
Mobile mob = ar.Players[j];
LadderEntry c = ladder.Find(mob);
if (p1 == null || c.Index < p1.Index)
{
p4 = p3;
p3 = p2;
p2 = p1;
p1 = c;
}
else if (p2 == null || c.Index < p2.Index)
{
p4 = p3;
p3 = p2;
p2 = c;
}
else if (p3 == null || c.Index < p3.Index)
{
p4 = p3;
p3 = c;
}
else if (p4 == null || c.Index < p4.Index)
{
p4 = c;
}
}
Append(sb, p1);
Append(sb, p2);
Append(sb, p3);
Append(sb, p4);
if (ar.Players.Count > 4)
sb.Append(", ...");
}
else
{
sb.Append("Empty");
}
AddBorderedText(x + 5, y + 5, 325 - 5, sb.ToString(), color, 0);
x += 325;
AddBorderedText(x, y + 5, 40, Center(ar.Spectators.ToString()), color, 0);
}
}
private void Append(StringBuilder sb, LadderEntry le)
{
if (le == null)
return;
if (sb.Length > 0)
sb.Append(", ");
sb.Append(le.Mobile.Name);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (info.ButtonID != 1)
return;
int[] switches = info.Switches;
if (switches.Length == 0)
return;
int opt = switches[0];
if (opt < 0 || opt >= m_Arenas.Count)
return;
Arena arena = m_Arenas[opt];
if (!m_From.InRange(m_Gate.GetWorldLocation(), 1) || m_From.Map != m_Gate.Map)
{
m_From.SendLocalizedMessage(1019002); // You are too far away to use the gate.
}
else if (DuelContext.CheckCombat(m_From))
{
m_From.SendMessage(0x22,
"You have recently been in combat with another player and cannot use this moongate.");
}
else if (m_From.Spell != null)
{
m_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))
{
m_From.SendLocalizedMessage(1019003); // You are already there.
}
else
{
BaseCreature.TeleportPets(m_From, arena.GateIn, arena.Facet);
m_From.Combatant = null;
m_From.Warmode = false;
m_From.Hidden = true;
m_From.MoveToWorld(arena.GateIn, arena.Facet);
Effects.PlaySound(arena.GateIn, arena.Facet, 0x1FE);
}
}
public string Center(string text)
{
return $"<CENTER>{text}</CENTER>";
}
public string Color(string text, int color)
{
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
}
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 void AddColoredText(int x, int y, int width, string text, int color)
{
if (color == 0)
AddHtml(x, y, width, 20, text);
else
AddHtml(x, y, width, 20, Color(text, color));
}
private void AddColumnHeader(int width, string name)
{
AddBackground(m_ColumnX, 12, width, 20, 0x242C);
AddImageTiled(m_ColumnX + 2, 14, width - 4, 16, 0x2430);
if (name != null)
AddBorderedText(m_ColumnX, 13, width, Center(name), 0xFFFFFF, 0);
m_ColumnX += width;
}
}
}

View file

@ -0,0 +1,72 @@
using Server.Gumps;
namespace Server.Engines.ConPVP
{
public class BeginGump : Gump
{
private const int LabelColor32 = 0xFFFFFF;
private const int BlackColor32 = 0x000008;
public BeginGump(int count) : base(50, 50)
{
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);
AddHtml(22 - 1, 22, 294, 20, Color(Center("Duel Countdown"), BlackColor32));
AddHtml(22 + 1, 22, 294, 20, Color(Center("Duel Countdown"), BlackColor32));
AddHtml(22, 22 - 1, 294, 20, Color(Center("Duel Countdown"), BlackColor32));
AddHtml(22, 22 + 1, 294, 20, Color(Center("Duel Countdown"), BlackColor32));
AddHtml(22, 22, 294, 20, Color(Center("Duel Countdown"), LabelColor32));
AddHtml(22 - 1, 50, 294, 80,
Color(
"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.",
BlackColor32));
AddHtml(22 + 1, 50, 294, 80,
Color(
"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.",
BlackColor32));
AddHtml(22, 50 - 1, 294, 80,
Color(
"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.",
BlackColor32));
AddHtml(22, 50 + 1, 294, 80,
Color(
"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.",
BlackColor32));
AddHtml(22, 50, 294, 80,
Color(
"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.",
0xFFCC66));
/*AddImageTiled( 32, 128, 264, 1, 9107 );
AddImageTiled( 42, 130, 264, 1, 9157 );
AddHtml( 60-1, 140, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#{2:X6}>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false );
AddHtml( 60+1, 140, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#{2:X6}>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false );
AddHtml( 60, 140-1, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#{2:X6}>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false );
AddHtml( 60, 140+1, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#{2:X6}>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false );
AddHtml( 60, 140, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#FF6666>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", 0x66AACC ), 0x66AACC ), false, false );*/
AddButton(314 - 50, 157 - offset, 247, 248, 1);
}
public string Center(string text)
{
return $"<CENTER>{text}</CENTER>";
}
public string Color(string text, int color)
{
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
}
}
}

View file

@ -0,0 +1,566 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Server.Factions;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Engines.ConPVP
{
public class ConfirmSignupGump : Gump
{
private const int BlackColor32 = 0x000008;
private const int LabelColor32 = 0xFFFFFF;
private Mobile m_From;
private List<Mobile> m_Players;
private Mobile m_Registrar;
private Tournament m_Tournament;
public ConfirmSignupGump(Mobile from, Mobile registrar, Tournament tourney, List<Mobile> players) : base(50, 50)
{
m_From = from;
m_Registrar = registrar;
m_Tournament = tourney;
m_Players = players;
m_From.CloseGump<AcceptTeamGump>();
m_From.CloseGump<AcceptDuelGump>();
m_From.CloseGump<DuelContextGump>();
m_From.CloseGump<ConfirmSignupGump>();
#region Rules
Ruleset ruleset = tourney.Ruleset;
Ruleset basedef = ruleset.Base;
int height = 185 + 60 + 12;
int changes = 0;
BitArray defs;
if (ruleset.Flavors.Count > 0)
{
defs = new BitArray(basedef.Options);
for (int i = 0; i < ruleset.Flavors.Count; ++i)
defs.Or(ruleset.Flavors[i].Options);
height += ruleset.Flavors.Count * 18;
}
else
{
defs = basedef.Options;
}
BitArray opts = ruleset.Options;
for (int i = 0; i < opts.Length; ++i)
if (defs[i] != opts[i])
++changes;
height += changes * 22;
height += 10 + 22 + 25 + 25;
if (tourney.PlayersPerParticipant > 1)
height += 36 + tourney.PlayersPerParticipant * 20;
#endregion
Closable = false;
AddPage(0);
//AddBackground( 0, 0, 400, 220, 9150 );
AddBackground(1, 1, 398, height, 3600);
//AddBackground( 16, 15, 369, 189, 9100 );
AddImageTiled(16, 15, 369, height - 29, 3604);
AddAlphaRegion(16, 15, 369, height - 29);
AddImage(215, -43, 0xEE40);
//AddImage( 330, 141, 0x8BA );
StringBuilder sb = new StringBuilder();
if (tourney.TourneyType == TourneyType.FreeForAll)
{
sb.Append("FFA");
}
else if (tourney.TourneyType == TourneyType.RandomTeam)
{
sb.Append(tourney.ParticipantsPerMatch);
sb.Append("-Team");
}
else if (tourney.TourneyType == TourneyType.Faction)
{
sb.Append(tourney.ParticipantsPerMatch);
sb.Append("-Team Faction");
}
else if (tourney.TourneyType == TourneyType.RedVsBlue)
{
sb.Append("Red v Blue");
}
else
{
for (int i = 0; i < tourney.ParticipantsPerMatch; ++i)
{
if (sb.Length > 0)
sb.Append('v');
sb.Append(tourney.PlayersPerParticipant);
}
}
if (tourney.EventController != null)
sb.Append(' ').Append(tourney.EventController.Title);
sb.Append(" Tournament Signup");
AddBorderedText(22, 22, 294, 20, Center(sb.ToString()), LabelColor32, BlackColor32);
AddBorderedText(22, 50, 294, 40, "You have requested to join the tournament. Do you accept the rules?", 0xB0C868,
BlackColor32);
AddImageTiled(32, 88, 264, 1, 9107);
AddImageTiled(42, 90, 264, 1, 9157);
#region Rules
int y = 100;
string groupText = null;
switch (tourney.GroupType)
{
case GroupingType.HighVsLow:
groupText = "High vs Low";
break;
case GroupingType.Nearest:
groupText = "Closest opponent";
break;
case GroupingType.Random:
groupText = "Random";
break;
}
AddBorderedText(35, y, 190, 20, $"Grouping: {groupText}", LabelColor32, BlackColor32);
y += 20;
string tieText = null;
switch (tourney.TieType)
{
case TieType.Random:
tieText = "Random";
break;
case TieType.Highest:
tieText = "Highest advances";
break;
case TieType.Lowest:
tieText = "Lowest advances";
break;
case TieType.FullAdvancement:
tieText = tourney.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances";
break;
case TieType.FullElimination:
tieText = tourney.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated";
break;
}
AddBorderedText(35, y, 190, 20, $"Tiebreaker: {tieText}", LabelColor32, BlackColor32);
y += 20;
string sdText = "Off";
if (tourney.SuddenDeath > TimeSpan.Zero)
{
sdText = $"{(int)tourney.SuddenDeath.TotalMinutes}:{tourney.SuddenDeath.Seconds:D2}";
if (tourney.SuddenDeathRounds > 0)
sdText = $"{sdText} (first {tourney.SuddenDeathRounds} rounds)";
else
sdText = $"{sdText} (all rounds)";
}
AddBorderedText(35, y, 240, 20, $"Sudden Death: {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 (int 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 (int i = 0; i < opts.Length; ++i)
if (defs[i] != opts[i])
{
string 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;
}
#endregion
#region Team
if (tourney.PlayersPerParticipant > 1)
{
y += 8;
AddImageTiled(32, y - 1, 264, 1, 9107);
AddImageTiled(42, y + 1, 264, 1, 9157);
y += 8;
AddBorderedText(35, y, 190, 20, "Your Team", LabelColor32, BlackColor32);
y += 20;
for (int i = 0; i < players.Count; ++i, y += 20)
{
if (i == 0)
AddImage(35, y, 0xD2);
else
AddGoldenButton(35, y, 1 + i);
AddBorderedText(60, y, 200, 20, players[i].Name, LabelColor32, BlackColor32);
}
for (int i = players.Count; i < tourney.PlayersPerParticipant; ++i, y += 20)
{
if (i == 0)
AddImage(35, y, 0xD2);
else
AddGoldenButton(35, y, 1 + i);
AddBorderedText(60, y, 200, 20, "(Empty)", LabelColor32, BlackColor32);
}
}
#endregion
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 wish to join the tournament.", LabelColor32, BlackColor32);
y += 35;
AddRadio(24, y, 9727, 9730, false, 2);
AddBorderedText(60, y + 5, 250, 20, "No, I do not wish to join.", LabelColor32, BlackColor32);
y += 35;
y -= 3;
AddButton(314, y, 247, 248, 1);
}
public string Center(string text)
{
return $"<CENTER>{text}</CENTER>";
}
public string Color(string text, int color)
{
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
}
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);
}
private void AddColoredText(int x, int y, int width, int height, string text, int color)
{
if (color == 0)
AddHtml(x, y, width, height, text);
else
AddHtml(x, y, width, height, Color(text, color));
}
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, RelayInfo info)
{
if (info.ButtonID == 1 && info.IsSwitched(1))
{
Tournament tourney = m_Tournament;
Mobile from = m_From;
switch (tourney.Stage)
{
case TournamentStage.Fighting:
{
if (m_Registrar != null)
{
if (m_Tournament.HasParticipant(from))
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x35, false, "Excuse me? You are already signed up.", from.NetState);
else
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x22, false, "The tournament has already begun. You are too late to signup now.",
from.NetState);
}
break;
}
case TournamentStage.Inactive:
{
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x35, false, "The tournament is closed.", from.NetState);
break;
}
case TournamentStage.Signup:
{
if (m_Players.Count != tourney.PlayersPerParticipant)
{
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x35, false, "You have not yet chosen your team.", from.NetState);
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
break;
}
Ladder ladder = Ladder.Instance;
for (int i = 0; i < m_Players.Count; ++i)
{
Mobile mob = m_Players[i];
LadderEntry entry = ladder?.Find(mob);
if (entry != null && Ladder.GetLevel(entry.Experience) < tourney.LevelRequirement)
{
if (m_Registrar != null)
{
if (mob == from)
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x35, false, "You have not yet proven yourself a worthy dueler.", from.NetState);
else
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x35, false, $"{mob.Name} has not yet proven themselves a worthy dueler.",
from.NetState);
}
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
return;
}
if (tourney.IsFactionRestricted && Faction.Find(mob) == null)
{
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x35, false, "Only those who have declared their faction allegiance may participate.",
from.NetState);
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
return;
}
if (tourney.HasParticipant(mob))
{
if (m_Registrar != null)
{
if (mob == from)
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x35, false, "You have already entered this tournament.", from.NetState);
else
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x35, false, $"{mob.Name} has already entered this tournament.", from.NetState);
}
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
return;
}
if (mob is PlayerMobile mobile && mobile.DuelContext != null)
{
if (mob == from)
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x35, false,
"You are already assigned to a duel. You must yield it before joining this tournament.",
from.NetState);
else
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x35, false,
$"{mobile.Name} is already assigned to a duel. They must yield it before joining this tournament.",
from.NetState);
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
return;
}
}
if (m_Registrar != null)
{
string fmt;
if (tourney.PlayersPerParticipant == 1)
fmt =
"As you say m'{0}. I've written your name to the bracket. The tournament will begin {1}.";
else if (tourney.PlayersPerParticipant == 2)
fmt =
"As you wish m'{0}. The tournament will begin {1}, but first you must name your partner.";
else
fmt = "As you wish m'{0}. The tournament will begin {1}, but first you must name your team.";
string timeUntil;
int minutesUntil = (int)Math.Round((tourney.SignupStart + tourney.SignupPeriod - DateTime.UtcNow)
.TotalMinutes);
if (minutesUntil == 0)
timeUntil = "momentarily";
else
timeUntil = $"in {minutesUntil} minute{(minutesUntil == 1 ? "" : "s")}";
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
0x35, false, string.Format(fmt, from.Female ? "Lady" : "Lord", timeUntil), from.NetState);
}
TourneyParticipant part = new TourneyParticipant(from);
part.Players.Clear();
part.Players.AddRange(m_Players);
tourney.Participants.Add(part);
break;
}
}
}
else if (info.ButtonID > 1)
{
int index = info.ButtonID - 1;
if (index > 0 && index < m_Players.Count)
{
m_Players.RemoveAt(index);
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
}
else if (m_Players.Count < m_Tournament.PlayersPerParticipant)
{
m_From.BeginTarget(12, false, TargetFlags.None, AddPlayer_OnTarget);
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
}
}
}
private void AddPlayer_OnTarget(Mobile from, object obj)
{
if (!(obj is Mobile mob) || mob == from)
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x22, false, "Excuse me?", from.NetState);
}
else if (!mob.Player)
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
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.
}
else if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x22, false, "They ignore your invitation.", from.NetState);
}
else
{
if (!(mob is PlayerMobile pm))
return;
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 (mob.HasGump<AcceptTeamGump>())
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x22, false, "They have already been offered a partnership.", from.NetState);
}
else if (mob.HasGump<ConfirmSignupGump>())
{
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x22, false, "They are already trying to join this tournament.", 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_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
mob.SendGump(new AcceptTeamGump(from, mob, m_Tournament, m_Registrar, m_Players));
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
0x59, false,
$"As you command m'{(from.Female ? "Lady" : "Lord")}. I've given your offer to {mob.Name}.",
from.NetState);
}
}
}
}
}

View file

@ -0,0 +1,139 @@
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
{
public class DuelContextGump : Gump
{
public DuelContextGump(Mobile from, DuelContext context) : base(50, 50)
{
From = from;
Context = context;
from.CloseGump<RulesetGump>();
from.CloseGump<DuelContextGump>();
from.CloseGump<ParticipantGump>();
int count = context.Participants.Count;
if (count < 3)
count = 3;
int 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"));
int x = 35;
int 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 (int i = 0; i < context.Participants.Count; ++i)
{
Participant 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;
}
}
public Mobile From{ get; }
public DuelContext Context{ get; }
public string Center(string text)
{
return $"<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 void AddGoldenButtonLabeled(int x, int y, int bid, string text)
{
AddGoldenButton(x, y, bid);
AddHtml(x + 25, y, 200, 20, text);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (!Context.Registered)
return;
int index = info.ButtonID;
switch (index)
{
case -1: // CloseGump
{
break;
}
case 0: // closed
{
Context.Unregister();
break;
}
case 1: // Rules
{
//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;
}
case 2: // Start
{
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;
}
case 3: // New Participant
{
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;
}
default: // Participant
{
index -= 4;
if (index >= 0 && index < Context.Participants.Count)
From.SendGump(new ParticipantGump(From, Context, Context.Participants[index]));
break;
}
}
}
}
}

View file

@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
{
public class LadderItem : Item
{
[Constructible]
public LadderItem() : base(0x117F)
{
Movable = false;
}
public LadderItem(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public LadderController Ladder{ get; set; }
public override string DefaultName => "1v1 leaderboard";
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1);
writer.Write(Ladder);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 1:
{
Ladder = reader.ReadItem<LadderController>();
break;
}
}
}
public override void OnDoubleClick(Mobile from)
{
if (from.InRange(GetWorldLocation(), 2))
{
Ladder ladder = ConPVP.Ladder.Instance ?? Ladder.Ladder;
if (ladder != null)
{
from.CloseGump<LadderGump>();
from.SendGump(new LadderGump(ladder));
}
}
else
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
}
}
}
public class LadderGump : Gump
{
private int m_ColumnX = 12;
private Ladder m_Ladder;
private List<LadderEntry> m_List;
private int m_Page;
public LadderGump(Ladder ladder, int page = 0) : base(50, 50)
{
m_Ladder = ladder;
m_Page = page;
AddPage(0);
m_List = new List<LadderEntry>(ladder.Entries);
int lc = Math.Min(m_List.Count, 150);
int start = page * 15;
int end = start + 15;
if (end > lc)
end = lc;
int ct = end - start;
int height = 12 + 20 + ct * 20 + 23 + 12;
AddBackground(0, 0, 499, height, 0x2436);
for (int i = start + 1; i < end; i += 2)
AddImageTiled(12, 32 + (i - start) * 20, 475, 20, 0x2430);
AddAlphaRegion(10, 10, 479, height - 20);
if (page > 0)
AddButton(446, height - 12 - 2 - 16, 0x15E3, 0x15E7, 1);
else
AddImage(446, height - 12 - 2 - 16, 0x2626);
if ((page + 1) * 15 < lc)
AddButton(466, height - 12 - 2 - 16, 0x15E1, 0x15E5, 2);
else
AddImage(466, height - 12 - 2 - 16, 0x2622);
AddHtml(16, height - 12 - 2 - 18, 400, 20,
Color(string.Format("Top {3} of {0:N0} duelists, page {1} of {2}", m_List.Count, page + 1, (lc + 14) / 15, lc),
0xFFC000));
AddColumnHeader(75, "Rank");
AddColumnHeader(115, "Level");
AddColumnHeader(50, "Guild");
AddColumnHeader(115, "Name");
AddColumnHeader(60, "Wins");
AddColumnHeader(60, "Losses");
for (int i = start; i < end && i < lc; ++i)
{
LadderEntry entry = m_List[i];
int y = 32 + (i - start) * 20;
int x = 12;
AddBorderedText(x, y, 75, Center(Rank(i + 1)), 0xFFFFFF, 0);
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);
int xp = entry.Experience;
int level = Ladder.GetLevel(xp);
Ladder.GetLevelInfo(level, out int xpBase, out int xpAdvance);
int width;
int xpOffset = xp - xpBase;
if (xpOffset >= xpAdvance)
width = 109; // level 50
else
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, Center(level.ToString()), 0xFFFFFF, 0);
x += 115;
Mobile mob = entry.Mobile;
if (mob.Guild != null)
AddBorderedText(x, y, 50, Center(mob.Guild.Abbreviation), 0xFFFFFF, 0);
x += 50;
AddBorderedText(x + 5, y, 115 - 5, mob.Name, 0xFFFFFF, 0);
x += 115;
AddBorderedText(x, y, 60, Center(entry.Wins.ToString()), 0xFFFFFF, 0);
x += 60;
AddBorderedText(x, y, 60, Center(entry.Losses.ToString()), 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 );
}
}
public static string Rank(int num)
{
string numStr = num.ToString("N0");
if (num % 100 > 10 && num % 100 < 20)
return numStr + "th";
switch (num % 10)
{
case 1: return numStr + "st";
case 2: return numStr + "nd";
case 3: return numStr + "rd";
default: return numStr + "th";
}
}
public override void OnResponse(NetState sender, RelayInfo info)
{
Mobile from = sender.Mobile;
if (info.ButtonID == 1 && m_Page > 0)
from.SendGump(new LadderGump(m_Ladder, m_Page - 1));
else if (info.ButtonID == 2 && (m_Page + 1) * 15 < Math.Min(m_List.Count, 150))
from.SendGump(new LadderGump(m_Ladder, m_Page + 1));
}
public string Center(string text)
{
return $"<CENTER>{text}</CENTER>";
}
public string Color(string text, int color)
{
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
}
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 void AddColoredText(int x, int y, int width, string text, int color)
{
if (color == 0)
AddHtml(x, y, width, 20, text);
else
AddHtml(x, y, width, 20, Color(text, color));
}
private void AddColumnHeader(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, Center(name), 0xFFFFFF, 0);
m_ColumnX += width;
}
}
}

View file

@ -0,0 +1,253 @@
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Engines.ConPVP
{
public class ParticipantGump : Gump
{
public ParticipantGump(Mobile from, DuelContext context, Participant p) : base(50, 50)
{
From = from;
Context = context;
Participant = p;
from.CloseGump<RulesetGump>();
from.CloseGump<DuelContextGump>();
from.CloseGump<ParticipantGump>();
int count = p.Players.Length;
if (count < 4)
count = 4;
AddPage(0);
int 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"));
int x = 35;
int 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 (int i = 0; i < p.Players.Length; ++i)
{
DuelPlayer pl = p.Players[i];
AddGoldenButtonLabeled(x, y, 5 + i, $"{1 + i}: {(pl == null ? "Empty" : pl.Mobile.Name)}");
y += 22;
}
}
public Mobile From{ get; }
public DuelContext Context{ get; }
public Participant Participant{ get; }
public string Center(string text)
{
return $"<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 void AddGoldenButtonLabeled(int x, int y, int bid, string text)
{
AddGoldenButton(x, y, bid);
AddHtml(x + 25, y, 200, 20, text);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (!Context.Registered)
return;
int bid = info.ButtonID;
if (bid == 0)
{
From.SendGump(new DuelContextGump(From, Context));
}
else if (bid == 1)
{
if (Participant.Count < 8)
Participant.Resize(Participant.Count + 1);
else
From.SendMessage("You may not raise the team size any further.");
From.SendGump(new ParticipantGump(From, Context, Participant));
}
else if (bid == 2)
{
if (Participant.Count > 1 && Participant.Count > Participant.FilledSlots)
Participant.Resize(Participant.Count - 1);
else
From.SendMessage("You may not lower the team size any further.");
From.SendGump(new ParticipantGump(From, Context, Participant));
}
else if (bid == 3)
{
if (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));
}
else if (Context.Participants.Count > 2)
{
/*Container cont = m_Participant.Stakes;
if ( cont != null )
cont.Delete();*/
Context.Participants.Remove(Participant);
From.SendGump(new DuelContextGump(From, Context));
}
else
{
From.SendMessage("Duels must have at least two participating parties.");
From.SendGump(new ParticipantGump(From, Context, Participant));
}
}
/*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)
{
if (Participant.Players[bid] == null)
{
From.Target = new ParticipantTarget(Context, Participant, bid);
From.SendMessage("Target a player.");
}
else
{
Participant.Players[bid].Mobile.SendMessage("You have been removed from the duel.");
if (Participant.Players[bid].Mobile is PlayerMobile)
((PlayerMobile)Participant.Players[bid].Mobile).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 DuelContext m_Context;
private int m_Index;
private 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;
int index = m_Index;
if (index < 0 || index >= m_Participant.Players.Length)
return;
if (!(targeted is 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.
}
else if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
{
from.SendMessage("They ignore your offer.");
}
else
{
if (!(mob is PlayerMobile pm))
return;
if (pm.DuelContext != null)
{
from.SendMessage("{0} cannot fight because they are already assigned to another duel.", pm.Name);
}
else if (DuelContext.CheckCombat(pm))
{
from.SendMessage("{0} cannot fight because they have recently been in combat with another player.",
pm.Name);
}
else if (mob.HasGump<AcceptDuelGump>())
{
from.SendMessage("{0} has already been offered a duel.");
}
else
{
from.SendMessage("You send {0} to {1}.",
m_Participant.Find(from) == null ? "a challenge" : "an invitation", mob.Name);
mob.SendGump(new AcceptDuelGump(from, mob, m_Context, m_Participant, m_Index));
}
}
}
protected override void OnTargetFinish(Mobile from)
{
from.SendGump(new ParticipantGump(from, m_Context, m_Participant));
}
}
}
}

View file

@ -0,0 +1,126 @@
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
{
public class PickRulesetGump : Gump
{
private DuelContext m_Context;
private Ruleset[] m_Defaults;
private Ruleset[] m_Flavors;
private Mobile m_From;
private Ruleset m_Ruleset;
public PickRulesetGump(Mobile from, DuelContext context, Ruleset ruleset) : base(50, 50)
{
m_From = from;
m_Context = context;
m_Ruleset = ruleset;
m_Defaults = ruleset.Layout.Defaults;
m_Flavors = ruleset.Layout.Flavors;
int 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"));
int y = 25 + 20;
for (int i = 0; i < m_Defaults.Length; ++i)
{
Ruleset 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 (int i = 0; i < m_Flavors.Length; ++i)
{
Ruleset 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;
}
}
public string Center(string text)
{
return $"<CENTER>{text}</CENTER>";
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (m_Context?.Registered == false)
return;
switch (info.ButtonID)
{
case 0: // closed
{
if (m_Context != null)
m_From.SendGump(new DuelContextGump(m_From, m_Context));
break;
}
case 1: // customize
{
m_From.SendGump(new RulesetGump(m_From, m_Ruleset, m_Ruleset.Layout, m_Context));
break;
}
default:
{
int idx = info.ButtonID - 2;
if (idx >= 0 && idx < m_Defaults.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 (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));
}
}
break;
}
}
}
}
}

View file

@ -0,0 +1,109 @@
using System.Collections.Generic;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
{
public class ReadyGump : Gump
{
private DuelContext m_Context;
private int m_Count;
private Mobile m_From;
public ReadyGump(Mobile from, DuelContext context, int count) : base(50, 50)
{
m_From = from;
m_Context = context;
m_Count = count;
List<Participant> parts = context.Participants;
int height = 25 + 20;
for (int i = 0; i < parts.Count; ++i)
{
Participant 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);
}
int y = 25 + 20;
for (int i = 0; i < parts.Count; ++i)
{
Participant p = parts[i];
y += 4;
bool isAllReady = true;
int yStore = y;
int offset = 0;
if (p.Players.Length > 1)
{
AddHtml(35 + 14, y, 176, 20, $"Participant #{i + 1}");
y += 22;
offset = 10;
}
for (int j = 0; j < p.Players.Length; ++j)
{
DuelPlayer pl = p.Players[j];
if (pl?.Ready == true)
{
AddImage(35 + offset, y + 4, 0x939);
}
else
{
AddImage(35 + offset, y + 4, 0x938);
isAllReady = false;
}
string 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);
}
}
public string Center(string text)
{
return $"<CENTER>{text}</CENTER>";
}
public override void OnResponse(NetState sender, RelayInfo info)
{
}
}
}

View file

@ -0,0 +1,233 @@
using System.Collections;
using System.Collections.Generic;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.ConPVP
{
public class ReadyUpGump : Gump
{
private DuelContext m_Context;
private Mobile m_From;
public ReadyUpGump(Mobile from, DuelContext context) : base(50, 50)
{
m_From = from;
m_Context = context;
Closable = false;
AddPage(0);
if (context.Rematch)
{
int height = 25 + 20 + 10 + 22 + 25;
AddBackground(0, 0, 210, height, 9250);
AddBackground(10, 10, 190, height - 20, 0xDAC);
AddHtml(35, 25, 140, 20, Center("Rematch?"));
AddButton(35, 55, 247, 248, 1);
AddButton(115, 55, 242, 241, 2);
}
else
{
#region Participants
AddPage(1);
List<Participant> parts = context.Participants;
int height = 25 + 20;
for (int i = 0; i < parts.Count; ++i)
{
Participant p = parts[i];
height += 4;
if (p.Players.Length > 1)
height += 22;
height += p.Players.Length * 22;
}
height += 10 + 22 + 25;
AddBackground(0, 0, 260, height, 9250);
AddBackground(10, 10, 240, height - 20, 0xDAC);
AddHtml(35, 25, 190, 20, Center("Participants"));
int y = 20 + 25;
for (int i = 0; i < parts.Count; ++i)
{
Participant p = parts[i];
y += 4;
int offset = 0;
if (p.Players.Length > 1)
{
AddHtml(35, y, 176, 20, $"Team #{i + 1}");
y += 22;
offset = 10;
}
for (int j = 0; j < p.Players.Length; ++j)
{
DuelPlayer pl = p.Players[j];
string 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);
#endregion
#region Rules
AddPage(2);
Ruleset ruleset = context.Ruleset;
Ruleset basedef = ruleset.Base;
height = 25 + 20 + 5 + 20 + 20 + 4;
int changes = 0;
BitArray defs;
if (ruleset.Flavors.Count > 0)
{
defs = new BitArray(basedef.Options);
for (int i = 0; i < ruleset.Flavors.Count; ++i)
defs.Or(ruleset.Flavors[i].Options);
height += ruleset.Flavors.Count * 18;
}
else
{
defs = basedef.Options;
}
BitArray opts = ruleset.Options;
for (int i = 0; i < opts.Length; ++i)
if (defs[i] != opts[i])
++changes;
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 (int 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 (int i = 0; i < opts.Length; ++i)
if (defs[i] != opts[i])
{
string 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);
#endregion
}
}
public string Center(string text)
{
return $"<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, RelayInfo info)
{
if (!m_Context.Registered || !m_Context.ReadyWait)
return;
switch (info.ButtonID)
{
case 1: // okay
{
if (!(m_From is PlayerMobile pm))
break;
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;
}
}
}
}
}

View file

@ -0,0 +1,130 @@
using System.Collections;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.ConPVP
{
public class RulesetGump : Gump
{
private DuelContext m_DuelContext;
private Mobile m_From;
private RulesetLayout m_Page;
private bool m_ReadOnly;
private Ruleset m_Ruleset;
public RulesetGump(Mobile from, Ruleset ruleset, RulesetLayout page, DuelContext duelContext, bool readOnly = false)
: base(readOnly ? 310 : 50, 50)
{
m_From = from;
m_Ruleset = ruleset;
m_Page = page;
m_DuelContext = duelContext;
m_ReadOnly = readOnly;
Draggable = !readOnly;
from.CloseGump<RulesetGump>();
from.CloseGump<DuelContextGump>();
from.CloseGump<ParticipantGump>();
RulesetLayout depthCounter = page;
int depth = 0;
while (depthCounter != null)
{
++depth;
depthCounter = depthCounter.Parent;
}
int count = page.Children.Length + page.Options.Length;
AddPage(0);
int 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));
int x = 35;
int y = 47;
for (int 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 (int i = 0; i < page.Options.Length; ++i)
{
bool 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;
}
}
public string Center(string text)
{
return $"<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, RelayInfo info)
{
if (m_DuelContext?.Registered == false)
return;
if (!m_ReadOnly)
{
BitArray opts = new BitArray(m_Page.Options.Length);
for (int i = 0; i < info.Switches.Length; ++i)
{
int sid = info.Switches[i];
if (sid >= 0 && sid < m_Page.Options.Length)
opts[sid] = true;
}
for (int 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;
}
}
int 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));
}
else
{
bid -= 1;
if (bid >= 0 && bid < m_Page.Children.Length)
m_From.SendGump(new RulesetGump(m_From, m_Ruleset, m_Page.Children[bid], m_DuelContext, m_ReadOnly));
}
}
}
}

View file

@ -0,0 +1,856 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.ConPVP
{
public enum TourneyBracketGumpType
{
Index,
Rules_Info,
Participant_List,
Participant_Info,
Round_List,
Round_Info,
Match_Info,
Player_Info
}
public class TournamentBracketGump : Gump
{
private const int BlackColor32 = 0x000008;
private const int LabelColor32 = 0xFFFFFF;
private Mobile m_From;
private List<object> m_List;
private object m_Object;
private int m_Page;
private int m_PerPage;
private Tournament m_Tournament;
private TourneyBracketGumpType m_Type;
public TournamentBracketGump(Mobile from, Tournament tourney, TourneyBracketGumpType type,
List<object> list = null, int page = 0, object obj = null) : base(50, 50)
{
m_From = from;
m_Tournament = tourney;
m_Type = type;
m_List = list;
m_Page = page;
m_Object = obj;
m_PerPage = 12;
switch (type)
{
case TourneyBracketGumpType.Index:
{
AddPage(0);
AddBackground(0, 0, 300, 300, 9380);
StringBuilder sb = new StringBuilder();
if (tourney.TourneyType == TourneyType.FreeForAll)
{
sb.Append("FFA");
}
else if (tourney.TourneyType == TourneyType.RandomTeam)
{
sb.Append(tourney.ParticipantsPerMatch);
sb.Append("-Team");
}
else if (tourney.TourneyType == TourneyType.RedVsBlue)
{
sb.Append("Red v Blue");
}
else if (tourney.TourneyType == TourneyType.Faction)
{
sb.Append(tourney.ParticipantsPerMatch);
sb.Append("-Team Faction");
}
else
{
for (int i = 0; i < tourney.ParticipantsPerMatch; ++i)
{
if (sb.Length > 0)
sb.Append('v');
sb.Append(tourney.PlayersPerParticipant);
}
}
if (tourney.EventController != null)
sb.Append(' ').Append(tourney.EventController.Title);
sb.Append(" Tournament Bracket");
AddHtml(25, 35, 250, 20, Center(sb.ToString()));
AddRightArrow(25, 53, ToButtonID(0, 4), "Rules");
AddRightArrow(25, 71, ToButtonID(0, 1), "Participants");
if (m_Tournament.Stage == TournamentStage.Signup)
{
TimeSpan until = m_Tournament.SignupStart + m_Tournament.SignupPeriod - DateTime.UtcNow;
string text;
int secs = (int)until.TotalSeconds;
if (secs > 0)
{
int mins = secs / 60;
secs %= 60;
if (mins > 0 && secs > 0)
text =
$"The tournament will begin in {mins} minute{(mins == 1 ? "" : "s")} and {secs} second{(secs == 1 ? "" : "s")}.";
else if (mins > 0)
text = $"The tournament will begin in {mins} minute{(mins == 1 ? "" : "s")}.";
else if (secs > 0)
text = $"The tournament will begin in {secs} second{(secs == 1 ? "" : "s")}.";
else
text = "The tournament will begin shortly.";
}
else
{
text = "The tournament will begin shortly.";
}
AddHtml(25, 92, 250, 40, text);
}
else
{
AddRightArrow(25, 89, ToButtonID(0, 2), "Rounds");
}
break;
}
case TourneyBracketGumpType.Rules_Info:
{
Ruleset ruleset = tourney.Ruleset;
Ruleset basedef = ruleset.Base;
BitArray defs;
if (ruleset.Flavors.Count > 0)
{
defs = new BitArray(basedef.Options);
for (int i = 0; i < ruleset.Flavors.Count; ++i)
defs.Or(ruleset.Flavors[i].Options);
}
else
{
defs = basedef.Options;
}
int changes = 0;
BitArray opts = ruleset.Options;
for (int i = 0; i < opts.Length; ++i)
if (defs[i] != opts[i])
++changes;
AddPage(0);
AddBackground(0, 0, 300,
60 + 18 + 20 + 20 + 20 + 8 + 20 + ruleset.Flavors.Count * 18 + 4 + 20 + changes * 22 + 6, 9380);
AddLeftArrow(25, 11, ToButtonID(0, 0));
AddHtml(25, 35, 250, 20, Center("Rules"));
int y = 53;
string groupText = null;
switch (tourney.GroupType)
{
case GroupingType.HighVsLow:
groupText = "High vs Low";
break;
case GroupingType.Nearest:
groupText = "Closest opponent";
break;
case GroupingType.Random:
groupText = "Random";
break;
}
AddHtml(35, y, 190, 20, $"Grouping: {groupText}");
y += 20;
string tieText = null;
switch (tourney.TieType)
{
case TieType.Random:
tieText = "Random";
break;
case TieType.Highest:
tieText = "Highest advances";
break;
case TieType.Lowest:
tieText = "Lowest advances";
break;
case TieType.FullAdvancement:
tieText = tourney.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances";
break;
case TieType.FullElimination:
tieText = tourney.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated";
break;
}
AddHtml(35, y, 190, 20, $"Tiebreaker: {tieText}");
y += 20;
string sdText = "Off";
if (tourney.SuddenDeath > TimeSpan.Zero)
{
sdText = $"{(int)tourney.SuddenDeath.TotalMinutes}:{tourney.SuddenDeath.Seconds:D2}";
if (tourney.SuddenDeathRounds > 0)
sdText = $"{sdText} (first {tourney.SuddenDeathRounds} rounds)";
else
sdText = $"{sdText} (all rounds)";
}
AddHtml(35, y, 240, 20, $"Sudden Death: {sdText}");
y += 20;
y += 8;
AddHtml(35, y, 190, 20, $"Ruleset: {basedef.Title}");
y += 20;
for (int 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 (int i = 0; i < opts.Length; ++i)
if (defs[i] != opts[i])
{
string 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");
}
break;
}
case TourneyBracketGumpType.Participant_List:
{
AddPage(0);
AddBackground(0, 0, 300, 300, 9380);
List<TourneyParticipant> pList = m_List != null
? Utility.CastListCovariant<object, TourneyParticipant>(m_List)
: new List<TourneyParticipant>(tourney.Participants);
AddLeftArrow(25, 11, ToButtonID(0, 0));
AddHtml(25, 35, 250, 20, Center($"{pList.Count} Participant{(pList.Count == 1 ? "" : "s")}"));
StartPage(out int index, out int count, out int y, 12);
for (int i = 0; i < count; ++i, y += 18)
{
TourneyParticipant part = pList[index + i];
string name = part.NameList;
if (m_Tournament.TourneyType != TourneyType.Standard && part.Players.Count == 1)
if (part.Players[0] is PlayerMobile pm && pm.DuelPlayer != null)
name = Color(name, pm.DuelPlayer.Eliminated ? 0x6633333 : 0x336666);
AddRightArrow(25, y, ToButtonID(2, index + i), name);
}
break;
}
case TourneyBracketGumpType.Participant_Info:
{
if (!(obj is TourneyParticipant part))
break;
AddPage(0);
AddBackground(0, 0, 300, 60 + 18 + 20 + part.Players.Count * 18 + 20 + 20 + 160, 9380);
AddLeftArrow(25, 11, ToButtonID(0, 1));
AddHtml(25, 35, 250, 20, Center("Participants"));
int y = 53;
AddHtml(25, y, 200, 20, part.Players.Count == 1 ? "Players" : "Team");
y += 20;
for (int i = 0; i < part.Players.Count; ++i)
{
Mobile mob = part.Players[i];
string name = mob.Name;
if (m_Tournament.TourneyType != TourneyType.Standard)
if (mob is PlayerMobile pm && pm.DuelPlayer != null)
name = Color(name, pm.DuelPlayer.Eliminated ? 0x6633333 : 0x336666);
AddRightArrow(35, y, ToButtonID(4, i), name);
y += 18;
}
AddHtml(25, y, 200, 20,
$"Free Advances: {(part.FreeAdvances == 0 ? "None" : part.FreeAdvances.ToString())}");
y += 20;
AddHtml(25, y, 200, 20, "Log:");
y += 20;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < part.Log.Count; ++i)
{
if (sb.Length > 0)
sb.Append("<br>");
sb.Append(part.Log[i]);
}
if (sb.Length == 0)
sb.Append("Nothing logged yet.");
AddHtml(25, y, 250, 150, Color(sb.ToString(), BlackColor32), false, true);
break;
}
case TourneyBracketGumpType.Player_Info:
{
AddPage(0);
AddBackground(0, 0, 300, 300, 9380);
AddLeftArrow(25, 11, ToButtonID(0, 3));
AddHtml(25, 35, 250, 20, Center("Participants"));
if (!(obj is Mobile mob))
break;
Ladder ladder = Ladder.Instance;
LadderEntry entry = ladder?.Find(mob);
AddHtml(25, 53, 250, 20, $"Name: {mob.Name}");
AddHtml(25, 73, 250, 20,
$"Guild: {(mob.Guild == null ? "None" : mob.Guild.Name + " [" + mob.Guild.Abbreviation + "]")}");
AddHtml(25, 93, 250, 20, $"Rank: {(entry == null ? "N/A" : LadderGump.Rank(entry.Index + 1))}");
AddHtml(25, 113, 250, 20, $"Level: {(entry == null ? 0 : Ladder.GetLevel(entry.Experience))}");
AddHtml(25, 133, 250, 20, $"Wins: {entry?.Wins ?? 0:N0}");
AddHtml(25, 153, 250, 20, $"Losses: {entry?.Losses ?? 0:N0}");
break;
}
case TourneyBracketGumpType.Round_List:
{
AddPage(0);
AddBackground(0, 0, 300, 300, 9380);
AddLeftArrow(25, 11, ToButtonID(0, 0));
AddHtml(25, 35, 250, 20, Center("Rounds"));
// List<PyramidLevel> levelsList = m_List != null
// ? Utility.CastListCovariant<object, PyramidLevel>(m_List)
// : new List<PyramidLevel>(tourney.Pyramid.Levels);
StartPage(out int index, out int count, out int y, 12);
for (int i = 0; i < count; ++i, y += 18)
AddRightArrow(25, y, ToButtonID(3, index + i), "Round #" + (index + i + 1));
break;
}
case TourneyBracketGumpType.Round_Info:
{
AddPage(0);
AddBackground(0, 0, 300, 300, 9380);
AddLeftArrow(25, 11, ToButtonID(0, 2));
AddHtml(25, 35, 250, 20, Center("Rounds"));
if (!(m_Object is PyramidLevel level))
break;
List<TourneyMatch> matchesList = m_List != null
? Utility.CastListCovariant<object, TourneyMatch>(m_List)
: new List<TourneyMatch>(level.Matches);
AddRightArrow(25, 53, ToButtonID(5, 0),
$"Free Advance: {(level.FreeAdvance == null ? "None" : level.FreeAdvance.NameList)}");
AddHtml(25, 73, 200, 20, $"{matchesList.Count} Match{(matchesList.Count == 1 ? "" : "es")}");
StartPage(out int index, out int count, out int y, 10);
for (int i = 0; i < count; ++i, y += 18)
{
TourneyMatch match = matchesList[index + i];
int color = -1;
if (match.InProgress)
color = 0x336666;
else if (match.Context != null && match.Winner == null)
color = 0x666666;
StringBuilder sb = new StringBuilder();
if (m_Tournament.TourneyType == TourneyType.Standard)
for (int j = 0; j < match.Participants.Count; ++j)
{
if (sb.Length > 0)
sb.Append(" vs ");
TourneyParticipant part = match.Participants[j];
string txt = part.NameList;
if (color == -1 && match.Context != null && match.Winner == part)
txt = Color(txt, 0x336633);
else if (color == -1 && match.Context != null)
txt = Color(txt, 0x663333);
sb.Append(txt);
}
else if (m_Tournament.EventController != null || m_Tournament.TourneyType == TourneyType.RandomTeam ||
m_Tournament.TourneyType == TourneyType.RedVsBlue ||
m_Tournament.TourneyType == TourneyType.Faction)
for (int j = 0; j < match.Participants.Count; ++j)
{
if (sb.Length > 0)
sb.Append(" vs ");
TourneyParticipant part = match.Participants[j];
string txt;
if (m_Tournament.EventController != null)
{
txt = $"Team {m_Tournament.EventController.GetTeamName(j)} ({part.Players.Count})";
}
else if (m_Tournament.TourneyType == TourneyType.RandomTeam)
{
txt = $"Team {j + 1} ({part.Players.Count})";
}
else if (m_Tournament.TourneyType == TourneyType.Faction)
{
if (m_Tournament.ParticipantsPerMatch == 4)
{
string name = "(null)";
switch (j)
{
case 0:
{
name = "Minax";
break;
}
case 1:
{
name = "Council of Mages";
break;
}
case 2:
{
name = "True Britannians";
break;
}
case 3:
{
name = "Shadowlords";
break;
}
}
txt = $"{name} ({part.Players.Count})";
}
else if (m_Tournament.ParticipantsPerMatch == 2)
{
txt = $"{(j == 0 ? "Evil" : "Hero")} Team ({part.Players.Count})";
}
else
{
txt = $"Team {j + 1} ({part.Players.Count})";
}
}
else
{
txt = $"Team {(j == 0 ? "Red" : "Blue")} ({part.Players.Count})";
}
if (color == -1 && match.Context != null && match.Winner == part)
txt = Color(txt, 0x336633);
else if (color == -1 && match.Context != null)
txt = Color(txt, 0x663333);
sb.Append(txt);
}
else if (m_Tournament.TourneyType == TourneyType.FreeForAll) sb.Append("Free For All");
string str = sb.ToString();
if (color >= 0)
str = Color(str, color);
AddRightArrow(25, y, ToButtonID(5, index + i + 1), str);
}
break;
}
case TourneyBracketGumpType.Match_Info:
{
if (!(obj is TourneyMatch match))
break;
int ct = m_Tournament.TourneyType == TourneyType.FreeForAll ? 2 : match.Participants.Count;
AddPage(0);
AddBackground(0, 0, 300, 60 + 18 + 20 + 20 + 20 + ct * 18 + 6, 9380);
AddLeftArrow(25, 11, ToButtonID(0, 5));
AddHtml(25, 35, 250, 20, Center("Rounds"));
AddHtml(25, 53, 250, 20, $"Winner: {(match.Winner == null ? "N/A" : match.Winner.NameList)}");
AddHtml(25, 73, 250, 20,
$"State: {(match.InProgress ? "In progress" : match.Context != null ? "Complete" : "Waiting")}");
AddHtml(25, 93, 250, 20, "Participants:");
if (m_Tournament.TourneyType == TourneyType.Standard)
for (int i = 0; i < match.Participants.Count; ++i)
{
TourneyParticipant part = match.Participants[i];
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i), part.NameList);
}
else if (m_Tournament.EventController != null || m_Tournament.TourneyType == TourneyType.RandomTeam ||
m_Tournament.TourneyType == TourneyType.RedVsBlue ||
m_Tournament.TourneyType == TourneyType.Faction)
for (int i = 0; i < match.Participants.Count; ++i)
{
TourneyParticipant part = match.Participants[i];
if (m_Tournament.EventController != null)
{
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
$"Team {m_Tournament.EventController.GetTeamName(i)} ({part.Players.Count})");
}
else if (m_Tournament.TourneyType == TourneyType.RandomTeam)
{
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
$"Team {i + 1} ({part.Players.Count})");
}
else if (m_Tournament.TourneyType == TourneyType.Faction)
{
if (m_Tournament.ParticipantsPerMatch == 4)
{
string name = "(null)";
switch (i)
{
case 0:
{
name = "Minax";
break;
}
case 1:
{
name = "Council of Mages";
break;
}
case 2:
{
name = "True Britannians";
break;
}
case 3:
{
name = "Shadowlords";
break;
}
}
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
$"{name} ({part.Players.Count})");
}
else if (m_Tournament.ParticipantsPerMatch == 2)
{
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
$"{(i == 0 ? "Evil" : "Hero")} Team ({part.Players.Count})");
}
else
{
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
$"Team {i + 1} ({part.Players.Count})");
}
}
else
{
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
$"Team {(i == 0 ? "Red" : "Blue")} ({part.Players.Count})");
}
}
else if (m_Tournament.TourneyType == TourneyType.FreeForAll)
AddHtml(25, 113, 250, 20, "Free For All");
break;
}
}
}
public string Center(string text)
{
return $"<CENTER>{text}</CENTER>";
}
public string Color(string text, int color)
{
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
}
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);
}
private void AddColoredText(int x, int y, int width, int height, string text, int color)
{
if (color == 0)
AddHtml(x, y, width, height, text);
else
AddHtml(x, y, width, height, Color(text, color));
}
public void AddRightArrow(int x, int y, int bid, string text)
{
AddButton(x, y, 0x15E1, 0x15E5, bid);
if (text != null)
AddHtml(x + 20, y - 1, 230, 20, text);
}
public void AddRightArrow(int x, int y, int bid)
{
AddRightArrow(x, y, bid, null);
}
public void AddLeftArrow(int x, int y, int bid, string text)
{
AddButton(x, y, 0x15E3, 0x15E7, bid);
if (text != null)
AddHtml(x + 20, y - 1, 230, 20, text);
}
public void AddLeftArrow(int x, int y, int bid)
{
AddLeftArrow(x, y, bid, null);
}
public int ToButtonID(int type, int index)
{
return 1 + index * 7 + type;
}
public bool FromButtonID(int bid, out int type, out int index)
{
type = (bid - 1) % 7;
index = (bid - 1) / 7;
return bid >= 1;
}
public void StartPage(out int index, out int count, out int y, int perPage)
{
m_PerPage = perPage;
index = Math.Max(m_Page * perPage, 0);
count = Math.Max(Math.Min(m_List.Count - index, perPage), 0);
y = 53 + (12 - perPage) * 18;
if (m_Page > 0)
AddLeftArrow(242, 35, ToButtonID(1, 0));
if ((m_Page + 1) * perPage < m_List.Count)
AddRightArrow(260, 35, ToButtonID(1, 1));
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (!FromButtonID(info.ButtonID, out int type, out int index))
return;
switch (type)
{
case 0:
{
switch (index)
{
case 0:
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Index));
break;
case 1:
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
TourneyBracketGumpType.Participant_List));
break;
case 2:
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Round_List));
break;
case 4:
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Rules_Info));
break;
case 3:
{
Mobile mob = m_Object as Mobile;
for (int i = 0; i < m_Tournament.Participants.Count; ++i)
{
TourneyParticipant part = m_Tournament.Participants[i];
if (part.Players.Contains(mob))
{
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
TourneyBracketGumpType.Participant_Info, null, 0, part));
break;
}
}
break;
}
case 5:
{
if (!(m_Object is TourneyMatch match))
break;
for (int i = 0; i < m_Tournament.Pyramid.Levels.Count; ++i)
{
PyramidLevel level = m_Tournament.Pyramid.Levels[i];
if (level.Matches.Contains(match))
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
TourneyBracketGumpType.Round_Info, null, 0, level));
}
break;
}
}
break;
}
case 1:
{
switch (index)
{
case 0:
{
if (m_List != null && m_Page > 0)
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, m_Type, m_List, m_Page - 1,
m_Object));
break;
}
case 1:
{
if (m_List != null && (m_Page + 1) * m_PerPage < m_List.Count)
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, m_Type, m_List, m_Page + 1,
m_Object));
break;
}
}
break;
}
case 2:
{
if (m_Type != TourneyBracketGumpType.Participant_List)
break;
if (index >= 0 && index < m_List.Count)
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
TourneyBracketGumpType.Participant_Info, null, 0, m_List[index]));
break;
}
case 3:
{
if (m_Type != TourneyBracketGumpType.Round_List)
break;
if (index >= 0 && index < m_List.Count)
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Round_Info,
null, 0, m_List[index]));
break;
}
case 4:
{
if (m_Type != TourneyBracketGumpType.Participant_Info)
break;
if (m_Object is TourneyParticipant part && index >= 0 && index < part.Players.Count)
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Player_Info,
null, 0, part.Players[index]));
break;
}
case 5:
{
if (m_Type != TourneyBracketGumpType.Round_Info)
break;
if (!(m_Object is PyramidLevel level))
break;
if (index == 0)
{
if (level.FreeAdvance != null)
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
TourneyBracketGumpType.Participant_Info, null, 0, level.FreeAdvance));
else
m_From.SendGump(
new TournamentBracketGump(m_From, m_Tournament, m_Type, m_List, m_Page, m_Object));
}
else if (index >= 1 && index <= level.Matches.Count)
{
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Match_Info,
null, 0, level.Matches[index - 1]));
}
break;
}
case 6:
{
if (m_Type != TourneyBracketGumpType.Match_Info)
break;
if (m_Object is TourneyMatch match && index >= 0 && index < match.Participants.Count)
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
TourneyBracketGumpType.Participant_Info, null, 0, match.Participants[index]));
break;
}
}
}
}
}