647 lines
20 KiB
C#
647 lines
20 KiB
C#
using Server;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Server.Items;
|
|
using Server.Mobiles;
|
|
using Server.Engines.Points;
|
|
using System.Linq;
|
|
using Server.Commands;
|
|
using Server.Gumps;
|
|
|
|
//TODO: Party: 1152064 You cannot invite other players in an arena to your party!
|
|
namespace Server.Engines.ArenaSystem
|
|
{
|
|
public class PVPArenaSystem : PointsSystem
|
|
{
|
|
public static PVPArenaSystem Instance { get; set; }
|
|
public static bool Enabled { get { return Core.HS; } }
|
|
public static bool BlockSameIP { get { return true; } }
|
|
|
|
public override PointsType Loyalty { get { return PointsType.PVPArena; } }
|
|
public override TextDefinition Name { get { return m_Name; } }
|
|
public override bool AutoAdd { get { return true; } }
|
|
public override double MaxPoints { get { return double.MaxValue; } }
|
|
|
|
public override bool ShowOnLoyaltyGump { get { return false; } }
|
|
private TextDefinition m_Name = new TextDefinition("Arena Stats");
|
|
|
|
public static List<PVPArena> Arenas { get; set; }
|
|
public static List<string> BlockedArenas { get; set; }
|
|
|
|
public static bool SystemInitialized { get; set; }
|
|
|
|
public PVPArenaSystem()
|
|
{
|
|
Instance = this;
|
|
|
|
if (Enabled)
|
|
{
|
|
CommandSystem.Register("ResetArenaStats", AccessLevel.Administrator, ResetStats_OnTarget);
|
|
CommandSystem.Register("ArenaSetup", AccessLevel.Administrator, ArenaSetup);
|
|
}
|
|
}
|
|
|
|
public void OnTick()
|
|
{
|
|
Arenas.ForEach(a => a.OnTick());
|
|
}
|
|
|
|
public List<ArenaDuel> GetBookedDuels()
|
|
{
|
|
List<ArenaDuel> booked = new List<ArenaDuel>();
|
|
|
|
foreach (var arena in Arenas.Where(a => a.BookedDuels.Count > 0))
|
|
{
|
|
booked.AddRange(arena.BookedDuels);
|
|
}
|
|
|
|
return booked;
|
|
}
|
|
|
|
public ArenaDuel GetBookedDuel(PlayerMobile pm)
|
|
{
|
|
foreach (var arena in Arenas.Where(a => a.BookedDuels.Count > 0))
|
|
{
|
|
foreach (var duel in arena.BookedDuels.Where(d => d.IsParticipant(pm)))
|
|
{
|
|
return duel;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override void SendMessage(PlayerMobile from, double old, double points, bool quest)
|
|
{
|
|
}
|
|
|
|
public override TextDefinition GetTitle(PlayerMobile from)
|
|
{
|
|
return new TextDefinition("Arena Stats");
|
|
}
|
|
|
|
public override PointsEntry GetSystemEntry(PlayerMobile pm)
|
|
{
|
|
return new PlayerStatsEntry(pm);
|
|
}
|
|
|
|
public void Register(PVPArena arena)
|
|
{
|
|
if (Arenas == null)
|
|
Arenas = new List<PVPArena>();
|
|
|
|
if (!Arenas.Contains(arena))
|
|
Arenas.Add(arena);
|
|
}
|
|
|
|
public void Unregister(PVPArena arena)
|
|
{
|
|
if (Arenas != null)
|
|
{
|
|
Arenas.Remove(arena);
|
|
}
|
|
|
|
arena.Unregister();
|
|
}
|
|
|
|
public void AddBlockedArena(PVPArena arena)
|
|
{
|
|
if (BlockedArenas == null)
|
|
{
|
|
BlockedArenas = new List<string>();
|
|
}
|
|
|
|
if (!IsBlocked(arena.Definition))
|
|
{
|
|
Utility.WriteConsoleColor(ConsoleColor.Green, "Adding blocked EA PVP Arena: {0}", arena.Definition.Name);
|
|
BlockedArenas.Add(arena.Definition.Name);
|
|
Unregister(arena);
|
|
}
|
|
}
|
|
|
|
public void RemoveBlockedArena(ArenaDefinition def)
|
|
{
|
|
if (BlockedArenas == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BlockedArenas.Remove(def.Name);
|
|
|
|
if (Arenas == null || Arenas.Count == 0)
|
|
{
|
|
Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), () => Instance.OnTick());
|
|
}
|
|
|
|
var arena = new PVPArena(def);
|
|
Instance.Register(arena);
|
|
Utility.WriteConsoleColor(ConsoleColor.Green, "Removing blocked EA PVP Arena: {0}", arena.Definition.Name);
|
|
arena.ConfigureArena();
|
|
}
|
|
|
|
public bool IsBlocked(ArenaDefinition def)
|
|
{
|
|
return BlockedArenas != null && BlockedArenas.Contains(def.Name);
|
|
}
|
|
|
|
public static bool IsEnemy(Mobile source, Mobile target)
|
|
{
|
|
var sourceRegion = Region.Find(source.Location, source.Map) as ArenaRegion;
|
|
var targetRegion = Region.Find(target.Location, target.Map) as ArenaRegion;
|
|
|
|
if (sourceRegion != null && sourceRegion.Arena.CurrentDuel != null && sourceRegion == targetRegion)
|
|
{
|
|
return sourceRegion.Arena.CurrentDuel.IsEnemy(source, target);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static bool IsFriendly(Mobile source, Mobile target)
|
|
{
|
|
var sourceRegion = Region.Find(source.Location, source.Map) as ArenaRegion;
|
|
var targetRegion = Region.Find(target.Location, target.Map) as ArenaRegion;
|
|
|
|
if (sourceRegion != null && sourceRegion.Arena.CurrentDuel != null && sourceRegion == targetRegion)
|
|
{
|
|
return sourceRegion.Arena.CurrentDuel.IsFriendly(source, target);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override void Serialize(GenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
|
|
writer.Write(2);
|
|
|
|
writer.Write(BlockedArenas == null ? 0 : BlockedArenas.Count);
|
|
|
|
if (BlockedArenas != null)
|
|
{
|
|
for (int i = 0; i < BlockedArenas.Count; i++)
|
|
{
|
|
writer.Write(BlockedArenas[i]);
|
|
}
|
|
}
|
|
|
|
writer.Write(Arenas == null ? 0 : Arenas.Count);
|
|
|
|
if (Arenas != null)
|
|
{
|
|
for (int i = 0; i < Arenas.Count; i++)
|
|
{
|
|
writer.Write(Arenas[i].Definition.Name);
|
|
Arenas[i].Serialize(writer);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Deserialize(GenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
SystemInitialized = true;
|
|
|
|
int version = reader.ReadInt();
|
|
|
|
if (version < 2)
|
|
{
|
|
InitializeArenas();
|
|
}
|
|
|
|
switch (version)
|
|
{
|
|
case 2:
|
|
case 1:
|
|
int c = reader.ReadInt();
|
|
|
|
for (int i = 0; i < c; i++)
|
|
{
|
|
if (BlockedArenas == null)
|
|
BlockedArenas = new List<string>();
|
|
|
|
BlockedArenas.Add(reader.ReadString());
|
|
}
|
|
goto case 0;
|
|
case 0:
|
|
int count = reader.ReadInt();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
if (Arenas == null)
|
|
Arenas = new List<PVPArena>();
|
|
|
|
if (version >= 2)
|
|
{
|
|
var arena = new PVPArena(GetDefinition(reader.ReadString()));
|
|
Register(arena);
|
|
arena.Deserialize(reader);
|
|
}
|
|
else
|
|
{
|
|
Arenas[i].Deserialize(reader);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private ArenaDefinition GetDefinition(string name)
|
|
{
|
|
var def = ArenaDefinition.Definitions.FirstOrDefault(d => d.Name == name);
|
|
|
|
if (def == null)
|
|
{
|
|
return ArenaDefinition.Definitions[0];
|
|
}
|
|
|
|
return def;
|
|
}
|
|
|
|
public static void SendMessage(Mobile from, string message, int hue = 0x1F)
|
|
{
|
|
from.SendMessage(hue, message);
|
|
}
|
|
|
|
public static void SendMessage(Mobile from, int message, string args = "", int hue = 0x1F)
|
|
{
|
|
from.SendLocalizedMessage(message, args, hue);
|
|
}
|
|
|
|
public static void SendParticipantMessage(ArenaDuel duel, int message, bool inRegion = false, string args = "", int hue = 0x1F)
|
|
{
|
|
foreach (var part in duel.GetParticipants(inRegion))
|
|
{
|
|
SendMessage(part.Key, message, args, hue);
|
|
}
|
|
}
|
|
|
|
public void CheckTitle(PlayerMobile pm)
|
|
{
|
|
var entry = GetPlayerEntry<PlayerStatsEntry>(pm);
|
|
int title = 0;
|
|
|
|
switch (entry.TotalDuels)
|
|
{
|
|
case 1: title = 1152068 + (int)ArenaTitle.FledglingGladiator; break;
|
|
case 50: title = 1152068 + (int)ArenaTitle.BuddingGladiator; break;
|
|
case 100: title = 1152068 + (int)ArenaTitle.Gladiator; break;
|
|
case 250: title = 1152068 + (int)ArenaTitle.WellKnownGladiator; break;
|
|
case 500: title = 1152068 + (int)ArenaTitle.VeteranGladiator; break;
|
|
}
|
|
|
|
if (title > 0)
|
|
{
|
|
pm.AddRewardTitle(title);
|
|
pm.SendLocalizedMessage(1152067, String.Format("#{0}", title.ToString())); // You have gotten a new subtitle, ~1_VAL~, in reward for your duel!
|
|
}
|
|
}
|
|
|
|
public static bool HasSameIP(Mobile m, ArenaDuel duel)
|
|
{
|
|
if (duel == null || m.AccessLevel > AccessLevel.Player)
|
|
return false;
|
|
|
|
foreach (var kvp in duel.GetParticipants())
|
|
{
|
|
if (IsSameIP(m, kvp.Key))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static bool IsSameIP(Mobile one, Mobile two)
|
|
{
|
|
if (one.NetState == null || two.NetState == null || one.AccessLevel > AccessLevel.Player || two.AccessLevel > AccessLevel.Player)
|
|
return false;
|
|
|
|
var oneAddress = one.NetState.Address;
|
|
var twoAddress = two.NetState.Address;
|
|
|
|
return one.NetState.Address == two.NetState.Address;
|
|
}
|
|
|
|
public static void Initialize()
|
|
{
|
|
if (Enabled)
|
|
{
|
|
if (!SystemInitialized)
|
|
{
|
|
InitializeArenas();
|
|
SystemInitialized = true;
|
|
}
|
|
|
|
if (Arenas != null)
|
|
{
|
|
foreach (var arena in Arenas)
|
|
{
|
|
arena.ConfigureArena();
|
|
}
|
|
|
|
Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), () => Instance.OnTick());
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void InitializeArenas()
|
|
{
|
|
if (CanInitialize(ArenaDefinition.LostLandsTrammel))
|
|
{
|
|
Instance.Register(new PVPArena(ArenaDefinition.LostLandsTrammel));
|
|
}
|
|
|
|
if (CanInitialize(ArenaDefinition.LostLandsFelucca))
|
|
{
|
|
Instance.Register(new PVPArena(ArenaDefinition.LostLandsFelucca));
|
|
}
|
|
|
|
if (CanInitialize(ArenaDefinition.HavenTrammel))
|
|
{
|
|
Instance.Register(new PVPArena(ArenaDefinition.HavenTrammel));
|
|
}
|
|
|
|
if (CanInitialize(ArenaDefinition.HavenFelucca))
|
|
{
|
|
Instance.Register(new PVPArena(ArenaDefinition.HavenFelucca));
|
|
}
|
|
}
|
|
|
|
private static bool CanInitialize(ArenaDefinition def)
|
|
{
|
|
return !Instance.IsBlocked(def) && (Arenas == null || !Arenas.Any(arena => arena.Definition == def));
|
|
}
|
|
|
|
[Usage("ArenaSetup")]
|
|
[Description("Gives gump for arena setup.")]
|
|
public static void ArenaSetup(CommandEventArgs e)
|
|
{
|
|
var pm = e.Mobile as PlayerMobile;
|
|
|
|
if(pm != null)
|
|
{
|
|
BaseGump.SendGump(new PVPArenaSystemSetupGump(pm));
|
|
}
|
|
}
|
|
|
|
[Usage("ResetArenaStats")]
|
|
[Description("Target an arena stone to reset/wipe the stats associated with that arena.")]
|
|
public static void ResetStats_OnTarget(CommandEventArgs e)
|
|
{
|
|
Mobile m = e.Mobile;
|
|
|
|
m.BeginTarget(-1, false, Server.Targeting.TargetFlags.None, (fro, targeted) =>
|
|
{
|
|
if (m is PlayerMobile && targeted is ArenaStone)
|
|
{
|
|
var stone = (ArenaStone)targeted;
|
|
|
|
if (stone.Arena != null)
|
|
{
|
|
var arena = stone.Arena;
|
|
|
|
BaseGump.SendGump(new GenericConfirmCallbackGump<PVPArena>((PlayerMobile)m,
|
|
String.Format("Reset {0} Statistics?", arena.Definition.Name),
|
|
"By selecting yes, you will permanently wipe the stats associated to this arena.",
|
|
arena,
|
|
null,
|
|
(from, a) =>
|
|
{
|
|
ColUtility.Free(a.TeamRankings);
|
|
ColUtility.Free(a.SurvivalRankings);
|
|
from.SendMessage("Arena stats cleared.");
|
|
}));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public class PlayerStatsEntry : PointsEntry
|
|
{
|
|
public int SurvivalWins { get; set; }
|
|
public int SurvivalLosses { get; set; }
|
|
public int SurvivalDraws { get; set; }
|
|
|
|
public int TeamWins { get; set; }
|
|
public int TeamLosses { get; set; }
|
|
public int TeamDraws { get; set; }
|
|
|
|
public int Kills { get; set; }
|
|
public int Deaths { get; set; }
|
|
|
|
public bool IgnoreInvites { get; set; }
|
|
public bool OpenStats { get; set; }
|
|
|
|
public int TotalDuels { get { return SurvivalWins + SurvivalLosses + SurvivalDraws + TeamWins + TeamLosses + TeamDraws; } }
|
|
|
|
public List<DuelRecord> Record { get; set; }
|
|
|
|
public DuelProfile Profile { get; set; }
|
|
|
|
public PlayerStatsEntry(PlayerMobile pm)
|
|
: base(pm)
|
|
{
|
|
IgnoreInvites = true;
|
|
OpenStats = true;
|
|
|
|
Record = new List<DuelRecord>();
|
|
}
|
|
|
|
public void HandleDeath(Mobile m, bool killedBy)
|
|
{
|
|
Record.Add(new DuelRecord(m, killedBy));
|
|
|
|
if (Record.Count > 12)
|
|
{
|
|
Record.RemoveAt(12);
|
|
}
|
|
}
|
|
|
|
// Rating, seems to start at 10000, then +33 for win, -33 for loss
|
|
public override void Serialize(GenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
writer.Write(0);
|
|
|
|
if (Profile != null)
|
|
{
|
|
writer.Write(1);
|
|
Profile.Serialize(writer);
|
|
}
|
|
else
|
|
{
|
|
writer.Write(0);
|
|
}
|
|
|
|
writer.Write(Record.Count);
|
|
for (int i = 0; i < Record.Count; i++)
|
|
{
|
|
Record[i].Serialize(writer);
|
|
}
|
|
|
|
writer.Write(OpenStats);
|
|
writer.Write(IgnoreInvites);
|
|
|
|
writer.Write(SurvivalWins);
|
|
writer.Write(SurvivalLosses);
|
|
writer.Write(SurvivalDraws);
|
|
|
|
writer.Write(TeamWins);
|
|
writer.Write(TeamLosses);
|
|
writer.Write(TeamDraws);
|
|
|
|
writer.Write(Kills);
|
|
writer.Write(Deaths);
|
|
}
|
|
|
|
public override void Deserialize(GenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
int version = reader.ReadInt();
|
|
|
|
Record = new List<DuelRecord>();
|
|
|
|
if (reader.ReadInt() == 1)
|
|
{
|
|
Profile = new DuelProfile(reader);
|
|
}
|
|
|
|
int count = reader.ReadInt();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
Record.Add(new DuelRecord(reader));
|
|
}
|
|
|
|
OpenStats = reader.ReadBool();
|
|
IgnoreInvites = reader.ReadBool();
|
|
|
|
SurvivalWins = reader.ReadInt();
|
|
SurvivalLosses = reader.ReadInt();
|
|
SurvivalDraws = reader.ReadInt();
|
|
|
|
TeamWins = reader.ReadInt();
|
|
TeamLosses = reader.ReadInt();
|
|
TeamDraws = reader.ReadInt();
|
|
|
|
Kills = reader.ReadInt();
|
|
Deaths = reader.ReadInt();
|
|
}
|
|
|
|
public class DuelRecord
|
|
{
|
|
public Mobile Opponent { get; set; }
|
|
public bool KilledBy { get; set; }
|
|
public DateTime DuelDate { get; set; }
|
|
|
|
public DuelRecord(Mobile opponent, bool killedBy)
|
|
{
|
|
Opponent = opponent;
|
|
KilledBy = killedBy;
|
|
DuelDate = DateTime.Now;
|
|
}
|
|
|
|
public DuelRecord(GenericReader reader)
|
|
{
|
|
int version = reader.ReadInt();
|
|
|
|
Opponent = reader.ReadMobile();
|
|
KilledBy = reader.ReadBool();
|
|
DuelDate = reader.ReadDateTime();
|
|
}
|
|
|
|
public void Serialize(GenericWriter writer)
|
|
{
|
|
writer.Write(0);
|
|
|
|
writer.Write(Opponent);
|
|
writer.Write(KilledBy);
|
|
writer.Write(DuelDate);
|
|
}
|
|
}
|
|
|
|
public class DuelProfile
|
|
{
|
|
public int Entries { get; set; }
|
|
public RoomType RoomType { get; set; }
|
|
public BattleMode BattleMode { get; set; }
|
|
public bool Ranked { get; set; }
|
|
public TimeLimit TimeLimit { get; set; }
|
|
public EntryFee EntryFee { get; set; }
|
|
public int PetSlots { get; set; }
|
|
public bool RidingFlyingAllowed { get; set; }
|
|
public bool RangedWeaponsAllowed { get; set; }
|
|
public bool SummonSpellsAllowed { get; set; }
|
|
public bool FieldSpellsAllowed { get; set; }
|
|
public PotionRules PotionRules { get; set; }
|
|
|
|
public DuelProfile(ArenaDuel duel)
|
|
{
|
|
Entries = duel.Entries;
|
|
RoomType = duel.RoomType;
|
|
BattleMode = duel.BattleMode;
|
|
Ranked = duel.Ranked;
|
|
TimeLimit = duel.TimeLimit;
|
|
EntryFee = duel.EntryFee;
|
|
PetSlots = duel.PetSlots;
|
|
RidingFlyingAllowed = duel.RidingFlyingAllowed;
|
|
RangedWeaponsAllowed = duel.RangedWeaponsAllowed;
|
|
SummonSpellsAllowed = duel.SummonSpellsAllowed;
|
|
FieldSpellsAllowed = duel.FieldSpellsAllowed;
|
|
PotionRules = duel.PotionRules;
|
|
}
|
|
|
|
public DuelProfile(GenericReader reader)
|
|
{
|
|
int version = reader.ReadInt();
|
|
|
|
Entries = reader.ReadInt();
|
|
RoomType = (RoomType)reader.ReadInt();
|
|
BattleMode = (BattleMode)reader.ReadInt();
|
|
Ranked = reader.ReadBool();
|
|
TimeLimit = (TimeLimit)reader.ReadInt();
|
|
EntryFee = (EntryFee)reader.ReadInt();
|
|
PetSlots = reader.ReadInt();
|
|
RidingFlyingAllowed = reader.ReadBool();
|
|
RangedWeaponsAllowed = reader.ReadBool();
|
|
SummonSpellsAllowed = reader.ReadBool();
|
|
FieldSpellsAllowed = reader.ReadBool();
|
|
PotionRules = (PotionRules)reader.ReadInt();
|
|
}
|
|
|
|
public void Serialize(GenericWriter writer)
|
|
{
|
|
writer.Write(0);
|
|
|
|
writer.Write(Entries);
|
|
writer.Write((int)RoomType);
|
|
writer.Write((int)BattleMode);
|
|
writer.Write(Ranked);
|
|
writer.Write((int)TimeLimit);
|
|
writer.Write((int)EntryFee);
|
|
writer.Write(PetSlots);
|
|
writer.Write(RidingFlyingAllowed);
|
|
writer.Write(RangedWeaponsAllowed);
|
|
writer.Write(SummonSpellsAllowed);
|
|
writer.Write(FieldSpellsAllowed);
|
|
writer.Write((int)PotionRules);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace Server.Mobiles
|
|
{
|
|
public enum ArenaTitle
|
|
{
|
|
FledglingGladiator = 0,
|
|
BuddingGladiator = 1,
|
|
Gladiator = 3,
|
|
WellKnownGladiator = 4,
|
|
VeteranGladiator =5
|
|
}
|
|
}
|