Reorganizes Project (#41)
This commit is contained in:
parent
08bf44af9a
commit
3614a66aee
3499 changed files with 79 additions and 55 deletions
279
Projects/Scripts/Engines/ConPVP/AcceptDuelGump.cs
Normal file
279
Projects/Scripts/Engines/ConPVP/AcceptDuelGump.cs
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class AcceptDuelGump : Gump
|
||||
{
|
||||
private const int LabelColor32 = 0xFFFFFF;
|
||||
private const int BlackColor32 = 0x000008;
|
||||
|
||||
private static Dictionary<Mobile, List<IgnoreEntry>> m_IgnoreLists = new Dictionary<Mobile, List<IgnoreEntry>>();
|
||||
|
||||
private bool m_Active = true;
|
||||
private Mobile m_Challenger, m_Challenged;
|
||||
private DuelContext m_Context;
|
||||
private Participant m_Participant;
|
||||
private int m_Slot;
|
||||
|
||||
public AcceptDuelGump(Mobile challenger, Mobile challenged, DuelContext context, Participant p, int slot) : base(50,
|
||||
50)
|
||||
{
|
||||
m_Challenger = challenger;
|
||||
m_Challenged = challenged;
|
||||
m_Context = context;
|
||||
m_Participant = p;
|
||||
m_Slot = slot;
|
||||
|
||||
challenged.CloseGump<AcceptDuelGump>();
|
||||
|
||||
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 );
|
||||
|
||||
AddHtml(22 - 1, 22, 294, 20, Color(Center("Duel Challenge"), BlackColor32));
|
||||
AddHtml(22 + 1, 22, 294, 20, Color(Center("Duel Challenge"), BlackColor32));
|
||||
AddHtml(22, 22 - 1, 294, 20, Color(Center("Duel Challenge"), BlackColor32));
|
||||
AddHtml(22, 22 + 1, 294, 20, Color(Center("Duel Challenge"), BlackColor32));
|
||||
AddHtml(22, 22, 294, 20, Color(Center("Duel Challenge"), LabelColor32));
|
||||
|
||||
string fmt;
|
||||
|
||||
if (p.Contains(challenger))
|
||||
fmt = "You have been asked to join sides with {0} in a duel. Do you accept?";
|
||||
else
|
||||
fmt = "You have been challenged to a duel from {0}. Do you accept?";
|
||||
|
||||
AddHtml(22 - 1, 50, 294, 40, Color(string.Format(fmt, challenger.Name), BlackColor32));
|
||||
AddHtml(22 + 1, 50, 294, 40, Color(string.Format(fmt, challenger.Name), BlackColor32));
|
||||
AddHtml(22, 50 - 1, 294, 40, Color(string.Format(fmt, challenger.Name), BlackColor32));
|
||||
AddHtml(22, 50 + 1, 294, 40, Color(string.Format(fmt, challenger.Name), BlackColor32));
|
||||
AddHtml(22, 50, 294, 40, Color(string.Format(fmt, challenger.Name), 0xB0C868));
|
||||
|
||||
AddImageTiled(32, 88, 264, 1, 9107);
|
||||
AddImageTiled(42, 90, 264, 1, 9157);
|
||||
|
||||
AddRadio(24, 100, 9727, 9730, true, 1);
|
||||
AddHtml(60 - 1, 105, 250, 20, Color("Yes, I will fight this duel.", BlackColor32));
|
||||
AddHtml(60 + 1, 105, 250, 20, Color("Yes, I will fight this duel.", BlackColor32));
|
||||
AddHtml(60, 105 - 1, 250, 20, Color("Yes, I will fight this duel.", BlackColor32));
|
||||
AddHtml(60, 105 + 1, 250, 20, Color("Yes, I will fight this duel.", BlackColor32));
|
||||
AddHtml(60, 105, 250, 20, Color("Yes, I will fight this duel.", LabelColor32));
|
||||
|
||||
AddRadio(24, 135, 9727, 9730, false, 2);
|
||||
AddHtml(60 - 1, 140, 250, 20, Color("No, I do not wish to fight.", BlackColor32));
|
||||
AddHtml(60 + 1, 140, 250, 20, Color("No, I do not wish to fight.", BlackColor32));
|
||||
AddHtml(60, 140 - 1, 250, 20, Color("No, I do not wish to fight.", BlackColor32));
|
||||
AddHtml(60, 140 + 1, 250, 20, Color("No, I do not wish to fight.", BlackColor32));
|
||||
AddHtml(60, 140, 250, 20, Color("No, I do not wish to fight.", LabelColor32));
|
||||
|
||||
AddRadio(24, 170, 9727, 9730, false, 3);
|
||||
AddHtml(60 - 1, 175, 250, 20, Color("No, knave. Do not ask again.", BlackColor32));
|
||||
AddHtml(60 + 1, 175, 250, 20, Color("No, knave. Do not ask again.", BlackColor32));
|
||||
AddHtml(60, 175 - 1, 250, 20, Color("No, knave. Do not ask again.", BlackColor32));
|
||||
AddHtml(60, 175 + 1, 250, 20, Color("No, knave. Do not ask again.", BlackColor32));
|
||||
AddHtml(60, 175, 250, 20, Color("No, knave. Do not ask again.", LabelColor32));
|
||||
|
||||
AddButton(314, 173, 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>";
|
||||
}
|
||||
|
||||
public void AutoReject()
|
||||
{
|
||||
if (!m_Active)
|
||||
return;
|
||||
|
||||
m_Active = false;
|
||||
|
||||
m_Challenged.CloseGump<AcceptDuelGump>();
|
||||
|
||||
m_Challenger.SendMessage("{0} seems unresponsive.", m_Challenged.Name);
|
||||
m_Challenged.SendMessage("You decline the challenge.");
|
||||
}
|
||||
|
||||
public static void BeginIgnore(Mobile source, Mobile toIgnore)
|
||||
{
|
||||
if (!m_IgnoreLists.TryGetValue(source, out List<IgnoreEntry> list))
|
||||
m_IgnoreLists[source] = list = new List<IgnoreEntry>();
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
IgnoreEntry 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 List<IgnoreEntry> list))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
IgnoreEntry ie = list[i];
|
||||
|
||||
if (ie.Expired)
|
||||
list.RemoveAt(i--);
|
||||
else if (ie.Ignored == check)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID != 1 || !m_Active || !m_Context.Registered)
|
||||
return;
|
||||
|
||||
m_Active = false;
|
||||
|
||||
if (!m_Context.Participants.Contains(m_Participant))
|
||||
return;
|
||||
|
||||
if (info.IsSwitched(1))
|
||||
{
|
||||
if (!(m_Challenged is PlayerMobile 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("{0} cannot fight because they are already assigned to another duel.", pm.Name);
|
||||
}
|
||||
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(
|
||||
"{0} cannot fight because they have recently been in combat with another player.", pm.Name);
|
||||
}
|
||||
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.");
|
||||
}
|
||||
else
|
||||
{
|
||||
bool 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 (int 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("{0} has accepted the request.", m_Challenged.Name);
|
||||
m_Challenged.SendMessage("You have accepted the request from {0}.", m_Challenger.Name);
|
||||
|
||||
NetState ns = m_Challenger.NetState;
|
||||
|
||||
if (ns != null)
|
||||
foreach (Gump g in ns.Gumps)
|
||||
{
|
||||
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 {0} could not join.",
|
||||
m_Challenged.Name);
|
||||
m_Challenged.SendMessage(
|
||||
"The participant list was full and so you could not join the fight {1} {0}.", m_Challenger.Name,
|
||||
m_Participant.Contains(m_Challenger) ? "with" : "against");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.IsSwitched(3))
|
||||
BeginIgnore(m_Challenged, m_Challenger);
|
||||
|
||||
m_Challenger.SendMessage("{0} does not wish to fight.", m_Challenged.Name);
|
||||
m_Challenged.SendMessage("You chose not to fight {1} {0}.", m_Challenger.Name,
|
||||
m_Participant.Contains(m_Challenger) ? "with" : "against");
|
||||
}
|
||||
}
|
||||
|
||||
private class IgnoreEntry
|
||||
{
|
||||
private static TimeSpan ExpireDelay = TimeSpan.FromMinutes(15.0);
|
||||
public DateTime m_Expire;
|
||||
public Mobile m_Ignored;
|
||||
|
||||
public IgnoreEntry(Mobile ignored)
|
||||
{
|
||||
m_Ignored = ignored;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public Mobile Ignored => m_Ignored;
|
||||
public bool Expired => DateTime.UtcNow >= m_Expire;
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
m_Expire = DateTime.UtcNow + ExpireDelay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
825
Projects/Scripts/Engines/ConPVP/Arena.cs
Normal file
825
Projects/Scripts/Engines/ConPVP/Arena.cs
Normal file
|
|
@ -0,0 +1,825 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Multis;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class ArenaController : Item
|
||||
{
|
||||
[Constructible]
|
||||
public ArenaController() : base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
|
||||
Arena = new Arena();
|
||||
|
||||
Instances.Add(this);
|
||||
}
|
||||
|
||||
public ArenaController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Arena Arena{ get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool IsPrivate{ get; set; }
|
||||
|
||||
public override string DefaultName => "arena controller";
|
||||
|
||||
public static List<ArenaController> Instances{ get; set; } = new List<ArenaController>();
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
base.OnDelete();
|
||||
|
||||
Instances.Remove(this);
|
||||
Arena.Delete();
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster)
|
||||
from.SendGump(new PropertiesGump(from, Arena));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1);
|
||||
|
||||
writer.Write(IsPrivate);
|
||||
|
||||
Arena.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
IsPrivate = reader.ReadBool();
|
||||
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
Arena = new Arena(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Instances.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class ArenaStartPoints
|
||||
{
|
||||
public ArenaStartPoints(Point3D[] points = null)
|
||||
{
|
||||
Points = points ?? new Point3D[8];
|
||||
}
|
||||
|
||||
public ArenaStartPoints(GenericReader reader)
|
||||
{
|
||||
Points = new Point3D[reader.ReadEncodedInt()];
|
||||
|
||||
for (int i = 0; i < Points.Length; ++i)
|
||||
Points[i] = reader.ReadPoint3D();
|
||||
}
|
||||
|
||||
public Point3D[] Points{ get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D EdgeWest
|
||||
{
|
||||
get => Points[0];
|
||||
set => Points[0] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D EdgeEast
|
||||
{
|
||||
get => Points[1];
|
||||
set => Points[1] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D EdgeNorth
|
||||
{
|
||||
get => Points[2];
|
||||
set => Points[2] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D EdgeSouth
|
||||
{
|
||||
get => Points[3];
|
||||
set => Points[3] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D CornerNW
|
||||
{
|
||||
get => Points[4];
|
||||
set => Points[4] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D CornerSE
|
||||
{
|
||||
get => Points[5];
|
||||
set => Points[5] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D CornerSW
|
||||
{
|
||||
get => Points[6];
|
||||
set => Points[6] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D CornerNE
|
||||
{
|
||||
get => Points[7];
|
||||
set => Points[7] = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "...";
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(Points.Length);
|
||||
|
||||
for (int i = 0; i < Points.Length; ++i)
|
||||
writer.Write(Points[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class Arena : IComparable<Arena>
|
||||
{
|
||||
private bool m_Active;
|
||||
private Rectangle2D m_Bounds;
|
||||
private Map m_Facet;
|
||||
private Point3D m_GateOut;
|
||||
|
||||
private bool m_IsGuarded;
|
||||
private string m_Name;
|
||||
|
||||
private SafeZone m_Region;
|
||||
|
||||
private TournamentController m_Tournament;
|
||||
private Rectangle2D m_Zone;
|
||||
|
||||
public Arena()
|
||||
{
|
||||
Points = new ArenaStartPoints();
|
||||
Players = new List<Mobile>();
|
||||
}
|
||||
|
||||
public Arena(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 7:
|
||||
{
|
||||
m_IsGuarded = reader.ReadBool();
|
||||
|
||||
goto case 6;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
Ladder = reader.ReadItem() as LadderController;
|
||||
|
||||
goto case 5;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
m_Tournament = reader.ReadItem() as TournamentController;
|
||||
Announcer = reader.ReadMobile();
|
||||
|
||||
goto case 4;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
m_Name = reader.ReadString();
|
||||
|
||||
goto case 3;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
m_Zone = reader.ReadRect2D();
|
||||
|
||||
goto case 2;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
GateIn = reader.ReadPoint3D();
|
||||
m_GateOut = reader.ReadPoint3D();
|
||||
Teleporter = reader.ReadItem();
|
||||
|
||||
goto case 1;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
Players = reader.ReadStrongMobileList();
|
||||
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
m_Facet = reader.ReadMap();
|
||||
m_Bounds = reader.ReadRect2D();
|
||||
Outside = reader.ReadPoint3D();
|
||||
Wall = reader.ReadPoint3D();
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
reader.ReadBool();
|
||||
Players = new List<Mobile>();
|
||||
}
|
||||
|
||||
m_Active = reader.ReadBool();
|
||||
Points = new ArenaStartPoints(reader);
|
||||
|
||||
if (m_Active)
|
||||
{
|
||||
Arenas.Add(this);
|
||||
Arenas.Sort();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null)
|
||||
m_Region = new SafeZone(m_Zone, Outside, m_Facet, m_IsGuarded);
|
||||
|
||||
if (IsOccupied)
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(2.0), Evict);
|
||||
|
||||
if (m_Tournament != null)
|
||||
Timer.DelayCall(TimeSpan.Zero, AttachToTournament_Sandbox);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public LadderController Ladder{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool IsGuarded
|
||||
{
|
||||
get => m_IsGuarded;
|
||||
set
|
||||
{
|
||||
m_IsGuarded = value;
|
||||
|
||||
if (m_Region != null)
|
||||
m_Region.Disabled = !m_IsGuarded;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentController Tournament
|
||||
{
|
||||
get => m_Tournament;
|
||||
set
|
||||
{
|
||||
m_Tournament?.Tournament.Arenas.Remove(this);
|
||||
|
||||
m_Tournament = value;
|
||||
|
||||
m_Tournament?.Tournament.Arenas.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile Announcer{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public string Name
|
||||
{
|
||||
get => m_Name;
|
||||
set
|
||||
{
|
||||
m_Name = value;
|
||||
if (m_Active) Arenas.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Map Facet
|
||||
{
|
||||
get => m_Facet;
|
||||
set
|
||||
{
|
||||
m_Facet = value;
|
||||
|
||||
if (Teleporter != null)
|
||||
Teleporter.Map = value;
|
||||
|
||||
m_Region?.Unregister();
|
||||
|
||||
if (m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null)
|
||||
m_Region = new SafeZone(m_Zone, Outside, m_Facet, m_IsGuarded);
|
||||
else
|
||||
m_Region = null;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Rectangle2D Bounds
|
||||
{
|
||||
get => m_Bounds;
|
||||
set => m_Bounds = value;
|
||||
}
|
||||
|
||||
public int Spectators
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Region == null)
|
||||
return 0;
|
||||
|
||||
int specs = m_Region.GetPlayerCount() - Players.Count;
|
||||
|
||||
if (specs < 0)
|
||||
specs = 0;
|
||||
|
||||
return specs;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Rectangle2D Zone
|
||||
{
|
||||
get => m_Zone;
|
||||
set
|
||||
{
|
||||
m_Zone = value;
|
||||
|
||||
if (m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null)
|
||||
{
|
||||
m_Region?.Unregister();
|
||||
|
||||
m_Region = new SafeZone(m_Zone, Outside, m_Facet, m_IsGuarded);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Region?.Unregister();
|
||||
|
||||
m_Region = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D Outside{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D GateIn{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D GateOut
|
||||
{
|
||||
get => m_GateOut;
|
||||
set
|
||||
{
|
||||
m_GateOut = value;
|
||||
if (Teleporter != null)
|
||||
Teleporter.Location = m_GateOut;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D Wall{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool IsOccupied => Players.Count > 0;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ArenaStartPoints Points{ get; private set; }
|
||||
|
||||
public Item Teleporter{ get; set; }
|
||||
|
||||
public List<Mobile> Players{ get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool Active
|
||||
{
|
||||
get => m_Active;
|
||||
set
|
||||
{
|
||||
if (m_Active == value)
|
||||
return;
|
||||
|
||||
m_Active = value;
|
||||
|
||||
if (m_Active)
|
||||
{
|
||||
Arenas.Add(this);
|
||||
Arenas.Sort();
|
||||
}
|
||||
else
|
||||
{
|
||||
Arenas.Remove(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator, AccessLevel.Administrator)]
|
||||
public bool ForceEvict
|
||||
{
|
||||
get => false;
|
||||
set
|
||||
{
|
||||
if (value) Evict();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Arena> Arenas{ get; } = new List<Arena>();
|
||||
|
||||
public int CompareTo(Arena c)
|
||||
{
|
||||
string a = m_Name;
|
||||
string b = c.m_Name;
|
||||
|
||||
if (a == null && b == null)
|
||||
return 0;
|
||||
if (a == null)
|
||||
return -1;
|
||||
if (b == null)
|
||||
return +1;
|
||||
|
||||
return a.CompareTo(b);
|
||||
}
|
||||
|
||||
public Ladder AcquireLadder()
|
||||
{
|
||||
return Ladder?.Ladder ?? ConPVP.Ladder.Instance;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
Active = false;
|
||||
m_Region?.Unregister();
|
||||
m_Region = null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "...";
|
||||
}
|
||||
|
||||
public Point3D GetBaseStartPoint(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
return Points.Points[index % Points.Points.Length];
|
||||
}
|
||||
|
||||
public void MoveInside(DuelPlayer[] players, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
else
|
||||
index %= Points.Points.Length;
|
||||
|
||||
Point3D start = GetBaseStartPoint(index);
|
||||
|
||||
int offset = 0;
|
||||
|
||||
Point2D[] offsets = index < 4 ? m_EdgeOffsets : m_CornerOffsets;
|
||||
int[,] matrix = m_Rotate[index];
|
||||
|
||||
for (int i = 0; i < players.Length; ++i)
|
||||
{
|
||||
DuelPlayer pl = players[i];
|
||||
|
||||
if (pl == null)
|
||||
continue;
|
||||
|
||||
Mobile mob = pl.Mobile;
|
||||
|
||||
Point2D p;
|
||||
|
||||
if (offset < offsets.Length)
|
||||
p = offsets[offset++];
|
||||
else
|
||||
p = offsets[offsets.Length - 1];
|
||||
|
||||
p.X = p.X * matrix[0, 0] + p.Y * matrix[0, 1];
|
||||
p.Y = p.X * matrix[1, 0] + p.Y * matrix[1, 1];
|
||||
|
||||
mob.MoveToWorld(new Point3D(start.X + p.X, start.Y + p.Y, start.Z), m_Facet);
|
||||
mob.Direction = mob.GetDirectionTo(Wall);
|
||||
|
||||
Players.Add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachToTournament_Sandbox()
|
||||
{
|
||||
m_Tournament?.Tournament.Arenas.Add(this);
|
||||
}
|
||||
|
||||
public void Evict()
|
||||
{
|
||||
Point3D loc;
|
||||
Map facet;
|
||||
|
||||
if (m_Facet == null)
|
||||
{
|
||||
loc = new Point3D(2715, 2165, 0);
|
||||
facet = Map.Felucca;
|
||||
}
|
||||
else
|
||||
{
|
||||
loc = Outside;
|
||||
facet = m_Facet;
|
||||
}
|
||||
|
||||
bool hasBounds = m_Bounds.Start != Point2D.Zero && m_Bounds.End != Point2D.Zero;
|
||||
|
||||
for (int i = 0; i < Players.Count; ++i)
|
||||
{
|
||||
Mobile mob = Players[i];
|
||||
|
||||
if (mob == null)
|
||||
continue;
|
||||
|
||||
if (mob.Map == Map.Internal)
|
||||
{
|
||||
if ((m_Facet == null || mob.LogoutMap == m_Facet) &&
|
||||
(!hasBounds || m_Bounds.Contains(mob.LogoutLocation)))
|
||||
mob.LogoutLocation = loc;
|
||||
}
|
||||
else if ((m_Facet == null || mob.Map == m_Facet) && (!hasBounds || m_Bounds.Contains(mob.Location)))
|
||||
{
|
||||
mob.MoveToWorld(loc, facet);
|
||||
}
|
||||
|
||||
mob.Combatant = null;
|
||||
mob.Frozen = false;
|
||||
DuelContext.Debuff(mob);
|
||||
DuelContext.CancelSpell(mob);
|
||||
}
|
||||
|
||||
if (hasBounds)
|
||||
{
|
||||
List<Mobile> pets = new List<Mobile>();
|
||||
|
||||
foreach (Mobile mob in facet.GetMobilesInBounds(m_Bounds))
|
||||
if (mob is BaseCreature pet && pet.Controlled && pet.ControlMaster != null &&
|
||||
Players.Contains(pet.ControlMaster))
|
||||
pets.Add(pet);
|
||||
|
||||
foreach (Mobile pet in pets)
|
||||
{
|
||||
pet.Combatant = null;
|
||||
pet.Frozen = false;
|
||||
|
||||
pet.MoveToWorld(loc, facet);
|
||||
}
|
||||
}
|
||||
|
||||
Players.Clear();
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(7);
|
||||
|
||||
writer.Write(m_IsGuarded);
|
||||
|
||||
writer.Write(Ladder);
|
||||
|
||||
writer.Write(m_Tournament);
|
||||
writer.Write(Announcer);
|
||||
|
||||
writer.Write(m_Name);
|
||||
|
||||
writer.Write(m_Zone);
|
||||
|
||||
writer.Write(GateIn);
|
||||
writer.Write(m_GateOut);
|
||||
writer.Write(Teleporter);
|
||||
|
||||
writer.Write(Players);
|
||||
|
||||
writer.Write(m_Facet);
|
||||
writer.Write(m_Bounds);
|
||||
writer.Write(Outside);
|
||||
writer.Write(Wall);
|
||||
writer.Write(m_Active);
|
||||
|
||||
Points.Serialize(writer);
|
||||
}
|
||||
|
||||
public static Arena FindArena(List<Mobile> players)
|
||||
{
|
||||
Preferences prefs = Preferences.Instance;
|
||||
|
||||
if (prefs == null)
|
||||
return FindArena();
|
||||
|
||||
if (Arenas.Count == 0)
|
||||
return null;
|
||||
|
||||
if (players.Count > 0)
|
||||
{
|
||||
Mobile first = players[0];
|
||||
|
||||
List<ArenaController> allControllers = ArenaController.Instances;
|
||||
|
||||
for (int i = 0; i < allControllers.Count; ++i)
|
||||
{
|
||||
ArenaController controller = allControllers[i];
|
||||
|
||||
if (controller?.Deleted == false && controller.Arena != null && controller.IsPrivate &&
|
||||
controller.Map == first.Map && first.InRange(controller, 24))
|
||||
{
|
||||
BaseHouse house = BaseHouse.FindHouseAt(controller);
|
||||
bool allNear = true;
|
||||
|
||||
for (int j = 0; j < players.Count; ++j)
|
||||
{
|
||||
Mobile check = players[j];
|
||||
bool isNear;
|
||||
|
||||
if (house == null)
|
||||
isNear = controller.Map == check.Map && check.InRange(controller, 24);
|
||||
else
|
||||
isNear = BaseHouse.FindHouseAt(check) == house;
|
||||
|
||||
if (!isNear)
|
||||
{
|
||||
allNear = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allNear)
|
||||
return controller.Arena;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ArenaEntry> arenas = new List<ArenaEntry>();
|
||||
|
||||
for (int i = 0; i < Arenas.Count; ++i)
|
||||
{
|
||||
Arena arena = Arenas[i];
|
||||
|
||||
if (!arena.IsOccupied)
|
||||
arenas.Add(new ArenaEntry(arena));
|
||||
}
|
||||
|
||||
if (arenas.Count == 0)
|
||||
return Arenas[0];
|
||||
|
||||
int tc = 0;
|
||||
|
||||
for (int i = 0; i < arenas.Count; ++i)
|
||||
{
|
||||
ArenaEntry ae = arenas[i];
|
||||
|
||||
for (int j = 0; j < players.Count; ++j)
|
||||
{
|
||||
PreferencesEntry pe = prefs.Find(players[j]);
|
||||
|
||||
if (pe.Disliked.Contains(ae.m_Arena.Name))
|
||||
++ae.m_VotesAgainst;
|
||||
else
|
||||
++ae.m_VotesFor;
|
||||
}
|
||||
|
||||
tc += ae.Value;
|
||||
}
|
||||
|
||||
int rn = Utility.Random(tc);
|
||||
|
||||
for (int i = 0; i < arenas.Count; ++i)
|
||||
{
|
||||
ArenaEntry ae = arenas[i];
|
||||
|
||||
if (rn < ae.Value)
|
||||
return ae.m_Arena;
|
||||
|
||||
rn -= ae.Value;
|
||||
}
|
||||
|
||||
return arenas[Utility.Random(arenas.Count)].m_Arena;
|
||||
}
|
||||
|
||||
public static Arena FindArena()
|
||||
{
|
||||
if (Arenas.Count == 0)
|
||||
return null;
|
||||
|
||||
int offset = Utility.Random(Arenas.Count);
|
||||
|
||||
for (int i = 0; i < Arenas.Count; ++i)
|
||||
{
|
||||
Arena arena = Arenas[(i + offset) % Arenas.Count];
|
||||
|
||||
if (!arena.IsOccupied)
|
||||
return arena;
|
||||
}
|
||||
|
||||
return Arenas[offset];
|
||||
}
|
||||
|
||||
private class ArenaEntry
|
||||
{
|
||||
public Arena m_Arena;
|
||||
public int m_VotesAgainst;
|
||||
public int m_VotesFor;
|
||||
|
||||
public ArenaEntry(Arena arena)
|
||||
{
|
||||
m_Arena = arena;
|
||||
}
|
||||
|
||||
public int Value => m_VotesFor;
|
||||
}
|
||||
|
||||
#region Offsets & Rotation
|
||||
|
||||
private static Point2D[] m_EdgeOffsets =
|
||||
{
|
||||
/*
|
||||
* /\
|
||||
* /\/\
|
||||
* /\/\/\
|
||||
* \/\/\/
|
||||
* \/\/\
|
||||
* \/\/
|
||||
*/
|
||||
new Point2D(0, 0),
|
||||
new Point2D(0, -1),
|
||||
new Point2D(0, +1),
|
||||
new Point2D(1, 0),
|
||||
new Point2D(1, -1),
|
||||
new Point2D(1, +1),
|
||||
new Point2D(2, 0),
|
||||
new Point2D(2, -1),
|
||||
new Point2D(2, +1),
|
||||
new Point2D(3, 0)
|
||||
};
|
||||
|
||||
// nw corner
|
||||
private static Point2D[] m_CornerOffsets =
|
||||
{
|
||||
/*
|
||||
* /\
|
||||
* /\/\
|
||||
* /\/\/\
|
||||
* /\/\/\/\
|
||||
* \/\/\/\/
|
||||
*/
|
||||
new Point2D(0, 0),
|
||||
new Point2D(0, 1),
|
||||
new Point2D(1, 0),
|
||||
new Point2D(1, 1),
|
||||
new Point2D(0, 2),
|
||||
new Point2D(2, 0),
|
||||
new Point2D(2, 1),
|
||||
new Point2D(1, 2),
|
||||
new Point2D(0, 3),
|
||||
new Point2D(3, 0)
|
||||
};
|
||||
|
||||
private static int[][,] m_Rotate =
|
||||
{
|
||||
new[,] { { +1, 0 }, { 0, +1 } }, // west
|
||||
new[,] { { -1, 0 }, { 0, -1 } }, // east
|
||||
new[,] { { 0, +1 }, { +1, 0 } }, // north
|
||||
new[,] { { 0, -1 }, { -1, 0 } }, // south
|
||||
new[,] { { +1, 0 }, { 0, +1 } }, // nw
|
||||
new[,] { { -1, 0 }, { 0, -1 } }, // se
|
||||
new[,] { { 0, +1 }, { +1, 0 } }, // sw
|
||||
new[,] { { 0, -1 }, { -1, 0 } } // ne
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2495
Projects/Scripts/Engines/ConPVP/DuelContext.cs
Normal file
2495
Projects/Scripts/Engines/ConPVP/DuelContext.cs
Normal file
File diff suppressed because it is too large
Load diff
89
Projects/Scripts/Engines/ConPVP/DuelTeleporterAddon.cs
Normal file
89
Projects/Scripts/Engines/ConPVP/DuelTeleporterAddon.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public enum DuelTeleporterType
|
||||
{
|
||||
Squares = 6095,
|
||||
Buds = 6104,
|
||||
Flowers = 6113,
|
||||
Spikes = 6122,
|
||||
Arrows = 6140,
|
||||
Links = 6149
|
||||
}
|
||||
|
||||
public class DuelTeleporterAddon : BaseAddon
|
||||
{
|
||||
[Constructible]
|
||||
public DuelTeleporterAddon(DuelTeleporterType type = DuelTeleporterType.Squares)
|
||||
{
|
||||
int itemID = (int)type;
|
||||
|
||||
AddComponent(new AddonComponent(itemID + 0), -1, -1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 1), -1, 0, 5);
|
||||
AddComponent(new AddonComponent(itemID + 2), 0, -1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 3), -1, +1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 4), 0, 0, 5);
|
||||
AddComponent(new AddonComponent(itemID + 5), +1, -1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 6), 0, +1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 7), +1, 0, 5);
|
||||
AddComponent(new AddonComponent(itemID + 8), +1, +1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x759), -2, -2, 0);
|
||||
AddComponent(new AddonComponent(0x75A), +2, +2, 0);
|
||||
AddComponent(new AddonComponent(0x75B), -2, +2, 0);
|
||||
AddComponent(new AddonComponent(0x75C), +2, -2, 0);
|
||||
|
||||
AddComponent(new AddonComponent(0x751), -1, +2, 0);
|
||||
AddComponent(new AddonComponent(0x751), 0, +2, 0);
|
||||
AddComponent(new AddonComponent(0x751), +1, +2, 0);
|
||||
|
||||
AddComponent(new AddonComponent(0x752), +2, -1, 0);
|
||||
AddComponent(new AddonComponent(0x752), +2, 0, 0);
|
||||
AddComponent(new AddonComponent(0x752), +2, +1, 0);
|
||||
|
||||
AddComponent(new AddonComponent(0x753), -1, -2, 0);
|
||||
AddComponent(new AddonComponent(0x753), 0, -2, 0);
|
||||
AddComponent(new AddonComponent(0x753), +1, -2, 0);
|
||||
|
||||
AddComponent(new AddonComponent(0x754), -2, -1, 0);
|
||||
AddComponent(new AddonComponent(0x754), -2, 0, 0);
|
||||
AddComponent(new AddonComponent(0x754), -2, +1, 0);
|
||||
}
|
||||
|
||||
public DuelTeleporterAddon(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DuelTeleporterType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Components.Count > 0)
|
||||
return (DuelTeleporterType)Components[0].ItemID;
|
||||
|
||||
return DuelTeleporterType.Squares;
|
||||
}
|
||||
set
|
||||
{
|
||||
for (int i = 0; i < Components.Count && i < 9; ++i)
|
||||
Components[i].ItemID = i + (int)value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
1797
Projects/Scripts/Engines/ConPVP/Games/BombingRun.cs
Normal file
1797
Projects/Scripts/Engines/ConPVP/Games/BombingRun.cs
Normal file
File diff suppressed because it is too large
Load diff
1205
Projects/Scripts/Engines/ConPVP/Games/CTF.cs
Normal file
1205
Projects/Scripts/Engines/ConPVP/Games/CTF.cs
Normal file
File diff suppressed because it is too large
Load diff
1109
Projects/Scripts/Engines/ConPVP/Games/DoubleDom.cs
Normal file
1109
Projects/Scripts/Engines/ConPVP/Games/DoubleDom.cs
Normal file
File diff suppressed because it is too large
Load diff
77
Projects/Scripts/Engines/ConPVP/Games/EventGame.cs
Normal file
77
Projects/Scripts/Engines/ConPVP/Games/EventGame.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public abstract class EventController : Item
|
||||
{
|
||||
public EventController()
|
||||
: base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public EventController(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract string Title{ get; }
|
||||
public abstract EventGame Construct(DuelContext dc);
|
||||
|
||||
public abstract string GetTeamName(int teamID);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster)
|
||||
from.SendGump(new PropertiesGump(from, this));
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class EventGame
|
||||
{
|
||||
protected DuelContext m_Context;
|
||||
|
||||
public EventGame(DuelContext context)
|
||||
{
|
||||
m_Context = context;
|
||||
}
|
||||
|
||||
public DuelContext Context => m_Context;
|
||||
|
||||
public virtual bool FreeConsume => true;
|
||||
|
||||
public virtual bool OnDeath(Mobile mob, Container corpse)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool CantDoAnything(Mobile mob)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void OnStart()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnStop()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
1184
Projects/Scripts/Engines/ConPVP/Games/KingOfTheHill.cs
Normal file
1184
Projects/Scripts/Engines/ConPVP/Games/KingOfTheHill.cs
Normal file
File diff suppressed because it is too large
Load diff
123
Projects/Scripts/Engines/ConPVP/Games/TourneyMatch.cs
Normal file
123
Projects/Scripts/Engines/ConPVP/Games/TourneyMatch.cs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TourneyMatch
|
||||
{
|
||||
public TourneyMatch(List<TourneyParticipant> participants)
|
||||
{
|
||||
Participants = participants;
|
||||
|
||||
for (int i = 0; i < participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = participants[i];
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("Matched in a duel against ");
|
||||
|
||||
if (participants.Count > 2)
|
||||
sb.AppendFormat("{0} other {1}: ", participants.Count - 1,
|
||||
part.Players.Count == 1 ? "players" : "teams");
|
||||
|
||||
bool hasAppended = false;
|
||||
|
||||
for (int j = 0; j < participants.Count; ++j)
|
||||
{
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
if (hasAppended)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(participants[j].NameList);
|
||||
hasAppended = true;
|
||||
}
|
||||
|
||||
sb.Append(".");
|
||||
|
||||
part.AddLog(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public List<TourneyParticipant> Participants{ get; set; }
|
||||
|
||||
public TourneyParticipant Winner{ get; set; }
|
||||
|
||||
public DuelContext Context{ get; set; }
|
||||
|
||||
public bool InProgress => Context?.Registered == true;
|
||||
|
||||
public void Start(Arena arena, Tournament tourney)
|
||||
{
|
||||
TourneyParticipant first = Participants[0];
|
||||
|
||||
DuelContext dc = new DuelContext(first.Players[0], tourney.Ruleset.Layout, false);
|
||||
dc.Ruleset.Options.SetAll(false);
|
||||
dc.Ruleset.Options.Or(tourney.Ruleset.Options);
|
||||
|
||||
for (int i = 0; i < Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant tourneyPart = Participants[i];
|
||||
Participant duelPart = new Participant(dc, tourneyPart.Players.Count)
|
||||
{
|
||||
TourneyPart = tourneyPart
|
||||
};
|
||||
|
||||
|
||||
for (int j = 0; j < tourneyPart.Players.Count; ++j)
|
||||
duelPart.Add(tourneyPart.Players[j]);
|
||||
|
||||
for (int j = 0; j < duelPart.Players.Length; ++j)
|
||||
if (duelPart.Players[j] != null)
|
||||
duelPart.Players[j].Ready = true;
|
||||
|
||||
dc.Participants.Add(duelPart);
|
||||
}
|
||||
|
||||
if (tourney.EventController != null)
|
||||
dc.m_EventGame = tourney.EventController.Construct(dc);
|
||||
|
||||
dc.m_Tournament = tourney;
|
||||
dc.m_Match = this;
|
||||
|
||||
dc.m_OverrideArena = arena;
|
||||
|
||||
if (tourney.SuddenDeath > TimeSpan.Zero &&
|
||||
(tourney.SuddenDeathRounds == 0 || tourney.Pyramid.Levels.Count <= tourney.SuddenDeathRounds))
|
||||
dc.StartSuddenDeath(tourney.SuddenDeath);
|
||||
|
||||
dc.SendReadyGump(0);
|
||||
|
||||
if (dc.StartedBeginCountdown)
|
||||
{
|
||||
Context = dc;
|
||||
|
||||
for (int i = 0; i < Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant p = Participants[i];
|
||||
|
||||
for (int j = 0; j < p.Players.Count; ++j)
|
||||
{
|
||||
Mobile mob = p.Players[j];
|
||||
|
||||
foreach (Mobile view in mob.GetMobilesInRange(18))
|
||||
if (!mob.CanSee(view))
|
||||
mob.Send(view.RemovePacket);
|
||||
|
||||
mob.LocalOverheadMessage(MessageType.Emote, 0x3B2, false,
|
||||
"* Your mind focuses intently on the fight and all other distractions fade away *");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.Unregister();
|
||||
dc.StopCountdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
382
Projects/Scripts/Engines/ConPVP/Gumps/AcceptTeamGump.cs
Normal file
382
Projects/Scripts/Engines/ConPVP/Gumps/AcceptTeamGump.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
285
Projects/Scripts/Engines/ConPVP/Gumps/ArenaGump.cs
Normal file
285
Projects/Scripts/Engines/ConPVP/Gumps/ArenaGump.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Projects/Scripts/Engines/ConPVP/Gumps/BeginGump.cs
Normal file
72
Projects/Scripts/Engines/ConPVP/Gumps/BeginGump.cs
Normal 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>";
|
||||
}
|
||||
}
|
||||
}
|
||||
566
Projects/Scripts/Engines/ConPVP/Gumps/ConfirmSignupGump.cs
Normal file
566
Projects/Scripts/Engines/ConPVP/Gumps/ConfirmSignupGump.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
139
Projects/Scripts/Engines/ConPVP/Gumps/DuelContextGump.cs
Normal file
139
Projects/Scripts/Engines/ConPVP/Gumps/DuelContextGump.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
248
Projects/Scripts/Engines/ConPVP/Gumps/LadderGump.cs
Normal file
248
Projects/Scripts/Engines/ConPVP/Gumps/LadderGump.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
253
Projects/Scripts/Engines/ConPVP/Gumps/ParticipantGump.cs
Normal file
253
Projects/Scripts/Engines/ConPVP/Gumps/ParticipantGump.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
Projects/Scripts/Engines/ConPVP/Gumps/PickRulesetGump.cs
Normal file
126
Projects/Scripts/Engines/ConPVP/Gumps/PickRulesetGump.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Projects/Scripts/Engines/ConPVP/Gumps/ReadyGump.cs
Normal file
109
Projects/Scripts/Engines/ConPVP/Gumps/ReadyGump.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
233
Projects/Scripts/Engines/ConPVP/Gumps/ReadyUpGump.cs
Normal file
233
Projects/Scripts/Engines/ConPVP/Gumps/ReadyUpGump.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Projects/Scripts/Engines/ConPVP/Gumps/RulesetGump.cs
Normal file
130
Projects/Scripts/Engines/ConPVP/Gumps/RulesetGump.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
856
Projects/Scripts/Engines/ConPVP/Gumps/TournamentBracketGump.cs
Normal file
856
Projects/Scripts/Engines/ConPVP/Gumps/TournamentBracketGump.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
366
Projects/Scripts/Engines/ConPVP/Ladder.cs
Normal file
366
Projects/Scripts/Engines/ConPVP/Ladder.cs
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class LadderController : Item
|
||||
{
|
||||
[Constructible]
|
||||
public LadderController() : base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
|
||||
Ladder = new Ladder();
|
||||
|
||||
if (Ladder.Instance == null)
|
||||
Ladder.Instance = Ladder;
|
||||
}
|
||||
|
||||
public LadderController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public Ladder Ladder{ get; private set; }
|
||||
|
||||
public override string DefaultName => "ladder controller";
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
if (Ladder.Instance == Ladder)
|
||||
Ladder.Instance = null;
|
||||
|
||||
base.Delete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1);
|
||||
|
||||
Ladder.Serialize(writer);
|
||||
|
||||
writer.Write(Ladder.Instance == Ladder);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
Ladder = new Ladder(reader);
|
||||
|
||||
if (version < 1 || reader.ReadBool())
|
||||
Ladder.Instance = Ladder;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Ladder
|
||||
{
|
||||
private static int[] m_ShortLevels =
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3, 3,
|
||||
4, 4,
|
||||
5, 5, 5,
|
||||
6, 6, 6,
|
||||
7, 7, 7, 7,
|
||||
8, 8, 8, 8,
|
||||
9, 9, 9, 9, 9
|
||||
};
|
||||
|
||||
private static int[] m_BaseXP =
|
||||
{
|
||||
0, 100, 200, 400, 600, 900, 1200, 1600, 2000, 2500
|
||||
};
|
||||
|
||||
private static int[] m_LossFactors =
|
||||
{
|
||||
10,
|
||||
11, 11,
|
||||
25, 25,
|
||||
43, 43,
|
||||
67, 67
|
||||
};
|
||||
|
||||
private static int[,] m_OffsetScalar =
|
||||
{
|
||||
/* { win, los } */
|
||||
/* -6 */ { 175, 25 },
|
||||
/* -5 */ { 165, 35 },
|
||||
/* -4 */ { 155, 45 },
|
||||
/* -3 */ { 145, 55 },
|
||||
/* -2 */ { 130, 70 },
|
||||
/* -1 */ { 115, 85 },
|
||||
/* 0 */ { 100, 100 },
|
||||
/* +1 */ { 90, 110 },
|
||||
/* +2 */ { 80, 120 },
|
||||
/* +3 */ { 70, 130 },
|
||||
/* +4 */ { 60, 140 },
|
||||
/* +5 */ { 50, 150 },
|
||||
/* +6 */ { 40, 160 }
|
||||
};
|
||||
|
||||
public List<LadderEntry> Entries{ get; } = new List<LadderEntry>();
|
||||
|
||||
private Dictionary<Mobile, LadderEntry> m_Table;
|
||||
|
||||
public Ladder()
|
||||
{
|
||||
m_Table = new Dictionary<Mobile, LadderEntry>();
|
||||
}
|
||||
|
||||
public Ladder(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
int count = reader.ReadEncodedInt();
|
||||
|
||||
m_Table = new Dictionary<Mobile, LadderEntry>(count);
|
||||
Entries = new List<LadderEntry>(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
LadderEntry entry = new LadderEntry(reader, this, version);
|
||||
|
||||
if (entry.Mobile != null)
|
||||
{
|
||||
m_Table[entry.Mobile] = entry;
|
||||
entry.Index = Entries.Count;
|
||||
Entries.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
Entries.Sort();
|
||||
|
||||
for (int i = 0; i < Entries.Count; ++i)
|
||||
{
|
||||
LadderEntry entry = Entries[i];
|
||||
|
||||
entry.Index = i;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Ladder Instance{ get; set; }
|
||||
|
||||
public static int GetLevel(int xp)
|
||||
{
|
||||
if (xp >= 22500)
|
||||
return 50;
|
||||
if (xp >= 2500)
|
||||
return 10 + (xp - 2500) / 500;
|
||||
if (xp < 0)
|
||||
xp = 0;
|
||||
|
||||
return m_ShortLevels[xp / 100];
|
||||
}
|
||||
|
||||
public static void GetLevelInfo(int level, out int xpBase, out int xpAdvance)
|
||||
{
|
||||
if (level >= 10)
|
||||
{
|
||||
xpBase = 2500 + (level - 10) * 500;
|
||||
xpAdvance = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
xpBase = m_BaseXP[level - 1];
|
||||
xpAdvance = m_BaseXP[level] - xpBase;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetLossFactor(int level)
|
||||
{
|
||||
if (level >= 10)
|
||||
return 100;
|
||||
|
||||
return m_LossFactors[level - 1];
|
||||
}
|
||||
|
||||
public static int GetOffsetScalar(int ourLevel, int theirLevel, bool win)
|
||||
{
|
||||
int x = ourLevel - theirLevel;
|
||||
|
||||
if (x < -6 || x > +6)
|
||||
return 0;
|
||||
|
||||
int y = win ? 0 : 1;
|
||||
|
||||
return m_OffsetScalar[x + 6, y];
|
||||
}
|
||||
|
||||
public static int GetExperienceGain(LadderEntry us, LadderEntry them, bool weWon)
|
||||
{
|
||||
if (us == null || them == null)
|
||||
return 0;
|
||||
|
||||
int ourLevel = GetLevel(us.Experience);
|
||||
int theirLevel = GetLevel(them.Experience);
|
||||
|
||||
int scalar = GetOffsetScalar(ourLevel, theirLevel, weWon);
|
||||
|
||||
if (scalar == 0)
|
||||
return 0;
|
||||
|
||||
int xp = 25 * scalar;
|
||||
|
||||
if (!weWon)
|
||||
xp = xp * GetLossFactor(ourLevel) / 100;
|
||||
|
||||
xp /= 100;
|
||||
|
||||
if (xp <= 0)
|
||||
xp = 1;
|
||||
|
||||
return xp * (weWon ? 1 : -1);
|
||||
}
|
||||
|
||||
private int Swap(int idx, int newIdx)
|
||||
{
|
||||
LadderEntry hold = Entries[idx];
|
||||
|
||||
Entries[idx] = Entries[newIdx];
|
||||
Entries[newIdx] = hold;
|
||||
|
||||
Entries[idx].Index = idx;
|
||||
Entries[newIdx].Index = newIdx;
|
||||
|
||||
return newIdx;
|
||||
}
|
||||
|
||||
public void UpdateEntry(LadderEntry entry)
|
||||
{
|
||||
int index = entry.Index;
|
||||
|
||||
if (index >= 0 && index < Entries.Count)
|
||||
{
|
||||
while (index - 1 >= 0 && (entry.CompareTo(Entries[index - 1])) < 0)
|
||||
index = Swap(index, index - 1);
|
||||
|
||||
while (index + 1 < Entries.Count && (entry.CompareTo(Entries[index + 1])) > 0)
|
||||
index = Swap(index, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public LadderEntry Find(Mobile mob)
|
||||
{
|
||||
if (m_Table.TryGetValue(mob, out LadderEntry entry))
|
||||
{
|
||||
m_Table[mob] = entry = new LadderEntry(mob, this);
|
||||
entry.Index = Entries.Count;
|
||||
Entries.Add(entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public LadderEntry FindNoCreate(Mobile mob)
|
||||
{
|
||||
m_Table.TryGetValue(mob, out LadderEntry entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(1); // version;
|
||||
|
||||
writer.WriteEncodedInt(Entries.Count);
|
||||
|
||||
for (int i = 0; i < Entries.Count; ++i)
|
||||
Entries[i].Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public class LadderEntry : IComparable<LadderEntry>
|
||||
{
|
||||
private int m_Experience;
|
||||
private Ladder m_Ladder;
|
||||
|
||||
public LadderEntry(Mobile mob, Ladder ladder)
|
||||
{
|
||||
m_Ladder = ladder;
|
||||
Mobile = mob;
|
||||
}
|
||||
|
||||
public LadderEntry(GenericReader reader, Ladder ladder, int version)
|
||||
{
|
||||
m_Ladder = ladder;
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
Mobile = reader.ReadMobile();
|
||||
m_Experience = reader.ReadEncodedInt();
|
||||
Wins = reader.ReadEncodedInt();
|
||||
Losses = reader.ReadEncodedInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public int Experience
|
||||
{
|
||||
get => m_Experience;
|
||||
set
|
||||
{
|
||||
m_Experience = value;
|
||||
m_Ladder.UpdateEntry(this);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public int Wins{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public int Losses{ get; set; }
|
||||
|
||||
public int Index{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Rank => Index;
|
||||
|
||||
public int CompareTo(LadderEntry l)
|
||||
{
|
||||
return (l?.m_Experience ?? 0) - m_Experience;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(Mobile);
|
||||
writer.WriteEncodedInt(m_Experience);
|
||||
writer.WriteEncodedInt(Wins);
|
||||
writer.WriteEncodedInt(Losses);
|
||||
}
|
||||
}
|
||||
}
|
||||
231
Projects/Scripts/Engines/ConPVP/Participant.cs
Normal file
231
Projects/Scripts/Engines/ConPVP/Participant.cs
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class Participant
|
||||
{
|
||||
public Participant(DuelContext context, int count)
|
||||
{
|
||||
Context = context;
|
||||
//m_Stakes = new StakesContainer( context, this );
|
||||
Resize(count);
|
||||
}
|
||||
|
||||
public int Count => Players.Length;
|
||||
public DuelPlayer[] Players{ get; private set; }
|
||||
|
||||
public DuelContext Context{ get; }
|
||||
|
||||
public TourneyParticipant TourneyPart{ get; set; }
|
||||
|
||||
public int FilledSlots
|
||||
{
|
||||
get
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i] != null)
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasOpenSlot
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i] == null)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Eliminated
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i]?.Eliminated == false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public string NameList
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
{
|
||||
if (Players[i] == null)
|
||||
continue;
|
||||
|
||||
Mobile mob = Players[i].Mobile;
|
||||
|
||||
if (sb.Length > 0)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(mob.Name);
|
||||
}
|
||||
|
||||
if (sb.Length == 0)
|
||||
return "Empty";
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public DuelPlayer Find(Mobile mob)
|
||||
{
|
||||
if (mob is PlayerMobile pm)
|
||||
{
|
||||
if (pm.DuelContext == Context && pm.DuelPlayer.Participant == this)
|
||||
return pm.DuelPlayer;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i]?.Mobile == mob)
|
||||
return Players[i];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool Contains(Mobile mob)
|
||||
{
|
||||
return Find(mob) != null;
|
||||
}
|
||||
|
||||
public void Broadcast(int hue, string message, string nonLocalOverhead, string localOverhead)
|
||||
{
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i] != null)
|
||||
{
|
||||
if (message != null)
|
||||
Players[i].Mobile.SendMessage(hue, message);
|
||||
|
||||
if (nonLocalOverhead != null)
|
||||
Players[i].Mobile.NonlocalOverheadMessage(MessageType.Regular, hue, false,
|
||||
string.Format(nonLocalOverhead, Players[i].Mobile.Name,
|
||||
Players[i].Mobile.Female ? "her" : "his"));
|
||||
|
||||
if (localOverhead != null)
|
||||
Players[i].Mobile.LocalOverheadMessage(MessageType.Regular, hue, false, localOverhead);
|
||||
}
|
||||
}
|
||||
|
||||
public void Nullify(DuelPlayer player)
|
||||
{
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
int index = Array.IndexOf(Players, player);
|
||||
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
Players[index] = null;
|
||||
}
|
||||
|
||||
public void Remove(DuelPlayer player)
|
||||
{
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
int index = Array.IndexOf(Players, player);
|
||||
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
DuelPlayer[] old = Players;
|
||||
Players = new DuelPlayer[old.Length - 1];
|
||||
|
||||
for (int i = 0; i < index; ++i)
|
||||
Players[i] = old[i];
|
||||
|
||||
for (int i = index + 1; i < old.Length; ++i)
|
||||
Players[i - 1] = old[i];
|
||||
}
|
||||
|
||||
public void Remove(Mobile player)
|
||||
{
|
||||
Remove(Find(player));
|
||||
}
|
||||
|
||||
public void Add(Mobile player)
|
||||
{
|
||||
if (Contains(player))
|
||||
return;
|
||||
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i] == null)
|
||||
{
|
||||
Players[i] = new DuelPlayer(player, this);
|
||||
return;
|
||||
}
|
||||
|
||||
Resize(Players.Length + 1);
|
||||
Players[Players.Length - 1] = new DuelPlayer(player, this);
|
||||
}
|
||||
|
||||
public void Resize(int count)
|
||||
{
|
||||
DuelPlayer[] old = Players;
|
||||
Players = new DuelPlayer[count];
|
||||
|
||||
if (old != null)
|
||||
{
|
||||
int ct = 0;
|
||||
|
||||
for (int i = 0; i < old.Length; ++i)
|
||||
if (old[i] != null && ct < count)
|
||||
Players[ct++] = old[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DuelPlayer
|
||||
{
|
||||
private bool m_Eliminated;
|
||||
|
||||
public DuelPlayer(Mobile mob, Participant p)
|
||||
{
|
||||
Mobile = mob;
|
||||
Participant = p;
|
||||
|
||||
if (mob is PlayerMobile mobile)
|
||||
mobile.DuelPlayer = this;
|
||||
}
|
||||
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
public bool Ready{ get; set; }
|
||||
|
||||
public bool Eliminated
|
||||
{
|
||||
get => m_Eliminated;
|
||||
set
|
||||
{
|
||||
m_Eliminated = value;
|
||||
if (Participant.Context.m_Tournament != null && m_Eliminated)
|
||||
{
|
||||
Participant.Context.m_Tournament.OnEliminated(this);
|
||||
Mobile.SendEverything();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Participant Participant{ get; set; }
|
||||
}
|
||||
}
|
||||
277
Projects/Scripts/Engines/ConPVP/Preferences.cs
Normal file
277
Projects/Scripts/Engines/ConPVP/Preferences.cs
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class PreferencesController : Item
|
||||
{
|
||||
[Constructible]
|
||||
public PreferencesController() : base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
|
||||
Preferences = new Preferences();
|
||||
|
||||
if (Preferences.Instance == null)
|
||||
Preferences.Instance = Preferences;
|
||||
else
|
||||
Delete();
|
||||
}
|
||||
|
||||
public PreferencesController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public Preferences Preferences{ get; private set; }
|
||||
|
||||
public override string DefaultName => "preferences controller";
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
if (Preferences.Instance != Preferences)
|
||||
base.Delete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
Preferences.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Preferences = new Preferences(reader);
|
||||
Preferences.Instance = Preferences;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Preferences
|
||||
{
|
||||
private Dictionary<Mobile, PreferencesEntry> m_Table;
|
||||
|
||||
public Preferences()
|
||||
{
|
||||
m_Table = new Dictionary<Mobile, PreferencesEntry>();
|
||||
Entries = new List<PreferencesEntry>();
|
||||
}
|
||||
|
||||
public Preferences(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
int count = reader.ReadEncodedInt();
|
||||
|
||||
m_Table = new Dictionary<Mobile, PreferencesEntry>(count);
|
||||
Entries = new List<PreferencesEntry>(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
PreferencesEntry entry = new PreferencesEntry(reader, version);
|
||||
|
||||
if (entry.Mobile != null)
|
||||
{
|
||||
m_Table[entry.Mobile] = entry;
|
||||
Entries.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<PreferencesEntry> Entries{ get; }
|
||||
|
||||
public static Preferences Instance{ get; set; }
|
||||
|
||||
public PreferencesEntry Find(Mobile mob)
|
||||
{
|
||||
if (m_Table.TryGetValue(mob, out PreferencesEntry entry))
|
||||
{
|
||||
m_Table[mob] = entry = new PreferencesEntry(mob);
|
||||
Entries.Add(entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version;
|
||||
|
||||
writer.WriteEncodedInt(Entries.Count);
|
||||
|
||||
for (int i = 0; i < Entries.Count; ++i)
|
||||
Entries[i].Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public class PreferencesEntry
|
||||
{
|
||||
public PreferencesEntry(Mobile mob)
|
||||
{
|
||||
Mobile = mob;
|
||||
Disliked = new List<string>();
|
||||
}
|
||||
|
||||
public PreferencesEntry(GenericReader reader, int version)
|
||||
{
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Mobile = reader.ReadMobile();
|
||||
|
||||
int count = reader.ReadEncodedInt();
|
||||
|
||||
Disliked = new List<string>(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
Disliked.Add(reader.ReadString());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
public List<string> Disliked{ get; }
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(Mobile);
|
||||
|
||||
writer.WriteEncodedInt(Disliked.Count);
|
||||
|
||||
for (int i = 0; i < Disliked.Count; ++i)
|
||||
writer.Write(Disliked[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public class PreferencesGump : Gump
|
||||
{
|
||||
private int m_ColumnX = 12;
|
||||
private PreferencesEntry m_Entry;
|
||||
|
||||
public PreferencesGump(Mobile from, Preferences prefs) : base(50, 50)
|
||||
{
|
||||
m_Entry = prefs.Find(from);
|
||||
|
||||
if (m_Entry == null)
|
||||
return;
|
||||
|
||||
List<Arena> arenas = Arena.Arenas;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
int height = 12 + 20 + arenas.Count * 31 + 24 + 12;
|
||||
|
||||
AddBackground(0, 0, 499 + 40 - 365, height, 0x2436);
|
||||
|
||||
for (int i = 1; i < arenas.Count; i += 2)
|
||||
AddImageTiled(12, 32 + i * 31, 475 + 40 - 365, 30, 0x2430);
|
||||
|
||||
AddAlphaRegion(10, 10, 479 + 40 - 365, height - 20);
|
||||
|
||||
AddColumnHeader(35, null);
|
||||
AddColumnHeader(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);
|
||||
|
||||
for (int i = 0; i < arenas.Count; ++i)
|
||||
{
|
||||
Arena ar = arenas[i];
|
||||
|
||||
string name = ar.Name ?? "(no name)";
|
||||
|
||||
int x = 12;
|
||||
int y = 32 + i * 31;
|
||||
|
||||
int color = 0xCCFFCC;
|
||||
|
||||
AddCheck(x + 3, y + 1, 9730, 9727, m_Entry.Disliked.Contains(name), i);
|
||||
x += 35;
|
||||
|
||||
AddBorderedText(x + 5, y + 5, 115 - 5, name, color, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (m_Entry == null)
|
||||
return;
|
||||
|
||||
if (info.ButtonID != 1)
|
||||
return;
|
||||
|
||||
m_Entry.Disliked.Clear();
|
||||
|
||||
List<Arena> arenas = Arena.Arenas;
|
||||
|
||||
for (int i = 0; i < info.Switches.Length; ++i)
|
||||
{
|
||||
int idx = info.Switches[i];
|
||||
|
||||
if (idx >= 0 && idx < arenas.Count)
|
||||
m_Entry.Disliked.Add(arenas[idx].Name);
|
||||
}
|
||||
}
|
||||
|
||||
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, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Projects/Scripts/Engines/ConPVP/Ruleset.cs
Normal file
102
Projects/Scripts/Engines/ConPVP/Ruleset.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class Ruleset
|
||||
{
|
||||
public Ruleset(RulesetLayout layout)
|
||||
{
|
||||
Layout = layout;
|
||||
Options = new BitArray(layout.TotalLength);
|
||||
}
|
||||
|
||||
public RulesetLayout Layout{ get; }
|
||||
|
||||
public BitArray Options{ get; private set; }
|
||||
|
||||
public string Title{ get; set; }
|
||||
|
||||
public Ruleset Base{ get; private set; }
|
||||
|
||||
public List<Ruleset> Flavors{ get; } = new List<Ruleset>();
|
||||
|
||||
public bool Changed{ get; set; }
|
||||
|
||||
public void ApplyDefault(Ruleset newDefault)
|
||||
{
|
||||
Base = newDefault;
|
||||
Changed = false;
|
||||
|
||||
Options = new BitArray(newDefault.Options);
|
||||
|
||||
ApplyFlavorsTo(this);
|
||||
}
|
||||
|
||||
public void ApplyFlavorsTo(Ruleset ruleset)
|
||||
{
|
||||
for (int i = 0; i < Flavors.Count; ++i)
|
||||
{
|
||||
Ruleset flavor = Flavors[i];
|
||||
|
||||
Options.Or(flavor.Options);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddFlavor(Ruleset flavor)
|
||||
{
|
||||
if (Flavors.Contains(flavor))
|
||||
return;
|
||||
|
||||
Flavors.Add(flavor);
|
||||
Options.Or(flavor.Options);
|
||||
}
|
||||
|
||||
public void RemoveFlavor(Ruleset flavor)
|
||||
{
|
||||
if (!Flavors.Contains(flavor))
|
||||
return;
|
||||
|
||||
Flavors.Remove(flavor);
|
||||
Options.And(flavor.Options.Not());
|
||||
flavor.Options.Not();
|
||||
}
|
||||
|
||||
public void SetOptionRange(string title, bool value)
|
||||
{
|
||||
RulesetLayout layout = Layout.FindByTitle(title);
|
||||
|
||||
if (layout == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < layout.TotalLength; ++i)
|
||||
Options[i + layout.Offset] = value;
|
||||
|
||||
Changed = true;
|
||||
}
|
||||
|
||||
public bool GetOption(string title, string option)
|
||||
{
|
||||
int index = 0;
|
||||
RulesetLayout layout = Layout.FindByOption(title, option, ref index);
|
||||
|
||||
if (layout == null)
|
||||
return true;
|
||||
|
||||
return Options[layout.Offset + index];
|
||||
}
|
||||
|
||||
public void SetOption(string title, string option, bool value)
|
||||
{
|
||||
int index = 0;
|
||||
RulesetLayout layout = Layout.FindByOption(title, option, ref index);
|
||||
|
||||
if (layout == null)
|
||||
return;
|
||||
|
||||
Options[layout.Offset + index] = value;
|
||||
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
764
Projects/Scripts/Engines/ConPVP/RulesetLayout.cs
Normal file
764
Projects/Scripts/Engines/ConPVP/RulesetLayout.cs
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class RulesetLayout
|
||||
{
|
||||
private static RulesetLayout m_Root;
|
||||
|
||||
public RulesetLayout(string title, string[] options) : this(title, title, new RulesetLayout[0], options)
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, string description, string[] options) : this(title, description,
|
||||
new RulesetLayout[0], options)
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, RulesetLayout[] children) : this(title, title, children, new string[0])
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, string description, RulesetLayout[] children) : this(title, description, children,
|
||||
new string[0])
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, RulesetLayout[] children, string[] options) : this(title, title, children,
|
||||
options)
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, string description, RulesetLayout[] children, string[] options)
|
||||
{
|
||||
Title = title;
|
||||
Description = description;
|
||||
Children = children;
|
||||
Options = options;
|
||||
|
||||
for (int i = 0; i < children.Length; ++i)
|
||||
children[i].Parent = this;
|
||||
}
|
||||
|
||||
public static RulesetLayout Root
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Root != null)
|
||||
return m_Root;
|
||||
|
||||
List<RulesetLayout> entries = new List<RulesetLayout>
|
||||
{
|
||||
new RulesetLayout("Spells",
|
||||
new[]
|
||||
{
|
||||
new RulesetLayout("1st Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Reactive Armor", "Clumsy", "Create Food", "Feeblemind", "Heal", "Magic Arrow", "Night Sight",
|
||||
"Weaken"
|
||||
}),
|
||||
new RulesetLayout("2nd Circle", "Spells",
|
||||
new[] { "Agility", "Cunning", "Cure", "Harm", "Magic Trap", "Untrap", "Protection", "Strength" }),
|
||||
new RulesetLayout("3rd Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Bless", "Fireball", "Magic Lock", "Poison", "Telekinesis", "Teleport", "Unlock Spell",
|
||||
"Wall of Stone"
|
||||
}),
|
||||
new RulesetLayout("4th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Arch Cure", "Arch Protection", "Curse", "Fire Field", "Greater Heal", "Lightning", "Mana Drain",
|
||||
"Recall"
|
||||
}),
|
||||
new RulesetLayout("5th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Blade Spirits", "Dispel Field", "Incognito", "Magic Reflection", "Mind Blast", "Paralyze",
|
||||
"Poison Field", "Summon Creature"
|
||||
}),
|
||||
new RulesetLayout("6th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Dispel", "Energy Bolt", "Explosion", "Invisibility", "Mark", "Mass Curse", "Paralyze Field",
|
||||
"Reveal"
|
||||
}),
|
||||
new RulesetLayout("7th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Chain Lightning", "Energy Field", "Flame Strike", "Gate Travel", "Mana Vampire", "Mass Dispel",
|
||||
"Meteor Swarm", "Polymorph"
|
||||
}),
|
||||
new RulesetLayout("8th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Earthquake", "Energy Vortex", "Resurrection", "Air Elemental", "Summon Daemon", "Earth Elemental",
|
||||
"Fire Elemental", "Water Elemental"
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
entries.Add(new RulesetLayout("Chivalry", new[]
|
||||
{
|
||||
"Cleanse by Fire",
|
||||
"Close Wounds",
|
||||
"Consecrate Weapon",
|
||||
"Dispel Evil",
|
||||
"Divine Fury",
|
||||
"Enemy of One",
|
||||
"Holy Light",
|
||||
"Noble Sacrifice",
|
||||
"Remove Curse",
|
||||
"Sacred Journey"
|
||||
}));
|
||||
|
||||
entries.Add(new RulesetLayout("Necromancy", new[]
|
||||
{
|
||||
"Animate Dead",
|
||||
"Blood Oath",
|
||||
"Corpse Skin",
|
||||
"Curse Weapon",
|
||||
"Evil Omen",
|
||||
"Horrific Beast",
|
||||
"Lich Form",
|
||||
"Mind Rot",
|
||||
"Pain Spike",
|
||||
"Poison Strike",
|
||||
"Strangle",
|
||||
"Summon Familiar",
|
||||
"Vampiric Embrace",
|
||||
"Vengeful Spirit",
|
||||
"Wither",
|
||||
"Wraith Form"
|
||||
}));
|
||||
|
||||
if (Core.SE)
|
||||
{
|
||||
entries.Add(new RulesetLayout("Bushido", new[]
|
||||
{
|
||||
"Confidence",
|
||||
"Counter Attack",
|
||||
"Evasion",
|
||||
"Honorable Execution",
|
||||
"Lightning Strike",
|
||||
"Momentum Strike"
|
||||
}));
|
||||
|
||||
entries.Add(new RulesetLayout("Ninjitsu", new[]
|
||||
{
|
||||
"Animal Form",
|
||||
"Backstab",
|
||||
"Death Strike",
|
||||
"Focus Attack",
|
||||
"Ki Attack",
|
||||
"Mirror Image",
|
||||
"Shadow Jump",
|
||||
"Suprise Attack"
|
||||
}));
|
||||
|
||||
if (Core.ML)
|
||||
entries.Add(new RulesetLayout("Spellweaving", new[]
|
||||
{
|
||||
"Arcane Circle",
|
||||
"Arcane Empowerment",
|
||||
"Attune Weapon",
|
||||
"Dryad Allure",
|
||||
"Essence of Wind",
|
||||
"Ethereal Voyage",
|
||||
"Gift of Life",
|
||||
"Gift of Renewal",
|
||||
"Immolating Weapon",
|
||||
"Nature's Fury",
|
||||
"Reaper Form",
|
||||
"Summon Fey",
|
||||
"Summon Fiend",
|
||||
"Thunderstorm",
|
||||
"Wildfire",
|
||||
"Word of Death"
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
if (Core.SE)
|
||||
entries.Add(new RulesetLayout("Combat Abilities", new[]
|
||||
{
|
||||
"Stun",
|
||||
"Disarm",
|
||||
"Armor Ignore",
|
||||
"Bleed Attack",
|
||||
"Concussion Blow",
|
||||
"Crushing Blow",
|
||||
"Disarm",
|
||||
"Dismount",
|
||||
"Double Strike",
|
||||
"Infectious Strike",
|
||||
"Mortal Strike",
|
||||
"Moving Shot",
|
||||
"Paralyzing Blow",
|
||||
"Shadow Strike",
|
||||
"Whirlwind Attack",
|
||||
"Riding Swipe",
|
||||
"Frenzied Whirlwind",
|
||||
"Block",
|
||||
"Defense Mastery",
|
||||
"Nerve Strike",
|
||||
"Talon Strike",
|
||||
"Feint",
|
||||
"Dual Wield",
|
||||
"Double Shot",
|
||||
"Armor Pierce"
|
||||
}));
|
||||
else
|
||||
entries.Add(new RulesetLayout("Combat Abilities", new[]
|
||||
{
|
||||
"Stun",
|
||||
"Disarm",
|
||||
"Armor Ignore",
|
||||
"Bleed Attack",
|
||||
"Concussion Blow",
|
||||
"Crushing Blow",
|
||||
"Disarm",
|
||||
"Dismount",
|
||||
"Double Strike",
|
||||
"Infectious Strike",
|
||||
"Mortal Strike",
|
||||
"Moving Shot",
|
||||
"Paralyzing Blow",
|
||||
"Shadow Strike",
|
||||
"Whirlwind Attack"
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.Add(new RulesetLayout("Combat Abilities", new[]
|
||||
{
|
||||
"Stun",
|
||||
"Disarm",
|
||||
"Concussion Blow",
|
||||
"Crushing Blow",
|
||||
"Paralyzing Blow"
|
||||
}));
|
||||
}
|
||||
|
||||
entries.Add(new RulesetLayout("Skills", new[]
|
||||
{
|
||||
"Anatomy",
|
||||
"Detect Hidden",
|
||||
"Evaluating Intelligence",
|
||||
"Hiding",
|
||||
"Poisoning",
|
||||
"Snooping",
|
||||
"Stealing",
|
||||
"Spirit Speak",
|
||||
"Stealth"
|
||||
}));
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
entries.Add(new RulesetLayout("Weapons", new[]
|
||||
{
|
||||
"Magical",
|
||||
"Melee",
|
||||
"Ranged",
|
||||
"Poisoned",
|
||||
"Wrestling"
|
||||
}));
|
||||
|
||||
entries.Add(new RulesetLayout("Armor", new[]
|
||||
{
|
||||
"Magical",
|
||||
"Shields"
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.Add(new RulesetLayout("Weapons", new[]
|
||||
{
|
||||
"Magical",
|
||||
"Melee",
|
||||
"Ranged",
|
||||
"Poisoned",
|
||||
"Wrestling",
|
||||
"Runics"
|
||||
}));
|
||||
|
||||
entries.Add(new RulesetLayout("Armor", new[]
|
||||
{
|
||||
"Magical",
|
||||
"Shields",
|
||||
"Colored"
|
||||
}));
|
||||
}
|
||||
|
||||
if (Core.SE)
|
||||
entries.Add(new RulesetLayout("Items", new[]
|
||||
{
|
||||
new RulesetLayout("Potions", new[]
|
||||
{
|
||||
"Agility",
|
||||
"Cure",
|
||||
"Explosion",
|
||||
"Heal",
|
||||
"Nightsight",
|
||||
"Poison",
|
||||
"Refresh",
|
||||
"Strength"
|
||||
})
|
||||
},
|
||||
new[]
|
||||
{
|
||||
"Bandages",
|
||||
"Wands",
|
||||
"Trapped Containers",
|
||||
"Bolas",
|
||||
"Mounts",
|
||||
"Orange Petals",
|
||||
"Shurikens",
|
||||
"Fukiya Darts",
|
||||
"Fire Horns"
|
||||
}));
|
||||
else
|
||||
entries.Add(new RulesetLayout("Items", new[]
|
||||
{
|
||||
new RulesetLayout("Potions", new[]
|
||||
{
|
||||
"Agility",
|
||||
"Cure",
|
||||
"Explosion",
|
||||
"Heal",
|
||||
"Nightsight",
|
||||
"Poison",
|
||||
"Refresh",
|
||||
"Strength"
|
||||
})
|
||||
},
|
||||
new[]
|
||||
{
|
||||
"Bandages",
|
||||
"Wands",
|
||||
"Trapped Containers",
|
||||
"Bolas",
|
||||
"Mounts",
|
||||
"Orange Petals",
|
||||
"Fire Horns"
|
||||
}));
|
||||
|
||||
m_Root = new RulesetLayout("Rules", entries.ToArray());
|
||||
m_Root.ComputeOffsets();
|
||||
|
||||
// Set up default rulesets
|
||||
|
||||
if (!Core.AOS)
|
||||
{
|
||||
#region Mage 5x
|
||||
|
||||
Ruleset m5x = new Ruleset(m_Root);
|
||||
|
||||
m5x.Title = "Mage 5x";
|
||||
|
||||
m5x.SetOptionRange("Spells", true);
|
||||
|
||||
m5x.SetOption("Spells", "Wall of Stone", false);
|
||||
m5x.SetOption("Spells", "Fire Field", false);
|
||||
m5x.SetOption("Spells", "Poison Field", false);
|
||||
m5x.SetOption("Spells", "Energy Field", false);
|
||||
m5x.SetOption("Spells", "Reactive Armor", false);
|
||||
m5x.SetOption("Spells", "Protection", false);
|
||||
m5x.SetOption("Spells", "Teleport", false);
|
||||
m5x.SetOption("Spells", "Wall of Stone", false);
|
||||
m5x.SetOption("Spells", "Arch Protection", false);
|
||||
m5x.SetOption("Spells", "Recall", false);
|
||||
m5x.SetOption("Spells", "Blade Spirits", false);
|
||||
m5x.SetOption("Spells", "Incognito", false);
|
||||
m5x.SetOption("Spells", "Magic Reflection", false);
|
||||
m5x.SetOption("Spells", "Paralyze", false);
|
||||
m5x.SetOption("Spells", "Summon Creature", false);
|
||||
m5x.SetOption("Spells", "Invisibility", false);
|
||||
m5x.SetOption("Spells", "Mark", false);
|
||||
m5x.SetOption("Spells", "Paralyze Field", false);
|
||||
m5x.SetOption("Spells", "Energy Field", false);
|
||||
m5x.SetOption("Spells", "Gate Travel", false);
|
||||
m5x.SetOption("Spells", "Polymorph", false);
|
||||
m5x.SetOption("Spells", "Energy Vortex", false);
|
||||
m5x.SetOption("Spells", "Air Elemental", false);
|
||||
m5x.SetOption("Spells", "Summon Daemon", false);
|
||||
m5x.SetOption("Spells", "Earth Elemental", false);
|
||||
m5x.SetOption("Spells", "Fire Elemental", false);
|
||||
m5x.SetOption("Spells", "Water Elemental", false);
|
||||
m5x.SetOption("Spells", "Earthquake", false);
|
||||
m5x.SetOption("Spells", "Meteor Swarm", false);
|
||||
m5x.SetOption("Spells", "Chain Lightning", false);
|
||||
m5x.SetOption("Spells", "Resurrection", false);
|
||||
|
||||
m5x.SetOption("Weapons", "Wrestling", true);
|
||||
|
||||
m5x.SetOption("Skills", "Anatomy", true);
|
||||
m5x.SetOption("Skills", "Detect Hidden", true);
|
||||
m5x.SetOption("Skills", "Evaluating Intelligence", true);
|
||||
|
||||
m5x.SetOption("Items", "Trapped Containers", true);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mage 7x
|
||||
|
||||
Ruleset m7x = new Ruleset(m_Root);
|
||||
|
||||
m7x.Title = "Mage 7x";
|
||||
|
||||
m7x.SetOptionRange("Spells", true);
|
||||
|
||||
m7x.SetOption("Spells", "Wall of Stone", false);
|
||||
m7x.SetOption("Spells", "Fire Field", false);
|
||||
m7x.SetOption("Spells", "Poison Field", false);
|
||||
m7x.SetOption("Spells", "Energy Field", false);
|
||||
m7x.SetOption("Spells", "Reactive Armor", false);
|
||||
m7x.SetOption("Spells", "Protection", false);
|
||||
m7x.SetOption("Spells", "Teleport", false);
|
||||
m7x.SetOption("Spells", "Wall of Stone", false);
|
||||
m7x.SetOption("Spells", "Arch Protection", false);
|
||||
m7x.SetOption("Spells", "Recall", false);
|
||||
m7x.SetOption("Spells", "Blade Spirits", false);
|
||||
m7x.SetOption("Spells", "Incognito", false);
|
||||
m7x.SetOption("Spells", "Magic Reflection", false);
|
||||
m7x.SetOption("Spells", "Paralyze", false);
|
||||
m7x.SetOption("Spells", "Summon Creature", false);
|
||||
m7x.SetOption("Spells", "Invisibility", false);
|
||||
m7x.SetOption("Spells", "Mark", false);
|
||||
m7x.SetOption("Spells", "Paralyze Field", false);
|
||||
m7x.SetOption("Spells", "Energy Field", false);
|
||||
m7x.SetOption("Spells", "Gate Travel", false);
|
||||
m7x.SetOption("Spells", "Polymorph", false);
|
||||
m7x.SetOption("Spells", "Energy Vortex", false);
|
||||
m7x.SetOption("Spells", "Air Elemental", false);
|
||||
m7x.SetOption("Spells", "Summon Daemon", false);
|
||||
m7x.SetOption("Spells", "Earth Elemental", false);
|
||||
m7x.SetOption("Spells", "Fire Elemental", false);
|
||||
m7x.SetOption("Spells", "Water Elemental", false);
|
||||
m7x.SetOption("Spells", "Earthquake", false);
|
||||
m7x.SetOption("Spells", "Meteor Swarm", false);
|
||||
m7x.SetOption("Spells", "Chain Lightning", false);
|
||||
m7x.SetOption("Spells", "Resurrection", false);
|
||||
|
||||
m7x.SetOption("Combat Abilities", "Stun", true);
|
||||
|
||||
m7x.SetOption("Skills", "Anatomy", true);
|
||||
m7x.SetOption("Skills", "Detect Hidden", true);
|
||||
m7x.SetOption("Skills", "Poisoning", true);
|
||||
m7x.SetOption("Skills", "Evaluating Intelligence", true);
|
||||
|
||||
m7x.SetOption("Weapons", "Wrestling", true);
|
||||
|
||||
m7x.SetOption("Potions", "Refresh", true);
|
||||
m7x.SetOption("Items", "Trapped Containers", true);
|
||||
m7x.SetOption("Items", "Bandages", true);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Standard 7x
|
||||
|
||||
Ruleset s7x = new Ruleset(m_Root);
|
||||
|
||||
s7x.Title = "Standard 7x";
|
||||
|
||||
s7x.SetOptionRange("Spells", true);
|
||||
|
||||
s7x.SetOption("Spells", "Wall of Stone", false);
|
||||
s7x.SetOption("Spells", "Fire Field", false);
|
||||
s7x.SetOption("Spells", "Poison Field", false);
|
||||
s7x.SetOption("Spells", "Energy Field", false);
|
||||
s7x.SetOption("Spells", "Teleport", false);
|
||||
s7x.SetOption("Spells", "Wall of Stone", false);
|
||||
s7x.SetOption("Spells", "Arch Protection", false);
|
||||
s7x.SetOption("Spells", "Recall", false);
|
||||
s7x.SetOption("Spells", "Blade Spirits", false);
|
||||
s7x.SetOption("Spells", "Incognito", false);
|
||||
s7x.SetOption("Spells", "Magic Reflection", false);
|
||||
s7x.SetOption("Spells", "Paralyze", false);
|
||||
s7x.SetOption("Spells", "Summon Creature", false);
|
||||
s7x.SetOption("Spells", "Invisibility", false);
|
||||
s7x.SetOption("Spells", "Mark", false);
|
||||
s7x.SetOption("Spells", "Paralyze Field", false);
|
||||
s7x.SetOption("Spells", "Energy Field", false);
|
||||
s7x.SetOption("Spells", "Gate Travel", false);
|
||||
s7x.SetOption("Spells", "Polymorph", false);
|
||||
s7x.SetOption("Spells", "Energy Vortex", false);
|
||||
s7x.SetOption("Spells", "Air Elemental", false);
|
||||
s7x.SetOption("Spells", "Summon Daemon", false);
|
||||
s7x.SetOption("Spells", "Earth Elemental", false);
|
||||
s7x.SetOption("Spells", "Fire Elemental", false);
|
||||
s7x.SetOption("Spells", "Water Elemental", false);
|
||||
s7x.SetOption("Spells", "Earthquake", false);
|
||||
s7x.SetOption("Spells", "Meteor Swarm", false);
|
||||
s7x.SetOption("Spells", "Chain Lightning", false);
|
||||
s7x.SetOption("Spells", "Resurrection", false);
|
||||
|
||||
s7x.SetOptionRange("Combat Abilities", true);
|
||||
|
||||
s7x.SetOption("Skills", "Anatomy", true);
|
||||
s7x.SetOption("Skills", "Detect Hidden", true);
|
||||
s7x.SetOption("Skills", "Poisoning", true);
|
||||
s7x.SetOption("Skills", "Evaluating Intelligence", true);
|
||||
|
||||
s7x.SetOptionRange("Weapons", true);
|
||||
s7x.SetOption("Weapons", "Runics", false);
|
||||
s7x.SetOptionRange("Armor", true);
|
||||
|
||||
s7x.SetOption("Potions", "Refresh", true);
|
||||
s7x.SetOption("Items", "Bandages", true);
|
||||
s7x.SetOption("Items", "Trapped Containers", true);
|
||||
|
||||
#endregion
|
||||
|
||||
m_Root.Defaults = new[] { m5x, m7x, s7x };
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Standard All Skills
|
||||
|
||||
Ruleset all = new Ruleset(m_Root);
|
||||
|
||||
all.Title = "Standard All Skills";
|
||||
|
||||
|
||||
all.SetOptionRange("Spells", true);
|
||||
|
||||
all.SetOption("Spells", "Wall of Stone", false);
|
||||
all.SetOption("Spells", "Fire Field", false);
|
||||
all.SetOption("Spells", "Poison Field", false);
|
||||
all.SetOption("Spells", "Energy Field", false);
|
||||
all.SetOption("Spells", "Teleport", false);
|
||||
all.SetOption("Spells", "Wall of Stone", false);
|
||||
all.SetOption("Spells", "Arch Protection", false);
|
||||
all.SetOption("Spells", "Recall", false);
|
||||
all.SetOption("Spells", "Blade Spirits", false);
|
||||
all.SetOption("Spells", "Incognito", false);
|
||||
all.SetOption("Spells", "Magic Reflection", false);
|
||||
all.SetOption("Spells", "Paralyze", false);
|
||||
all.SetOption("Spells", "Summon Creature", false);
|
||||
all.SetOption("Spells", "Invisibility", false);
|
||||
all.SetOption("Spells", "Mark", false);
|
||||
all.SetOption("Spells", "Paralyze Field", false);
|
||||
all.SetOption("Spells", "Energy Field", false);
|
||||
all.SetOption("Spells", "Gate Travel", false);
|
||||
all.SetOption("Spells", "Polymorph", false);
|
||||
all.SetOption("Spells", "Energy Vortex", false);
|
||||
all.SetOption("Spells", "Air Elemental", false);
|
||||
all.SetOption("Spells", "Summon Daemon", false);
|
||||
all.SetOption("Spells", "Earth Elemental", false);
|
||||
all.SetOption("Spells", "Fire Elemental", false);
|
||||
all.SetOption("Spells", "Water Elemental", false);
|
||||
all.SetOption("Spells", "Earthquake", false);
|
||||
all.SetOption("Spells", "Meteor Swarm", false);
|
||||
all.SetOption("Spells", "Chain Lightning", false);
|
||||
all.SetOption("Spells", "Resurrection", false);
|
||||
|
||||
all.SetOptionRange("Necromancy", true);
|
||||
all.SetOption("Necromancy", "Summon Familiar", false);
|
||||
all.SetOption("Necromancy", "Vengeful Spirit", false);
|
||||
all.SetOption("Necromancy", "Animate Dead", false);
|
||||
all.SetOption("Necromancy", "Wither", false);
|
||||
all.SetOption("Necromancy", "Poison Strike", false);
|
||||
|
||||
all.SetOptionRange("Chivalry", true);
|
||||
all.SetOption("Chivalry", "Sacred Journey", false);
|
||||
all.SetOption("Chivalry", "Enemy of One", false);
|
||||
all.SetOption("Chivalry", "Noble Sacrifice", false);
|
||||
|
||||
all.SetOptionRange("Combat Abilities", true);
|
||||
all.SetOption("Combat Abilities", "Paralyzing Blow", false);
|
||||
all.SetOption("Combat Abilities", "Shadow Strike", false);
|
||||
|
||||
all.SetOption("Skills", "Anatomy", true);
|
||||
all.SetOption("Skills", "Detect Hidden", true);
|
||||
all.SetOption("Skills", "Poisoning", true);
|
||||
all.SetOption("Skills", "Spirit Speak", true);
|
||||
all.SetOption("Skills", "Evaluating Intelligence", true);
|
||||
|
||||
all.SetOptionRange("Weapons", true);
|
||||
all.SetOption("Weapons", "Poisoned", false);
|
||||
|
||||
all.SetOptionRange("Armor", true);
|
||||
|
||||
all.SetOptionRange("Ninjitsu", true);
|
||||
all.SetOption("Ninjitsu", "Animal Form", false);
|
||||
all.SetOption("Ninjitsu", "Mirror Image", false);
|
||||
all.SetOption("Ninjitsu", "Backstab", false);
|
||||
all.SetOption("Ninjitsu", "Suprise Attack", false);
|
||||
all.SetOption("Ninjitsu", "Shadow Jump", false);
|
||||
|
||||
all.SetOptionRange("Bushido", true);
|
||||
|
||||
all.SetOptionRange("Spellweaving", true);
|
||||
all.SetOption("Spellweaving", "Gift of Life", false);
|
||||
all.SetOption("Spellweaving", "Summon Fey", false);
|
||||
all.SetOption("Spellweaving", "Summon Fiend", false);
|
||||
all.SetOption("Spellweaving", "Nature's Fury", false);
|
||||
|
||||
all.SetOption("Potions", "Refresh", true);
|
||||
all.SetOption("Items", "Bandages", true);
|
||||
all.SetOption("Items", "Trapped Containers", true);
|
||||
|
||||
m_Root.Defaults = new[] { all };
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
// Set up flavors
|
||||
|
||||
Ruleset pots = new Ruleset(m_Root) { Title = "Potions" };
|
||||
|
||||
|
||||
pots.SetOptionRange("Potions", true);
|
||||
pots.SetOption("Potions", "Explosion", false);
|
||||
|
||||
Ruleset para = new Ruleset(m_Root) { Title = "Paralyze" };
|
||||
|
||||
para.SetOption("Spells", "Paralyze", true);
|
||||
para.SetOption("Spells", "Paralyze Field", true);
|
||||
para.SetOption("Combat Abilities", "Paralyzing Blow", true);
|
||||
|
||||
Ruleset fields = new Ruleset(m_Root) { Title = "Fields" };
|
||||
|
||||
fields.SetOption("Spells", "Wall of Stone", true);
|
||||
fields.SetOption("Spells", "Fire Field", true);
|
||||
fields.SetOption("Spells", "Poison Field", true);
|
||||
fields.SetOption("Spells", "Energy Field", true);
|
||||
fields.SetOption("Spells", "Wildfire", true);
|
||||
|
||||
Ruleset area = new Ruleset(m_Root) { Title = "Area Effect" };
|
||||
|
||||
area.SetOption("Spells", "Earthquake", true);
|
||||
area.SetOption("Spells", "Meteor Swarm", true);
|
||||
area.SetOption("Spells", "Chain Lightning", true);
|
||||
area.SetOption("Necromancy", "Wither", true);
|
||||
area.SetOption("Necromancy", "Poison Strike", true);
|
||||
|
||||
Ruleset summons = new Ruleset(m_Root) { Title = "Summons" };
|
||||
|
||||
summons.SetOption("Spells", "Blade Spirits", true);
|
||||
summons.SetOption("Spells", "Energy Vortex", true);
|
||||
summons.SetOption("Spells", "Air Elemental", true);
|
||||
summons.SetOption("Spells", "Summon Daemon", true);
|
||||
summons.SetOption("Spells", "Earth Elemental", true);
|
||||
summons.SetOption("Spells", "Fire Elemental", true);
|
||||
summons.SetOption("Spells", "Water Elemental", true);
|
||||
summons.SetOption("Necromancy", "Summon Familiar", true);
|
||||
summons.SetOption("Necromancy", "Vengeful Spirit", true);
|
||||
summons.SetOption("Necromancy", "Animate Dead", true);
|
||||
summons.SetOption("Ninjitsu", "Mirror Image", true);
|
||||
summons.SetOption("Spellweaving", "Summon Fey", true);
|
||||
summons.SetOption("Spellweaving", "Summon Fiend", true);
|
||||
summons.SetOption("Spellweaving", "Nature's Fury", true);
|
||||
|
||||
m_Root.Flavors = new[] { pots, para, fields, area, summons };
|
||||
|
||||
return m_Root;
|
||||
}
|
||||
}
|
||||
|
||||
public string Title{ get; }
|
||||
|
||||
public string Description{ get; }
|
||||
|
||||
public string[] Options{ get; }
|
||||
|
||||
public int Offset{ get; private set; }
|
||||
|
||||
public int TotalLength{ get; private set; }
|
||||
|
||||
public RulesetLayout Parent{ get; private set; }
|
||||
|
||||
public RulesetLayout[] Children{ get; }
|
||||
|
||||
public Ruleset[] Defaults{ get; set; }
|
||||
|
||||
public Ruleset[] Flavors{ get; set; }
|
||||
|
||||
public RulesetLayout FindByTitle(string title)
|
||||
{
|
||||
if (Title == title)
|
||||
return this;
|
||||
|
||||
for (int i = 0; i < Children.Length; ++i)
|
||||
{
|
||||
RulesetLayout layout = Children[i].FindByTitle(title);
|
||||
|
||||
if (layout != null)
|
||||
return layout;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string FindByIndex(int index)
|
||||
{
|
||||
if (index >= Offset && index < Offset + Options.Length)
|
||||
return Description + ": " + Options[index - Offset];
|
||||
|
||||
for (int i = 0; i < Children.Length; ++i)
|
||||
{
|
||||
string opt = Children[i].FindByIndex(index);
|
||||
|
||||
if (opt != null)
|
||||
return opt;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public RulesetLayout FindByOption(string title, string option, ref int index)
|
||||
{
|
||||
if (title == null || Title == title)
|
||||
{
|
||||
index = GetOptionIndex(option);
|
||||
|
||||
if (index >= 0)
|
||||
return this;
|
||||
|
||||
title = null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Children.Length; ++i)
|
||||
{
|
||||
RulesetLayout layout = Children[i].FindByOption(title, option, ref index);
|
||||
|
||||
if (layout != null)
|
||||
return layout;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int GetOptionIndex(string option)
|
||||
{
|
||||
return Array.IndexOf(Options, option);
|
||||
}
|
||||
|
||||
public void ComputeOffsets()
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
RecurseComputeOffsets(ref offset);
|
||||
}
|
||||
|
||||
private int RecurseComputeOffsets(ref int offset)
|
||||
{
|
||||
Offset = offset;
|
||||
|
||||
offset += Options.Length;
|
||||
TotalLength += Options.Length;
|
||||
|
||||
for (int i = 0; i < Children.Length; ++i)
|
||||
TotalLength += Children[i].RecurseComputeOffsets(ref offset);
|
||||
|
||||
return TotalLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Projects/Scripts/Engines/ConPVP/SafeZone.cs
Normal file
66
Projects/Scripts/Engines/ConPVP/SafeZone.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
using Server.Regions;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class SafeZone : GuardedRegion
|
||||
{
|
||||
public static readonly int SafeZonePriority = HouseRegion.HousePriority + 1;
|
||||
|
||||
/*public override bool AllowReds => true;*/
|
||||
|
||||
public SafeZone(Rectangle2D area, Point3D goloc, Map map, bool isGuarded) : base(null, map, SafeZonePriority, area)
|
||||
{
|
||||
GoLocation = goloc;
|
||||
|
||||
Disabled = !isGuarded;
|
||||
|
||||
Register();
|
||||
}
|
||||
|
||||
public override bool AllowHousing(Mobile from, Point3D p)
|
||||
{
|
||||
return from.AccessLevel >= AccessLevel.GameMaster && base.AllowHousing(from, p);
|
||||
}
|
||||
|
||||
public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
|
||||
{
|
||||
if (m.Player && Sigil.ExistsOn(m))
|
||||
{
|
||||
m.SendMessage(0x22, "You are holding a sigil and cannot enter this zone.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerMobile pm = m as PlayerMobile ??
|
||||
(m is BaseCreature bc && bc.Summoned ?
|
||||
bc.SummonMaster as PlayerMobile : null);
|
||||
|
||||
if (pm?.DuelContext?.StartedBeginCountdown == true)
|
||||
return true;
|
||||
|
||||
if (DuelContext.CheckCombat(m))
|
||||
{
|
||||
m.SendMessage(0x22, "You have recently been in combat and cannot enter this zone.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OnMoveInto(m, d, newLocation, oldLocation);
|
||||
}
|
||||
|
||||
public override void OnEnter(Mobile m)
|
||||
{
|
||||
m.SendMessage("You have entered a dueling safezone. No combat other than duels are allowed in this zone.");
|
||||
}
|
||||
|
||||
public override void OnExit(Mobile m)
|
||||
{
|
||||
m.SendMessage("You have left a dueling safezone. Combat is now unrestricted.");
|
||||
}
|
||||
|
||||
public override bool CanUseStuckMenu(Mobile m)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
910
Projects/Scripts/Engines/ConPVP/Tournament.cs
Normal file
910
Projects/Scripts/Engines/ConPVP/Tournament.cs
Normal file
|
|
@ -0,0 +1,910 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Factions;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
using Server.Regions;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public enum TournamentStage
|
||||
{
|
||||
Inactive,
|
||||
Signup,
|
||||
Fighting
|
||||
}
|
||||
|
||||
public enum GroupingType
|
||||
{
|
||||
HighVsLow,
|
||||
Nearest,
|
||||
Random
|
||||
}
|
||||
|
||||
public enum TieType
|
||||
{
|
||||
Random,
|
||||
Highest,
|
||||
Lowest,
|
||||
FullElimination,
|
||||
FullAdvancement
|
||||
}
|
||||
|
||||
public enum TourneyType
|
||||
{
|
||||
Standard,
|
||||
FreeForAll,
|
||||
RandomTeam,
|
||||
RedVsBlue,
|
||||
Faction
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class Tournament
|
||||
{
|
||||
private static readonly TimeSpan SliceInterval = TimeSpan.FromSeconds(12.0);
|
||||
private int m_ParticipantsPerMatch;
|
||||
private int m_PlayersPerParticipant;
|
||||
|
||||
public Tournament(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 5:
|
||||
{
|
||||
FactionRestricted = reader.ReadBool();
|
||||
|
||||
goto case 4;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
EventController = reader.ReadItem() as EventController;
|
||||
|
||||
goto case 3;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
SuddenDeathRounds = reader.ReadEncodedInt();
|
||||
|
||||
goto case 2;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
TourneyType = (TourneyType)reader.ReadEncodedInt();
|
||||
|
||||
goto case 1;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
GroupType = (GroupingType)reader.ReadEncodedInt();
|
||||
TieType = (TieType)reader.ReadEncodedInt();
|
||||
SignupPeriod = reader.ReadTimeSpan();
|
||||
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
if (version < 3)
|
||||
SuddenDeathRounds = 3;
|
||||
|
||||
m_ParticipantsPerMatch = reader.ReadEncodedInt();
|
||||
m_PlayersPerParticipant = reader.ReadEncodedInt();
|
||||
SignupPeriod = reader.ReadTimeSpan();
|
||||
CurrentStage = TournamentStage.Inactive;
|
||||
Pyramid = new TourneyPyramid();
|
||||
Ruleset = new Ruleset(RulesetLayout.Root);
|
||||
Ruleset.ApplyDefault(Ruleset.Layout.Defaults[0]);
|
||||
Participants = new List<TourneyParticipant>();
|
||||
Undefeated = new List<TourneyParticipant>();
|
||||
Arenas = new List<Arena>();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Timer.DelayCall(SliceInterval, SliceInterval, Slice);
|
||||
}
|
||||
|
||||
public Tournament()
|
||||
{
|
||||
m_ParticipantsPerMatch = 2;
|
||||
m_PlayersPerParticipant = 1;
|
||||
Pyramid = new TourneyPyramid();
|
||||
Ruleset = new Ruleset(RulesetLayout.Root);
|
||||
Ruleset.ApplyDefault(Ruleset.Layout.Defaults[0]);
|
||||
Participants = new List<TourneyParticipant>();
|
||||
Undefeated = new List<TourneyParticipant>();
|
||||
Arenas = new List<Arena>();
|
||||
SignupPeriod = TimeSpan.FromMinutes(10.0);
|
||||
|
||||
Timer.DelayCall(SliceInterval, SliceInterval, Slice);
|
||||
}
|
||||
|
||||
public bool IsNotoRestricted => TourneyType != TourneyType.Standard;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public EventController EventController{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int SuddenDeathRounds{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TourneyType TourneyType{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public GroupingType GroupType{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TieType TieType{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan SuddenDeath{ get; set; }
|
||||
|
||||
public Ruleset Ruleset{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ParticipantsPerMatch
|
||||
{
|
||||
get => m_ParticipantsPerMatch;
|
||||
set
|
||||
{
|
||||
if (value < 2) value = 2;
|
||||
else if (value > 10) value = 10;
|
||||
m_ParticipantsPerMatch = value;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int PlayersPerParticipant
|
||||
{
|
||||
get => m_PlayersPerParticipant;
|
||||
set
|
||||
{
|
||||
if (value < 1) value = 1;
|
||||
else if (value > 10) value = 10;
|
||||
m_PlayersPerParticipant = value;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int LevelRequirement{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool FactionRestricted{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan SignupPeriod{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime SignupStart{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentStage CurrentStage{ get; private set; }
|
||||
|
||||
public TournamentStage Stage
|
||||
{
|
||||
get => CurrentStage;
|
||||
set => CurrentStage = value;
|
||||
}
|
||||
|
||||
public TourneyPyramid Pyramid{ get; set; }
|
||||
|
||||
public List<Arena> Arenas{ get; set; }
|
||||
|
||||
public List<TourneyParticipant> Participants{ get; set; }
|
||||
|
||||
public List<TourneyParticipant> Undefeated{ get; set; }
|
||||
|
||||
public bool IsFactionRestricted => FactionRestricted || TourneyType == TourneyType.Faction;
|
||||
|
||||
public bool HasParticipant(Mobile mob)
|
||||
{
|
||||
for (int i = 0; i < Participants.Count; ++i)
|
||||
{
|
||||
if (Participants[i].Players.Contains(mob))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(5); // version
|
||||
|
||||
writer.Write(FactionRestricted);
|
||||
|
||||
writer.Write(EventController);
|
||||
|
||||
writer.WriteEncodedInt(SuddenDeathRounds);
|
||||
|
||||
writer.WriteEncodedInt((int)TourneyType);
|
||||
|
||||
writer.WriteEncodedInt((int)GroupType);
|
||||
writer.WriteEncodedInt((int)TieType);
|
||||
writer.Write(SuddenDeath);
|
||||
|
||||
writer.WriteEncodedInt(m_ParticipantsPerMatch);
|
||||
writer.WriteEncodedInt(m_PlayersPerParticipant);
|
||||
writer.Write(SignupPeriod);
|
||||
}
|
||||
|
||||
public void HandleTie(Arena arena, TourneyMatch match, List<TourneyParticipant> remaining)
|
||||
{
|
||||
if (remaining.Count == 1)
|
||||
HandleWon(arena, match, remaining[0]);
|
||||
|
||||
if (remaining.Count < 2)
|
||||
return;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("The match has ended in a tie ");
|
||||
|
||||
sb.Append(remaining.Count == 2 ? "between " : "among ");
|
||||
|
||||
sb.Append(remaining.Count);
|
||||
|
||||
sb.Append(remaining[0].Players.Count == 1 ? " players: " : " teams: ");
|
||||
|
||||
bool hasAppended = false;
|
||||
|
||||
for (int j = 0; j < match.Participants.Count; ++j)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[j];
|
||||
|
||||
if (remaining.Contains(part))
|
||||
{
|
||||
if (hasAppended)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(part.NameList);
|
||||
hasAppended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Undefeated.Remove(part);
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append(". ");
|
||||
|
||||
string whole = remaining.Count == 2 ? "both" : "all";
|
||||
|
||||
TieType tieType = TieType;
|
||||
|
||||
if (tieType == TieType.FullElimination && remaining.Count >= Undefeated.Count)
|
||||
tieType = TieType.FullAdvancement;
|
||||
|
||||
switch (tieType)
|
||||
{
|
||||
case TieType.FullAdvancement:
|
||||
{
|
||||
sb.AppendFormat("In accordance with the rules, {0} parties are advanced.", whole);
|
||||
break;
|
||||
}
|
||||
case TieType.FullElimination:
|
||||
{
|
||||
for (int j = 0; j < remaining.Count; ++j)
|
||||
Undefeated.Remove(remaining[j]);
|
||||
|
||||
sb.AppendFormat("In accordance with the rules, {0} parties are eliminated.", whole);
|
||||
break;
|
||||
}
|
||||
case TieType.Random:
|
||||
{
|
||||
TourneyParticipant advanced = remaining[Utility.Random(remaining.Count)];
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
if (remaining[i] != advanced)
|
||||
Undefeated.Remove(remaining[i]);
|
||||
|
||||
if (advanced != null)
|
||||
sb.AppendFormat("In accordance with the rules, {0} {1} advanced.", advanced.NameList,
|
||||
advanced.Players.Count == 1 ? "is" : "are");
|
||||
|
||||
break;
|
||||
}
|
||||
case TieType.Highest:
|
||||
{
|
||||
TourneyParticipant advanced = null;
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = remaining[i];
|
||||
|
||||
if (advanced == null || part.TotalLadderXP > advanced.TotalLadderXP)
|
||||
advanced = part;
|
||||
}
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
if (remaining[i] != advanced)
|
||||
Undefeated.Remove(remaining[i]);
|
||||
|
||||
if (advanced != null)
|
||||
sb.AppendFormat("In accordance with the rules, {0} {1} advanced.", advanced.NameList,
|
||||
advanced.Players.Count == 1 ? "is" : "are");
|
||||
|
||||
break;
|
||||
}
|
||||
case TieType.Lowest:
|
||||
{
|
||||
TourneyParticipant advanced = null;
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = remaining[i];
|
||||
|
||||
if (advanced == null || part.TotalLadderXP < advanced.TotalLadderXP)
|
||||
advanced = part;
|
||||
}
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
if (remaining[i] != advanced)
|
||||
Undefeated.Remove(remaining[i]);
|
||||
|
||||
if (advanced != null)
|
||||
sb.AppendFormat("In accordance with the rules, {0} {1} advanced.", advanced.NameList,
|
||||
advanced.Players.Count == 1 ? "is" : "are");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Alert(arena, sb.ToString());
|
||||
}
|
||||
|
||||
public void OnEliminated(DuelPlayer player)
|
||||
{
|
||||
Participant part = player.Participant;
|
||||
|
||||
if (!part.Eliminated)
|
||||
return;
|
||||
|
||||
if (TourneyType == TourneyType.FreeForAll)
|
||||
{
|
||||
int rem = 0;
|
||||
|
||||
for (int i = 0; i < part.Context.Participants.Count; ++i)
|
||||
{
|
||||
if (part.Context.Participants[i]?.Eliminated == false)
|
||||
++rem;
|
||||
}
|
||||
|
||||
TourneyParticipant tp = part.TourneyPart;
|
||||
|
||||
if (tp == null)
|
||||
return;
|
||||
|
||||
if (rem == 1)
|
||||
GiveAwards(tp.Players, TrophyRank.Silver, ComputeCashAward() / 2);
|
||||
else if (rem == 2)
|
||||
GiveAwards(tp.Players, TrophyRank.Bronze, ComputeCashAward() / 4);
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleWon(Arena arena, TourneyMatch match, TourneyParticipant winner)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("The match is complete. ");
|
||||
sb.Append(winner.NameList);
|
||||
|
||||
if (winner.Players.Count > 1)
|
||||
sb.Append(" have bested ");
|
||||
else
|
||||
sb.Append(" has bested ");
|
||||
|
||||
if (match.Participants.Count > 2)
|
||||
sb.AppendFormat("{0} other {1}: ", match.Participants.Count - 1,
|
||||
winner.Players.Count == 1 ? "players" : "teams");
|
||||
|
||||
bool hasAppended = false;
|
||||
|
||||
for (int j = 0; j < match.Participants.Count; ++j)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[j];
|
||||
|
||||
if (part == winner)
|
||||
continue;
|
||||
|
||||
Undefeated.Remove(part);
|
||||
|
||||
if (hasAppended)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(part.NameList);
|
||||
hasAppended = true;
|
||||
}
|
||||
|
||||
sb.Append(".");
|
||||
|
||||
if (TourneyType == TourneyType.Standard)
|
||||
Alert(arena, sb.ToString());
|
||||
}
|
||||
|
||||
private int ComputeCashAward()
|
||||
{
|
||||
return Participants.Count * m_PlayersPerParticipant * 2500;
|
||||
}
|
||||
|
||||
private void GiveAwards()
|
||||
{
|
||||
switch (TourneyType)
|
||||
{
|
||||
case TourneyType.FreeForAll:
|
||||
{
|
||||
if (Pyramid.Levels.Count < 1)
|
||||
break;
|
||||
|
||||
PyramidLevel top = Pyramid.Levels[Pyramid.Levels.Count - 1];
|
||||
|
||||
if (top.FreeAdvance != null || top.Matches.Count != 1)
|
||||
break;
|
||||
|
||||
TourneyMatch match = top.Matches[0];
|
||||
TourneyParticipant winner = match.Winner;
|
||||
|
||||
if (winner != null)
|
||||
GiveAwards(winner.Players, TrophyRank.Gold, ComputeCashAward());
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyType.Standard:
|
||||
{
|
||||
if (Pyramid.Levels.Count < 2)
|
||||
break;
|
||||
|
||||
PyramidLevel top = Pyramid.Levels[Pyramid.Levels.Count - 1];
|
||||
|
||||
if (top.FreeAdvance != null || top.Matches.Count != 1)
|
||||
break;
|
||||
|
||||
int cash = ComputeCashAward();
|
||||
|
||||
TourneyMatch match = top.Matches[0];
|
||||
TourneyParticipant winner = match.Winner;
|
||||
|
||||
for (int i = 0; i < match.Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[i];
|
||||
|
||||
if (part == winner)
|
||||
GiveAwards(part.Players, TrophyRank.Gold, cash);
|
||||
else
|
||||
GiveAwards(part.Players, TrophyRank.Silver, cash / 2);
|
||||
}
|
||||
|
||||
PyramidLevel next = Pyramid.Levels[Pyramid.Levels.Count - 2];
|
||||
|
||||
if (next.Matches.Count > 2)
|
||||
break;
|
||||
|
||||
for (int i = 0; i < next.Matches.Count; ++i)
|
||||
{
|
||||
match = next.Matches[i];
|
||||
winner = match.Winner;
|
||||
|
||||
for (int j = 0; j < match.Participants.Count; ++j)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[j];
|
||||
|
||||
if (part != winner)
|
||||
GiveAwards(part.Players, TrophyRank.Bronze, cash / 4);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GiveAwards(List<Mobile> players, TrophyRank rank, int cash)
|
||||
{
|
||||
if (players.Count == 0)
|
||||
return;
|
||||
|
||||
if (players.Count > 1)
|
||||
cash /= players.Count - 1;
|
||||
|
||||
cash += 500;
|
||||
cash /= 1000;
|
||||
cash *= 1000;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (TourneyType == TourneyType.FreeForAll)
|
||||
{
|
||||
sb.Append(Participants.Count * m_PlayersPerParticipant);
|
||||
sb.Append("-man FFA");
|
||||
}
|
||||
else if (TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
sb.Append(m_ParticipantsPerMatch);
|
||||
sb.Append("-Team");
|
||||
}
|
||||
else if (TourneyType == TourneyType.Faction)
|
||||
{
|
||||
sb.Append(m_ParticipantsPerMatch);
|
||||
sb.Append("-Team Faction");
|
||||
}
|
||||
else if (TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
sb.Append("Red v Blue");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < m_ParticipantsPerMatch; ++i)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append('v');
|
||||
|
||||
sb.Append(m_PlayersPerParticipant);
|
||||
}
|
||||
}
|
||||
|
||||
if (EventController != null)
|
||||
sb.Append(' ').Append(EventController.Title);
|
||||
|
||||
sb.Append(" Champion");
|
||||
|
||||
string title = sb.ToString();
|
||||
|
||||
for (int i = 0; i < players.Count; ++i)
|
||||
{
|
||||
Mobile mob = players[i];
|
||||
|
||||
if (mob?.Deleted != false)
|
||||
continue;
|
||||
|
||||
Item item = new Trophy(title, rank);
|
||||
|
||||
if (!mob.PlaceInBackpack(item))
|
||||
mob.BankBox.DropItem(item);
|
||||
|
||||
if (cash > 0)
|
||||
{
|
||||
item = new BankCheck(cash);
|
||||
|
||||
if (!mob.PlaceInBackpack(item))
|
||||
mob.BankBox.DropItem(item);
|
||||
|
||||
mob.SendMessage(
|
||||
"You have been awarded a {0} trophy and {1:N0}gp for your participation in this tournament.",
|
||||
rank.ToString().ToLower(), cash);
|
||||
}
|
||||
else
|
||||
{
|
||||
mob.SendMessage("You have been awarded a {0} trophy for your participation in this tournament.",
|
||||
rank.ToString().ToLower());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Slice()
|
||||
{
|
||||
if (CurrentStage == TournamentStage.Signup)
|
||||
{
|
||||
TimeSpan until = SignupStart + SignupPeriod - DateTime.UtcNow;
|
||||
|
||||
if (until <= TimeSpan.Zero)
|
||||
{
|
||||
for (int i = Participants.Count - 1; i >= 0; --i)
|
||||
{
|
||||
TourneyParticipant part = Participants[i];
|
||||
bool bad = false;
|
||||
|
||||
for (int j = 0; j < part.Players.Count; ++j)
|
||||
{
|
||||
Mobile check = part.Players[j];
|
||||
|
||||
if (check.Deleted || check.Map == null || check.Map == Map.Internal || !check.Alive ||
|
||||
Sigil.ExistsOn(check) || check.Region.IsPartOf<Jail>())
|
||||
{
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bad)
|
||||
{
|
||||
for (int j = 0; j < part.Players.Count; ++j)
|
||||
part.Players[j].SendMessage("You have been disqualified from the tournament.");
|
||||
|
||||
Participants.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (Participants.Count >= 2)
|
||||
{
|
||||
CurrentStage = TournamentStage.Fighting;
|
||||
|
||||
Undefeated.Clear();
|
||||
|
||||
Pyramid.Levels.Clear();
|
||||
Pyramid.AddLevel(m_ParticipantsPerMatch, Participants, GroupType, TourneyType);
|
||||
|
||||
PyramidLevel level = Pyramid.Levels[0];
|
||||
|
||||
if (level.FreeAdvance != null)
|
||||
Undefeated.Add(level.FreeAdvance);
|
||||
|
||||
for (int i = 0; i < level.Matches.Count; ++i)
|
||||
{
|
||||
TourneyMatch match = level.Matches[i];
|
||||
|
||||
Undefeated.AddRange(match.Participants);
|
||||
}
|
||||
|
||||
Alert("Hear ye! Hear ye!", "The tournament will begin shortly.");
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Alert( "Is this all?", "Pitiful. Signup extended." );
|
||||
m_SignupStart = DateTime.UtcNow;*/
|
||||
|
||||
Alert("Is this all?", "Pitiful. Tournament cancelled.");
|
||||
CurrentStage = TournamentStage.Inactive;
|
||||
}
|
||||
}
|
||||
else if (Math.Abs(until.TotalSeconds - TimeSpan.FromMinutes(1.0).TotalSeconds) <
|
||||
SliceInterval.TotalSeconds / 2)
|
||||
{
|
||||
Alert("Last call!", "If you wish to enter the tournament, sign up with the registrar now.");
|
||||
}
|
||||
else if (Math.Abs(until.TotalSeconds - TimeSpan.FromMinutes(5.0).TotalSeconds) <
|
||||
SliceInterval.TotalSeconds / 2)
|
||||
{
|
||||
Alert("The tournament will begin in 5 minutes.", "Sign up now before it's too late.");
|
||||
}
|
||||
}
|
||||
else if (CurrentStage == TournamentStage.Fighting)
|
||||
{
|
||||
if (Undefeated.Count == 1)
|
||||
{
|
||||
TourneyParticipant winner = Undefeated[0];
|
||||
|
||||
try
|
||||
{
|
||||
if (EventController != null)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {EventController.GetTeamName(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner))} has won!");
|
||||
}
|
||||
else if (TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!");
|
||||
}
|
||||
else if (TourneyType == TourneyType.Faction)
|
||||
{
|
||||
if (m_ParticipantsPerMatch == 4)
|
||||
{
|
||||
string name = "(null)";
|
||||
|
||||
switch (Pyramid.Levels[0].Matches[0].Participants.IndexOf(
|
||||
winner))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
name = "Minax";
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
name = "Council of Mages";
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
name = "True Britannians";
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
name = "Shadowlords";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Alert("The tournament has completed!", $"The {name} team has won!");
|
||||
}
|
||||
else if (m_ParticipantsPerMatch == 2)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"The {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Evil" : "Hero")} team has won!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!");
|
||||
}
|
||||
}
|
||||
else if (TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Red" : "Blue")} has won!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"{winner.NameList} {(winner.Players.Count > 1 ? "are" : "is")} the champion{(winner.Players.Count == 1 ? "" : "s")}.");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
GiveAwards();
|
||||
|
||||
CurrentStage = TournamentStage.Inactive;
|
||||
Undefeated.Clear();
|
||||
}
|
||||
else if (Pyramid.Levels.Count > 0)
|
||||
{
|
||||
PyramidLevel activeLevel = Pyramid.Levels[Pyramid.Levels.Count - 1];
|
||||
bool stillGoing = false;
|
||||
|
||||
for (int i = 0; i < activeLevel.Matches.Count; ++i)
|
||||
{
|
||||
TourneyMatch match = activeLevel.Matches[i];
|
||||
|
||||
if (match.Winner == null)
|
||||
{
|
||||
stillGoing = true;
|
||||
|
||||
if (!match.InProgress)
|
||||
for (int j = 0; j < Arenas.Count; ++j)
|
||||
{
|
||||
Arena arena = Arenas[j];
|
||||
|
||||
if (!arena.IsOccupied)
|
||||
{
|
||||
match.Start(arena, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!stillGoing)
|
||||
{
|
||||
for (int i = Undefeated.Count - 1; i >= 0; --i)
|
||||
{
|
||||
TourneyParticipant part = Undefeated[i];
|
||||
bool bad = false;
|
||||
|
||||
for (int j = 0; j < part.Players.Count; ++j)
|
||||
{
|
||||
Mobile check = part.Players[j];
|
||||
|
||||
if (check.Deleted || check.Map == null || check.Map == Map.Internal || !check.Alive ||
|
||||
Sigil.ExistsOn(check) || check.Region.IsPartOf<Jail>())
|
||||
{
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bad)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < part.Players.Count; ++j)
|
||||
part.Players[j].SendMessage("You have been disqualified from the tournament.");
|
||||
|
||||
Undefeated.RemoveAt(i);
|
||||
|
||||
if (Undefeated.Count == 1)
|
||||
{
|
||||
TourneyParticipant winner = Undefeated[0];
|
||||
|
||||
try
|
||||
{
|
||||
if (EventController != null)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {EventController.GetTeamName(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner))} has won");
|
||||
}
|
||||
else if (TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!");
|
||||
}
|
||||
else if (TourneyType == TourneyType.Faction)
|
||||
{
|
||||
if (m_ParticipantsPerMatch == 4)
|
||||
{
|
||||
string name = "(null)";
|
||||
|
||||
switch (Pyramid.Levels[0].Matches[0]
|
||||
.Participants.IndexOf(winner))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
name = "Minax";
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
name = "Council of Mages";
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
name = "True Britannians";
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
name = "Shadowlords";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Alert("The tournament has completed!", $"The {name} team has won!");
|
||||
}
|
||||
else if (m_ParticipantsPerMatch == 2)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"The {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Evil" : "Hero")} team has won!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!");
|
||||
}
|
||||
}
|
||||
else if (TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Red" : "Blue")} has won!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"{winner.NameList} {(winner.Players.Count > 1 ? "are" : "is")} the champion{(winner.Players.Count == 1 ? "" : "s")}.");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
GiveAwards();
|
||||
|
||||
CurrentStage = TournamentStage.Inactive;
|
||||
Undefeated.Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Undefeated.Count > 1)
|
||||
Pyramid.AddLevel(m_ParticipantsPerMatch, Undefeated, GroupType, TourneyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Alert(params string[] alerts)
|
||||
{
|
||||
for (int i = 0; i < Arenas.Count; ++i)
|
||||
Alert(Arenas[i], alerts);
|
||||
}
|
||||
|
||||
public void Alert(Arena arena, params string[] alerts)
|
||||
{
|
||||
if (arena?.Announcer != null)
|
||||
for (int j = 0; j < alerts.Length; ++j)
|
||||
{
|
||||
string alert = alerts[j];
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(Math.Max(j - 0.5, 0.0)),
|
||||
() => arena.Announcer.PublicOverheadMessage(MessageType.Regular, 0x35, false, alert));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
Projects/Scripts/Engines/ConPVP/TournamentBracketItem.cs
Normal file
65
Projects/Scripts/Engines/ConPVP/TournamentBracketItem.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TournamentBracketItem : Item
|
||||
{
|
||||
[Constructible]
|
||||
public TournamentBracketItem() : base(3774)
|
||||
{
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public TournamentBracketItem(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentController Tournament{ get; set; }
|
||||
|
||||
public override string DefaultName => "tournament bracket";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
|
||||
}
|
||||
else
|
||||
{
|
||||
Tournament tourney = Tournament?.Tournament;
|
||||
|
||||
if (tourney != null)
|
||||
{
|
||||
from.CloseGump<TournamentBracketGump>();
|
||||
from.SendGump(new TournamentBracketGump(from, tourney, TourneyBracketGumpType.Index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
writer.Write(Tournament);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Tournament = reader.ReadItem() as TournamentController;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
Projects/Scripts/Engines/ConPVP/TournamentController.cs
Normal file
143
Projects/Scripts/Engines/ConPVP/TournamentController.cs
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.ContextMenus;
|
||||
using Server.Gumps;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TournamentController : Item
|
||||
{
|
||||
private static List<TournamentController> m_Instances = new List<TournamentController>();
|
||||
|
||||
[Constructible]
|
||||
public TournamentController() : base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
|
||||
Tournament = new Tournament();
|
||||
m_Instances.Add(this);
|
||||
}
|
||||
|
||||
public TournamentController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Tournament Tournament{ get; private set; }
|
||||
|
||||
public static bool IsActive
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < m_Instances.Count; ++i)
|
||||
{
|
||||
TournamentController controller = m_Instances[i];
|
||||
|
||||
if (controller?.Deleted == false && controller.Tournament != null &&
|
||||
controller.Tournament.Stage != TournamentStage.Inactive)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string DefaultName => "tournament controller";
|
||||
|
||||
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
|
||||
{
|
||||
base.GetContextMenuEntries(from, list);
|
||||
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster && Tournament != null)
|
||||
{
|
||||
list.Add(new EditEntry(Tournament));
|
||||
|
||||
if (Tournament.CurrentStage == TournamentStage.Inactive)
|
||||
list.Add(new StartEntry(Tournament));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster && Tournament != null)
|
||||
{
|
||||
from.CloseGump<PickRulesetGump>();
|
||||
from.CloseGump<RulesetGump>();
|
||||
from.SendGump(new PickRulesetGump(from, null, Tournament.Ruleset));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
Tournament.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Tournament = new Tournament(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_Instances.Add(this);
|
||||
}
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
base.OnDelete();
|
||||
|
||||
m_Instances.Remove(this);
|
||||
}
|
||||
|
||||
private class EditEntry : ContextMenuEntry
|
||||
{
|
||||
private Tournament m_Tournament;
|
||||
|
||||
public EditEntry(Tournament tourney) : base(5101)
|
||||
{
|
||||
m_Tournament = tourney;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
Owner.From.SendGump(new PropertiesGump(Owner.From, m_Tournament));
|
||||
}
|
||||
}
|
||||
|
||||
private class StartEntry : ContextMenuEntry
|
||||
{
|
||||
private Tournament m_Tournament;
|
||||
|
||||
public StartEntry(Tournament tourney) : base(5113)
|
||||
{
|
||||
m_Tournament = tourney;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
if (m_Tournament.Stage == TournamentStage.Inactive)
|
||||
{
|
||||
m_Tournament.SignupStart = DateTime.UtcNow;
|
||||
m_Tournament.Stage = TournamentStage.Signup;
|
||||
m_Tournament.Participants.Clear();
|
||||
m_Tournament.Pyramid.Levels.Clear();
|
||||
m_Tournament.Alert("Hear ye! Hear ye!",
|
||||
"Tournament signup has opened. You can enter by signing up with the registrar.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
190
Projects/Scripts/Engines/ConPVP/TournamentPyramid.cs
Normal file
190
Projects/Scripts/Engines/ConPVP/TournamentPyramid.cs
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Ethics;
|
||||
using Server.Factions;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TourneyPyramid
|
||||
{
|
||||
public TourneyPyramid()
|
||||
{
|
||||
Levels = new List<PyramidLevel>();
|
||||
}
|
||||
|
||||
public List<PyramidLevel> Levels{ get; set; }
|
||||
|
||||
public void AddLevel(int partsPerMatch, List<TourneyParticipant> participants, GroupingType groupType, TourneyType tourneyType)
|
||||
{
|
||||
List<TourneyParticipant> copy = new List<TourneyParticipant>(participants);
|
||||
|
||||
if (groupType == GroupingType.Nearest || groupType == GroupingType.HighVsLow)
|
||||
copy.Sort();
|
||||
|
||||
PyramidLevel level = new PyramidLevel();
|
||||
|
||||
switch (tourneyType)
|
||||
{
|
||||
case TourneyType.RedVsBlue:
|
||||
{
|
||||
TourneyParticipant[] parts = new TourneyParticipant[2];
|
||||
|
||||
for (int i = 0; i < parts.Length; ++i)
|
||||
parts[i] = new TourneyParticipant(new List<Mobile>());
|
||||
|
||||
for (int i = 0; i < copy.Count; ++i)
|
||||
{
|
||||
List<Mobile> players = copy[i].Players;
|
||||
|
||||
for (int j = 0; j < players.Count; ++j)
|
||||
{
|
||||
Mobile mob = players[j];
|
||||
|
||||
if (mob.Kills >= 5)
|
||||
parts[0].Players.Add(mob);
|
||||
else
|
||||
parts[1].Players.Add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
level.Matches.Add(new TourneyMatch(new List<TourneyParticipant>(parts)));
|
||||
break;
|
||||
}
|
||||
case TourneyType.Faction:
|
||||
{
|
||||
TourneyParticipant[] parts = new TourneyParticipant[partsPerMatch];
|
||||
|
||||
for (int i = 0; i < parts.Length; ++i)
|
||||
parts[i] = new TourneyParticipant(new List<Mobile>());
|
||||
|
||||
for (int i = 0; i < copy.Count; ++i)
|
||||
{
|
||||
List<Mobile> players = copy[i].Players;
|
||||
|
||||
for (int j = 0; j < players.Count; ++j)
|
||||
{
|
||||
Mobile mob = players[j];
|
||||
|
||||
int index = -1;
|
||||
|
||||
if (partsPerMatch == 4)
|
||||
{
|
||||
Faction fac = Faction.Find(mob);
|
||||
|
||||
if (fac != null)
|
||||
index = fac.Definition.Sort;
|
||||
}
|
||||
else if (partsPerMatch == 2)
|
||||
{
|
||||
if (Ethic.Evil.IsEligible(mob))
|
||||
index = 0;
|
||||
else if (Ethic.Hero.IsEligible(mob)) index = 1;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= partsPerMatch) index = i % partsPerMatch;
|
||||
|
||||
parts[index].Players.Add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
level.Matches.Add(new TourneyMatch(new List<TourneyParticipant>(parts)));
|
||||
break;
|
||||
}
|
||||
case TourneyType.RandomTeam:
|
||||
{
|
||||
TourneyParticipant[] parts = new TourneyParticipant[partsPerMatch];
|
||||
|
||||
for (int i = 0; i < partsPerMatch; ++i)
|
||||
parts[i] = new TourneyParticipant(new List<Mobile>());
|
||||
|
||||
for (int i = 0; i < copy.Count; ++i)
|
||||
parts[i % parts.Length].Players.AddRange(copy[i].Players);
|
||||
|
||||
level.Matches.Add(new TourneyMatch(new List<TourneyParticipant>(parts)));
|
||||
break;
|
||||
}
|
||||
case TourneyType.FreeForAll:
|
||||
{
|
||||
level.Matches.Add(new TourneyMatch(copy));
|
||||
break;
|
||||
}
|
||||
case TourneyType.Standard:
|
||||
{
|
||||
if (partsPerMatch >= 2 && participants.Count % partsPerMatch == 1)
|
||||
{
|
||||
int lowAdvances = int.MaxValue;
|
||||
|
||||
for (int i = 0; i < participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant p = participants[i];
|
||||
|
||||
if (p.FreeAdvances < lowAdvances)
|
||||
lowAdvances = p.FreeAdvances;
|
||||
}
|
||||
|
||||
List<TourneyParticipant> toAdvance = new List<TourneyParticipant>();
|
||||
|
||||
for (int i = 0; i < participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant p = participants[i];
|
||||
|
||||
if (p.FreeAdvances == lowAdvances)
|
||||
toAdvance.Add(p);
|
||||
}
|
||||
|
||||
if (toAdvance.Count == 0)
|
||||
toAdvance = copy; // sanity
|
||||
|
||||
int idx = Utility.Random(toAdvance.Count);
|
||||
|
||||
toAdvance[idx].AddLog(
|
||||
"Advanced automatically due to an odd number of challengers.");
|
||||
level.FreeAdvance = toAdvance[idx];
|
||||
++level.FreeAdvance.FreeAdvances;
|
||||
copy.Remove(toAdvance[idx]);
|
||||
}
|
||||
|
||||
while (copy.Count >= partsPerMatch)
|
||||
{
|
||||
List<TourneyParticipant> thisMatch = new List<TourneyParticipant>();
|
||||
|
||||
for (int i = 0; i < partsPerMatch; ++i)
|
||||
{
|
||||
int idx = 0;
|
||||
|
||||
switch (groupType)
|
||||
{
|
||||
case GroupingType.HighVsLow:
|
||||
idx = i * (copy.Count - 1) / (partsPerMatch - 1);
|
||||
break;
|
||||
case GroupingType.Nearest:
|
||||
idx = 0;
|
||||
break;
|
||||
case GroupingType.Random:
|
||||
idx = Utility.Random(copy.Count);
|
||||
break;
|
||||
}
|
||||
|
||||
thisMatch.Add(copy[idx]);
|
||||
copy.RemoveAt(idx);
|
||||
}
|
||||
|
||||
level.Matches.Add(new TourneyMatch(thisMatch));
|
||||
}
|
||||
|
||||
if (copy.Count > 1)
|
||||
level.Matches.Add(new TourneyMatch(copy));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Levels.Add(level);
|
||||
}
|
||||
}
|
||||
|
||||
public class PyramidLevel
|
||||
{
|
||||
public List<TourneyMatch> Matches{ get; set; } = new List<TourneyMatch>();
|
||||
public TourneyParticipant FreeAdvance{ get; set; }
|
||||
}
|
||||
}
|
||||
93
Projects/Scripts/Engines/ConPVP/TournamentRegistrar.cs
Normal file
93
Projects/Scripts/Engines/ConPVP/TournamentRegistrar.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TournamentRegistrar : Banker
|
||||
{
|
||||
[Constructible]
|
||||
public TournamentRegistrar()
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(30.0), TimeSpan.FromSeconds(30.0), Announce_Callback);
|
||||
}
|
||||
|
||||
public TournamentRegistrar(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentController Tournament{ get; set; }
|
||||
|
||||
private void Announce_Callback()
|
||||
{
|
||||
Tournament tourney = Tournament?.Tournament;
|
||||
|
||||
if (tourney?.Stage == TournamentStage.Signup)
|
||||
PublicOverheadMessage(MessageType.Regular, 0x35, false,
|
||||
"Come one, come all! Do you aspire to be a fighter of great renown? Join this tournament and show the world your abilities.");
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
base.OnMovement(m, oldLocation);
|
||||
|
||||
Tournament tourney = Tournament?.Tournament;
|
||||
|
||||
if (InRange(m, 4) && !InRange(oldLocation, 4) && tourney != null && tourney.Stage == TournamentStage.Signup &&
|
||||
m.CanBeginAction(this))
|
||||
{
|
||||
Ladder ladder = Ladder.Instance;
|
||||
|
||||
LadderEntry entry = ladder?.Find(m);
|
||||
|
||||
if (entry != null && Ladder.GetLevel(entry.Experience) < tourney.LevelRequirement)
|
||||
return;
|
||||
|
||||
if (tourney.IsFactionRestricted && Faction.Find(m) == null) return;
|
||||
|
||||
if (tourney.HasParticipant(m))
|
||||
return;
|
||||
|
||||
PrivateOverheadMessage(MessageType.Regular, 0x35, false,
|
||||
$"Hello m'{(m.Female ? "Lady" : "Lord")}. Dost thou wish to enter this tournament? You need only to write your name in this book.",
|
||||
m.NetState);
|
||||
m.BeginAction(this);
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(10.0), ReleaseLock_Callback, m);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseLock_Callback(Mobile m)
|
||||
{
|
||||
m.EndAction(this);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
writer.Write(Tournament);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Tournament = reader.ReadItem() as TournamentController;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(30.0), TimeSpan.FromSeconds(30.0), Announce_Callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
149
Projects/Scripts/Engines/ConPVP/TournamentSignupItem.cs
Normal file
149
Projects/Scripts/Engines/ConPVP/TournamentSignupItem.cs
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TournamentSignupItem : Item
|
||||
{
|
||||
[Constructible]
|
||||
public TournamentSignupItem() : base(4029)
|
||||
{
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public TournamentSignupItem(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentController Tournament{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile Registrar{ get; set; }
|
||||
|
||||
public override string DefaultName => "tournament signup book";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
|
||||
}
|
||||
else
|
||||
{
|
||||
Tournament tourney = Tournament?.Tournament;
|
||||
|
||||
if (tourney == null)
|
||||
return;
|
||||
|
||||
if (Registrar != null)
|
||||
Registrar.Direction = Registrar.GetDirectionTo(this);
|
||||
|
||||
switch (tourney.Stage)
|
||||
{
|
||||
case TournamentStage.Fighting:
|
||||
{
|
||||
if (Registrar != null)
|
||||
{
|
||||
if (tourney.HasParticipant(from))
|
||||
Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "Excuse me? You are already signed up.", from.NetState);
|
||||
else
|
||||
Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "The tournament has already begun. You are too late to signup now.",
|
||||
from.NetState);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TournamentStage.Inactive:
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "The tournament is closed.", from.NetState);
|
||||
|
||||
break;
|
||||
}
|
||||
case TournamentStage.Signup:
|
||||
{
|
||||
Ladder ladder = Ladder.Instance;
|
||||
LadderEntry entry = ladder?.Find(from);
|
||||
|
||||
if (entry != null && Ladder.GetLevel(entry.Experience) < tourney.LevelRequirement)
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "You have not yet proven yourself a worthy dueler.", from.NetState);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (tourney.IsFactionRestricted && Faction.Find(from) == null)
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "Only those who have declared their faction allegiance may participate.",
|
||||
from.NetState);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (from.HasGump<AcceptTeamGump>())
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "You must first respond to the offer I've given you.", from.NetState);
|
||||
}
|
||||
else if (from.HasGump<AcceptDuelGump>())
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "You must first cancel your duel offer.", from.NetState);
|
||||
}
|
||||
else if (from is PlayerMobile mobile && mobile.DuelContext != null)
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "You are already participating in a duel.", mobile.NetState);
|
||||
}
|
||||
else if (!tourney.HasParticipant(from))
|
||||
{
|
||||
from.CloseGump<ConfirmSignupGump>();
|
||||
from.SendGump(new ConfirmSignupGump(from, Registrar, tourney, new List<Mobile> { from }));
|
||||
}
|
||||
else
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "You have already entered this tournament.", from.NetState);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
writer.Write(Tournament);
|
||||
writer.Write(Registrar);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Tournament = reader.ReadItem() as TournamentController;
|
||||
Registrar = reader.ReadMobile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Projects/Scripts/Engines/ConPVP/TourneyParticipant.cs
Normal file
109
Projects/Scripts/Engines/ConPVP/TourneyParticipant.cs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TourneyParticipant : IComparable<TourneyParticipant>
|
||||
{
|
||||
public TourneyParticipant(Mobile owner)
|
||||
{
|
||||
Log = new List<string>();
|
||||
Players = new List<Mobile> { owner };
|
||||
}
|
||||
|
||||
public TourneyParticipant(List<Mobile> players)
|
||||
{
|
||||
Log = new List<string>();
|
||||
Players = players;
|
||||
}
|
||||
|
||||
public List<Mobile> Players{ get; set; }
|
||||
|
||||
public List<string> Log{ get; set; }
|
||||
|
||||
public int FreeAdvances{ get; set; }
|
||||
|
||||
public int TotalLadderXP
|
||||
{
|
||||
get
|
||||
{
|
||||
Ladder ladder = Ladder.Instance;
|
||||
|
||||
if (ladder == null)
|
||||
return 0;
|
||||
|
||||
int total = 0;
|
||||
|
||||
for (int i = 0; i < Players.Count; ++i)
|
||||
{
|
||||
Mobile mob = Players[i];
|
||||
LadderEntry entry = ladder.Find(mob);
|
||||
|
||||
if (entry != null)
|
||||
total += entry.Experience;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
public string NameList
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < Players.Count; ++i)
|
||||
{
|
||||
if (Players[i] == null)
|
||||
continue;
|
||||
|
||||
Mobile mob = Players[i];
|
||||
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
if (Players.Count == 2)
|
||||
sb.Append(" and ");
|
||||
else if (i + 1 < Players.Count)
|
||||
sb.Append(", ");
|
||||
else
|
||||
sb.Append(", and ");
|
||||
}
|
||||
|
||||
sb.Append(mob.Name);
|
||||
}
|
||||
|
||||
if (sb.Length == 0)
|
||||
return "Empty";
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(TourneyParticipant p)
|
||||
{
|
||||
return p.TotalLadderXP - TotalLadderXP;
|
||||
}
|
||||
|
||||
public void AddLog(string text)
|
||||
{
|
||||
Log.Add(text);
|
||||
}
|
||||
|
||||
public void AddLog(string format, params object[] args)
|
||||
{
|
||||
AddLog(string.Format(format, args));
|
||||
}
|
||||
|
||||
public void WonMatch(TourneyMatch match)
|
||||
{
|
||||
AddLog("Match won.");
|
||||
}
|
||||
|
||||
public void LostMatch(TourneyMatch match)
|
||||
{
|
||||
AddLog("Match lost.");
|
||||
}
|
||||
}
|
||||
}
|
||||
119
Projects/Scripts/Engines/ConPVP/Trophy.cs
Normal file
119
Projects/Scripts/Engines/ConPVP/Trophy.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public enum TrophyRank
|
||||
{
|
||||
Bronze,
|
||||
Silver,
|
||||
Gold
|
||||
}
|
||||
|
||||
[Flippable(5020, 4647)]
|
||||
public class Trophy : Item
|
||||
{
|
||||
private TrophyRank m_Rank;
|
||||
|
||||
[Constructible]
|
||||
public Trophy(string title, TrophyRank rank) : base(5020)
|
||||
{
|
||||
Title = title;
|
||||
m_Rank = rank;
|
||||
Date = DateTime.UtcNow;
|
||||
|
||||
LootType = LootType.Blessed;
|
||||
|
||||
UpdateStyle();
|
||||
}
|
||||
|
||||
public Trophy(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public string Title{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TrophyRank Rank
|
||||
{
|
||||
get => m_Rank;
|
||||
set
|
||||
{
|
||||
m_Rank = value;
|
||||
UpdateStyle();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile Owner{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime Date{ get; private set; }
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1); // version
|
||||
|
||||
writer.Write(Title);
|
||||
writer.Write((int)m_Rank);
|
||||
writer.Write(Owner);
|
||||
writer.Write(Date);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Title = reader.ReadString();
|
||||
m_Rank = (TrophyRank)reader.ReadInt();
|
||||
Owner = reader.ReadMobile();
|
||||
Date = reader.ReadDateTime();
|
||||
|
||||
if (version == 0)
|
||||
LootType = LootType.Blessed;
|
||||
}
|
||||
|
||||
public override void OnAdded(IEntity parent)
|
||||
{
|
||||
base.OnAdded(parent);
|
||||
|
||||
if (Owner == null)
|
||||
Owner = RootParent as Mobile;
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
base.OnSingleClick(from);
|
||||
|
||||
if (Owner != null)
|
||||
LabelTo(from, "{0} -- {1}", Title, Owner.RawName);
|
||||
else if (Title != null)
|
||||
LabelTo(from, Title);
|
||||
|
||||
if (Date != DateTime.MinValue)
|
||||
LabelTo(from, Date.ToString("d"));
|
||||
}
|
||||
|
||||
public void UpdateStyle()
|
||||
{
|
||||
Name = $"{m_Rank.ToString().ToLower()} trophy";
|
||||
|
||||
switch (m_Rank)
|
||||
{
|
||||
case TrophyRank.Gold:
|
||||
Hue = 2213;
|
||||
break;
|
||||
case TrophyRank.Silver:
|
||||
Hue = 0;
|
||||
break;
|
||||
case TrophyRank.Bronze:
|
||||
Hue = 2206;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue