Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

View File

@@ -0,0 +1,296 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using Server;
using Server.Accounting;
using Server.Engines.Help;
using Server.Misc;
using Server.Mobiles;
using VitaNex.IO;
using VitaNex.SuperGumps.UI;
using VitaNex.Text;
#endregion
namespace VitaNex.Modules.AntiAdverts
{
public static partial class AntiAdverts
{
public const AccessLevel Access = AccessLevel.Administrator;
public static AntiAdvertsOptions CMOptions { get; private set; }
public static FileInfo ReportsFile => IOUtility.EnsureFile(VitaNexCore.SavesDirectory + "/AntiAdverts/Reports.bin");
public static List<AntiAdvertsReport> Reports { get; private set; }
public static event Action<AntiAdvertNotifyGump> OnBeforeSendGump;
public static event Action<AntiAdvertNotifyGump> OnAfterSendGump;
private static void InvokeOnBeforeSendGump(AntiAdvertNotifyGump g)
{
if (OnBeforeSendGump != null)
{
OnBeforeSendGump(g);
}
}
private static void InvokeOnAfterSendGump(AntiAdvertNotifyGump g)
{
if (OnAfterSendGump != null)
{
OnAfterSendGump(g);
}
}
public static bool Detect(string text)
{
return Detect(text, out var keyword);
}
public static bool Detect(string text, out string keyword)
{
// Does the speech contain any forbidden key words?
foreach (var kw in CMOptions.KeyWords)
{
if (CMOptions.SearchMode.Execute(text, kw, CMOptions.SearchCapsIgnore))
{
keyword = kw;
return true;
}
if (!kw.Contains(' '))
{
continue;
}
foreach (var kwr in CMOptions.WhitespaceAliases.Select(wa => kw.Replace(' ', wa))
.Where(kwr => CMOptions.SearchMode.Execute(text, kwr, CMOptions.SearchCapsIgnore)))
{
keyword = kwr;
return true;
}
}
keyword = null;
return false;
}
private static void OnSpeech(SpeechEventArgs e)
{
if (e == null || !(e.Mobile is PlayerMobile) || e.Mobile.NetState == null || String.IsNullOrWhiteSpace(e.Speech) ||
e.Mobile.AccessLevel > CMOptions.HandleAccess)
{
return;
}
if (!Detect(e.Speech, out var detected))
{
return;
}
var banned = Ban(e.Mobile, e.Speech);
var jailed = Jail(e.Mobile, e.Speech);
ToConsole(e.Mobile, e.Speech, jailed, banned);
ToLog(e.Mobile, e.Speech, jailed, banned);
SendPage(e.Mobile, e.Speech, jailed, banned);
SendWarning(e.Mobile, e.Speech, jailed, banned);
if (CMOptions.Squelch)
{
e.Mobile.Squelched = true;
}
if (CMOptions.Kick)
{
e.Mobile.Say("I've been kicked!");
if (e.Mobile.NetState != null)
{
e.Mobile.NetState.Dispose();
}
}
Reports.Insert(
0,
new AntiAdvertsReport(
DateTime.Now,
e.Mobile,
GetDetectedString(false, e.Mobile, e.Speech, jailed, banned),
e.Speech,
jailed,
banned));
Reports.TrimEndTo(100);
}
private static string GetDetectedString(bool lines, Mobile m, string speech, bool jailed, bool banned)
{
if (m == null || m.Deleted || !m.Player || String.IsNullOrWhiteSpace(speech))
{
return String.Empty;
}
return String.Format(
lines
? "IP('{0}')\nAccount('{1}')\nChar('{2}')\nJail('{3}')\nBan('{4}')\nQuote(\"{5}\")"
: "IP('{0}') Account('{1}') Char('{2}') Jail('{3}') Ban('{4}') Quote(\"{5}\")",
m.NetState.Address,
m.Account.Username,
m.RawName,
jailed ? "yes" : "no",
banned ? "yes" : "no",
speech);
}
private static void ToConsole(Mobile m, string speech, bool jailed, bool banned)
{
if (m != null && !m.Deleted && m.Player && !String.IsNullOrWhiteSpace(speech) && CMOptions.ConsoleWrite)
{
Console.WriteLine("[Warning: Advertising Detected]: " + GetDetectedString(false, m, speech, jailed, banned));
}
}
private static void ToLog(Mobile m, string speech, bool jailed, bool banned)
{
if (m != null && !m.Deleted && !String.IsNullOrWhiteSpace(speech) && CMOptions.LogEnabled)
{
String.Format(
"[{0}]: {1}",
DateTime.Now.TimeOfDay.ToSimpleString("h:m"),
GetDetectedString(false, m, speech, jailed, banned))
.Log("DetectedAdvertisers.log");
}
}
private static void SendPage(Mobile m, string speech, bool jailed, bool banned)
{
if (m == null || m.Deleted || !m.Player || String.IsNullOrWhiteSpace(speech) || !CMOptions.PageStaff)
{
return;
}
var entry = PageQueue.GetEntry(m);
if (entry == null || !entry.Message.StartsWith("[Warning: Advertising Detected]"))
{
PageQueue.Enqueue(
new PageEntry(
m,
"[Warning: Advertising Detected]: " + GetDetectedString(true, m, speech, jailed, banned),
PageType.Account));
}
}
private static void SendWarning(Mobile m, string speech, bool jailed, bool banned)
{
if (m == null || m.Deleted || !m.Player || String.IsNullOrWhiteSpace(speech))
{
return;
}
string message;
if (CMOptions.NotifyStaff)
{
message = "[Warning: Advertising Detected]: " + GetDetectedString(true, m, speech, jailed, banned);
Notify.Notify.Broadcast<AntiAdvertNotifyGump>(
message,
false,
1.0,
3.0,
Color.OrangeRed,
InvokeOnBeforeSendGump,
InvokeOnAfterSendGump,
CMOptions.NotifyAccess);
}
if (!CMOptions.NotifyPlayer)
{
return;
}
var pm = m as PlayerMobile;
if (pm == null)
{
return;
}
message = String.Empty;
message += "A recent check shows that you may be trying to advertise on " + ServerList.ServerName + ".\n";
message += "Advertising is not allowed.\n";
if (jailed)
{
message += "You have been jailed until a member of staff can review your case.\n";
message += "If you are found to be innocent, you will be promptly released and free to adventure again.\n";
}
else
{
message += "A report has been submitted to the staff team for review.\n";
}
message += "\nOffending Speech:\n" + speech;
new NoticeDialogGump(pm)
{
Width = 420,
Height = 420,
CanMove = false,
CanDispose = false,
BlockSpeech = true,
RandomButtonID = true,
Title = jailed ? "Jailed! Why?" : "Advertising Reported",
Html = message
}.Send();
}
private static bool Jail(Mobile m, string speech)
{
return m != null && !m.Deleted && m.Player && !String.IsNullOrWhiteSpace(speech) && CMOptions.Jail &&
CMOptions.JailPoint.MoveToWorld(m);
}
private static bool Ban(Mobile m, string speech)
{
if (m == null || m.Deleted || !m.Player || String.IsNullOrWhiteSpace(speech) || !CMOptions.Ban)
{
return false;
}
var a = m.Account as Account;
if (a != null)
{
a.Banned = true;
a.SetBanTags(null, DateTime.UtcNow, TimeSpan.MaxValue);
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,77 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.AntiAdverts
{
[CoreModule("Anti Adverts", "1.0.0.2")]
public static partial class AntiAdverts
{
static AntiAdverts()
{
CMOptions = new AntiAdvertsOptions();
Reports = new List<AntiAdvertsReport>(100);
}
private static void CMConfig()
{
EventSink.Speech += OnSpeech;
}
private static void CMInvoke()
{
CommandUtility.Register("AntiAds", Access, e => new AntiAvertsReportsGump(e.Mobile).Send());
}
private static void CMEnabled()
{
EventSink.Speech += OnSpeech;
}
private static void CMDisabled()
{
EventSink.Speech -= OnSpeech;
}
private static void CMSave()
{
VitaNexCore.TryCatch(() => ReportsFile.Serialize(SerializeReports), CMOptions.ToConsole);
}
private static void CMLoad()
{
VitaNexCore.TryCatch(() => ReportsFile.Deserialize(DeserializeReports), CMOptions.ToConsole);
}
private static void CMDisposed()
{ }
private static void SerializeReports(GenericWriter writer)
{
writer.SetVersion(0);
writer.WriteBlockList(Reports, (w, r) => r.Serialize(w));
}
private static void DeserializeReports(GenericReader reader)
{
reader.GetVersion();
reader.ReadBlockList(r => new AntiAdvertsReport(r), Reports);
}
}
}

View File

@@ -0,0 +1,125 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AntiAdverts
{
public sealed class AntiAdvertsReport : IEquatable<AntiAdvertsReport>
{
public DateTime Date { get; private set; }
public Mobile Mobile { get; private set; }
public string Report { get; set; }
public string Speech { get; set; }
public bool Jailed { get; set; }
public bool Banned { get; set; }
public bool Viewed { get; set; }
public AntiAdvertsReport(
DateTime date,
Mobile m,
string report,
string speech,
bool jailed,
bool banned,
bool viewed = false)
{
Date = date;
Mobile = m;
Speech = speech;
Report = report;
Viewed = viewed;
Jailed = jailed;
Banned = banned;
}
public AntiAdvertsReport(GenericReader reader)
{
Deserialize(reader);
}
public override string ToString()
{
return String.Format(
"[{0}] {1}: {2}",
Date.ToSimpleString("t@h:m@ m-d"),
Mobile == null ? "-null-" : Mobile.RawName,
Report);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (Mobile != null ? Mobile.Serial.Value : 0);
hashCode = (hashCode * 397) ^ Date.GetHashCode();
hashCode = (hashCode * 397) ^ (Speech != null ? Speech.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Report != null ? Report.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ Jailed.GetHashCode();
hashCode = (hashCode * 397) ^ Banned.GetHashCode();
return hashCode;
}
}
public override bool Equals(object obj)
{
return obj is AntiAdvertsReport && Equals((AntiAdvertsReport)obj);
}
public bool Equals(AntiAdvertsReport other)
{
return !ReferenceEquals(other, null) && Mobile == other.Mobile && Date == other.Date && Jailed == other.Jailed &&
Banned == other.Banned && Speech == other.Speech && Report == other.Report;
}
public void Serialize(GenericWriter writer)
{
writer.SetVersion(0);
writer.Write(Date);
writer.Write(Mobile);
writer.Write(Speech);
writer.Write(Report);
writer.Write(Viewed);
writer.Write(Jailed);
writer.Write(Banned);
}
public void Deserialize(GenericReader reader)
{
reader.GetVersion();
Date = reader.ReadDateTime();
Mobile = reader.ReadMobile<PlayerMobile>();
Speech = reader.ReadString();
Report = reader.ReadString();
Viewed = reader.ReadBool();
Jailed = reader.ReadBool();
Banned = reader.ReadBool();
}
public static bool operator ==(AntiAdvertsReport l, AntiAdvertsReport r)
{
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
}
public static bool operator !=(AntiAdvertsReport l, AntiAdvertsReport r)
{
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
}
}
}

View File

@@ -0,0 +1,271 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections.Generic;
using Server;
using VitaNex.Text;
#endregion
namespace VitaNex.Modules.AntiAdverts
{
public sealed class AntiAdvertsOptions : CoreModuleOptions
{
/// <summary>
/// Log the info in a log file?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool LogEnabled { get; set; }
/// <summary>
/// Write info to the console?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool ConsoleWrite { get; set; }
/// <summary>
/// Page staff with offense?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool PageStaff { get; set; }
/// <summary>
/// Send a warning broadcast to staff?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool NotifyStaff { get; set; }
/// <summary>
/// Send a warning to offending player
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool NotifyPlayer { get; set; }
/// <summary>
/// Send a warning broadcast to staff of this access and above.
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public AccessLevel NotifyAccess { get; set; }
/// <summary>
/// AccessLevels higher than this value will not have their speech handled.
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public AccessLevel HandleAccess { get; set; }
/// <summary>
/// Jail the offender?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool Jail { get; set; }
/// <summary>
/// The location and map of the jail area.
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public MapPoint JailPoint { get; set; }
/// <summary>
/// Squelch the offender?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool Squelch { get; set; }
/// <summary>
/// Kick the offender?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool Kick { get; set; }
/// <summary>
/// Ban the offender?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool Ban { get; set; }
/// <summary>
/// The mode used to find matching key words in text.
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public StringSearchFlags SearchMode { get; set; }
/// <summary>
/// Should the search be case-insensitive?
/// </summary>
[CommandProperty(AntiAdverts.Access)]
public bool SearchCapsIgnore { get; set; }
/// <summary>
/// A list of common symbols used to replace whitespaces to avoid detection.
/// </summary>
public List<char> WhitespaceAliases { get; private set; }
/// <summary>
/// A case-insensitive list of all disallowed keywords and phrases.
/// Any whitespaces in keywords will also be tested with their aliases.
/// </summary>
public List<string> KeyWords { get; private set; }
public AntiAdvertsOptions()
: base(typeof(AntiAdverts))
{
WhitespaceAliases = new List<char>();
KeyWords = new List<string>();
EnsureDefaults();
}
public AntiAdvertsOptions(GenericReader reader)
: base(reader)
{ }
public void EnsureDefaults()
{
LogEnabled = true;
ConsoleWrite = true;
PageStaff = true;
NotifyStaff = true;
NotifyAccess = AccessLevel.Counselor;
HandleAccess = AccessLevel.Player;
Jail = false;
JailPoint = new MapPoint(Map.Felucca, new Point3D(5275, 1174, 0));
Squelch = false;
Kick = false;
Ban = false;
SearchMode = StringSearchFlags.Contains;
SearchCapsIgnore = true;
WhitespaceAliases.AddRange(
new[]
{
'_', ':', ';', '@', '#', '=', '-', '+', '*', '/', //
'\\', '!', '"', '<27>', '$', '%', '^', '&', '"' //
});
KeyWords.AddRange(
new[]
{
"port: 2593", "port 2593", "port: 2595", "port 2595", "paypal", "no-ip", "joinuo", "uoisnotdead", "shard.li",
"easyuo"
});
}
public override void Clear()
{
base.Clear();
EnsureDefaults();
}
public override void Reset()
{
base.Reset();
EnsureDefaults();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(2);
switch (version)
{
case 2:
writer.Write(NotifyPlayer);
goto case 1;
case 1:
{
writer.WriteFlag(SearchMode);
writer.Write(SearchCapsIgnore);
}
goto case 0;
case 0:
{
writer.WriteBlockList(WhitespaceAliases, (w, a) => w.Write(a));
writer.WriteBlockList(KeyWords, (w, k) => w.Write(k));
writer.Write(LogEnabled);
writer.Write(ConsoleWrite);
writer.Write(PageStaff);
writer.Write(NotifyStaff);
writer.WriteFlag(NotifyAccess);
writer.Write(Jail);
JailPoint.Serialize(writer);
writer.Write(Squelch);
writer.Write(Kick);
writer.Write(Ban);
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 2:
NotifyPlayer = reader.ReadBool();
goto case 1;
case 1:
{
SearchMode = reader.ReadFlag<StringSearchFlags>();
SearchCapsIgnore = reader.ReadBool();
}
goto case 0;
case 0:
{
if (version < 1)
{
SearchMode = StringSearchFlags.Contains;
SearchCapsIgnore = true;
}
WhitespaceAliases = reader.ReadBlockList(r => r.ReadChar());
KeyWords = reader.ReadBlockList(r => r.ReadString());
LogEnabled = reader.ReadBool();
ConsoleWrite = reader.ReadBool();
PageStaff = reader.ReadBool();
NotifyStaff = reader.ReadBool();
NotifyAccess = reader.ReadFlag<AccessLevel>();
Jail = reader.ReadBool();
JailPoint = new MapPoint(reader);
Squelch = reader.ReadBool();
Kick = reader.ReadBool();
Ban = reader.ReadBool();
}
break;
}
}
}
}

View File

@@ -0,0 +1,81 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Server;
using Server.Gumps;
using VitaNex.SuperGumps.UI;
#endregion
namespace VitaNex.Modules.AntiAdverts
{
public sealed class AntiAdvertsEditAliasesGump : GenericListGump<char>
{
public string Input { get; set; }
public AntiAdvertsEditAliasesGump(Mobile user, Gump parent = null)
: base(
user,
parent,
list: AntiAdverts.CMOptions.WhitespaceAliases,
title: "Anti-Adverts: Whitespace Aliases",
emptyText: "No whitespace aliases to display.",
canAdd: true,
canClear: true,
canRemove: true)
{ }
public override string GetSearchKeyFor(char key)
{
return key.ToString(CultureInfo.InvariantCulture);
}
protected override bool OnBeforeListAdd()
{
if (Input != null)
{
return true;
}
Send(
new InputDialogGump(
User,
Refresh(),
title: "Add Whitespace Alias",
html: "Write a single character to add it to this list.",
limit: 1,
callback: (b1, text) =>
{
Input = !String.IsNullOrWhiteSpace(text) ? text : String.Empty;
HandleAdd();
Input = null;
}));
return false;
}
public override List<char> GetExternalList()
{
return AntiAdverts.CMOptions.WhitespaceAliases;
}
public override char GetListAddObject()
{
return Input.FirstOrDefault();
}
}
}

View File

@@ -0,0 +1,78 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
using Server.Gumps;
using VitaNex.SuperGumps.UI;
#endregion
namespace VitaNex.Modules.AntiAdverts
{
public sealed class AntiAdvertsEditKeyWordsGump : GenericListGump<string>
{
public string Input { get; set; }
public AntiAdvertsEditKeyWordsGump(Mobile user, Gump parent = null)
: base(
user,
parent,
list: AntiAdverts.CMOptions.KeyWords,
title: "Anti-Adverts: Key Words",
emptyText: "No key words to display.",
canAdd: true,
canClear: true,
canRemove: true)
{ }
public override string GetSearchKeyFor(string key)
{
return key ?? String.Empty;
}
protected override bool OnBeforeListAdd()
{
if (Input != null)
{
return true;
}
Send(
new InputDialogGump(
User,
Refresh(),
title: "Add Key Word",
html: "Write a phrase to add it to this list.",
callback: (b1, text) =>
{
Input = !String.IsNullOrWhiteSpace(text) ? text : null;
HandleAdd();
Input = null;
}));
return false;
}
public override List<string> GetExternalList()
{
return AntiAdverts.CMOptions.KeyWords;
}
public override string GetListAddObject()
{
return Input;
}
}
}

View File

@@ -0,0 +1,33 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
using VitaNex.Notify;
#endregion
namespace VitaNex.Modules.AntiAdverts
{
public sealed class AntiAdvertNotifyGump : NotifyGump
{
private static void InitSettings(NotifySettings settings)
{
settings.CanIgnore = true;
settings.Access = AntiAdverts.Access;
settings.Desc = "Advertising Reports";
}
public AntiAdvertNotifyGump(Mobile user, string html)
: base(user, html)
{ }
}
}

View File

@@ -0,0 +1,165 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
using Server.Gumps;
using VitaNex.SuperGumps.UI;
#endregion
namespace VitaNex.Modules.AntiAdverts
{
public sealed class AntiAvertsReportsGump : ListGump<AntiAdvertsReport>
{
public AntiAvertsReportsGump(Mobile user)
: base(user)
{
Title = "Anti-Advert Reports";
EmptyText = "No reports to display.";
Sorted = true;
CanSearch = true;
CanMove = false;
}
protected override void CompileList(List<AntiAdvertsReport> list)
{
list.Clear();
list.AddRange(AntiAdverts.Reports);
base.CompileList(list);
}
protected override void CompileMenuOptions(MenuGumpOptions list)
{
list.AppendEntry(
new ListGumpEntry(
"Options",
() =>
{
Refresh();
User.SendGump(new PropertiesGump(User, AntiAdverts.CMOptions));
},
HighlightHue));
list.AppendEntry(
new ListGumpEntry("Key Words", () => new AntiAdvertsEditKeyWordsGump(User, this).Send(), HighlightHue));
list.AppendEntry(
new ListGumpEntry("Whitespace Aliases", () => new AntiAdvertsEditAliasesGump(User, this).Send(), HighlightHue));
list.AppendEntry(
new ListGumpEntry(
"Mark All: Viewed",
() =>
{
AntiAdverts.Reports.ForEach(t => t.Viewed = true);
User.SendMessage("All reports have been marked as viewed.");
Refresh(true);
},
TextHue));
list.AppendEntry(
new ListGumpEntry(
"Mark All: Not Viewed",
() =>
{
AntiAdverts.Reports.ForEach(t => t.Viewed = false);
User.SendMessage("All reports have been marked as not viewed.");
Refresh(true);
},
TextHue));
list.AppendEntry(
new ListGumpEntry(
"Delete All",
() =>
{
AntiAdverts.Reports.Free(true);
User.SendMessage("All reports have been deleted.");
Refresh(true);
},
ErrorHue));
list.AppendEntry(
new ListGumpEntry(
"Delete Old",
() =>
{
var expire = DateTime.Now - TimeSpan.FromDays(7);
AntiAdverts.Reports.RemoveAll(t => t.Date <= expire);
AntiAdverts.Reports.Free(false);
User.SendMessage("All old reports have been deleted.");
Refresh(true);
},
ErrorHue));
base.CompileMenuOptions(list);
}
protected override void SelectEntry(GumpButton button, AntiAdvertsReport entry)
{
base.SelectEntry(button, entry);
var opts = new MenuGumpOptions();
opts.AppendEntry(
new ListGumpEntry(
"View",
() =>
{
entry.Viewed = true;
new NoticeDialogGump(User, Refresh(true))
{
Title = "Anti-Advert Report",
Html = entry.ToString(),
Modal = false,
CanMove = false
}.Send();
},
HighlightHue));
opts.AppendEntry(
!entry.Viewed
? new ListGumpEntry("Mark Viewed", () => entry.Viewed = true)
: new ListGumpEntry("Mark Not Viewed", () => entry.Viewed = false));
opts.AppendEntry(new ListGumpEntry("Delete", () => AntiAdverts.Reports.Remove(entry), ErrorHue));
new MenuGump(User, Refresh(), opts, button).Send();
}
protected override int GetLabelHue(int index, int pageIndex, AntiAdvertsReport entry)
{
return entry != null ? entry == Selected ? HighlightHue : !entry.Viewed ? TextHue : ErrorHue : ErrorHue;
}
protected override string GetLabelText(int index, int pageIndex, AntiAdvertsReport entry)
{
return entry != null ? entry.ToString() : String.Empty;
}
public override string GetSearchKeyFor(AntiAdvertsReport key)
{
return key != null ? key.ToString() : String.Empty;
}
}
}

View File

@@ -0,0 +1,271 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
using Server.Commands;
using VitaNex.IO;
#endregion
namespace VitaNex.Modules.Games
{
[CoreModule("Games Arcade", "1.0.0.0")]
public static class Arcade
{
public const AccessLevel Access = AccessLevel.Administrator;
public static ArcadeOptions CMOptions { get; private set; }
public static BinaryDataStore<Type, IGame> Games { get; private set; }
public static BinaryDataStore<Mobile, ArcadeProfile> Profiles { get; private set; }
public static Type[] GameTypes { get; private set; }
static Arcade()
{
CMOptions = new ArcadeOptions();
Games = new BinaryDataStore<Type, IGame>(VitaNexCore.SavesDirectory + "/Arcade", "Games")
{
Async = true,
OnSerialize = SerializeGames,
OnDeserialize = DeserializeGames
};
Profiles = new BinaryDataStore<Mobile, ArcadeProfile>(VitaNexCore.SavesDirectory + "/Arcade", "Profiles")
{
Async = true,
OnSerialize = SerializeProfiles,
OnDeserialize = DeserializeProfiles
};
GameTypes = typeof(IGame).GetConstructableChildren();
foreach (var t in GameTypes)
{
var g = CreateGame(t);
if (g != null)
{
Games[t] = g;
}
}
}
private static void CMConfig()
{
CommandUtility.Register("Arcade", AccessLevel.Player, HandleCommand);
CommandUtility.RegisterAlias("Arcade", "Games");
}
private static void CMInvoke()
{ }
private static void CMSave()
{
Games.Export();
}
private static void CMLoad()
{
Games.Import();
}
private static void HandleCommand(CommandEventArgs e)
{
if (CMOptions.ModuleEnabled)
{
new ArcadeUI(e.Mobile).Send();
}
}
private static IGame CreateGame(Type t)
{
try
{
return t.CreateInstanceSafe<IGame>();
}
catch
{
return null;
}
}
public static ArcadeProfile EnsureProfile(Mobile m)
{
if (m == null)
{
return null;
}
var p = Profiles.GetValue(m);
if (p == null || p.Owner != m)
{
if (!m.Player || m.Deleted)
{
Profiles.Remove(m);
if (p != null)
{
p.Clear();
p = null;
}
}
else
{
Profiles[m] = p = new ArcadeProfile(m);
}
}
else if (!m.Player || m.Deleted)
{
Profiles.Remove(m);
p.Clear();
p = null;
}
return p;
}
public static bool OpenGame(Type t, Mobile m)
{
return VitaNexCore.TryCatchGet(
() =>
{
var g = Games.GetValue(t);
return g != null && g.Open(m);
},
CMOptions.ToConsole);
}
public static bool OpenGame<T>(Mobile m)
where T : IGame
{
return OpenGame(typeof(T), m);
}
public static void CloseGame(Mobile m, Type t)
{
VitaNexCore.TryCatch(
() =>
{
var g = Games.GetValue(t);
if (g != null)
{
g.Close(m);
}
},
CMOptions.ToConsole);
}
private static bool SerializeGames(GenericWriter writer)
{
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteBlockDictionary(
Games,
(w, t, g) =>
{
w.WriteType(t);
g.Serialize(w);
});
}
break;
}
return true;
}
private static bool DeserializeGames(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 0:
{
reader.ReadBlockDictionary(
r =>
{
var t = r.ReadType();
var g = Games.GetValue(t) ?? CreateGame(t);
g.Deserialize(r);
return new KeyValuePair<Type, IGame>(t, g);
},
Games);
}
break;
}
return true;
}
private static bool SerializeProfiles(GenericWriter writer)
{
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteBlockDictionary(
Profiles,
(w, m, p) =>
{
w.Write(m);
p.Serialize(w);
});
}
break;
}
return true;
}
private static bool DeserializeProfiles(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 0:
{
reader.ReadBlockDictionary(
r =>
{
var m = r.ReadMobile();
var p = new ArcadeProfile(r);
return new KeyValuePair<Mobile, ArcadeProfile>(m, p);
},
Profiles);
}
break;
}
return true;
}
}
}

View File

@@ -0,0 +1,57 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
#endregion
namespace VitaNex.Modules.Games
{
public sealed class TrapSweeper : Game<TrapSweeperEngine>
{
private readonly IconDefinition _Icon = IconDefinition.FromGump(24013, 1258);
public override IconDefinition Icon => _Icon;
public override string Name => "Trap Sweeper";
public override string Desc => "Sweep the castle for traps!";
public override string Help => _Help;
private static readonly string _Help = String.Concat(
"<BIG>Rules & Basics</BIG>",
"<BR>",
"<BR><BIG>Objective</BIG>",
"<BR>Find the empty tiles while avoiding the traps.",
"<BR>The faster you clear the floor, the better your score.",
"<BR>",
"<BR><BIG>Floors</BIG>",
"<BR>There are three floors to choose from, each more difficult than the last.",
"<BR>",
"<BR><B>* Rookie:</B> Easy mode, small floor.",
"<BR><B>* Guard:</B> Normal mode, medium floor.",
"<BR><B>* Knight:</B> Expert mode, large floor.",
"<BR><B>* Random:</B> Generates a random floor.",
"<BR>",
"<BR><BIG>Rules</BIG>",
"<BR>Reveal a trap, you die.",
"<BR>Reveal an empty tile, you continue sweeping.",
"<BR>Reveal a bonus tile, you continue and collect a reward when you win.",
"<BR>Reveal a number tile, you continue and it tells you how many traps lay hidden in the eight surrounding tiles.",
"<BR><I>These numbers will help you decide which tiles are safe to reveal.</I>",
"<BR>",
"<BR><BIG>Tips</BIG>",
"<BR>Mark the traps!",
"<BR>If you think a tile hides a trap, select Mark and click it, this will highlight the tile.",
"<BR>You can unhighlight a tile by selecting Mark and clicking it again.");
}
}

View File

@@ -0,0 +1,789 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Server;
#endregion
namespace VitaNex.Modules.Games
{
public class TrapSweeperEngine : GameEngine<TrapSweeper, TrapSweeperUI>
{
public const int MinWidth = 10;
public const int MaxWidth = 22;
public const int MinHeight = 10;
public const int MaxHeight = 15;
public const int MinDensity = 10;
public const int MaxDensity = 30;
public const int MinBonusDensity = 1;
public const int MaxBonusDensity = 3;
public const int MinPoints = 100;
public const int MaxPoints = 500;
private Grid<TrapSweeperTile> _Grid;
public int Width => _Grid != null ? _Grid.Width : 0;
public int Height => _Grid != null ? _Grid.Height : 0;
public int Capacity => _Grid != null ? _Grid.Capacity : 0;
public int Count => _Grid != null ? _Grid.Count : 0;
public TrapSweeperState State { get; private set; }
public TrapSweeperMode Mode { get; private set; }
public DateTime Started { get; private set; }
public DateTime Ended { get; private set; }
public bool Mark { get; private set; }
public int Blanks { get; private set; }
public int Traps { get; private set; }
public int Bonuses { get; private set; }
public int Visible { get; private set; }
public int Marked { get; private set; }
public int Rewards { get; private set; }
public TrapSweeperEngine(TrapSweeper game, Mobile user)
: base(game, user)
{
_Grid = new Grid<TrapSweeperTile>();
}
public override void Reset()
{
base.Reset();
Visible = 0;
Marked = 0;
Rewards = 0;
Mark = false;
}
public IEnumerable<TrapSweeperTile> AllTiles()
{
return _Grid ?? _Grid.Ensure();
}
public IEnumerable<TrapSweeperTile> FindTiles(int x, int y, int w, int h)
{
return _Grid == null ? _Grid.Ensure() : _Grid.FindCells(x, y, w, h);
}
public IEnumerable<T> AllTiles<T>()
where T : TrapSweeperTile
{
return (_Grid ?? _Grid.Ensure()).OfType<T>();
}
public IEnumerable<T> FindTiles<T>(int x, int y, int w, int h)
where T : TrapSweeperTile
{
return (_Grid == null ? _Grid.Ensure() : _Grid.FindCells(x, y, w, h)).OfType<T>();
}
public void Generate(int w, int h, int d, int b, int p)
{
if (!Validate())
{
Dispose();
return;
}
w = Math.Max(MinWidth, Math.Min(MaxWidth, w));
h = Math.Max(MinHeight, Math.Min(MaxHeight, h));
d = Math.Max(MinDensity, Math.Min(MaxDensity, d));
b = Math.Max(MinBonusDensity, Math.Min(MaxBonusDensity, b));
p = Math.Max(MinPoints, Math.Min(MaxPoints, p));
if (_Grid == null)
{
_Grid = new Grid<TrapSweeperTile>(w, h);
}
else if (_Grid.Width != w || _Grid.Height != h)
{
_Grid.Resize(w, h);
}
_Grid.SetAllContent((x, y) => null);
var q = new List<Point2D>(_Grid.Capacity);
_Grid.ForEach((x, y, t) => q.Add(new Point2D(x, y)));
q.Shuffle();
var traps = (int)Math.Floor(q.Count * (d / 100.0));
var bonus = (int)Math.Floor((q.Count - traps) * (b / 100.0));
Parallel.ForEach(
q,
t =>
{
if (traps > 0)
{
_Grid[t.X, t.Y] = new TrapSweeperTileTrap(this, t.X, t.Y);
Interlocked.Decrement(ref traps);
}
else if (bonus > 0)
{
_Grid[t.X, t.Y] = new TrapSweeperTileBonus(this, t.X, t.Y);
Interlocked.Decrement(ref bonus);
}
else
{
_Grid[t.X, t.Y] = new TrapSweeperTileBlank(this, t.X, t.Y);
}
});
q.Free(true);
Blanks = Traps = Bonuses = 0;
foreach (var t in AllTiles())
{
if (t is TrapSweeperTileBlank)
{
++Blanks;
t.Points = p;
}
else if (t is TrapSweeperTileTrap)
{
++Traps;
t.Points = 0;
}
else if (t is TrapSweeperTileBonus)
{
++Bonuses;
t.Points = p * 2;
}
}
Reset();
}
public void GenerateEasy()
{
if (!Validate())
{
Dispose();
return;
}
Generate(MinWidth, MinHeight, MinDensity, MinBonusDensity, MinPoints);
}
public void GenerateNormal()
{
if (!Validate())
{
Dispose();
return;
}
const int w = MinWidth + ((MaxWidth - MinWidth) / 2);
const int h = MinHeight + ((MaxHeight - MinHeight) / 2);
const int d = MinDensity + ((MaxDensity - MinDensity) / 2);
const int b = MinBonusDensity + ((MaxBonusDensity - MinBonusDensity) / 2);
const int p = MinPoints + ((MaxPoints - MinPoints) / 2);
Generate(w, h, d, b, p);
}
public void GenerateHard()
{
if (!Validate())
{
Dispose();
return;
}
Generate(MaxWidth, MaxHeight, MaxDensity, MaxBonusDensity, MaxPoints);
}
public void GenerateRandom()
{
if (!Validate())
{
Dispose();
return;
}
Generate(
Utility.RandomMinMax(MinWidth, MaxWidth),
Utility.RandomMinMax(MinHeight, MaxHeight),
Utility.RandomMinMax(MinDensity, MaxDensity),
Utility.RandomMinMax(MinBonusDensity, MaxBonusDensity),
Utility.RandomMinMax(MinPoints, MaxPoints));
}
public void DoCollect()
{
if (!Validate())
{
Dispose();
return;
}
// TODO: Give Rewards
DoMenu();
}
public void DoMenu()
{
if (!Validate())
{
Dispose();
return;
}
UI.CanDispose = true;
if (State == TrapSweeperState.Play)
{
State = TrapSweeperState.Menu;
DoEnd(false);
}
else
{
State = TrapSweeperState.Menu;
UI.Refresh(true);
}
}
public void DoMode(TrapSweeperMode opt)
{
if (!Validate())
{
Dispose();
return;
}
Mode = opt;
UI.Refresh(true);
}
public void DoMark()
{
if (!Validate())
{
Dispose();
return;
}
Mark = !Mark;
UI.Refresh(true);
}
public void DoPlay()
{
if (!Validate())
{
Dispose();
return;
}
UI.CanDispose = false;
switch (Mode)
{
case TrapSweeperMode.Easy:
GenerateEasy();
break;
case TrapSweeperMode.Normal:
GenerateNormal();
break;
case TrapSweeperMode.Hard:
GenerateHard();
break;
case TrapSweeperMode.Random:
GenerateRandom();
break;
}
DoStart();
}
public void DoQuit()
{
if (!Validate())
{
Dispose();
return;
}
UI.CanDispose = true;
if (State == TrapSweeperState.Play)
{
State = TrapSweeperState.Menu;
DoEnd(false);
}
else if (State != TrapSweeperState.Menu)
{
State = TrapSweeperState.Menu;
UI.Refresh(true);
}
else
{
State = TrapSweeperState.Menu;
UI.Close(true);
}
}
public void DoStart()
{
if (!Validate())
{
Dispose();
return;
}
UI.CanDispose = false;
State = TrapSweeperState.Play;
Started = DateTime.UtcNow;
UI.Refresh(true);
}
public void DoEnd(bool win)
{
if (!Validate())
{
Dispose();
return;
}
UI.CanDispose = true;
State = win ? TrapSweeperState.Win : TrapSweeperState.Lose;
Ended = DateTime.UtcNow;
if (win)
{
var factor = 1.0;
var time = Ended - Started;
if (time.TotalMinutes > 0)
{
double threshold, multiplier;
switch (Mode)
{
case TrapSweeperMode.Easy:
{
threshold = 10.0;
multiplier = 0.33;
}
break;
case TrapSweeperMode.Normal:
{
threshold = 10.0;
multiplier = 0.66;
}
break;
case TrapSweeperMode.Hard:
{
threshold = 10.0;
multiplier = 1.00;
}
break;
default:
{
threshold = Utility.RandomMinMax(10.0, 30.0);
multiplier = Utility.RandomMinMax(0.33, 1.00);
}
break;
}
if (time.TotalMinutes <= threshold)
{
factor += (1.0 - (time.TotalMinutes / threshold)) * multiplier;
}
}
OffsetPoints(Points * factor, true);
Log("Victories", 1, true);
}
else
{
OffsetPoints(-Points, true);
Log("Defeats", 1, true);
}
UI.Refresh(true);
}
protected override void OnDispose()
{
base.OnDispose();
if (_Grid != null)
{
_Grid.ForEach(
(x, y, t) =>
{
if (t != null)
{
t.Dispose();
}
});
_Grid.Free(true);
_Grid = null;
}
}
public abstract class TrapSweeperTile : IDisposable
{
public virtual int HiddenID => 9026;
public virtual int MarkID => 9026;
public virtual int ClickID => 9021;
public virtual int DisplayID => 9021;
public virtual int Hue => 0;
public bool IsDisposed { get; private set; }
public TrapSweeperEngine Engine { get; private set; }
public int X { get; private set; }
public int Y { get; private set; }
public int Points { get; set; }
private bool _Marked;
public bool Marked
{
get => _Marked;
set
{
if (!Validate())
{
Dispose();
return;
}
if (!_Marked && value)
{
if (Engine.Marked < Engine.Traps)
{
_Marked = true;
OnMarked();
}
}
else if (_Marked && !value)
{
_Marked = false;
OnUnmarked();
}
}
}
private bool _Visible;
public bool Visible
{
get => _Visible;
set
{
if (!Validate())
{
Dispose();
return;
}
if (!_Visible && value)
{
_Visible = true;
OnReveal();
}
else if (_Visible && !value)
{
_Visible = false;
OnHide();
}
}
}
public TrapSweeperTile(TrapSweeperEngine g, int x, int y)
{
Engine = g;
X = x;
Y = y;
}
~TrapSweeperTile()
{
Dispose();
}
public bool Validate()
{
return !IsDisposed && Engine != null && Engine.Validate();
}
public void Click()
{
if (!Validate())
{
Dispose();
return;
}
if (Engine.Mark)
{
ToggleMark();
}
else
{
ToggleVisibility();
}
Engine.UI.Refresh(true);
}
protected void ToggleMark()
{
if (!Validate())
{
Dispose();
return;
}
if (!Visible)
{
Marked = !Marked;
}
}
protected void ToggleVisibility()
{
if (!Validate())
{
Dispose();
return;
}
Marked = false;
Visible = !Visible;
}
public void Dispose()
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
OnDispose();
if (Engine != null)
{
if (Engine._Grid != null)
{
Engine._Grid[X, Y] = null;
}
Engine = null;
}
X = Y = -1;
}
protected virtual void OnHide()
{
--Engine.Visible;
Engine.OffsetPoints(-Points, true);
}
protected virtual void OnReveal()
{
++Engine.Visible;
Engine.OffsetPoints(Points, true);
}
protected virtual void OnMarked()
{
++Engine.Marked;
}
protected virtual void OnUnmarked()
{
--Engine.Marked;
}
protected virtual void OnDispose()
{
if (Engine == null || Engine.IsDisposed)
{
_Visible = _Marked = false;
return;
}
if (_Visible)
{
--Engine.Visible;
}
if (_Marked)
{
--Engine.Marked;
}
_Visible = _Marked = false;
}
}
public sealed class TrapSweeperTileBlank : TrapSweeperTile
{
private int _Traps = -1;
public int Traps
{
get
{
if (!Validate())
{
Dispose();
return 0;
}
if (_Traps < 0)
{
_Traps = Engine.FindTiles<TrapSweeperTileTrap>(X - 1, Y - 1, 3, 3).Count();
}
return _Traps;
}
}
public override int DisplayID => Traps > 0 ? 2225 + (Traps - 1) : 9021;
public TrapSweeperTileBlank(TrapSweeperEngine g, int x, int y)
: base(g, x, y)
{ }
protected override void OnReveal()
{
base.OnReveal();
if (Engine.AllTiles<TrapSweeperTileBlank>().All(t => t.Visible))
{
Engine.DoEnd(true);
return;
}
Engine.IncreasePoints(Points, true);
if (Traps > 0)
{
return;
}
var p = 0.0;
foreach (var t in Engine.FindTiles<TrapSweeperTileBlank>(X - 1, Y - 1, 3, 3).Where(t => t != this && !t.Visible))
{
t.Visible = true;
p += t.Points;
}
Engine.OffsetPoints(p, true);
}
}
public sealed class TrapSweeperTileTrap : TrapSweeperTile
{
public override int DisplayID => 9020;
public override int Hue => 34;
public TrapSweeperTileTrap(TrapSweeperEngine g, int x, int y)
: base(g, x, y)
{ }
/*protected override void OnMarked()
{
base.OnMarked();
if (!Engine.AllTiles<SweeperTileTrap>().All(t => t.Marked))
{
return;
}
Engine.Rewards += Engine.AllTiles<SweeperTileBonus>().Count(t => !t.Visible);
Engine.DoEnd(true);
}*/
protected override void OnReveal()
{
base.OnReveal();
Engine.DecreasePoints(Points, true);
Engine.DoEnd(false);
}
}
public sealed class TrapSweeperTileBonus : TrapSweeperTile
{
public override int DisplayID => 9027;
public override int Hue => 85;
public TrapSweeperTileBonus(TrapSweeperEngine g, int x, int y)
: base(g, x, y)
{ }
protected override void OnReveal()
{
base.OnReveal();
++Engine.Rewards;
}
protected override void OnHide()
{
base.OnHide();
--Engine.Rewards;
}
}
}
}

View File

@@ -0,0 +1,21 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
namespace VitaNex.Modules.Games
{
public enum TrapSweeperMode
{
Easy,
Normal,
Hard,
Random
}
}

View File

@@ -0,0 +1,21 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
namespace VitaNex.Modules.Games
{
public enum TrapSweeperState
{
Menu,
Play,
Win,
Lose
}
}

View File

@@ -0,0 +1,368 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Drawing;
using VitaNex.SuperGumps;
#endregion
namespace VitaNex.Modules.Games
{
public class TrapSweeperUI : GameUI<TrapSweeperEngine>
{
public TrapSweeperUI(TrapSweeperEngine engine)
: base(engine)
{
HighlightHue = 1258;
}
protected override void CompileLayout(SuperGumpLayout layout)
{
base.CompileLayout(layout);
if (Engine == null || Engine.IsDisposed)
{
return;
}
switch (Engine.State)
{
case TrapSweeperState.Menu:
CompileMenuLayout(layout);
break;
default:
CompilePlayLayout(layout);
break;
}
}
private void CompileMenuLayout(SuperGumpLayout layout)
{
layout.Add(
"window/menu/start",
() =>
{
AddImage(354, 256, 4501, HighlightHue);
AddButton(351, 254, 4501, 4501, b => Engine.DoPlay());
AddHtml(
140,
300,
435,
40,
"START SWEEPING!".WrapUOHtmlBold().WrapUOHtmlCenter().WrapUOHtmlColor(Color.Gold, false),
false,
false);
});
layout.Add(
"window/menu/option/easy",
() =>
{
var s = false;
// EASY
if (Engine.Mode != TrapSweeperMode.Easy)
{
AddImage(155, 330, 1417);
AddButton(164, 339, 5575, 5576, b => Engine.DoMode(TrapSweeperMode.Easy));
AddButton(145, 420, 5403, 5403, b => Engine.DoMode(TrapSweeperMode.Easy));
}
else
{
AddImage(155, 330, 1417, HighlightHue);
AddImage(164, 339, 5576);
s = true;
}
var text = "ROOKIE";
text = s ? text.WrapUOHtmlTag("U") : text;
text = text.WrapUOHtmlBig().WrapUOHtmlCenter().WrapUOHtmlColor(Color.Green, false);
AddBackground(145, 415, 100, 30, 9350);
AddHtml(145, 420, 100, 40, text, false, false);
});
layout.Add(
"window/menu/option/normal",
() =>
{
var s = false;
// NORMAL
if (Engine.Mode != TrapSweeperMode.Normal)
{
AddImage(262, 330, 1417);
AddButton(271, 339, 5587, 5588, b => Engine.DoMode(TrapSweeperMode.Normal));
AddButton(252, 420, 5403, 5403, b => Engine.DoMode(TrapSweeperMode.Normal));
}
else
{
AddImage(262, 330, 1417, HighlightHue);
AddImage(271, 339, 5588);
s = true;
}
var text = "GUARD";
text = s ? text.WrapUOHtmlTag("U") : text;
text = text.WrapUOHtmlBig().WrapUOHtmlCenter().WrapUOHtmlColor(Color.Yellow, false);
AddBackground(252, 415, 100, 30, 9350);
AddHtml(252, 420, 100, 40, text, false, false);
});
layout.Add(
"window/menu/option/hard",
() =>
{
var s = false;
// HARD
if (Engine.Mode != TrapSweeperMode.Hard)
{
AddImage(368, 330, 1417);
AddButton(377, 339, 5547, 5548, b => Engine.DoMode(TrapSweeperMode.Hard));
AddButton(358, 420, 5403, 5403, b => Engine.DoMode(TrapSweeperMode.Hard));
}
else
{
AddImage(368, 330, 1417, HighlightHue);
AddImage(377, 339, 5548);
s = true;
}
var text = "KNIGHT";
text = s ? text.WrapUOHtmlTag("U") : text;
text = text.WrapUOHtmlBig().WrapUOHtmlCenter().WrapUOHtmlColor(Color.Red, false);
AddBackground(358, 415, 100, 30, 9350);
AddHtml(358, 420, 100, 40, text, false, false);
});
layout.Add(
"window/menu/option/random",
() =>
{
var s = false;
// RANDOM
if (Engine.Mode != TrapSweeperMode.Random)
{
AddImage(475, 330, 1417);
AddButton(484, 339, 5583, 5584, b => Engine.DoMode(TrapSweeperMode.Random));
AddButton(465, 420, 5403, 5403, b => Engine.DoMode(TrapSweeperMode.Random));
}
else
{
AddImage(475, 330, 1417, HighlightHue);
AddImage(484, 339, 5584);
s = true;
}
var text = "RANDOM";
text = s ? text.WrapUOHtmlTag("U") : text;
text = text.WrapUOHtmlBig().WrapUOHtmlCenter().WrapUOHtmlColor(Color.Blue, false);
AddBackground(465, 415, 100, 30, 9350);
AddHtml(465, 420, 100, 40, text, false, false);
});
}
private void CompilePlayLayout(SuperGumpLayout layout)
{
layout.Add(
"window/play",
() =>
{
AddBackground(133, 100, 450, 350, 9200);
AddBackground(142, 130, 435, 315, 9300);
});
layout.Add(
"window/play/info",
() =>
{
if (Engine.State == TrapSweeperState.Lose)
{
AddImage(325, 55, 7034, 34);
AddImage(270, 32, 50562);
}
else
{
AddImage(325, 55, 7034);
}
AddImage(230, 60, 30082, HighlightHue);
AddImage(315, 45, 30061, HighlightHue);
AddImage(390, 60, 30080, HighlightHue);
});
layout.Add(
"window/play/info/traps",
() =>
{
AddImage(260, 50, 20999);
AddBackground(185, 50, 75, 44, 9300);
var count = Engine.Traps - Engine.Marked;
AddHtml(185, 65, 75, 40, count.ToString("#,0").WrapUOHtmlCenter(), false, false);
});
layout.Add(
"window/play/info/time",
() =>
{
AddImage(415, 50, 23000);
AddBackground(460, 50, 75, 44, 9300);
TimeSpan time;
switch (Engine.State)
{
case TrapSweeperState.Lose:
time = Engine.Ended - Engine.Started;
break;
default:
time = DateTime.UtcNow - Engine.Started;
break;
}
AddHtml(460, 65, 75, 40, time.ToSimpleString("h:m:s").WrapUOHtmlCenter(), false, false);
});
layout.Add(
"window/play/game/grid",
() =>
{
var w = Engine.Width * 19;
var h = Engine.Height * 20;
var xo = 148 + ((418 - w) / 2);
var yo = 137 + ((300 - h) / 2);
foreach (var t in Engine.AllTiles())
{
if (t == null)
{
return;
}
if (Engine.State == TrapSweeperState.Play && !t.Visible)
{
AddButton(xo + (t.X * 19), yo + (t.Y * 20), t.Marked ? t.MarkID : t.HiddenID, t.ClickID, b => t.Click());
}
else
{
AddImage(xo + (t.X * 19), yo + (t.Y * 20), t.DisplayID, t.Hue);
}
AddImage(xo + (t.X * 19), yo + (t.Y * 20), 9028, t.Marked ? HighlightHue : 0);
}
});
switch (Engine.State)
{
case TrapSweeperState.Play:
{
layout.Add(
"window/play/mark",
() =>
{
var text = "MARK";
text = text.WrapUOHtmlBold().WrapUOHtmlCenter().WrapUOHtmlColor(Color.PaleGoldenrod, false);
AddHtml(45, 355, 80, 40, text, false, false);
AddButton(50, 380, 7031, 7031, b => Engine.DoMark());
if (Engine.Mark)
{
AddImage(50, 380, 7031, HighlightHue);
}
});
}
break;
case TrapSweeperState.Win:
{
layout.Add("window/play/results", () => AddAlphaRegion(142, 130, 435, 315));
layout.Add(
"window/play/collect",
() =>
{
var text = "COLLECT";
text = text.WrapUOHtmlBold().WrapUOHtmlCenter().WrapUOHtmlColor(Color.LawnGreen, false);
AddHtml(45, 355, 80, 40, text, false, false);
AddButton(50, 380, 7012, 7012, b => Engine.DoCollect());
AddImage(50, 380, 7012, 85);
});
}
break;
case TrapSweeperState.Lose:
{
layout.Add(
"window/play/menu",
() =>
{
var text = "RESURRECT";
text = text.WrapUOHtmlBold().WrapUOHtmlCenter().WrapUOHtmlColor(Color.Orange, false);
AddHtml(45, 355, 80, 40, text, false, false);
AddButton(50, 380, 7007, 7007, b => Engine.DoMenu());
AddImage(50, 380, 7007, HighlightHue);
});
layout.Add(
"window/play/blood",
() =>
{
AddItem(65, 73, 7572);
AddItem(273, 59, 7574);
AddItem(348, 58, 4655);
AddItem(599, 37, 7573);
AddItem(585, 310, 4652);
AddItem(603, 327, 4653);
AddItem(594, 450, 4650);
});
}
break;
}
}
protected override void OnQuit()
{
base.OnQuit();
if (Engine.State == TrapSweeperState.Win)
{
Engine.DoCollect();
}
else
{
Engine.DoQuit();
}
}
}
}

View File

@@ -0,0 +1,178 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Drawing;
using System.Text;
using VitaNex.SuperGumps;
#endregion
namespace VitaNex.Modules.Games
{
public abstract class GameUI<TEngine> : SuperGump, IGameUI
where TEngine : class, IGameEngine
{
public bool IsDisposing { get; private set; }
public TEngine Engine { get; private set; }
public GameUI(TEngine engine)
: base(engine.User)
{
Engine = engine;
RandomButtonID = true;
ForceRecompile = true;
}
public bool Validate()
{
return !IsDisposed && !IsDisposing && Engine != null && !Engine.IsDisposed && User != null && !User.Deleted;
}
protected override void OnDispose()
{
if (IsDisposed || IsDisposing)
{
return;
}
IsDisposing = true;
base.OnDispose();
}
protected override void OnDisposed()
{
base.OnDisposed();
IsDisposing = false;
}
protected override void OnClosed(bool all)
{
base.OnClosed(all);
if (!all)
{
OnQuit();
}
else
{
Engine.Dispose();
}
}
protected override void CompileLayout(SuperGumpLayout layout)
{
base.CompileLayout(layout);
layout.Add(
"window",
() =>
{
AddBackground(0, 0, 650, 490, 2620);
AddImage(5, 5, 9001);
AddImage(5, 5, 9002, 901);
});
layout.Add(
"window/title",
() =>
{
var title = GetTitle();
AddImage(10, 10, 2440, 901);
AddHtml(10, 12, 166, 40, title, false, false);
});
layout.Add(
"window/score",
() =>
{
var points = GetPoints();
AddImage(180, 10, 2440, 901);
AddHtml(180, 12, 166, 40, points, false, false);
});
layout.Add("window/quit", () => { AddButton(560, 5, 5514, 5515, Close); });
}
protected virtual void OnQuit()
{ }
public virtual string GetPoints()
{
if (Engine == null)
{
return String.Empty;
}
var p = String.Format("Points: {0:#,0.##}", Engine.Points);
var t = new StringBuilder();
var c1 = Color.Gold;
var c2 = Color.PaleGoldenrod;
for (var i = 0; i < p.Length; i++)
{
if (!Char.IsWhiteSpace(p, i))
{
t.Append(p[i].ToString().WrapUOHtmlColor(c1.Interpolate(c2, i / (p.Length - 1.0)), false));
}
else
{
t.Append(p[i]);
}
}
return t.ToString().WrapUOHtmlBig().WrapUOHtmlCenter();
}
public virtual string GetTitle()
{
if (Engine == null || Engine.Game == null)
{
return String.Empty;
}
var n = Engine.Game.Name.Trim();
var t = new StringBuilder();
var c1 = Color.Gold;
var c2 = Color.PaleGoldenrod;
for (var i = 0; i < n.Length; i++)
{
if (!Char.IsWhiteSpace(n, i))
{
t.Append(n[i].ToString().WrapUOHtmlColor(c1.Interpolate(c2, i / (n.Length - 1.0)), false));
}
else
{
t.Append(n[i]);
}
}
return t.ToString().WrapUOHtmlBig().WrapUOHtmlCenter();
}
#region Explicit Impl
IGameEngine IGameUI.Engine => Engine;
#endregion
}
}

View File

@@ -0,0 +1,56 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.Games
{
public interface IGame
{
Type EngineType { get; }
IconDefinition Icon { get; }
string Name { get; }
string Desc { get; }
string Help { get; }
bool Enabled { get; set; }
IEnumerable<IGameEngine> Sessions { get; }
int SessionCount { get; }
IGameEngine this[Mobile user] { get; set; }
GameStatistics Statistics { get; }
void Enable();
void Disable();
bool Validate(Mobile user);
bool Open(Mobile user);
void Close(Mobile user);
void Reset(Mobile user);
void Log(string context, double value, bool offset);
void LogIncrease(string context, double value);
void LogDecrease(string context, double value);
void Serialize(GenericWriter writer);
void Deserialize(GenericReader reader);
}
}

View File

@@ -0,0 +1,57 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Modules.Games
{
public interface IGameEngine : IDisposable
{
Type UIType { get; }
bool IsDisposed { get; }
bool IsDisposing { get; }
Mobile User { get; }
IGame Game { get; }
IGameUI UI { get; }
ArcadeProfile Profile { get; }
GameStatistics Statistics { get; }
double Points { get; }
bool Validate();
bool Open();
void Close();
void Reset();
void LogStatistics();
void Log(string context, double value, bool offset);
void LogIncrease(string context, double value);
void LogDecrease(string context, double value);
void OffsetPoints(double value, bool log);
void IncreasePoints(double value, bool log);
void DecreasePoints(double value, bool log);
void Serialize(GenericWriter writer);
void Deserialize(GenericReader reader);
}
}

View File

@@ -0,0 +1,31 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Modules.Games
{
public interface IGameUI : IDisposable
{
bool IsDisposed { get; }
bool IsDisposing { get; }
IGameEngine Engine { get; }
Mobile User { get; }
bool Validate();
}
}

View File

@@ -0,0 +1,162 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.Games
{
public sealed class ArcadeProfile : PropertyObject, IEnumerable<KeyValuePair<string, GameStatistics>>
{
private Dictionary<string, GameStatistics> _Statistics = new Dictionary<string, GameStatistics>();
public GameStatistics this[string key]
{
get => _Statistics.GetValue(key) ?? (_Statistics[key] = new GameStatistics());
set => _Statistics[key] = value;
}
public Dictionary<string, GameStatistics>.KeyCollection Categories => _Statistics.Keys;
public Mobile Owner { get; private set; }
public int Credits { get; set; }
public ArcadeProfile(Mobile owner)
{
Owner = owner;
}
public ArcadeProfile(GenericReader reader)
: base(reader)
{ }
public override void Clear()
{
foreach (var v in _Statistics.Values)
{
v.Clear();
}
_Statistics.Clear();
}
public override void Reset()
{
foreach (var v in _Statistics.Values)
{
v.Reset();
}
}
public void Log(IGame g, string context, double value, bool offset)
{
if (offset)
{
if (value > 0)
{
LogIncrease(g, context, value);
}
else if (value < 0)
{
LogDecrease(g, context, value);
}
}
else
{
this[g.Name][context] = value;
}
}
public void LogIncrease(IGame g, string context, double value)
{
value = Math.Abs(value);
this[g.Name][context] += value;
}
public void LogDecrease(IGame g, string context, double value)
{
value = Math.Abs(value);
this[g.Name][context] -= value;
}
public IEnumerator<KeyValuePair<string, GameStatistics>> GetEnumerator()
{
return _Statistics.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
writer.Write(Owner);
switch (version)
{
case 0:
{
writer.Write(Credits);
writer.WriteBlockDictionary(
_Statistics,
(w, k, v) =>
{
w.Write(k);
v.Serialize(w);
});
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
Owner = reader.ReadMobile();
switch (version)
{
case 0:
{
Credits = reader.ReadInt();
_Statistics = reader.ReadBlockDictionary(
r =>
{
var k = r.ReadString();
var v = new GameStatistics(r);
return new KeyValuePair<string, GameStatistics>(k, v);
},
_Statistics);
}
break;
}
}
}
}

View File

@@ -0,0 +1,343 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.Games
{
public abstract class Game<TEngine> : IGame, IEnumerable<TEngine>
where TEngine : class, IGameEngine
{
private readonly Type _EngineType = typeof(TEngine);
[CommandProperty(Arcade.Access)]
public Type EngineType => _EngineType;
[CommandProperty(Arcade.Access)]
public abstract IconDefinition Icon { get; }
[CommandProperty(Arcade.Access)]
public abstract string Name { get; }
[CommandProperty(Arcade.Access)]
public abstract string Desc { get; }
[CommandProperty(Arcade.Access)]
public abstract string Help { get; }
private bool _Enabled;
[CommandProperty(Arcade.Access)]
public bool Enabled
{
get => _Enabled;
set
{
if (_Enabled && !value)
{
_Enabled = false;
OnDisabled();
Flush();
}
else if (!_Enabled && value)
{
_Enabled = true;
OnEnabled();
}
}
}
private List<TEngine> _Sessions;
public IEnumerable<TEngine> Sessions
{
get
{
var c = _Sessions.Count;
while (--c >= 0)
{
if (!_Sessions.InBounds(c))
{
continue;
}
var e = _Sessions[c];
if (e != null && !e.IsDisposed && !e.IsDisposing)
{
yield return e;
}
}
}
}
[CommandProperty(Arcade.Access)]
public int SessionCount => _Sessions.Count;
public TEngine this[Mobile user]
{
get => _Sessions.Find(e => e != null && e.User == user);
private set
{
if (user == null)
{
return;
}
var e = this[user];
if (value != null)
{
if (e == value)
{
return;
}
if (e != null)
{
e.Dispose();
_Sessions.Remove(e);
}
_Sessions.Update(value);
}
else if (e != null)
{
e.Dispose();
_Sessions.Remove(e);
}
}
}
[CommandProperty(Arcade.Access)]
public GameStatistics Statistics { get; private set; }
public Game()
{
_Sessions = new List<TEngine>();
Statistics = new GameStatistics();
}
public void Flush()
{
foreach (var e in Sessions)
{
e.Dispose();
}
_Sessions.Clear();
}
public void Enable()
{
Enabled = true;
}
public void Disable()
{
Enabled = false;
}
protected virtual void OnEnabled()
{ }
protected virtual void OnDisabled()
{ }
protected TEngine EnsureSession(Mobile user)
{
if (user == null)
{
return null;
}
var e = this[user];
if (e == null || !e.IsDisposing || e.IsDisposed)
{
if (user.Deleted || !user.IsOnline())
{
return null;
}
this[user] = e = EngineType.CreateInstanceSafe<TEngine>(this, user);
}
else if (user.Deleted || !user.IsOnline())
{
this[user] = null;
}
return e;
}
public bool Validate(Mobile user)
{
var e = EnsureSession(user);
return e != null && e.Validate();
}
public bool Open(Mobile user)
{
var e = EnsureSession(user);
if (e == null)
{
return false;
}
if (!e.Open() || !e.Validate())
{
e.Dispose();
return false;
}
return true;
}
public void Close(Mobile user)
{
this[user] = null;
}
public void Reset(Mobile user)
{
var e = EnsureSession(user);
if (e != null && e.Validate())
{
e.Reset();
}
}
public void Log(string context, double value, bool offset)
{
if (offset)
{
if (value > 0)
{
LogIncrease(context, value);
}
else if (value < 0)
{
LogDecrease(context, value);
}
}
else
{
Statistics[context] = value;
}
}
public void LogIncrease(string context, double value)
{
value = Math.Abs(value);
Statistics[context] += value;
}
public void LogDecrease(string context, double value)
{
value = Math.Abs(value);
Statistics[context] -= value;
}
public IEnumerator<TEngine> GetEnumerator()
{
return _Sessions.GetEnumerator();
}
public virtual void Serialize(GenericWriter writer)
{
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.Write(_Enabled);
Statistics.Serialize(writer);
writer.WriteBlockList(
_Sessions,
(w, e) =>
{
w.Write(e.User);
e.Serialize(w);
});
}
break;
}
}
public virtual void Deserialize(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 0:
{
_Enabled = reader.ReadBool();
Statistics.Deserialize(reader);
_Sessions = reader.ReadBlockList(
r =>
{
var e = EnsureSession(r.ReadMobile());
e.Deserialize(r);
return e;
},
_Sessions);
}
break;
}
}
#region Explicit Impl
IEnumerable<IGameEngine> IGame.Sessions => Sessions;
IGameEngine IGame.this[Mobile user]
{
get => this[user];
set
{
if (value == null || value is TEngine)
{
this[user] = (TEngine)value;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}

View File

@@ -0,0 +1,302 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using VitaNex.SuperGumps;
#endregion
namespace VitaNex.Modules.Games
{
public abstract class GameEngine<TGame, TGump> : IGameEngine
where TGame : class, IGame
where TGump : SuperGump, IGameUI
{
private readonly Type _UIType = typeof(TGump);
public Type UIType => _UIType;
public bool IsDisposing { get; private set; }
public bool IsDisposed { get; private set; }
public Mobile User { get; private set; }
public TGame Game { get; private set; }
public TGump UI { get; private set; }
public ArcadeProfile Profile => Arcade.EnsureProfile(User);
public GameStatistics Statistics { get; private set; }
public double PointsTotal
{
get => Statistics["Points Total"];
private set => Statistics["Points Total"] = value;
}
public double PointsGained
{
get => Statistics["Points Gained"];
private set => Statistics["Points Gained"] = value;
}
public double PointsLost
{
get => Statistics["Points Lost"];
private set => Statistics["Points Lost"] = value;
}
public double Points { get; private set; }
public GameEngine(TGame game, Mobile user)
{
Game = game;
User = user;
Statistics = new GameStatistics();
}
~GameEngine()
{
Dispose();
}
protected bool EnsureUI()
{
if (IsDisposed || IsDisposing)
{
return false;
}
if (User == null || User.Deleted)
{
if (UI != null)
{
UI.Close(true);
UI = null;
}
return false;
}
if (UI != null && UI.User != User)
{
UI.Close(true);
UI = null;
}
if (UI == null || UI.IsDisposed || UI.IsDisposing)
{
UI = UIType.CreateInstanceSafe<TGump>(this);
}
return UI != null && UI.Validate();
}
public bool Validate()
{
return !IsDisposed && !IsDisposing && UI != null && UI.Validate();
}
public virtual bool Open()
{
if (!EnsureUI() || !Validate())
{
Dispose();
return false;
}
UI.Refresh(true);
return true;
}
public virtual void Close()
{
if (UI != null && !UI.IsDisposed)
{
UI.Close(true);
}
}
public virtual void Reset()
{
Points = 0;
Statistics.Reset();
}
public void LogStatistics()
{
var p = Profile;
foreach (var kv in Statistics)
{
Game.Log(kv.Key, kv.Value, true);
if (p != null)
{
p.Log(Game, kv.Key, kv.Value, true);
}
}
Statistics.Reset();
}
public void Log(string context, double value, bool offset)
{
if (offset)
{
if (value > 0)
{
LogIncrease(context, value);
}
else if (value < 0)
{
LogDecrease(context, value);
}
}
else
{
Statistics[context] = value;
}
}
public void LogIncrease(string context, double value)
{
value = Math.Abs(value);
Statistics[context] += value;
}
public void LogDecrease(string context, double value)
{
value = Math.Abs(value);
Statistics[context] -= value;
}
public void OffsetPoints(double value, bool log)
{
if (value > 0)
{
IncreasePoints(value, log);
}
else if (value < 0)
{
DecreasePoints(value, log);
}
}
public void IncreasePoints(double value, bool log)
{
value = Math.Abs(value);
Points += value;
PointsTotal += value;
if (log)
{
PointsGained += value;
}
}
public void DecreasePoints(double value, bool log)
{
value = Math.Abs(value);
Points -= value;
PointsTotal -= value;
if (log)
{
PointsLost += value;
}
}
public void Dispose()
{
if (IsDisposed || IsDisposing)
{
return;
}
IsDisposing = true;
LogStatistics();
Close();
if (UI == null)
{
return;
}
if (UI.IsOpen || UI.Hidden)
{
UI.Close(true);
}
UI = null;
OnDispose();
if (Game != null && User != null)
{
Game[User] = null;
}
Statistics.Clear();
Statistics = null;
Game = null;
User = null;
IsDisposed = true;
OnDisposed();
IsDisposing = false;
}
protected virtual void OnDispose()
{ }
protected virtual void OnDisposed()
{ }
public virtual void Serialize(GenericWriter writer)
{
writer.SetVersion(0);
writer.Write(Points);
Statistics.Serialize(writer);
}
public virtual void Deserialize(GenericReader reader)
{
reader.GetVersion();
Points = reader.ReadDouble();
Statistics.Deserialize(reader);
}
#region Explicit Impl
IGame IGameEngine.Game => Game;
IGameUI IGameEngine.UI => UI;
#endregion
}
}

View File

@@ -0,0 +1,94 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.Games
{
public sealed class GameStatistics : PropertyObject, IEnumerable<KeyValuePair<string, double>>
{
private readonly Dictionary<string, double> _Statistics = new Dictionary<string, double>();
public double this[string key] { get => _Statistics.GetValue(key); set => _Statistics[key] = value; }
public Dictionary<string, double>.KeyCollection Entries => _Statistics.Keys;
public GameStatistics()
{ }
public GameStatistics(GenericReader reader)
: base(reader)
{ }
public override void Clear()
{
_Statistics.Clear();
}
public override void Reset()
{
_Statistics.Keys.ForEach(k => _Statistics[k] = 0);
}
public bool Remove(string key)
{
return key != null && _Statistics.Remove(key);
}
public IEnumerator<KeyValuePair<string, double>> GetEnumerator()
{
return _Statistics.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.WriteDictionary(
_Statistics,
(w, k, v) =>
{
w.Write(k);
w.Write(v);
});
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
reader.ReadDictionary(
r =>
{
var k = r.ReadString();
var v = r.ReadDouble();
return new KeyValuePair<string, double>(k, v);
},
_Statistics);
}
}
}

View File

@@ -0,0 +1,50 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.Games
{
public sealed class ArcadeOptions : CoreModuleOptions
{
public ArcadeOptions()
: base(typeof(Arcade))
{ }
/*
public override void Clear()
{
base.Clear();
}
public override void Reset()
{
base.Reset();
}
*/
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

View File

@@ -0,0 +1,493 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using Server;
using Server.Gumps;
using VitaNex.SuperGumps;
using VitaNex.SuperGumps.UI;
#endregion
namespace VitaNex.Modules.Games
{
public sealed class ArcadeUI : SuperGumpList<IGame>
{
public ArcadeProfile Profile { get; private set; }
public int Width { get; set; }
public int Height { get; set; }
public int Margin { get; set; }
public int Padding { get; set; }
public int MenuSize { get; set; }
public int IconSize { get; set; }
public int Rows { get; private set; }
public int Cols { get; private set; }
public IGame SelectedGame { get; private set; }
public ArcadeUI(Mobile user)
: base(user)
{
Profile = Arcade.EnsureProfile(User);
Sorted = true;
EnsureDefaults();
}
public void EnsureDefaults()
{
Width = 800;
Height = 600;
Margin = 30;
Padding = 15;
MenuSize = 250;
IconSize = 120;
InvalidateGrid();
}
public void InvalidateGrid()
{
Width = Math.Max(300, Math.Min(1024, Width));
Height = Math.Max(300, Math.Min(768, Height));
MenuSize = Math.Max(200, Math.Min(400, MenuSize));
IconSize = Math.Max(100, Math.Min(250, IconSize));
Rows = (int)Math.Floor(((Width - MenuSize) - (Padding * 2)) / (double)IconSize);
Cols = (int)Math.Floor((Height - (Padding * 2)) / (double)IconSize);
EntriesPerPage = Rows * Cols;
}
protected override void Compile()
{
if (Profile == null || Profile.Owner != User)
{
Profile = Arcade.EnsureProfile(User);
}
InvalidateGrid();
base.Compile();
}
protected override void CompileList(List<IGame> list)
{
list.Clear();
list.AddRange(Arcade.Games.Values);
base.CompileList(list);
}
public override int SortCompare(IGame a, IGame b)
{
var res = 0;
if (a.CompareNull(b, ref res))
{
return res;
}
return Insensitive.Compare(a.Name, b.Name);
}
protected override void CompileLayout(SuperGumpLayout layout)
{
base.CompileLayout(layout);
layout.Add(
"body",
() =>
{
AddBackground(0, 0, Width + (Margin * 2), Height + (Margin * 2), 2600);
AddBackground(Margin, Margin, MenuSize, Height, 9250);
AddBackground(Margin + MenuSize, Margin, Width - MenuSize, Height, 9250);
});
layout.Add(
"title",
() =>
{
var x = Margin + MenuSize + Padding;
var y = Margin + Padding;
var w = Width - (MenuSize + (Padding * 2));
var title = "Games Arcade";
title = title.WrapUOHtmlBig().WrapUOHtmlCenter().WrapUOHtmlColor(Color.Gold, false);
AddHtml(x, y, w, 40, title, false, false);
});
layout.Add(
"menu",
() =>
{
var x = Margin + Padding;
var y = Margin + Padding;
var w = MenuSize - (Padding * 2);
var h = Height - (Padding * 2);
CompileMenuLayout(x, y, w, h);
});
var games = GetListRange();
if (games != null)
{
var width = Cols * IconSize;
var height = Rows * IconSize;
var initX = Margin + MenuSize;
var initY = Margin + Padding;
if (width < Width - MenuSize)
{
initX += ((Width - MenuSize) - width) / 2;
}
if (height < Height)
{
initY += (Height - height) / 2;
}
var xOffset = initX;
var yOffset = initY;
var index = 0;
var col = 0;
var row = 0;
foreach (var game in games.Values)
{
CompileGameLayout(layout, index++, xOffset, yOffset, game);
xOffset += IconSize;
if (++col % Cols == 0)
{
xOffset = initX;
yOffset += IconSize;
if (++row % Rows == 0)
{
break;
}
}
}
if (col < Cols || row < Rows)
{
while (index < EntriesPerPage)
{
CompileGameLayout(layout, index++, xOffset, yOffset, null);
xOffset += IconSize;
if (++col % Cols == 0)
{
xOffset = initX;
yOffset += IconSize;
if (++row % Rows == 0)
{
break;
}
}
}
}
}
}
private void CompileGameLayout(SuperGumpLayout layout, int index, int x, int y, IGame game)
{
layout.Add("games/" + index, () => CompileGameLayout(x, y, IconSize, IconSize, game));
}
private void CompileGameLayout(int x, int y, int w, int h, IGame game)
{
if (game != null)
{
AddTileButton(x + Margin, y + Margin, w - (Margin * 2), h - (Margin * 2), b => SelectGame(game));
}
AddBackground(x, y, w, h, 2600);
if (game == null)
{
return;
}
y += Margin;
h -= Margin;
if (game.Icon != null && !game.Icon.IsEmpty)
{
var s = game.Icon.Size;
if (game.Enabled)
{
game.Icon.AddToGump(this, x + ((w - s.Width) / 2), y);
}
else
{
game.Icon.AddToGump(this, x + ((w - s.Width) / 2), y, 900);
}
y += s.Height + 5;
h -= s.Height + 5;
}
var text = game.Name.WrapUOHtmlBig().WrapUOHtmlCenter().WrapUOHtmlColor(Color.Gold, false);
AddHtml(x, y, w, h, text, false, false);
}
private void CompileMenuLayout(int x, int y, int w, int h)
{
if (SelectedGame == null)
{
return;
}
AddHtml(x, y, w, h - 95, GetDescription(SelectedGame), false, false);
y += h - 85;
var help = "Help";
help = help.WrapUOHtmlCenter();
if (SupportsUltimaStore)
{
help = help.WrapUOHtmlColor(Color.Gold, false);
AddButton(x + ((w - 126) / 2), y, 40019, 40029, b => SelectHelp(SelectedGame));
AddHtml(x + ((w - 126) / 2), y + 2, 126, 40, help, false, false);
}
else
{
help = help.WrapUOHtmlBig();
AddHtmlButton(x + ((w - 126) / 2), y, 126, 25, b => SelectHelp(SelectedGame), help, Color.White, Color.Empty);
}
y += 25;
var play = "Play";
play = play.WrapUOHtmlCenter();
if (SupportsUltimaStore)
{
if (SelectedGame.Enabled || User.AccessLevel >= Arcade.Access)
{
play = play.WrapUOHtmlColor(Color.Gold, false);
AddButton(x + ((w - 126) / 2), y, 40019, 40029, b => PlayGame(SelectedGame));
AddHtml(x + ((w - 126) / 2), y + 2, 126, 40, play, false, false);
}
else
{
play = play.WrapUOHtmlColor(Color.Gray, false);
AddImage(x + ((w - 126) / 2), y, 40019, 900);
AddHtml(x + ((w - 126) / 2), y + 2, 126, 40, play, false, false);
}
}
else
{
if (SelectedGame.Enabled)
{
play = play.WrapUOHtmlBig();
AddHtmlButton(x + ((w - 126) / 2), y, 126, 25, b => PlayGame(SelectedGame), play, Color.White, Color.Black);
}
else
{
play = play.WrapUOHtmlColor(Color.Gray, false);
AddRectangle(x + ((w - 126) / 2), y, 126, 25, Color.Black, true);
AddHtml(x + ((w - 126) / 2), y + 2, 126, 40, play, false, false);
}
}
if (User.AccessLevel < Arcade.Access)
{
return;
}
y += 25;
var label = SelectedGame.Enabled ? "Enabled" : "Disabled";
label = label.WrapUOHtmlCenter();
if (SupportsUltimaStore)
{
if (SelectedGame.Enabled)
{
label = label.WrapUOHtmlColor(Color.PaleGreen, false);
AddButton(x + ((w - 126) / 2), y, 40019, 40029, b => DisableGame(SelectedGame));
AddHtml(x + ((w - 126) / 2), y + 2, 126, 40, label, false, false);
}
else
{
label = label.WrapUOHtmlColor(Color.Gray, false);
AddButton(x + ((w - 126) / 2), y, 40019, 40029, b => EnableGame(SelectedGame));
AddHtml(x + ((w - 126) / 2), y + 2, 126, 40, label, false, false);
}
}
else
{
if (SelectedGame.Enabled)
{
label = label.WrapUOHtmlBig();
AddHtmlButton(
x + ((w - 126) / 2),
y,
126,
25,
b => DisableGame(SelectedGame),
label,
Color.PaleGreen,
Color.Black);
}
else
{
label = label.WrapUOHtmlBig();
AddHtmlButton(x + ((w - 126) / 2), y, 126, 25, b => EnableGame(SelectedGame), label, Color.Gray, Color.Black);
}
}
}
public string GetDescription(IGame game)
{
if (game == null)
{
return String.Empty;
}
var desc = new StringBuilder();
desc.Append("<CENTER>");
desc.AppendLine(game.Name.WrapUOHtmlBig().WrapUOHtmlColor(Color.Gold, false));
desc.AppendLine(String.Empty.WrapUOHtmlColor(Color.White, false));
desc.AppendLine(game.Desc);
desc.Append("</CENTER>");
return desc.ToString();
}
public void EnableGame(IGame game)
{
if (game == null)
{
Refresh(true);
return;
}
game.Enabled = true;
Refresh(true);
}
public void DisableGame(IGame game)
{
if (game == null)
{
Refresh(true);
return;
}
game.Enabled = false;
Refresh(true);
}
public void PlayGame(IGame game)
{
if (game == null || !game.Open(User))
{
Refresh(true);
}
}
public void SelectGame(IGame game)
{
SelectedGame = SelectedGame == game ? null : game;
Refresh(true);
}
public void SelectHelp(IGame game)
{
if (game == null)
{
Refresh(true);
return;
}
new NoticeDialogGump(User, Refresh())
{
Title = game.Name,
Html = game.Help,
Width = 500,
Height = 400,
HtmlColor = Color.White,
AcceptHandler = Refresh,
CancelHandler = Refresh
}.Send();
}
protected override void OnLayoutApplied()
{
base.OnLayoutApplied();
if (!SupportsUltimaStore)
{
return;
}
foreach (var e in Entries.OfType<GumpBackground>())
{
switch (e.GumpID)
{
case 2600:
e.GumpID = 39925;
break;
case 9250:
e.GumpID = 40000;
break;
}
}
}
}
}

View File

@@ -0,0 +1,486 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using Server;
using Server.Accounting;
using VitaNex.IO;
using VitaNex.SuperGumps;
using VitaNex.Web;
#endregion
namespace VitaNex.Modules.AutoDonate
{
public static partial class AutoDonate
{
public const AccessLevel Access = AccessLevel.Owner;
public static DonationOptions CMOptions { get; private set; }
public static BinaryDataStore<string, DonationTransaction> Transactions { get; private set; }
public static BinaryDirectoryDataStore<IAccount, DonationProfile> Profiles { get; private set; }
private static readonly string[] _AcceptedTypes =
{"cart", "express_checkout", "recurring_payment", "send_money", "subscr_payment", "virtual_terminal", "web_accept"};
private static void OnLogin(LoginEventArgs e)
{
SpotCheck(e.Mobile);
}
public static void SpotCheck(IAccount a)
{
if (a != null)
{
SpotCheck(a.FindMobiles().FirstOrDefault(p => p.IsOnline()));
}
}
public static void SpotCheck(Mobile user)
{
if (user == null || user.Deleted || !user.Alive || !user.IsOnline() || Profiles.Status != DataStoreStatus.Idle ||
!CMOptions.ModuleEnabled || CMOptions.CurrencyType == null || CMOptions.CurrencyPrice <= 0)
{
return;
}
var profile = FindProfile(user.Account);
if (profile == null)
{
return;
}
if (profile.Processed.Any())
{
var message = String.Format("Hey, {0}!\nYou have unclaimed donation credit!", user.RawName);
user.SendNotification(
message,
false,
1.0,
3.0,
Color.LawnGreen,
ui =>
{
ui.CanClose = false;
ui.CanDispose = false;
ui.AddOption(
"Claim!",
b =>
{
CheckDonate(user);
ui.Close();
});
});
}
}
private static void HandleWebForm(WebAPIContext context)
{
if (!CMOptions.WebForm.Enabled)
{
context.Response.Data = String.Empty;
context.Response.Status = HttpStatusCode.NoContent;
return;
}
context.Response.Data = CMOptions.WebForm.Generate();
context.Response.ContentType = "html";
}
private static void HandleAccountCheck(WebAPIContext context)
{
if (!String.IsNullOrWhiteSpace(context.Request.Queries["username"]))
{
var acc = Accounts.GetAccount(context.Request.Queries["username"]);
context.Response.Data = acc != null ? "VALID" : "INVALID";
}
else
{
context.Response.Data = "INVALID";
}
context.Response.ContentType = "txt";
}
private static void HandleIPN(WebAPIContext context)
{
var test = context.Request.Queries["test"] != null || Insensitive.Contains(context.Request.Data, "test_ipn=1");
var endpoint = test ? "ipnpb.sandbox." : "ipnpb.";
var paypal = String.Format("https://{0}paypal.com/cgi-bin/webscr", endpoint);
WebAPI.BeginRequest(paypal, "cmd=_notify-validate&" + context.Request.Data, BeginVerification, EndVerification);
}
private static void BeginVerification(HttpWebRequest webReq, string state)
{
webReq.Method = "POST";
webReq.ContentType = "application/x-www-form-urlencoded";
webReq.SetContent(state, ResolveEncoding(state));
}
private static void EndVerification(HttpWebRequest webReq, string state, HttpWebResponse webRes)
{
var content = webRes.GetContent();
File.AppendAllLines("IPN.log", new[] { "\n\nREQUEST:\n", state, "\n\nRESPONSE:\n", content });
if (Insensitive.Contains(content, "VERIFIED"))
{
using (var queries = new WebAPIQueries(state))
{
ProcessTransaction(queries);
}
RefreshAdminUI();
}
}
private static void ProcessTransaction(WebAPIQueries queries)
{
var id = queries["txn_id"];
if (String.IsNullOrWhiteSpace(id))
{
return;
}
var type = queries["txn_type"];
if (String.IsNullOrWhiteSpace(type) || !type.EqualsAny(true, _AcceptedTypes))
{
return;
}
var status = queries["payment_status"];
if (String.IsNullOrWhiteSpace(status))
{
return;
}
TransactionState state;
switch (status.Trim().ToUpper())
{
case "PENDING":
case "PROCESSED":
case "CREATED":
state = TransactionState.Pending;
break;
case "COMPLETED":
state = TransactionState.Processed;
break;
default:
state = TransactionState.Voided;
break;
}
ExtractCart(queries, out var credit, out var value);
var custom = queries["custom"] ?? String.Empty;
var trans = Transactions.GetValue(id);
var create = trans == null;
if (create)
{
var email = queries["payer_email"] ?? String.Empty;
var notes = queries["payer_note"] ?? String.Empty;
var extra = queries["extra_info"] ?? String.Empty;
var a = Accounts.GetAccount(custom) ?? CMOptions.FallbackAccount;
Transactions[id] = trans = new DonationTransaction(id, a, email, value, credit, notes, extra);
var profile = EnsureProfile(a);
if (profile == null)
{
state = TransactionState.Voided;
trans.Extra += "{VOID: NO PROFILE}";
}
else
{
profile.Add(trans);
}
}
if (!VerifyValue(queries, "business", CMOptions.Business) &&
!VerifyValue(queries, "receiver_email", CMOptions.Business) &&
!VerifyValue(queries, "receiver_id", CMOptions.Business))
{
state = TransactionState.Voided;
trans.Extra += "{VOID: UNEXPECTED BUSINESS}";
}
if (trans.Total != value)
{
state = TransactionState.Voided;
trans.Extra += "{VOID: TOTAL CHANGED}";
}
if (queries["test"] != null || queries["test_ipn"] != null)
{
state = TransactionState.Voided;
trans.Extra += "{VOID: TESTING}";
}
switch (state)
{
case TransactionState.Processed:
trans.Process();
break;
case TransactionState.Voided:
trans.Void();
break;
}
if (create && trans.IsPending)
{
DonationEvents.InvokeTransPending(trans);
}
SpotCheck(trans.Account);
}
private static bool VerifyValue(WebAPIQueries queries, string key, string val)
{
return !String.IsNullOrWhiteSpace(queries[key]) && Insensitive.Equals(queries[key], val);
}
private static void ExtractCart(WebAPIQueries queries, out long credit, out double value)
{
var isCart = Insensitive.Equals(queries["txn_type"], "cart");
const string totalKey = "quantity";
var grossKey = "mc_gross";
if (isCart)
{
grossKey += '_';
}
credit = 0;
value = 0;
foreach (var kv in queries)
{
var i = kv.Key.IndexOf("item_number", StringComparison.OrdinalIgnoreCase);
if (i < 0 || !Insensitive.Equals(kv.Value, CMOptions.CurrencyType.TypeName))
{
continue;
}
var k = "0";
if (i + 11 < kv.Key.Length)
{
k = kv.Key.Substring(i + 11);
}
if (String.IsNullOrWhiteSpace(k))
{
k = "0";
}
if (!Int32.TryParse(k, out i))
{
continue;
}
var subTotal = Math.Max(0, Int64.Parse(queries[totalKey + i.ToString("#")] ?? "0"));
var subGross = Math.Max(0, Double.Parse(queries[grossKey + i.ToString("#")] ?? "0", CultureInfo.InvariantCulture));
if (subTotal <= (isCart ? 0 : 1))
{
subTotal = (long)(subGross / CMOptions.CurrencyPrice);
}
else
{
var expGross = subTotal * CMOptions.CurrencyPrice;
if (Math.Abs(expGross - subGross) > CMOptions.CurrencyPrice)
{
subGross = expGross;
}
}
credit += subTotal;
value += subGross;
}
}
private static Encoding ResolveEncoding(string state)
{
Encoding enc = null;
var efb = Encoding.UTF8.EncoderFallback;
var dfb = Encoding.UTF8.DecoderFallback;
try
{
if (Insensitive.Contains(state, "charset="))
{
var start = state.IndexOf("charset=", StringComparison.OrdinalIgnoreCase) + 8;
var count = state.IndexOf('&', start) - start;
var value = state.Substring(start, count);
if (Insensitive.StartsWith(value, "windows-"))
{
if (Int32.TryParse(value.Substring(8), out var id))
{
enc = Encoding.GetEncoding(id, efb, dfb);
}
}
if (enc == null)
{
enc = Encoding.GetEncoding(value, efb, dfb);
}
}
}
catch
{
enc = null;
}
return enc ?? Encoding.UTF8;
}
public static DonationProfile FindProfile(IAccount a)
{
return Profiles.GetValue(a);
}
public static DonationProfile EnsureProfile(IAccount a)
{
var p = Profiles.GetValue(a);
if (p == null && a != null)
{
Profiles[a] = p = new DonationProfile(a);
}
return p;
}
public static void CheckDonate(Mobile user, bool message = true)
{
if (user == null || user.Deleted)
{
return;
}
if (!CMOptions.ModuleEnabled)
{
if (message)
{
user.SendMessage("The donation exchange is currently unavailable, please try again later.");
}
return;
}
if (!user.Alive)
{
if (message)
{
user.SendMessage("You must be alive to do that!");
}
return;
}
if (Profiles.Status != DataStoreStatus.Idle)
{
if (message)
{
user.SendMessage("The donation exchange is busy, please try again in a few moments.");
}
return;
}
if (CMOptions.CurrencyType == null || CMOptions.CurrencyPrice <= 0)
{
if (message)
{
user.SendMessage("Currency conversion is currently disabled, contact a member of staff to handle your donations.");
}
return;
}
var profile = FindProfile(user.Account);
if (profile != null)
{
var count = profile.Visible.Count();
if (count == 0)
{
if (message)
{
user.SendMessage("There are no current donation records for your account.");
}
}
else
{
if (message)
{
user.SendMessage("Thank you for your donation{0}, {1}!", count != 1 ? "s" : "", user.RawName);
}
DonationProfileUI.DisplayTo(user, profile, profile.Visible.FirstOrDefault());
}
}
else if (message)
{
user.SendMessage("There are no current donation records for your account.");
}
}
public static void CheckConfig(Mobile user)
{
if (user != null && !user.Deleted && user.AccessLevel >= Access)
{
(SuperGump.GetInstance<DonationAdminUI>(user) ?? new DonationAdminUI(user)).Refresh(true);
}
}
public static void RefreshAdminUI()
{
foreach (var g in SuperGump.GlobalInstances.Values.OfType<DonationAdminUI>())
{
g.Refresh(true);
}
}
}
}

View File

@@ -0,0 +1,193 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Accounting;
using VitaNex.IO;
using VitaNex.Web;
#endregion
namespace VitaNex.Modules.AutoDonate
{
[CoreModule("Auto Donate", "3.1.0.0", true, TaskPriority.Highest)]
public static partial class AutoDonate
{
static AutoDonate()
{
CMOptions = new DonationOptions();
Transactions = new BinaryDataStore<string, DonationTransaction>(
VitaNexCore.SavesDirectory + "/AutoDonate",
"Transactions")
{
OnSerialize = SerializeTransactions,
OnDeserialize = DeserializeTransactions
};
Profiles = new BinaryDirectoryDataStore<IAccount, DonationProfile>(
VitaNexCore.SavesDirectory + "/AutoDonate",
"Profiles",
"pro")
{
OnSerialize = SerializeProfile,
OnDeserialize = DeserializeProfile
};
}
private static void CMConfig()
{
CommandUtility.Register("CheckDonate", AccessLevel.Player, e => CheckDonate(e.Mobile));
CommandUtility.Register("DonateConfig", Access, e => CheckConfig(e.Mobile));
CommandUtility.RegisterAlias("DonateConfig", "DonateAdmin");
EventSink.Login += OnLogin;
WebAPI.Register("/donate/ipn", HandleIPN);
WebAPI.Register("/donate/acc", HandleAccountCheck);
WebAPI.Register("/donate/form", HandleWebForm);
}
private static void CMEnabled()
{
WebAPI.Register("/donate/ipn", HandleIPN);
WebAPI.Register("/donate/acc", HandleAccountCheck);
WebAPI.Register("/donate/form", HandleWebForm);
}
private static void CMDisabled()
{
WebAPI.Unregister("/donate/ipn");
WebAPI.Unregister("/donate/acc");
WebAPI.Unregister("/donate/form");
}
private static void CMSave()
{
Transactions.Export();
Profiles.Export();
}
private static void CMLoad()
{
Transactions.Import();
Profiles.Import();
}
private static void CMInvoke()
{
var owner = Accounts.GetAccounts().FirstOrDefault(ac => ac.AccessLevel == AccessLevel.Owner);
foreach (var trans in Transactions.Values)
{
if (trans.Account == null && owner != null)
{
trans.SetAccount(owner);
}
if (trans.Account == null)
{
continue;
}
var p = EnsureProfile(trans.Account);
if (p != null)
{
p.Transactions[trans.ID] = trans;
}
}
}
private static bool SerializeTransactions(GenericWriter writer)
{
writer.SetVersion(0);
writer.WriteBlockDictionary(Transactions, (w, k, v) => v.Serialize(w));
return true;
}
private static bool DeserializeTransactions(GenericReader reader)
{
reader.GetVersion();
reader.ReadBlockDictionary(
r =>
{
var t = new DonationTransaction(r);
return new KeyValuePair<string, DonationTransaction>(t.ID, t);
},
Transactions);
return true;
}
private static bool SerializeProfile(GenericWriter writer, IAccount key, DonationProfile val)
{
var version = writer.SetVersion(1);
writer.WriteBlock(
w =>
{
w.Write(key);
switch (version)
{
case 1:
val.Serialize(w);
break;
case 0:
w.WriteType(val, t => val.Serialize(w));
break;
}
});
return true;
}
private static Tuple<IAccount, DonationProfile> DeserializeProfile(GenericReader reader)
{
var version = reader.GetVersion();
return reader.ReadBlock(r =>
{
var key = r.ReadAccount();
DonationProfile val = null;
switch (version)
{
case 1:
val = new DonationProfile(r);
break;
case 0:
val = r.ReadTypeCreate<DonationProfile>(r);
break;
}
if (key == null && val != null && val.Account != null)
{
key = val.Account;
}
return Tuple.Create(key, val);
});
}
}
}

View File

@@ -0,0 +1,112 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Text;
using Server;
using Server.Items;
#endregion
namespace VitaNex.Modules.AutoDonate
{
public class DonationGiftBook : RedBook
{
[Constructable]
public DonationGiftBook(Mobile author, string text)
: base("A Gift", author.RawName, GetPageCount(text), false)
{
Hue = 0x89B;
SetText(text);
}
public DonationGiftBook(Serial serial)
: base(serial)
{ }
private static int GetPageCount(string text)
{
ParseFactors(text.Split(' '), out var wordCount, out var wordsPerLine, out var linesPerPage, out var index, out var pageCount);
return pageCount;
}
private void SetText(string text)
{
var words = text.Split(' ');
ParseFactors(words, out var wordCount, out var wordsPerLine, out var linesPerPage, out var index, out var pageCount);
for (var currentPage = 0; currentPage < pageCount; currentPage++)
{
for (var currentLine = 0; currentLine < linesPerPage; currentLine++)
{
Pages[currentPage] = new BookPageInfo(new string[linesPerPage]);
var line = new StringBuilder();
for (var currentWord = 0; currentWord < wordsPerLine; currentWord++)
{
if (index >= wordCount)
{
continue;
}
line.AppendFormat(" {0}", words[index]);
index++;
}
Pages[currentPage].Lines[currentLine] = line.ToString();
}
}
}
private static void ParseFactors(
string[] words,
out int wordCount,
out int wordsPerLine,
out int linesPerPage,
out int index,
out int pageCount)
{
wordCount = words.Length;
wordsPerLine = 5;
linesPerPage = 8;
index = 0;
pageCount = wordCount / (wordsPerLine * linesPerPage);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
break;
}
}
}
}

View File

@@ -0,0 +1,264 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Accounting;
using VitaNex.Crypto;
#endregion
namespace VitaNex.Modules.AutoDonate
{
public sealed class DonationProfile : IEnumerable<DonationTransaction>, IEquatable<DonationProfile>
{
public delegate double TierCalculation(DonationProfile p, int tier, double factor);
public static TierCalculation ComputeNextTier = (p, t, f) => (t + 1) * f;
[CommandProperty(AutoDonate.Access, true)]
public CryptoHashCode UID { get; private set; }
[CommandProperty(AutoDonate.Access, true)]
public IAccount Account { get; private set; }
public Dictionary<string, DonationTransaction> Transactions { get; private set; }
public DonationTransaction this[string id] => Transactions.GetValue(id);
public IEnumerable<DonationTransaction> Pending => Find(TransactionState.Pending);
public IEnumerable<DonationTransaction> Processed => Find(TransactionState.Processed);
public IEnumerable<DonationTransaction> Claimed => Find(TransactionState.Claimed);
public IEnumerable<DonationTransaction> Voided => Find(TransactionState.Voided);
public IEnumerable<DonationTransaction> Visible => Transactions.Values.Where(t => !t.Hidden);
[CommandProperty(AutoDonate.Access)]
public long TotalCredit => Claimed.Aggregate(0L, (c, t) => c + t.CreditTotal);
[CommandProperty(AutoDonate.Access)]
public double TotalValue => Claimed.Aggregate(0.0, (c, t) => c + t.Total);
[CommandProperty(AutoDonate.Access)]
public int Tier
{
get
{
var tier = 0;
if (AutoDonate.CMOptions.TierFactor <= 0.0)
{
return tier;
}
double total = TotalValue, factor = AutoDonate.CMOptions.TierFactor, req;
while (total > 0)
{
req = ComputeNextTier(this, tier, factor);
if (req <= 0 || total < req)
{
break;
}
total -= req;
++tier;
}
return tier;
}
}
[CommandProperty(AutoDonate.Access)]
public long Credit { get; set; }
public DonationProfile(IAccount account)
{
Transactions = new Dictionary<string, DonationTransaction>();
Account = account;
UID = new CryptoHashCode(CryptoHashType.MD5, Account.Username);
}
public DonationProfile(GenericReader reader)
{
Deserialize(reader);
}
public IEnumerable<DonationTransaction> Find(TransactionState state)
{
return Transactions.Values.Where(trans => trans != null && trans.State == state);
}
public DonationTransaction Find(string id)
{
return Transactions.GetValue(id);
}
public bool Contains(DonationTransaction trans)
{
return Transactions.ContainsKey(trans.ID);
}
public void Add(DonationTransaction trans)
{
if (trans != null)
{
AutoDonate.Transactions[trans.ID] = Transactions[trans.ID] = trans;
}
}
public bool Remove(DonationTransaction trans)
{
return Transactions.Remove(trans.ID);
}
IEnumerator IEnumerable.GetEnumerator()
{
return Transactions.Values.GetEnumerator();
}
public IEnumerator<DonationTransaction> GetEnumerator()
{
return Transactions.Values.GetEnumerator();
}
public override int GetHashCode()
{
return UID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is DonationProfile && Equals((DonationProfile)obj);
}
public bool Equals(DonationProfile other)
{
return !ReferenceEquals(other, null) && (ReferenceEquals(other, this) || UID.Equals(other.UID));
}
public override string ToString()
{
return UID.ToString();
}
public void Serialize(GenericWriter writer)
{
var version = writer.SetVersion(1);
switch (version)
{
case 1:
case 0:
{
writer.Write(Account);
writer.Write(Credit);
writer.WriteDictionary(
Transactions,
(w, k, v) =>
{
if (v == null)
{
w.Write(false);
}
else
{
w.Write(true);
if (version > 0)
{
w.Write(v.ID);
}
else
{
v.Serialize(w);
}
}
});
}
break;
}
}
public void Deserialize(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 1:
case 0:
{
Account = reader.ReadAccount();
Credit = reader.ReadLong();
Transactions = reader.ReadDictionary(
r =>
{
string k = null;
DonationTransaction v = null;
if (r.ReadBool())
{
if (version > 0)
{
k = r.ReadString();
v = AutoDonate.Transactions.GetValue(k);
}
else
{
v = new DonationTransaction(r);
k = v.ID;
AutoDonate.Transactions[k] = v;
}
}
return new KeyValuePair<string, DonationTransaction>(k, v);
},
Transactions);
if (version < 1) // Gifts
{
reader.ReadDictionary(
() =>
{
var k = reader.ReadString();
var v = reader.ReadString();
return new KeyValuePair<string, string>(k, v);
});
}
}
break;
}
}
public static bool operator ==(DonationProfile l, DonationProfile r)
{
return ReferenceEquals(l, null) ? ReferenceEquals(r, null) : l.Equals(r);
}
public static bool operator !=(DonationProfile l, DonationProfile r)
{
return ReferenceEquals(l, null) ? !ReferenceEquals(r, null) : !l.Equals(r);
}
}
}

View File

@@ -0,0 +1,566 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Text;
using Server;
using Server.Accounting;
using Server.Misc;
using VitaNex.IO;
#endregion
namespace VitaNex.Modules.AutoDonate
{
[PropertyObject]
public sealed class DonationTransaction : IEquatable<DonationTransaction>, IComparable<DonationTransaction>
{
private static void Protect(Item item)
{
var flags = ScriptCompiler.FindTypeByFullName("Server.Items.ItemFlags");
if (flags != null)
{
flags.InvokeMethod("SetStealable", item, false);
}
}
[CommandProperty(AutoDonate.Access, true)]
public string ID { get; private set; }
[CommandProperty(AutoDonate.Access, true)]
public IAccount Account { get; private set; }
[CommandProperty(AutoDonate.Access, true)]
public bool Deleted { get; private set; }
[CommandProperty(AutoDonate.Access, true)]
public int Version { get; set; }
[CommandProperty(AutoDonate.Access, true)]
public TimeStamp Time { get; set; }
[CommandProperty(AutoDonate.Access, true)]
public string Email { get; set; }
[CommandProperty(AutoDonate.Access, true)]
public double Total { get; set; }
[CommandProperty(AutoDonate.Access, true)]
public long Bonus { get; set; }
[CommandProperty(AutoDonate.Access)]
public long Credit { get; set; }
[CommandProperty(AutoDonate.Access)]
public string Notes { get; set; }
[CommandProperty(AutoDonate.Access)]
public string Extra { get; set; }
[CommandProperty(AutoDonate.Access)]
public TimeStamp DeliveryTime { get; set; }
[CommandProperty(AutoDonate.Access)]
public string DeliveredTo { get; set; }
private TransactionState _State;
[CommandProperty(AutoDonate.Access)]
public TransactionState State
{
get => _State;
set
{
if (_State == value)
{
return;
}
var old = _State;
_State = value;
OnStateChanged(old);
}
}
public TransactionState InternalState { get => State; set => _State = value; }
[CommandProperty(AutoDonate.Access)]
public bool Hidden => (IsClaimed || IsVoided) && !AutoDonate.CMOptions.ShowHistory;
[CommandProperty(AutoDonate.Access)]
public long CreditTotal => Credit + Bonus;
public bool IsClaimed => State == TransactionState.Claimed;
public bool IsPending => State == TransactionState.Pending;
public bool IsProcessed => State == TransactionState.Processed;
public bool IsVoided => State == TransactionState.Voided;
public string FullPath => String.Format("{0}|{1}|{2}", Time.Value.Year, Time.Value.GetMonth(), ID);
public DonationTransaction(
string id,
IAccount account,
string email,
double total,
long credit,
string notes,
string extra)
{
Version = 0;
Time = TimeStamp.Now;
ID = id;
Account = account;
Email = email;
Total = total;
Credit = credit;
Bonus = 0;
Notes = notes;
Extra = extra;
_State = TransactionState.Pending;
}
public DonationTransaction(GenericReader reader)
{
Deserialize(reader);
}
private void OnStateChanged(TransactionState oldState)
{
DonationEvents.InvokeStateChanged(this, oldState);
}
public bool Void()
{
if (State == TransactionState.Voided)
{
return true;
}
if ((State = TransactionState.Voided) == TransactionState.Voided)
{
++Version;
DonationEvents.InvokeTransVoided(this);
LogToFile();
return true;
}
return false;
}
public bool Process()
{
if (State == TransactionState.Processed)
{
return true;
}
if (State != TransactionState.Pending)
{
return false;
}
if ((State = TransactionState.Processed) == TransactionState.Processed)
{
++Version;
DonationEvents.InvokeTransProcessed(this);
LogToFile();
return true;
}
return false;
}
public bool Claim(Mobile m)
{
if (State == TransactionState.Claimed)
{
return true;
}
if (State != TransactionState.Processed)
{
return false;
}
if ((State = TransactionState.Claimed) == TransactionState.Claimed)
{
Deliver(m);
DeliveredTo = m.RawName;
DeliveryTime = TimeStamp.Now;
Extra += "{SHARD: " + ServerList.ServerName + "}";
++Version;
DonationEvents.InvokeTransClaimed(this, m);
LogToFile();
return true;
}
return false;
}
public long GetCredit(DonationProfile dp, out long credit, out long bonus)
{
return GetCredit(dp, false, out credit, out bonus);
}
private long GetCredit(DonationProfile dp, bool delivering, out long credit, out long bonus)
{
if (!delivering && State != TransactionState.Processed)
{
return (credit = Credit) + (bonus = Bonus);
}
var total = DonationEvents.InvokeTransExchange(this, dp);
if (AutoDonate.CMOptions.CreditBonus > 0)
{
total += (long)Math.Floor(Credit * AutoDonate.CMOptions.CreditBonus);
}
bonus = Math.Max(0, total - Credit);
credit = Math.Max(0, total - bonus);
return total;
}
private void Deliver(Mobile m)
{
if (m == null || m.Account == null)
{
return;
}
if (Account != m.Account)
{
SetAccount(m.Account);
}
var dp = AutoDonate.EnsureProfile(Account);
if (dp == null)
{
return;
}
var total = GetCredit(dp, true, out var credit, out var bonus);
Credit = credit;
Bonus = bonus;
var bag = DonationEvents.InvokeTransPack(this, dp);
if (bag == null || bag.Deleted)
{
dp.Credit += total;
return;
}
Protect(bag);
while (credit > 0)
{
var cur = AutoDonate.CMOptions.CurrencyType.CreateInstance();
if (cur == null)
{
bag.Delete();
break;
}
Protect(cur);
if (cur.Stackable)
{
cur.Amount = (int)Math.Min(credit, 60000);
}
credit -= cur.Amount;
bag.DropItem(cur);
}
if (bag.Deleted)
{
dp.Credit += total;
return;
}
while (bonus > 0)
{
var cur = AutoDonate.CMOptions.CurrencyType.CreateInstance();
if (cur == null)
{
bag.Delete();
break;
}
Protect(cur);
cur.Name = String.Format("{0} [Bonus]", cur.ResolveName(m));
if (cur.Stackable)
{
cur.Amount = (int)Math.Min(bonus, 60000);
}
bonus -= cur.Amount;
bag.DropItem(cur);
}
if (bag.Deleted || bag.GiveTo(m, GiveFlags.PackBankDelete) == GiveFlags.Delete)
{
dp.Credit += total;
}
}
public void SetAccount(IAccount acc)
{
if (Account == acc)
{
return;
}
++Version;
Extra += "{ACCOUNT CHANGED FROM '" + Account + "' TO '" + acc + "'}";
var profile = AutoDonate.FindProfile(Account);
if (profile != null)
{
profile.Remove(this);
}
Account = acc;
profile = AutoDonate.EnsureProfile(Account);
if (profile != null)
{
profile.Add(this);
}
LogToFile();
}
public void Delete()
{
if (Deleted)
{
return;
}
Deleted = true;
AutoDonate.Transactions.Remove(ID);
DonationEvents.InvokeTransactionDeleted(this);
DeliveredTo = null;
SetAccount(null);
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is DonationTransaction && Equals((DonationTransaction)obj);
}
public bool Equals(DonationTransaction other)
{
return other != null && String.Equals(ID, other.ID);
}
public int CompareTo(DonationTransaction other)
{
var res = 0;
if (this.CompareNull(other, ref res))
{
return res;
}
return TimeStamp.Compare(Time, other.Time);
}
public override string ToString()
{
return ID;
}
public void LogToFile()
{
var file = IOUtility.EnsureFile(VitaNexCore.LogsDirectory + "/Donations/" + ID + ".log");
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine(new string('*', 80));
sb.AppendLine();
sb.AppendLine("{0}: {1}", file.Exists ? "UPDATED" : "CREATED", DateTime.Now);
sb.AppendLine();
sb.AppendLine("ID: {0}", ID);
sb.AppendLine("State: {0}", State);
sb.AppendLine("Time: {0}", Time.Value);
sb.AppendLine("Version: {0:#,0}", Version);
sb.AppendLine();
sb.AppendLine("Account: {0}", Account);
sb.AppendLine("Email: {0}", Email);
sb.AppendLine();
sb.AppendLine("Total: {0}{1} {2}", AutoDonate.CMOptions.MoneySymbol, Total, AutoDonate.CMOptions.MoneyAbbr);
sb.AppendLine("Credit: {0:#,0} {1}", Credit, AutoDonate.CMOptions.CurrencyName);
sb.AppendLine("Bonus: {0:#,0} {1}", Bonus, AutoDonate.CMOptions.CurrencyName);
if (DeliveredTo != null)
{
sb.AppendLine();
sb.AppendLine("Delivered: {0}", DeliveryTime.Value);
sb.AppendLine("Recipient: {0}", DeliveredTo);
}
if (!String.IsNullOrWhiteSpace(Notes))
{
sb.AppendLine();
sb.AppendLine("Notes:");
sb.AppendLine(Notes);
}
if (!String.IsNullOrWhiteSpace(Extra))
{
sb.AppendLine();
sb.AppendLine("Extra:");
sb.AppendLine(Extra);
}
sb.Log(file);
}
public void Serialize(GenericWriter writer)
{
var version = writer.SetVersion(3);
switch (version)
{
case 3:
writer.Write(Deleted);
goto case 2;
case 2:
case 1:
writer.Write(Bonus);
goto case 0;
case 0:
{
writer.Write(ID);
writer.WriteFlag(_State);
writer.Write(Account);
writer.Write(Email);
writer.Write(Total);
writer.Write(Credit);
writer.Write(Time);
writer.Write(Version);
writer.Write(Notes);
writer.Write(Extra);
writer.Write(DeliveredTo);
writer.Write(DeliveryTime);
}
break;
}
}
public void Deserialize(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 3:
Deleted = reader.ReadBool();
goto case 2;
case 2:
case 1:
Bonus = reader.ReadLong();
goto case 0;
case 0:
{
ID = reader.ReadString();
_State = reader.ReadFlag<TransactionState>();
Account = reader.ReadAccount();
Email = reader.ReadString();
Total = reader.ReadDouble();
Credit = reader.ReadLong();
Time = version > 0 ? reader.ReadTimeStamp() : reader.ReadDouble();
Version = reader.ReadInt();
if (version < 1)
{
reader.ReadInt(); // InternalVersion
}
Notes = reader.ReadString();
Extra = reader.ReadString();
if (version > 1)
{
DeliveredTo = reader.ReadString();
DeliveryTime = reader.ReadTimeStamp();
}
else if (version > 0)
{
var m = reader.ReadMobile();
DeliveredTo = m != null ? m.RawName : null;
DeliveryTime = reader.ReadTimeStamp();
}
else
{
reader.ReadMobile(); // DeliverFrom
var m = reader.ReadMobile();
DeliveredTo = m != null ? m.RawName : null;
DeliveryTime = reader.ReadDouble();
}
}
break;
}
}
}
}

View File

@@ -0,0 +1,21 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
namespace VitaNex.Modules.AutoDonate
{
public enum TransactionState
{
Voided = 0,
Pending,
Processed,
Claimed
}
}

View File

@@ -0,0 +1,75 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Linq;
using Server;
using VitaNex.IO;
#endregion
namespace VitaNex.Modules.AutoDonate
{
[PropertyObject]
public sealed class DonationStatistics
{
[CommandProperty(AutoDonate.Access)]
public DataStoreStatus ProfileStatus => AutoDonate.Profiles.Status;
[CommandProperty(AutoDonate.Access)]
public int ProfileCount => AutoDonate.Profiles.Count;
[CommandProperty(AutoDonate.Access)]
public double TotalIncome => ProfileCount <= 0 ? 0 : AutoDonate.Profiles.Values.Sum(p => p.TotalValue);
[CommandProperty(AutoDonate.Access)]
public long TotalCredit => ProfileCount <= 0 ? 0 : AutoDonate.Profiles.Values.Sum(p => p.TotalCredit);
[CommandProperty(AutoDonate.Access)]
public int TierMin => ProfileCount <= 0 ? 0 : AutoDonate.Profiles.Values.Min(p => p.Tier);
[CommandProperty(AutoDonate.Access)]
public int TierMax => ProfileCount <= 0 ? 0 : AutoDonate.Profiles.Values.Max(p => p.Tier);
[CommandProperty(AutoDonate.Access)]
public double TierAverage => ProfileCount <= 0 ? 0 : AutoDonate.Profiles.Values.Average(p => p.Tier);
[CommandProperty(AutoDonate.Access)]
public DataStoreStatus TransStatus => AutoDonate.Transactions.Status;
[CommandProperty(AutoDonate.Access)]
public int TransCount => AutoDonate.Transactions.Count;
[CommandProperty(AutoDonate.Access)]
public double TransMin => TransCount <= 0 ? 0 : AutoDonate.Transactions.Values.Min(p => p.Total);
[CommandProperty(AutoDonate.Access)]
public double TransMax => TransCount <= 0 ? 0 : AutoDonate.Transactions.Values.Max(p => p.Total);
[CommandProperty(AutoDonate.Access)]
public double TransAverage => TransCount <= 0 ? 0 : AutoDonate.Transactions.Values.Average(t => t.Total);
[CommandProperty(AutoDonate.Access)]
public long CreditMin => TransCount <= 0 ? 0 : AutoDonate.Transactions.Values.Min(p => p.Credit);
[CommandProperty(AutoDonate.Access)]
public long CreditMax => TransCount <= 0 ? 0 : AutoDonate.Transactions.Values.Max(p => p.Credit);
[CommandProperty(AutoDonate.Access)]
public double CreditAverage => TransCount <= 0 ? 0 : AutoDonate.Transactions.Values.Average(t => t.Credit);
public override string ToString()
{
return "Donation Statistics";
}
}
}

View File

@@ -0,0 +1,249 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Linq;
using Server;
using Server.Accounting;
#endregion
namespace VitaNex.Modules.AutoDonate
{
public sealed class DonationOptions : CoreModuleOptions
{
[CommandProperty(AutoDonate.Access)]
public DonationStatistics Info { get; set; }
[CommandProperty(AutoDonate.Access)]
public bool ShowHistory { get; set; }
[CommandProperty(AutoDonate.Access)]
public char MoneySymbol { get; set; }
[CommandProperty(AutoDonate.Access)]
public double TierFactor { get; set; }
[CommandProperty(AutoDonate.Access)]
public double CreditBonus { get; set; }
[CommandProperty(AutoDonate.Access)]
public DonationWebFormOptions WebForm { get; set; }
[CommandProperty(AutoDonate.Access)]
public string Business { get => WebForm.Business; set => WebForm.Business = value; }
[CommandProperty(AutoDonate.Access)]
public string MoneyAbbr { get => WebForm.Currency; set => WebForm.Currency = value; }
[CommandProperty(AutoDonate.Access)]
public double CurrencyPrice { get => WebForm.ItemValue; set => WebForm.ItemValue = value; }
[CommandProperty(AutoDonate.Access)]
public string CurrencyName { get => WebForm.ItemName; set => WebForm.ItemName = value; }
private ItemTypeSelectProperty _CurrencyType = new ItemTypeSelectProperty();
[CommandProperty(AutoDonate.Access)]
public ItemTypeSelectProperty CurrencyType
{
get
{
if (_CurrencyType.TypeName != WebForm.ItemType)
{
_CurrencyType.TypeName = WebForm.ItemType;
}
return _CurrencyType;
}
set
{
if (value != null)
{
_CurrencyType = value;
}
else
{
_CurrencyType.TypeName = String.Empty;
}
WebForm.ItemType = _CurrencyType.TypeName;
}
}
private IAccount _FallbackAccount;
public IAccount FallbackAccount
{
get
{
ValidateFallbackAccount(ref _FallbackAccount);
return _FallbackAccount;
}
set
{
_FallbackAccount = value;
ValidateFallbackAccount(ref _FallbackAccount);
}
}
[CommandProperty(AutoDonate.Access)]
public string FallbackUsername
{
get => FallbackAccount.Username;
set => FallbackAccount = Accounts.GetAccount(value);
}
private static void ValidateFallbackAccount(ref IAccount acc)
{
if (acc == null)
{
acc = Accounts.GetAccounts().FirstOrDefault(a => a.AccessLevel == AccessLevel.Owner);
}
}
public DonationOptions()
: base(typeof(AutoDonate))
{
WebForm = new DonationWebFormOptions();
MoneySymbol = '$';
ShowHistory = false;
TierFactor = 0.0;
CreditBonus = 0.0;
Info = new DonationStatistics();
}
public DonationOptions(GenericReader reader)
: base(reader)
{ }
public override void Clear()
{
base.Clear();
MoneySymbol = ' ';
ShowHistory = false;
TierFactor = 0.0;
CreditBonus = 0.0;
}
public override void Reset()
{
base.Reset();
MoneySymbol = '$';
ShowHistory = false;
TierFactor = 100.0;
CreditBonus = 0.0;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(4);
switch (version)
{
case 4:
writer.Write(FallbackAccount);
goto case 3;
case 3:
writer.Write(CreditBonus);
goto case 2;
case 2:
WebForm.Serialize(writer);
goto case 1;
case 1:
writer.Write(TierFactor);
goto case 0;
case 0:
{
writer.Write(ShowHistory);
writer.Write(MoneySymbol);
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
if (version < 2)
{
WebForm = new DonationWebFormOptions();
}
switch (version)
{
case 4:
FallbackAccount = reader.ReadAccount();
goto case 3;
case 3:
CreditBonus = reader.ReadDouble();
goto case 2;
case 2:
WebForm = new DonationWebFormOptions(reader);
goto case 1;
case 1:
TierFactor = reader.ReadDouble();
goto case 0;
case 0:
{
if (version < 2)
{
#region MySQL
reader.ReadInt();
reader.ReadInt();
reader.ReadString();
reader.ReadShort();
reader.ReadString();
reader.ReadString();
reader.ReadString();
reader.ReadByte();
reader.ReadInt();
reader.ReadString();
reader.ReadString();
#endregion
_CurrencyType = new ItemTypeSelectProperty(reader); // CurrencyType
reader.ReadString(); // TableName
}
ShowHistory = reader.ReadBool();
if (version < 2)
{
CurrencyPrice = reader.ReadDouble(); // UnitPrice
}
MoneySymbol = reader.ReadChar();
if (version < 2)
{
MoneyAbbr = reader.ReadString(); // MoneyAbbr
reader.ReadBool(); // GiftingEnabled
}
}
break;
}
Info = new DonationStatistics();
}
}
}

View File

@@ -0,0 +1,206 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Text;
using Server;
using VitaNex.Text;
#endregion
namespace VitaNex.Modules.AutoDonate
{
public sealed class DonationWebFormOptions : PropertyObject
{
private static readonly Dictionary<string, object> _DefOptions = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
{
{"test", false},
{"command", "_donations"},
{"business", String.Empty},
{"notifyUrl", String.Empty},
{"returnUrl", String.Empty},
{"verifyUrl", String.Empty},
{"currency", "USD"},
{"itemName", "Gold Coins"},
{"itemType", "Gold"},
{"itemValue", 1.00},
{"amountDef", 25.00},
{"amountMin", 5.00},
{"amountMax", 500.00},
{"amountInc", 1.00},
{"buttonName", "Donate"},
{"bannerUrl", String.Empty},
{"bannerImg", String.Empty},
{"shard", String.Empty}
};
private readonly Dictionary<string, object> _Options = new Dictionary<string, object>(_DefOptions, StringComparer.OrdinalIgnoreCase);
[CommandProperty(AutoDonate.Access)]
public bool Test { get => (bool)_Options["test"]; set => _Options["test"] = value; }
[CommandProperty(AutoDonate.Access)]
public string Command { get => (string)_Options["command"]; set => _Options["command"] = value; }
[CommandProperty(AutoDonate.Access)]
public string Business { get => (string)_Options["business"]; set => _Options["business"] = value; }
[CommandProperty(AutoDonate.Access)]
public string NotifyUrl { get => (string)_Options["notifyUrl"]; set => _Options["notifyUrl"] = value; }
[CommandProperty(AutoDonate.Access)]
public string ReturnUrl { get => (string)_Options["returnUrl"]; set => _Options["returnUrl"] = value; }
[CommandProperty(AutoDonate.Access)]
public string VerifyUrl { get => (string)_Options["verifyUrl"]; set => _Options["verifyUrl"] = value; }
[CommandProperty(AutoDonate.Access)]
public string Currency { get => (string)_Options["currency"]; set => _Options["currency"] = value; }
[CommandProperty(AutoDonate.Access)]
public string ItemName { get => (string)_Options["itemName"]; set => _Options["itemName"] = value; }
[CommandProperty(AutoDonate.Access)]
public string ItemType { get => (string)_Options["itemType"]; set => _Options["itemType"] = value; }
[CommandProperty(AutoDonate.Access)]
public double ItemValue { get => (double)_Options["itemValue"]; set => _Options["itemValue"] = value; }
[CommandProperty(AutoDonate.Access)]
public double AmountDef { get => (double)_Options["amountDef"]; set => _Options["amountDef"] = value; }
[CommandProperty(AutoDonate.Access)]
public double AmountMin { get => (double)_Options["amountMin"]; set => _Options["amountMin"] = value; }
[CommandProperty(AutoDonate.Access)]
public double AmountMax { get => (double)_Options["amountMax"]; set => _Options["amountMax"] = value; }
[CommandProperty(AutoDonate.Access)]
public double AmountInc { get => (double)_Options["amountInc"]; set => _Options["amountInc"] = value; }
[CommandProperty(AutoDonate.Access)]
public string ButtonName { get => (string)_Options["buttonName"]; set => _Options["buttonName"] = value; }
[CommandProperty(AutoDonate.Access)]
public string BannerUrl { get => (string)_Options["bannerUrl"]; set => _Options["bannerUrl"] = value; }
[CommandProperty(AutoDonate.Access)]
public string BannerImg { get => (string)_Options["bannerImg"]; set => _Options["bannerImg"] = value; }
[CommandProperty(AutoDonate.Access)]
public string Shard { get => (string)_Options["shard"]; set => _Options["shard"] = value; }
[CommandProperty(AutoDonate.Access)]
public bool Enabled { get; set; }
public Action<StringBuilder> GenerationHandler { get; set; }
public DonationWebFormOptions()
{ }
public DonationWebFormOptions(GenericReader reader)
: base(reader)
{ }
public override void Clear()
{
Enabled = false;
foreach (var kv in _DefOptions)
{
_Options[kv.Key] = kv.Value;
}
}
public override void Reset()
{
Enabled = false;
foreach (var kv in _DefOptions)
{
_Options[kv.Key] = kv.Value;
}
}
public string GetJsonOptions()
{
return Json.Encode(_Options);
}
public void SetJsonOptions(string json)
{
if (!Json.Decode(json, out var obj, out var e))
{
e.ToConsole();
return;
}
if (obj is Dictionary<string, object>)
{
foreach (var kv in (Dictionary<string, object>)obj)
{
_Options[kv.Key] = kv.Value;
}
}
}
public string Generate()
{
var html = new StringBuilder();
html.AppendLine("<!DOCTYPE html>");
html.AppendLine("<html>");
html.AppendLine("\t<head>");
html.AppendLine("\t\t<title>{0} - Donate</title>", Shard);
html.AppendLine("\t\t<link rel='stylesheet' type='text/css' href='http://www.vita-nex.com/js/inc/index.css' />");
html.AppendLine("\t\t<script type='text/javascript' src='http://www.vita-nex.com/js/mod/donateForm.js'></script>");
html.AppendLine("\t</head>");
html.AppendLine("\t<body>");
html.AppendLine("\t\t<div id='index'>");
html.AppendLine("\t\t\t<form class='donate-form' data-options='{0}'></form>", GetJsonOptions());
html.AppendLine("\t\t</div>");
html.AppendLine("\t</body>");
html.AppendLine("</html>");
if (GenerationHandler != null)
{
GenerationHandler(html);
}
return html.ToString();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(Enabled);
writer.Write(GetJsonOptions());
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
Enabled = reader.ReadBool();
SetJsonOptions(reader.ReadString());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,825 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using Server;
using Server.Accounting;
using Server.Gumps;
using VitaNex.Collections;
using VitaNex.SuperGumps;
using VitaNex.SuperGumps.UI;
using VitaNex.Text;
#endregion
namespace VitaNex.Modules.AutoDonate
{
public class DonationProfileUI : TreeGump
{
public static void DisplayTo(Mobile user, DonationProfile profile, DonationTransaction trans)
{
DisplayTo(user, profile, false, trans);
}
public static void DisplayTo(Mobile user, DonationProfile profile, bool refreshOnly, DonationTransaction trans)
{
var node = trans.IsPending
? ("Transactions|Pending|" + trans.ID)
: trans.IsProcessed //
? ("Transactions|Claim|" + trans.ID)
: !trans.Hidden //
? ("History|" + trans.FullPath)
: "History";
DisplayTo(user, profile, refreshOnly, node);
}
public static void DisplayTo(Mobile user)
{
DisplayTo(user, null);
}
public static void DisplayTo(Mobile user, DonationProfile profile)
{
DisplayTo(user, profile, String.Empty);
}
public static void DisplayTo(Mobile user, DonationProfile profile, string node)
{
DisplayTo(user, profile, false, node);
}
public static void DisplayTo(Mobile user, DonationProfile profile, bool refreshOnly)
{
DisplayTo(user, profile, refreshOnly, String.Empty);
}
public static void DisplayTo(Mobile user, DonationProfile profile, bool refreshOnly, string node)
{
var info = EnumerateInstances<DonationProfileUI>(user).FirstOrDefault(g => g != null && !g.IsDisposed && g.IsOpen);
if (info == null)
{
if (refreshOnly)
{
return;
}
info = new DonationProfileUI(user, profile);
}
else if (profile != null)
{
info.Profile = profile;
}
if (!String.IsNullOrWhiteSpace(node))
{
info.SelectedNode = node;
}
info.Refresh(true);
}
private bool _Admin;
private int _DonationTier;
private int _DonationCount;
private double _DonationValue;
private long _DonationCredit;
private int[,] _Indicies;
private List<DonationTransaction> _Transactions;
public DonationProfile Profile { get; set; }
public DonationProfileUI(Mobile user, DonationProfile profile = null)
: base(user, null, null, null, null, null, "Donations")
{
_Indicies = new int[6, 2];
Profile = profile;
CanMove = true;
CanClose = true;
CanDispose = true;
CanResize = false;
Width = 900;
Height = 500;
ForceRecompile = true;
}
public override void AssignCollections()
{
base.AssignCollections();
if (_Transactions == null)
{
ObjectPool.Acquire(out _Transactions);
}
}
protected override void MainButtonHandler(GumpButton b)
{
if (_Admin)
{
new DonationAdminUI(User, Hide()).Send();
return;
}
base.MainButtonHandler(b);
}
protected override void Compile()
{
_Admin = User.AccessLevel >= AutoDonate.Access;
if (Profile == null || Profile.Account == null || (!_Admin && User.AccessLevel <= Profile.Account.AccessLevel &&
!Profile.Account.IsSharedWith(User.Account)))
{
Profile = AutoDonate.EnsureProfile(User.Account);
}
if (Profile != null)
{
_DonationTier = Profile.Tier;
_DonationValue = Profile.TotalValue;
_DonationCredit = Profile.TotalCredit;
_DonationCount = _Admin ? Profile.Transactions.Count : Profile.Visible.Count();
Title = "Donations: " + Profile.Account;
}
base.Compile();
}
protected override void CompileNodes(Dictionary<TreeGumpNode, Action<Rectangle, int, TreeGumpNode>> list)
{
list.Clear();
list["Transactions"] = CompileTransactions;
list["Transactions|Pending"] = CompileTransactions;
list["Transactions|Claim"] = CompileTransactions;
var trans = _Admin ? Profile.Transactions.Values : Profile.Visible;
foreach (var t in trans)
{
if (t.IsPending)
{
list["Transactions|Pending|" + t.ID] = CompileTransaction;
}
else if (t.IsProcessed)
{
list["Transactions|Claim|" + t.ID] = CompileTransaction;
}
TreeGumpNode n = t.FullPath;
list["History|" + n.FullName] = CompileTransaction;
foreach (var p in n.GetParents())
{
list["History|" + p] = CompileTransactions;
}
}
base.CompileNodes(list);
}
protected override void CompileNodeLayout(
SuperGumpLayout layout,
int x,
int y,
int w,
int h,
int index,
TreeGumpNode node)
{
base.CompileNodeLayout(layout, x, y, w, h, index, node);
if (Nodes == null || !Nodes.ContainsKey(node))
{
CompileEmptyNodeLayout(layout, x, y, w, h, index, node);
}
}
protected override void CompileEmptyNodeLayout(
SuperGumpLayout layout,
int x,
int y,
int w,
int h,
int index,
TreeGumpNode node)
{
base.CompileEmptyNodeLayout(layout, x, y, w, h, index, node);
layout.Add("node/page/" + index, () => CompileOverview(new Rectangle(x, y, w, h), index, node));
}
protected virtual void CompileOverview(Rectangle bounds, int index, TreeGumpNode node)
{
var info = new StringBuilder();
info.AppendLine(
"Welcome to the Donation Exchange, {0}!",
User.RawName.WrapUOHtmlColor(User.GetNotorietyColor(), HtmlColor));
info.AppendLine();
info.AppendLine("Select a category on the left to browse your transactions.");
info.AppendLine();
info.AppendLine("MY EXCHANGE".WrapUOHtmlBold().WrapUOHtmlColor(Color.Gold, false));
info.AppendLine();
GetProfileOverview(info);
AddHtml(
bounds.X + 5,
bounds.Y,
bounds.Width - 5,
bounds.Height,
info.ToString().WrapUOHtmlColor(HtmlColor),
false,
true);
}
protected virtual void CompileTransactions(Rectangle b, int index, TreeGumpNode node)
{
_Transactions.Clear();
int idx;
var trans = _Admin ? Profile.Transactions.Values : Profile.Visible;
switch (node.Name)
{
case "Transactions":
idx = 0;
break;
case "Claim":
{
trans = trans.Where(t => t.IsProcessed);
idx = 1;
}
break;
case "Pending":
{
trans = trans.Where(t => t.IsPending);
idx = 2;
}
break;
default:
{
switch (node.Depth)
{
default: // History
idx = 3;
break;
case 1: // Year
{
var y = Utility.ToInt32(node.Name);
trans = trans.Where(t => t.Time.Value.Year == y);
idx = 4;
}
break;
case 2: // Month
{
var y = Utility.ToInt32(node.Parent.Name);
var m = (Months)Enum.Parse(typeof(Months), node.Name);
trans = trans.Where(t => t.Time.Value.Year == y);
trans = trans.Where(t => t.Time.Value.GetMonth() == m);
idx = 5;
}
break;
}
}
break;
}
_Transactions.AddRange(trans);
_Transactions.Sort();
_Indicies[idx, 1] = _Transactions.Count;
_Indicies[idx, 0] = Math.Max(0, Math.Min(_Indicies[idx, 1] - 1, _Indicies[idx, 0]));
_Transactions.TrimStart(_Indicies[idx, 0]);
_Transactions.TrimEndTo((b.Height / 24) - 1);
// ID | Date | Recipient | Value | Credit | State
var cols = new[] { -1, -1, -1, 80, 80, 80 };
AddTable(b.X, b.Y, b.Width - 25, b.Height, true, cols, _Transactions, 24, Color.Empty, 0, RenderTransaction);
_Transactions.Clear();
AddBackground(b.X + (b.Width - 25), b.Y, 28, b.Height, SupportsUltimaStore ? 40000 : 9260);
AddScrollbarV(
b.X + (b.Width - 24),
b.Y,
b.Height,
_Indicies[idx, 1],
_Indicies[idx, 0],
p =>
{
--_Indicies[idx, 0];
Refresh(true);
},
n =>
{
++_Indicies[idx, 0];
Refresh(true);
});
}
protected virtual void RenderTransaction(int x, int y, int w, int h, DonationTransaction t, int r, int c)
{
var bgCol = r % 2 != 0 ? Color.DarkSlateGray : Color.Black;
var fgCol = r % 2 != 0 ? Color.White : Color.WhiteSmoke;
ApplyPadding(ref x, ref y, ref w, ref h, 2);
if (r < 0) // headers
{
var label = String.Empty;
switch (c)
{
case -1:
AddHtml(x, y, w, h, label, fgCol, bgCol);
break;
case 0:
label = "ID";
goto case -1;
case 1:
label = "Date";
goto case -1;
case 2:
label = "Recipient";
goto case -1;
case 3:
label = AutoDonate.CMOptions.MoneySymbol + AutoDonate.CMOptions.MoneyAbbr;
goto case -1;
case 4:
label = AutoDonate.CMOptions.CurrencyName;
goto case -1;
case 5:
label = "Status";
goto case -1;
}
}
else if (t != null)
{
switch (c)
{
case 0: // ID
AddHtml(x, y, w, h, t.ID, fgCol, bgCol);
break;
case 1: // Date
{
AddHtml(x, y, w, h, t.Time.Value.ToSimpleString("m/d/y"), fgCol, bgCol);
AddTooltip(t.Time.Value.ToSimpleString());
}
break;
case 2: // Recipient
{
AddHtml(x, y, w, h, t.DeliveredTo ?? String.Empty, fgCol, bgCol);
if (!String.IsNullOrWhiteSpace(t.DeliveredTo))
{
AddTooltip(t.DeliveryTime.Value.ToSimpleString());
}
}
break;
case 3: // Value
AddHtml(x, y, w, h, AutoDonate.CMOptions.MoneySymbol + t.Total.ToString("#,0.00"), fgCol, bgCol);
break;
case 4: // Credit
{
if (t.Bonus > 0)
{
AddHtml(x, y, w, h, String.Format("{0:#,0} +{1:#,0}", t.Credit, t.Bonus), fgCol, bgCol);
}
else
{
AddHtml(x, y, w, h, t.Credit.ToString("#,0"), fgCol, bgCol);
}
}
break;
case 5: // Status
{
string node;
if (t.IsPending)
{
node = "Transactions|Pending|" + t.ID;
}
else if (t.IsProcessed)
{
node = "Transactions|Claim|" + t.ID;
}
else
{
node = "History|" + t.FullPath;
}
var label = String.Empty;
var color = fgCol;
switch (t.State)
{
case TransactionState.Voided:
{
label = UniGlyph.CircleX.ToString();
color = Color.IndianRed;
}
break;
case TransactionState.Pending:
{
label = UniGlyph.Coffee.ToString();
color = Color.Yellow;
}
break;
case TransactionState.Processed:
{
label = UniGlyph.StarEmpty.ToString();
color = Color.SkyBlue;
}
break;
case TransactionState.Claimed:
{
label = UniGlyph.StarFill.ToString();
color = Color.LawnGreen;
}
break;
}
label = label.WrapUOHtmlColor(color, fgCol);
label += " " + t.State.ToString(true);
AddHtmlButton(x, y, w, h, b => SelectNode(node), label, fgCol, bgCol);
}
break;
}
}
}
protected virtual void CompileTransaction(Rectangle b, int index, TreeGumpNode node)
{
var trans = Profile[node.Name];
if (trans == null)
{
CompileOverview(b, index, node);
return;
}
var cpHeight = _Admin ? 60 : 30;
var html = new StringBuilder();
GetTransactionOverview(trans, html, true, true, true);
AddHtml(
b.X + 5,
b.Y,
b.Width - 5,
b.Height - cpHeight,
html.ToString().WrapUOHtmlColor(Color.White, false),
false,
true);
var bw = b.Width;
var bh = cpHeight;
if (_Admin)
{
bh /= 2;
}
switch (trans.State)
{
case TransactionState.Voided:
{
AddHtmlButton(
b.X,
b.Y + (b.Height - bh),
bw,
bh,
o => OnVoidedTransaction(trans),
"[VOIDED]",
Color.OrangeRed,
Color.Black,
Color.OrangeRed,
2);
}
break;
case TransactionState.Pending:
{
AddHtmlButton(
b.X,
b.Y + (b.Height - bh),
bw,
bh,
o => OnPendingTransaction(trans),
"[PENDING]",
Color.Yellow,
Color.Black,
Color.Yellow,
2);
}
break;
case TransactionState.Processed:
{
AddHtmlButton(
b.X,
b.Y + (b.Height - bh),
bw,
bh,
o => OnClaimTransaction(trans),
"[CLAIM]",
Color.SkyBlue,
Color.Black,
Color.SkyBlue,
2);
}
break;
case TransactionState.Claimed:
{
AddHtmlButton(
b.X,
b.Y + (b.Height - bh),
bw,
bh,
o => OnClaimedTransaction(trans),
"[CLAIMED]",
Color.LawnGreen,
Color.Black,
Color.LawnGreen,
2);
}
break;
}
if (_Admin)
{
bw /= 2;
AddHtmlButton(
b.X,
b.Y + (b.Height - (bh * 2)),
bw,
bh,
o => OnTransactionEdit(trans),
"[EDIT]",
Color.Gold,
Color.Black,
Color.Gold,
2);
AddHtmlButton(
b.X + bw,
b.Y + (b.Height - (bh * 2)),
bw,
bh,
o => OnTransactionTransfer(trans),
"[TRANSFER]",
Color.Gold,
Color.Black,
Color.Gold,
2);
}
}
protected virtual void GetTransactionOverview(
DonationTransaction trans,
StringBuilder info,
bool details,
bool exchange,
bool status)
{
if (details)
{
info.AppendLine();
info.AppendLine("Details");
info.AppendLine();
info.AppendLine("ID: {0}", trans.ID);
info.AppendLine("Date: {0}", trans.Time.Value);
if (_Admin)
{
info.AppendLine();
info.AppendLine("Notes: {0}", trans.Notes);
info.AppendLine();
info.AppendLine("Extra: {0}", trans.Extra);
}
}
if (exchange)
{
info.AppendLine();
info.AppendLine("Exchange");
info.AppendLine();
info.AppendLine(
"Value: {0}{1:#,0.00} {2}",
AutoDonate.CMOptions.MoneySymbol,
trans.Total,
AutoDonate.CMOptions.MoneyAbbr);
var total = trans.GetCredit(Profile, out var credit, out var bonus);
info.AppendLine("Credit: {0:#,0} {1}", credit, AutoDonate.CMOptions.CurrencyName);
info.AppendLine("Bonus: {0:#,0} {1}", bonus, AutoDonate.CMOptions.CurrencyName);
info.AppendLine("Total: {0:#,0} {1}", total, AutoDonate.CMOptions.CurrencyName);
}
if (status)
{
info.AppendLine();
info.AppendLine("Status");
info.AppendLine();
info.AppendLine("State: {0}", trans.State);
switch (trans.State)
{
case TransactionState.Voided:
info.AppendLine("Transaction has been voided.");
break;
case TransactionState.Pending:
info.AppendLine("Transaction is pending verification.");
break;
case TransactionState.Processed:
info.AppendLine("Transaction is complete and can be claimed.");
break;
case TransactionState.Claimed:
{
info.AppendLine("Transaction has been delivered.");
info.AppendLine();
info.AppendLine("Date: {0}", trans.DeliveryTime.Value);
if (trans.DeliveredTo != null)
{
info.AppendLine("Recipient: {0}", trans.DeliveredTo);
}
}
break;
}
}
}
public void GetProfileOverview(StringBuilder info)
{
var ms = AutoDonate.CMOptions.MoneySymbol;
var ma = AutoDonate.CMOptions.MoneyAbbr;
var cn = AutoDonate.CMOptions.CurrencyName;
var val = _DonationTier.ToString("#,0").WrapUOHtmlColor(Color.LawnGreen, HtmlColor);
info.AppendLine("Donation Tier: {0}", val);
val = _DonationValue.ToString("#,0.00").WrapUOHtmlColor(Color.LawnGreen, HtmlColor);
info.AppendLine("Donations Total: {0}{1} {2}", ms, val, ma);
val = _DonationCredit.ToString("#,0").WrapUOHtmlColor(Color.LawnGreen, HtmlColor);
info.AppendLine("Donations Claimed: {0} {1}", val, cn);
}
protected virtual void OnTransactionEdit(DonationTransaction trans)
{
Refresh();
if (_Admin)
{
User.SendGump(new PropertiesGump(User, trans));
}
}
protected virtual void OnTransactionTransfer(DonationTransaction trans)
{
new InputDialogGump(User, Refresh())
{
Title = "Transfer Transaction",
Html = "Enter the account name of the recipient for the transfer.",
InputText = trans.Account != null ? trans.Account.Username : String.Empty,
Callback = (b, a) =>
{
if (User.AccessLevel >= AutoDonate.Access)
{
var acc = Accounts.GetAccount(a);
if (acc == null)
{
User.SendMessage(34, "The account '{0}' does not exist.", a);
}
else if (trans.Account == acc)
{
User.SendMessage(34, "The transaction is already bound to '{0}'", a);
}
else
{
trans.SetAccount(acc);
User.SendMessage(85, "The transaction has been transferred to '{0}'", a);
}
}
Refresh(true);
}
}.Send();
}
protected virtual void OnVoidedTransaction(DonationTransaction trans)
{
var html = new StringBuilder();
GetTransactionOverview(trans, html, false, false, true);
new NoticeDialogGump(User, Refresh())
{
Title = "Transaction Voided",
Html = html.ToString()
}.Send();
}
protected virtual void OnPendingTransaction(DonationTransaction trans)
{
var html = new StringBuilder();
GetTransactionOverview(trans, html, false, false, true);
new NoticeDialogGump(User, Refresh())
{
Title = "Transaction Pending",
Html = html.ToString()
}.Send();
}
protected virtual void OnClaimTransaction(DonationTransaction trans)
{
var html = new StringBuilder();
GetTransactionOverview(trans, html, false, true, false);
html.AppendLine();
html.AppendLine("Click OK to claim this transaction!");
new ConfirmDialogGump(User, Refresh())
{
Title = "Reward Claim",
Html = html.ToString(),
AcceptHandler = b =>
{
if (trans.Claim(User))
{
SelectedNode = "Transactions|" + trans.FullPath;
User.SendMessage(85, "You claimed the transaction!");
}
Refresh(true);
}
}.Send();
}
protected virtual void OnClaimedTransaction(DonationTransaction trans)
{
var info = new StringBuilder();
GetTransactionOverview(trans, info, false, false, true);
new NoticeDialogGump(User, Refresh())
{
Title = "Reward Delivered",
Html = info.ToString()
}.Send();
}
protected override void OnDisposed()
{
_Indicies = null;
ObjectPool.Free(ref _Transactions);
base.OnDisposed();
}
}
}

View File

@@ -0,0 +1,248 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Items;
using Server.Misc;
#endregion
namespace VitaNex.Modules.AutoDonate
{
public static class DonationEvents
{
#region TransPending
public delegate void TransPending(TransPendingEventArgs e);
public static event TransPending OnTransPending;
public static void InvokeTransPending(DonationTransaction trans)
{
if (OnTransPending != null)
{
OnTransPending(new TransPendingEventArgs(trans));
}
}
public sealed class TransPendingEventArgs : EventArgs
{
public DonationTransaction Transaction { get; private set; }
public TransPendingEventArgs(DonationTransaction trans)
{
Transaction = trans;
}
}
#endregion TransPending
#region TransVoided
public delegate void TransVoided(TransVoidedEventArgs e);
public static event TransVoided OnTransVoided;
public static void InvokeTransVoided(DonationTransaction trans)
{
if (OnTransVoided != null)
{
OnTransVoided(new TransVoidedEventArgs(trans));
}
}
public sealed class TransVoidedEventArgs : EventArgs
{
public DonationTransaction Transaction { get; private set; }
public TransVoidedEventArgs(DonationTransaction trans)
{
Transaction = trans;
}
}
#endregion TransVoided
#region TransClaimed
public delegate void TransClaimed(TransClaimedEventArgs e);
public static event TransClaimed OnTransClaimed;
public static void InvokeTransClaimed(DonationTransaction trans, Mobile deliverTo)
{
if (OnTransClaimed != null)
{
OnTransClaimed(new TransClaimedEventArgs(trans, deliverTo));
}
}
public sealed class TransClaimedEventArgs : EventArgs
{
public DonationTransaction Transaction { get; private set; }
public Mobile DeliverTo { get; set; }
public TransClaimedEventArgs(DonationTransaction trans, Mobile deliverTo)
{
Transaction = trans;
DeliverTo = deliverTo;
}
}
#endregion TransClaimed
#region TransProcessed
public delegate void TransProcessed(TransProcessedEventArgs e);
public static event TransProcessed OnTransProcessed;
public static void InvokeTransProcessed(DonationTransaction trans)
{
if (OnTransProcessed != null)
{
OnTransProcessed(new TransProcessedEventArgs(trans));
}
}
public sealed class TransProcessedEventArgs : EventArgs
{
public DonationTransaction Transaction { get; private set; }
public TransProcessedEventArgs(DonationTransaction trans)
{
Transaction = trans;
}
}
#endregion TransProcessed
#region StateChanged
public delegate void StateChanged(StateChangedEventArgs e);
public static event StateChanged OnStateChanged;
public static void InvokeStateChanged(DonationTransaction trans, TransactionState oldState)
{
if (OnStateChanged != null)
{
OnStateChanged(new StateChangedEventArgs(trans, oldState));
}
}
public sealed class StateChangedEventArgs : EventArgs
{
public DonationTransaction Transaction { get; private set; }
public TransactionState OldState { get; private set; }
public StateChangedEventArgs(DonationTransaction trans, TransactionState oldState)
{
Transaction = trans;
OldState = oldState;
}
}
#endregion StateChanged
#region TransactionExchange
public delegate void TransExchanger(TransExchangeEventArgs e);
public static event TransExchanger OnTransExchange;
public static long InvokeTransExchange(DonationTransaction trans, DonationProfile dp)
{
var e = new TransExchangeEventArgs(trans, dp);
if (OnTransExchange != null)
{
OnTransExchange(e);
}
return e.Exchanged;
}
public sealed class TransExchangeEventArgs : EventArgs
{
public DonationTransaction Transaction { get; private set; }
public DonationProfile Profile { get; private set; }
public long Exchanged { get; set; }
public ulong Flags { get; set; }
public TransExchangeEventArgs(DonationTransaction trans, DonationProfile dp)
{
Transaction = trans;
Profile = dp;
Exchanged = Transaction.Credit;
}
}
#endregion
#region TransactionPack
public delegate void TransPacker(TransPackEventArgs e);
public static event TransPacker OnTransPack;
public static Container InvokeTransPack(DonationTransaction trans, DonationProfile dp)
{
var cont = new Bag
{
Name = ServerList.ServerName + " Donation Rewards",
Hue = 1152
};
var e = new TransPackEventArgs(trans, dp, cont);
OnTransPack?.Invoke(e);
return e.Container;
}
public sealed class TransPackEventArgs : EventArgs
{
public DonationTransaction Transaction { get; private set; }
public DonationProfile Profile { get; private set; }
public Container Container { get; set; }
public ulong Flags { get; set; }
public TransPackEventArgs(DonationTransaction trans, DonationProfile dp, Container cont)
{
Transaction = trans;
Profile = dp;
Container = cont;
}
}
#endregion
#region TransactionDeleted
public delegate void TransactionDeleted(TransactionDeletedEventArgs e);
public static event TransactionDeleted OnTransactionDeleted;
public static void InvokeTransactionDeleted(DonationTransaction trans)
{
if (OnTransactionDeleted != null)
{
OnTransactionDeleted(new TransactionDeletedEventArgs(trans));
}
}
public sealed class TransactionDeletedEventArgs : EventArgs
{
public DonationTransaction Transaction { get; private set; }
public TransactionDeletedEventArgs(DonationTransaction trans)
{
Transaction = trans;
}
}
#endregion StateChanged
}
}

View File

@@ -0,0 +1,678 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Accounting;
using Server.Mobiles;
using VitaNex.IO;
using VitaNex.Schedules;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public delegate void SeasonChangedHandler(PvPSeason newSeason, PvPSeason oldSeason);
public static partial class AutoPvP
{
public const AccessLevel Access = AccessLevel.Seer;
public static ScheduleInfo DefaultSeasonSchedule = new ScheduleInfo(ScheduleMonths.All, ScheduleDays.Monday, ScheduleTimes.Midnight);
public static AutoPvPOptions CMOptions { get; private set; }
public static BinaryDataStore<int, PvPSeason> Seasons { get; private set; }
public static BinaryDataStore<PlayerMobile, PvPProfile> Profiles { get; private set; }
public static BinaryDirectoryDataStore<PvPSerial, PvPBattle> Battles { get; private set; }
public static Dictionary<IAccount, Timer> Deserters { get; private set; }
public static Type[] BattleTypes { get; set; }
public static PvPScenario[] Scenarios { get; set; }
public static Schedule SeasonSchedule { get; set; }
public static PvPSeason CurrentSeason => EnsureSeason(CMOptions.Advanced.Seasons.CurrentSeason);
public static DateTime NextSeasonTime => SeasonSchedule.NextGlobalTick ?? DateTime.UtcNow;
private static DateTime LastSort { get; set; }
private static TimeSpan CacheDelay { get; set; }
private static List<PvPProfile> CachedSort { get; set; }
public static event Action<PvPSeason> OnSeasonChanged;
public static event Action<PvPBattle, PvPTeam, PlayerMobile> OnQueueJoin;
public static event Action<PvPBattle, PvPTeam, PlayerMobile> OnQueueLeave;
public static event Action<PvPBattle, PvPTeam, PlayerMobile> OnQueueUpdate;
public static event Action<PvPBattle, PvPRegion, Mobile> OnEnterBattle;
public static event Action<PvPBattle, PvPRegion, Mobile> OnExitBattle;
public static event Action<PvPBattle, string> OnBattleLocalBroadcast;
public static event Action<PvPBattle, string> OnBattleWorldBroadcast;
public static event Action<PvPBattle> OnBattleStateChanged;
public static void ChangeSeason(Schedule schedule)
{
if (!CMOptions.ModuleEnabled)
{
return;
}
if (CMOptions.Advanced.Seasons.SkippedTicks < CMOptions.Advanced.Seasons.SkipTicks)
{
++CMOptions.Advanced.Seasons.SkippedTicks;
return;
}
CMOptions.Advanced.Seasons.SkippedTicks = 0;
var old = CurrentSeason;
EnsureSeason(++CMOptions.Advanced.Seasons.CurrentSeason).Start();
old.End();
SeasonChanged(old);
}
public static void SeasonChanged(PvPSeason old)
{
var idx = 0;
foreach (var profile in GetSortedProfiles(old).Where(o => o.Owner.AccessLevel <= AccessLevel.Player))
{
if (idx < CMOptions.Advanced.Seasons.TopListCount)
{
IssueWinnerRewards(old, ++idx, profile);
}
else if (idx < CMOptions.Advanced.Seasons.TopListCount + CMOptions.Advanced.Seasons.RunnersUpCount)
{
IssueLoserRewards(old, ++idx, profile);
}
else
{
break;
}
}
if (OnSeasonChanged != null)
{
OnSeasonChanged(old);
}
}
public static void IssueWinnerRewards(this PvPSeason season, int rank, PvPProfile profile)
{
var rewards = CMOptions.Advanced.Seasons.Rewards.Winner.GiveReward(profile.Owner);
if (rewards == null)
{
rewards = new List<Item>();
}
else
{
var fmt = "{0} (Season {1} - Rank {2})";
rewards.ForEach(r => r.Name = String.Format(fmt, r.ResolveName(profile.Owner), season.Number, rank));
}
if (!season.Winners.TryGetValue(profile.Owner, out var list) || list == null)
{
season.Winners[profile.Owner] = rewards;
}
else
{
list.AddRange(rewards);
rewards.Free(true);
}
}
public static void IssueLoserRewards(this PvPSeason season, int rank, PvPProfile profile)
{
var rewards = CMOptions.Advanced.Seasons.Rewards.Loser.GiveReward(profile.Owner);
if (rewards == null)
{
rewards = new List<Item>();
}
else
{
var fmt = "{0} (Season {1} - Rank {2})";
rewards.ForEach(r => r.Name = String.Format(fmt, r.ResolveName(profile.Owner), season.Number, rank));
}
if (!season.Losers.TryGetValue(profile.Owner, out var list) || list == null)
{
season.Losers[profile.Owner] = rewards;
}
else
{
list.AddRange(rewards);
rewards.Free(true);
}
}
public static PvPSeason EnsureSeason(int num, bool replace = false)
{
if (!Seasons.TryGetValue(num, out var season) || season == null || replace)
{
Seasons[num] = season = new PvPSeason(num);
}
return season;
}
public static PvPProfile EnsureProfile(PlayerMobile pm, bool replace = false)
{
if (!Profiles.ContainsKey(pm))
{
Profiles.Add(pm, new PvPProfile(pm));
}
else if (replace || Profiles[pm] == null || Profiles[pm].Deleted)
{
Profiles[pm] = new PvPProfile(pm);
}
return Profiles[pm];
}
public static IEnumerable<PvPProfile> GetSortedProfiles(PvPSeason season = null)
{
return GetSortedProfiles(CMOptions.Advanced.Profiles.RankingOrder, season);
}
public static IEnumerable<PvPProfile> GetSortedProfiles(IEnumerable<PvPProfile> profiles, PvPSeason season = null)
{
return GetSortedProfiles(CMOptions.Advanced.Profiles.RankingOrder, profiles, season);
}
public static IEnumerable<PvPProfile> GetSortedProfiles(PvPProfileRankOrder order, PvPSeason season = null)
{
return GetSortedProfiles(order, null, season);
}
public static IEnumerable<PvPProfile> GetSortedProfiles(PvPProfileRankOrder order, IEnumerable<PvPProfile> profiles, PvPSeason season = null)
{
if (profiles == null)
{
profiles = Profiles.Values;
if (Profiles.Count > 1024)
{
profiles = profiles.AsParallel();
}
}
return profiles.OrderByDescending(p => GetSortedValue(order, p, season));
}
public static long GetSortedValue(PvPProfileRankOrder order, PvPProfile profile, PvPSeason season = null)
{
switch (order)
{
case PvPProfileRankOrder.Points:
{
if (season == null)
{
return profile.TotalPoints;
}
return profile.History.EnsureEntry(season).Points;
}
case PvPProfileRankOrder.Wins:
{
if (season == null)
{
return profile.TotalWins;
}
return profile.History.EnsureEntry(season).Wins;
}
case PvPProfileRankOrder.Kills:
{
if (season == null)
{
return profile.TotalKills;
}
return profile.History.EnsureEntry(season).Kills;
}
}
return 0;
}
public static void InvokeQueueJoin(PvPBattle battle, PvPTeam team, PlayerMobile m)
{
if (OnQueueJoin != null)
{
OnQueueJoin(battle, team, m);
}
}
public static void InvokeQueueLeave(PvPBattle battle, PvPTeam team, PlayerMobile m)
{
if (OnQueueLeave != null)
{
OnQueueLeave(battle, team, m);
}
}
public static void InvokeQueueUpdate(PvPBattle battle, PvPTeam team, PlayerMobile m)
{
if (OnQueueUpdate != null)
{
OnQueueUpdate(battle, team, m);
}
}
public static void InvokeEnterBattle(PvPBattle battle, PvPRegion region, Mobile m)
{
if (OnEnterBattle != null)
{
OnEnterBattle(battle, region, m);
}
}
public static void InvokeExitBattle(PvPBattle battle, PvPRegion region, Mobile m)
{
if (OnExitBattle != null)
{
OnExitBattle(battle, region, m);
}
}
public static void InvokeBattleLocalBroadcast(PvPBattle battle, string message)
{
if (OnBattleLocalBroadcast != null)
{
OnBattleLocalBroadcast(battle, message);
}
}
public static void InvokeBattleWorldBroadcast(PvPBattle battle, string message)
{
if (OnBattleWorldBroadcast != null)
{
OnBattleWorldBroadcast(battle, message);
}
}
public static void InvokeBattleStateChanged(PvPBattle battle)
{
if (OnBattleStateChanged != null)
{
OnBattleStateChanged(battle);
}
}
public static PvPBattle FindBattleByID(int uid)
{
return Battles.Where(o => o.Key.ValueHash.Equals(uid)).Select(kvp => kvp.Value).FirstOrDefault();
}
public static PvPBattle FindBattleByID(PvPSerial serial)
{
return Battles.Where(o => o.Key.Equals(serial)).Select(kvp => kvp.Value).FirstOrDefault();
}
public static PvPBattle FindBattle(PlayerMobile pm)
{
return FindBattle<PvPBattle>(pm);
}
public static T FindBattle<T>(PlayerMobile pm)
where T : PvPBattle
{
if (IsParticipant(pm, out T battle) || IsSpectator(pm, out battle))
{
return battle;
}
return default(T);
}
public static bool IsParticipant(PlayerMobile pm)
{
return pm != null && IsParticipant<PvPBattle>(pm);
}
public static bool IsParticipant<T>(PlayerMobile pm)
where T : PvPBattle
{
return pm != null && Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>().Any(b => b.IsParticipant(pm));
}
public static bool IsParticipant<T>(PlayerMobile pm, out T battle)
where T : PvPBattle
{
battle = default(T);
if (pm == null)
{
return false;
}
battle = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>().FirstOrDefault(b => b.IsParticipant(pm));
return battle != null;
}
public static ILookup<PvPBattle, IEnumerable<PlayerMobile>> GetParticipants()
{
return GetParticipants<PvPBattle>();
}
public static ILookup<T, IEnumerable<PlayerMobile>> GetParticipants<T>()
where T : PvPBattle
{
var battles = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>();
return battles.ToLookup(b => b, b => b.GetParticipants());
}
public static ILookup<PvPBattle, int> CountParticipants()
{
return CountParticipants<PvPBattle>();
}
public static ILookup<T, int> CountParticipants<T>()
where T : PvPBattle
{
var battles = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>();
return battles.ToLookup(b => b, b => b.GetParticipants().Count());
}
public static int TotalParticipants()
{
return TotalParticipants<PvPBattle>();
}
public static int TotalParticipants<T>()
where T : PvPBattle
{
var battles = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>();
return battles.Aggregate(0, (c, b) => c + b.GetParticipants().Count());
}
public static bool IsSpectator(PlayerMobile pm)
{
return pm != null && IsSpectator<PvPBattle>(pm);
}
public static bool IsSpectator<T>(PlayerMobile pm)
where T : PvPBattle
{
return pm != null && Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>().Any(b => b.IsSpectator(pm));
}
public static bool IsSpectator<T>(PlayerMobile pm, out T battle)
where T : PvPBattle
{
battle = default(T);
if (pm == null)
{
return false;
}
battle = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>().FirstOrDefault(b => b.IsSpectator(pm));
return battle != null;
}
public static ILookup<PvPBattle, IEnumerable<PlayerMobile>> GetSpectators()
{
return GetSpectators<PvPBattle>();
}
public static ILookup<T, IEnumerable<PlayerMobile>> GetSpectators<T>()
where T : PvPBattle
{
var battles = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>();
return battles.ToLookup(b => b, b => b.GetSpectators());
}
public static ILookup<PvPBattle, int> CountSpectators()
{
return CountSpectators<PvPBattle>();
}
public static ILookup<T, int> CountSpectators<T>()
where T : PvPBattle
{
var battles = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>();
return battles.ToLookup(b => b, b => b.Spectators.Count);
}
public static int TotalSpectators()
{
return TotalSpectators<PvPBattle>();
}
public static int TotalSpectators<T>()
where T : PvPBattle
{
var battles = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>();
return battles.Aggregate(0, (c, b) => c + b.Spectators.Count);
}
public static void AddDeserter(PlayerMobile pm)
{
AddDeserter(pm, true);
}
public static void AddDeserter(PlayerMobile pm, bool message)
{
SetDeserter(pm, true, message);
}
public static void RemoveDeserter(PlayerMobile pm)
{
RemoveDeserter(pm, true);
}
public static void RemoveDeserter(PlayerMobile pm, bool message)
{
SetDeserter(pm, false, message);
}
public static void SetDeserter(PlayerMobile pm, bool state, bool message)
{
if (pm == null)
{
return;
}
var t = Deserters.GetValue(pm.Account);
if (t != null && t.Running)
{
t.Stop();
}
if (state && CMOptions.Advanced.Misc.DeserterLockout > TimeSpan.Zero)
{
Deserters[pm.Account] = t = Timer.DelayCall(CMOptions.Advanced.Misc.DeserterLockout, RemoveDeserter, pm);
if (message)
{
pm.SendMessage(0x22, "You have deserted your team and must wait until you can join another battle.");
}
if (!CMOptions.Advanced.Misc.DeserterAssoc)
{
return;
}
foreach (var a in pm.Account.FindSharedAccounts().Where(a => a != pm.Account && !Deserters.ContainsKey(a)))
{
Deserters[a] = t;
var p = a.GetOnlineMobile();
if (p != null)
{
p.SendMessage(0x22, "{0} has deserted a battle!", pm.RawName);
p.SendMessage(0x22, "You must wait until you can join a battle because you have associated accounts.");
}
}
}
else
{
if (Deserters.Remove(pm.Account) && message)
{
pm.SendMessage(0x55, "You are no longer known as a deserter and may now join battles.");
}
if (t == null)
{
return;
}
Deserters.RemoveRange(
o =>
{
if (o.Value == null)
{
return true;
}
if (o.Value == t)
{
var p = o.Key.GetOnlineMobile();
if (p != null)
{
p.SendMessage(0x55, "You are no longer associated with a deserter and may now join battles.");
}
return true;
}
return false;
});
}
}
public static bool IsDeserter(PlayerMobile pm)
{
return pm != null && pm.Account != null && Deserters.GetValue(pm.Account) != null;
}
public static IEnumerable<PvPBattle> GetBattles(params PvPBattleState[] states)
{
return GetBattles<PvPBattle>(states);
}
public static IEnumerable<T> GetBattles<T>(params PvPBattleState[] states)
where T : PvPBattle
{
if (states == null || states.Length == 0)
{
return Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>();
}
return Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>().Where(b => states.Contains(b.State));
}
public static int CountBattles(params PvPBattleState[] states)
{
return CountBattles<PvPBattle>(states);
}
public static int CountBattles<T>(params PvPBattleState[] states)
where T : PvPBattle
{
if (states == null || states.Length == 0)
{
return Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>().Count();
}
return Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>().Count(b => states.Contains(b.State));
}
public static void DeleteAllBattles()
{
Battles.Values.Where(b => b != null && !b.Deleted).ForEach(b => b.Delete());
}
public static void InternalizeAllBattles()
{
Battles.Values.Where(b => b != null && !b.Deleted).ForEach(b => b.State = PvPBattleState.Internal);
}
public static PvPBattle CreateBattle(PvPScenario scenario)
{
if (scenario == null)
{
return null;
}
var battle = scenario.CreateBattle();
Battles[battle.Serial] = battle;
battle.Init();
return battle;
}
public static bool RemoveBattle(PvPBattle battle)
{
return battle != null && Battles.Remove(battle.Serial);
}
public static bool RemoveProfile(PvPProfile profile)
{
if (profile != null && Profiles.GetValue(profile.Owner) == profile && Profiles.Remove(profile.Owner))
{
profile.Remove();
return true;
}
return false;
}
public static void DeleteAllProfiles()
{
Profiles.Values.Where(p => p != null && !p.Deleted).ForEach(p => p.Delete());
}
public static int TotalQueued()
{
return TotalQueued<PvPBattle>();
}
public static int TotalQueued<T>()
where T : PvPBattle
{
var battles = Battles.Values.Where(b => b != null && !b.Deleted).OfType<T>();
return battles.Aggregate(0, (c, b) => c + b.Queue.Count);
}
}
}

View File

@@ -0,0 +1,495 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Accounting;
using Server.Mobiles;
using VitaNex.IO;
using VitaNex.Schedules;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[CoreModule("Auto PvP", "3.1.0.0", false, TaskPriority.High)]
public static partial class AutoPvP
{
static AutoPvP()
{
CMOptions = new AutoPvPOptions();
Scenarios = new PvPScenario[0];
BattleTypes = typeof(PvPBattle).GetConstructableChildren();
SeasonSchedule = new Schedule(CMOptions.ModuleName + " Seasons", false, DefaultSeasonSchedule);
Seasons = new BinaryDataStore<int, PvPSeason>(VitaNexCore.SavesDirectory + "/AutoPvP", "Seasons")
{
OnSerialize = SerializeSeasons,
OnDeserialize = DeserializeSeasons
};
Battles = new BinaryDirectoryDataStore<PvPSerial, PvPBattle>(VitaNexCore.SavesDirectory + "/AutoPvP", "Battles", "pvp")
{
OnSerialize = SerializeBattle,
OnDeserialize = DeserializeBattle
};
Profiles = new BinaryDataStore<PlayerMobile, PvPProfile>(VitaNexCore.SavesDirectory + "/AutoPvP", "Profiles")
{
Async = true,
OnSerialize = SerializeProfiles,
OnDeserialize = DeserializeProfiles
};
Deserters = new Dictionary<IAccount, Timer>();
}
private static void CMConfig()
{
SeasonSchedule.OnGlobalTick += ChangeSeason;
}
private static void CMEnabled()
{
PvPBattle.Bind();
BattleNotoriety.Enable();
}
private static void CMDisabled()
{
InternalizeAllBattles();
PvPBattle.Unbind();
BattleNotoriety.Disable();
}
private static void CMInvoke()
{
PvPBattle.Bind();
BattleNotoriety.Enable();
var scenarios = new List<PvPScenario>();
foreach (var type in BattleTypes.Where(t => t != null))
{
VitaNexCore.TryCatch(
() =>
{
var battle = type.CreateInstanceSafe<PvPBattle>();
if (battle == null)
{
throw new Exception("PvPBattle Type could not be constructed, requires a constructor with 0 arguments.");
}
PvPScenario scenario = battle;
scenarios.Add(scenario);
battle.Delete();
CMOptions.ToConsole("Created scenario ({0}) '{1}'", scenario.TypeOf.Name, scenario.Name);
},
CMOptions.ToConsole);
}
Scenarios = scenarios.ToArray();
scenarios.Clear();
foreach (var battle in Battles.Values.Where(b => b != null && !b.Deleted).ToArray())
{
VitaNexCore.TryCatch(
battle.Init,
ex =>
{
VitaNexCore.TryCatch(battle.Delete);
CMOptions.ToConsole("Failed to initialize battle #{0} '{1}'", battle.Serial, battle.Name);
CMOptions.ToConsole(ex);
});
}
foreach (var profile in Profiles.Values.Where(p => p != null && !p.Deleted).ToArray())
{
VitaNexCore.TryCatch(
profile.Init,
ex =>
{
VitaNexCore.TryCatch(profile.Delete);
CMOptions.ToConsole("Failed to initialize profile #{0} '{1}'", profile.Owner.Serial.Value, profile.Owner.RawName);
CMOptions.ToConsole(ex);
});
}
}
private static void CMSave()
{
Save();
Sync();
}
private static void CMLoad()
{
Load();
Sync();
}
public static void Save()
{
VitaNexCore.TryCatch(SaveSeasons, CMOptions.ToConsole);
VitaNexCore.TryCatch(SaveBattles, CMOptions.ToConsole);
VitaNexCore.TryCatch(SaveProfiles, CMOptions.ToConsole);
}
public static void SaveSeasons()
{
var result = Seasons.Export();
CMOptions.ToConsole("Result: {0}", result.ToString());
switch (result)
{
case DataStoreResult.Null:
case DataStoreResult.Busy:
case DataStoreResult.Error:
{
if (Seasons.HasErrors)
{
CMOptions.ToConsole("Seasons database has errors...");
Seasons.Errors.ForEach(CMOptions.ToConsole);
}
}
break;
case DataStoreResult.OK:
CMOptions.ToConsole("Season count: {0:#,0}", Seasons.Count);
break;
}
}
public static void SaveProfiles()
{
var result = Profiles.Export();
CMOptions.ToConsole("Result: {0}", result.ToString());
switch (result)
{
case DataStoreResult.Null:
case DataStoreResult.Busy:
case DataStoreResult.Error:
{
if (Profiles.HasErrors)
{
CMOptions.ToConsole("Profiles database has errors...");
Profiles.Errors.ForEach(CMOptions.ToConsole);
}
}
break;
case DataStoreResult.OK:
CMOptions.ToConsole("Profile count: {0:#,0}", Profiles.Count);
break;
}
}
public static void SaveBattles()
{
var result = Battles.Export();
CMOptions.ToConsole("Result: {0}", result.ToString());
switch (result)
{
case DataStoreResult.Null:
case DataStoreResult.Busy:
case DataStoreResult.Error:
{
if (Battles.HasErrors)
{
CMOptions.ToConsole("Battles database has errors...");
Battles.Errors.ForEach(CMOptions.ToConsole);
}
}
break;
case DataStoreResult.OK:
CMOptions.ToConsole("Battle count: {0:#,0}", Battles.Count);
break;
}
}
public static void Load()
{
VitaNexCore.TryCatch(LoadSeasons, CMOptions.ToConsole);
VitaNexCore.TryCatch(LoadBattles, CMOptions.ToConsole);
VitaNexCore.TryCatch(LoadProfiles, CMOptions.ToConsole);
}
public static void LoadSeasons()
{
var result = Seasons.Import();
CMOptions.ToConsole("Result: {0}", result.ToString());
switch (result)
{
case DataStoreResult.Null:
case DataStoreResult.Busy:
case DataStoreResult.Error:
{
if (Seasons.HasErrors)
{
CMOptions.ToConsole("Seasons database has errors...");
Seasons.Errors.ForEach(CMOptions.ToConsole);
}
}
break;
case DataStoreResult.OK:
CMOptions.ToConsole("Season count: {0:#,0}", Seasons.Count);
break;
}
}
public static void LoadProfiles()
{
var result = Profiles.Import();
CMOptions.ToConsole("Result: {0}", result.ToString());
switch (result)
{
case DataStoreResult.Null:
case DataStoreResult.Busy:
case DataStoreResult.Error:
{
if (Profiles.HasErrors)
{
CMOptions.ToConsole("Profiles database has errors...");
Profiles.Errors.ForEach(CMOptions.ToConsole);
}
}
break;
case DataStoreResult.OK:
CMOptions.ToConsole("Profile count: {0:#,0}", Profiles.Count);
break;
}
}
public static void LoadBattles()
{
var result = Battles.Import();
CMOptions.ToConsole("Result: {0}", result.ToString());
switch (result)
{
case DataStoreResult.Null:
case DataStoreResult.Busy:
case DataStoreResult.Error:
{
if (Battles.HasErrors)
{
CMOptions.ToConsole("Battles database has errors...");
Battles.Errors.ForEach(CMOptions.ToConsole);
}
}
break;
case DataStoreResult.OK:
CMOptions.ToConsole("Battle count: {0:#,0}", Battles.Count);
break;
}
}
public static void Sync()
{
VitaNexCore.TryCatch(SyncSeasons, CMOptions.ToConsole);
VitaNexCore.TryCatch(SyncBattles, CMOptions.ToConsole);
}
public static void SyncSeasons()
{
foreach (var season in Seasons.Values)
{
VitaNexCore.TryCatch(
season.Sync,
ex =>
{
CMOptions.ToConsole("Failed to sync season #{0}", season.Number);
CMOptions.ToConsole(ex);
});
}
}
public static void SyncBattles()
{
foreach (var battle in Battles.Values)
{
VitaNexCore.TryCatch(
battle.Sync,
ex =>
{
CMOptions.ToConsole("Failed to sync battle #{0} '{1}'", battle.Serial, battle.Name);
CMOptions.ToConsole(ex);
});
}
}
private static bool SerializeSeasons(GenericWriter writer)
{
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteBlockDictionary(
Seasons,
(w, key, val) =>
{
w.Write(key);
w.WriteType(val, t => val.Serialize(w));
});
}
break;
}
return true;
}
private static bool DeserializeSeasons(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 0:
{
reader.ReadBlockDictionary(
r =>
{
var key = r.ReadInt();
var val = r.ReadTypeCreate<PvPSeason>(r) ?? new PvPSeason(key);
return new KeyValuePair<int, PvPSeason>(key, val);
},
Seasons);
}
break;
}
return true;
}
private static bool SerializeProfiles(GenericWriter writer)
{
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteBlockDictionary(
Profiles,
(w, key, val) =>
{
w.Write(key);
w.WriteType(val, t => val.Serialize(w));
});
}
break;
}
return true;
}
private static bool DeserializeProfiles(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 0:
{
reader.ReadBlockDictionary(
r =>
{
var key = r.ReadMobile<PlayerMobile>();
var val = r.ReadTypeCreate<PvPProfile>(r);
return new KeyValuePair<PlayerMobile, PvPProfile>(key, val);
},
Profiles);
}
break;
}
return true;
}
private static bool SerializeBattle(GenericWriter writer, PvPSerial key, PvPBattle val)
{
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteBlock(w => w.WriteType(key, t => key.Serialize(w)));
writer.WriteBlock(w => w.WriteType(val, t => val.Serialize(w)));
}
break;
}
return true;
}
private static Tuple<PvPSerial, PvPBattle> DeserializeBattle(GenericReader reader)
{
PvPSerial key = null;
PvPBattle val = null;
var version = reader.GetVersion();
switch (version)
{
case 0:
{
key = reader.ReadBlock(r => r.ReadTypeCreate<PvPSerial>(r));
val = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattle>(r));
}
break;
}
if (key == null)
{
if (val != null && val.Serial != null)
{
key = val.Serial;
}
else
{
return null;
}
}
return new Tuple<PvPSerial, PvPBattle>(key, val);
}
}
}

View File

@@ -0,0 +1,282 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Mobiles;
using VitaNex.Schedules;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class CTFBattle : PvPBattle
{
[CommandProperty(AutoPvP.Access)]
public virtual double FlagDamageInc { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual double FlagDamageIncMax { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int FlagCapturePoints { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int FlagReturnPoints { get; set; }
public CTFBattle()
{
Name = "Capture The Flag";
Category = "Capture The Flag";
Description = "Capture the enemy flag and return it to your podium to score points!" +
"\nDefend your flag from the enemy, you can only capture their flag when your flag is on your podium.";
AddTeam(NameList.RandomName("daemon"), 1, 5, 0x22);
AddTeam(NameList.RandomName("daemon"), 1, 5, 0x55);
Options.Missions.Enabled = true;
Options.Missions.Team = new CTFBattleObjectives
{
FlagsCaptured = 5
};
Schedule.Info.Months = ScheduleMonths.All;
Schedule.Info.Days = ScheduleDays.All;
Schedule.Info.Times = ScheduleTimes.EveryQuarterHour;
Options.Timing.QueuePeriod = TimeSpan.FromMinutes(5.0);
Options.Timing.PreparePeriod = TimeSpan.FromMinutes(5.0);
Options.Timing.RunningPeriod = TimeSpan.FromMinutes(15.0);
Options.Timing.EndedPeriod = TimeSpan.FromMinutes(5.0);
Options.Rules.AllowBeneficial = true;
Options.Rules.AllowHarmful = true;
Options.Rules.AllowHousing = false;
Options.Rules.AllowPets = false;
Options.Rules.AllowSpawn = false;
Options.Rules.AllowSpeech = true;
Options.Rules.CanBeDamaged = true;
Options.Rules.CanDamageEnemyTeam = true;
Options.Rules.CanDamageOwnTeam = false;
Options.Rules.CanDie = false;
Options.Rules.CanHeal = true;
Options.Rules.CanHealEnemyTeam = false;
Options.Rules.CanHealOwnTeam = true;
Options.Rules.CanMount = false;
Options.Rules.CanFly = false;
Options.Rules.CanResurrect = true;
Options.Rules.CanUseStuckMenu = false;
Options.Rules.CanEquip = true;
}
public CTFBattle(GenericReader reader)
: base(reader)
{ }
public override bool Validate(Mobile viewer, List<string> errors, bool pop = true)
{
if (!base.Validate(viewer, errors, pop) && pop)
{
return false;
}
if (!Teams.All(t => t is CTFTeam))
{
errors.Add("One or more teams are not of the CTFTeam type.");
errors.Add("[Options] -> [View Teams]");
if (pop)
{
return false;
}
}
return true;
}
public override bool AddTeam(string name, int minCapacity, int capacity, int color)
{
return AddTeam(new CTFTeam(this, name, minCapacity, capacity, color));
}
public override bool AddTeam(PvPTeam team)
{
if (team == null || team.Deleted)
{
return false;
}
if (team is CTFTeam)
{
return base.AddTeam(team);
}
var added = AddTeam(team.Name, team.MinCapacity, team.MinCapacity, team.Color);
team.Delete();
return added;
}
public virtual void OnFlagDropped(CTFFlag flag, PlayerMobile attacker, CTFTeam enemyTeam)
{
UpdateStatistics(enemyTeam, attacker, s => ++s["Flags Dropped"]);
PlaySound(746);
LocalBroadcast("[{0}]: {1} has dropped the flag of {2}!", enemyTeam.Name, attacker.Name, flag.Team.Name);
}
public virtual void OnFlagCaptured(CTFFlag flag, PlayerMobile attacker, CTFTeam enemyTeam)
{
UpdateStatistics(enemyTeam, attacker, s => ++s["Flags Captured"]);
if (FlagCapturePoints > 0)
{
AwardPoints(attacker, FlagCapturePoints);
}
PlaySound(747);
LocalBroadcast("[{0}]: {1} has captured the flag of {2}!", enemyTeam.Name, attacker.Name, flag.Team.Name);
}
public virtual void OnFlagStolen(CTFFlag flag, PlayerMobile attacker, CTFTeam enemyTeam)
{
UpdateStatistics(enemyTeam, attacker, s => ++s["Flags Stolen"]);
PlaySound(748);
LocalBroadcast("[{0}]: {1} has stolen the flag of {2}!", enemyTeam.Name, attacker.Name, flag.Team.Name);
}
public virtual void OnFlagReturned(CTFFlag flag, PlayerMobile defender)
{
UpdateStatistics(flag.Team, defender, s => ++s["Flags Returned"]);
if (FlagReturnPoints > 0)
{
AwardPoints(defender, FlagReturnPoints);
}
PlaySound(749);
LocalBroadcast("[{0}]: {1} has returned the flag of {0}!", flag.Team.Name, defender.Name);
}
public virtual void OnFlagTimeout(CTFFlag flag)
{
PlaySound(749);
LocalBroadcast("[{0}]: Flag has been returned to the base!", flag.Team.Name);
}
public override bool CheckDamage(Mobile damaged, ref int damage)
{
if (!base.CheckDamage(damaged, ref damage))
{
return false;
}
if (damaged != null && damaged.Player && damaged.Backpack != null && damage > 0)
{
var flag = damaged.Backpack.FindItemByType<CTFFlag>();
if (flag != null)
{
damage += (int)(damage * flag.DamageInc);
}
}
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(3);
switch (version)
{
case 3:
case 2:
{
writer.Write(FlagDamageInc);
writer.Write(FlagDamageIncMax);
}
goto case 1;
case 1:
{
writer.Write(FlagCapturePoints);
writer.Write(FlagReturnPoints);
}
goto case 0;
case 0:
writer.Write(-1); // CapsToWin
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
if (!(Options.Missions.Team is CTFBattleObjectives))
{
Options.Missions.Enabled = true;
Options.Missions.Team = new CTFBattleObjectives
{
FlagsCaptured = 5
};
}
var version = reader.ReadInt();
switch (version)
{
case 3:
case 2:
{
FlagDamageInc = reader.ReadDouble();
FlagDamageIncMax = reader.ReadDouble();
}
goto case 1;
case 1:
{
FlagCapturePoints = reader.ReadInt();
FlagReturnPoints = reader.ReadInt();
}
goto case 0;
case 0:
{
var capsToWin = reader.ReadInt();
if (capsToWin >= 0)
{
((CTFBattleObjectives)Options.Missions.Team).FlagsCaptured = capsToWin;
}
}
break;
}
if (version < 3)
{
RewardTeam = true;
}
}
}
}

View File

@@ -0,0 +1,313 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Drawing;
using System.Text;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class CTFBattleObjectives : PvPBattleObjectives
{
[CommandProperty(AutoPvP.Access)]
public long FlagsCaptured { get; set; }
[CommandProperty(AutoPvP.Access)]
public long FlagsDropped { get; set; }
[CommandProperty(AutoPvP.Access)]
public long FlagsStolen { get; set; }
[CommandProperty(AutoPvP.Access)]
public long FlagsReturned { get; set; }
public override bool IsEmpty => base.IsEmpty && FlagsCaptured + FlagsDropped + FlagsStolen + FlagsReturned <= 0;
public CTFBattleObjectives()
{ }
public CTFBattleObjectives(GenericReader reader)
: base(reader)
{ }
public override void SetDefaults()
{
base.SetDefaults();
FlagsCaptured = 0;
FlagsDropped = 0;
FlagsStolen = 0;
FlagsReturned = 0;
}
public override double ComputeScore(PvPTeam t, ref double min, ref double max, ref double total)
{
var score = base.ComputeScore(t, ref min, ref max, ref total);
if (t == null || t.Deleted)
{
return score;
}
var ct = t as CTFTeam;
if (ct == null)
{
return score;
}
double val;
if (FlagsCaptured > 0)
{
score += val = Math.Min(1.0, ct.GetTotalFlagsCaptured() / (double)FlagsCaptured);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (FlagsDropped > 0)
{
score += val = Math.Min(1.0, ct.GetTotalFlagsDropped() / (double)FlagsDropped);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (FlagsStolen > 0)
{
score += val = Math.Min(1.0, ct.GetTotalFlagsStolen() / (double)FlagsStolen);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (FlagsReturned > 0)
{
score += val = Math.Min(1.0, ct.GetTotalFlagsReturned() / (double)FlagsReturned);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
return score;
}
public override double ComputeScore(PvPBattle b, PlayerMobile p, ref double min, ref double max, ref double total)
{
var score = base.ComputeScore(b, p, ref min, ref max, ref total);
if (b == null || b.Deleted)
{
return score;
}
if (p == null || p.Deleted)
{
return score;
}
double val;
if (FlagsCaptured > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o["Flags Captured"]) / (double)FlagsCaptured);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (FlagsDropped > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o["Flags Dropped"]) / (double)FlagsDropped);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (FlagsStolen > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o["Flags Stolen"]) / (double)FlagsStolen);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (FlagsReturned > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o["Flags Returned"]) / (double)FlagsReturned);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
return score;
}
public override string GetStatus(PvPTeam t)
{
var status = base.GetStatus(t);
if (t == null || t.Deleted)
{
return status;
}
var ct = t as CTFTeam;
if (ct == null)
{
return status;
}
var lines = new StringBuilder(status);
if (FlagsCaptured > 0)
{
lines.AppendLine("Flags Captured: {0:#,0} / {1:#,0}", ct.GetTotalFlagsCaptured(), FlagsCaptured);
}
if (FlagsDropped > 0)
{
lines.AppendLine("Flags Dropped: {0:#,0} / {1:#,0}", ct.GetTotalFlagsDropped(), FlagsDropped);
}
if (FlagsStolen > 0)
{
lines.AppendLine("Flags Stolen: {0:#,0} / {1:#,0}", ct.GetTotalFlagsStolen(), FlagsStolen);
}
if (FlagsReturned > 0)
{
lines.AppendLine("Flags Returned: {0:#,0} / {1:#,0}", ct.GetTotalFlagsReturned(), FlagsReturned);
}
return lines.ToString();
}
public override string GetStatus(PvPBattle b, PlayerMobile p)
{
var status = base.GetStatus(b, p);
if (b == null || b.Deleted)
{
return status;
}
if (p == null || p.Deleted)
{
return status;
}
var lines = new StringBuilder(status);
if (FlagsCaptured > 0)
{
lines.AppendLine("Flags Captured: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o["Flags Captured"]), FlagsCaptured);
}
if (FlagsDropped > 0)
{
lines.AppendLine("Flags Dropped: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o["Flags Dropped"]), FlagsDropped);
}
if (FlagsStolen > 0)
{
lines.AppendLine("Flags Stolen: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o["Flags Stolen"]), FlagsStolen);
}
if (FlagsReturned > 0)
{
lines.AppendLine("Flags Returned: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o["Flags Returned"]), FlagsReturned);
}
return lines.ToString();
}
public override void GetHtmlString(StringBuilder html)
{
base.GetHtmlString(html);
var len = html.Length;
if (FlagsCaptured > 0)
{
html.AppendLine("Flags Captured: {0:#,0}", FlagsCaptured);
}
if (FlagsDropped > 0)
{
html.AppendLine("Flags Dropped: {0:#,0}", FlagsDropped);
}
if (FlagsStolen > 0)
{
html.AppendLine("Flags Stolen: {0:#,0}", FlagsStolen);
}
if (FlagsReturned > 0)
{
html.AppendLine("Flags Returned: {0:#,0}", FlagsReturned);
}
if (len < html.Length)
{
html.Insert(len, String.Empty.WrapUOHtmlColor(Color.PaleGoldenrod, false));
html.AppendLine(String.Empty.WrapUOHtmlColor(Color.White, false));
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(FlagsCaptured);
writer.Write(FlagsDropped);
writer.Write(FlagsStolen);
writer.Write(FlagsReturned);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
FlagsCaptured = reader.ReadLong();
FlagsDropped = reader.ReadLong();
FlagsStolen = reader.ReadLong();
FlagsReturned = reader.ReadLong();
}
}
}

View File

@@ -0,0 +1,447 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Mobiles;
using VitaNex.FX;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class CTFFlag : Item
{
private static readonly TimeSpan SplitSecond = TimeSpan.FromMilliseconds(250.0);
private static readonly TimeSpan HalfSecond = TimeSpan.FromSeconds(0.5);
private static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1.0);
private static readonly TimeSpan FiveSeconds = TimeSpan.FromSeconds(5.0);
private static readonly TimeSpan TenSeconds = TimeSpan.FromSeconds(10.0);
private static readonly TimeSpan TwentySeconds = TimeSpan.FromSeconds(20.0);
private DateTime _NextMultiUpdate = DateTime.UtcNow;
private DateTime _NextFlagReturn = DateTime.UtcNow;
[CommandProperty(AutoPvP.Access)]
public virtual CTFTeam Team { get; set; }
private PlayerMobile _Carrier;
[CommandProperty(AutoPvP.Access)]
public virtual PlayerMobile Carrier
{
get => _Carrier;
set
{
if (_Carrier == null || _Carrier == value)
{
return;
}
if (value == null)
{
Drop(_Carrier);
}
else
{
Drop(_Carrier);
Steal(value);
}
}
}
[CommandProperty(AutoPvP.Access)]
public virtual double DamageInc { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual DateTime NextAssault { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual DateTime NextEffect { get; set; }
public override bool HandlesOnMovement => RootParent == null;
public override bool Nontransferable => RootParent != null;
public override bool IsVirtualItem => RootParent != null;
public CTFFlag(CTFTeam team)
: base(8351)
{
Team = team;
Name = Team.Name;
Hue = Team.Color;
Weight = 10.1;
Movable = false;
NextAssault = NextEffect = DateTime.UtcNow;
}
public CTFFlag(Serial serial)
: base(serial)
{ }
public CTFTeam GetTeam(PlayerMobile pm)
{
return Team.Battle.FindTeam<CTFTeam>(pm);
}
public void Reset()
{
if (Team == null || Team.Deleted || Team.Battle == null || Team.Battle.Deleted)
{
Delete();
return;
}
if (Team.FlagPodium != null && !Team.FlagPodium.Deleted)
{
MoveToWorld(Team.FlagPodium.Location.Clone3D(0, 0, Team.FlagPodium.ItemData.Height + 5), Team.FlagPodium.Map);
DamageInc = 0;
}
else
{
MoveToWorld(Team.HomeBase, Team.Battle.Options.Locations.Map);
DamageInc = 0;
}
NextAssault = DateTime.UtcNow;
}
public void Drop(PlayerMobile attacker)
{
if (Team == null || Team.Deleted || Team.Battle == null || Team.Battle.Deleted)
{
Delete();
return;
}
if (attacker == null || attacker.Deleted || attacker != _Carrier)
{
return;
}
var enemy = GetTeam(attacker);
if (enemy != null)
{
attacker.SolidHueOverride = enemy.Color;
}
NextAssault = DateTime.UtcNow + FiveSeconds;
_Carrier = null;
_NextFlagReturn = DateTime.UtcNow + TwentySeconds;
MoveToWorld(attacker.Location, attacker.Map);
Team.OnFlagDropped(attacker, enemy);
InvalidateCarrier();
}
public void Steal(PlayerMobile attacker)
{
if (Team == null || Team.Deleted || Team.Battle == null || Team.Battle.Deleted)
{
Delete();
return;
}
if (attacker == null || attacker.Deleted || attacker == _Carrier || attacker.Backpack == null || attacker.Backpack.Deleted)
{
return;
}
if (NextAssault > DateTime.UtcNow)
{
attacker.SendMessage(54, "This flag cannot be picked up for another {0} seconds.", (NextAssault - DateTime.UtcNow).TotalSeconds);
return;
}
if (attacker.HasItem<CTFFlag>())
{
attacker.SendMessage("You may only carry one flag at any given time!");
return;
}
if (!attacker.Backpack.TryDropItem(attacker, this, true))
{
return;
}
var enemy = GetTeam(attacker);
attacker.SolidHueOverride = 2498;
_Carrier = attacker;
Team.OnFlagStolen(attacker, enemy);
InvalidateCarrier();
}
public void Capture(PlayerMobile attacker)
{
if (Team == null || Team.Deleted || Team.Battle == null || Team.Battle.Deleted)
{
Delete();
return;
}
if (attacker == null || attacker.Deleted)
{
return;
}
var enemy = GetTeam(attacker);
if (enemy != null)
{
attacker.SolidHueOverride = enemy.Color;
}
Team.OnFlagCaptured(attacker, enemy);
InvalidateCarrier();
Delete();
}
public void Return(PlayerMobile defender)
{
if (Team == null || Team.Deleted)
{
Delete();
return;
}
if (defender == null || defender.Deleted)
{
return;
}
if (Team.FlagPodium != null && !Team.FlagPodium.Deleted)
{
MoveToWorld(Team.FlagPodium.Location.Clone3D(0, 0, Team.FlagPodium.ItemData.Height + 5), Team.FlagPodium.Map);
}
else
{
MoveToWorld(Team.HomeBase, Team.Battle.Options.Locations.Map);
}
NextAssault = DateTime.UtcNow;
DamageInc = 0;
Team.OnFlagReturned(defender);
InvalidateCarrier();
}
public bool IsAtPodium()
{
return Carrier == null && (this.InRange2D(Team.FlagPodium, 0) || this.InRange2D(Team.HomeBase, 0));
}
public void UpdateDamageIncrease()
{
if (DateTime.UtcNow < _NextMultiUpdate)
{
return;
}
if (IsAtPodium())
{
DamageInc = 0;
}
else if (Carrier != null && DamageInc < Team.CTFBattle.FlagDamageIncMax)
{
DamageInc += Team.CTFBattle.FlagDamageInc;
_NextMultiUpdate = DateTime.UtcNow + TenSeconds;
}
}
public void CheckReset()
{
if (DateTime.UtcNow < _NextFlagReturn || Carrier != null || IsAtPodium())
{
return;
}
Team.CTFBattle.OnFlagTimeout(this);
Reset();
}
#if NEWPARENT
public override void OnParentDeleted(IEntity parent)
#else
public override void OnParentDeleted(object parent)
#endif
{
Drop(parent as PlayerMobile);
base.OnParentDeleted(parent);
}
public override DeathMoveResult OnParentDeath(Mobile parent)
{
Drop(parent as PlayerMobile);
return base.OnParentDeath(parent);
}
public override void OnDoubleClick(Mobile m)
{
if (Team == null || Team.Deleted || Team.Battle == null || Team.Battle.Deleted ||
!this.CheckDoubleClick(m, true, false, 1) || !(m is PlayerMobile))
{
return;
}
var pm = (PlayerMobile)m;
var battle = Team.CTFBattle;
if (battle == null || !battle.IsParticipant(pm))
{
pm.SendMessage("You must be a participant to perform that action.");
return;
}
if (Team.IsMember(pm))
{
if (Team.FlagPodium != null && !Team.FlagPodium.Deleted)
{
if (!this.InRange3D(Team.FlagPodium, 1, -10, 10))
{
Return(pm);
}
}
else if (!this.InRange3D(Team.HomeBase, 1, -10, 10))
{
Return(pm);
}
}
else if (Carrier != pm)
{
Steal(pm);
}
else
{
Drop(pm);
}
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
if (Deleted || Team == null || Team.Deleted || Team.Battle == null || Team.Battle.Deleted || !(m is PlayerMobile) ||
!this.CheckDoubleClick(m, false, false, 1))
{
return;
}
var pm = (PlayerMobile)m;
var battle = Team.CTFBattle;
if (battle == null || !battle.IsParticipant(pm))
{
return;
}
if (Team.IsMember(pm))
{
if (Team.FlagPodium != null && !Team.FlagPodium.Deleted)
{
if (!this.InRange3D(Team.FlagPodium, 1, -10, 10))
{
Return(pm);
}
}
else if (!this.InRange3D(Team.HomeBase, 1, -10, 10))
{
Return(pm);
}
}
else if (Carrier != pm)
{
Steal(pm);
}
}
public void InvalidateCarrier()
{
if (Deleted)
{
_Carrier = null;
return;
}
if (Team == null || Team.Deleted)
{
Delete();
return;
}
InvalidateCarryEffect();
}
public void InvalidateCarryEffect()
{
if (Deleted || Carrier == null || Carrier.Deleted || !IsChildOf(Carrier.Backpack))
{
_Carrier = null;
return;
}
if (DateTime.UtcNow < NextEffect)
{
return;
}
new EffectInfo(Carrier.Clone3D(0, 0, 22), Carrier.Map, ItemID, Team.Color).Send();
NextEffect = DateTime.UtcNow + SplitSecond;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
writer.Write(_Carrier);
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
_Carrier = reader.ReadMobile<PlayerMobile>();
break;
}
}
}
}

View File

@@ -0,0 +1,102 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
using Server.Mobiles;
using VitaNex.FX;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class CTFPodium : Item
{
[CommandProperty(AutoPvP.Access)]
public virtual CTFTeam Team { get; set; }
public override bool HandlesOnMovement => true;
public CTFPodium(CTFTeam team)
: base(16144)
{
Team = team;
Name = Team.Name;
Hue = Team.Color;
Movable = false;
}
public CTFPodium(Serial serial)
: base(serial)
{ }
public override void OnDoubleClick(Mobile from)
{
if (this.CheckDoubleClick(from, true, false, 2))
{
CheckCapture(from as PlayerMobile);
}
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
CheckCapture(m as PlayerMobile);
}
public virtual void CheckCapture(PlayerMobile attacker)
{
if (Team == null || Team.Deleted || Team.Flag == null || Team.Flag.Deleted)
{
return;
}
if (attacker == null || attacker.Deleted || !attacker.InRange3D(this, 2, -10, 10) || !Team.IsMember(attacker))
{
return;
}
if (Team.Flag.Carrier != null && !Team.Flag.Carrier.Deleted)
{
return;
}
Team.Battle.ForEachTeam<CTFTeam>(
t =>
{
if (t == Team || t.Flag == null || t.Flag.Deleted || t.Flag.Carrier != attacker)
{
return;
}
t.Flag.Capture(attacker);
ExplodeFX.Random.CreateInstance(this, Map, 3, 0, null, e => e.Hue = t.Color).Send();
});
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

View File

@@ -0,0 +1,554 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Server;
using Server.Mobiles;
using VitaNex.SuperGumps;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class CTFTeam : PvPTeam
{
private static readonly TimeSpan _OneSecond = TimeSpan.FromSeconds(1.0);
private CTFPodium _FlagPodium;
private bool _SolidHueOverride = true;
public Dictionary<PlayerMobile, int> Attackers { get; private set; }
public Dictionary<PlayerMobile, int> Defenders { get; private set; }
[CommandProperty(AutoPvP.Access)]
public CTFBattle CTFBattle => Battle as CTFBattle;
[CommandProperty(AutoPvP.Access, true)]
public CTFFlag Flag { get; private set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool SolidHueOverride
{
get => _SolidHueOverride;
set
{
_SolidHueOverride = value;
InvalidateSolidHueOverride();
}
}
[CommandProperty(AutoPvP.Access)]
public virtual TimeSpan FlagRespawnDelay { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual CTFPodium FlagPodium
{
get => _FlagPodium;
set
{
_FlagPodium = value;
InvalidateFlagPodium();
}
}
[CommandProperty(AutoPvP.Access)]
public override Point3D HomeBase
{
get => base.HomeBase;
set
{
base.HomeBase = value;
InvalidateFlagPodium();
}
}
[CommandProperty(AutoPvP.Access)]
public override Point3D SpawnPoint
{
get => base.SpawnPoint;
set
{
base.SpawnPoint = value;
InvalidateFlagPodium();
}
}
protected override void EnsureConstructDefaults()
{
base.EnsureConstructDefaults();
Attackers = new Dictionary<PlayerMobile, int>();
Defenders = new Dictionary<PlayerMobile, int>();
}
public CTFTeam(PvPBattle battle, string name = "Team", int minCapacity = 0, int maxCapacity = 1, int color = 12)
: base(battle, name, minCapacity, maxCapacity, color)
{
FlagRespawnDelay = TimeSpan.FromSeconds(10.0);
RespawnOnDeath = true;
KickOnDeath = false;
}
public CTFTeam(PvPBattle battle, GenericReader reader)
: base(battle, reader)
{ }
protected override void OnMicroSync()
{
base.OnMicroSync();
if (Flag == null || Flag.Deleted)
{
Flag = null;
return;
}
if (Battle == null || Battle.Deleted || Battle.Hidden || Battle.IsInternal)
{
Flag.Delete();
Flag = null;
return;
}
Flag.InvalidateCarrier();
if (Flag.IsAtPodium())
{
return;
}
Flag.UpdateDamageIncrease();
Flag.CheckReset();
}
public override void Reset()
{
base.Reset();
if (Flag != null)
{
Flag.Delete();
Flag = null;
}
if (Attackers != null)
{
Attackers.Clear();
}
else
{
Attackers = new Dictionary<PlayerMobile, int>();
}
if (Defenders != null)
{
Defenders.Clear();
}
else
{
Defenders = new Dictionary<PlayerMobile, int>();
}
}
public virtual void InvalidateFlagPodium()
{
if (Deserializing || SpawnPoint == Point3D.Zero || Battle.Options.Locations.Map == null ||
Battle.Options.Locations.Map == Map.Internal)
{
return;
}
if (FlagPodium == null || FlagPodium.Deleted)
{
FlagPodium = new CTFPodium(this);
}
else
{
FlagPodium.Hue = Color;
FlagPodium.Name = Name;
}
FlagPodium.MoveToWorld(SpawnPoint, Battle.Options.Locations.Map);
}
public virtual void InvalidateSolidHueOverride()
{
if (!Deserializing)
{
ForEachMember(InvalidateSolidHueOverride);
}
}
public virtual void InvalidateSolidHueOverride(PlayerMobile pm)
{
if (!Deserializing && pm != null && !pm.Deleted && IsMember(pm) && pm.InRegion(Battle.BattleRegion))
{
if ((Battle.IsPreparing || Battle.IsRunning) && _SolidHueOverride)
{
pm.SolidHueOverride = Color;
}
else
{
pm.SolidHueOverride = -1;
}
}
}
public override void OnMemberAdded(PlayerMobile pm)
{
base.OnMemberAdded(pm);
InvalidateSolidHueOverride(pm);
}
public override void OnMemberRemoved(PlayerMobile pm)
{
base.OnMemberRemoved(pm);
if (Battle != null && !Battle.Deleted)
{
Battle.ForEachTeam<CTFTeam>(
t =>
{
if (t.Flag != null && !t.Flag.Deleted && t.Flag.Carrier == pm)
{
t.Flag.Carrier = null;
}
});
}
InvalidateSolidHueOverride(pm);
}
public override void OnBattleOpened()
{
base.OnBattleOpened();
InvalidateFlagPodium();
InvalidateSolidHueOverride();
}
public override void OnBattlePreparing()
{
base.OnBattlePreparing();
InvalidateFlagPodium();
InvalidateSolidHueOverride();
}
public override void OnBattleStarted()
{
base.OnBattleStarted();
InvalidateFlagPodium();
InvalidateSolidHueOverride();
if (Flag == null || Flag.Deleted)
{
RespawnFlag();
}
else
{
Flag.Reset();
}
}
public override void OnBattleEnded()
{
base.OnBattleEnded();
InvalidateFlagPodium();
InvalidateSolidHueOverride();
}
public override void OnMemberDeath(PlayerMobile pm)
{
if (Battle != null && !Battle.Deleted)
{
Battle.ForEachTeam<CTFTeam>(
t =>
{
if (t.Flag != null && !t.Flag.Deleted && t.Flag.Carrier == pm)
{
t.Flag.Carrier = null;
}
});
}
InvalidateSolidHueOverride(pm);
base.OnMemberDeath(pm);
}
public virtual void SpawnFlag()
{
if (!Battle.IsRunning)
{
if (Flag != null && !Flag.Deleted)
{
Flag.Delete();
}
Flag = null;
return;
}
if (Flag == null || Flag.Deleted)
{
Flag = new CTFFlag(this);
}
Flag.Carrier = null;
Flag.Reset();
}
public virtual void RespawnFlag()
{
Timer.DelayCall(FlagRespawnDelay, SpawnFlag);
}
public virtual void OnFlagDropped(PlayerMobile attacker, CTFTeam enemyTeam)
{
if (attacker == null || enemyTeam == null || Flag == null || Flag.Deleted || CTFBattle == null || CTFBattle.Deleted)
{
return;
}
Broadcast("[{0}]: {1} has dropped your flag!", enemyTeam.Name, attacker.RawName);
CTFBattle.OnFlagDropped(Flag, attacker, enemyTeam);
}
public virtual void OnFlagCaptured(PlayerMobile attacker, CTFTeam enemyTeam)
{
if (attacker == null || enemyTeam == null || Flag == null || Flag.Deleted || CTFBattle == null || CTFBattle.Deleted)
{
return;
}
if (enemyTeam.Attackers.ContainsKey(attacker))
{
enemyTeam.Attackers[attacker]++;
}
else
{
enemyTeam.Attackers.Add(attacker, 1);
}
Broadcast("[{0}]: {1} has captured your flag!", enemyTeam.Name, attacker.RawName);
CTFBattle.OnFlagCaptured(Flag, attacker, enemyTeam);
RespawnFlag();
}
public virtual void OnFlagStolen(PlayerMobile attacker, CTFTeam enemyTeam)
{
if (attacker == null || enemyTeam == null || Flag == null || Flag.Deleted || CTFBattle == null || CTFBattle.Deleted)
{
return;
}
Broadcast("[{0}]: {1} has stolen your flag!", enemyTeam.Name, attacker.RawName);
CTFBattle.OnFlagStolen(Flag, attacker, enemyTeam);
}
public virtual void OnFlagReturned(PlayerMobile defender)
{
if (defender == null || Flag == null || Flag.Deleted || CTFBattle == null || CTFBattle.Deleted)
{
return;
}
if (Defenders.ContainsKey(defender))
{
Defenders[defender]++;
}
else
{
Defenders.Add(defender, 1);
}
Broadcast("[{0}]: {1} has returned your flag!", Name, defender.RawName);
CTFBattle.OnFlagReturned(Flag, defender);
}
public long GetTotalFlagsCaptured()
{
return Statistics.Values.Aggregate(0L, (v, o) => v + o["Flags Captured"]);
}
public long GetTotalFlagsDropped()
{
return Statistics.Values.Aggregate(0L, (v, o) => v + o["Flags Dropped"]);
}
public long GetTotalFlagsStolen()
{
return Statistics.Values.Aggregate(0L, (v, o) => v + o["Flags Stolen"]);
}
public long GetTotalFlagsReturned()
{
return Statistics.Values.Aggregate(0L, (v, o) => v + o["Flags Returned"]);
}
protected override void OnDeleted()
{
if (Flag != null)
{
Flag.Delete();
Flag = null;
}
if (FlagPodium != null)
{
FlagPodium.Delete();
FlagPodium = null;
}
base.OnDeleted();
}
public override void GetHtmlStatistics(Mobile viewer, StringBuilder html)
{
base.GetHtmlStatistics(viewer, html);
html.AppendLine("----------");
html.AppendLine("Flags Captured: {0:#,0}", GetTotalFlagsCaptured());
html.AppendLine("Flags Dropped: {0:#,0}", GetTotalFlagsDropped());
html.AppendLine("Flags Stolen: {0:#,0}", GetTotalFlagsStolen());
html.AppendLine("Flags Returned: {0:#,0}", GetTotalFlagsReturned());
html.AppendLine();
html.Append(String.Empty.WrapUOHtmlColor(System.Drawing.Color.LawnGreen, false));
html.AppendLine("Defenders:");
html.AppendLine();
string t;
var i = 0;
foreach (var o in Defenders.OrderBy(kv => kv.Value))
{
t = String.Format("{0:#,0}: {1} ({2:#,0} Returns)", ++i, o.Key.RawName, o.Value);
t = t.WrapUOHtmlColor(viewer.GetNotorietyColor(o.Key), SuperGump.DefaultHtmlColor);
html.AppendLine(t);
}
html.AppendLine();
html.Append(String.Empty.WrapUOHtmlColor(System.Drawing.Color.OrangeRed, false));
html.AppendLine("Attackers:");
html.AppendLine();
i = 0;
foreach (var o in Attackers.OrderBy(kv => kv.Value))
{
t = String.Format("{0:#,0}: {1} ({2:#,0} Captures)", ++i, o.Key.RawName, o.Value);
t = t.WrapUOHtmlColor(viewer.GetNotorietyColor(o.Key), SuperGump.DefaultHtmlColor);
html.AppendLine(t);
}
html.Append(String.Empty.WrapUOHtmlColor(SuperGump.DefaultHtmlColor, false));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.Write(Flag);
writer.Write(FlagPodium);
writer.Write(-1); // Caps
writer.Write(FlagRespawnDelay);
writer.Write(SolidHueOverride);
writer.WriteDictionary(
Attackers,
(w, m, c) =>
{
w.Write(m);
w.Write(c);
});
writer.WriteDictionary(
Defenders,
(w, m, c) =>
{
w.Write(m);
w.Write(c);
});
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
{
Flag = reader.ReadItem<CTFFlag>();
if (Flag != null)
{
Flag.Team = this;
}
FlagPodium = reader.ReadItem<CTFPodium>();
if (FlagPodium != null)
{
FlagPodium.Team = this;
}
reader.ReadInt(); // Caps
FlagRespawnDelay = reader.ReadTimeSpan();
SolidHueOverride = reader.ReadBool();
reader.ReadDictionary(
r => new KeyValuePair<PlayerMobile, int>(r.ReadMobile<PlayerMobile>(), r.ReadInt()),
Attackers);
reader.ReadDictionary(
r => new KeyValuePair<PlayerMobile, int>(r.ReadMobile<PlayerMobile>(), r.ReadInt()),
Defenders);
}
break;
}
}
}
}

View File

@@ -0,0 +1,77 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using VitaNex.Schedules;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class FFABattle : PvPBattle
{
public FFABattle()
{
Name = "Free For All";
Category = "Free For All";
Description = "The last participant alive wins!";
AddTeam(NameList.RandomName("daemon"), 5, 40, 85);
Schedule.Info.Months = ScheduleMonths.All;
Schedule.Info.Days = ScheduleDays.All;
Schedule.Info.Times = ScheduleTimes.EveryHour;
Options.Timing.PreparePeriod = TimeSpan.FromMinutes(5.0);
Options.Timing.RunningPeriod = TimeSpan.FromMinutes(15.0);
Options.Timing.EndedPeriod = TimeSpan.FromMinutes(5.0);
Options.Rules.AllowBeneficial = true;
Options.Rules.AllowHarmful = true;
Options.Rules.AllowHousing = false;
Options.Rules.AllowPets = false;
Options.Rules.AllowSpawn = false;
Options.Rules.AllowSpeech = true;
Options.Rules.CanBeDamaged = true;
Options.Rules.CanDamageEnemyTeam = true;
Options.Rules.CanDamageOwnTeam = true;
Options.Rules.CanDie = false;
Options.Rules.CanHeal = true;
Options.Rules.CanHealEnemyTeam = false;
Options.Rules.CanHealOwnTeam = false;
Options.Rules.CanMount = false;
Options.Rules.CanFly = false;
Options.Rules.CanResurrect = false;
Options.Rules.CanUseStuckMenu = false;
}
public FFABattle(GenericReader reader)
: base(reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

View File

@@ -0,0 +1,50 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public sealed class PvPCustomBattle : PvPBattle
{
public PvPCustomBattle()
{
Name = "Generic Battle";
Description =
"This generic battle serves as a template to create standard battles with general rules, using no advanced features.";
AddTeam("Team Alpha", 5, 10, 11);
AddTeam("Team Bravo", 5, 10, 22);
AddTeam("Team Gamma", 5, 10, 33);
AddTeam("Team Omega", 5, 10, 44);
}
public PvPCustomBattle(GenericReader reader)
: base(reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

View File

@@ -0,0 +1,82 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public sealed class TournamentArchive : PropertyObject, IEnumerable<TournamentMatch>
{
[CommandProperty(AutoPvP.Access)]
public List<TournamentMatch> Matches { get; private set; }
[CommandProperty(AutoPvP.Access)]
public int Count => Matches.Count;
[CommandProperty(AutoPvP.Access)]
public string Name { get; private set; }
[CommandProperty(AutoPvP.Access)]
public DateTime Date { get; private set; }
public TournamentArchive(string name, DateTime date)
{
Name = name;
Date = date;
Matches = new List<TournamentMatch>();
}
public TournamentArchive(GenericReader reader)
: base(reader)
{ }
public IEnumerator<TournamentMatch> GetEnumerator()
{
return Matches.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(Name);
writer.Write(Date);
writer.WriteList(Matches, (w, o) => o.Serialize(w));
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
Name = reader.ReadString();
Date = reader.ReadDateTime();
Matches = reader.ReadList(r => new TournamentMatch(r), Matches);
}
}
}

View File

@@ -0,0 +1,564 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using Server;
using Server.Gumps;
using Server.Mobiles;
using VitaNex.SuperGumps;
using VitaNex.SuperGumps.UI;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TournamentArchivesUI : ListGump<TournamentArchive>
{
public TournamentArchivesUI(Mobile user, Gump parent = null)
: base(user, parent)
{ }
protected override void CompileList(List<TournamentArchive> list)
{
list.Clear();
list.AddRange(TournamentArchives.Registry);
base.CompileList(list);
}
public override string GetSearchKeyFor(TournamentArchive key)
{
if (key != null)
{
return key.Name + " @ " + key.Date;
}
return base.GetSearchKeyFor(null);
}
protected override string GetLabelText(int index, int pageIndex, TournamentArchive entry)
{
if (entry != null)
{
return entry.Name + " @ " + entry.Date.ToShortDateString();
}
return base.GetLabelText(index, pageIndex, null);
}
protected override void SelectEntry(GumpButton button, TournamentArchive entry)
{
base.SelectEntry(button, entry);
new TournamentArchiveUI(User, entry, this).Send();
}
}
public class TournamentArchiveUI : SuperGumpList<TournamentMatch>
{
public IEnumerable<TournamentMatch> Archive { get; private set; }
public string Title { get; set; }
public int EntryWidth { get; set; }
public int EntryHeight { get; set; }
public int Width { get; private set; }
public int Height { get; private set; }
public PlayerMobile Leader { get; private set; }
public TournamentArchiveUI(Mobile user, TournamentBattle battle, Gump parent = null)
: this(user, (IEnumerable<TournamentMatch>)battle, parent)
{ }
public TournamentArchiveUI(Mobile user, TournamentArchive archive, Gump parent = null)
: this(user, (IEnumerable<TournamentMatch>)archive, parent)
{ }
private TournamentArchiveUI(Mobile user, IEnumerable<TournamentMatch> archive, Gump parent = null)
: base(user, parent)
{
Archive = archive;
Title = "Tournament Records";
if (Archive is TournamentArchive)
{
var a = (TournamentArchive)Archive;
Title = String.Format("{0} - {1}", a.Name, a.Date.ToSimpleString("t@h:m:s@ D d M y"));
}
else if (Archive is TournamentBattle)
{
var b = (TournamentBattle)Archive;
Title = b.Name;
if (b.State == PvPBattleState.Running)
{
AutoRefresh = true;
AutoRefreshRate = TimeSpan.FromSeconds(30.0);
}
}
CanClose = true;
CanDispose = true;
CanMove = true;
CanResize = true;
EntriesPerPage = 5;
EntryWidth = 400;
EntryHeight = 120;
Init();
}
protected override void Compile()
{
EntryWidth = Math.Max(400, EntryWidth);
EntryHeight = Math.Max(120, EntryHeight);
base.Compile();
}
protected virtual void Init()
{
if (Archive != null)
{
Leader = List.Where(m => m.Winner != null)
.GroupBy(m => m.Winner)
.OrderByDescending(o => o.Count())
.ThenByDescending(o => o.Aggregate(0.0, (c, m) => c + m.ComputeScore(o.Key)))
.Select(o => o.Key)
.FirstOrDefault();
}
var pad = SupportsUltimaStore ? 10 : 15;
var count = Math.Max(1, Math.Min(EntryCount, EntriesPerPage));
Width = 30 + (pad * 3) + EntryWidth;
Height = 90 + (pad * 3) + (count * EntryHeight);
}
protected override bool OnBeforeSend()
{
return base.OnBeforeSend() && Archive != null;
}
protected override void CompileList(List<TournamentMatch> list)
{
list.Clear();
if (Archive != null)
{
list.AddRange(Archive.Not(o => o.IsEmpty));
}
base.CompileList(list);
Init();
}
protected override void CompileLayout(SuperGumpLayout layout)
{
base.CompileLayout(layout);
var sup = SupportsUltimaStore;
var pad = sup ? 10 : 15;
var bgID = sup ? 40000 : 9270;
var bgCol = sup ? Color.FromArgb(0xFF, 0x29, 0x31, 0x39) : Color.Black;
layout.Add(
"bg",
() =>
{
var x = 0;
var y = 0;
var w = Width;
var h = Height;
AddBackground(x, y, w, h, bgID);
x = pad;
y = (Height - pad) - 60;
w = Width - (pad * 2);
h = 60;
AddRectangle(x, y, w, h, bgCol, true);
});
layout.Add(
"title",
() =>
{
var title = Title;
title = title.WrapUOHtmlBig();
title = title.WrapUOHtmlCenter();
title = title.WrapUOHtmlColor(Color.Gold, false);
AddHtml(pad, pad, Width - (pad * 2), 40, title, false, false);
});
layout.Add("results", CompileResults);
layout.Add(
"scroll",
() =>
{
var x = Width - (pad + 30);
var y = pad + 30;
var h = Height - ((pad * 3) + 90);
AddScrollbarV(x, y, h, PageCount, Page, PreviousPage, NextPage);
});
layout.Add("cpanel", CompileControls);
}
private void CompileControls()
{
var sup = SupportsUltimaStore;
var pad = sup ? 10 : 15;
//var bgCol = sup ? Color.FromArgb(0xFF, 0x29, 0x31, 0x39) : Color.Black;
var x = pad;
var y = Height - (pad + 60);
var w = (Width - (pad * 2)) / 4;
//////////
var players = List.SelectMany(o => o.Players.Where(p => p != null)).Distinct().Count();
var text = String.Format("PLAYERS:\n{0:#,0}", players);
text = text.WrapUOHtmlBold();
text = text.WrapUOHtmlCenter();
text = text.WrapUOHtmlColor(Color.PaleGoldenrod, false);
AddRectangle(x, y, w, 60, Color.White);
AddHtml(x + pad, y + pad, w - (pad * 2), 60, text, false, false);
x += w;
//////////
text = String.Format("MATCHES:\n{0:#,0}", EntryCount);
text = text.WrapUOHtmlBold();
text = text.WrapUOHtmlCenter();
text = text.WrapUOHtmlColor(Color.PaleGoldenrod, false);
AddRectangle(x, y, w, 60, Color.White);
AddHtml(x + pad, y + pad, w - (pad * 2), 60, text, false, false);
x += w;
//////////
var ticks = List.Select(o => o.IsRunning ? o.Expire : o.TotalTime).Aggregate(0L, (v, o) => v + o.Ticks);
var duration = TimeSpan.FromTicks(ticks).ToSimpleString(@"!<d\d ><h\h >m\m");
text = String.Format("DURATION:\n{0}", duration);
text = text.WrapUOHtmlBold();
text = text.WrapUOHtmlCenter();
text = text.WrapUOHtmlColor(Color.PaleGoldenrod, false);
AddRectangle(x, y, w, 60, Color.White);
AddHtml(x + pad, y + pad, w - (pad * 2), 60, text, false, false);
x += w;
//////////
if (Archive is TournamentArchive || (Archive is TournamentBattle && !((TournamentBattle)Archive).IsRunning))
{
text = String.Format("WINNER:\n{0}", Leader != null ? Leader.RawName : "N/A");
}
else
{
text = String.Format("LEADER:\n{0}", Leader != null ? Leader.RawName : "N/A");
}
text = text.WrapUOHtmlBold();
text = text.WrapUOHtmlCenter();
text = text.WrapUOHtmlColor(Color.PaleGoldenrod, false);
AddRectangle(x, y, w, 60, Color.White);
AddHtml(x + pad, y + pad, w - (pad * 2), 60, text, false, false);
}
private void CompileResults()
{
var sup = SupportsUltimaStore;
var pad = sup ? 10 : 15;
var x = pad;
var y = pad + 30;
var range = GetListRange();
foreach (var o in range.Values)
{
CompileMatchLayout(x, y, EntryWidth, EntryHeight, o);
y += EntryHeight;
}
range.Clear();
}
private void CompileMatchLayout(int x, int y, int w, int h, TournamentMatch match)
{
var sup = SupportsUltimaStore;
var pad = sup ? 10 : 15;
var bgID = sup ? 40000 : 9270;
//var bgCol = sup ? Color.FromArgb(0xFF, 0x29, 0x31, 0x39) : Color.Black;
AddTileButton(x, y, w, h, b => Select(match));
AddBackground(x, y, w, h, bgID);
var capacity = match.Capacity;
if (capacity <= 0)
{
return;
}
var xx = x + pad;
var yy = y + pad;
var ww = (w - (pad * 2)) / capacity;
//var hh = h - (pad * 2);
string t;
Color c;
Size s;
Point o;
int ox, oy, tx, ty;
for (var i = 0; i < capacity; i++)
{
var p = match.Players[i];
if (p != null)
{
t = p.RawName;
}
else
{
t = "???";
}
t = t.WrapUOHtmlBig();
t = t.WrapUOHtmlCenter();
if (p != null)
{
t = t.WrapUOHtmlColor(User.GetNotorietyColor(p), false);
}
else
{
t = t.WrapUOHtmlColor(Color.White, false);
}
AddHtml(xx, yy, ww, 40, t, false, false);
if (p != null)
{
s = GetImageSize(7034);
o = new Point(ComputeCenter(xx, ww - s.Width), yy + 30);
AddImage(o.X, o.Y, 7034);
c = match.Winner == null ? Color.Silver : match.Winner == p ? Color.LawnGreen : Color.IndianRed;
AddRectangle(o.X, o.Y, s.Width, s.Height, c, 2);
}
else
{
s = GetImageSize(7034);
o = new Point(ComputeCenter(xx, ww - s.Width), yy + 30);
AddImage(o.X, o.Y, 7034);
c = Color.White;
AddRectangle(o.X, o.Y, s.Width, s.Height, c, 2);
}
if (i + 1 < capacity)
{
ox = o.X + s.Width;
tx = xx + (ww - 30);
}
else
{
ox = xx + 30;
tx = o.X;
}
oy = ComputeCenter(o.Y, s.Height - 4);
ty = oy + 4;
AddRectangle(ox, oy, tx - ox, ty - oy, c, true);
if (i + 1 < capacity)
{
AddImageShadow(xx + (ww - 30), yy + 30, 5578, 0, 90);
}
xx += ww;
}
}
public void GetHtml(StringBuilder html, TournamentMatch match, bool extended)
{
var text = String.Format("Match #{0}", match.Index + 1);
text = text.WrapUOHtmlBig();
text = text.WrapUOHtmlColor(Color.Gold, false);
html.AppendLine(text);
var sep = " vs ".WrapUOHtmlColor(Color.IndianRed, Color.White);
text = String.Join(sep, match.Players.Select(o => o != null ? o.RawName : "???"));
text = text.WrapUOHtmlColor(Color.White, false);
html.AppendLine(text);
if (extended)
{
html.AppendLine();
}
if (match.Winner != null)
{
text = String.Format("Winner: {0}", match.Winner.RawName);
text = text.WrapUOHtmlColor(Color.PaleGoldenrod, false);
}
else if (match.IsComplete)
{
text = "Draw";
text = text.WrapUOHtmlColor(Color.LightGray, false);
}
else
{
var exp = match.Expire;
if (exp > TimeSpan.Zero)
{
text = String.Format("Expire: {0}", exp.ToSimpleString("h:m:s"));
text = text.WrapUOHtmlColor(Color.SkyBlue, false);
}
else
{
text = "Expired";
text = text.WrapUOHtmlColor(Color.IndianRed, false);
}
}
html.AppendLine(text);
if (!extended)
{
return;
}
html.AppendLine();
if (match.DateStart > DateTime.MinValue)
{
text = String.Format("Start: {0}", match.DateStart.ToSimpleString("t@h:m:s@ D d M y"));
text = text.WrapUOHtmlColor(Color.SkyBlue, false);
html.AppendLine(text);
}
if (match.DateEnd < DateTime.MaxValue)
{
text = String.Format("Finish: {0}", match.DateEnd.ToSimpleString("t@h:m:s@ D d M y"));
text = text.WrapUOHtmlColor(Color.SkyBlue, false);
html.AppendLine(text);
}
html.AppendLine();
text = "Records";
text = text.WrapUOHtmlBig();
text = text.WrapUOHtmlColor(Color.Gold, false);
html.AppendLine(text);
html.AppendLine(String.Empty.WrapUOHtmlColor(Color.White, false));
foreach (var o in match.Records)
{
html.AppendLine("[{0}]: {1}", o.Time.ToSimpleString("t@h:m:s@"), o.Value);
}
}
private void Select(TournamentMatch match)
{
var html = new StringBuilder();
GetHtml(html, match, true);
new NoticeDialogGump(User, Refresh(true))
{
Width = 600,
Height = 400,
Title = String.Format("Match #{0:#,0}", match.Index + 1),
Html = html.ToString()
}.Send();
}
public override int SortCompare(TournamentMatch a, TournamentMatch b)
{
var res = 0;
if (a.CompareNull(b, ref res))
{
return res;
}
if (a.Index < b.Index)
{
return -1;
}
if (a.Index > b.Index)
{
return 1;
}
return base.SortCompare(a, b);
}
protected override void OnAutoRefresh()
{
base.OnAutoRefresh();
AutoRefresh = Archive is TournamentBattle && ((TournamentBattle)Archive).IsRunning;
}
}
}

View File

@@ -0,0 +1,88 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Server;
using VitaNex.IO;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public static class TournamentArchives
{
static TournamentArchives()
{
Registry = new List<TournamentArchive>();
}
public static void Initialize()
{
CommandUtility.Register("TournamentArchives", AutoPvP.Access, e => new TournamentArchivesUI(e.Mobile).Send());
CommandUtility.RegisterAlias("TournamentArchives", "TArchives");
}
public static FileInfo File => IOUtility.EnsureFile(VitaNexCore.SavesDirectory + "/AutoPvP/Tournament/Archives.bin");
public static List<TournamentArchive> Registry { get; private set; }
public static int Count => Registry.Count;
public static void Configure()
{
VitaNexCore.OnModuleLoaded += OnModuleLoaded;
VitaNexCore.OnModuleSaved += OnModuleSaved;
}
private static void OnModuleLoaded(CoreModuleInfo cmi)
{
if (cmi.Enabled && cmi.TypeOf == typeof(AutoPvP))
{
File.Deserialize(r => r.ReadBlockList(r1 => new TournamentArchive(r1), Registry));
}
}
private static void OnModuleSaved(CoreModuleInfo cmi)
{
if (cmi.Enabled && cmi.TypeOf == typeof(AutoPvP))
{
File.Serialize(w => w.WriteBlockList(Registry, (w1, o) => o.Serialize(w1)));
}
}
public static TournamentArchive CreateArchive(TournamentBattle b)
{
TournamentArchive a = null;
foreach (var r in b.Matches.Where(o => !o.IsDisposed && o.IsComplete && o.Records.Count > 0))
{
if (a == null)
{
a = new TournamentArchive(b.Name, DateTime.UtcNow);
}
a.Matches.Add(r);
}
if (a != null)
{
Registry.Add(a);
}
return a;
}
}
}

View File

@@ -0,0 +1,58 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TournamentRecord : PropertyObject
{
[CommandProperty(AutoPvP.Access, true)]
public DateTime Time { get; private set; }
[CommandProperty(AutoPvP.Access, true)]
public string Value { get; private set; }
public TournamentRecord(string value)
{
Time = DateTime.UtcNow;
Value = value ?? String.Empty;
}
public TournamentRecord(GenericReader reader)
: base(reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(Time);
writer.Write(Value);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
Time = reader.ReadDateTime();
Value = reader.ReadString();
}
}
}

View File

@@ -0,0 +1,83 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public sealed class TournamentRecords : PropertyObject, IEnumerable<TournamentRecord>
{
[CommandProperty(AutoPvP.Access)]
public List<TournamentRecord> Entries { get; private set; }
[CommandProperty(AutoPvP.Access)]
public int Count => Entries.Count;
[CommandProperty(AutoPvP.Access)]
public DateTime DateBegin => Count > 0 ? Entries.Lowest(o => o.Time.Ticks).Time : DateTime.MinValue;
[CommandProperty(AutoPvP.Access)]
public DateTime DateEnd => Count > 0 ? Entries.Highest(o => o.Time.Ticks).Time : DateTime.MaxValue;
public TournamentRecords()
{
Entries = new List<TournamentRecord>();
}
public TournamentRecords(GenericReader reader)
: base(reader)
{ }
public void Record(string format, params object[] args)
{
Record(String.Format(format, args));
}
public void Record(string value)
{
Entries.Add(new TournamentRecord(value));
}
public IEnumerator<TournamentRecord> GetEnumerator()
{
return Entries.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.WriteList(Entries, (w, o) => o.Serialize(w));
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
Entries = reader.ReadList(r => new TournamentRecord(r), Entries);
}
}
}

View File

@@ -0,0 +1,544 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Linq;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public sealed class TournamentMatch : PropertyObject, IDisposable
{
private long _MessageBuffer;
public bool IsDisposed { get; private set; }
[CommandProperty(AutoPvP.Access)]
public TournamentRecords Records { get; private set; }
[CommandProperty(AutoPvP.Access, true)]
public int Index { get; private set; }
[CommandProperty(AutoPvP.Access, true)]
public int Team { get; private set; }
[CommandProperty(AutoPvP.Access)]
public PlayerMobile[] Players { get; private set; }
[CommandProperty(AutoPvP.Access)]
public bool[] Dead { get; private set; }
[CommandProperty(AutoPvP.Access)]
public int[][] Statistics { get; private set; }
[CommandProperty(AutoPvP.Access, true)]
public PlayerMobile Winner { get; set; }
[CommandProperty(AutoPvP.Access, true)]
public DateTime DateStart { get; set; }
[CommandProperty(AutoPvP.Access, true)]
public DateTime DateEnd { get; set; }
[CommandProperty(AutoPvP.Access, true)]
public TimeSpan Delay { get; set; }
[CommandProperty(AutoPvP.Access, true)]
public TimeSpan Duration { get; set; }
[CommandProperty(AutoPvP.Access)]
public TimeSpan TotalTime => Delay + Duration;
[CommandProperty(AutoPvP.Access)]
public TimeSpan Expire
{
get
{
if (DateStart > DateTime.MinValue)
{
var now = DateTime.UtcNow;
var exp = DateStart + TotalTime;
if (exp > now)
{
return exp - now;
}
}
return TimeSpan.Zero;
}
}
[CommandProperty(AutoPvP.Access)]
public bool IsRunning => Expire > TimeSpan.Zero;
[CommandProperty(AutoPvP.Access)]
public bool IsDelayed => DateStart + Delay > DateTime.UtcNow;
[CommandProperty(AutoPvP.Access)]
public bool IsComplete => DateEnd < DateTime.MaxValue;
[CommandProperty(AutoPvP.Access)]
public int Capacity => Players.Length;
[CommandProperty(AutoPvP.Access)]
public int Count => Players.Count(o => o != null);
[CommandProperty(AutoPvP.Access)]
public int CountAlive => Players.Count(o => o != null && IsAlive(o));
[CommandProperty(AutoPvP.Access)]
public int CountDead => Players.Count(o => o != null && IsDead(o));
[CommandProperty(AutoPvP.Access)]
public bool IsEmpty => Count == 0;
[CommandProperty(AutoPvP.Access)]
public bool IsFull => Count == Capacity;
public TournamentMatch(int index, int team, TimeSpan delay, TimeSpan duration)
{
Index = index;
Team = team;
Delay = delay;
Duration = duration;
Records = new TournamentRecords();
Players = new PlayerMobile[2];
Dead = new bool[Players.Length];
Statistics = new int[Players.Length][];
Statistics.SetAll(i => new int[2]); // Damage, Healing
DateStart = DateTime.MinValue;
DateEnd = DateTime.MaxValue;
}
public TournamentMatch(int index, TournamentBattle battle, TournamentTeam team)
: this(index, team.Serial.ValueHash, battle.MatchDelay, battle.MatchDuration)
{ }
public TournamentMatch(GenericReader reader)
: base(reader)
{ }
public void RecordDamage(PlayerMobile pm, int amount)
{
var i = Players.IndexOf(pm);
if (i >= 0)
{
Statistics[i][0] += amount;
Record("{0} deals {1:#,0} damage.", pm.RawName, amount);
}
}
public void RecordHeal(PlayerMobile pm, int amount)
{
var i = Players.IndexOf(pm);
if (i >= 0)
{
Statistics[i][1] += amount;
Record("{0} heals {1:#,0} health.", pm.RawName, amount);
}
}
public int GetDamageDone(PlayerMobile pm)
{
var i = Players.IndexOf(pm);
if (i >= 0)
{
return Statistics[i][0];
}
return -1;
}
public int GetHealingDone(PlayerMobile pm)
{
var i = Players.IndexOf(pm);
if (i >= 0)
{
return Statistics[i][1];
}
return -1;
}
public double ComputeScore(PlayerMobile pm)
{
return GetDamageDone(pm) - GetHealingDone(pm);
}
public void Record(string format, params object[] args)
{
Records.Record(format, args);
}
public void Record(string value)
{
Records.Record(value);
}
public void ForEachPlayer(Action<PlayerMobile> action)
{
if (action == null)
{
return;
}
foreach (var pm in Players.Where(o => o != null))
{
action(pm);
}
}
public void Broadcast(int hue, string format, params object[] args)
{
Record(format, args);
ForEachPlayer(pm => pm.SendMessage(hue, format, args));
}
public void Broadcast(int hue, string message)
{
Record(message);
ForEachPlayer(pm => pm.SendMessage(hue, message));
}
public void Broadcast(string format, params object[] args)
{
Record(format, args);
ForEachPlayer(pm => pm.SendMessage(format, args));
}
public void Broadcast(string message)
{
Record(message);
ForEachPlayer(pm => pm.SendMessage(message));
}
public void HandleDeath(PlayerMobile pm)
{
var i = Players.IndexOf(pm);
if (Dead.InBounds(i))
{
Dead[i] = true;
}
}
public bool IsDead(PlayerMobile pm)
{
var i = Players.IndexOf(pm);
if (Dead.InBounds(i))
{
return Dead[i];
}
return false;
}
public bool IsAlive(PlayerMobile pm)
{
var i = Players.IndexOf(pm);
if (Dead.InBounds(i))
{
return !Dead[i];
}
return false;
}
public bool Contains(PlayerMobile pm)
{
return Players.Contains(pm);
}
public void Sync(TournamentBattle b, TournamentTeam t)
{
if (IsDisposed || IsComplete)
{
return;
}
if (b == null || b.Deleted || b.IsInternal || b.IsQueueing || b.IsPreparing)
{
return;
}
if (t == null || t.Deleted || t.Serial.ValueHash != Team)
{
return;
}
if (b.IsRunning && DateStart == DateTime.MinValue) // Populate & Start
{
for (var i = 0; i < Capacity; i++)
{
var pm = Players[i];
if (pm != null && !b.IsAliveParticipant(pm))
{
Players[i] = null;
Dead[i] = false;
Statistics[i].SetAll(0);
Broadcast(0x22, "{0} has left the match! [{1} / {2}]", pm.RawName, Count, Capacity);
}
}
if (!IsFull)
{
var q = b.GetMatchQueue(Capacity - Count);
for (var i = 0; i < Capacity && q.Count > 0; i++)
{
var pm = Players[i];
if (pm == null)
{
Players[i] = pm = q.Dequeue();
Dead[i] = false;
Statistics[i].SetAll(0);
Broadcast(0x55, "{0} has joined the match! [{1} / {2}]", pm.RawName, Count, Capacity);
}
}
q.Free(true);
}
if (IsFull)
{
Broadcast("The match is now full, prepare to fight!");
Start(b, t);
}
}
else if (b.IsRunning && Expire > TimeSpan.Zero) // Tick
{
var started = !IsDelayed;
if (_MessageBuffer <= Core.TickCount)
{
var time = started ? Expire : ((DateStart + Delay) - DateTime.UtcNow);
if (time.Hours > 0 && time.Hours <= 3)
{
_MessageBuffer = Core.TickCount + (Math.Min(15, time.Minutes) * 60000);
}
else if (time.Minutes > 0 && time.Minutes <= 5)
{
_MessageBuffer = Core.TickCount + (Math.Min(15, time.Seconds) * 1000);
}
else if (time.Seconds > 0 && time.Seconds <= 10)
{
_MessageBuffer = Core.TickCount + Math.Min(1000, time.Milliseconds);
}
else
{
_MessageBuffer = Int64.MaxValue;
}
var seconds = (int)Math.Ceiling(time.TotalSeconds);
if (seconds > 5)
{
Broadcast(
"The match will {0} in {1} second{2}!",
!started ? "begin" : "end",
seconds,
seconds != 1 ? "s" : String.Empty);
}
else if (seconds > 0)
{
Broadcast("{0}...", seconds);
}
else
{
Broadcast(!started ? "FIGHT!" : "CEASE!");
}
}
PlayerMobile o = null;
var count = 0;
foreach (var pm in Players.Where(p => IsAlive(p) && b.IsAliveParticipant(p)).OrderBy(ComputeScore))
{
o = pm;
++count;
}
if (count <= 1)
{
if (!started)
{
Broadcast("Not enough players to start the match.");
}
Winner = o;
if (Winner != null)
{
if (!started)
{
Broadcast("{0} has won the match by default!", Winner.RawName);
}
else
{
Broadcast("{0} has won the match!", Winner.RawName);
}
}
else
{
Broadcast("No winner has been declared.");
}
End(b, t);
}
}
else if ((b.IsRunning || b.IsEnded) && DateEnd == DateTime.MaxValue) // End
{
var started = !IsDelayed;
if (started)
{
Broadcast("TIME UP!");
}
Winner = Players.Where(p => IsAlive(p) && b.IsAliveParticipant(p)).Highest(ComputeScore);
if (Winner != null)
{
if (!started)
{
Broadcast("{0} has won the match by default!", Winner.RawName);
}
else
{
Broadcast("{0} has won the match!", Winner.RawName);
}
}
else
{
Broadcast("No winner has been declared.");
}
End(b, t);
}
}
private void Start(TournamentBattle b, TournamentTeam t)
{
DateStart = DateTime.UtcNow;
foreach (var pm in Players.Where(p => IsAlive(p) && b.IsParticipant(p)))
{
b.RefreshStats(pm, true, true);
b.TeleportToSpawnPoint(t, pm);
}
}
private void End(TournamentBattle b, TournamentTeam t)
{
DateEnd = DateTime.UtcNow;
foreach (var pm in Players.Where(p => IsAlive(p) && b.IsParticipant(p)))
{
b.RefreshStats(pm, true, true);
b.TeleportToHomeBase(t, pm);
}
}
public void Dispose()
{
if (IsDisposed)
{
return;
}
Players.Clear();
Records = null;
Players = null;
Dead = null;
Statistics = null;
Winner = null;
IsDisposed = true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(Index);
writer.Write(Team);
writer.WriteArray(Players, (w, o) => w.Write(o));
writer.WriteArray(Dead, (w, o) => w.Write(o));
writer.WriteArray(Statistics, (w, o) => w.WriteArray(o, (w1, o1) => w1.Write(o1)));
writer.Write(Delay);
writer.Write(Duration);
writer.Write(DateStart);
writer.Write(DateEnd);
writer.Write(Winner);
Records.Serialize(writer);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
Index = reader.ReadInt();
Team = reader.ReadInt();
Players = reader.ReadArray(r => r.ReadMobile<PlayerMobile>(), Players);
Dead = reader.ReadArray(r => r.ReadBool(), Dead);
Statistics = reader.ReadArray(r => r.ReadArray(r1 => r1.ReadInt()), Statistics);
Delay = reader.ReadTimeSpan();
Duration = reader.ReadTimeSpan();
DateStart = reader.ReadDateTime();
DateEnd = reader.ReadDateTime();
Winner = reader.ReadMobile<PlayerMobile>();
Records = new TournamentRecords(reader);
}
}
}

View File

@@ -0,0 +1,71 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TournamentTeam : PvPTeam
{
public TournamentTeam(
PvPBattle battle,
string name = "Incognito",
int minCapacity = 10,
int maxCapacity = 50,
int color = 12)
: base(battle, name, minCapacity, maxCapacity, color)
{
RespawnOnStart = false;
RespawnOnDeath = false;
KickOnDeath = true;
}
public TournamentTeam(PvPBattle battle, GenericReader reader)
: base(battle, reader)
{ }
public override void AddMember(PlayerMobile pm, bool teleport)
{
if (IsMember(pm))
{
return;
}
Members[pm] = DateTime.UtcNow;
if (teleport)
{
Battle.TeleportToHomeBase(this, pm);
}
OnMemberAdded(pm);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

View File

@@ -0,0 +1,609 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Mobiles;
using VitaNex.Schedules;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TournamentBattle : PvPBattle, IEnumerable<TournamentMatch>
{
[CommandProperty(AutoPvP.Access)]
public List<TournamentMatch> Matches { get; private set; }
[CommandProperty(AutoPvP.Access)]
public TimeSpan MatchDelay { get; set; }
[CommandProperty(AutoPvP.Access)]
public TimeSpan MatchDuration { get; set; }
[CommandProperty(AutoPvP.Access)]
public double MatchSuddenDeath { get; set; }
[CommandProperty(AutoPvP.Access)]
public int FinalBestOfCur { get; set; }
[CommandProperty(AutoPvP.Access)]
public int FinalBestOfMax { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool IsFinalMatch => State == PvPBattleState.Running && Matches.Count > 0 && CurrentCapacity <= 2;
public TournamentBattle()
{
Name = "Tournament";
Category = "Tournaments";
Description = "An elimination tournament!";
AddTeam("Contenders", 10, 50, 85);
Schedule.Info.Months = ScheduleMonths.All;
Schedule.Info.Days = ScheduleDays.Sunday;
Schedule.Info.Times = ScheduleTimes.Noon;
Options.Timing.QueuePeriod = TimeSpan.FromHours(1.0);
Options.Timing.PreparePeriod = TimeSpan.FromMinutes(10.0);
Options.Timing.RunningPeriod = TimeSpan.FromHours(5.0);
Options.Timing.EndedPeriod = TimeSpan.FromHours(5.0);
Options.Rules.AllowBeneficial = true;
Options.Rules.AllowHarmful = true;
Options.Rules.AllowHousing = false;
Options.Rules.AllowPets = false;
Options.Rules.AllowSpawn = false;
Options.Rules.AllowSpeech = true;
Options.Rules.CanBeDamaged = true;
Options.Rules.CanDamageEnemyTeam = true;
Options.Rules.CanDamageOwnTeam = true;
Options.Rules.CanDie = false;
Options.Rules.CanHeal = true;
Options.Rules.CanHealEnemyTeam = true;
Options.Rules.CanHealOwnTeam = true;
Options.Rules.CanMount = false;
Options.Rules.CanFly = false;
Options.Rules.CanResurrect = false;
Options.Rules.CanUseStuckMenu = false;
Options.Rules.CanMoveThrough = true;
Options.Rules.CanEquip = true;
RequireCapacity = true;
UseTeamColors = false;
IdleKick = false;
IdleThreshold = TimeSpan.FromMinutes(30.0);
LogoutDelay = TimeSpan.FromMinutes(5.0);
MatchDelay = TimeSpan.FromSeconds(10.0);
MatchDuration = TimeSpan.FromMinutes(15.0);
MatchSuddenDeath = 0.25;
FinalBestOfCur = 0;
FinalBestOfMax = 3;
}
public TournamentBattle(GenericReader reader)
: base(reader)
{ }
protected override void EnsureConstructDefaults()
{
base.EnsureConstructDefaults();
Matches = new List<TournamentMatch>();
}
protected override void RegisterSubCommands()
{
base.RegisterSubCommands();
RegisterSubCommand(
"scores",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
UpdateUI(state.Mobile, false);
return true;
},
"Display the current match rankings.");
}
public override bool Validate(Mobile viewer, List<string> errors, bool pop = true)
{
if (!base.Validate(viewer, errors, pop) && pop)
{
return false;
}
if (!Teams.All(t => t is TournamentTeam))
{
errors.Add("One or more teams are not of the TournamentTeam type.");
errors.Add("[Options] -> [View Teams]");
if (pop)
{
return false;
}
}
return true;
}
protected override void GetAssignPriority(PvPTeam team, out double weight)
{
base.GetAssignPriority(team, out weight);
if (weight > Double.MinValue && weight < Double.MaxValue)
{
weight = team.Members.Count;
}
}
public override bool AddTeam(string name, int minCapacity, int capacity, int color)
{
return AddTeam(new TournamentTeam(this, name, minCapacity, capacity, color));
}
public override bool AddTeam(PvPTeam team)
{
if (team == null || team.Deleted)
{
return false;
}
if (team is TournamentTeam)
{
return base.AddTeam(team);
}
var added = AddTeam(team.Name, team.MinCapacity, team.MinCapacity, team.Color);
team.Delete();
return added;
}
public override void OnTeamMemberDeath(PvPTeam team, PlayerMobile pm)
{
base.OnTeamMemberDeath(team, pm);
if (team is TournamentTeam)
{
var o = FindActiveMatch(pm);
if (o != null)
{
o.HandleDeath(pm);
o.Sync(this, (TournamentTeam)team);
}
}
}
public override void OnAfterTeamMemberDeath(PvPTeam team, PlayerMobile pm)
{
base.OnAfterTeamMemberDeath(team, pm);
UpdateUI(true);
}
public override bool TryKickOnDeath(PvPTeam team, PlayerMobile pm, bool isLoss)
{
if (isLoss && IsFinalMatch && FinalBestOfCur < FinalBestOfMax)
{
var o = FindActiveMatch(pm);
int min = 0, max = 0;
if (o == null)
{
++FinalBestOfCur;
}
else if (o.CountAlive <= 1)
{
foreach (var c in o.Players.Where(p => p != null).Select(CountMatchesWon))
{
min = Math.Min(min, c);
max = Math.Max(max, c);
}
++FinalBestOfCur;
}
if (max - min < (FinalBestOfMax / 2) + 1)
{
return false;
}
}
return base.TryKickOnDeath(team, pm, isLoss);
}
public void UpdateUI(bool refreshOnly)
{
foreach (var pm in GetLocalBroadcastList())
{
UpdateUI(pm, refreshOnly);
}
}
public void UpdateUI(PlayerMobile pm, bool refreshOnly)
{
var g = pm.FindGump<TournamentArchiveUI>();
if (g == null)
{
if (refreshOnly)
{
return;
}
g = new TournamentArchiveUI(pm, this);
}
g.Refresh(true);
}
public override void OnHeal(Mobile healer, Mobile healed, int heal)
{
base.OnHeal(healer, healed, heal);
if (heal > 0 && healer == healed && healer is PlayerMobile)
{
var p = (PlayerMobile)healer;
var o = FindActiveMatch(p);
if (o != null)
{
if (MatchSuddenDeath > 0)
{
var t = o.Expire.TotalSeconds / o.Duration.TotalSeconds;
if (t < MatchSuddenDeath)
{
heal = (int)(heal * (t / MatchSuddenDeath));
}
}
o.RecordHeal(p, heal);
}
}
}
public override void OnDamage(Mobile attacker, Mobile damaged, int damage)
{
base.OnDamage(attacker, damaged, damage);
if (damage > 0 && attacker != damaged && attacker is PlayerMobile)
{
var p = (PlayerMobile)attacker;
var o = FindActiveMatch(p);
if (o != null)
{
o.RecordDamage(p, damage);
}
}
}
protected override void OnSpectatorAdded(PlayerMobile pm)
{
base.OnSpectatorAdded(pm);
UpdateUI(pm, false);
}
protected override void OnBattleStarted()
{
base.OnBattleStarted();
SyncMatches();
UpdateUI(true);
}
protected override void OnBattleEnded()
{
SyncMatches();
Matches.RemoveAll(o => o.IsEmpty);
if (Matches.Count > 0)
{
var a = TournamentArchives.CreateArchive(this);
if (a != null)
{
foreach (var pm in GetLocalBroadcastList())
{
new TournamentArchiveUI(pm, a).Send();
}
}
else
{
UpdateUI(false);
}
}
base.OnBattleEnded();
}
protected override void OnBattleCancelled()
{
SyncMatches();
Matches.RemoveAll(o => o.IsEmpty);
base.OnBattleCancelled();
}
protected override void OnReset()
{
Matches.Clear();
FinalBestOfCur = 0;
base.OnReset();
}
protected override void OnMicroSync()
{
base.OnMicroSync();
SyncMatches();
}
protected void SyncMatches()
{
if (!IsInternal)
{
ForEachTeam<TournamentTeam>(SyncMatch);
}
}
protected void SyncMatch(TournamentTeam team)
{
var m = Matches.Find(o => o.Team == team.Serial.ValueHash && !o.IsComplete);
if (m == null || m.IsDisposed)
{
if (!IsRunning || CurrentCapacity <= CountActiveParticipants())
{
return;
}
Matches.Add(m = new TournamentMatch(Matches.Count, this, team));
}
m.Sync(this, team);
}
public Queue<PlayerMobile> GetMatchQueue(int capacity)
{
var list = GetParticipants();
list = list.ToLookup(CountMatchesCompleted).Lowest(o => o.Key);
list = list.Not(InActiveMatch);
list = list.Randomize();
if (capacity > 0)
{
list = list.Take(capacity);
}
return list.ToQueue();
}
public IEnumerable<PlayerMobile> GetMatchParticipants()
{
return Matches.SelectMany(o => o.Players.Where(p => p != null)).Distinct();
}
public int CountActiveParticipants()
{
return Matches.Where(o => !o.IsComplete).Aggregate(0, (v, o) => v + o.CountAlive);
}
public int CountMatchesWon(PlayerMobile pm)
{
return Matches.Count(o => o.IsComplete && o.Winner == pm);
}
public int CountMatchesCompleted(PlayerMobile pm)
{
return Matches.Count(o => o.IsComplete && o.Contains(pm));
}
public bool InActiveMatch(PlayerMobile pm)
{
return Matches.Any(o => !o.IsComplete && o.Contains(pm));
}
public TournamentMatch FindActiveMatch(PlayerMobile pm)
{
return Matches.Find(o => !o.IsComplete && o.Contains(pm));
}
public override bool CheckSkillUse(Mobile user, int skill)
{
if (!base.CheckSkillUse(user, skill))
{
return false;
}
var o = FindActiveMatch(user as PlayerMobile);
return o != null && !o.IsDelayed;
}
public override bool CheckSpellCast(Mobile caster, ISpell spell)
{
if (!base.CheckSpellCast(caster, spell))
{
return false;
}
var o = FindActiveMatch(caster as PlayerMobile);
return o != null && !o.IsDelayed;
}
public override bool CheckAllowHarmful(Mobile m, Mobile target, out bool handled)
{
var val = base.CheckAllowHarmful(m, target, out handled);
if (!handled || !val || !m.InRegion(BattleRegion) || !target.InRegion(BattleRegion))
{
return val;
}
var pmS = m as PlayerMobile;
var pmT = target as PlayerMobile;
var o = FindActiveMatch(pmS);
return o != null && !o.IsDelayed && o == FindActiveMatch(pmT);
}
public override bool CheckAllowBeneficial(Mobile m, Mobile target, out bool handled)
{
var val = base.CheckAllowBeneficial(m, target, out handled);
if (!handled || !val || !m.InRegion(BattleRegion) || !target.InRegion(BattleRegion))
{
return val;
}
var pmS = m as PlayerMobile;
var pmT = target as PlayerMobile;
var o = FindActiveMatch(pmS);
return o != null && !o.IsDelayed && o == FindActiveMatch(pmT);
}
protected override int NotorietyHandler(PlayerMobile source, PlayerMobile target, out bool handled)
{
var noto = base.NotorietyHandler(source, target, out handled);
if (!handled || noto == BattleNotoriety.Bubble || noto == Notoriety.Invulnerable)
{
return noto;
}
if (!source.InRegion(BattleRegion) || !target.InRegion(BattleRegion))
{
return noto;
}
var o = FindActiveMatch(source);
if (o != null && !o.IsDelayed && o == FindActiveMatch(target))
{
return noto;
}
return Notoriety.Invulnerable;
}
public override TimeSpan GetStateTimeLeft(DateTime when, PvPBattleState state)
{
var time = base.GetStateTimeLeft(when, state);
if (state == PvPBattleState.Running)
{
var o = Matches.Where(r => r.IsRunning).Highest(r => r.Expire);
if (o != null)
{
if (o.Expire > time)
{
time = o.Expire;
}
}
else if (HasCapacity())
{
time = MatchDelay + MatchDuration;
}
}
return time;
}
public IEnumerator<TournamentMatch> GetEnumerator()
{
return Matches.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(1);
writer.Write(MatchSuddenDeath);
writer.Write(MatchDelay);
writer.Write(MatchDuration);
writer.Write(FinalBestOfCur);
writer.Write(FinalBestOfMax);
writer.WriteBlockList(Matches, (w, r) => r.Serialize(w));
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var v = reader.GetVersion();
if (v > 0)
{
MatchSuddenDeath = reader.ReadDouble();
}
else
{
MatchSuddenDeath = 0.25;
}
MatchDelay = reader.ReadTimeSpan();
MatchDuration = reader.ReadTimeSpan();
FinalBestOfCur = reader.ReadInt();
FinalBestOfMax = reader.ReadInt();
Matches = reader.ReadBlockList(r => new TournamentMatch(r), Matches);
}
}
}

View File

@@ -0,0 +1,87 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using VitaNex.Schedules;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TvTBattle : PvPBattle
{
public TvTBattle()
{
Name = "Team vs Team";
Category = "Team vs Team";
Description = "The last team alive wins!";
Ranked = true;
RewardTeam = true;
AddTeam(NameList.RandomName("daemon"), 1, 1, 0x22);
AddTeam(NameList.RandomName("daemon"), 1, 1, 0x55);
Schedule.Info.Months = ScheduleMonths.All;
Schedule.Info.Days = ScheduleDays.All;
Schedule.Info.Times = ScheduleTimes.EveryQuarterHour;
Options.Timing.PreparePeriod = TimeSpan.FromMinutes(2.0);
Options.Timing.RunningPeriod = TimeSpan.FromMinutes(8.0);
Options.Timing.EndedPeriod = TimeSpan.FromMinutes(1.0);
Options.Rules.AllowBeneficial = true;
Options.Rules.AllowHarmful = true;
Options.Rules.AllowHousing = false;
Options.Rules.AllowPets = false;
Options.Rules.AllowSpawn = false;
Options.Rules.AllowSpeech = true;
Options.Rules.CanBeDamaged = true;
Options.Rules.CanDamageEnemyTeam = true;
Options.Rules.CanDamageOwnTeam = false;
Options.Rules.CanDie = false;
Options.Rules.CanHeal = true;
Options.Rules.CanHealEnemyTeam = false;
Options.Rules.CanHealOwnTeam = true;
Options.Rules.CanMount = false;
Options.Rules.CanFly = false;
Options.Rules.CanResurrect = false;
Options.Rules.CanUseStuckMenu = false;
Options.Rules.CanEquip = true;
}
public TvTBattle(GenericReader reader)
: base(reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(1);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var v = reader.GetVersion();
if (v < 1)
{
RewardTeam = true;
}
}
}
}

View File

@@ -0,0 +1,65 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TvTBattle1v1 : TvTBattle
{
private static readonly TimeSpan[] _Times =
{
new TimeSpan(0, 30, 0), new TimeSpan(2, 30, 0), new TimeSpan(4, 30, 0), new TimeSpan(6, 30, 0),
new TimeSpan(8, 30, 0), new TimeSpan(10, 30, 0), new TimeSpan(13, 30, 0), new TimeSpan(15, 30, 0),
new TimeSpan(17, 30, 0), new TimeSpan(19, 30, 0), new TimeSpan(21, 30, 0), new TimeSpan(23, 45, 0)
};
public TvTBattle1v1()
{
Name = "1 vs 1";
Teams[0].MinCapacity = 1;
Teams[0].MaxCapacity = 1;
Teams[1].MinCapacity = 1;
Teams[1].MaxCapacity = 1;
Schedule.Info.Times.Clear();
Schedule.Info.Times.Add(_Times);
Options.Timing.PreparePeriod = TimeSpan.FromMinutes(4.0);
Options.Timing.RunningPeriod = TimeSpan.FromMinutes(8.0);
Options.Timing.EndedPeriod = TimeSpan.FromMinutes(10.0);
}
public TvTBattle1v1(GenericReader reader)
: base(reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

View File

@@ -0,0 +1,77 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TvTBattle2v2 : TvTBattle
{
private static readonly TimeSpan[] _Times =
{
new TimeSpan(0, 30, 0), new TimeSpan(2, 30, 0), new TimeSpan(4, 30, 0), new TimeSpan(6, 30, 0),
new TimeSpan(8, 30, 0), new TimeSpan(10, 30, 0), new TimeSpan(13, 30, 0), new TimeSpan(15, 30, 0),
new TimeSpan(17, 30, 0), new TimeSpan(19, 30, 0), new TimeSpan(21, 30, 0), new TimeSpan(23, 45, 0)
};
public TvTBattle2v2()
{
Name = "2 vs 2";
Teams[0].MinCapacity = 1;
Teams[0].MaxCapacity = 2;
Teams[1].MinCapacity = 1;
Teams[1].MaxCapacity = 2;
Schedule.Info.Times.Clear();
Schedule.Info.Times.Add(_Times);
Options.Timing.PreparePeriod = TimeSpan.FromMinutes(4.0);
Options.Timing.RunningPeriod = TimeSpan.FromMinutes(8.0);
Options.Timing.EndedPeriod = TimeSpan.FromMinutes(10.0);
}
public TvTBattle2v2(GenericReader reader)
: base(reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
break;
}
}
}
}

View File

@@ -0,0 +1,79 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TvTBattle3v3 : TvTBattle
{
private static readonly TimeSpan[] _Times =
{
new TimeSpan(1, 30, 0), new TimeSpan(3, 30, 0), new TimeSpan(5, 30, 0), new TimeSpan(7, 30, 0),
new TimeSpan(9, 30, 0), new TimeSpan(11, 30, 0), new TimeSpan(14, 30, 0), new TimeSpan(16, 30, 0),
new TimeSpan(18, 30, 0), new TimeSpan(20, 30, 0)
};
public TvTBattle3v3()
{
Name = "3 vs 3";
Teams[0].MinCapacity = 1;
Teams[0].MaxCapacity = 3;
Teams[1].MinCapacity = 1;
Teams[1].MaxCapacity = 3;
Schedule.Info.Times.Clear();
Schedule.Info.Times.Add(_Times);
Options.Broadcasts.World.MessageHue = 891;
Options.Timing.PreparePeriod = TimeSpan.FromMinutes(3.0);
Options.Timing.RunningPeriod = TimeSpan.FromMinutes(12.0);
Options.Timing.EndedPeriod = TimeSpan.FromMinutes(10.0);
}
public TvTBattle3v3(GenericReader reader)
: base(reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
break;
}
}
}
}

View File

@@ -0,0 +1,79 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP.Battles
{
public class TvTBattle5v5 : TvTBattle
{
private static readonly TimeSpan[] _Times =
{
new TimeSpan(1, 30, 0), new TimeSpan(3, 30, 0), new TimeSpan(5, 30, 0), new TimeSpan(7, 30, 0),
new TimeSpan(9, 30, 0), new TimeSpan(11, 30, 0), new TimeSpan(14, 30, 0), new TimeSpan(16, 30, 0),
new TimeSpan(18, 30, 0), new TimeSpan(20, 30, 0)
};
public TvTBattle5v5()
{
Name = "5 vs 5";
Teams[0].MinCapacity = 1;
Teams[0].MaxCapacity = 5;
Teams[1].MinCapacity = 1;
Teams[1].MaxCapacity = 5;
Schedule.Info.Times.Clear();
Schedule.Info.Times.Add(_Times);
Options.Broadcasts.World.MessageHue = 891;
Options.Timing.PreparePeriod = TimeSpan.FromMinutes(3.0);
Options.Timing.RunningPeriod = TimeSpan.FromMinutes(12.0);
Options.Timing.EndedPeriod = TimeSpan.FromMinutes(10.0);
}
public TvTBattle5v5(GenericReader reader)
: base(reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
break;
}
}
}
}

View File

@@ -0,0 +1,147 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Drawing;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public enum AutoPvPStoneCommand
{
ViewBattles,
ViewProfiles,
GlobalConfig
}
public class AutoPvPStone : Item
{
[CommandProperty(AutoPvP.Access)]
public AutoPvPStoneCommand Command { get; set; }
[CommandProperty(AutoPvP.Access)]
public KnownColor UsageColor { get; set; }
public override bool DisplayLootType => false;
public override bool DisplayWeight => false;
[Constructable]
public AutoPvPStone()
: this(4963)
{ }
[Constructable]
public AutoPvPStone(int itemID)
: base(itemID)
{
Command = AutoPvPStoneCommand.ViewBattles;
UsageColor = KnownColor.SkyBlue;
Name = "PvP Battle Stone";
LootType = LootType.Blessed;
Weight = 0;
}
public AutoPvPStone(Serial serial)
: base(serial)
{ }
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
var color = Color.FromKnownColor(UsageColor).ToRgb();
switch (Command)
{
case AutoPvPStoneCommand.ViewBattles:
{
list.Add("<basefont color=#{0:X6}>Opens the PvP battles menu<basefont color=#ffffff>", color);
}
break;
case AutoPvPStoneCommand.ViewProfiles:
{
list.Add("<basefont color=#{0:X6}>Opens the PvP profiles menu<basefont color=#ffffff>", color);
}
break;
case AutoPvPStoneCommand.GlobalConfig:
{
list.Add("<basefont color=#{0:X6}>Use: Opens the PvP control panel<basefont color=#ffffff>", color);
}
break;
}
}
public override void OnDoubleClick(Mobile from)
{
if (from == null || from.Deleted)
{
return;
}
switch (Command)
{
case AutoPvPStoneCommand.ViewBattles:
{
AutoPvP.CMOptions.Advanced.Commands.InvokeBattlesCommand(from);
}
break;
case AutoPvPStoneCommand.ViewProfiles:
{
AutoPvP.CMOptions.Advanced.Commands.InvokeProfilesCommand(from);
}
break;
case AutoPvPStoneCommand.GlobalConfig:
{
AutoPvP.CMOptions.Advanced.Commands.InvokeConfigCommand(from);
}
break;
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteFlag(Command);
writer.WriteFlag(UsageColor);
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
{
Command = reader.ReadFlag<AutoPvPStoneCommand>();
UsageColor = reader.ReadFlag<KnownColor>();
}
break;
}
}
}
}

View File

@@ -0,0 +1,118 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Mobiles;
using VitaNex.Items;
using VitaNex.SuperGumps.UI;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPSpectatorGate : FloorTile<PlayerMobile>
{
[CommandProperty(AutoPvP.Access)]
public PvPBattle Battle { get; set; }
public override bool ForceShowProperties => true;
public PvPSpectatorGate(PvPBattle battle)
{
Battle = battle;
Name = "PvP Battle Gate";
ItemID = 19343;
Hue = 51;
Visible = true;
Movable = false;
}
public PvPSpectatorGate(Serial serial)
: base(serial)
{ }
public override void OnAosSingleClick(Mobile from)
{
OnSingleClick(from);
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
if (Battle == null)
{
return;
}
LabelTo(from, "Battle: {0}", Battle.Name);
LabelTo(from, "Status: {0} ({1})", Battle.State, Battle.GetStateTimeLeft().ToSimpleString("h:m:s"));
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
if (Battle != null)
{
list.Add(
"Battle: {0}\nStatus: {1} ({2})",
Battle.Name,
Battle.State,
Battle.GetStateTimeLeft().ToSimpleString("h:m:s"));
}
}
public override bool OnMoveOver(PlayerMobile mob)
{
if (!base.OnMoveOver(mob) || mob == null || Battle == null || Battle.Deleted || !Battle.SpectateAllowed || Battle.IsInternal)
{
return false;
}
Timer.DelayCall(
TimeSpan.FromSeconds(1),
() =>
{
if (mob.X == X && mob.Y == Y)
{
new ConfirmDialogGump(mob)
{
Title = "Join as Spectator?",
Html = "Join " + Battle.Name +
" as a spectator.\nYou will be teleported to a safe area where you can watch the battle.\nClick OK to join!",
AcceptHandler = b => Battle.AddSpectator(mob, true)
}.Send();
}
});
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

View File

@@ -0,0 +1,118 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Mobiles;
using VitaNex.Items;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPTeamGate : FloorTile<PlayerMobile>
{
[CommandProperty(AutoPvP.Access)]
public PvPTeam Team { get; set; }
public override bool ForceShowProperties => true;
public PvPTeamGate(PvPTeam team)
{
Team = team;
Name = "PvP Team Gate";
Hue = Team.Color;
ItemID = 19343;
Visible = true;
Movable = false;
}
public PvPTeamGate(Serial serial)
: base(serial)
{ }
public override void OnAosSingleClick(Mobile from)
{
OnSingleClick(from);
}
public override void OnSingleClick(Mobile from)
{
base.OnSingleClick(from);
if (Team == null || Team.Battle == null)
{
return;
}
LabelTo(from, "Battle: {0}", Team.Battle.Name);
LabelTo(from, "Team: {0}", Team.Name);
LabelTo(from, "Status: {0} ({1})", Team.Battle.State, Team.Battle.GetStateTimeLeft().ToSimpleString("h:m:s"));
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
if (Team != null && Team.Battle != null)
{
list.Add(
"Battle: {0}\nTeam: {1}\nStatus: {2} ({3})",
Team.Battle.Name,
Team.Name,
Team.Battle.State,
Team.Battle.GetStateTimeLeft().ToSimpleString("h:m:s"));
}
}
public override bool OnMoveOver(PlayerMobile mob)
{
if (mob == null || !base.OnMoveOver(mob))
{
return false;
}
if (Team == null || Team.Deleted || Team.Battle == null || Team.Battle.Deleted || !Team.Battle.QueueAllowed || Team.Battle.IsInternal)
{
return false;
}
Timer.DelayCall(
TimeSpan.FromSeconds(1),
() =>
{
if (mob.X == X && mob.Y == Y)
{
Team.Battle.Enqueue(mob, Team);
}
});
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,858 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Targeting;
using VitaNex.Network;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
public void Teleport(Mobile m, Point3D destLoc, Map destMap)
{
if (m == null || m.Deleted || destLoc == Point3D.Zero || destMap == Map.Internal)
{
return;
}
var oldLoc = m.Location;
var oldMap = m.Map;
var pm = m as PlayerMobile;
if (pm != null && !IsOnline(pm))
{
pm.LogoutLocation = destLoc;
pm.LogoutMap = destMap;
if (!pm.Alive && pm.Corpse != null && !pm.Corpse.Deleted)
{
pm.Corpse.MoveToWorld(destLoc, destMap);
}
OnTeleported(pm, oldLoc, oldMap);
return;
}
if (!m.Hidden)
{
var fx = EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration);
Effects.SendLocationParticles(fx, 0x3728, 10, 10, 5023);
}
m.MoveToWorld(destLoc, destMap);
m.Send(VNScreenLightFlash.Instance);
SendSound(Options.Sounds.Teleport);
if (!m.Hidden)
{
var fx = EffectItem.Create(destLoc, destMap, EffectItem.DefaultDuration);
Effects.SendLocationParticles(fx, 0x3728, 10, 10, 5023);
}
if (m.Location != destLoc || m.Map != destMap)
{
return;
}
if (!m.Alive && m.Corpse != null && !m.Corpse.Deleted)
{
m.Corpse.MoveToWorld(m.Location, m.Map);
}
OnTeleported(m, oldLoc, oldMap);
}
public virtual void TeleportToEjectLocation(PlayerMobile pm)
{
if (pm != null && !pm.Deleted && !Options.Locations.Eject.Zero && !Options.Locations.Eject.Internal)
{
Teleport(pm, Options.Locations.Eject, Options.Locations.Eject);
}
}
public virtual void TeleportToSpectateLocation(PlayerMobile pm)
{
if (pm != null && !pm.Deleted && Options.Locations.SpectateJoin != Point3D.Zero && Options.Locations.Map != null &&
Options.Locations.Map != Map.Internal)
{
Teleport(pm, Options.Locations.SpectateJoin, Options.Locations.Map);
}
}
public virtual void TeleportToHomeBase(PvPTeam team, PlayerMobile pm)
{
if (pm != null && !pm.Deleted && team != null && !team.Deleted)
{
Teleport(pm, team.HomeBase, Options.Locations.Map);
}
}
public virtual void TeleportToSpawnPoint(PvPTeam team, PlayerMobile pm)
{
if (pm == null || pm.Deleted || team == null || team.Deleted)
{
return;
}
var p = team.SpawnPoint;
if (team.RespawnRangeMin > 0 && team.RespawnRangeMax > 0)
{
p = p.GetRandomPoint3D(team.RespawnRangeMin, team.RespawnRangeMax);
}
Teleport(pm, p, Options.Locations.Map);
}
protected virtual void OnTeleported(Mobile m, Point3D oldLocation, Map oldMap)
{
if (m == null || m.Deleted)
{
return;
}
m.UpdateRegion();
if (m is PlayerMobile)
{
OnTeleported((PlayerMobile)m, oldLocation, oldMap);
}
m.Delta(MobileDelta.Noto);
m.ProcessDelta();
}
protected virtual void OnTeleported(PlayerMobile pm, Point3D oldLocation, Map oldMap)
{
if (pm == null || pm.Deleted)
{
return;
}
var old = Region.Find(oldLocation, oldMap);
if (!old.IsPartOf(BattleRegion))
{
if (pm.InRegion(BattleRegion))
{
Negate(pm);
}
}
else
{
if (!pm.InRegion(BattleRegion))
{
Negate(pm);
}
}
}
public virtual bool CheckMounted(Mobile m, bool dismount)
{
if (m == null || m.Deleted || !m.Mounted || m.Mount == null)
{
return false;
}
if (dismount)
{
CheckDismount(m);
}
return true;
}
public virtual bool CheckDismount(Mobile m)
{
if (m == null || m.Deleted)
{
return false;
}
if (!DebugMode && m.AccessLevel >= AccessLevel.Counselor)
{
return false;
}
if (State == PvPBattleState.Internal || Hidden)
{
return false;
}
if (m.Flying && Options.Rules.CanFly)
{
return false;
}
if (m.Mounted)
{
if (m.Mount is EtherealMount && Options.Rules.CanMountEthereal)
{
return false;
}
if (Options.Rules.CanMount)
{
return false;
}
}
Dismount(m);
return true;
}
public virtual void Dismount(Mobile m)
{
if (m == null || m.Deleted)
{
return;
}
if (m.Flying)
{
m.Flying = false;
OnDismounted(m, null);
}
else if (m.Mount != null)
{
var mount = m.Mount;
mount.Rider = null;
OnDismounted(m, mount);
}
}
public virtual void OnDismounted(Mobile m, IMount mount)
{
if (m != null && !m.Deleted)
{
m.SendMessage(mount != null ? "You have been dismounted." : "You have been wing clipped.");
}
}
public bool AllowSpawn()
{
if (CheckAllowSpawn())
{
OnAllowSpawnAccept();
return true;
}
OnAllowSpawnDeny();
return false;
}
public virtual bool CheckAllowSpawn()
{
return Options.Rules.AllowSpawn;
}
protected virtual void OnAllowSpawnAccept()
{ }
protected virtual void OnAllowSpawnDeny()
{ }
public bool CanMoveThrough(Mobile m, IEntity e)
{
if (CheckCanMoveThrough(m, e))
{
OnCanMoveThroughAccept(m, e);
return true;
}
OnCanMoveThroughDeny(m, e);
return false;
}
public virtual bool CheckCanMoveThrough(Mobile m, IEntity e)
{
if (m == null || m.Deleted)
{
return false;
}
if (!DebugMode && m.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
#if NEWENTITY
return e == null || e.Deleted || Options.Rules.CanMoveThrough;
#else
return e == null || (e is Mobile && ((Mobile)e).Deleted) || (e is Item && ((Item)e).Deleted) ||
Options.Rules.CanMoveThrough;
#endif
}
protected virtual void OnCanMoveThroughAccept(Mobile m, IEntity e)
{ }
protected virtual void OnCanMoveThroughDeny(Mobile m, IEntity e)
{ }
public bool AllowHousing(Mobile m, Point3D p)
{
if (CheckAllowHousing(m, p))
{
OnAllowHousingAccept(m, p);
return true;
}
OnAllowHousingDeny(m, p);
return false;
}
public virtual bool CheckAllowHousing(Mobile m, Point3D p)
{
if (m == null || m.Deleted)
{
return false;
}
if (!DebugMode && m.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
return Options.Rules.AllowHousing;
}
protected virtual void OnAllowHousingAccept(Mobile m, Point3D p)
{ }
protected virtual void OnAllowHousingDeny(Mobile m, Point3D p)
{
if (m != null && !m.Deleted)
{
m.SendMessage("You can not place structures here at this time.");
}
}
public bool CanUseStuckMenu(Mobile m)
{
if (CheckCanUseStuckMenu(m))
{
OnCanUseStuckMenuAccept(m);
return true;
}
OnCanUseStuckMenuDeny(m);
return false;
}
public virtual bool CheckCanUseStuckMenu(Mobile m)
{
if (m == null || m.Deleted)
{
return false;
}
if (!DebugMode && m.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
return Options.Rules.CanUseStuckMenu;
}
protected virtual void OnCanUseStuckMenuAccept(Mobile m)
{ }
protected virtual void OnCanUseStuckMenuDeny(Mobile m)
{
if (m != null && !m.Deleted)
{
m.SendMessage("You can not use the stuck menu at this time.");
}
}
public bool OnBeforeDeath(Mobile m)
{
if (CheckDeath(m))
{
OnDeathAccept(m);
return true;
}
OnDeathDeny(m);
return false;
}
public virtual bool CheckDeath(Mobile m)
{
if (m == null || m.Deleted)
{
return false;
}
if (!DebugMode && m.AccessLevel >= AccessLevel.Counselor)
{
return false;
}
return Options.Rules.CanDie;
}
protected virtual void OnDeathAccept(Mobile m)
{
if (m == null || m.Deleted)
{
return;
}
var pm = m as PlayerMobile;
if (pm == null)
{
return;
}
if (IsParticipant(pm, out var team) && team != null && !team.Deleted)
{
team.OnMemberDeath(pm);
}
}
protected virtual void OnDeathDeny(Mobile m)
{
if (m == null || m.Deleted)
{
return;
}
var pm = m as PlayerMobile;
if (pm == null)
{
return;
}
if (IsParticipant(pm, out var team) && team != null && !team.Deleted)
{
team.OnMemberDeath(pm);
}
}
public virtual void OnDeath(Mobile m)
{ }
public bool OnSkillUse(Mobile user, int skill)
{
if (CheckSkillUse(user, skill))
{
OnSkillUseAccept(user, skill);
return true;
}
OnSkillUseDeny(user, skill);
return false;
}
public virtual bool CheckSkillUse(Mobile user, int skill)
{
if (user == null || user.Deleted || skill < 0)
{
return false;
}
if (!DebugMode && user.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
return !Options.Restrictions.Skills.IsRestricted(skill);
}
protected virtual void OnSkillUseAccept(Mobile user, int skill)
{ }
protected virtual void OnSkillUseDeny(Mobile user, int skill)
{
if (user != null && !user.Deleted && skill >= 0)
{
user.SendMessage("You can not use that skill at this time.");
}
}
public bool OnBeginSpellCast(Mobile caster, ISpell spell)
{
if (CheckSpellCast(caster, spell))
{
OnSpellCastAccept(caster, spell);
return true;
}
OnSpellCastDeny(caster, spell);
return false;
}
public virtual bool CheckSpellCast(Mobile caster, ISpell spell)
{
if (caster == null || caster.Deleted || spell == null)
{
return false;
}
if (!DebugMode && caster.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
if (!(spell is Spell))
{
return true;
}
if (!Options.Rules.CanFly)
{
var t = spell.GetType();
if (t.Name.ContainsAny("FlySpell", "FlightSpell"))
{
return false;
}
}
return !Options.Restrictions.Spells.IsRestricted((Spell)spell);
}
protected virtual void OnSpellCastAccept(Mobile caster, ISpell spell)
{ }
protected virtual void OnSpellCastDeny(Mobile caster, ISpell spell)
{
if (caster != null && !caster.Deleted && spell != null)
{
caster.SendMessage("You can not use that spell at this time.");
}
}
public virtual bool CheckDamage(Mobile damaged, ref int damage)
{
if (damaged == null || damaged.Deleted)
{
return false;
}
if (!DebugMode && damaged.AccessLevel >= AccessLevel.Counselor)
{
return false;
}
return Options.Rules.CanBeDamaged;
}
public virtual void OnDamage(Mobile damager, Mobile damaged, int damage)
{
if (damage <= 0)
{
return;
}
PlayerMobile pm;
PvPTeam t;
if (damager != null && !damager.Deleted && damager is PlayerMobile)
{
pm = (PlayerMobile)damager;
if (IsParticipant(pm, out t))
{
var d = damage;
UpdateStatistics(t, pm, o => o.DamageDone += d);
}
}
if (damaged != null && !damaged.Deleted && damaged is PlayerMobile)
{
pm = (PlayerMobile)damaged;
if (IsParticipant(pm, out t))
{
var d = damage;
UpdateStatistics(t, pm, o => o.DamageTaken += d);
}
}
}
public virtual bool CheckHeal(Mobile healed, ref int heal)
{
if (healed == null || healed.Deleted)
{
return false;
}
if (!DebugMode && healed.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
return Options.Rules.CanHeal;
}
public virtual void OnHeal(Mobile healer, Mobile healed, int heal)
{
if (heal <= 0)
{
return;
}
PlayerMobile pm;
PvPTeam t;
if (healer != null && !healer.Deleted && healer is PlayerMobile)
{
pm = (PlayerMobile)healer;
if (IsParticipant(pm, out t))
{
var h = heal;
UpdateStatistics(t, pm, o => o.HealingDone += h);
}
}
if (healed != null && !healed.Deleted && healed is PlayerMobile)
{
pm = (PlayerMobile)healed;
if (IsParticipant(pm, out t))
{
var h = heal;
UpdateStatistics(t, pm, o => o.HealingTaken += h);
}
}
}
public bool OnResurrect(Mobile m)
{
if (CheckResurrect(m))
{
OnResurrectAccept(m);
return true;
}
OnResurrectDeny(m);
return false;
}
public virtual bool CheckResurrect(Mobile m)
{
if (m == null || m.Deleted)
{
return false;
}
if (!DebugMode && m.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
return Options.Rules.CanResurrect;
}
protected virtual void OnResurrectAccept(Mobile m)
{
if (m == null || m.Deleted)
{
return;
}
var pm = m as PlayerMobile;
if (pm == null)
{
return;
}
if (IsParticipant(pm, out var team) && team != null && !team.Deleted)
{
team.OnMemberResurrected(pm);
}
}
protected virtual void OnResurrectDeny(Mobile m)
{
if (m != null && !m.Deleted)
{
m.SendMessage("You can not be resurrected at this time.");
}
}
public void OnSpeech(SpeechEventArgs args)
{
if (args.Mobile is PlayerMobile)
{
var pm = (PlayerMobile)args.Mobile;
if (HandleSubCommand(pm, args.Speech))
{
args.Handled = true;
args.Blocked = true;
return;
}
}
if (CheckSpeech(args))
{
OnSpeechAccept(args);
return;
}
args.Handled = true;
args.Blocked = true;
OnSpeechDeny(args);
}
public virtual bool CheckSpeech(SpeechEventArgs e)
{
if (e.Mobile == null || e.Mobile.Deleted)
{
return false;
}
if (!DebugMode && e.Mobile.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
return Options.Rules.AllowSpeech;
}
protected virtual void OnSpeechAccept(SpeechEventArgs args)
{ }
protected virtual void OnSpeechDeny(SpeechEventArgs args)
{
if (args.Mobile != null && !args.Mobile.Deleted)
{
args.Mobile.SendMessage("You can not talk at this time.");
}
}
public virtual void OnSpellCast(Mobile m, ISpell s)
{ }
public virtual void OnAggressed(Mobile aggressor, Mobile aggressed, bool criminal)
{ }
public virtual void OnBeneficialAction(Mobile helper, Mobile target)
{ }
public virtual bool OnCombatantChange(Mobile m, Mobile oldMob, Mobile newMob)
{
return m != null && !m.Deleted;
}
public virtual void OnCriminalAction(Mobile m, bool message)
{ }
public virtual void OnDidHarmful(Mobile harmer, Mobile harmed)
{ }
public virtual bool OnDoubleClick(Mobile m, object o)
{
if (o is Item)
{
return OnDoubleClick(m, (Item)o);
}
if (o is Mobile)
{
return OnDoubleClick(m, (Mobile)o);
}
return m != null && !m.Deleted && o != null;
}
public virtual bool OnDoubleClick(Mobile m, Item item)
{
return m != null && !m.Deleted && item != null && !item.Deleted && CanUseItem(m, item, true);
}
public virtual bool OnDoubleClick(Mobile m, Mobile target)
{
if (target is BaseCreature)
{
return OnDoubleClick(m, (BaseCreature)target);
}
return m != null && !m.Deleted && target != null && !target.Deleted && CanUseMobile(m, target, true);
}
public virtual bool OnDoubleClick(Mobile m, BaseCreature target)
{
return m != null && !m.Deleted && target != null && !target.Deleted && CanUseMobile(m, target, true);
}
public virtual bool OnSingleClick(Mobile m, object o)
{
if (o is Item)
{
return OnSingleClick(m, (Item)o);
}
if (o is Mobile)
{
return OnSingleClick(m, (Mobile)o);
}
return m != null && !m.Deleted && o != null;
}
public virtual bool OnSingleClick(Mobile m, Item item)
{
return m != null && !m.Deleted && item != null && !item.Deleted && CanUseItem(m, item, false);
}
public virtual bool OnSingleClick(Mobile m, Mobile target)
{
if (target is BaseCreature)
{
return OnSingleClick(m, (BaseCreature)target);
}
return m != null && !m.Deleted && target != null && !target.Deleted && CanUseMobile(m, target, false);
}
public virtual bool OnSingleClick(Mobile m, BaseCreature target)
{
return m != null && !m.Deleted && target != null && !target.Deleted && CanUseMobile(m, target, false);
}
public virtual void OnGotBeneficialAction(Mobile helper, Mobile target)
{ }
public virtual void OnGotHarmful(Mobile harmer, Mobile harmed)
{ }
public virtual bool OnTarget(Mobile m, Target target, object o)
{
return m != null && !m.Deleted && target != null && o != null;
}
}
}

View File

@@ -0,0 +1,610 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Mobiles;
using Server.Regions;
using VitaNex.SuperGumps;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
[CommandProperty(AutoPvP.Access)]
public virtual TimeSpan LogoutDelay { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual TimeSpan IdleThreshold { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool IdleKick { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool InviteWhileRunning { get; set; }
public virtual Dictionary<PlayerMobile, MapPoint> BounceInfo { get; private set; }
public virtual bool InOtherBattle(PlayerMobile pm)
{
if (pm == null)
{
return false;
}
var battle = AutoPvP.FindBattle(pm);
return battle != null && battle != this && battle.IsParticipant(pm);
}
public bool IsAliveParticipant(PlayerMobile pm)
{
if (pm == null)
{
return false;
}
return IsParticipant(pm, out var team) && !team.IsDead(pm);
}
public bool IsDeadParticipant(PlayerMobile pm)
{
if (pm == null)
{
return false;
}
return IsParticipant(pm, out var team) && team.IsDead(pm);
}
public bool IsParticipant(PlayerMobile pm)
{
if (pm == null)
{
return false;
}
return IsParticipant(pm, out var team);
}
public bool IsParticipant(PlayerMobile pm, out PvPTeam team)
{
if (pm == null)
{
team = null;
return false;
}
team = FindTeam(pm);
return team != null;
}
public virtual TimeSpan GetLogoutDelay(Mobile m)
{
return LogoutDelay;
}
public IEnumerable<PlayerMobile> GetParticipants()
{
return Teams.Where(t => t != null && !t.Deleted).SelectMany(t => t.Where(p => p != null && !p.Deleted));
}
public virtual bool CanSendInvites()
{
return !Hidden && (IsPreparing || (IsRunning && InviteWhileRunning)) && CurrentCapacity < MaxCapacity;
}
public virtual bool CanSendInvite(PlayerMobile pm)
{
return pm != null && !pm.Deleted && pm.Alive && !pm.InRegion<Jail>() && pm.DesignContext == null && IsOnline(pm) &&
!InCombat(pm) && IsQueued(pm) && !IsParticipant(pm) && !InOtherBattle(pm) && !AutoPvP.IsDeserter(pm);
}
public virtual void SendInvites()
{
foreach (var pm in Queue.Keys)
{
var invites = SuperGump.GetInstances<PvPInviteGump>(pm);
if (CanSendInvite(pm))
{
var sendNew = invites.All(invite => !invite.IsOpen || invite.Battle != this);
if (sendNew)
{
OnSendInvite(pm, new PvPInviteGump(pm, this));
}
}
else
{
foreach (var invite in invites.Where(invite => invite.IsOpen && invite.Battle == this))
{
invite.Close();
}
}
}
}
protected virtual void OnSendInvite(PlayerMobile pm, PvPInviteGump invite)
{
if (pm == null || pm.Deleted || !pm.Alive || invite == null || invite.IsDisposed)
{
return;
}
invite.Send();
SendSound(pm, Options.Sounds.InviteSend);
}
public void AcceptInvite(PlayerMobile pm)
{
if (pm == null || pm.Deleted || !pm.Alive)
{
return;
}
if (CanSendInvites() && CanSendInvite(pm))
{
OnInviteAccept(pm);
}
else
{
OnInviteRejected(pm);
}
}
public void DeclineInvite(PlayerMobile pm)
{
if (pm != null && !pm.Deleted)
{
OnInviteDecline(pm);
}
}
protected virtual void OnInviteAccept(PlayerMobile pm)
{
if (pm == null || pm.Deleted || !IsOnline(pm) || IsInternal || Hidden)
{
return;
}
if (!IsQueued(pm))
{
pm.SendMessage("You are not queued for {0}", Name);
return;
}
if (IsParticipant(pm))
{
pm.SendMessage("You are already participating in {0}", Name);
return;
}
if (InOtherBattle(pm))
{
pm.SendMessage("You cannot join {0} while you are in another battle.", Name);
return;
}
if (IsFull)
{
pm.SendMessage("The battle is full, you will be sent an invite if someone leaves.");
return;
}
var team = Queue[pm];
if (team == null || team.Deleted) // Assume AutoAssign is true
{
if (Teams.Count == 1)
{
team = Teams[0];
}
else if (AutoAssign) // Make sure AutoAssign is true
{
team = GetAutoAssignTeam(pm);
}
}
if (team == null || team.Deleted) // Fallback to most empty, or random team
{
team = GetMostEmptyTeam();
if (team == null || team.Deleted)
{
team = GetRandomTeam();
}
}
if (team == null || team.Deleted)
{
pm.SendMessage("The team you've chosen seems to have vanished in the void, sorry about that.");
Queue.Remove(pm);
return;
}
if (team.IsFull)
{
pm.SendMessage("The team you've chosen is full, you will be sent an invite if someone leaves.");
return;
}
Queue.Remove(pm);
RecordBounce(pm);
team.AddMember(pm, true);
SendSound(pm, Options.Sounds.InviteAccept);
}
protected virtual void OnInviteDecline(PlayerMobile pm)
{
if (pm == null || pm.Deleted)
{
return;
}
pm.SendMessage("You decide not to join {0}", Name);
SendSound(pm, Options.Sounds.InviteCancel);
if (IsQueued(pm))
{
Dequeue(pm);
}
}
protected virtual void OnInviteRejected(PlayerMobile pm)
{
if (pm == null || pm.Deleted)
{
return;
}
pm.SendMessage("You can not join {0} at this time.", Name);
SendSound(pm, Options.Sounds.InviteCancel);
}
public void RecordBounce(PlayerMobile pm)
{
if (pm == null || pm.Deleted || pm.InRegion<PvPBattleRegion>())
{
return;
}
var bounce = pm.ToMapPoint();
if (bounce != null && !bounce.InternalOrZero)
{
BounceInfo[pm] = bounce;
}
}
public void Quit(Mobile m, bool teleport)
{
var pm = m as PlayerMobile;
if (pm != null)
{
if (IsParticipant(pm, out var team))
{
UpdateStatistics(team, pm, o => ++o.Losses);
if (IsRunning)
{
OnDeserted(team, pm);
}
}
}
Eject(m, teleport);
}
public void Eject(Mobile m, bool teleport)
{
if (m == null || m.Deleted)
{
return;
}
if (m is PlayerMobile)
{
Eject((PlayerMobile)m, teleport);
}
else if (m is BaseCreature)
{
Eject((BaseCreature)m, teleport);
}
}
public void Eject(PlayerMobile pm, bool teleport)
{
if (pm == null || pm.Deleted)
{
return;
}
if (IsParticipant(pm, out var team))
{
if (IsRunning || IsEnded)
{
UpdateStatistics(team, pm, o => ++o.Battles);
}
team.RemoveMember(pm, false);
}
else if (IsSpectator(pm))
{
RemoveSpectator(pm, false);
}
if (teleport)
{
var bounce = BounceInfo.GetValue(pm);
if (bounce != null && !bounce.InternalOrZero)
{
Teleport(pm, bounce, bounce);
BounceInfo.Remove(pm);
}
else
{
Teleport(pm, Options.Locations.Eject, Options.Locations.Eject.Map);
}
}
}
public void Eject(BaseCreature bc, bool teleportOrStable)
{
if (bc == null || bc.Deleted)
{
return;
}
var pet = bc.IsControlled<PlayerMobile>();
if (!teleportOrStable)
{
if (!pet)
{
bc.Delete();
}
return;
}
if (!pet || !bc.Stable())
{
Teleport(bc, Options.Locations.Eject, Options.Locations.Eject);
}
}
protected virtual void OnEjected(Mobile m)
{
if (m == null || m.Deleted)
{
return;
}
if (m is PlayerMobile)
{
OnEjected((PlayerMobile)m);
}
else if (m is BaseCreature)
{
OnEjected((BaseCreature)m);
}
}
protected virtual void OnEjected(PlayerMobile pm)
{
if (pm != null && !pm.Deleted)
{
pm.SendMessage("You have been ejected from the battle.");
}
}
protected virtual void OnEjected(BaseCreature bc)
{ }
protected virtual void OnDeserted(PvPTeam team, PlayerMobile pm)
{
if (pm == null || pm.Deleted)
{
return;
}
pm.SendMessage(0x22, "You have deserted {0}!", Name);
AutoPvP.AddDeserter(pm);
RevokePoints(pm);
UpdateStatistics(team, pm, o => ++o["Deserted"]);
WorldBroadcast("{0} has deserted {1}!", pm.RawName, Name);
}
public virtual void InvalidateStray(Mobile m)
{
if (IsInternal || Hidden || m == null || m.Deleted)
{
return;
}
if (m is PlayerMobile)
{
InvalidateStrayPlayer((PlayerMobile)m);
}
else if (m is BaseCreature)
{
var bc = (BaseCreature)m;
if (bc.IsControlled())
{
InvalidateStrayPet(bc);
}
else
{
InvalidateStraySpawn(bc);
}
}
}
public virtual void InvalidateStrayPlayer(PlayerMobile player)
{
if (IsInternal || Hidden || player == null || player.Deleted)
{
return;
}
if (player.InRegion(SpectateRegion))
{
if (IsParticipant(player))
{
Eject(player, false);
}
if (!IsSpectator(player))
{
AddSpectator(player, false);
}
}
else if (player.InRegion(BattleRegion))
{
if (IsParticipant(player))
{
if (IsSpectator(player))
{
RemoveSpectator(player, false);
}
Queue.Remove(player);
if (DebugMode || player.AccessLevel < AccessLevel.Counselor)
{
if (player.Flying && !Options.Rules.CanFly)
{
player.Flying = false;
}
if (player.Mounted)
{
var canMount = Options.Rules.CanMount;
if (player.Mount is EtherealMount)
{
canMount = Options.Rules.CanMountEthereal;
}
if (!canMount)
{
player.Dismount();
}
}
}
}
else if (!IsSpectator(player))
{
if ((DebugMode || player.AccessLevel < AccessLevel.Counselor) && SpectateAllowed)
{
AddSpectator(player, true);
}
else if (DebugMode || player.AccessLevel < AccessLevel.Counselor)
{
Eject(player, true);
}
}
}
}
public virtual void InvalidateStraySpawn(BaseCreature mob)
{
if (IsInternal || Hidden || mob == null || mob.Deleted || !mob.InRegion(BattleRegion))
{
return;
}
if (!AllowSpawn())
{
Eject(mob, mob.IsControlled<PlayerMobile>());
}
}
public virtual void InvalidateStrayPet(BaseCreature pet)
{
if (IsInternal || Hidden || pet == null || pet.Deleted || !pet.InRegion(BattleRegion))
{
return;
}
if (!Options.Rules.AllowPets)
{
var master = pet.GetMaster<PlayerMobile>();
if (master == null || DebugMode || master.AccessLevel < AccessLevel.Counselor)
{
Eject(pet, master != null);
}
}
}
public virtual void InvalidateGates()
{
InvalidateSpectateGate();
InvalidateTeamGates();
}
public virtual void InvalidateSpectateGate()
{
if (!SpectateAllowed || SpectateRegion == null || IsInternal || Options.Locations.SpectateGate.InternalOrZero)
{
if (Gate != null)
{
Gate.Delete();
Gate = null;
}
return;
}
if (Gate == null || Gate.Deleted)
{
Gate = new PvPSpectatorGate(this);
if (!Options.Locations.SpectateGate.MoveToWorld(Gate))
{
Gate.MoveToWorld(Options.Locations.SpectateGate, Options.Locations.SpectateGate);
}
}
if (Gate.Battle == null)
{
Gate.Battle = this;
}
}
public virtual void InvalidateTeamGates()
{
ForEachTeam(t => t.InvalidateGate());
}
}
}

View File

@@ -0,0 +1,293 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#if ServUO58
#define ServUOX
#endif
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Commands;
using Server.Mobiles;
using Server.Network;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public enum PvPBattleWarning
{
Starting,
Ending,
WBStarting,
WBEnding
}
public abstract partial class PvPBattle
{
public virtual IEnumerable<PlayerMobile> GetLocalBroadcastList()
{
if (BattleRegion != null)
{
#if ServUOX
foreach (var pm in BattleRegion.AllPlayers.OfType<PlayerMobile>().Where(IsOnline))
#else
foreach (var pm in BattleRegion.GetMobiles().OfType<PlayerMobile>().Where(IsOnline))
#endif
{
yield return pm;
}
}
if (SpectateRegion != null)
{
#if ServUOX
foreach (var pm in SpectateRegion.AllPlayers.OfType<PlayerMobile>().Where(IsOnline))
#else
foreach (var pm in SpectateRegion.GetMobiles().OfType<PlayerMobile>().Where(IsOnline))
#endif
{
yield return pm;
}
}
}
public virtual IEnumerable<PlayerMobile> GetWorldBroadcastList()
{
return NetState.Instances.Where(state => state != null)
.Select(state => state.Mobile as PlayerMobile)
.Where(pm => pm != null && !pm.Deleted)
.Where(pm => IsOnline(pm) && AutoPvP.EnsureProfile(pm).IsSubscribed(this));
}
public virtual void LocalBroadcast(string message, params object[] args)
{
var text = String.Format(message, args);
if (String.IsNullOrWhiteSpace(text))
{
return;
}
if (Options.Broadcasts.Local.Mode == PvPBattleLocalBroadcastMode.Disabled)
{
return;
}
AutoPvP.InvokeBattleLocalBroadcast(this, text);
foreach (var pm in GetLocalBroadcastList())
{
pm.SendMessage(IsParticipant(pm, out var team) ? team.Color : Options.Broadcasts.Local.MessageHue, text);
}
}
public virtual void WorldBroadcast(string message, params object[] args)
{
var text = String.Format(message, args);
if (String.IsNullOrWhiteSpace(text))
{
return;
}
if (Options.Broadcasts.World.Mode == PvPBattleWorldBroadcastMode.Disabled)
{
return;
}
AutoPvP.InvokeBattleWorldBroadcast(this, text);
switch (Options.Broadcasts.World.Mode)
{
case PvPBattleWorldBroadcastMode.Notify:
{
foreach (var pm in GetWorldBroadcastList())
{
pm.SendNotification(text, true, 0.5, 10.0);
}
}
break;
case PvPBattleWorldBroadcastMode.Broadcast:
{
var p = new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Regular, Options.Broadcasts.World.MessageHue, 3, "System", text);
p.Acquire();
foreach (var pm in GetWorldBroadcastList())
{
pm.Send(p);
}
p.Release();
NetState.FlushAll();
}
break;
case PvPBattleWorldBroadcastMode.TownCrier:
{
foreach (var tc in TownCrier.Instances)
{
tc.PublicOverheadMessage(MessageType.Yell, Options.Broadcasts.World.MessageHue, true, String.Format(message, args));
}
}
break;
}
}
protected virtual void BroadcastStateHandler()
{
if (Hidden)
{
return;
}
var state = State;
var timeLeft = GetStateTimeLeft(DateTime.UtcNow).Add(TimeSpan.FromSeconds(1.0));
if (timeLeft <= TimeSpan.Zero)
{
return;
}
switch (state)
{
case PvPBattleState.Ended:
BroadcastOpenMessage(timeLeft);
break;
case PvPBattleState.Preparing:
BroadcastStartMessage(timeLeft);
break;
case PvPBattleState.Running:
BroadcastEndMessage(timeLeft);
break;
}
}
protected virtual void BroadcastOpenMessage(TimeSpan timeLeft)
{
if (timeLeft.Minutes > 5 || timeLeft.Minutes == 0 || timeLeft.Seconds != 0)
{
return;
}
var msg = String.Format("{0} {1}", timeLeft.Minutes, timeLeft.Minutes != 1 ? "minutes" : "minute");
if (String.IsNullOrWhiteSpace(msg))
{
return;
}
if (Options.Broadcasts.Local.OpenNotify)
{
LocalBroadcast("{0} will open in {1}!", Name, msg);
}
if (Options.Broadcasts.World.OpenNotify)
{
var cmd = String.Empty;
if (QueueAllowed)
{
cmd = AutoPvP.CMOptions.Advanced.Commands.BattlesCommand;
cmd = String.Format("Use {0}{1} to join!", CommandSystem.Prefix, cmd);
}
WorldBroadcast("{0} will open in {1}! {2}", Name, msg, cmd);
}
}
protected virtual void BroadcastStartMessage(TimeSpan timeLeft)
{
if ((timeLeft.Minutes == 0 && timeLeft.Seconds > 10) || timeLeft.Minutes > 5)
{
return;
}
var msg = String.Empty;
if (timeLeft.Minutes > 0)
{
if (timeLeft.Seconds == 0)
{
msg = String.Format("{0} {1}", timeLeft.Minutes, timeLeft.Minutes != 1 ? "minutes" : "minute");
}
}
else if (timeLeft.Seconds > 0)
{
msg = String.Format("{0} {1}", timeLeft.Seconds, timeLeft.Seconds != 1 ? "seconds" : "second");
}
if (String.IsNullOrWhiteSpace(msg))
{
return;
}
if (Options.Broadcasts.Local.StartNotify)
{
LocalBroadcast("{0} will start in {1}!", Name, msg);
}
if (Options.Broadcasts.World.StartNotify && timeLeft.Minutes > 0)
{
var cmd = String.Empty;
if (QueueAllowed)
{
cmd = AutoPvP.CMOptions.Advanced.Commands.BattlesCommand;
cmd = String.Format("Use {0}{1} to join!", CommandSystem.Prefix, cmd);
}
WorldBroadcast("{0} will start in {1}! {2}", Name, msg, cmd);
}
}
protected virtual void BroadcastEndMessage(TimeSpan timeLeft)
{
if ((timeLeft.Minutes == 0 && timeLeft.Seconds > 10) || timeLeft.Minutes > 5)
{
return;
}
var msg = String.Empty;
if (timeLeft.Minutes > 0)
{
if (timeLeft.Seconds == 0)
{
msg = String.Format("{0} {1}", timeLeft.Minutes, timeLeft.Minutes != 1 ? "minutes" : "minute");
}
}
else if (timeLeft.Seconds > 0)
{
msg = String.Format("{0} {1}", timeLeft.Seconds, timeLeft.Seconds != 1 ? "seconds" : "second");
}
if (String.IsNullOrWhiteSpace(msg))
{
return;
}
if (Options.Broadcasts.Local.EndNotify)
{
LocalBroadcast("{0} will end in {1}!", Name, msg);
}
if (Options.Broadcasts.World.EndNotify && timeLeft.Minutes > 0)
{
WorldBroadcast("{0} will end in {1}", Name, msg);
}
}
}
}

View File

@@ -0,0 +1,107 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
[CommandProperty(AutoPvP.Access)]
public virtual int KillPoints { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int PointsBase { get; set; }
public virtual int GetAwardPoints(PvPTeam team, PlayerMobile pm)
{
if (!IsRunning || team == null || team.Deleted || (pm != null && !team.IsMember(pm)))
{
return 0;
}
return PointsBase;
}
public virtual void AwardPoints(PlayerMobile pm)
{
if (pm != null)
{
AwardPoints(pm, GetAwardPoints(FindTeam(pm), pm));
}
}
public virtual void AwardPoints(PlayerMobile pm, int points)
{
if (pm != null && points > 0)
{
if (IsParticipant(pm, out var t))
{
UpdateStatistics(t, pm, o => o.PointsGained += points);
}
}
}
public virtual void RevokePoints(PlayerMobile pm)
{
if (pm != null)
{
RevokePoints(pm, GetAwardPoints(FindTeam(pm), pm));
}
}
public virtual void RevokePoints(PlayerMobile pm, int points)
{
if (pm != null && points > 0)
{
if (IsParticipant(pm, out var t))
{
UpdateStatistics(t, pm, o => o.PointsLost += points);
}
}
}
public virtual void AwardTeamPoints(PvPTeam team)
{
if (team != null)
{
team.ForEachMember(pm => UpdateStatistics(team, pm, o => o.PointsGained += GetAwardPoints(team, pm)));
}
}
public virtual void AwardTeamPoints(PvPTeam team, int points)
{
if (team != null && points > 0)
{
team.ForEachMember(pm => UpdateStatistics(team, pm, o => o.PointsGained += points));
}
}
public virtual void RevokeTeamPoints(PvPTeam team)
{
if (team != null)
{
team.ForEachMember(pm => UpdateStatistics(team, pm, o => o.PointsLost += GetAwardPoints(team, pm)));
}
}
public virtual void RevokeTeamPoints(PvPTeam team, int points)
{
if (team != null)
{
team.ForEachMember(pm => UpdateStatistics(team, pm, o => o.PointsLost += points));
}
}
}
}

View File

@@ -0,0 +1,183 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Engines.PartySystem;
using Server.Mobiles;
using Server.Regions;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
public Dictionary<PlayerMobile, PvPTeam> Queue { get; private set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool QueueAllowed { get; set; }
public virtual IEnumerable<PlayerMobile> GetQueued(PvPTeam team)
{
foreach (var kvp in Queue.Where(kvp => kvp.Value == team))
{
yield return kvp.Key;
}
}
public virtual void EnqueueParty(PlayerMobile pm, Party party, PvPTeam team = null)
{
if (pm == null || pm.Deleted || party == null || !party.Active || party.Leader != pm)
{
return;
}
var players = party.Members.Where(pmi => pmi != null && pmi.Mobile != pm)
.Select(pmi => pmi.Mobile as PlayerMobile)
.Where(m => m != null);
foreach (var m in players)
{
Enqueue(m, team, false);
}
}
public virtual void Enqueue(PlayerMobile pm, PvPTeam team = null, bool party = true)
{
if (pm == null || pm.Deleted)
{
return;
}
if (!CanQueue(pm))
{
OnQueueReject(pm);
return;
}
if (team != null && team.Deleted)
{
team = null;
}
if (!IsQueued(pm))
{
Queue.Add(pm, team);
OnQueueJoin(pm, team);
}
else
{
Queue[pm] = team;
OnQueueUpdate(pm, team);
}
if (party)
{
EnqueueParty(pm, Party.Get(pm), team);
}
}
public virtual void Dequeue(PlayerMobile pm)
{
if (pm == null || pm.Deleted)
{
return;
}
var team = Queue.GetValue(pm);
if (Queue.Remove(pm))
{
OnQueueLeave(pm, team);
}
}
public virtual bool CanQueue(PlayerMobile pm)
{
return !IsInternal && QueueAllowed && IsOnline(pm) && pm.Alive && !InCombat(pm) && !IsQueued(pm) &&
!InOtherBattle(pm) && !AutoPvP.IsDeserter(pm) && !pm.InRegion<Jail>();
}
public virtual bool IsQueued(PlayerMobile pm)
{
return pm != null && Queue.ContainsKey(pm);
}
protected virtual void OnQueueJoin(PlayerMobile pm, PvPTeam team)
{
if (pm == null || pm.Deleted)
{
return;
}
pm.SendMessage(
"You have joined the queue for {0}{1}",
Name,
team != null ? ", your team is " + team.Name : String.Empty);
SendSound(pm, Options.Sounds.QueueJoin);
AutoPvP.InvokeQueueJoin(this, team, pm);
}
protected virtual void OnQueueUpdate(PlayerMobile pm, PvPTeam team)
{
if (pm == null || pm.Deleted)
{
return;
}
pm.SendMessage(
"Your queue status for {0} has changed{1}",
Name,
team != null ? ", your team is " + team.Name : String.Empty);
SendSound(pm, Options.Sounds.QueueJoin);
AutoPvP.InvokeQueueUpdate(this, team, pm);
}
protected virtual void OnQueueLeave(PlayerMobile pm, PvPTeam team)
{
if (pm == null || pm.Deleted || IsParticipant(pm))
{
return;
}
pm.SendMessage("You have left the queue for {0}", Name);
SendSound(pm, Options.Sounds.QueueLeave);
AutoPvP.InvokeQueueLeave(this, team, pm);
}
protected virtual void OnQueueReject(PlayerMobile pm)
{
if (pm == null || pm.Deleted)
{
return;
}
if (IsQueued(pm))
{
pm.SendMessage("You are already in the queue for {0}", Name);
}
else
{
pm.SendMessage("You can not queue for {0} at this time.", Name);
}
}
}
}

View File

@@ -0,0 +1,578 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
private PvPBattleRegion _BattleRegion;
private PvPSpectateRegion _SpectateRegion;
private bool _FloorItemDelete = true;
private int _LightLevel = 100;
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleRegion BattleRegion
{
get => _BattleRegion;
set
{
if (_BattleRegion == value)
{
return;
}
_BattleRegion = value;
if (!Deserializing)
{
InvalidateBattleRegion();
}
}
}
[CommandProperty(AutoPvP.Access)]
public virtual PvPSpectateRegion SpectateRegion
{
get => _SpectateRegion;
set
{
if (_SpectateRegion == value)
{
return;
}
_SpectateRegion = value;
if (!Deserializing)
{
InvalidateSpectateRegion();
}
}
}
[CommandProperty(AutoPvP.Access)]
public virtual bool FloorItemDelete
{
get => _BattleRegion == null ? _FloorItemDelete : (_FloorItemDelete = _BattleRegion.FloorItemDelete);
set => _FloorItemDelete = _BattleRegion == null ? value : (_BattleRegion.FloorItemDelete = value);
}
[CommandProperty(AutoPvP.Access)]
public virtual int LightLevel { get => _LightLevel; set => _LightLevel = Math.Max(0, Math.Min(100, value)); }
[CommandProperty(AutoPvP.Access)]
public virtual string BattleRegionName => String.Format("{0} ({1})", Name, Serial);
[CommandProperty(AutoPvP.Access)]
public virtual string SpectateRegionName => String.Format("{0} (Safe) ({1})", Name, Serial);
public virtual void InvalidateRegions()
{
if (Deserializing)
{
return;
}
InvalidateBattleRegion();
InvalidateSpectateRegion();
}
public virtual void InvalidateBattleRegion()
{
if (Deserializing)
{
return;
}
if (_BattleRegion != null)
{
if (_BattleRegion.Map == Map &&
_BattleRegion.Area.GetBoundsHashCode() == Options.Locations.BattleBounds.GetBoundsHashCode())
{
return;
}
_BattleRegion.Unregister();
}
if (Options.Locations.BattleFixedPoint == Point3D.Zero)
{
_BattleRegion = null;
return;
}
_BattleRegion = _BattleRegion != null ? _BattleRegion.Clone(this) : RegionExtUtility.Create<PvPBattleRegion>(this);
if (_BattleRegion == null)
{
return;
}
_BattleRegion.GoLocation = Options.Locations.BattleFixedPoint;
_BattleRegion.Register();
}
public virtual void InvalidateSpectateRegion()
{
if (Deserializing)
{
return;
}
if (_SpectateRegion != null)
{
if (_SpectateRegion.Map == Map && _SpectateRegion.Area.GetBoundsHashCode() ==
Options.Locations.SpectateBounds.GetBoundsHashCode())
{
return;
}
_SpectateRegion.Unregister();
}
if (Options.Locations.SpectateFixedPoint == Point3D.Zero)
{
_SpectateRegion = null;
return;
}
_SpectateRegion = _SpectateRegion != null
? _SpectateRegion.Clone(this)
: RegionExtUtility.Create<PvPSpectateRegion>(this);
if (_SpectateRegion == null)
{
return;
}
_SpectateRegion.GoLocation = Options.Locations.SpectateFixedPoint;
_SpectateRegion.Register();
}
public virtual int NotorietyHandler(Mobile source, Mobile target, out bool handled)
{
handled = false;
if (IsInternal || Hidden)
{
return BattleNotoriety.Bubble;
}
if (source == null || source.Deleted || target == null || target.Deleted)
{
return BattleNotoriety.Bubble;
}
handled = true;
if (NotoUtility.Resolve(source, target, out PlayerMobile x, out PlayerMobile y))
{
var noto = NotorietyHandler(x, y, out handled);
if (handled || noto != BattleNotoriety.Bubble)
{
return noto;
}
}
var xrs = source.InRegion(SpectateRegion);
var xrb = source.InRegion(BattleRegion);
var yrs = target.InRegion(SpectateRegion);
var yrb = target.InRegion(BattleRegion);
if (xrs || xrb || yrs || yrb)
{
return Notoriety.Invulnerable;
}
handled = false;
return BattleNotoriety.Bubble;
}
protected virtual int NotorietyHandler(PlayerMobile source, PlayerMobile target, out bool handled)
{
handled = false;
if (IsInternal || Hidden)
{
return BattleNotoriety.Bubble;
}
if (source == null || source.Deleted || target == null || target.Deleted)
{
return BattleNotoriety.Bubble;
}
if (IsParticipant(source, out var teamA) && IsParticipant(target, out var teamB))
{
handled = true;
if (!IsRunning)
{
return Notoriety.Invulnerable;
}
if (teamA == teamB)
{
if (CanDamageOwnTeam(source, target))
{
return Notoriety.Enemy;
}
return Notoriety.Ally;
}
if (CanDamageEnemyTeam(source, target))
{
return Notoriety.Enemy;
}
return Notoriety.Invulnerable;
}
return BattleNotoriety.Bubble;
}
public virtual bool AcceptsSpawnsFrom(Region region)
{
return AllowSpawn() && region != null && (region.IsPartOf(BattleRegion) || region.IsPartOf(SpectateRegion));
}
public virtual void AlterLightLevel(Mobile m, ref int global, ref int personal)
{
personal = personal != LightLevel ? LightLevel : personal;
}
public virtual void OnLocationChanged(Mobile m, Point3D oldLocation)
{
if (m == null || m.Deleted)
{
return;
}
if (m.Region != null && (m.Region.IsPartOf(SpectateRegion) || m.Region.IsPartOf(BattleRegion)))
{
CheckDismount(m);
InvalidateStray(m);
}
var pm = m as PlayerMobile;
if (pm == null)
{
return;
}
if (IsParticipant(pm, out var team) && team != null && !team.Deleted)
{
team.UpdateActivity(pm);
}
}
public virtual bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
{
return true;
}
public virtual void OnEnter(PvPRegion region, Mobile m)
{
if (region == null || m == null || m.Deleted)
{
return;
}
if (region.IsPartOf(BattleRegion) && m.InRegion(BattleRegion))
{
var pm = m as PlayerMobile;
if (pm != null)
{
pm.SendMessage("You have entered {0}", Name);
}
AutoPvP.InvokeEnterBattle(this, region, m);
}
else if (region.IsPartOf(SpectateRegion) && m.InRegion(SpectateRegion))
{
var pm = m as PlayerMobile;
if (pm != null)
{
pm.SendMessage("You have entered {0} spectator area.", Name);
if (!IsSpectator(pm))
{
AddSpectator(pm, false);
}
}
AutoPvP.InvokeEnterBattle(this, region, m);
}
m.Delta(MobileDelta.Noto);
}
public virtual void OnExit(PvPRegion region, Mobile m)
{
if (region == null || m == null || m.Deleted)
{
return;
}
if (region.IsPartOf(BattleRegion) && !m.InRegion(BattleRegion))
{
var pm = m as PlayerMobile;
if (pm != null)
{
if (IsParticipant(pm))
{
Quit(pm, false);
}
pm.SendMessage("You have left {0}", Name);
}
AutoPvP.InvokeExitBattle(this, region, m);
}
else if (region.IsPartOf(SpectateRegion) && !m.InRegion(SpectateRegion))
{
var pm = m as PlayerMobile;
if (pm != null)
{
pm.SendMessage("You have left {0} spectator area", Name);
if (IsSpectator(pm))
{
RemoveSpectator(pm, false);
}
}
AutoPvP.InvokeExitBattle(this, region, m);
}
m.Delta(MobileDelta.Noto);
}
public bool AllowBeneficial(Mobile m, Mobile target, out bool handled)
{
if (CheckAllowBeneficial(m, target, out handled))
{
if (handled)
{
OnAllowBeneficialAccept(m, target);
}
return true;
}
if (handled)
{
OnAllowBeneficialDeny(m, target);
}
return false;
}
public virtual bool CheckAllowBeneficial(Mobile m, Mobile target, out bool handled)
{
handled = false;
if (m == null || m.Deleted || target == null || target.Deleted)
{
return false;
}
if (Deleted || State == PvPBattleState.Internal || Hidden)
{
return false;
}
handled = true;
if (NotoUtility.Resolve(m, target, out PlayerMobile x, out PlayerMobile y))
{
if (IsParticipant(x, out var teamA) && IsParticipant(y, out var teamB))
{
if (State != PvPBattleState.Running)
{
return true;
}
if (!Options.Rules.AllowBeneficial)
{
return false;
}
if (teamA == teamB)
{
if (!CanHealOwnTeam(x, y))
{
return false;
}
}
else if (!CanHealEnemyTeam(x, y))
{
return false;
}
}
}
var xrs = m.InRegion(SpectateRegion);
var xrb = m.InRegion(BattleRegion);
var yrs = target.InRegion(SpectateRegion);
var yrb = target.InRegion(BattleRegion);
if (xrs || xrb || yrs || yrb)
{
if (xrs && yrs)
{
return true;
}
if (xrb && yrb)
{
return true;
}
return false;
}
handled = false;
return false;
}
protected virtual void OnAllowBeneficialAccept(Mobile m, Mobile target)
{ }
protected virtual void OnAllowBeneficialDeny(Mobile m, Mobile target)
{
if (m != null && !m.Deleted && target != null && !target.Deleted && m != target)
{
m.SendMessage("You can not perform beneficial actions on your target.");
}
}
public bool AllowHarmful(Mobile m, Mobile target, out bool handled)
{
if (CheckAllowHarmful(m, target, out handled))
{
if (handled)
{
OnAllowHarmfulAccept(m, target);
}
return true;
}
if (handled)
{
OnAllowHarmfulDeny(m, target);
}
return false;
}
public virtual bool CheckAllowHarmful(Mobile m, Mobile target, out bool handled)
{
handled = false;
if (m == null || m.Deleted || target == null || target.Deleted)
{
return false;
}
if (Deleted || State == PvPBattleState.Internal || Hidden)
{
return false;
}
handled = true;
if (NotoUtility.Resolve(m, target, out PlayerMobile x, out PlayerMobile y))
{
if (IsParticipant(x, out var teamA) && IsParticipant(y, out var teamB))
{
if (!Options.Rules.AllowHarmful)
{
return false;
}
if (State != PvPBattleState.Running)
{
return false;
}
if (teamA == teamB)
{
if (!CanDamageOwnTeam(x, y))
{
return false;
}
}
else if (!CanDamageEnemyTeam(x, y))
{
return false;
}
}
}
var xrs = m.InRegion(SpectateRegion);
var xrb = m.InRegion(BattleRegion);
var yrs = target.InRegion(SpectateRegion);
var yrb = target.InRegion(BattleRegion);
if (xrs || xrb || yrs || yrb)
{
if (xrs && yrs)
{
return true;
}
if (xrb && yrb)
{
return true;
}
return false;
}
handled = false;
return false;
}
protected virtual void OnAllowHarmfulAccept(Mobile m, Mobile target)
{ }
protected virtual void OnAllowHarmfulDeny(Mobile m, Mobile target)
{
if (m != null && !m.Deleted && target != null && !target.Deleted && m != target)
{
m.SendMessage("You can not perform harmful actions on your target.");
}
}
}
}

View File

@@ -0,0 +1,267 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using Server.Items;
using VitaNex.Crypto;
using VitaNex.Schedules;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public sealed class PvPSerial : CryptoHashCode
{
public static CryptoHashType Algorithm = CryptoHashType.MD5;
[CommandProperty(AutoPvP.Access)]
public override string Value => base.Value.Replace("-", String.Empty);
public PvPSerial()
: this(TimeStamp.UtcNow + "+" + Utility.RandomDouble())
{ }
public PvPSerial(string seed)
: base(Algorithm, seed)
{ }
public PvPSerial(GenericReader reader)
: base(reader)
{ }
}
public abstract partial class PvPBattle
{
[CommandProperty(AutoPvP.Access, true)]
public PvPSerial Serial { get; private set; }
protected bool Deserialized { get; private set; }
protected bool Deserializing { get; private set; }
private PvPBattle(bool deserializing)
{
Deserialized = deserializing;
EnsureConstructDefaults();
}
public PvPBattle(GenericReader reader)
: this(true)
{
Deserializing = true;
Deserialize(reader);
Deserializing = false;
}
public virtual void SerializeRegion(GenericWriter w, PvPRegion r)
{
if (r != null)
{
r.Serialize(w);
}
}
public virtual void Serialize(GenericWriter writer)
{
var version = writer.SetVersion(10);
if (version > 5)
{
writer.WriteBlock(
w =>
{
if (version > 6)
{
Serial.Serialize(w);
}
else
{
w.WriteType(Serial, t => Serial.Serialize(w));
}
});
}
switch (version)
{
case 10:
writer.Write(Shortcut);
goto case 9;
case 9:
writer.Write(RewardTeam);
goto case 8;
case 8:
writer.Write(RequireCapacity);
goto case 7;
case 7:
case 6:
case 5:
writer.Write(Hidden);
goto case 4;
case 4:
writer.Write(_FloorItemDelete);
goto case 3;
case 3:
case 2:
writer.Write(Gate);
goto case 1;
case 1:
{
writer.Write(Category);
writer.Write(Ranked);
writer.Write(InviteWhileRunning);
}
goto case 0;
case 0:
{
if (version < 6)
{
writer.WriteBlock(w => w.WriteType(Serial, t => Serial.Serialize(w)));
}
writer.Write(DebugMode);
writer.WriteFlag(_State);
writer.Write(_Name);
writer.Write(Description);
writer.Write(AutoAssign);
writer.Write(UseTeamColors);
writer.Write(false); // IgnoreCapacity
writer.Write(_SubCommandPrefix);
writer.Write(QueueAllowed);
writer.Write(SpectateAllowed);
writer.Write(KillPoints);
writer.Write(PointsBase);
writer.Write(0.0); // PointsRankFactor
writer.Write(IdleKick);
writer.Write(IdleThreshold);
writer.WriteFlag(LastState);
writer.Write(LastStateChange);
writer.Write(_LightLevel);
writer.Write(LogoutDelay);
writer.WriteItemList(Doors, true);
writer.WriteBlock(w => w.WriteType(Options, t => Options.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Schedule, t => Schedule.Serialize(w)));
writer.WriteBlock(w => w.WriteType(BattleRegion, t => SerializeRegion(w, BattleRegion)));
writer.WriteBlock(w => w.WriteType(SpectateRegion, t => SerializeRegion(w, SpectateRegion)));
writer.WriteBlockList(Teams, (w, team) => w.WriteType(team, t => team.Serialize(w)));
}
break;
}
}
public virtual void Deserialize(GenericReader reader)
{
var v = reader.GetVersion();
if (v > 5)
{
Serial = reader.ReadBlock(r => v > 6 ? new PvPSerial(r) : r.ReadTypeCreate<PvPSerial>(r)) ?? new PvPSerial();
}
switch (v)
{
case 10:
Shortcut = reader.ReadString();
goto case 9;
case 9:
RewardTeam = reader.ReadBool();
goto case 8;
case 8:
RequireCapacity = reader.ReadBool();
goto case 7;
case 7:
case 6:
case 5:
Hidden = reader.ReadBool();
goto case 4;
case 4:
_FloorItemDelete = reader.ReadBool();
goto case 3;
case 3:
case 2:
{
Gate = reader.ReadItem<PvPSpectatorGate>();
if (Gate != null)
{
Gate.Battle = this;
}
}
goto case 1;
case 1:
{
Category = reader.ReadString();
Ranked = reader.ReadBool();
InviteWhileRunning = reader.ReadBool();
}
goto case 0;
case 0:
{
if (v < 6)
{
Serial = reader.ReadBlock(r => r.ReadTypeCreate<PvPSerial>(r)) ?? new PvPSerial();
}
DebugMode = reader.ReadBool();
_State = reader.ReadFlag<PvPBattleState>();
_Name = reader.ReadString();
Description = reader.ReadString();
AutoAssign = reader.ReadBool();
UseTeamColors = reader.ReadBool();
reader.ReadBool(); // IgnoreCapacity
_SubCommandPrefix = reader.ReadChar();
QueueAllowed = reader.ReadBool();
SpectateAllowed = reader.ReadBool();
KillPoints = v < 3 ? (reader.ReadBool() ? 1 : 0) : reader.ReadInt();
PointsBase = reader.ReadInt();
reader.ReadDouble(); //PointsRankFactor
IdleKick = reader.ReadBool();
IdleThreshold = reader.ReadTimeSpan();
LastState = reader.ReadFlag<PvPBattleState>();
LastStateChange = reader.ReadDateTime();
_LightLevel = reader.ReadInt();
LogoutDelay = reader.ReadTimeSpan();
Doors.AddRange(reader.ReadStrongItemList<BaseDoor>());
Options = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleOptions>(r)) ?? new PvPBattleOptions();
if (Schedule != null && Schedule.Running)
{
Schedule.Stop();
}
Schedule = reader.ReadBlock(r => r.ReadTypeCreate<Schedule>(r)) ?? new Schedule(Name, false);
if (Schedule.Name != Name && Name != null)
{
Schedule.Name = Name;
}
BattleRegion = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleRegion>(this, r));
SpectateRegion = reader.ReadBlock(r => r.ReadTypeCreate<PvPSpectateRegion>(this, r));
Teams = reader.ReadBlockList(r => r.ReadTypeCreate<PvPTeam>(this, r), Teams);
}
break;
}
}
}
}

View File

@@ -0,0 +1,94 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
public void SendGlobalSound(int soundID)
{
if (!Options.Sounds.Enabled || soundID <= 0)
{
return;
}
foreach (var m in GetLocalBroadcastList())
{
SendSound(m, soundID);
}
}
public void SendSound(int soundID)
{
if (Options.Sounds.Enabled && soundID > 0)
{
ForEachTeam(t => SendSound(t, soundID));
}
}
public void SendSound(PvPTeam t, int soundID)
{
if (Options.Sounds.Enabled && t != null && !t.Deleted && soundID > 0)
{
t.SendSound(soundID);
}
}
public virtual void SendSound(Mobile m, int soundID)
{
if (Options.Sounds.Enabled && m != null && !m.Deleted && soundID > 0)
{
m.SendSound(soundID);
}
}
public void PlayGlobalSound(int soundID)
{
if (!Options.Sounds.Enabled || soundID <= 0)
{
return;
}
foreach (var m in GetLocalBroadcastList())
{
PlaySound(m, soundID);
}
}
public void PlaySound(int soundID)
{
if (Options.Sounds.Enabled && soundID > 0)
{
ForEachTeam(t => PlaySound(t, soundID));
}
}
public void PlaySound(PvPTeam t, int soundID)
{
if (Options.Sounds.Enabled && t != null && !t.Deleted && soundID > 0)
{
t.PlaySound(soundID);
}
}
public virtual void PlaySound(Mobile m, int soundID)
{
if (Options.Sounds.Enabled && m != null && !m.Deleted && soundID > 0)
{
m.PlaySound(soundID);
}
}
}
}

View File

@@ -0,0 +1,118 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
using Server.Mobiles;
using Server.Regions;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
public List<PlayerMobile> Spectators { get; private set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool SpectateAllowed { get; set; }
public IEnumerable<PlayerMobile> GetSpectators()
{
return Spectators;
}
public void AddSpectator(PlayerMobile pm, bool teleport)
{
if (pm == null || pm.Deleted)
{
return;
}
if (!CanSpectate(pm))
{
OnSpectateReject(pm);
return;
}
Spectators.Add(pm);
if (teleport)
{
RecordBounce(pm);
Teleport(pm, Options.Locations.SpectateJoin, Options.Locations.Map);
}
OnSpectatorAdded(pm);
}
public void RemoveSpectator(PlayerMobile pm, bool teleport)
{
if (!IsSpectator(pm))
{
return;
}
Spectators.Remove(pm);
if (teleport)
{
var bounce = BounceInfo.GetValue(pm);
if (bounce != null && !bounce.InternalOrZero)
{
Teleport(pm, bounce, bounce);
BounceInfo.Remove(pm);
}
else
{
Teleport(pm, Options.Locations.Eject, Options.Locations.Eject);
}
}
OnSpectatorRemoved(pm);
}
public virtual bool CanSpectate(PlayerMobile pm)
{
return SpectateAllowed && State != PvPBattleState.Internal && pm != null && !pm.Deleted && pm.Alive &&
(pm.Region == null || !pm.Region.IsPartOf<Jail>()) && IsOnline(pm) && !InCombat(pm) && !InOtherBattle(pm);
}
public bool IsSpectator(PlayerMobile pm)
{
return Spectators.Contains(pm);
}
protected virtual void OnSpectatorAdded(PlayerMobile pm)
{
if (pm != null && !pm.Deleted)
{
pm.SendMessage("You have been granted a front-row seat.");
}
}
protected virtual void OnSpectatorRemoved(PlayerMobile pm)
{ }
protected virtual void OnSpectateReject(PlayerMobile pm)
{
if (pm != null && !pm.Deleted && IsSpectator(pm))
{
pm.SendMessage("You can not spectate {0} at this time.", Name);
}
}
}
}

View File

@@ -0,0 +1,486 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Linq;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public enum PvPBattleState
{
Internal,
Queueing,
Preparing,
Running,
Ended
}
public abstract partial class PvPBattle
{
private bool _StateTransition;
private PvPBattleState _State = PvPBattleState.Internal;
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleState State
{
get => _State;
set
{
if (_State == value)
{
return;
}
var oldState = _State;
_State = value;
if (!Deserializing)
{
OnStateChanged(oldState);
}
}
}
[CommandProperty(AutoPvP.Access, true)]
public virtual PvPBattleState LastState { get; private set; }
[CommandProperty(AutoPvP.Access, true)]
public virtual DateTime LastStateChange { get; private set; }
[CommandProperty(AutoPvP.Access)]
public bool IsInternal => State == PvPBattleState.Internal;
[CommandProperty(AutoPvP.Access)]
public bool IsQueueing => State == PvPBattleState.Queueing;
[CommandProperty(AutoPvP.Access)]
public bool IsPreparing => State == PvPBattleState.Preparing;
[CommandProperty(AutoPvP.Access)]
public bool IsRunning => State == PvPBattleState.Running;
[CommandProperty(AutoPvP.Access)]
public bool IsEnded => State == PvPBattleState.Ended;
public void InvalidateState()
{
if (_StateTransition || Deleted || Hidden || IsInternal)
{
return;
}
var state = State;
var reset = false;
switch (state)
{
case PvPBattleState.Queueing:
{
if (CanPrepareBattle(ref reset))
{
state = PvPBattleState.Preparing;
}
}
break;
case PvPBattleState.Preparing:
{
if (CanStartBattle(ref reset))
{
state = PvPBattleState.Running;
}
else if (!reset && GetStateTimeLeft(state) <= TimeSpan.Zero)
{
state = PvPBattleState.Ended;
}
}
break;
case PvPBattleState.Running:
{
if (CanEndBattle(ref reset))
{
state = PvPBattleState.Ended;
}
}
break;
case PvPBattleState.Ended:
{
if (CanOpenBattle(ref reset))
{
state = PvPBattleState.Queueing;
}
}
break;
}
if (reset)
{
Options.Timing.SetTime(State, DateTime.UtcNow);
}
State = state;
}
protected virtual void OnStateChanged(PvPBattleState oldState)
{
_StateTransition = true;
LastState = oldState;
if (IsInternal)
{
Options.Timing.SetAllTimes(DateTime.MinValue);
OnBattleInternalized();
}
else
{
if (LastState == PvPBattleState.Internal)
{
InvalidateRegions();
}
Options.Timing.SetTime(State, DateTime.UtcNow);
switch (State)
{
case PvPBattleState.Queueing:
OnBattleOpened();
break;
case PvPBattleState.Preparing:
OnBattlePreparing();
break;
case PvPBattleState.Running:
OnBattleStarted();
break;
case PvPBattleState.Ended:
OnBattleEnded();
break;
}
}
LastStateChange = DateTime.UtcNow;
_StateTransition = false;
AutoPvP.InvokeBattleStateChanged(this);
PvPBattlesUI.RefreshAll(this);
}
protected bool CanOpenBattle(ref bool timeReset)
{
if (!IsEnded)
{
return false;
}
if (GetStateTimeLeft(PvPBattleState.Ended) > TimeSpan.Zero)
{
return false;
}
return true;
}
protected bool CanPrepareBattle(ref bool timeReset)
{
if (!IsQueueing)
{
return false;
}
if (GetStateTimeLeft(PvPBattleState.Queueing) > TimeSpan.Zero)
{
return false;
}
if (!RequireCapacity || Queue.Count >= MinCapacity)
{
return true;
}
if (Schedule == null || !Schedule.Enabled || Schedule.NextGlobalTick == null)
{
timeReset = true;
}
return false;
}
protected bool CanStartBattle(ref bool timeReset)
{
if (!IsPreparing)
{
return false;
}
if (GetStateTimeLeft(PvPBattleState.Preparing) > TimeSpan.Zero)
{
return false;
}
if (Teams.All(t => t.IsReady()))
{
return true;
}
if (Schedule == null || !Schedule.Enabled || Schedule.NextGlobalTick == null)
{
timeReset = true;
}
return false;
}
protected bool CanEndBattle(ref bool timeReset)
{
if (!IsRunning)
{
return false;
}
if (GetStateTimeLeft(PvPBattleState.Running) <= TimeSpan.Zero)
{
return true;
}
if (!InviteWhileRunning && !HasCapacity())
{
return true;
}
if (Teams.All(t => !t.RespawnOnDeath && !t.IsAlive))
{
return true;
}
if (CheckMissions())
{
return true;
}
return false;
}
protected virtual void OnBattleInternalized()
{
if (LastState == PvPBattleState.Running)
{
OnBattleCancelled();
}
Reset();
foreach (var p in AutoPvP.Profiles.Values.Where(p => p != null && !p.Deleted && p.IsSubscribed(this)))
{
p.Unsubscribe(this);
}
PvPBattlesUI.RefreshAll(this);
}
protected virtual void OnBattleOpened()
{
Hidden = false;
if (Options.Broadcasts.World.OpenNotify)
{
WorldBroadcast("{0} is queueing volunteers!", Name);
}
if (Options.Broadcasts.Local.OpenNotify)
{
LocalBroadcast("{0} is queueing volunteers!", Name);
}
SendGlobalSound(Options.Sounds.BattleOpened);
Reset();
ForEachTeam(t => t.OnBattleOpened());
if (LastState == PvPBattleState.Internal)
{
foreach (var p in AutoPvP.Profiles.Values.Where(p => p != null && !p.Deleted && !p.IsSubscribed(this)))
{
p.Subscribe(this);
}
}
PvPBattlesUI.RefreshAll(this);
}
protected virtual void OnBattlePreparing()
{
Hidden = false;
if (Options.Broadcasts.World.StartNotify)
{
WorldBroadcast("{0} is preparing!", Name);
}
if (Options.Broadcasts.Local.StartNotify)
{
LocalBroadcast("{0} is preparing!", Name);
}
SendGlobalSound(Options.Sounds.BattlePreparing);
ForEachTeam(t => t.OnBattlePreparing());
PvPBattlesUI.RefreshAll(this);
}
protected virtual void OnBattleStarted()
{
Hidden = false;
if (Options.Broadcasts.World.StartNotify)
{
WorldBroadcast("{0} has begun!", Name);
}
if (Options.Broadcasts.Local.StartNotify)
{
LocalBroadcast("{0} has begun!", Name);
}
SendGlobalSound(Options.Sounds.BattleStarted);
OpendDoors(true);
ForEachTeam(t => t.OnBattleStarted());
PvPBattlesUI.RefreshAll(this);
}
protected virtual void OnBattleEnded()
{
if (LastState == PvPBattleState.Preparing)
{
OnBattleCancelled();
}
Hidden = false;
if (Options.Broadcasts.World.EndNotify)
{
WorldBroadcast("{0} has ended!", Name);
}
if (Options.Broadcasts.Local.EndNotify)
{
LocalBroadcast("{0} has ended!", Name);
}
SendGlobalSound(Options.Sounds.BattleEnded);
CloseDoors(true);
ProcessRanks();
ForEachTeam(t => t.OnBattleEnded());
TransferStatistics();
PvPBattlesUI.RefreshAll(this);
}
protected virtual void OnBattleCancelled()
{
Hidden = false;
if (Options.Broadcasts.World.EndNotify)
{
WorldBroadcast("{0} has been cancelled!", Name);
}
if (Options.Broadcasts.Local.EndNotify)
{
LocalBroadcast("{0} has been cancelled!", Name);
}
SendGlobalSound(Options.Sounds.BattleCanceled);
CloseDoors(true);
if (!Deleted && !IsInternal && QueueAllowed)
{
ForEachTeam(t => t.ForEachMember(o => Queue[o] = t));
}
ForEachTeam(t => t.OnBattleCancelled());
}
public TimeSpan GetStateTimeLeft()
{
return GetStateTimeLeft(DateTime.UtcNow);
}
public TimeSpan GetStateTimeLeft(DateTime when)
{
return GetStateTimeLeft(when, State);
}
public TimeSpan GetStateTimeLeft(PvPBattleState state)
{
return GetStateTimeLeft(DateTime.UtcNow, state);
}
public virtual TimeSpan GetStateTimeLeft(DateTime when, PvPBattleState state)
{
var time = 0.0;
switch (state)
{
case PvPBattleState.Queueing:
{
time = (Options.Timing.OpenedWhen.Add(Options.Timing.QueuePeriod) - when).TotalSeconds;
if (Schedule != null && Schedule.Enabled)
{
if (Schedule.CurrentGlobalTick != null)
{
time = (Schedule.CurrentGlobalTick.Value - when).TotalSeconds;
}
else if (Schedule.NextGlobalTick != null)
{
time = (Schedule.NextGlobalTick.Value - when).TotalSeconds;
}
}
}
break;
case PvPBattleState.Preparing:
time = (Options.Timing.PreparedWhen.Add(Options.Timing.PreparePeriod) - when).TotalSeconds;
break;
case PvPBattleState.Running:
time = (Options.Timing.StartedWhen.Add(Options.Timing.RunningPeriod) - when).TotalSeconds;
break;
case PvPBattleState.Ended:
time = (Options.Timing.EndedWhen.Add(Options.Timing.EndedPeriod) - when).TotalSeconds;
break;
}
if (time > 0)
{
return TimeSpan.FromSeconds(time);
}
return TimeSpan.Zero;
}
}
}

View File

@@ -0,0 +1,149 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Linq;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
[CommandProperty(AutoPvP.Access)]
public virtual bool Ranked { get; set; }
public long GetStatistic(PlayerMobile pm, Func<PvPProfileHistoryEntry, long> fetch)
{
if (pm == null || fetch == null)
{
return 0;
}
return Teams.Aggregate(0L, (v, t) => v + GetStatistic(t, pm, fetch));
}
public long GetStatistic(PvPTeam t, PlayerMobile pm, Func<PvPProfileHistoryEntry, long> fetch)
{
if (t == null || t.Deleted || pm == null || fetch == null)
{
return 0;
}
var s = t.GetStatistics(pm);
if (s != null)
{
return VitaNexCore.TryCatchGet(fetch, s, AutoPvP.CMOptions.ToConsole);
}
return 0;
}
public bool UpdateStatistics(PvPTeam t, PlayerMobile pm, Action<PvPProfileHistoryEntry> update)
{
if (t == null || t.Deleted || pm == null || update == null)
{
return false;
}
var s = t.GetStatistics(pm);
if (s == null)
{
return false;
}
var success = true;
VitaNexCore.TryCatch(
update,
s,
x =>
{
AutoPvP.CMOptions.ToConsole(x);
success = false;
});
if (t.IsMember(pm))
{
t.UpdateActivity(pm);
}
return success;
}
public void ResetStatistics()
{
ForEachTeam(ResetStatistics);
}
public void ResetStatistics(PvPTeam t)
{
if (t != null)
{
t.Statistics.Clear();
}
}
private void TransferStatistics()
{
ForEachTeam(TransferStatistics);
}
private void TransferStatistics(PvPTeam t)
{
if (t != null)
{
t.Statistics.ForEachReverse(o => TransferStatistics(o.Key, o.Value));
}
}
private void TransferStatistics(PlayerMobile pm, PvPProfileHistoryEntry e)
{
var profile = AutoPvP.EnsureProfile(pm);
OnTransferStatistics(profile, e);
OnTransferPoints(profile, e.Points);
}
protected virtual void OnTransferStatistics(PvPProfile profile, PvPProfileHistoryEntry stats)
{
if (Ranked && profile != null && stats != null)
{
stats.AddTo(profile.Statistics, true);
}
}
protected virtual void OnTransferPoints(PvPProfile profile, long points)
{
if (!Ranked || profile == null || points == 0)
{
return;
}
profile.RawPoints += points;
if (IsOnline(profile.Owner))
{
profile.Owner.SendMessage(
"You have {0} {1:#,0} Battle Point{2} from {3}!",
points > 0 ? "gained" : "lost",
points,
points != 1 ? "s" : String.Empty,
Name);
}
}
}
}

View File

@@ -0,0 +1,503 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Server;
using Server.Gumps;
using Server.Mobiles;
using VitaNex.SuperGumps.UI;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleCommandState
{
public virtual PvPBattle Battle { get; protected set; }
public virtual PlayerMobile Mobile { get; protected set; }
public virtual string Command { get; protected set; }
public virtual string Speech { get; protected set; }
public virtual string[] Args { get; protected set; }
public PvPBattleCommandState(PvPBattle battle, PlayerMobile from, string command, string[] args)
{
Battle = battle;
Mobile = from;
Command = command;
Args = args;
Speech = String.Join(" ", args);
}
}
public class PvPBattleCommandInfo
{
public virtual string Command { get; protected set; }
public virtual string Usage { get; set; }
public virtual string Description { get; set; }
public virtual AccessLevel Access { get; set; }
public virtual Func<PvPBattleCommandState, bool> Handler { get; set; }
public PvPBattleCommandInfo(
string command,
string desc,
string usage,
AccessLevel access,
Func<PvPBattleCommandState, bool> handler)
{
Command = command;
Description = desc;
Usage = usage;
Access = access;
Handler = handler;
}
}
public abstract partial class PvPBattle
{
private char _SubCommandPrefix = '@';
[CommandProperty(AutoPvP.Access)]
public virtual char SubCommandPrefix
{
get
{
if (!Char.IsSymbol(_SubCommandPrefix))
{
_SubCommandPrefix = '@';
}
return _SubCommandPrefix;
}
set
{
if (!Char.IsSymbol(value))
{
value = '@';
}
_SubCommandPrefix = value;
}
}
public Dictionary<string, PvPBattleCommandInfo> SubCommandHandlers { get; private set; }
protected virtual void RegisterSubCommands()
{
RegisterSubCommand(
"help",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
foreach (var ci in SubCommandHandlers.Keys.Select(cmd => SubCommandHandlers[cmd])
.Where(ci => state.Mobile.AccessLevel >= ci.Access))
{
state.Mobile.SendMessage("{0}{1} {2}", SubCommandPrefix, ci.Command, ci.Usage);
}
return true;
},
"Displays a list of available commands for this battle.",
"[?]",
AccessLevel.Player);
RegisterSubCommandAlias("help", "commands");
RegisterSubCommand(
"battle",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
LocalBroadcast("[{0}]: {1}", state.Mobile.RawName, state.Speech);
return true;
},
"Broadcasts a message to all battle participants and spectators.",
"<message>",
AccessLevel.Player);
RegisterSubCommandAlias("battle", "b");
RegisterSubCommand(
"team",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
if (!IsParticipant(state.Mobile, out var team))
{
state.Mobile.SendMessage("You must be a participant to use that command.");
return true;
}
if (team == null || team.Deleted)
{
state.Mobile.SendMessage("You are not a member of a team.");
return true;
}
team.Broadcast("[{0}]: {1}", state.Mobile.RawName, state.Speech);
return true;
},
"Sends a message to your team.",
"<message>",
AccessLevel.Player);
RegisterSubCommandAlias("team", "t");
RegisterSubCommand(
"join",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
if (IsParticipant(state.Mobile))
{
state.Mobile.SendMessage("You are already participating in this battle.");
return true;
}
if (IsQueued(state.Mobile))
{
state.Mobile.SendMessage("You are already queued for this battle.");
return true;
}
Enqueue(state.Mobile);
return true;
},
"Joins the queue for the battle.",
"",
AccessLevel.Player);
RegisterSubCommandAlias("join", "j");
RegisterSubCommand(
"leave",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
Quit(state.Mobile, true);
return true;
},
"Removes you from the battle.",
"",
AccessLevel.Player);
RegisterSubCommandAlias("leave", "quit");
RegisterSubCommand(
"time",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
var timeLeft = GetStateTimeLeft(DateTime.UtcNow);
if (timeLeft > TimeSpan.Zero)
{
var time = timeLeft.ToSimpleString(@"h\:m\:s");
var nextState = "";
switch (State)
{
case PvPBattleState.Queueing:
nextState = "Preparation";
break;
case PvPBattleState.Preparing:
nextState = "Start";
break;
case PvPBattleState.Running:
nextState = "End";
break;
case PvPBattleState.Ended:
nextState = "Open";
break;
}
state.Mobile.SendMessage("Battle is currently {0}. Time left until {1}: {2}", State.ToString(), nextState, time);
}
else
{
state.Mobile.SendMessage("Time unavailable.");
}
return true;
},
"Displays the amount of time left until the next battle state.",
"",
AccessLevel.Player);
RegisterSubCommand(
"menu",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
new PvPBattleUI(state.Mobile, battle: this).Send();
return true;
},
"Opens the interface for this battle.",
"",
AccessLevel.Player);
RegisterSubCommand(
"config",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
state.Mobile.SendGump(new PropertiesGump(state.Mobile, this));
return true;
},
"Opens the configuration for this battle.");
RegisterSubCommand(
"scores",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
var stats = new StringBuilder();
ForEachTeam(
t =>
{
stats.AppendLine("Team: {0}", t.Name);
stats.AppendLine();
t.GetHtmlStatistics(state.Mobile, stats);
stats.AppendLine();
});
new NoticeDialogGump(state.Mobile)
{
Width = 600,
Height = 400,
Title = "Battle Statistics",
Html = stats.ToString()
}.Send();
return true;
},
"Display the statistics for all teams.");
RegisterSubCommand(
"hidden",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
Hidden = !Hidden;
return true;
},
"Toggle the battle visiblility.");
RegisterSubCommand(
"state",
state =>
{
if (state == null || state.Mobile == null || state.Mobile.Deleted)
{
return false;
}
var oldState = State;
if (!Validate())
{
State = PvPBattleState.Internal;
state.Mobile.SendMessage("This battle has failed validation and has been internalized.");
}
else
{
Hidden = false;
switch (State)
{
case PvPBattleState.Internal:
State = PvPBattleState.Queueing;
break;
case PvPBattleState.Queueing:
State = PvPBattleState.Preparing;
break;
case PvPBattleState.Preparing:
State = PvPBattleState.Running;
break;
case PvPBattleState.Running:
State = PvPBattleState.Ended;
break;
case PvPBattleState.Ended:
State = PvPBattleState.Queueing;
break;
}
}
if (State != oldState)
{
state.Mobile.SendMessage("The state of the battle has been changed to {0}", State.ToString());
return true;
}
return false;
},
"Toggles the state of the current battle.");
}
public void RegisterSubCommand(
string command,
Func<PvPBattleCommandState, bool> handler,
string desc = "",
string usage = "",
AccessLevel access = AutoPvP.Access)
{
if (!String.IsNullOrWhiteSpace(command) && handler != null)
{
RegisterSubCommand(new PvPBattleCommandInfo(command, desc, usage, access, handler));
}
}
public void RegisterSubCommand(PvPBattleCommandInfo info)
{
if (info != null)
{
SubCommandHandlers[info.Command] = info;
}
}
public void RegisterSubCommandAlias(string command, params string[] alias)
{
if (!IsCommand(command))
{
return;
}
var info = SubCommandHandlers[command];
foreach (var cmd in alias)
{
RegisterSubCommand(cmd, info.Handler, info.Description, info.Usage, info.Access);
}
}
public bool HandleSubCommand(PlayerMobile pm, string speech)
{
if (pm == null || pm.Deleted || String.IsNullOrWhiteSpace(speech))
{
return false;
}
speech = speech.Trim();
if (!speech.StartsWith(SubCommandPrefix.ToString(CultureInfo.InvariantCulture)))
{
return false;
}
var command = String.Empty;
var args = new string[0];
speech = speech.TrimStart(SubCommandPrefix);
var split = speech.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (split.Length > 0)
{
command = split[0];
args = new string[split.Length - 1];
for (var i = 0; i < args.Length; i++)
{
args[i] = split[i + 1];
}
}
if (!IsCommand(command))
{
pm.SendMessage("Command not found.");
return true;
}
var info = SubCommandHandlers[command];
if (pm.AccessLevel < info.Access)
{
pm.SendMessage("You do not have access to that command.");
return true;
}
if (args.Length > 0 && (args[0] == "?" || Insensitive.Equals(args[0], "help")))
{
pm.SendMessage("Usage: {0}{1} {2}", SubCommandPrefix, info.Command, info.Usage);
pm.SendMessage(info.Description);
return true;
}
var state = new PvPBattleCommandState(this, pm, command, args);
if (info.Handler.Invoke(state))
{
OnCommand(state);
return true;
}
pm.SendMessage("Usage: {0}{1} {2}", SubCommandPrefix, info.Command, info.Usage);
pm.SendMessage(info.Description);
return true;
}
public bool IsCommand(string command)
{
return !String.IsNullOrWhiteSpace(command) && SubCommandHandlers.ContainsKey(command);
}
protected virtual void OnCommand(PvPBattleCommandState state)
{ }
}
}

View File

@@ -0,0 +1,629 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Mobiles;
using Server.Spells.Fifth;
using VitaNex.Collections;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
public List<PvPTeam> Teams { get; private set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool AutoAssign { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool UseTeamColors { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool UseIncognito { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool RequireCapacity { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual bool RewardTeam { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int MinCapacity => GetMinCapacity();
[CommandProperty(AutoPvP.Access)]
public virtual int MaxCapacity => GetMaxCapacity();
[CommandProperty(AutoPvP.Access)]
public virtual int CurrentCapacity => GetCurrentCapacity();
[CommandProperty(AutoPvP.Access)]
public virtual bool IsFull => (CurrentCapacity >= MaxCapacity);
public int GetMinCapacity()
{
return Teams.Aggregate(0, (v, t) => v + t.MinCapacity);
}
public int GetMaxCapacity()
{
return Teams.Aggregate(0, (v, t) => v + t.MaxCapacity);
}
public int GetCurrentCapacity()
{
return Teams.Aggregate(0, (v, t) => v + t.Count);
}
public bool HasCapacity()
{
return HasCapacity(0);
}
public bool HasCapacity(int min)
{
if (min <= 0)
{
return CurrentCapacity > 1;
}
if (!RequireCapacity)
{
return true;
}
return CurrentCapacity >= min;
}
public virtual bool AddTeam(string name, int capacity, int color)
{
return AddTeam(name, 0, capacity, color);
}
public virtual bool AddTeam(string name, int minCapacity, int capacity, int color)
{
return AddTeam(new PvPTeam(this, name, minCapacity, capacity, color));
}
public virtual bool AddTeam(PvPTeam team)
{
if (!ContainsTeam(team))
{
Teams.Add(team);
OnTeamAdded(team);
return true;
}
return false;
}
public bool RemoveTeam(PvPTeam team)
{
if (Teams.Remove(team))
{
OnTeamRemoved(team);
return true;
}
return false;
}
public bool ContainsTeam(PvPTeam team)
{
return Teams.Contains(team);
}
public void ResetTeam(PvPTeam team)
{
if (team != null && !team.Deleted)
{
team.Reset();
}
}
public void ForEachTeam(Action<PvPTeam> action)
{
Teams.ForEachReverse(
t =>
{
if (t != null && !t.Deleted)
{
action(t);
}
else
{
Teams.Remove(t);
}
});
}
public void ForEachTeam<T>(Action<T> action)
where T : PvPTeam
{
Teams.ForEachReverse(
t =>
{
if (t != null && !t.Deleted)
{
if (t is T)
{
action((T)t);
}
}
else
{
Teams.Remove(t);
}
});
}
public virtual bool CanDamageOwnTeam(PlayerMobile damager, PlayerMobile target)
{
return Options.Rules.CanDamageOwnTeam && State == PvPBattleState.Running;
}
public virtual bool CanDamageEnemyTeam(PlayerMobile damager, PlayerMobile target)
{
return Options.Rules.CanDamageEnemyTeam && State == PvPBattleState.Running;
}
public virtual bool CanHealOwnTeam(PlayerMobile healer, PlayerMobile target)
{
return Options.Rules.CanHealOwnTeam && (State == PvPBattleState.Preparing || State == PvPBattleState.Running);
}
public virtual bool CanHealEnemyTeam(PlayerMobile healer, PlayerMobile target)
{
return Options.Rules.CanHealEnemyTeam && (State == PvPBattleState.Preparing || State == PvPBattleState.Running);
}
public virtual IEnumerable<PvPTeam> GetTeams()
{
return Teams.Where(t => t != null && !t.Deleted);
}
public virtual IOrderedEnumerable<PvPTeam> GetTeamsRanked()
{
return Teams.Where(t => t != null && !t.Deleted).Order();
}
public virtual int CompareTeam(PvPTeam a, PvPTeam b)
{
if (ReferenceEquals(a, b))
{
return 0;
}
var result = 0;
if (a.CompareNull(b, ref result))
{
return result;
}
return a.CompareTo(b);
}
public virtual int CountAliveTeams()
{
return Teams.Count(t => t.Dead.Count < t.Count);
}
public virtual IEnumerable<PvPTeam> GetAliveTeams()
{
return Teams.Where(t => t != null && !t.Deleted && t.Dead.Count < t.Count);
}
public virtual PvPTeam GetMostEmptyTeam()
{
return Teams.Where(t => t != null && !t.Deleted).Lowest(t => t.Count);
}
public virtual PvPTeam GetMostFullTeam()
{
return Teams.Where(t => t != null && !t.Deleted).Lowest(t => t.Count);
}
public virtual PvPTeam GetRandomTeam()
{
return Teams.Where(t => t != null && !t.Deleted).GetRandom();
}
public virtual PvPTeam GetAutoAssignTeam(PlayerMobile pm)
{
if (pm == null || pm.Deleted)
{
return null;
}
if (IsParticipant(pm, out var team) && team != null && !team.Deleted)
{
return team;
}
return Teams.OrderBy(GetAssignPriority).FirstOrDefault();
}
public virtual double GetAssignPriority(PvPTeam team)
{
GetAssignPriority(team, out var weight);
return weight;
}
protected virtual void GetAssignPriority(PvPTeam team, out double weight)
{
if (team == null || team.Deleted)
{
weight = Double.MaxValue;
return;
}
if (team.IsEmpty)
{
weight = Double.MinValue;
return;
}
weight = team.Aggregate(0.0, (v, m) => v + (m.SkillsTotal * m.RawStatTotal));
}
public PvPTeam FindTeam(PlayerMobile pm)
{
return FindTeam<PvPTeam>(pm);
}
public T FindTeam<T>(PlayerMobile pm)
where T : PvPTeam
{
return pm != null ? Teams.OfType<T>().FirstOrDefault(t => t.IsMember(pm)) : null;
}
public virtual void TeamRespawn(PvPTeam team)
{
if (team != null && !team.Deleted)
{
team.ForEachMember(team.Respawn);
}
}
public virtual void TeamEject(PvPTeam team)
{
if (team != null && !team.Deleted)
{
team.ForEachMember(member => team.RemoveMember(member, true));
}
}
public virtual void OnTeamInit(PvPTeam team)
{ }
public virtual void OnTeamSync(PvPTeam team)
{ }
public virtual void OnTeamMicroSync(PvPTeam team)
{ }
public virtual void OnTeamAdded(PvPTeam team)
{ }
public virtual void OnTeamRemoved(PvPTeam team)
{ }
public virtual void OnTeamFrozen(PvPTeam team)
{ }
public virtual void OnTeamUnfrozen(PvPTeam team)
{ }
public virtual void OnTeamMemberFrozen(PvPTeam team, PlayerMobile pm)
{ }
public virtual void OnTeamMemberUnfrozen(PvPTeam team, PlayerMobile pm)
{ }
public virtual void OnTeamMemberDeath(PvPTeam team, PlayerMobile pm)
{
LocalBroadcast("{0} has died.", pm.RawName);
UpdateStatistics(team, pm, s => ++s.Deaths);
var pk = pm.FindMostRecentDamager(false) as PlayerMobile;
if (pk != null && !pk.Deleted)
{
if (IsParticipant(pk, out var pkt))
{
if (KillPoints > 0 && !pk.Account.IsSharedWith(pm.Account))
{
RevokePoints(pm, KillPoints);
}
pm.LastKiller = pk;
UpdateStatistics(pkt, pk, s => ++s.Kills);
if (KillPoints > 0 && !pk.Account.IsSharedWith(pm.Account))
{
AwardPoints(pk, KillPoints);
}
}
}
TeleportToHomeBase(team, pm);
}
public virtual void OnAfterTeamMemberDeath(PvPTeam team, PlayerMobile pm)
{
RefreshStats(pm, true, true);
if (!TryKickOnDeath(team, pm, true) && !TryRespawnOnDeath(team, pm, true))
{
TeleportToHomeBase(team, pm);
team.Respawn(pm, false);
}
}
public virtual void OnTeamMemberResurrected(PvPTeam team, PlayerMobile pm)
{
UpdateStatistics(team, pm, s => ++s.Resurrections);
}
public virtual void OnAfterTeamMemberResurrected(PvPTeam team, PlayerMobile pm)
{
team.Dead.Remove(pm);
}
public virtual void OnTeamMemberAdded(PvPTeam team, PlayerMobile pm)
{
team.Broadcast("{0} has joined the battle.", pm.RawName);
if (UseTeamColors)
{
pm.SolidHueOverride = team.Color;
}
if (UseIncognito)
{
pm.BeginAction(typeof(IncognitoSpell));
pm.NameMod = NameList.RandomName(pm.Female ? "female" : "male");
var race = pm.Race ?? Race.DefaultRace;
pm.BodyMod = race.Body(pm);
pm.HueMod = race.RandomSkinHue();
pm.SetHairMods(race.RandomHair(pm.Female), race.RandomFacialHair(pm.Female));
}
}
public virtual void OnTeamMemberRemoved(PvPTeam team, PlayerMobile pm)
{
team.Broadcast("{0} has left the battle.", pm.RawName);
pm.SolidHueOverride = -1;
pm.EndAction(typeof(IncognitoSpell));
pm.NameMod = null;
pm.BodyMod = 0;
pm.HueMod = -1;
pm.SetHairMods(-1, -1);
}
public virtual bool TryKickOnDeath(PvPTeam team, PlayerMobile pm, bool isLoss)
{
if (team.KickOnDeath)
{
if (isLoss)
{
OnLose(pm);
}
team.RemoveMember(pm, true);
return true;
}
return false;
}
public virtual bool TryRespawnOnDeath(PvPTeam team, PlayerMobile pm, bool isDelayed)
{
if (team.RespawnOnDeath)
{
if (isDelayed && team.RespawnDelay > TimeSpan.Zero)
{
Timer.DelayCall(team.RespawnDelay, team.Respawn, pm);
}
else
{
team.Respawn(pm);
}
return true;
}
return false;
}
protected virtual void ProcessRanks()
{
if (Options.Missions.Enabled)
{
ProcessMissionRanks();
}
else if (RewardTeam)
{
ProcessTeamRanks(1);
}
else
{
ProcessPlayerRanks(1);
}
}
protected virtual void ProcessMissionRanks()
{
var players = ListPool<PlayerMobile>.AcquireObject();
players.AddRange(GetParticipants());
if (CheckMissions(out var team, out var player))
{
if (team != null)
{
WorldBroadcast("{0} has won {1}!", team.Name, Name);
team.ForEachMember(OnWin);
players.RemoveAll(team.IsMember);
}
else if (player != null)
{
WorldBroadcast("{0} has won {1}!", player.Name, Name);
OnWin(player);
players.Remove(player);
}
}
foreach (var p in players)
{
OnLose(p);
}
ObjectPool.Free(ref players);
}
protected virtual void ProcessTeamRanks(int limit)
{
if (limit <= 0)
{
return;
}
var teams = GetTeams().Where(t => !t.IsEmpty).ToLookup(GetScore, o => o);
if (teams.Count <= 0)
{
return;
}
bool win;
foreach (var o in teams.OrderByDescending(o => o.Key))
{
win = limit > 0 && o.Key > 0 && o.Any() && --limit >= 0;
foreach (var team in o)
{
if (win)
{
WorldBroadcast("{0} has won {1}!", team.Name, Name);
team.ForEachMember(OnWin);
}
else
{
team.ForEachMember(OnLose);
}
}
}
}
protected virtual void ProcessPlayerRanks(int limit)
{
if (limit <= 0)
{
return;
}
var players = GetParticipants().ToLookup(GetScore, o => o);
if (players.Count <= 0)
{
return;
}
bool win;
foreach (var o in players.OrderByDescending(o => o.Key))
{
win = limit > 0 && o.Key > 0 && o.Any() && --limit >= 0;
foreach (var player in o)
{
if (win)
{
WorldBroadcast("{0} has won {1}!", player.Name, Name);
OnWin(player);
}
else
{
OnLose(player);
}
}
}
}
protected double GetScore(PvPTeam team)
{
if (team != null)
{
return team.GetScore();
}
return 0;
}
protected double GetMissionsScore(PvPTeam team)
{
if (team != null)
{
return team.GetMissionsScore();
}
return 0;
}
protected double GetScore(PlayerMobile pm)
{
if (Options.Missions.Enabled)
{
return GetMissionsScore(pm);
}
return GetStatistic(pm, e => e.Points);
}
public double GetMissionsScore(PlayerMobile pm)
{
if (Options.Missions.Enabled)
{
return Options.Missions.ComputeScore(this, pm);
}
return 0;
}
}
}

View File

@@ -0,0 +1,228 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
public bool Validate(Mobile viewer = null)
{
return Validate(viewer, new List<string>());
}
public virtual bool Validate(Mobile viewer, List<string> errors, bool pop = true)
{
if (Deleted)
{
errors.Add("This battle has been deleted.");
return false;
}
if (String.IsNullOrWhiteSpace(Name))
{
errors.Add("Select a valid Name.");
errors.Add("[Options] -> [Edit Options]");
if (pop)
{
return false;
}
}
if (String.IsNullOrWhiteSpace(Description))
{
errors.Add("Select a valid Description.");
errors.Add("[Options] -> [Edit Options]");
if (pop)
{
return false;
}
}
if (SpectateAllowed)
{
if (SpectateRegion == null)
{
errors.Add("Select a valid Spectate Region.");
errors.Add("[Options] -> [Edit Spectage Region]");
if (pop)
{
return false;
}
}
else if (Options.Locations.SpectateBounds.Count == 0)
{
errors.Add("The Spectate Region has no zones.");
errors.Add("[Options] -> [Edit Spectage Region]");
if (pop)
{
return false;
}
}
}
if (BattleRegion == null)
{
errors.Add("Select a valid Battle Region.");
errors.Add("[Options] -> [Edit Battle Region]");
if (pop)
{
return false;
}
}
else if (Options.Locations.BattleBounds.Count == 0)
{
errors.Add("The Battle Region has no zones.");
errors.Add("[Options] -> [Edit Battle Region]");
if (pop)
{
return false;
}
}
if (Options.Locations.Map == Map.Internal)
{
errors.Add("The Battle Map must not be Internal.");
errors.Add("[Options] -> [Edit Advanced Options] -> [Locations]");
if (pop)
{
return false;
}
}
if (Options.Locations.Eject.Internal)
{
errors.Add("The Eject Map must not be Internal.");
errors.Add("[Options] -> [Edit Advanced Options] -> [Locations]");
if (pop)
{
return false;
}
}
if (Options.Locations.Eject == Point3D.Zero)
{
errors.Add("Select a valid Eject Location.");
errors.Add("[Options] -> [Edit Advanced Options] -> [Locations]");
if (pop)
{
return false;
}
}
else if (BattleRegion != null &&
BattleRegion.Contains(Options.Locations.Eject.Location, Options.Locations.Eject.Map))
{
errors.Add("Eject Location must be outside the Battle Region.");
errors.Add("[Options] -> [Edit Advanced Options] -> [Locations]");
if (pop)
{
return false;
}
}
if (SpectateAllowed)
{
if (Options.Locations.SpectateJoin == Point3D.Zero)
{
errors.Add("Select a valid Spectator Join location.");
errors.Add("[Options] -> [Edit Advanced Options] -> [Locations]");
if (pop)
{
return false;
}
}
else if (SpectateRegion != null && !SpectateRegion.Contains(Options.Locations.SpectateJoin))
{
errors.Add("Spectate Join Location must be within the Spectate Region.");
errors.Add("[Options] -> [Edit Advanced Options] -> [Locations]");
if (pop)
{
return false;
}
}
}
if (Schedule == null)
{
errors.Add("No Schedule has been set for this battle.");
errors.Add("[Options] -> [View Schedule]");
if (pop)
{
return false;
}
}
else if (Schedule.Enabled && Schedule.NextGlobalTick == null)
{
errors.Add("The Schedule has no more future dates.");
errors.Add("[Options] -> [View Schedule]");
if (pop)
{
return false;
}
}
if (IdleKick && IdleThreshold.TotalSeconds < 10.0)
{
errors.Add("The Idle Threshold must be greater than, or equal to 10 seconds.");
errors.Add("[Options] -> [Edit Options]");
if (pop)
{
return false;
}
}
if (Teams.Count == 0)
{
errors.Add("There are no teams available for this Battle.");
errors.Add("[Options] -> [View Teams]");
if (pop)
{
return false;
}
}
else if (Teams.Any(t => !t.Validate(viewer)))
{
errors.Add("One or more teams did not pass validation.");
errors.Add("[Options] -> [View Teams]");
if (pop)
{
return false;
}
}
return errors.Count == 0;
}
}
}

View File

@@ -0,0 +1,190 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#if ServUO58
#define ServUOX
#endif
#region References
using System;
using System.Linq;
using System.Threading.Tasks;
using Server;
using Server.Movement;
using VitaNex.FX;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public abstract partial class PvPBattle
{
private static readonly PvPBattleWeatherDirection[] _WeatherDirections = ((PvPBattleWeatherDirection)0)
.GetValues<PvPBattleWeatherDirection>()
.Not(d => d == PvPBattleWeatherDirection.None || d == PvPBattleWeatherDirection.Random)
.ToArray();
public virtual bool CanUseWeather()
{
if (Options.Locations.BattleBounds == null || Options.Locations.BattleBounds.Count == 0 ||
Options.Locations.Map == Map.Internal)
{
return false;
}
if (Options.Weather.Density <= 0 || Options.Weather.EffectID <= 0 || Options.Weather.EffectSpeed <= 0)
{
return false;
}
if (Options.Weather.Force)
{
return true;
}
if (!Options.Weather.Enabled || State == PvPBattleState.Internal)
{
return false;
}
#if ServUOX
if (BattleRegion != null && BattleRegion.MobileCount == 0)
#else
if (BattleRegion != null && BattleRegion.GetMobileCount() == 0)
#endif
{
return false;
}
if (!Options.SuddenDeath.Enabled || !Options.SuddenDeath.Active)
{
return false;
}
if (DateTime.UtcNow - Options.SuddenDeath.StartedWhen < Options.SuddenDeath.Delay)
{
return false;
}
return true;
}
public virtual Point3D GetWeatherStartPoint(Point3D loc, PvPBattleWeatherDirection direction)
{
if (!Options.Weather.Enabled || Options.Locations.Map == null || Options.Locations.Map == Map.Internal ||
loc == Point3D.Zero)
{
return loc;
}
switch (direction)
{
case PvPBattleWeatherDirection.None:
return loc.Clone3D(0, 0, 80);
case PvPBattleWeatherDirection.Random:
direction = _WeatherDirections.GetRandom(PvPBattleWeatherDirection.None);
break;
}
int x = 0, y = 0;
Movement.Offset((Direction)direction, ref x, ref y);
var rand = Utility.RandomMinMax(4, 8);
return loc.Clone3D(x * rand, y * rand, 80);
}
protected virtual void WeatherCycle()
{
if (!CanUseWeather())
{
return;
}
Point3D start, end;
Parallel.ForEach(
Options.Locations.BattleBounds,
b =>
{
end = b.Start.Clone2D(Utility.Random(b.Width), Utility.Random(b.Height)).GetWorldTop(Options.Locations.Map);
start = GetWeatherStartPoint(end, Options.Weather.Direction);
new MovingEffectInfo(
start,
end,
Options.Locations.Map,
Options.Weather.EffectID,
Options.Weather.EffectHue,
Options.Weather.EffectSpeed,
Options.Weather.EffectRender,
TimeSpan.FromMilliseconds(Utility.Random(500))).MovingImpact(WeatherImpactHandler);
});
}
protected virtual void WeatherImpactHandler(MovingEffectInfo info)
{
if (info == null || Deleted || !Options.Weather.Impacts || Options.Weather.ImpactEffectID <= 0 ||
Options.Weather.ImpactEffectSpeed <= 0 || Options.Weather.ImpactEffectDuration <= 0)
{
return;
}
OnWeatherImpact(info);
if (Options.Weather.ImpactEffectID <= 0)
{
return;
}
var effect = new EffectInfo(
info.Target,
info.Map,
Options.Weather.ImpactEffectID,
Options.Weather.ImpactEffectHue,
Options.Weather.ImpactEffectSpeed,
Options.Weather.ImpactEffectDuration,
Options.Weather.ImpactEffectRender);
effect.Send();
OnWeatherImpact(effect);
}
protected virtual void OnWeatherImpact(MovingEffectInfo info)
{ }
protected virtual void OnWeatherImpact(EffectInfo info)
{
if (info == null || Deleted || !Options.Weather.Impacts)
{
return;
}
if (Options.Weather.ImpactEffectSound > 0)
{
Effects.PlaySound(info.Source, info.Map, Options.Weather.ImpactEffectSound);
}
if (!Options.SuddenDeath.Enabled || !Options.SuddenDeath.Active || !Options.SuddenDeath.Damages)
{
return;
}
foreach (var pm in info.Source.GetPlayersInRange(info.Map, Options.SuddenDeath.DamageRange))
{
Options.SuddenDeath.Damage(pm);
}
}
}
}

View File

@@ -0,0 +1,412 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using Server;
using Server.Mobiles;
using VitaNex.SuperGumps;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public class PvPProfile : IEnumerable<PvPProfileHistoryEntry>
{
[CommandProperty(AutoPvP.Access)]
public bool Deleted { get; private set; }
[CommandProperty(AutoPvP.Access)]
public PlayerMobile Owner { get; private set; }
private long _Points;
[CommandProperty(AutoPvP.Access)]
public long RawPoints { get => _Points; set => _Points = Math.Max(0, value); }
[CommandProperty(AutoPvP.Access)]
public long Points
{
get => RawPoints;
set
{
var oldVal = RawPoints;
RawPoints = value;
if (oldVal != RawPoints)
{
OnPointsChanged(oldVal);
}
}
}
[CommandProperty(AutoPvP.Access)]
public List<PvPBattle> Subscriptions { get; private set; }
[CommandProperty(AutoPvP.Access)]
public long TotalDamageTaken => GetTotalDamageTaken();
[CommandProperty(AutoPvP.Access)]
public long TotalDamageDone => GetTotalDamageDone();
[CommandProperty(AutoPvP.Access)]
public long TotalHealingTaken => GetTotalHealingTaken();
[CommandProperty(AutoPvP.Access)]
public long TotalHealingDone => GetTotalHealingDone();
[CommandProperty(AutoPvP.Access)]
public long TotalDeaths => GetTotalDeaths();
[CommandProperty(AutoPvP.Access)]
public long TotalResurrections => GetTotalResurrections();
[CommandProperty(AutoPvP.Access)]
public long TotalKills => GetTotalKills();
[CommandProperty(AutoPvP.Access)]
public long TotalPointsGained => GetTotalPointsGained();
[CommandProperty(AutoPvP.Access)]
public long TotalPointsLost => GetTotalPointsLost();
[CommandProperty(AutoPvP.Access)]
public long TotalPoints => TotalPointsGained - TotalPointsLost;
[CommandProperty(AutoPvP.Access)]
public long TotalWins => GetTotalWins();
[CommandProperty(AutoPvP.Access)]
public long TotalLosses => GetTotalLosses();
[CommandProperty(AutoPvP.Access)]
public long TotalBattles => GetTotalBattles();
[CommandProperty(AutoPvP.Access)]
public virtual PvPProfileHistory History { get; set; }
[CommandProperty(AutoPvP.Access)]
public PvPProfileHistoryEntry Statistics => History.EnsureEntry();
public PvPProfile(PlayerMobile owner)
{
Owner = owner;
History = new PvPProfileHistory(this);
Subscriptions = new List<PvPBattle>();
SubscribeAllBattles();
}
public PvPProfile(GenericReader reader)
{
Deserialize(reader);
}
public void SubscribeAllBattles()
{
foreach (var battle in AutoPvP.GetBattles())
{
Subscribe(battle);
}
}
public bool IsSubscribed(PvPBattle battle)
{
return battle != null && !battle.Deleted && Subscriptions.Contains(battle);
}
public void Subscribe(PvPBattle battle)
{
if (battle != null && !battle.Deleted && !battle.IsInternal)
{
Subscriptions.Update(battle);
}
}
public void Unsubscribe(PvPBattle battle)
{
if (battle != null && !battle.Deleted)
{
Subscriptions.Remove(battle);
}
}
protected virtual void OnPointsChanged(long oldVal)
{
if (_Points > oldVal)
{
OnPointsGained(_Points - oldVal);
}
else if (_Points < oldVal)
{
OnPointsLost(oldVal - _Points);
}
}
protected virtual void OnPointsGained(long value)
{
Statistics.PointsGained += value;
Owner.SendMessage("You have gained {0:#,0} Battle Point{1}!", value, value != 1 ? "s" : String.Empty);
}
protected virtual void OnPointsLost(long value)
{
Statistics.PointsLost += value;
Owner.SendMessage("You have lost {0:#,0} Battle Point{1}!", value, value != 1 ? "s" : String.Empty);
}
public long GetTotalDamageTaken()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.DamageTaken);
}
public long GetTotalDamageDone()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.DamageDone);
}
public long GetTotalHealingTaken()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.HealingTaken);
}
public long GetTotalHealingDone()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.HealingDone);
}
public long GetTotalResurrections()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.Resurrections);
}
public long GetTotalDeaths()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.Deaths);
}
public long GetTotalKills()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.Kills);
}
public long GetTotalPointsGained()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.PointsGained);
}
public long GetTotalPointsLost()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.PointsLost);
}
public long GetTotalWins()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.Wins);
}
public long GetTotalLosses()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.Losses);
}
public long GetTotalBattles()
{
return History.Values.Aggregate(0L, (c, entry) => c + entry.Battles);
}
public IEnumerable<KeyValuePair<string, long>> GetMiscStatisticTotals()
{
return History.Values.SelectMany(e => e.MiscStats)
.ToLookup(o => o.Key, o => o.Value)
.Select(o => new KeyValuePair<string, long>(o.Key, o.Aggregate(0L, (c, v) => c + v)));
}
public void Remove()
{
if (AutoPvP.RemoveProfile(this))
{
OnRemoved();
}
}
public void Delete()
{
if (Deleted)
{
return;
}
Deleted = true;
Remove();
History = null;
OnDeleted();
}
protected virtual void OnDeleted()
{ }
protected virtual void OnRemoved()
{ }
public virtual void Init()
{ }
public string ToHtmlString(Mobile viewer = null, bool big = true)
{
var html = new StringBuilder();
if (big)
{
html.Append("<BIG>");
}
GetHtmlString(viewer, html);
if (big)
{
html.Append("</BIG>");
}
return html.ToString();
}
public virtual void GetHtmlString(Mobile viewer, StringBuilder html)
{
html.Append("".WrapUOHtmlColor(SuperGump.DefaultHtmlColor, false));
if (Deleted)
{
html.Append("<B>This profile has been deleted.</B>");
return;
}
html.AppendLine("<B>PvP Profile for {0}</B>", Owner.RawName);
html.AppendLine();
html.Append("".WrapUOHtmlColor(Color.YellowGreen, false));
html.AppendLine("<B>Statistics</B>");
html.AppendLine();
html.AppendLine("* Overall Points: {0}", _Points.ToString("#,0"));
html.AppendLine();
Statistics.GetHtmlString(viewer, html);
html.Append("".WrapUOHtmlColor(Color.Cyan, false));
html.AppendLine("<B>Statisctics For All Seasons:</B>");
html.AppendLine();
html.AppendLine("<B>Main Statistic Totals</B>");
html.AppendLine();
html.AppendLine("* Battles Attended: {0}", TotalBattles.ToString("#,0"));
html.AppendLine("* Battles Won: {0}", TotalWins.ToString("#,0"));
html.AppendLine("* Battles Lost: {0}", TotalLosses.ToString("#,0"));
html.AppendLine("* Points Gained: {0}", TotalPointsGained.ToString("#,0"));
html.AppendLine("* Points Lost: {0}", TotalPointsLost.ToString("#,0"));
html.AppendLine("* Kills: {0}", TotalKills.ToString("#,0"));
html.AppendLine("* Deaths: {0}", TotalDeaths.ToString("#,0"));
html.AppendLine("* Resurrections: {0}", TotalResurrections.ToString("#,0"));
html.AppendLine("* Damage Taken: {0}", TotalDamageTaken.ToString("#,0"));
html.AppendLine("* Damage Done: {0}", TotalDamageDone.ToString("#,0"));
html.AppendLine("* Healing Taken: {0}", TotalHealingTaken.ToString("#,0"));
html.AppendLine("* Healing Done: {0}", TotalHealingDone.ToString("#,0"));
html.AppendLine();
html.Append("".WrapUOHtmlColor(Color.GreenYellow, false));
html.AppendLine("<B>Misc Statistic Totals</B>");
html.AppendLine();
foreach (var kvp in GetMiscStatisticTotals())
{
html.AppendLine("* {0}: {1}", kvp.Key, kvp.Value.ToString("#,0"));
}
html.AppendLine();
html.Append("".WrapUOHtmlColor(SuperGump.DefaultHtmlColor, false));
}
public IEnumerator<PvPProfileHistoryEntry> GetEnumerator()
{
return History.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Serialize(GenericWriter writer)
{
var version = writer.SetVersion(0);
writer.Write(Deleted);
writer.Write(Owner);
switch (version)
{
case 0:
{
writer.Write(_Points);
writer.WriteBlock(w => w.WriteType(History, t => History.Serialize(w)));
writer.WriteBlockList(Subscriptions, (w, b) => w.WriteType(b.Serial, t => b.Serial.Serialize(w)));
}
break;
}
}
public void Deserialize(GenericReader reader)
{
var version = reader.ReadInt();
Deleted = reader.ReadBool();
Owner = reader.ReadMobile<PlayerMobile>();
switch (version)
{
case 0:
{
_Points = reader.ReadLong();
History = reader.ReadBlock(r => r.ReadTypeCreate<PvPProfileHistory>(this, r)) ?? new PvPProfileHistory(this);
Subscriptions = reader.ReadBlockList(
r =>
{
var serial = r.ReadTypeCreate<PvPSerial>(r) ?? new PvPSerial(r);
return AutoPvP.FindBattleByID(serial);
},
Subscriptions);
}
break;
}
}
}
}

View File

@@ -0,0 +1,119 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public class PvPProfileHistory
{
public PvPProfile Profile { get; private set; }
public Dictionary<int, PvPProfileHistoryEntry> Entries { get; private set; }
public Dictionary<int, PvPProfileHistoryEntry>.KeyCollection Keys => Entries.Keys;
public Dictionary<int, PvPProfileHistoryEntry>.ValueCollection Values => Entries.Values;
private PvPProfileHistory(PvPProfile owner)
{
Profile = owner;
}
public PvPProfileHistory(PvPProfile owner, params PvPProfileHistoryEntry[] entries)
: this(owner)
{
if (entries == null)
{
Entries = new Dictionary<int, PvPProfileHistoryEntry>();
}
else
{
Entries = new Dictionary<int, PvPProfileHistoryEntry>(entries.Length);
foreach (var entry in entries)
{
var season = AutoPvP.EnsureSeason(entry.Season);
if (season != null)
{
Entries[season.Number] = entry;
}
}
}
}
public PvPProfileHistory(PvPProfile owner, IDictionary<int, PvPProfileHistoryEntry> dictionary)
: this(owner)
{
Entries = new Dictionary<int, PvPProfileHistoryEntry>(dictionary);
}
public PvPProfileHistory(PvPProfile owner, GenericReader reader)
: this(owner)
{
Deserialize(reader);
}
public virtual PvPProfileHistoryEntry EnsureEntry(bool replace = false)
{
return EnsureEntry(AutoPvP.CurrentSeason, replace);
}
public virtual PvPProfileHistoryEntry EnsureEntry(PvPSeason season, bool replace = false)
{
if (!Entries.TryGetValue(season.Number, out var entry) || entry == null || replace)
{
Entries[season.Number] = entry = new PvPProfileHistoryEntry(season.Number);
}
return entry;
}
public virtual void Serialize(GenericWriter writer)
{
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteBlockDictionary(Entries, (w, k, e) => w.WriteType(e, t => e.Serialize(w)));
}
break;
}
}
public virtual void Deserialize(GenericReader reader)
{
var version = reader.ReadInt();
switch (version)
{
case 0:
{
Entries = reader.ReadBlockDictionary(
r =>
{
var e = r.ReadTypeCreate<PvPProfileHistoryEntry>(r);
return new KeyValuePair<int, PvPProfileHistoryEntry>(e.Season, e);
},
Entries);
}
break;
}
}
}
}

View File

@@ -0,0 +1,404 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Server;
using VitaNex.SuperGumps;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPProfileHistoryEntry : PropertyObject, IEquatable<PvPProfileHistoryEntry>
{
[CommandProperty(AutoPvP.Access)]
public PvPSerial UID { get; private set; }
[CommandProperty(AutoPvP.Access, true)]
public int Season { get; private set; }
[CommandProperty(AutoPvP.Access)]
public virtual long Battles { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long Wins { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long Losses { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long PointsGained { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long PointsLost { get; set; }
[CommandProperty(AutoPvP.Access)]
public long Points => PointsGained - PointsLost;
[CommandProperty(AutoPvP.Access)]
public virtual long DamageTaken { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long DamageDone { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long HealingTaken { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long HealingDone { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long Kills { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long Deaths { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual long Resurrections { get; set; }
public virtual Dictionary<string, long> MiscStats { get; protected set; }
public virtual long this[string stat]
{
get => MiscStats.GetValue(stat);
set
{
if (String.IsNullOrWhiteSpace(stat))
{
return;
}
if (MiscStats.ContainsKey(stat))
{
if (value < 0)
{
MiscStats.Remove(stat);
}
else
{
MiscStats[stat] = value;
}
}
else if (value >= 0)
{
MiscStats[stat] = value;
}
}
}
public PvPProfileHistoryEntry(int season)
{
Season = season;
UID = new PvPSerial(Season + "~" + TimeStamp.UtcNow + "~" + Utility.RandomDouble());
MiscStats = new Dictionary<string, long>();
}
public PvPProfileHistoryEntry(GenericReader reader)
: base(reader)
{ }
public virtual void SetDefaults()
{
Battles = 0;
Wins = 0;
Losses = 0;
PointsGained = 0;
PointsLost = 0;
DamageTaken = 0;
DamageDone = 0;
HealingTaken = 0;
HealingDone = 0;
Kills = 0;
Deaths = 0;
Resurrections = 0;
MiscStats.Clear();
}
public override void Clear()
{
SetDefaults();
}
public override void Reset()
{
SetDefaults();
}
public virtual long GetMiscStat(string stat)
{
return this[stat];
}
public virtual void SetMiscStat(string stat, long value)
{
this[stat] = value;
}
public void MergeFrom(PvPProfileHistoryEntry e, bool points)
{
if (e != null)
{
e.MergeTo(this, points);
}
}
public void MergeTo(PvPProfileHistoryEntry e, bool points)
{
if (e == null)
{
return;
}
AddTo(e, points);
Battles = 0;
Wins = 0;
Losses = 0;
if (points)
{
PointsGained = 0;
PointsLost = 0;
}
DamageTaken = 0;
DamageDone = 0;
HealingTaken = 0;
HealingDone = 0;
Kills = 0;
Deaths = 0;
Resurrections = 0;
MiscStats.Clear();
}
public void TakeFrom(PvPProfileHistoryEntry e, bool points)
{
if (e != null)
{
e.AddTo(this, points);
}
}
public void AddTo(PvPProfileHistoryEntry e, bool points)
{
if (e == null)
{
return;
}
e.Battles += Battles;
e.Wins += Wins;
e.Losses += Losses;
if (points)
{
e.PointsGained += PointsGained;
e.PointsLost += PointsLost;
}
e.DamageTaken += DamageTaken;
e.DamageDone += DamageDone;
e.HealingTaken += HealingTaken;
e.HealingDone += HealingDone;
e.Kills += Kills;
e.Deaths += Deaths;
e.Resurrections += Resurrections;
foreach (var o in MiscStats)
{
e[o.Key] += o.Value;
}
}
public string ToHtmlString(bool big)
{
return ToHtmlString(null, big);
}
public string ToHtmlString(Mobile viewer, bool big)
{
var sb = new StringBuilder();
if (big)
{
sb.Append("<BIG>");
}
GetHtmlString(viewer, sb);
if (big)
{
sb.Append("</BIG>");
}
return sb.ToString();
}
public virtual void GetHtmlString(Mobile viewer, StringBuilder html)
{
html.Append(String.Empty.WrapUOHtmlColor(Color.Cyan, false));
html.AppendLine("Statistics For Season: {0:#,0}".WrapUOHtmlBold(), Season);
html.AppendLine();
html.AppendLine("Statistics:".WrapUOHtmlBold());
html.AppendLine();
html.AppendLine("Battles Attended: {0:#,0}", Battles);
html.AppendLine("Battles Won: {0:#,0}", Wins);
html.AppendLine("Battles Lost: {0:#,0}", Losses);
html.AppendLine();
html.AppendLine("Points Total: {0:#,0}", Points);
html.AppendLine("Points Gained: {0:#,0}", PointsGained);
html.AppendLine("Points Lost: {0:#,0}", PointsLost);
html.AppendLine();
html.AppendLine("Kills: {0:#,0}", Kills);
html.AppendLine("Deaths: {0:#,0}", Deaths);
html.AppendLine("Resurrections: {0:#,0}", Resurrections);
html.AppendLine("Damage Taken: {0:#,0}", DamageTaken);
html.AppendLine("Damage Given: {0:#,0}", DamageDone);
html.AppendLine("Healing Taken: {0:#,0}", HealingTaken);
html.AppendLine("Healing Given: {0:#,0}", HealingDone);
html.AppendLine();
html.Append(String.Empty.WrapUOHtmlColor(Color.GreenYellow, false));
html.AppendLine("Misc Statistics:");
foreach (var kvp in MiscStats)
{
html.AppendLine("{0}: {1:#,0}", kvp.Key, kvp.Value);
}
html.AppendLine();
html.Append(String.Empty.WrapUOHtmlColor(SuperGump.DefaultHtmlColor, false));
}
public override sealed int GetHashCode()
{
return UID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is PvPProfileHistoryEntry && Equals((PvPProfileHistoryEntry)obj);
}
public virtual bool Equals(PvPProfileHistoryEntry other)
{
return !ReferenceEquals(other, null) && UID == other.UID;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(1);
UID.Serialize(writer);
switch (version)
{
case 1:
case 0:
{
writer.Write(Season);
writer.Write(DamageTaken);
writer.Write(DamageDone);
writer.Write(HealingTaken);
writer.Write(HealingDone);
writer.Write(Kills);
writer.Write(Deaths);
writer.Write(Resurrections);
writer.Write(PointsGained);
writer.Write(PointsLost);
writer.Write(Wins);
writer.Write(Losses);
writer.Write(Battles);
writer.WriteBlockDictionary(
MiscStats,
(w, k, v) =>
{
w.Write(k);
w.Write(v);
});
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
UID = version > 0 ? new PvPSerial(reader) : new PvPSerial(TimeStamp.UtcNow + "~" + Utility.RandomDouble());
switch (version)
{
case 1:
case 0:
{
Season = reader.ReadInt();
DamageTaken = reader.ReadLong();
DamageDone = reader.ReadLong();
HealingTaken = reader.ReadLong();
HealingDone = reader.ReadLong();
Kills = reader.ReadLong();
Deaths = reader.ReadLong();
Resurrections = reader.ReadLong();
PointsGained = reader.ReadLong();
PointsLost = reader.ReadLong();
Wins = reader.ReadLong();
Losses = reader.ReadLong();
Battles = reader.ReadLong();
MiscStats = reader.ReadBlockDictionary(
r =>
{
var k = r.ReadString();
var v = r.ReadLong();
return new KeyValuePair<string, long>(k, v);
},
MiscStats);
}
break;
}
}
public static bool operator ==(PvPProfileHistoryEntry left, PvPProfileHistoryEntry right)
{
return ReferenceEquals(left, null) ? ReferenceEquals(right, null) : left.Equals(right);
}
public static bool operator !=(PvPProfileHistoryEntry left, PvPProfileHistoryEntry right)
{
return ReferenceEquals(left, null) ? !ReferenceEquals(right, null) : !left.Equals(right);
}
}
}

View File

@@ -0,0 +1,21 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
namespace VitaNex.Modules.AutoPvP
{
public enum PvPProfileRankOrder
{
None,
Points,
Wins,
Kills
}
}

View File

@@ -0,0 +1,604 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Linq;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Regions;
using Server.Targeting;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public abstract class PvPRegion : BaseRegion
{
[CommandProperty(AutoPvP.Access)]
public PvPBattle Battle { get; set; }
public PvPRegion(PvPBattle battle, string name, params Rectangle3D[] bounds)
: base(name, battle.Options.Locations.Map, battle.Options.Locations.BattlePriority, bounds.Ensure().ZFix().ToArray())
{
Battle = battle;
}
public PvPRegion(PvPBattle battle, string name, GenericReader reader)
: this(battle, name)
{
Deserialize(reader);
}
public void MicroSync()
{
if (Battle != null)
{
OnMicroSync();
}
}
public virtual void OnMicroSync()
{ }
public override bool AllowBeneficial(Mobile from, Mobile target)
{
if (Battle != null)
{
if (NotoUtility.Resolve(from, target, out PlayerMobile x, out PlayerMobile y))
{
var result = Battle.AllowBeneficial(x, y, out var handled);
if (handled)
{
return result;
}
}
}
return base.AllowBeneficial(from, target);
}
public override bool AllowHarmful(Mobile from, IDamageable target)
{
if (target is Mobile mt)
{
return AllowHarmful(from, mt);
}
return base.AllowHarmful(from, target);
}
public virtual bool AllowHarmful(Mobile from, Mobile target)
{
if (Battle != null)
{
if (NotoUtility.Resolve(from, target, out PlayerMobile x, out PlayerMobile y))
{
var result = Battle.AllowHarmful(x, y, out var handled);
if (handled)
{
return result;
}
}
}
return base.AllowHarmful(from, target);
}
public override bool AllowHousing(Mobile from, Point3D p)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.AllowHousing(from, p))
{
return false;
}
return base.AllowHousing(from, p);
}
public override bool AllowSpawn()
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.AllowSpawn())
{
return false;
}
return base.AllowSpawn();
}
public override bool CanUseStuckMenu(Mobile m)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.CanUseStuckMenu(m))
{
return false;
}
return base.CanUseStuckMenu(m);
}
public override void OnAggressed(Mobile aggressor, Mobile aggressed, bool criminal)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnAggressed(aggressor, aggressed, criminal);
}
base.OnAggressed(aggressor, aggressed, criminal);
}
public override bool AcceptsSpawnsFrom(Region region)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.AcceptsSpawnsFrom(region))
{
return false;
}
return base.AcceptsSpawnsFrom(region);
}
public override void AlterLightLevel(Mobile m, ref int global, ref int personal)
{
base.AlterLightLevel(m, ref global, ref personal);
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.AlterLightLevel(m, ref global, ref personal);
}
}
public override bool CheckAccessibility(Item item, Mobile from)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.CheckAccessibility(item, from))
{
return false;
}
return base.CheckAccessibility(item, from);
}
public override TimeSpan GetLogoutDelay(Mobile m)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
return Battle.GetLogoutDelay(m);
}
return base.GetLogoutDelay(m);
}
public override bool OnDecay(Item item)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnDecay(item))
{
return false;
}
return base.OnDecay(item);
}
public override bool OnBeginSpellCast(Mobile m, ISpell s)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnBeginSpellCast(m, s))
{
return false;
}
return base.OnBeginSpellCast(m, s);
}
public override void OnBeneficialAction(Mobile helper, Mobile target)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnBeneficialAction(helper, target);
}
base.OnBeneficialAction(helper, target);
}
public override bool OnCombatantChange(Mobile m, IDamageable oldC, IDamageable newC)
{
if (oldC is Mobile || newC is Mobile)
{
return OnCombatantChange(m, oldC as Mobile, newC as Mobile);
}
return base.OnCombatantChange(m, oldC, newC);
}
public virtual bool OnCombatantChange(Mobile m, Mobile oldMob, Mobile newMob)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnCombatantChange(m, oldMob, newMob))
{
return false;
}
return base.OnCombatantChange(m, oldMob, newMob);
}
public override void OnCriminalAction(Mobile m, bool message)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnCriminalAction(m, message);
}
base.OnCriminalAction(m, message);
}
public override bool OnDamage(Mobile m, ref int damage)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
if (!Battle.CheckDamage(m, ref damage))
{
return false;
}
Timer.DelayCall(d => OnDamage(m, m.GetLastDamager(true), d), damage);
return true;
}
return base.OnDamage(m, ref damage);
}
protected void OnDamage(Mobile m, IEntity damager, int damage)
{
OnDamage(m, damager as Mobile, damage);
}
protected virtual void OnDamage(Mobile m, Mobile damager, int damage)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnDamage(damager, m, damage);
}
}
public override bool OnBeforeDeath(Mobile m)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnBeforeDeath(m))
{
return false;
}
return base.OnBeforeDeath(m);
}
public override void OnDeath(Mobile m)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnDeath(m);
}
base.OnDeath(m);
}
public override void OnDidHarmful(Mobile harmer, IDamageable harmed)
{
if (harmed is Mobile mh)
{
OnDidHarmful(harmer, mh);
}
else
{
base.OnDidHarmful(harmer, harmed);
}
}
public virtual void OnDidHarmful(Mobile harmer, Mobile harmed)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnDidHarmful(harmer, harmed);
}
base.OnDidHarmful(harmer, harmed);
}
public override bool OnSingleClick(Mobile m, object o)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnSingleClick(m, o))
{
return false;
}
return base.OnSingleClick(m, o);
}
public override bool OnDoubleClick(Mobile m, object o)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnDoubleClick(m, o))
{
return false;
}
return base.OnDoubleClick(m, o);
}
public override void OnEnter(Mobile m)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnEnter(this, m);
}
base.OnEnter(m);
}
public override void OnExit(Mobile m)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnExit(this, m);
}
base.OnExit(m);
}
public override void OnGotBeneficialAction(Mobile helper, Mobile target)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnGotBeneficialAction(helper, target);
}
base.OnGotBeneficialAction(helper, target);
}
public override void OnGotHarmful(Mobile harmer, IDamageable harmed)
{
if (harmed is Mobile mh)
{
OnGotHarmful(harmer, mh);
}
else
{
base.OnGotHarmful(harmer, harmed);
}
}
public virtual void OnGotHarmful(Mobile harmer, Mobile harmed)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnGotHarmful(harmer, harmed);
}
base.OnGotHarmful(harmer, harmed);
}
public override bool OnHeal(Mobile m, ref int heal)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
if (!Battle.CheckHeal(m, ref heal))
{
return false;
}
Timer.DelayCall(h => OnHeal(m, m.GetLastHealer(true), h), heal);
return true;
}
return base.OnHeal(m, ref heal);
}
protected void OnHeal(Mobile m, IEntity healer, int heal)
{
OnHeal(m, healer as Mobile, heal);
}
protected virtual void OnHeal(Mobile m, Mobile healer, int heal)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnHeal(healer, m, heal);
}
}
public override void OnLocationChanged(Mobile m, Point3D oldLocation)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnLocationChanged(m, oldLocation);
}
base.OnLocationChanged(m, oldLocation);
}
public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnMoveInto(m, d, newLocation, oldLocation))
{
return false;
}
return base.OnMoveInto(m, d, newLocation, oldLocation);
}
public override bool OnResurrect(Mobile m)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnResurrect(m))
{
return false;
}
return base.OnResurrect(m);
}
public override bool OnSkillUse(Mobile m, int skill)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnSkillUse(m, skill))
{
return false;
}
return base.OnSkillUse(m, skill);
}
public override void OnSpeech(SpeechEventArgs args)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnSpeech(args);
}
base.OnSpeech(args);
}
public override void OnSpellCast(Mobile m, ISpell s)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.OnSpellCast(m, s);
}
base.OnSpellCast(m, s);
}
public override bool OnTarget(Mobile m, Target t, object o)
{
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden && !Battle.OnTarget(m, t, o))
{
return false;
}
return base.OnTarget(m, t, o);
}
public override void SpellDamageScalar(Mobile caster, Mobile target, ref double damage)
{
base.SpellDamageScalar(caster, target, ref damage);
if (Battle != null && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
Battle.SpellDamageScalar(caster, target, ref damage);
}
}
public virtual void Serialize(GenericWriter writer)
{
var version = writer.SetVersion(0);
switch (version)
{
case 0:
break;
}
}
public virtual void Deserialize(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 0:
break;
}
}
}
public class PvPBattleRegion : PvPRegion
{
[CommandProperty(AutoPvP.Access)]
public bool FloorItemDelete { get; set; }
public PvPBattleRegion(PvPBattle battle)
: base(battle, battle.BattleRegionName, battle.Options.Locations.BattleBounds.ToArray())
{ }
public PvPBattleRegion(PvPBattle battle, GenericReader reader)
: base(battle, battle.BattleRegionName, reader)
{ }
public override void OnMicroSync()
{
base.OnMicroSync();
if (FloorItemDelete && Battle.State != PvPBattleState.Internal && !Battle.Hidden)
{
var delete = Area.SelectMany(r => r.FindEntities<Item>(Map))
.Not(i => i == null || i.Deleted || i is Static || i is LOSBlocker || i is Blocker)
.Where(i => i.Movable && i.Visible && i.Decays);
foreach (var i in delete)
{
i.Delete();
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(1);
switch (version)
{
case 1:
writer.Write(FloorItemDelete);
goto case 0;
case 0:
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 1:
FloorItemDelete = reader.ReadBool();
goto case 0;
case 0:
break;
}
}
}
public class PvPSpectateRegion : PvPRegion
{
public PvPSpectateRegion(PvPBattle battle)
: base(battle, battle.SpectateRegionName, battle.Options.Locations.SpectateBounds.ToArray())
{ }
public PvPSpectateRegion(PvPBattle battle, GenericReader reader)
: base(battle, battle.SpectateRegionName, reader)
{ }
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
}
}

View File

@@ -0,0 +1,91 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public sealed class PvPScenario
{
private readonly Type _TypeOf;
private string _Info;
private string _Name;
public PvPScenario(PvPBattle battle)
{
_TypeOf = battle.GetType();
_Name = battle.Name;
_Info = battle.ToHtmlString(preview: true).Replace("(Internal)", String.Empty);
}
public Type TypeOf => _TypeOf;
public string Name
{
get => _Name;
set
{
if (!String.IsNullOrEmpty(value))
{
_Name = value;
}
}
}
public string Info
{
get => _Info;
set
{
if (!String.IsNullOrEmpty(value))
{
_Info = value;
}
}
}
public PvPBattle CreateBattle()
{
var battle = Activator.CreateInstance(_TypeOf) as PvPBattle;
foreach (var profile in AutoPvP.Profiles.Values)
{
if (!profile.IsSubscribed(battle))
{
profile.Subscribe(battle);
}
}
return battle;
}
public override string ToString()
{
return String.Format("{0}: {1}", _Name, _TypeOf);
}
public string ToHtmlString(Mobile viewer = null, bool big = true)
{
return big ? String.Format("<big>{0}</big>", _Info) : _Info;
}
public static implicit operator PvPScenario(PvPBattle battle)
{
return new PvPScenario(battle);
}
}
}

View File

@@ -0,0 +1,260 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPSeason : IComparable<PvPSeason>, IEquatable<PvPSeason>
{
public PvPSeason(int number)
{
Number = number;
Winners = new Dictionary<PlayerMobile, List<Item>>();
Losers = new Dictionary<PlayerMobile, List<Item>>();
}
public PvPSeason(GenericReader reader)
{
Deserialize(reader);
}
public int Number { get; private set; }
public DateTime? Started { get; private set; }
public DateTime? Ended { get; private set; }
public Dictionary<PlayerMobile, List<Item>> Winners { get; private set; }
public Dictionary<PlayerMobile, List<Item>> Losers { get; private set; }
public bool Active => (this == AutoPvP.CurrentSeason);
public virtual int CompareTo(PvPSeason a)
{
if (a == null)
{
return -1;
}
if (Number > a.Number)
{
return 1;
}
if (Number < a.Number)
{
return -1;
}
return 0;
}
public virtual bool Equals(PvPSeason a)
{
return a != null && (ReferenceEquals(this, a) || Number == a.Number);
}
public override int GetHashCode()
{
return Number;
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public virtual void Start()
{
Started = DateTime.UtcNow;
}
public virtual void End()
{
Ended = DateTime.UtcNow;
}
public virtual void Sync()
{
if (Active && Started == null)
{
Start();
}
else if (!Active && Ended == null)
{
if (Started == null)
{
Start();
}
End();
AutoPvP.SeasonChanged(this);
}
}
public virtual void Serialize(GenericWriter writer)
{
var version = writer.SetVersion(1);
switch (version)
{
case 1:
{
writer.WriteBlockDictionary(
Winners,
(w, k, v) =>
{
w.Write(k);
w.WriteItemList(v, true);
});
writer.WriteBlockDictionary(
Losers,
(w, k, v) =>
{
w.Write(k);
w.WriteItemList(v, true);
});
}
goto case 0;
case 0:
{
writer.Write(Number);
if (version < 1)
{
writer.WriteMobileList(Winners.Keys.ToList(), true);
writer.WriteMobileList(Losers.Keys.ToList(), true);
}
if (Started != null)
{
writer.Write(true);
writer.Write(Started.Value);
}
else
{
writer.Write(false);
}
if (Ended != null)
{
writer.Write(true);
writer.Write(Ended.Value);
}
else
{
writer.Write(false);
}
}
break;
}
}
public virtual void Deserialize(GenericReader reader)
{
var version = reader.GetVersion();
switch (version)
{
case 1:
{
Winners = reader.ReadBlockDictionary(
r =>
{
var k = r.ReadMobile<PlayerMobile>();
var v = r.ReadStrongItemList();
return new KeyValuePair<PlayerMobile, List<Item>>(k, v);
});
Losers = reader.ReadBlockDictionary(
r =>
{
var k = r.ReadMobile<PlayerMobile>();
var v = r.ReadStrongItemList();
return new KeyValuePair<PlayerMobile, List<Item>>(k, v);
});
}
goto case 0;
case 0:
{
Number = reader.ReadInt();
if (version < 1)
{
var winners = reader.ReadStrongMobileList<PlayerMobile>();
Winners = new Dictionary<PlayerMobile, List<Item>>(winners.Count);
winners.ForEach(m => Winners.Add(m, new List<Item>()));
var losers = reader.ReadStrongMobileList<PlayerMobile>();
Losers = new Dictionary<PlayerMobile, List<Item>>(losers.Count);
losers.ForEach(m => Losers.Add(m, new List<Item>()));
}
if (reader.ReadBool())
{
Started = reader.ReadDateTime();
}
if (reader.ReadBool())
{
Ended = reader.ReadDateTime();
}
}
break;
}
}
public override string ToString()
{
return String.Format("Season: {0}", Number);
}
public string ToHtmlString(Mobile viewer = null, bool big = true)
{
var sb = new StringBuilder();
sb.AppendLine(ToString());
sb.AppendLine();
if (Started != null)
{
sb.AppendLine("Started: {0}", Started);
}
if (Ended != null)
{
sb.AppendLine("Ended: {0}", Ended);
}
if (Winners.Count > 0)
{
sb.AppendLine("Winners");
sb.AppendLine();
Winners.Keys.For(
(i, p) => sb.AppendLine("{0}: {1}", (Numeral)(i + 1), p.Name.WrapUOHtmlColor(viewer.GetNotorietyColor(p))));
}
sb.AppendLine();
return big ? String.Format("<big>{0}</big>", sb) : sb.ToString();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleBroadcasts : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleLocalBroadcasts Local { get; protected set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleWorldBroadcasts World { get; protected set; }
public PvPBattleBroadcasts()
{
Local = new PvPBattleLocalBroadcasts();
World = new PvPBattleWorldBroadcasts();
}
public PvPBattleBroadcasts(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Battle Broadcasts";
}
public override void Clear()
{
Local.Clear();
World.Clear();
}
public override void Reset()
{
Local.Reset();
World.Reset();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteBlock(w => w.WriteType(Local, t => Local.Serialize(w)));
writer.WriteBlock(w => w.WriteType(World, t => World.Serialize(w)));
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
{
reader.ReadBlock(r => Local = r.ReadTypeCreate<PvPBattleLocalBroadcasts>(r) ?? new PvPBattleLocalBroadcasts());
reader.ReadBlock(r => World = r.ReadTypeCreate<PvPBattleWorldBroadcasts>(r) ?? new PvPBattleWorldBroadcasts());
}
break;
}
}
}
}

View File

@@ -0,0 +1,118 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public enum PvPBattleLocalBroadcastMode
{
Disabled,
Broadcast
}
[PropertyObject]
public class PvPBattleLocalBroadcasts : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public PvPBattleLocalBroadcastMode Mode { get; set; }
[Hue, CommandProperty(AutoPvP.Access)]
public int MessageHue { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool OpenNotify { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool StartNotify { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool EndNotify { get; set; }
public PvPBattleLocalBroadcasts()
{
OpenNotify = true;
StartNotify = true;
EndNotify = true;
MessageHue = 85;
Mode = PvPBattleLocalBroadcastMode.Disabled;
}
public PvPBattleLocalBroadcasts(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Local Broadcasts";
}
public override void Clear()
{
OpenNotify = false;
StartNotify = false;
EndNotify = false;
MessageHue = 0;
Mode = PvPBattleLocalBroadcastMode.Disabled;
}
public override void Reset()
{
OpenNotify = true;
StartNotify = true;
EndNotify = true;
MessageHue = 85;
Mode = PvPBattleLocalBroadcastMode.Disabled;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteFlag(Mode);
writer.Write(MessageHue);
writer.Write(OpenNotify);
writer.Write(StartNotify);
writer.Write(EndNotify);
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
switch (version)
{
case 0:
{
Mode = reader.ReadFlag<PvPBattleLocalBroadcastMode>();
MessageHue = reader.ReadInt();
OpenNotify = reader.ReadBool();
StartNotify = reader.ReadBool();
EndNotify = reader.ReadBool();
}
break;
}
}
}
}

View File

@@ -0,0 +1,120 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public enum PvPBattleWorldBroadcastMode
{
Disabled,
Broadcast,
TownCrier,
Notify
}
[PropertyObject]
public class PvPBattleWorldBroadcasts : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public PvPBattleWorldBroadcastMode Mode { get; set; }
[Hue, CommandProperty(AutoPvP.Access)]
public int MessageHue { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool OpenNotify { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool StartNotify { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool EndNotify { get; set; }
public PvPBattleWorldBroadcasts()
{
OpenNotify = true;
StartNotify = true;
EndNotify = true;
MessageHue = 85;
Mode = PvPBattleWorldBroadcastMode.Broadcast;
}
public PvPBattleWorldBroadcasts(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "World Broadcasts";
}
public override void Clear()
{
OpenNotify = false;
StartNotify = false;
EndNotify = false;
MessageHue = 0;
Mode = PvPBattleWorldBroadcastMode.Disabled;
}
public override void Reset()
{
OpenNotify = true;
StartNotify = true;
EndNotify = true;
MessageHue = 85;
Mode = PvPBattleWorldBroadcastMode.Broadcast;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteFlag(Mode);
writer.Write(MessageHue);
writer.Write(OpenNotify);
writer.Write(StartNotify);
writer.Write(EndNotify);
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
switch (version)
{
case 0:
{
Mode = reader.ReadFlag<PvPBattleWorldBroadcastMode>();
MessageHue = reader.ReadInt();
OpenNotify = reader.ReadBool();
StartNotify = reader.ReadBool();
EndNotify = reader.ReadBool();
}
break;
}
}
}
}

View File

@@ -0,0 +1,165 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleLocations : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public virtual int BattlePriority { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual Map Map { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual Point3D SpectateJoin { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual MapPoint Eject { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual MapPoint SpectateGate { get; set; }
public virtual List<Rectangle3D> BattleBounds { get; set; }
public virtual List<Rectangle3D> SpectateBounds { get; set; }
public Point3D BattleFixedPoint => GetBattleFixedPoint();
public Point3D SpectateFixedPoint => GetSpectateFixedPoint();
public PvPBattleLocations()
{
BattlePriority = Region.DefaultPriority;
Map = Map.Internal;
Eject = MapPoint.Empty;
SpectateGate = MapPoint.Empty;
SpectateJoin = Point3D.Zero;
BattleBounds = new List<Rectangle3D>();
SpectateBounds = new List<Rectangle3D>();
}
public PvPBattleLocations(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Battle Locations";
}
public override void Clear()
{
Map = Map.Internal;
BattlePriority = Region.DefaultPriority;
BattleBounds.Free(true);
SpectateBounds.Free(true);
SpectateJoin = Point3D.Zero;
Eject = MapPoint.Empty;
}
public override void Reset()
{
Map = Map.Internal;
BattlePriority = Region.DefaultPriority;
BattleBounds.Free(true);
SpectateBounds.Free(true);
SpectateJoin = Point3D.Zero;
Eject = MapPoint.Empty;
}
public Point3D GetBattleFixedPoint()
{
if (BattleBounds == null || BattleBounds.Count == 0)
{
return Point3D.Zero;
}
var p = BattleBounds[0].Start;
return p.ToPoint3D(Map.GetAverageZ(p.X, p.Y));
}
public Point3D GetSpectateFixedPoint()
{
if (SpectateBounds == null || SpectateBounds.Count == 0)
{
return Point3D.Zero;
}
var p = SpectateBounds[0].Start;
return p.ToPoint3D(Map.GetAverageZ(p.X, p.Y));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(1);
switch (version)
{
case 1:
SpectateGate.Serialize(writer);
goto case 0;
case 0:
{
writer.Write(Map);
writer.Write(BattlePriority);
Eject.Serialize(writer);
writer.Write(SpectateJoin);
writer.WriteBlockList(BattleBounds, (w, b) => w.Write(b));
writer.WriteBlockList(SpectateBounds, (w, b) => w.Write(b));
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 1:
SpectateGate = new MapPoint(reader);
goto case 0;
case 0:
{
Map = reader.ReadMap();
BattlePriority = reader.ReadInt();
Eject = new MapPoint(reader);
SpectateJoin = reader.ReadPoint3D();
BattleBounds = reader.ReadBlockList(r => r.ReadRect3D());
SpectateBounds = reader.ReadBlockList(r => r.ReadRect3D());
}
break;
}
}
}
}

View File

@@ -0,0 +1,183 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Drawing;
using System.Text;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleMissions : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public bool Enabled { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleObjectives Team { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleObjectives Player { get; set; }
public PvPBattleMissions()
{
Enabled = false;
Team = new PvPBattleObjectives();
Player = new PvPBattleObjectives();
}
public PvPBattleMissions(GenericReader reader)
: base(reader)
{ }
public virtual double ComputeScore(PvPTeam team)
{
if (!Enabled || Team.IsEmpty)
{
return 0;
}
return Team.ComputeScore(team);
}
public virtual double ComputeScore(PvPBattle battle, PlayerMobile player)
{
if (!Enabled || Player.IsEmpty)
{
return 0;
}
return Player.ComputeScore(battle, player);
}
public virtual bool Completed(PvPTeam team)
{
if (!Enabled || Team.IsEmpty)
{
return false;
}
return Team.Completed(team);
}
public virtual bool Completed(PvPBattle battle, PlayerMobile player)
{
if (!Enabled || Player.IsEmpty)
{
return false;
}
return Player.Completed(battle, player);
}
public virtual string GetStatus(PvPTeam team)
{
if (!Enabled || Team.IsEmpty)
{
return String.Empty;
}
return Team.GetStatus(team);
}
public virtual string GetStatus(PvPBattle battle, PlayerMobile player)
{
if (!Enabled || Player.IsEmpty)
{
return String.Empty;
}
return Player.GetStatus(battle, player);
}
public virtual void GetHtmlString(StringBuilder html)
{
if (!Enabled)
{
return;
}
var idx = html.Length;
var len = html.Length;
if (!Team.IsEmpty)
{
Team.GetHtmlString(html);
if (len < html.Length)
{
html.Insert(len, "Team Objectives\n".WrapUOHtmlColor(Color.LawnGreen, false));
}
}
len = html.Length;
if (!Player.IsEmpty)
{
Player.GetHtmlString(html);
if (len < html.Length)
{
html.Insert(len, "Player Objectives\n".WrapUOHtmlColor(Color.LawnGreen, false));
}
}
if (idx < html.Length)
{
html.Insert(idx, "Missions\n".WrapUOHtmlBig().WrapUOHtmlColor(Color.PaleGoldenrod, false));
html.Append(String.Empty.WrapUOHtmlColor(Color.White, false));
}
}
public virtual string ToHtmlString()
{
var html = new StringBuilder();
GetHtmlString(html);
return html.ToString();
}
public override string ToString()
{
return "Battle Missions";
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(Enabled);
writer.WriteBlock(w => w.WriteType(Team, (w1, t) => Team.Serialize(w1)));
writer.WriteBlock(w => w.WriteType(Player, (w1, t) => Player.Serialize(w1)));
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
Enabled = reader.ReadBool();
Team = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleObjectives>(r)) ?? new PvPBattleObjectives();
Player = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleObjectives>(r)) ?? new PvPBattleObjectives();
}
}
}

View File

@@ -0,0 +1,643 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Drawing;
using System.Text;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleObjectives : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public bool AllRequired { get; set; }
[CommandProperty(AutoPvP.Access)]
public long PointsTotal { get; set; }
[CommandProperty(AutoPvP.Access)]
public long PointsGained { get; set; }
[CommandProperty(AutoPvP.Access)]
public long PointsLost { get; set; }
[CommandProperty(AutoPvP.Access)]
public long Kills { get; set; }
[CommandProperty(AutoPvP.Access)]
public long Deaths { get; set; }
[CommandProperty(AutoPvP.Access)]
public long Resurrections { get; set; }
[CommandProperty(AutoPvP.Access)]
public long DamageTaken { get; set; }
[CommandProperty(AutoPvP.Access)]
public long DamageDone { get; set; }
[CommandProperty(AutoPvP.Access)]
public long HealingTaken { get; set; }
[CommandProperty(AutoPvP.Access)]
public long HealingDone { get; set; }
public virtual bool IsEmpty => PointsTotal + PointsGained + PointsLost
+ Kills + Deaths + Resurrections
+ DamageTaken + DamageDone
+ HealingTaken + HealingDone
<= 0;
public PvPBattleObjectives()
{
SetDefaults();
}
public PvPBattleObjectives(GenericReader reader)
: base(reader)
{ }
public override void Clear()
{
base.Clear();
SetDefaults();
}
public override void Reset()
{
base.Reset();
SetDefaults();
}
public virtual void SetDefaults()
{
AllRequired = false;
PointsTotal = 0;
PointsGained = 0;
PointsLost = 0;
Kills = 0;
Deaths = 0;
Resurrections = 0;
DamageTaken = 0;
DamageDone = 0;
HealingTaken = 0;
HealingDone = 0;
}
public double ComputeScorePotential(PvPTeam t)
{
double min = 0, max = 0, total = 0;
ComputeScore(t, ref min, ref max, ref total);
return total;
}
public double ComputeScore(PvPTeam t)
{
double min = 0, max = 0, total = 0;
return ComputeScore(t, ref min, ref max, ref total);
}
public virtual double ComputeScore(PvPTeam t, ref double min, ref double max, ref double total)
{
if (t == null || t.Deleted)
{
return 0;
}
double val, score = 0.0;
if (PointsTotal > 0)
{
score += val = Math.Min(1.0, t.GetTotalPoints() / (double)PointsTotal);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (PointsGained > 0)
{
score += val = Math.Min(1.0, t.GetTotalPointsGained() / (double)PointsGained);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (PointsLost > 0)
{
score += val = Math.Min(1.0, t.GetTotalPointsLost() / (double)PointsLost);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (Kills > 0)
{
score += val = Math.Min(1.0, t.GetTotalKills() / (double)Kills);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (Deaths > 0)
{
score += val = Math.Min(1.0, t.GetTotalDeaths() / (double)Deaths);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (Resurrections > 0)
{
score += val = Math.Min(1.0, t.GetTotalResurrections() / (double)Resurrections);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (DamageTaken > 0)
{
score += val = Math.Min(1.0, t.GetTotalDamageTaken() / (double)DamageTaken);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (DamageDone > 0)
{
score += val = Math.Min(1.0, t.GetTotalDamageDone() / (double)DamageDone);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (HealingTaken > 0)
{
score += val = Math.Min(1.0, t.GetTotalHealingTaken() / (double)HealingTaken);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (HealingDone > 0)
{
score += val = Math.Min(1.0, t.GetTotalHealingDone() / (double)HealingDone);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
return score;
}
public double ComputeScorePotential(PvPBattle b, PlayerMobile p)
{
double min = 0, max = 0, total = 0;
ComputeScore(b, p, ref min, ref max, ref total);
return total;
}
public double ComputeScore(PvPBattle b, PlayerMobile p)
{
double min = 0, max = 0, total = 0;
return ComputeScore(b, p, ref min, ref max, ref total);
}
public virtual double ComputeScore(PvPBattle b, PlayerMobile p, ref double min, ref double max, ref double total)
{
if (b == null || b.Deleted)
{
return 0;
}
if (p == null || p.Deleted)
{
return 0;
}
double val, score = 0.0;
if (PointsTotal > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.Points) / (double)PointsTotal);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (PointsGained > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.PointsGained) / (double)PointsGained);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (PointsLost > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.PointsLost) / (double)PointsLost);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (Kills > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.Kills) / (double)Kills);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (Deaths > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.Deaths) / (double)Deaths);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (Resurrections > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.Resurrections) / (double)Resurrections);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (DamageTaken > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.DamageTaken) / (double)DamageTaken);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (DamageDone > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.DamageDone) / (double)DamageDone);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (HealingTaken > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.HealingTaken) / (double)HealingTaken);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
if (HealingDone > 0)
{
score += val = Math.Min(1.0, b.GetStatistic(p, o => o.HealingDone) / (double)HealingDone);
min = Math.Min(min, val);
max = Math.Max(max, val);
++total;
}
return score;
}
public virtual bool Completed(PvPTeam t)
{
double min = 0, max = 0, total = 0;
var score = ComputeScore(t, ref min, ref max, ref total);
if (score <= 0 || max <= 0)
{
return false;
}
if (AllRequired)
{
return score >= total;
}
return max >= 1.0;
}
public virtual bool Completed(PvPBattle b, PlayerMobile p)
{
double min = 0, max = 0, total = 0;
var score = ComputeScore(b, p, ref min, ref max, ref total);
if (score <= 0 || total <= 0)
{
return false;
}
if (AllRequired)
{
return score >= total;
}
return max >= 1.0;
}
public virtual string GetStatus(PvPTeam t)
{
if (t == null || t.Deleted)
{
return String.Empty;
}
var lines = new StringBuilder();
if (PointsTotal > 0)
{
lines.AppendLine("Points Total: {0:#,0} / {1:#,0}", t.GetTotalPoints(), PointsTotal);
}
if (PointsGained > 0)
{
lines.AppendLine("Points Gained: {0:#,0} / {1:#,0}", t.GetTotalPointsGained(), PointsGained);
}
if (PointsLost > 0)
{
lines.AppendLine("Points Lost: {0:#,0} / {1:#,0}", t.GetTotalPointsLost(), PointsLost);
}
if (Kills > 0)
{
lines.AppendLine("Kills: {0:#,0} / {1:#,0}", t.GetTotalKills(), Kills);
}
if (Deaths > 0)
{
lines.AppendLine("Deaths: {0:#,0} / {1:#,0}", t.GetTotalDeaths(), Deaths);
}
if (Resurrections > 0)
{
lines.AppendLine("Resurrections: {0:#,0} / {1:#,0}", t.GetTotalResurrections(), Resurrections);
}
if (DamageTaken > 0)
{
lines.AppendLine("Damage Taken: {0:#,0} / {1:#,0}", t.GetTotalDamageTaken(), DamageTaken);
}
if (DamageDone > 0)
{
lines.AppendLine("Damage Done: {0:#,0} / {1:#,0}", t.GetTotalDamageDone(), DamageDone);
}
if (HealingTaken > 0)
{
lines.AppendLine("Healing Taken: {0:#,0} / {1:#,0}", t.GetTotalHealingTaken(), HealingTaken);
}
if (HealingDone > 0)
{
lines.AppendLine("Healing Done: {0:#,0} / {1:#,0}", t.GetTotalHealingDone(), HealingDone);
}
return lines.ToString();
}
public virtual string GetStatus(PvPBattle b, PlayerMobile p)
{
if (b == null || b.Deleted)
{
return String.Empty;
}
if (p == null || p.Deleted)
{
return String.Empty;
}
var lines = new StringBuilder();
if (PointsTotal > 0)
{
lines.AppendLine("Points Total: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.Points), PointsTotal);
}
if (PointsGained > 0)
{
lines.AppendLine("Points Gained: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.PointsGained), PointsGained);
}
if (PointsLost > 0)
{
lines.AppendLine("Points Lost: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.PointsLost), PointsLost);
}
if (Kills > 0)
{
lines.AppendLine("Kills: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.Kills), Kills);
}
if (Deaths > 0)
{
lines.AppendLine("Deaths: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.Deaths), Deaths);
}
if (Resurrections > 0)
{
lines.AppendLine("Resurrections: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.Resurrections), Resurrections);
}
if (DamageTaken > 0)
{
lines.AppendLine("Damage Taken: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.DamageTaken), DamageTaken);
}
if (DamageDone > 0)
{
lines.AppendLine("Damage Done: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.DamageDone), DamageDone);
}
if (HealingTaken > 0)
{
lines.AppendLine("Healing Taken: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.HealingTaken), HealingTaken);
}
if (HealingDone > 0)
{
lines.AppendLine("Healing Done: {0:#,0} / {1:#,0}", b.GetStatistic(p, o => o.HealingDone), HealingDone);
}
return lines.ToString();
}
public virtual void GetHtmlString(StringBuilder html)
{
var len = html.Length;
if (PointsTotal > 0)
{
html.AppendLine("Points Total: {0:#,0}", PointsTotal);
}
if (PointsGained > 0)
{
html.AppendLine("Points Gained: {0:#,0}", PointsGained);
}
if (PointsLost > 0)
{
html.AppendLine("Points Lost: {0:#,0}", PointsLost);
}
if (Kills > 0)
{
html.AppendLine("Kills: {0:#,0}", Kills);
}
if (Deaths > 0)
{
html.AppendLine("Deaths: {0:#,0}", Deaths);
}
if (Resurrections > 0)
{
html.AppendLine("Resurrections: {0:#,0}", Resurrections);
}
if (DamageTaken > 0)
{
html.AppendLine("Damage Taken: {0:#,0}", DamageTaken);
}
if (DamageDone > 0)
{
html.AppendLine("Damage Done: {0:#,0}", DamageDone);
}
if (HealingTaken > 0)
{
html.AppendLine("Healing Taken: {0:#,0}", HealingTaken);
}
if (HealingDone > 0)
{
html.AppendLine("Healing Done: {0:#,0}", HealingDone);
}
if (len < html.Length)
{
html.Insert(len, AllRequired ? "(Complete All)\n" : "(Complete Any)\n");
html.Insert(len, String.Empty.WrapUOHtmlColor(Color.PaleGoldenrod, false));
html.Append(String.Empty.WrapUOHtmlColor(Color.White, false));
}
}
public virtual string ToHtmlString()
{
var html = new StringBuilder();
GetHtmlString(html);
return html.ToString();
}
public override string ToString()
{
return "Mission Objectives";
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
writer.Write(PointsTotal);
writer.Write(PointsGained);
writer.Write(PointsLost);
writer.Write(Kills);
writer.Write(Deaths);
writer.Write(Resurrections);
writer.Write(DamageTaken);
writer.Write(DamageDone);
writer.Write(HealingTaken);
writer.Write(HealingDone);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
PointsTotal = reader.ReadLong();
PointsGained = reader.ReadLong();
PointsLost = reader.ReadLong();
Kills = reader.ReadLong();
Deaths = reader.ReadLong();
Resurrections = reader.ReadLong();
DamageTaken = reader.ReadLong();
DamageDone = reader.ReadLong();
HealingTaken = reader.ReadLong();
HealingDone = reader.ReadLong();
}
}
}

View File

@@ -0,0 +1,160 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleOptions : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleBroadcasts Broadcasts { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleLocations Locations { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleRestrictions Restrictions { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPRewards Rewards { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleRules Rules { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleSounds Sounds { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleSuddenDeath SuddenDeath { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleTiming Timing { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleWeather Weather { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleMissions Missions { get; set; }
public PvPBattleOptions()
{
Broadcasts = new PvPBattleBroadcasts();
Locations = new PvPBattleLocations();
Restrictions = new PvPBattleRestrictions();
Rewards = new PvPRewards();
Rules = new PvPBattleRules();
Sounds = new PvPBattleSounds();
SuddenDeath = new PvPBattleSuddenDeath();
Timing = new PvPBattleTiming();
Weather = new PvPBattleWeather();
Missions = new PvPBattleMissions();
}
public PvPBattleOptions(GenericReader reader)
: base(reader)
{ }
public override void Clear()
{
Broadcasts.Clear();
Locations.Clear();
Restrictions.Clear();
Rewards.Clear();
Rules.Clear();
Sounds.Clear();
SuddenDeath.Clear();
Timing.Clear();
Weather.Clear();
Missions.Clear();
}
public override void Reset()
{
Broadcasts.Reset();
Locations.Reset();
Restrictions.Reset();
Rewards.Reset();
Rules.Reset();
Sounds.Reset();
SuddenDeath.Reset();
Timing.Reset();
Weather.Reset();
Missions.Reset();
}
public override string ToString()
{
return "Advanced Options";
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(1);
switch (version)
{
case 1:
writer.WriteBlock(w => w.WriteType(Missions, t => Missions.Serialize(w)));
goto case 0;
case 0:
{
writer.WriteBlock(w => w.WriteType(Broadcasts, t => Broadcasts.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Locations, t => Locations.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Restrictions, t => Restrictions.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Rewards, t => Rewards.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Rules, t => Rules.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Sounds, t => Sounds.Serialize(w)));
writer.WriteBlock(w => w.WriteType(SuddenDeath, t => SuddenDeath.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Timing, t => Timing.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Weather, t => Weather.Serialize(w)));
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 1:
Missions = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleMissions>(r)) ?? new PvPBattleMissions();
goto case 0;
case 0:
{
Broadcasts = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleBroadcasts>(r)) ?? new PvPBattleBroadcasts();
Locations = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleLocations>(r)) ?? new PvPBattleLocations();
Restrictions = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleRestrictions>(r)) ?? new PvPBattleRestrictions();
Rewards = reader.ReadBlock(r => r.ReadTypeCreate<PvPRewards>(r)) ?? new PvPRewards();
Rules = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleRules>(r)) ?? new PvPBattleRules();
Sounds = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleSounds>(r)) ?? new PvPBattleSounds();
SuddenDeath = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleSuddenDeath>(r)) ?? new PvPBattleSuddenDeath();
Timing = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleTiming>(r)) ?? new PvPBattleTiming();
Weather = reader.ReadBlock(r => r.ReadTypeCreate<PvPBattleWeather>(r)) ?? new PvPBattleWeather();
}
break;
}
if (version < 1)
{
Missions = new PvPBattleMissions();
}
}
}
}

View File

@@ -0,0 +1,142 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public abstract class PvPBattleRestrictionsBase<TKey> : PropertyObject, IEnumerable<TKey>
{
public static void SetFlag(ref ulong flags, ulong f, bool v)
{
if (v)
{
flags |= f;
}
else
{
flags &= ~f;
}
}
public static bool GetFlag(ulong flags, ulong f)
{
return (flags & f) != 0;
}
private Dictionary<TKey, bool> _List = new Dictionary<TKey, bool>();
public virtual Dictionary<TKey, bool> List
{
get => _List;
set => _List = value ?? new Dictionary<TKey, bool>();
}
public bool this[TKey key] { get => IsRestricted(key); set => SetRestricted(key, value); }
public PvPBattleRestrictionsBase()
{
Invalidate();
}
public PvPBattleRestrictionsBase(GenericReader reader)
: base(reader)
{ }
public abstract void Invalidate();
public virtual void Invert()
{
_List.Keys.ForEach(t => _List[t] = !_List[t]);
}
public virtual void Reset(bool val)
{
_List.Keys.ForEach(t => _List[t] = val);
}
public virtual bool Remove(TKey key)
{
return _List.Remove(key);
}
public override void Reset()
{
Reset(false);
}
public override void Clear()
{
_List.Clear();
}
public virtual void SetRestricted(TKey key, bool val)
{
if (key != null)
{
_List[key] = val;
}
}
public virtual bool IsRestricted(TKey key)
{
return key != null && _List.ContainsKey(key) && _List[key];
}
public IEnumerator<TKey> GetEnumerator()
{
return _List.Keys.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
writer.WriteDictionary(_List, SerializeEntry);
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
_List = reader.ReadDictionary(DeserializeEntry);
break;
}
}
public abstract void SerializeEntry(GenericWriter writer, TKey key, bool val);
public abstract KeyValuePair<TKey, bool> DeserializeEntry(GenericReader reader);
}
}

View File

@@ -0,0 +1,149 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public class PvPBattleItemRestrictions : PvPBattleRestrictionsBase<Type>
{
private static readonly Type _TypeOf = typeof(Item);
private static Type FindType(string name, bool full = false, bool ignoreCase = true)
{
return Type.GetType(name, false, ignoreCase) ?? (full
? ScriptCompiler.FindTypeByFullName(name, ignoreCase)
: ScriptCompiler.FindTypeByName(name, ignoreCase));
}
[CommandProperty(AutoPvP.Access)]
public bool AllowNonExceptional { get; set; }
public PvPBattleItemRestrictions()
{
AllowNonExceptional = true;
}
public PvPBattleItemRestrictions(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Item Restrictions";
}
public override void Invalidate()
{ }
public virtual void SetRestricted(Item item, bool restrict)
{
if (item != null)
{
SetRestricted(item.GetType(), restrict);
}
}
public virtual void SetRestricted(string item, bool restrict)
{
if (!String.IsNullOrWhiteSpace(item))
{
SetRestricted(FindType(item), restrict);
}
}
public override void SetRestricted(Type key, bool val)
{
if (key == null)
{
return;
}
if (key.IsEqualOrChildOf(_TypeOf))
{
base.SetRestricted(key, val);
}
}
public virtual bool IsRestricted(Item item)
{
return item != null && IsRestricted(item.GetType());
}
public override bool IsRestricted(Type key)
{
if (key == null)
{
return false;
}
if (key.IsEqualOrChildOf(_TypeOf))
{
return base.IsRestricted(_TypeOf) || base.IsRestricted(key);
}
return false;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var v = writer.SetVersion(1);
if (v > 0)
{
var flags = 0UL;
SetFlag(ref flags, 0x1, AllowNonExceptional);
writer.Write(flags);
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var v = reader.GetVersion();
if (v > 0)
{
var flags = reader.ReadULong();
AllowNonExceptional = GetFlag(flags, 0x1);
}
else
{
AllowNonExceptional = true;
}
}
public override void SerializeEntry(GenericWriter writer, Type key, bool val)
{
writer.WriteType(key);
writer.Write(val);
}
public override KeyValuePair<Type, bool> DeserializeEntry(GenericReader reader)
{
var k = reader.ReadType();
var v = reader.ReadBool();
return new KeyValuePair<Type, bool>(k, v);
}
}
}

View File

@@ -0,0 +1,125 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
using Server.Mobiles;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public class PvPBattlePetRestrictions : PvPBattleRestrictionsBase<Type>
{
private static readonly Type _TypeOf = typeof(BaseCreature);
private static Type FindType(string name, bool full = false, bool ignoreCase = true)
{
return Type.GetType(name, false, ignoreCase) ?? (full
? ScriptCompiler.FindTypeByFullName(name, ignoreCase)
: ScriptCompiler.FindTypeByName(name, ignoreCase));
}
public PvPBattlePetRestrictions()
{ }
public PvPBattlePetRestrictions(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Pet Restrictions";
}
public override void Invalidate()
{ }
public virtual void SetRestricted(BaseCreature pet, bool restrict)
{
if (pet != null)
{
SetRestricted(pet.GetType(), restrict);
}
}
public virtual void SetRestricted(string pet, bool restrict)
{
if (!String.IsNullOrWhiteSpace(pet))
{
SetRestricted(FindType(pet), restrict);
}
}
public override void SetRestricted(Type key, bool val)
{
if (key == null)
{
return;
}
if (key.IsEqualOrChildOf(_TypeOf))
{
base.SetRestricted(key, val);
}
}
public virtual bool IsRestricted(BaseCreature pet)
{
return pet != null && IsRestricted(pet.GetType());
}
public override bool IsRestricted(Type key)
{
if (key == null)
{
return false;
}
if (key.IsEqualOrChildOf(_TypeOf))
{
return base.IsRestricted(_TypeOf) || base.IsRestricted(key);
}
return false;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
public override void SerializeEntry(GenericWriter writer, Type key, bool val)
{
writer.WriteType(key);
writer.Write(val);
}
public override KeyValuePair<Type, bool> DeserializeEntry(GenericReader reader)
{
var k = reader.ReadType();
var v = reader.ReadBool();
return new KeyValuePair<Type, bool>(k, v);
}
}
}

View File

@@ -0,0 +1,105 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleRestrictions : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleItemRestrictions Items { get; protected set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattlePetRestrictions Pets { get; protected set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleSkillRestrictions Skills { get; protected set; }
[CommandProperty(AutoPvP.Access)]
public virtual PvPBattleSpellRestrictions Spells { get; protected set; }
public PvPBattleRestrictions()
{
Items = new PvPBattleItemRestrictions();
Pets = new PvPBattlePetRestrictions();
Skills = new PvPBattleSkillRestrictions();
Spells = new PvPBattleSpellRestrictions();
}
public PvPBattleRestrictions(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Battle Restrictions";
}
public override void Clear()
{
Items.Clear();
Pets.Clear();
Skills.Clear();
Spells.Clear();
}
public override void Reset()
{
Items.Reset(false);
Pets.Reset(false);
Skills.Reset(false);
Spells.Reset(false);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.WriteBlock(w => w.WriteType(Items, t => Items.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Pets, t => Pets.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Skills, t => Skills.Serialize(w)));
writer.WriteBlock(w => w.WriteType(Spells, t => Spells.Serialize(w)));
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
{
reader.ReadBlock(r => Items = r.ReadTypeCreate<PvPBattleItemRestrictions>(r) ?? new PvPBattleItemRestrictions());
reader.ReadBlock(r => Pets = r.ReadTypeCreate<PvPBattlePetRestrictions>(r) ?? new PvPBattlePetRestrictions());
reader.ReadBlock(
r => Skills = r.ReadTypeCreate<PvPBattleSkillRestrictions>(r) ?? new PvPBattleSkillRestrictions());
reader.ReadBlock(
r => Spells = r.ReadTypeCreate<PvPBattleSpellRestrictions>(r) ?? new PvPBattleSpellRestrictions());
}
break;
}
}
}
}

View File

@@ -0,0 +1,142 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public class PvPBattleSkillRestrictions : PvPBattleRestrictionsBase<int>
{
private static readonly string[] _SkillNames = Enum.GetNames(typeof(SkillName));
private static int FindSkill(string name, bool ignoreCase = true)
{
return _SkillNames.IndexOf(
_SkillNames.FirstOrDefault(s => ignoreCase ? Insensitive.Equals(s, name) : String.Equals(s, name)));
}
public PvPBattleSkillRestrictions()
{ }
public PvPBattleSkillRestrictions(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Skill Restrictions";
}
public override void Invalidate()
{
foreach (var info in SkillInfo.Table)
{
SetRestricted(info, false);
}
}
public virtual void SetRestricted(Skill skill, bool restrict)
{
if (skill != null)
{
SetRestricted(skill.Info, restrict);
}
}
public virtual void SetRestricted(SkillInfo skill, bool restrict)
{
if (skill != null)
{
SetRestricted(skill.SkillID, restrict);
}
}
public virtual void SetRestricted(string skill, bool restrict)
{
if (!String.IsNullOrWhiteSpace(skill))
{
SetRestricted(FindSkill(skill), restrict);
}
}
public virtual void SetRestricted(SkillName skill, bool restrict)
{
SetRestricted((int)skill, restrict);
}
public override void SetRestricted(int skill, bool restrict)
{
if (skill >= 0)
{
base.SetRestricted(skill, restrict);
}
}
public virtual bool IsRestricted(Skill skill)
{
return skill != null && IsRestricted(skill.Info);
}
public virtual bool IsRestricted(SkillInfo skill)
{
return skill != null && IsRestricted(skill.SkillID);
}
public virtual bool IsRestricted(string skill)
{
return !String.IsNullOrEmpty(skill) && IsRestricted(FindSkill(skill));
}
public virtual bool IsRestricted(SkillName skill)
{
return IsRestricted((int)skill);
}
public override bool IsRestricted(int key)
{
return key >= 0 && base.IsRestricted(key);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
public override void SerializeEntry(GenericWriter writer, int key, bool val)
{
writer.Write(key);
writer.Write(val);
}
public override KeyValuePair<int, bool> DeserializeEntry(GenericReader reader)
{
var k = reader.ReadInt();
var v = reader.ReadBool();
return new KeyValuePair<int, bool>(k, v);
}
}
}

View File

@@ -0,0 +1,130 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using System.Collections.Generic;
using Server;
using Server.Spells;
#endregion
namespace VitaNex.Modules.AutoPvP
{
[PropertyObject]
public class PvPBattleSpellRestrictions : PvPBattleRestrictionsBase<Type>
{
private static readonly Type _TypeOf = typeof(Spell);
private static Type FindType(string name, bool full = false, bool ignoreCase = true)
{
return Type.GetType(name, false, ignoreCase) ?? (full
? ScriptCompiler.FindTypeByFullName(name, ignoreCase)
: ScriptCompiler.FindTypeByName(name, ignoreCase));
}
public PvPBattleSpellRestrictions()
{ }
public PvPBattleSpellRestrictions(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Spell Restrictions";
}
public override void Invalidate()
{
foreach (var t in SpellRegistry.Types)
{
SetRestricted(t, IsRestricted(t));
}
}
public virtual void SetRestricted(Spell spell, bool restrict)
{
if (spell != null)
{
SetRestricted(spell.GetType(), restrict);
}
}
public virtual void SetRestricted(string spell, bool restrict)
{
if (!String.IsNullOrWhiteSpace(spell))
{
SetRestricted(FindType(spell), restrict);
}
}
public override void SetRestricted(Type key, bool val)
{
if (key == null)
{
return;
}
if (key.IsEqualOrChildOf(_TypeOf))
{
base.SetRestricted(key, val);
}
}
public virtual bool IsRestricted(Spell spell)
{
return spell != null && IsRestricted(spell.GetType());
}
public override bool IsRestricted(Type key)
{
if (key == null)
{
return false;
}
if (key.IsEqualOrChildOf(_TypeOf))
{
return base.IsRestricted(_TypeOf) || base.IsRestricted(key);
}
return false;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.SetVersion(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.GetVersion();
}
public override void SerializeEntry(GenericWriter writer, Type key, bool val)
{
writer.WriteType(key);
writer.Write(val);
}
public override KeyValuePair<Type, bool> DeserializeEntry(GenericReader reader)
{
var k = reader.ReadType();
var v = reader.ReadBool();
return new KeyValuePair<Type, bool>(k, v);
}
}
}

View File

@@ -0,0 +1,242 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using System;
using Server;
using VitaNex.Reflection;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleRules : PropertyObject
{
private readonly object _CopyLock = new object();
private PropertyList<PvPBattleRules> _CopyStore;
[CommandProperty(AutoPvP.Access)]
public bool AllowSpeech { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool AllowBeneficial { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool AllowHarmful { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool AllowHousing { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool AllowSpawn { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanDie { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanHeal { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanBeDamaged { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanDamageOwnTeam { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanDamageEnemyTeam { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanHealOwnTeam { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanHealEnemyTeam { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool AllowPets { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanMount { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanFly { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanMountEthereal { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanMoveThrough { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanResurrect { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanUseStuckMenu { get; set; }
[CommandProperty(AutoPvP.Access)]
public bool CanEquip { get; set; }
public PvPBattleRules()
{
SetDefaults();
}
public PvPBattleRules(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Battle Rules";
}
public void SetDefaults()
{
AllowBeneficial = true;
AllowHarmful = true;
AllowHousing = false;
AllowPets = false;
AllowSpawn = false;
AllowSpeech = true;
CanBeDamaged = true;
CanDamageEnemyTeam = true;
CanDamageOwnTeam = false;
CanDie = false;
CanEquip = true;
CanFly = false;
CanHeal = true;
CanHealEnemyTeam = false;
CanHealOwnTeam = true;
CanMount = false;
CanMountEthereal = false;
CanMoveThrough = false;
CanResurrect = false;
CanUseStuckMenu = false;
}
public override void Clear()
{
SetDefaults();
}
public override void Reset()
{
SetDefaults();
}
public void CopyFrom(PvPBattleRules source)
{
source.CopyTo(this);
}
public void CopyTo(PvPBattleRules target)
{
lock (_CopyLock)
{
if (_CopyStore == null)
{
_CopyStore = new PropertyList<PvPBattleRules>
{
Filter = p => p.Name != "InvokeReset" && p.Name != "InvokeClear" && p.PropertyType.IsEqual<bool>()
};
}
_CopyStore.Deserialize(this);
_CopyStore.Serialize(target);
_CopyStore.Clear();
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(3);
switch (version)
{
case 3:
writer.Write(CanEquip);
goto case 2;
case 2:
writer.Write(CanMoveThrough);
goto case 1;
case 1:
writer.Write(CanFly);
goto case 0;
case 0:
{
writer.Write(AllowBeneficial);
writer.Write(AllowHarmful);
writer.Write(AllowHousing);
writer.Write(AllowPets);
writer.Write(AllowSpawn);
writer.Write(AllowSpeech);
writer.Write(CanBeDamaged);
writer.Write(CanDamageEnemyTeam);
writer.Write(CanDamageOwnTeam);
writer.Write(CanDie);
writer.Write(CanHeal);
writer.Write(CanHealEnemyTeam);
writer.Write(CanHealOwnTeam);
writer.Write(CanMount);
writer.Write(CanMountEthereal);
writer.Write(CanResurrect);
writer.Write(CanUseStuckMenu);
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
SetDefaults();
var version = reader.GetVersion();
switch (version)
{
case 3:
CanEquip = reader.ReadBool();
goto case 2;
case 2:
CanMoveThrough = reader.ReadBool();
goto case 1;
case 1:
CanFly = reader.ReadBool();
goto case 0;
case 0:
{
AllowBeneficial = reader.ReadBool();
AllowHarmful = reader.ReadBool();
AllowHousing = reader.ReadBool();
AllowPets = reader.ReadBool();
AllowSpawn = reader.ReadBool();
AllowSpeech = reader.ReadBool();
CanBeDamaged = reader.ReadBool();
CanDamageEnemyTeam = reader.ReadBool();
CanDamageOwnTeam = reader.ReadBool();
CanDie = reader.ReadBool();
CanHeal = reader.ReadBool();
CanHealEnemyTeam = reader.ReadBool();
CanHealOwnTeam = reader.ReadBool();
CanMount = reader.ReadBool();
CanMountEthereal = reader.ReadBool();
CanResurrect = reader.ReadBool();
CanUseStuckMenu = reader.ReadBool();
}
break;
}
}
}
}

View File

@@ -0,0 +1,177 @@
#region Header
// _,-'/-'/
// . __,-; ,'( '/
// \. `-.__`-._`:_,-._ _ , . ``
// `:-._,------' ` _,`--` -: `_ , ` ,' :
// `---..__,,--' (C) 2023 ` -'. -'
// # Vita-Nex [http://core.vita-nex.com] #
// {o)xxx|===============- # -===============|xxx(o}
// # #
#endregion
#region References
using Server;
#endregion
namespace VitaNex.Modules.AutoPvP
{
public class PvPBattleSounds : PropertyObject
{
[CommandProperty(AutoPvP.Access)]
public virtual bool Enabled { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int InviteSend { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int InviteAccept { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int InviteCancel { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int QueueJoin { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int QueueLeave { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int Teleport { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int BattleOpened { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int BattlePreparing { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int BattleStarted { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int BattleEnded { get; set; }
[CommandProperty(AutoPvP.Access)]
public virtual int BattleCanceled { get; set; }
public PvPBattleSounds()
{
SetDefaults();
}
public PvPBattleSounds(GenericReader reader)
: base(reader)
{ }
public override string ToString()
{
return "Battle Sounds";
}
public override void Clear()
{
Enabled = false;
InviteSend = -1;
InviteAccept = -1;
InviteCancel = -1;
QueueJoin = -1;
QueueLeave = -1;
Teleport = -1;
BattleOpened = -1;
BattlePreparing = -1;
BattleStarted = -1;
BattleEnded = -1;
BattleCanceled = -1;
}
public override void Reset()
{
SetDefaults();
}
public virtual void SetDefaults()
{
Enabled = true;
InviteSend = 0xF0;
InviteAccept = 0x5B5;
InviteCancel = 0x5B4;
QueueJoin = 0x664;
QueueLeave = 0x51C;
Teleport = 0x029;
BattleOpened = 0x2E8;
BattlePreparing = 0x2E8;
BattleStarted = 0x2E9;
BattleEnded = 0x2EA;
BattleCanceled = 0x2EA;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
var version = writer.SetVersion(0);
switch (version)
{
case 0:
{
writer.Write(Enabled);
writer.Write(InviteSend);
writer.Write(InviteAccept);
writer.Write(InviteCancel);
writer.Write(QueueJoin);
writer.Write(QueueLeave);
writer.Write(Teleport);
writer.Write(BattleOpened);
writer.Write(BattlePreparing);
writer.Write(BattleStarted);
writer.Write(BattleEnded);
writer.Write(BattleCanceled);
}
break;
}
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
var version = reader.GetVersion();
switch (version)
{
case 0:
{
Enabled = reader.ReadBool();
InviteSend = reader.ReadInt();
InviteAccept = reader.ReadInt();
InviteCancel = reader.ReadInt();
QueueJoin = reader.ReadInt();
QueueLeave = reader.ReadInt();
Teleport = reader.ReadInt();
BattleOpened = reader.ReadInt();
BattlePreparing = reader.ReadInt();
BattleStarted = reader.ReadInt();
BattleEnded = reader.ReadInt();
BattleCanceled = reader.ReadInt();
}
break;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More