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,760 @@
using Server;
using Server.Engines.CityLoyalty;
using Server.Gumps;
using Server.ContextMenus;
using Server.Guilds;
using Server.Mobiles;
using Server.Engines.Quests;
using Server.Commands;
using Server.Engines.Khaldun;
using Server.Items;
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
namespace Server.Services.TownCryer
{
public static class TownCryerSystem
{
public static bool Enabled { get; set; }
public static readonly int MaxNewsEntries = 100;
public static readonly int MaxPerGuildEntries = 1;
public static readonly int MaxPerCityGoverrnorEntries = 5;
public static readonly int MaxEMEntries = 15;
public static readonly int MinGuildMemberCount = 20;
public static bool UsePreloadedMessages = false;
public static AccessLevel EMAccess = AccessLevel.Counselor;
public static readonly string EMEventsPage = "https://uo.com/live-events/";
private static string PreLoadedPath = "Data/PreLoadedTC.xml";
public static List<TownCryerGreetingEntry> GreetingsEntries { get; private set; }
//public static List<TextDefinition> GreetingsEntries { get; private set; }
public static List<TownCryerNewsEntry> NewsEntries { get; private set; }
public static List<TownCryerModeratorEntry> ModeratorEntries { get; private set; }
public static List<TownCryerCityEntry> CityEntries { get; private set; }
public static List<TownCryerGuildEntry> GuildEntries { get; private set; }
public static List<PlayerMobile> TownCryerExempt { get; private set; }
public static Dictionary<Mobile, DateTime> MysteriousPotionEffects { get; private set; }
public static Timer Timer { get; private set; }
public static bool NewGreeting { get; private set; }
public static void Configure()
{
GreetingsEntries = new List<TownCryerGreetingEntry>();
ModeratorEntries = new List<TownCryerModeratorEntry>();
CityEntries = new List<TownCryerCityEntry>();
GuildEntries = new List<TownCryerGuildEntry>();
NewsEntries = new List<TownCryerNewsEntry>();
TownCryerExempt = new List<PlayerMobile>();
GreetingsEntries.Add(new TownCryerGreetingEntry(1158955));
/*<center>Rising Tide</center><br><br>The Seas call to us once more! A powerful pirate called Hook has
* taken control of the Guild, an organization of cutthroats and brigands engaged in high seas piracy!
* Great peril stands in the way of those brave enough to challenge Hook's vile plan - read the latest
* headlines in the Town Cryer to learn more!<br><br>The realms tinkers have been busy at work and are
* proud to announce advancements in ship to ship ballistics! The cannon firing process has been streamlined
* - from crafting supplies through loading the cannons and lighting the fuse! FIRE IN THE HOLE!
* <br><br>Whether you are celebrating your first year in Britannia or your 22nd we want to extend a
* very special thank you to our veteran players! New veteran rewards are available! New MONSTER STATUETTES
* featuring Krampus, Khal Ankur, and the Krampus Minion, are available! Decorate your home with the WATER
* WHEEL and personalize your clothes with the EMBROIDERY TOOL. Every crafter will want to get their hands
* on the REPAIR BENCH and TINKER BENCH!*/
GreetingsEntries.Add(new TownCryerGreetingEntry(1158757));
/*Fall is approaching and strangeness is afoot in Britannia!<br><br>Britannians are looking skyward in
* search of constellations and other celestial objects using the new telescope!<br><br>The pumpkin patches
* of Britannia once again bearing fruit as the Grimms hold their carveable pumpkins close!<br><br>Visit a
* cemetery to battle against the Butchers and carve new Jack o' Lantern designs!<br><br>Beware the
* skeletons! Zombie skeletons roam the cemeteries!<br><br>Trick or Treat? Shopkeepers and citizens
* alike have new treats to share!<br><br>Strange events worth investigating? A new article from the
* Town Cryer on the new Royal Britannian Guard Detective Branch!*/
GreetingsEntries.Add(new TownCryerGreetingEntry(1158388));
/* Greetings, Avatar!<br><br>Welcome to Britannia! Whether these are your first steps or you are a
* seasoned veteran King Blackthorn welcomes you! The realm is bustling with opportunities for adventure!
* TownCryers can be visited at all banks and points of interest to learn about the latest goings on in
* the realm. Many guilds are actively recruiting members, so be sure to check the Town Cryer guild
* section for the latest recruitment events. <br><br>We wish you the best of luck in your
* <A HREF="https://uo.com/endless-journey/">Endless Journey</A>*/
LoadPreloadedMessages();
}
public static void Initialize()
{
if (Enabled)
{
EventSink.Login += OnLogin;
NewsEntries.Add(new TownCryerNewsEntry(1159262, 1159263, 0x64E, null, "https://uo.com/wiki/ultima-online-wiki/seasonal-events/halloween-treasures-of-the-sea/")); // Forsaken Foes
NewsEntries.Add(new TownCryerNewsEntry(1158944, 1158945, 0x9CEA, null, "https://uo.com/wiki/ultima-online-wiki/combat/pvm-player-versus-monster/rising-tide/")); // Rising Tide
NewsEntries.Add(new TownCryerNewsEntry(1158552, 1158553, 0x6CE, typeof(GoingGumshoeQuest), null)); // Going Gumshoe
NewsEntries.Add(new TownCryerNewsEntry(1158095, 1158097, 0x61E, null, "https://uo.com/")); // Britain Commons
NewsEntries.Add(new TownCryerNewsEntry(1158089, 1158091, 0x60F, null, "https://uo.com/wiki/ultima-online-wiki/gameplay/npc-commercial-transactions/clean-up-britannia/")); // Cleanup Britannia
NewsEntries.Add(new TownCryerNewsEntry(1158098, 1158100, 0x615, null, "https://uo.com/wiki/ultima-online-wiki/gameplay/crafting/bulk-orders/")); // New Bulk Orders
NewsEntries.Add(new TownCryerNewsEntry(1158101, 1158103, 0x616, null, "https://uo.com/wiki/ultima-online-wiki/a-summary-for-returning-players/weapons-armor-and-loot-revamps-2016/")); // 2016 Loot Revamps
NewsEntries.Add(new TownCryerNewsEntry(1158116, 1158118, 0x64F, null, "https://uo.com/wiki/ultima-online-wiki/gameplay/the-virtues/")); // Virtues
NewsEntries.Add(new TownCryerNewsEntry(1158083, 1158085, 0x617, typeof(TamingPetQuest), "https://uo.com/wiki/ultima-online-wiki/skills/animal-taming/animal-training/")); // Animal Training
NewsEntries.Add(new TownCryerNewsEntry(1158086, 1158088, 0x61D, typeof(ExploringTheDeepQuest), null));
NewsEntries.Add(new TownCryerNewsEntry(1158092, 1158094, 0x651, typeof(HuntmastersChallengeQuest), "https://uo.com/wiki/ultima-online-wiki/gameplay/huntmasters-challenge/")); // Huntsmaster Challenge
NewsEntries.Add(new TownCryerNewsEntry(1158104, 1158106, 0x61C, typeof(PaladinsOfTrinsic), "https://uo.com/wiki/ultima-online-wiki/world/dungeons/dungeon-shame/")); // New Shame
NewsEntries.Add(new TownCryerNewsEntry(1158107, 1158109, 0x61A, typeof(RightingWrongQuest), "https://uo.com/wiki/ultima-online-wiki/world/dungeons/dungeon-wrong/")); // New Wrong
if (TreasureMapInfo.NewSystem)
{
NewsEntries.Add(new TownCryerNewsEntry(1158113, 1158115, 0x64C, typeof(BuriedRichesQuest), "https://uo.com/wiki/ultima-online-wiki/gameplay/treasure-maps/")); // New TMaps
}
NewsEntries.Add(new TownCryerNewsEntry(1158119, 1158121, 0x64D, typeof(APleaFromMinocQuest), "https://uo.com/wiki/ultima-online-wiki/world/dungeons/dungeon-covetous/")); // New Covetous
NewsEntries.Add(new TownCryerNewsEntry(1158110, 1158112, 0x64E, typeof(AVisitToCastleBlackthornQuest), "https://uo.com/wiki/ultima-online-wiki/items/artifacts-castle-blackthorn/")); // Castle Blackthorn
NewsEntries.Add(new TownCryerNewsEntry(1158122, 1158124, 0x650, typeof(WishesOfTheWispQuest), "https://uo.com/wiki/ultima-online-wiki/world/dungeons/dungeon-despise-trammel/")); // New Despise
// New greeting, resets all TC hiding
if (NewGreeting)
{
TownCryerExempt.Clear();
}
if (UsePreloadedMessages)
{
CommandSystem.Register("ReloadTCGreetings", AccessLevel.Administrator, Reload_OnCommand);
}
}
}
public static bool IsExempt(Mobile m)
{
return m is PlayerMobile && TownCryerExempt.Contains((PlayerMobile)m);
}
public static void AddExempt(PlayerMobile pm)
{
if (!TownCryerExempt.Contains(pm))
{
TownCryerExempt.Add(pm);
}
}
public static void AddEntry(TownCryerModeratorEntry entry)
{
ModeratorEntries.Add(entry);
CheckTimer();
}
public static void AddEntry(TownCryerCityEntry entry)
{
CityEntries.Add(entry);
CheckTimer();
}
public static void AddEntry(TownCryerGuildEntry entry)
{
GuildEntries.Add(entry);
CheckTimer();
entry.GetExpiration();
}
public static void AddEntry(TownCryerGreetingEntry entry)
{
GreetingsEntries.Add(entry);
CheckTimer();
}
public static void CompleteQuest(PlayerMobile pm, BaseQuest quest)
{
BaseGump.SendGump(new TownCrierQuestCompleteGump(pm, quest));
}
public static void CompleteQuest(PlayerMobile pm, object title, object body, int gumpID)
{
BaseGump.SendGump(new TownCrierQuestCompleteGump(pm, title, body, gumpID));
}
public static void OnLogin(LoginEventArgs e)
{
if (Enabled && e.Mobile is PlayerMobile && !IsExempt(e.Mobile))
{
Timer.DelayCall<PlayerMobile>(TimeSpan.FromSeconds(1), player =>
{
if (HasCustomEntries())
{
BaseGump.SendGump(new TownCryerGreetingsGump(player, null));
}
else
{
IPooledEnumerable eable = player.Map.GetMobilesInRange(player.Location, 25);
foreach (Mobile m in eable)
{
if (m is TownCrier)
{
BaseGump.SendGump(new TownCryerGreetingsGump(player, (TownCrier)m));
break;
}
}
eable.Free();
}
}, (PlayerMobile)e.Mobile);
}
}
public static int CityEntryCount(City city)
{
return CityEntries.Where(x => x.City == city).Count();
}
public static bool HasGuildEntry(Guild g)
{
if (g == null)
return false;
return GuildEntries.Any(x => x.Guild == g);
}
public static bool HasCustomEntries()
{
return GreetingsEntries.Any(x => x.Saves || x.Expires != DateTime.MinValue);
}
public static void CheckTimer()
{
if (ModeratorEntries.Count > 0 ||
CityEntries.Count > 0 ||
GuildEntries.Count > 0 ||
GreetingsEntries.Any(e => e.Expires != DateTime.MinValue) ||
MysteriousPotionEffects != null)
{
if (Timer == null || !Timer.Running)
{
Timer = Timer.DelayCall(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5), CheckExpiredEntries);
Timer.Priority = TimerPriority.OneMinute;
}
}
else if (Timer != null)
{
Timer.Stop();
Timer = null;
}
}
public static void CheckExpiredEntries()
{
for (int i = GreetingsEntries.Count - 1; i >= 0; i--)
{
if (GreetingsEntries[i].Expires != DateTime.MinValue && GreetingsEntries[i].Expired)
GreetingsEntries.RemoveAt(i);
}
for (int i = ModeratorEntries.Count - 1; i >= 0; i--)
{
if (ModeratorEntries[i].Expired)
ModeratorEntries.RemoveAt(i);
}
for (int i = CityEntries.Count - 1; i >= 0; i--)
{
if (CityEntries[i].Expired)
CityEntries.RemoveAt(i);
}
for (int i = GuildEntries.Count - 1; i >= 0; i--)
{
if (GuildEntries[i].Expired)
GuildEntries.RemoveAt(i);
}
if (MysteriousPotionEffects != null)
{
var list = new List<Mobile>(MysteriousPotionEffects.Keys);
foreach (var m in list)
{
if (MysteriousPotionEffects != null && MysteriousPotionEffects.ContainsKey(m) && MysteriousPotionEffects[m] < DateTime.UtcNow)
{
MysteriousPotionEffects.Remove(m);
if (MysteriousPotionEffects.Count == 0)
{
MysteriousPotionEffects = null;
}
}
}
ColUtility.Free(list);
}
CheckTimer();
}
public static bool IsGovernor(PlayerMobile pm, CityLoyaltySystem system)
{
return system != null && system.Governor == pm;
}
public static void GetContextMenus(TownCrier tc, Mobile from, List<ContextMenuEntry> list)
{
if (from is PlayerMobile)
{
var pm = from as PlayerMobile;
if (pm.AccessLevel >= EMAccess)
{
list.Add(new AddGreetingEntry(tc));
list.Add(new UpdateEMEntry(tc));
}
var system = CityLoyaltySystem.GetCitizenship(pm, false);
if (IsGovernor(pm, system))
{
list.Add(new UpdateCityEntry(tc, system.City));
}
Guild g = pm.Guild as Guild;
if (g != null && pm.GuildRank != null && pm.GuildRank.Rank >= 3 && g.Leader == pm && (pm.AccessLevel > AccessLevel.Player || g.Members.Count >= MinGuildMemberCount))
{
list.Add(new UpdateGuildEntry(from, tc));
}
}
}
public static int GetCityLoc(City city)
{
switch (city)
{
default:
case City.Britain: return 1158043;
case City.Jhelom: return 1158044;
case City.Minoc: return 1158045;
case City.Moonglow: return 1158046;
case City.NewMagincia: return 1158047;
case City.SkaraBrae: return 1158048;
case City.Trinsic: return 1158049;
case City.Vesper: return 1158050;
case City.Yew: return 1158051;
}
}
public static bool UnderMysteriousPotionEffects(Mobile m, bool checkQuest = false)
{
return
MysteriousPotionEffects != null && MysteriousPotionEffects.ContainsKey(m) && MysteriousPotionEffects[m] > DateTime.UtcNow &&
(!checkQuest || (m is PlayerMobile && QuestHelper.HasQuest<AForcedSacraficeQuest2>((PlayerMobile)m)));
}
public static void AddMysteriousPotionEffects(Mobile m)
{
if (MysteriousPotionEffects == null)
{
MysteriousPotionEffects = new Dictionary<Mobile, DateTime>();
}
MysteriousPotionEffects[m] = DateTime.UtcNow + TimeSpan.FromDays(3);
CheckTimer();
}
#region Pre-Loaded
private static void LoadPreloadedMessages()
{
if (!Enabled || !UsePreloadedMessages)
return;
if (File.Exists(PreLoadedPath))
{
XmlDocument doc = new XmlDocument();
Utility.WriteConsoleColor(ConsoleColor.Cyan, "*** Loading Pre-Loaded Town Crier Messages...");
try
{
doc.Load(PreLoadedPath);
}
catch (Exception e)
{
Console.WriteLine(e);
Utility.WriteConsoleColor(ConsoleColor.Cyan, "...FAILED! ***");
return;
}
XmlElement root = doc["preloadedTC"];
int good = 0;
int expired = 0;
int errors = 0;
if (root != null)
{
int index = 0;
foreach (XmlElement reg in root.GetElementsByTagName("message"))
{
string title = Utility.GetText(reg["title"], null);
string body = Utility.GetText(reg["body"], null);
DateTime created = GetDateTime(Utility.GetText(reg["created"], null));
DateTime expires = GetDateTime(Utility.GetText(reg["expires"], null));
string link = Utility.GetText(reg["link"], null);
string linktext = Utility.GetText(reg["linktext"], null);
if (title == null)
{
ErrorToConsole("Invalid title", index);
errors++;
}
else if (body == null)
{
ErrorToConsole("Invalid body", index);
errors++;
}
else if (created == DateTime.MinValue)
{
ErrorToConsole("Invalid creation time", index);
errors++;
}
else if (expires > DateTime.Now || expires == DateTime.MinValue)
{
var entry = new TownCryerGreetingEntry(title, body, -1, link, linktext);
entry.PreLoaded = true;
entry.Created = created;
if (expires > created)
{
entry.Expires = expires;
}
TownCryerSystem.AddEntry(entry);
good++;
}
else
{
ErrorToConsole("Expired message", index);
expired++;
}
index++;
}
}
if (expired > 0 || errors > 0)
{
Utility.WriteConsoleColor(ConsoleColor.Cyan, "...Complete! Loaded {0} Pre-Loaded Messages. {1} expired messages and {2} erroneous messages not loaded! ***", good, expired, errors);
}
else
{
Utility.WriteConsoleColor(ConsoleColor.Cyan, "...Complete! Loaded {0} Pre-Loaded Messages. ***", good);
}
}
}
public static void ErrorToConsole(string type, int index)
{
Utility.WriteConsoleColor(ConsoleColor.Red, "[TC Pre-Loaded Message]: {0} for pre-loaded Message #{1}", type, index.ToString());
}
public static DateTime GetDateTime(string text)
{
DateTime datetime = DateTime.MinValue;
try
{
datetime = DateTime.Parse(text, CultureInfo.CreateSpecificCulture("en-US"));
}
catch
{
}
return datetime;
}
[Usage("ReloadTCGreetings")]
[Description("Reloads Pre-Loaded Town Cryer Messages. This enables changes to be made to the PreLoadedTC.xml and show in game without a server restart.")]
public static void Reload_OnCommand(CommandEventArgs e)
{
bool clear = false;
GreetingsEntries.IterateReverse(entry =>
{
if (entry.PreLoaded)
{
GreetingsEntries.Remove(entry);
if (!clear)
clear = true;
}
});
LoadPreloadedMessages();
if (clear)
{
TownCryerExempt.Clear();
}
e.Mobile.SendMessage("Pre-Loaded TC messages re-loaded from {0}!", PreLoadedPath);
}
#endregion
public static void Save(GenericWriter writer)
{
writer.Write(1);
writer.Write(GreetingsEntries.Count);
writer.Write(TownCryerExempt.Count);
foreach (var pm in TownCryerExempt)
writer.Write(pm);
writer.Write(GreetingsEntries.Where(x => x.Saves).Count());
foreach (var e in GreetingsEntries.Where(x => x.Saves))
e.Serialize(writer);
writer.Write(ModeratorEntries.Count);
foreach (var e in ModeratorEntries)
e.Serialize(writer);
writer.Write(CityEntries.Count);
foreach (var e in CityEntries)
e.Serialize(writer);
writer.Write(GuildEntries.Count);
foreach (var e in GuildEntries)
e.Serialize(writer);
writer.Write(MysteriousPotionEffects != null ? MysteriousPotionEffects.Count : 0);
if (MysteriousPotionEffects != null)
{
foreach (var kvp in MysteriousPotionEffects)
{
writer.Write(kvp.Key);
writer.Write(kvp.Value);
}
}
}
public static void Load(GenericReader reader)
{
int version = reader.ReadInt();
int greetingsCount = 0;
switch (version)
{
case 1:
greetingsCount = reader.ReadInt();
int count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
var pm = reader.ReadMobile() as PlayerMobile;
if (pm != null)
{
AddExempt(pm);
}
}
count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
var entry = new TownCryerGreetingEntry(reader);
if (!entry.Expired)
{
GreetingsEntries.Add(entry);
}
}
goto case 0;
case 0:
count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
var entry = new TownCryerModeratorEntry(reader);
if (!entry.Expired)
{
ModeratorEntries.Add(entry);
}
}
count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
var entry = new TownCryerCityEntry(reader);
if (!entry.Expired)
{
CityEntries.Add(entry);
}
}
count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
var entry = new TownCryerGuildEntry(reader);
if (!entry.Expired)
{
GuildEntries.Add(entry);
}
}
count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
Mobile m = reader.ReadMobile();
DateTime dt = reader.ReadDateTime();
if (m != null)
{
if (MysteriousPotionEffects == null)
MysteriousPotionEffects = new Dictionary<Mobile, DateTime>();
MysteriousPotionEffects[m] = dt;
}
}
break;
}
if (greetingsCount < GreetingsEntries.Count)
{
NewGreeting = true;
}
CheckTimer();
}
}
public class AddGreetingEntry : ContextMenuEntry
{
public TownCrier Cryer { get; set; }
public AddGreetingEntry(TownCrier cryer)
: base(1011405, 3) // Change Greeting
{
Cryer = cryer;
}
public override void OnClick()
{
if (Owner.From is PlayerMobile && Owner.From.AccessLevel >= AccessLevel.GameMaster)
{
//BaseGump.SendGump(new CreateGreetingEntryGump((PlayerMobile)Owner.From, Cryer));
BaseGump.SendGump(new TownCryerGreetingsGump((PlayerMobile)Owner.From, Cryer));
}
}
}
public class UpdateEMEntry : ContextMenuEntry
{
public TownCrier Cryer { get; set; }
public UpdateEMEntry(TownCrier cryer)
: base(1158022, 3) // Update EM Town Crier
{
Cryer = cryer;
Enabled = TownCryerSystem.ModeratorEntries.Count < TownCryerSystem.MaxEMEntries;
}
public override void OnClick()
{
if (Owner.From is PlayerMobile)
{
if (TownCryerSystem.ModeratorEntries.Count < TownCryerSystem.MaxEMEntries)
{
BaseGump.SendGump(new CreateEMEntryGump((PlayerMobile)Owner.From, Cryer));
}
else
{
Owner.From.SendLocalizedMessage(1158038); // You have reached the maximum entry count. Please remove some and try again.
}
}
}
}
public class UpdateCityEntry : ContextMenuEntry
{
public City City { get; set; }
public TownCrier Cryer { get; set; }
public UpdateCityEntry(TownCrier cryer, City city)
: base(1158023, 3) // Update City Town Crier
{
Cryer = cryer;
City = city;
}
public override void OnClick()
{
if (Owner.From is PlayerMobile)
{
var pm = Owner.From as PlayerMobile;
var system = CityLoyaltySystem.GetCitizenship(pm, false);
if (TownCryerSystem.IsGovernor(pm, system))
{
if (TownCryerSystem.CityEntryCount(system.City) < TownCryerSystem.MaxPerCityGoverrnorEntries)
{
BaseGump.SendGump(new CreateCityEntryGump(pm, Cryer, system.City));
}
else
{
pm.SendLocalizedMessage(1158038); // You have reached the maximum entry count. Please remove some and try again.
}
}
}
}
}
public class UpdateGuildEntry : ContextMenuEntry
{
public TownCrier Cryer { get; set; }
public UpdateGuildEntry(Mobile from, TownCrier cryer)
: base(1158024, 3) // Update Guild Town Crier
{
Cryer = cryer;
Enabled = from.Guild != null && !TownCryerSystem.HasGuildEntry(from.Guild as Guild);
}
public override void OnClick()
{
PlayerMobile pm = Owner.From as PlayerMobile;
if(pm != null)
{
Guild g = pm.Guild as Guild;
if (g != null && pm.GuildRank != null && pm.GuildRank.Rank >= 3 && (pm.AccessLevel > AccessLevel.Player || g.Members.Count >= TownCryerSystem.MinGuildMemberCount))
{
if (TownCryerSystem.HasGuildEntry(g))
{
Owner.From.SendLocalizedMessage(1158038); // You have reached the maximum entry count. Please remove some and try again.
}
else
{
BaseGump.SendGump(new CreateGuildEntryGump(pm, Cryer));
}
}
else
{
pm.SendLocalizedMessage(1158025); // Only Guild Leaders and Warlords of guilds with at least 20 members may post in the Town Cryer.
}
}
}
}
}