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

3533
Scripts/Misc/AOS.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
using System;
using Server.Accounting;
namespace Server.Misc
{
public class AccountPrompt
{
public static void Initialize()
{
if (Accounts.Count == 0 && !Core.Service)
{
Console.WriteLine("This server has no accounts.");
Console.Write("Do you want to create the owner account now? (y/n)");
string key = Console.ReadLine();
if (key.ToUpper() == "Y")
{
Console.WriteLine();
Console.Write("Username: ");
string username = Console.ReadLine();
Console.Write("Password: ");
string password = Console.ReadLine();
Account a = new Account(username, password);
a.AccessLevel = AccessLevel.Owner;
Console.WriteLine("Account created.");
}
else
{
Console.WriteLine();
Console.WriteLine("Account not created.");
}
}
}
}
}

152
Scripts/Misc/Aggression.cs Normal file
View File

@@ -0,0 +1,152 @@
using System;
using System.Linq;
using System.Collections.Generic;
using Server.Network;
using Server.Mobiles;
namespace Server.Misc
{
public class Aggression
{
private static readonly TimeSpan Delay = TimeSpan.FromMinutes(2.0);
private const string AggressorFormat = "You are attacking {0}!";
private const string AggressedFormat = "{0} is attacking you!";
private const int Hue = 0x22;
public static TimeSpan CombatHeatDelay { get { return Delay; } }
public static void Initialize()
{
EventSink.AggressiveAction += EventSink_AggressiveAction;
EventSink.PlayerDeath += EventSink_PlayerDeath;
EventSink.CreatureDeath += EventSink_CreatureDeath;
}
public static void EventSink_AggressiveAction(AggressiveActionEventArgs e)
{
Mobile aggressor = e.Aggressor;
Mobile aggressed = e.Aggressed;
if (!aggressor.Player || !aggressed.Player)
return;
if (!CheckAggressions(aggressor, aggressed))
{
aggressor.LocalOverheadMessage(MessageType.Regular, Hue, true, String.Format(AggressorFormat, aggressed.Name));
aggressed.LocalOverheadMessage(MessageType.Regular, Hue, true, String.Format(AggressedFormat, aggressor.Name));
}
BuffInfo.AddBuff(aggressor, new BuffInfo(BuffIcon.HeatOfBattleStatus, 1153801, 1153827, Delay, aggressor, true));
BuffInfo.AddBuff(aggressed, new BuffInfo(BuffIcon.HeatOfBattleStatus, 1153801, 1153827, Delay, aggressed, true));
}
public static void EventSink_PlayerDeath(PlayerDeathEventArgs e)
{
var killed = e.Mobile;
foreach (var m in killed.Aggressed.Select(m => m.Defender))
{
CheckCombat(m);
}
foreach (var m in killed.Aggressors.Select(x => x.Attacker))
{
CheckCombat(m);
}
BuffInfo.RemoveBuff(killed, BuffIcon.HeatOfBattleStatus);
}
public static void EventSink_CreatureDeath(CreatureDeathEventArgs e)
{
var killed = e.Creature;
foreach (var m in killed.Aggressed.Select(x => x.Defender))
{
CheckCombat(m);
}
foreach (var m in killed.Aggressors.Select(x => x.Attacker))
{
CheckCombat(m);
}
}
private static void CheckCombat(Mobile m)
{
if (m is PlayerMobile && !CheckHasAggression(m))
{
BuffInfo.RemoveBuff(m, BuffIcon.HeatOfBattleStatus);
}
}
public static bool CheckAggressions(Mobile m1, Mobile m2)
{
List<AggressorInfo> list = m1.Aggressors;
for (int i = 0; i < list.Count; ++i)
{
AggressorInfo info = list[i];
if (info.Attacker == m2 && DateTime.UtcNow < (info.LastCombatTime + Delay))
return true;
}
list = m2.Aggressors;
for (int i = 0; i < list.Count; ++i)
{
AggressorInfo info = list[i];
if (info.Attacker == m1 && DateTime.UtcNow < (info.LastCombatTime + Delay))
return true;
}
return false;
}
public static bool CheckHasAggression(Mobile m, bool aggressedOnly = false)
{
if (Server.Engines.VvV.ViceVsVirtueSystem.HasBattleAggression(m))
{
return true;
}
var list = m.Aggressed;
for (int i = 0; i < list.Count; ++i)
{
AggressorInfo info = list[i];
var defender = info.Defender;
if ((defender is PlayerMobile || (defender is BaseCreature && !((BaseCreature)defender).IsMonster)) &&
(DateTime.UtcNow < info.LastCombatTime + Delay && defender.LastKilled < info.LastCombatTime))
{
return true;
}
}
if (aggressedOnly)
{
return false;
}
list = m.Aggressors;
for (int i = 0; i < list.Count; ++i)
{
AggressorInfo info = list[i];
var attacker = info.Attacker;
if ((attacker is PlayerMobile || (attacker is BaseCreature && !((BaseCreature)attacker).IsMonster)) &&
(DateTime.UtcNow < info.LastCombatTime + Delay && attacker.LastKilled < info.LastCombatTime))
{
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
namespace Server.Misc
{
public class Animations
{
public static void Initialize()
{
EventSink.AnimateRequest += new AnimateRequestEventHandler(EventSink_AnimateRequest);
}
private static void EventSink_AnimateRequest(AnimateRequestEventArgs e)
{
Mobile from = e.Mobile;
int action;
bool useNew = Core.SA;
switch (e.Action)
{
case "bow":
action = useNew ? 0 : 32;
break;
case "salute":
action = useNew ? 1 : 33;
break;
default:
return;
}
if (from.Alive && !from.Mounted && (from.Body.IsHuman || from.Body.IsGargoyle))
{
if (useNew)
{
from.Animate(AnimationType.Emote, action);
}
else
{
from.Animate(action, 5, 1, true, false, 0);
}
}
}
}
}

View File

@@ -0,0 +1,284 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Server.Misc
{
public static class ArchivedSaves
{
public enum MergeType
{
Months,
Days,
Hours,
Minutes
}
private static readonly string _DefaultDestination;
private static string _Destination;
public static string Destination
{
get
{
if (string.IsNullOrWhiteSpace(_Destination) || _Destination.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
return _DefaultDestination;
return _Destination;
}
set
{
if (_Destination == value)
return;
_Destination = value;
if (_Enabled)
Utility.WriteConsoleColor(ConsoleColor.Cyan, "Archives: {0}", Destination);
}
}
private static bool _Enabled;
public static bool Enabled
{
get { return _Enabled; }
set
{
if (_Enabled == value)
return;
_Enabled = value;
var dest = _Enabled ? Destination : "Disabled";
Utility.WriteConsoleColor(ConsoleColor.Cyan, "Archives: {0}", dest);
}
}
public static bool Async { get; set; }
public static TimeSpan ExpireAge { get; set; }
public static MergeType Merge { get; set; }
private static readonly List<IAsyncResult> _Tasks = new List<IAsyncResult>(0x40);
private static readonly object _TaskRoot = ((ICollection)_Tasks).SyncRoot;
private static readonly AutoResetEvent _Sync = new AutoResetEvent(true);
private static readonly Action<string> _Pack = InternalPack;
private static readonly Action<DateTime> _Prune = InternalPrune;
public static int PendingTasks
{
get
{
lock (_TaskRoot)
return _Tasks.Count - _Tasks.RemoveAll(t => t.IsCompleted);
}
}
static ArchivedSaves()
{
_DefaultDestination = Path.Combine(Core.BaseDirectory, "Backups", "Archived");
_Destination = Config.Get("AutoSave.ArchivesPath", (string)null);
Enabled = Config.Get("AutoSave.ArchivesEnabled", false);
Async = Config.Get("AutoSave.ArchivesAsync", true);
ExpireAge = Config.Get("AutoSave.ArchivesExpire", TimeSpan.Zero);
Merge = Config.GetEnum("AutoSave.ArchivesMerging", MergeType.Minutes);
}
[CallPriority(int.MaxValue - 10)]
public static void Configure()
{
EventSink.Shutdown += Wait;
EventSink.WorldSave += Wait;
}
public static bool Process(string source)
{
if (!Enabled)
return false;
if (!Directory.Exists(Destination))
Directory.CreateDirectory(Destination);
if (ExpireAge > TimeSpan.Zero)
BeginPrune(DateTime.UtcNow - ExpireAge);
if (!string.IsNullOrWhiteSpace(source))
BeginPack(source);
return true;
}
private static void Wait(WorldSaveEventArgs e)
{
WaitForTaskCompletion();
}
private static void Wait(ShutdownEventArgs e)
{
WaitForTaskCompletion();
}
private static void WaitForTaskCompletion()
{
if (!Core.Crashed && !Core.Closing)
return;
var pending = PendingTasks;
if (pending <= 0)
return;
Utility.WriteConsoleColor(ConsoleColor.Cyan, "Archives: Waiting for {0:#,0} pending tasks...", pending);
while (pending > 0)
{
_Sync.WaitOne(10);
pending = PendingTasks;
}
Utility.WriteConsoleColor(ConsoleColor.Cyan, "Archives: All tasks completed.");
}
private static void InternalPack(string source)
{
Utility.WriteConsoleColor(ConsoleColor.Cyan, "Archives: Packing started...");
var sw = Stopwatch.StartNew();
try
{
var now = DateTime.Now;
var ampm = now.Hour < 12 ? "AM" : "PM";
var hour12 = now.Hour > 12 ? now.Hour - 12 : now.Hour <= 0 ? 12 : now.Hour;
string date;
switch (Merge)
{
case MergeType.Months: date = string.Format("{0}-{1}", now.Month, now.Year); break;
case MergeType.Days: date = string.Format("{0}-{1}-{2}", now.Day, now.Month, now.Year); break;
case MergeType.Hours: date = string.Format("{0}-{1}-{2} {3:D2} {4}", now.Day, now.Month, now.Year, hour12, ampm); break;
case MergeType.Minutes: default: date = string.Format("{0}-{1}-{2} {3:D2}-{4:D2} {5}", now.Day, now.Month, now.Year, hour12, now.Minute, ampm); break;
}
var file = string.Format("{0} Saves ({1}).zip", ServerList.ServerName, date);
var dest = Path.Combine(Destination, file);
try { File.Delete(dest); }
catch { }
ZipFile.CreateFromDirectory(source, dest, CompressionLevel.Optimal, false);
}
catch { }
try { Directory.Delete(source, true); }
catch { }
sw.Stop();
Utility.WriteConsoleColor(ConsoleColor.Cyan, "Archives: Packing done in {0:F1} seconds.", sw.Elapsed.TotalSeconds);
}
private static void BeginPack(string source)
{
// Do not use async packing during a crash state or when closing.
if (!Async || Core.Crashed || Core.Closing)
{
_Pack.Invoke(source);
return;
}
_Sync.Reset();
var t = _Pack.BeginInvoke(source, EndPack, source);
lock (_TaskRoot)
_Tasks.Add(t);
}
private static void EndPack(IAsyncResult r)
{
_Pack.EndInvoke(r);
lock (_TaskRoot)
_Tasks.Remove(r);
_Sync.Set();
}
private static void InternalPrune(DateTime threshold)
{
if (!Directory.Exists(Destination))
return;
Utility.WriteConsoleColor(ConsoleColor.Cyan, "Archives: Pruning started...");
var sw = Stopwatch.StartNew();
try
{
var root = new DirectoryInfo(Destination);
foreach (FileInfo archive in root.GetFiles("*.zip", SearchOption.AllDirectories))
{
try
{
if (archive.LastWriteTimeUtc < threshold)
archive.Delete();
}
catch { }
}
}
catch { }
sw.Stop();
Utility.WriteConsoleColor(ConsoleColor.Cyan, "Archives: Pruning done in {0:F1} seconds.", sw.Elapsed.TotalSeconds);
}
private static void BeginPrune(DateTime threshold)
{
// Do not use async pruning during a crash state or when closing.
if (!Async || Core.Crashed || Core.Closing)
{
_Prune.Invoke(threshold);
return;
}
_Sync.Reset();
var t = _Prune.BeginInvoke(threshold, EndPrune, threshold);
lock (_TaskRoot)
_Tasks.Add(t);
}
private static void EndPrune(IAsyncResult r)
{
_Prune.EndInvoke(r);
lock (_TaskRoot)
_Tasks.Remove(r);
_Sync.Set();
}
}
}

145
Scripts/Misc/AutoRestart.cs Normal file
View File

@@ -0,0 +1,145 @@
using System;
using Server.Commands;
namespace Server.Misc
{
public class AutoRestart : Timer
{
private static readonly TimeSpan RestartDelay = TimeSpan.FromSeconds(10); // how long the server should remain active before restart (period of 'server wars')
private static readonly TimeSpan WarningDelay = TimeSpan.FromMinutes(1.0); // at what interval should the shutdown message be displayed?
public static DateTime RestartTime { get; private set; }
public static bool Restarting { get; private set; }
public static Timer Timer { get; private set; }
public static bool DoneWarning { get; private set; }
public static bool Enabled = Config.Get("AutoRestart.Enabled", false);
public static int Hour = Config.Get("AutoRestart.Hour", 12);
public static int Minutes = Config.Get("AutoRestart.Minute", 0);
public static int Frequency = Config.Get("AutoRestart.Frequency", 24);
public AutoRestart()
: base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
{
}
public static void Initialize()
{
CommandSystem.Register("Restart", AccessLevel.Administrator, new CommandEventHandler(Restart_OnCommand));
CommandSystem.Register("Shutdown", AccessLevel.Administrator, new CommandEventHandler(Shutdown_OnCommand));
if (Enabled)
{
var now = DateTime.Now;
var force = new DateTime(now.Year, now.Month, now.Day, Hour, Minutes, 0);
if (now > force)
{
force += TimeSpan.FromHours(Frequency);
}
RestartTime = force;
BeginTimer();
Utility.WriteConsoleColor(ConsoleColor.Magenta, "[Auto Restart] Configured for {0}:{1}:00, every {2} hours!", RestartTime.Hour, RestartTime.Minute, Frequency);
Utility.WriteConsoleColor(ConsoleColor.Magenta, "[Auto Restart] Next Shard Restart: {0}", RestartTime.ToString());
}
}
public static void Restart_OnCommand(CommandEventArgs e)
{
if (Restarting)
{
e.Mobile.SendMessage("The server is already restarting.");
}
else
{
e.Mobile.SendMessage("You have initiated server restart.");
StopTimer();
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
{
AutoSave.Save();
Restarting = true;
TimedShutdown(true);
});
}
}
public static void Shutdown_OnCommand(CommandEventArgs e)
{
if (Restarting)
{
e.Mobile.SendMessage("The server is already shutting down.");
}
else
{
e.Mobile.SendMessage("You have initiated server shutdown.");
StopTimer();
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
{
AutoSave.Save();
Restarting = true;
TimedShutdown(false);
});
}
}
private static void BeginTimer()
{
StopTimer();
Timer = new AutoRestart();
Timer.Start();
}
private static void StopTimer()
{
if (Timer != null)
{
Timer.Stop();
Timer = null;
}
}
protected override void OnTick()
{
if (Restarting || !Enabled)
return;
if (WarningDelay > TimeSpan.Zero && !DoneWarning && RestartTime - WarningDelay < DateTime.Now)
{
World.Broadcast(0x22, true, "The server will be going down in about {0} minute{1}.", WarningDelay.TotalMinutes.ToString(), WarningDelay.TotalMinutes == 1 ? "" : "s");
DoneWarning = true;
return;
}
if (DateTime.Now < RestartTime)
{
return;
}
AutoSave.Save();
Restarting = true;
TimedShutdown(true);
}
private static void TimedShutdown(bool restart)
{
World.Broadcast(0x22, true, String.Format("The server will be going down in about {0} seconds!", RestartDelay.TotalSeconds.ToString()));
Timer.DelayCall(RestartDelay, rest =>
{
Core.Kill(rest);
},
restart);
}
}
}

182
Scripts/Misc/AutoSave.cs Normal file
View File

@@ -0,0 +1,182 @@
using System;
using System.IO;
using Server.Commands;
namespace Server.Misc
{
public static class AutoSave
{
private static readonly string[] m_Backups = new string[]
{
"Third Backup",
"Second Backup",
"Most Recent"
};
private static readonly TimeSpan m_Delay;
private static readonly TimeSpan m_Warning;
private static readonly Timer m_Timer;
public static bool SavesEnabled { get; set; }
static AutoSave()
{
SavesEnabled = Config.Get("AutoSave.Enabled", true);
m_Delay = Config.Get("AutoSave.Frequency", TimeSpan.FromMinutes(5.0));
m_Warning = Config.Get("AutoSave.WarningTime", TimeSpan.Zero);
m_Timer = Timer.DelayCall(m_Delay - m_Warning, m_Delay, Tick);
m_Timer.Stop();
}
public static void Initialize()
{
m_Timer.Start();
CommandSystem.Register("SetSaves", AccessLevel.Administrator, SetSaves_OnCommand);
}
[Usage("SetSaves <true | false>")]
[Description("Enables or disables automatic shard saving.")]
public static void SetSaves_OnCommand(CommandEventArgs e)
{
if (e.Length == 1)
{
SavesEnabled = e.GetBoolean(0);
e.Mobile.SendMessage("Saves have been {0}.", SavesEnabled ? "enabled" : "disabled");
}
else
e.Mobile.SendMessage("Format: SetSaves <true | false>");
}
public static void Save()
{
Save(false);
}
public static void Save(bool permitBackgroundWrite)
{
if (AutoRestart.Restarting || CreateWorld.WorldCreating)
return;
World.WaitForWriteCompletion();
try
{
if (!Backup())
Console.WriteLine("WARNING: Automatic backup FAILED");
}
catch (Exception e)
{
Console.WriteLine("WARNING: Automatic backup FAILED:\n{0}", e);
}
World.Save(true, permitBackgroundWrite);
}
private static void Tick()
{
if (!SavesEnabled || AutoRestart.Restarting || Commands.CreateWorld.WorldCreating)
return;
if (m_Warning == TimeSpan.Zero)
Save();
else
{
int s = (int)m_Warning.TotalSeconds;
int m = s / 60;
s %= 60;
if (m > 0 && s > 0)
World.Broadcast(0x35, true, "The world will save in {0} minute{1} and {2} second{3}.", m, m != 1 ? "s" : "", s, s != 1 ? "s" : "");
else if (m > 0)
World.Broadcast(0x35, true, "The world will save in {0} minute{1}.", m, m != 1 ? "s" : "");
else
World.Broadcast(0x35, true, "The world will save in {0} second{1}.", s, s != 1 ? "s" : "");
Timer.DelayCall(m_Warning, Save);
}
}
private static bool Backup()
{
if (m_Backups.Length == 0)
return false;
string root = Path.Combine(Core.BaseDirectory, "Backups/Automatic");
if (!Directory.Exists(root))
Directory.CreateDirectory(root);
string tempRoot = Path.Combine(Core.BaseDirectory, "Backups/Temp");
if (Directory.Exists(tempRoot))
Directory.Delete(tempRoot, true);
string[] existing = Directory.GetDirectories(root);
bool anySuccess = existing.Length == 0;
for (int i = 0; i < m_Backups.Length; ++i)
{
DirectoryInfo dir = Match(existing, m_Backups[i]);
if (dir == null)
continue;
if (i > 0)
{
try
{
dir.MoveTo(Path.Combine(root, m_Backups[i - 1]));
anySuccess = true;
}
catch { }
}
else
{
bool delete = true;
try
{
dir.MoveTo(tempRoot);
delete = !ArchivedSaves.Process(tempRoot);
}
catch { }
if (delete)
{
try { dir.Delete(true); }
catch { }
}
}
}
string saves = Path.Combine(Core.BaseDirectory, "Saves");
if (Directory.Exists(saves))
Directory.Move(saves, Path.Combine(root, m_Backups[m_Backups.Length - 1]));
return anySuccess;
}
private static DirectoryInfo Match(string[] paths, string match)
{
for (int i = 0; i < paths.Length; ++i)
{
DirectoryInfo info = new DirectoryInfo(paths[i]);
if (info.Name.StartsWith(match))
return info;
}
return null;
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace Server.Misc
{
public class Broadcasts
{
public static void Initialize()
{
EventSink.Crashed += new CrashedEventHandler(EventSink_Crashed);
EventSink.Shutdown += new ShutdownEventHandler(EventSink_Shutdown);
}
public static void EventSink_Crashed(CrashedEventArgs e)
{
try
{
World.Broadcast(0x35, true, "The server has crashed.");
}
catch
{
}
}
public static void EventSink_Shutdown(ShutdownEventArgs e)
{
try
{
World.Broadcast(0x35, true, "The server has shut down.");
}
catch
{
}
}
}
}

498
Scripts/Misc/BuffIcons.cs Normal file
View File

@@ -0,0 +1,498 @@
using System;
using Server.Mobiles;
using Server.Network;
namespace Server
{
public class BuffInfo
{
public static bool Enabled
{
get
{
return Core.ML;
}
}
public static void Initialize()
{
if (Enabled)
{
EventSink.ClientVersionReceived += new ClientVersionReceivedHandler(delegate(ClientVersionReceivedArgs args)
{
PlayerMobile pm = args.State.Mobile as PlayerMobile;
if (pm != null)
Timer.DelayCall(TimeSpan.Zero, pm.ResendBuffs);
});
}
}
public static int Blank { get { return 1114057; } } // ~1_val~
#region Properties
private readonly BuffIcon m_ID;
public BuffIcon ID
{
get
{
return m_ID;
}
}
private readonly int m_TitleCliloc;
public int TitleCliloc
{
get
{
return m_TitleCliloc;
}
}
private readonly int m_SecondaryCliloc;
public int SecondaryCliloc
{
get
{
return m_SecondaryCliloc;
}
}
private readonly bool m_NoTimer;
public bool NoTimer
{
get
{
return m_NoTimer;
}
}
private readonly TimeSpan m_TimeLength;
public TimeSpan TimeLength
{
get
{
return m_TimeLength;
}
}
private readonly DateTime m_TimeStart;
public DateTime TimeStart
{
get
{
return m_TimeStart;
}
}
private readonly Timer m_Timer;
public Timer Timer
{
get
{
return m_Timer;
}
}
private readonly bool m_RetainThroughDeath;
public bool RetainThroughDeath
{
get
{
return m_RetainThroughDeath;
}
}
private readonly TextDefinition m_Args;
public TextDefinition Args
{
get
{
return m_Args;
}
}
#endregion
#region Constructors
public BuffInfo(BuffIcon iconID, int titleCliloc)
: this(iconID, titleCliloc, titleCliloc + 1)
{
}
public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc)
{
m_ID = iconID;
m_TitleCliloc = titleCliloc;
m_SecondaryCliloc = secondaryCliloc;
}
public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m)
: this(iconID, titleCliloc, titleCliloc + 1, length, m)
{
}
//Only the timed one needs to Mobile to know when to automagically remove it.
public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m)
: this(iconID, titleCliloc, secondaryCliloc)
{
m_TimeLength = length;
m_TimeStart = DateTime.UtcNow;
m_Timer = Timer.DelayCall(length, new TimerCallback(
delegate
{
PlayerMobile pm = m as PlayerMobile;
if (pm == null)
return;
pm.RemoveBuff(this);
}));
}
public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, bool notimer)
: this(iconID, titleCliloc, secondaryCliloc, length, m)
{
m_NoTimer = notimer;
}
public BuffInfo(BuffIcon iconID, int titleCliloc, TextDefinition args)
: this(iconID, titleCliloc, titleCliloc + 1, args)
{
}
public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args)
: this(iconID, titleCliloc, secondaryCliloc)
{
m_Args = args;
}
public BuffInfo(BuffIcon iconID, int titleCliloc, bool retainThroughDeath)
: this(iconID, titleCliloc, titleCliloc + 1, retainThroughDeath)
{
}
public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, bool retainThroughDeath)
: this(iconID, titleCliloc, secondaryCliloc)
{
m_RetainThroughDeath = retainThroughDeath;
}
public BuffInfo(BuffIcon iconID, int titleCliloc, TextDefinition args, bool retainThroughDeath)
: this(iconID, titleCliloc, titleCliloc + 1, args, retainThroughDeath)
{
}
public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, bool retainThroughDeath)
: this(iconID, titleCliloc, secondaryCliloc, args)
{
m_RetainThroughDeath = retainThroughDeath;
}
public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m, TextDefinition args)
: this(iconID, titleCliloc, titleCliloc + 1, length, m, args)
{
}
public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, TextDefinition args)
: this(iconID, titleCliloc, secondaryCliloc, length, m)
{
m_Args = args;
}
public BuffInfo(BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m, TextDefinition args, bool retainThroughDeath)
: this(iconID, titleCliloc, titleCliloc + 1, length, m, args, retainThroughDeath)
{
}
public BuffInfo(BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, TextDefinition args, bool retainThroughDeath)
: this(iconID, titleCliloc, secondaryCliloc, length, m)
{
m_Args = args;
m_RetainThroughDeath = retainThroughDeath;
}
#endregion
#region Convenience Methods
public static void AddBuff(Mobile m, BuffInfo b)
{
PlayerMobile pm = m as PlayerMobile;
if (pm != null)
pm.AddBuff(b);
}
public static void RemoveBuff(Mobile m, BuffInfo b)
{
PlayerMobile pm = m as PlayerMobile;
if (pm != null)
pm.RemoveBuff(b);
}
public static void RemoveBuff(Mobile m, BuffIcon b)
{
PlayerMobile pm = m as PlayerMobile;
if (pm != null)
pm.RemoveBuff(b);
}
#endregion
}
public enum BuffIcon : short
{
DismountPrevention = 0x3E9,
NoRearm = 0x3EA,
//Currently, no 0x3EB or 0x3EC
NightSight = 0x3ED, //*
DeathStrike,
EvilOmen,
HonoredDebuff,
AchievePerfection,
DivineFury, //*
EnemyOfOne, //*
HidingAndOrStealth, //*
ActiveMeditation, //*
BloodOathCaster, //*
BloodOathCurse, //*
CorpseSkin, //*
Mindrot, //*
PainSpike, //*
Strangle,
GiftOfRenewal, //*
AttuneWeapon, //*
Thunderstorm, //*
EssenceOfWind, //*
EtherealVoyage, //*
GiftOfLife, //*
ArcaneEmpowerment, //*
MortalStrike,
ReactiveArmor, //*
Protection, //*
ArchProtection,
MagicReflection, //*
Incognito, //*
Disguised,
AnimalForm,
Polymorph,
Invisibility, //*
Paralyze, //*
Poison,
Bleed,
Clumsy, //*
FeebleMind, //*
Weaken, //*
Curse, //*
MassCurse,
Agility, //*
Cunning, //*
Strength, //*
Bless, //*
Sleep,
StoneForm,
SpellPlague,
Berserk,
MassSleep,
Fly,
Inspire,
Invigorate,
Resilience,
Perseverance,
TribulationTarget,
DespairTarget,
FishPie = 0x426,
HitLowerAttack,
HitLowerDefense,
DualWield,
Block,
DefenseMastery,
DespairCaster,
Healing,
SpellFocusingBuff,
SpellFocusingDebuff,
RageFocusingDebuff,
RageFocusingBuff,
Warding,
TribulationCaster,
ForceArrow,
Disarm,
Surge,
Feint,
TalonStrike,
PsychicAttack,
ConsecrateWeapon,
GrapesOfWrath,
EnemyOfOneDebuff,
HorrificBeast,
LichForm,
VampiricEmbrace,
CurseWeapon,
ReaperForm,
ImmolatingWeapon,
Enchant,
HonorableExecution,
Confidence,
Evasion,
CounterAttack,
LightningStrike,
MomentumStrike,
OrangePetals,
RoseOfTrinsic,
PoisonImmunity,
Veterinary,
Perfection,
Honored,
ManaPhase,
FanDancerFanFire,
Rage,
Webbing,
MedusaStone,
TrueFear,
AuraOfNausea,
HowlOfCacophony,
GazeDespair,
HiryuPhysicalResistance,
RuneBeetleCorruption,
BloodwormAnemia,
RotwormBloodDisease,
SkillUseDelay,
FactionStatLoss,
HeatOfBattleStatus,
CriminalStatus,
ArmorPierce,
SplinteringEffect,
SwingSpeedDebuff,
WraithForm,
CityTradeDeal = 0x466,
HumilityDebuff = 0x467,
Spirituality,
Humility,
// Skill Masteries
Rampage,
Stagger, // Debuff
Toughness,
Thrust,
Pierce, // Debuff
PlayingTheOdds,
FocusedEye,
Onslaught, // Debuff
ElementalFury,
ElementalFuryDebuff, // Debuff
CalledShot,
Knockout,
SavingThrow,
Conduit,
EtherealBurst,
MysticWeapon,
ManaShield,
AnticipateHit,
Warcry,
Shadow,
WhiteTigerForm,
Bodyguard,
HeightenedSenses,
Tolerance,
DeathRay,
DeathRayDebuff,
Intuition,
EnchantedSummoning,
ShieldBash,
Whispering,
CombatTraining,
InjectedStrikeDebuff,
InjectedStrike,
UnknownTomato,
PlayingTheOddsDebuff,
DragonTurtleDebuff,
Boarding,
Potency,
ThrustDebuff,
FistsOfFury, // 1169
BarrabHemolymphConcentrate,
JukariBurnPoiltice,
KurakAmbushersEssence,
BarakoDraftOfMight,
UraliTranceTonic,
SakkhraProphylaxis,
CaddelliteInfused = 1186,
PotionGloriousFortune,
MysticalPolymorphTotem
}
public sealed class AddBuffPacket : Packet
{
public AddBuffPacket(Mobile m, BuffInfo info)
: this(m, info.ID, info.TitleCliloc, info.SecondaryCliloc, info.Args, info.NoTimer ? TimeSpan.Zero :(info.TimeStart != DateTime.MinValue) ? ((info.TimeStart + info.TimeLength) - DateTime.UtcNow) : TimeSpan.Zero)
{
}
public AddBuffPacket(Mobile mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, TimeSpan length)
: base(0xDF)
{
bool hasArgs = (args != null);
EnsureCapacity((hasArgs ? (48 + args.ToString().Length * 2) : 44));
m_Stream.Write((int)mob.Serial);
m_Stream.Write((short)iconID); //ID
m_Stream.Write((short)0x1); //Type 0 for removal. 1 for add 2 for Data
m_Stream.Fill(4);
m_Stream.Write((short)iconID); //ID
m_Stream.Write((short)0x01); //Type 0 for removal. 1 for add 2 for Data
m_Stream.Fill(4);
if (length < TimeSpan.Zero)
length = TimeSpan.Zero;
m_Stream.Write((short)length.TotalSeconds); //Time in seconds
m_Stream.Fill(3);
m_Stream.Write((int)titleCliloc);
m_Stream.Write((int)secondaryCliloc);
if (!hasArgs)
{
//m_Stream.Fill( 2 );
m_Stream.Fill(10);
}
else
{
m_Stream.Fill(4);
m_Stream.Write((short)0x1); //Unknown -> Possibly something saying 'hey, I have more data!'?
m_Stream.Fill(2);
//m_Stream.WriteLittleUniNull( "\t#1018280" );
m_Stream.WriteLittleUniNull(String.Format("\t{0}", args.ToString()));
m_Stream.Write((short)0x1); //Even more Unknown -> Possibly something saying 'hey, I have more data!'?
m_Stream.Fill(2);
}
}
}
public sealed class RemoveBuffPacket : Packet
{
public RemoveBuffPacket(Mobile mob, BuffInfo info)
: this(mob, info.ID)
{
}
public RemoveBuffPacket(Mobile mob, BuffIcon iconID)
: base(0xDF)
{
EnsureCapacity(13);
m_Stream.Write((int)mob.Serial);
m_Stream.Write((short)iconID); //ID
m_Stream.Write((short)0x0); //Type 0 for removal. 1 for add 2 for Data
m_Stream.Fill(4);
}
}
}

File diff suppressed because it is too large Load Diff

176
Scripts/Misc/Cleanup.cs Normal file
View File

@@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
using Server.Multis;
namespace Server.Misc
{
public class Cleanup
{
public static void Initialize()
{
Timer.DelayCall(TimeSpan.FromSeconds(2.5), new TimerCallback(Run));
}
public static void Run()
{
List<Item> items = new List<Item>();
List<Item> validItems = new List<Item>();
List<Mobile> hairCleanup = new List<Mobile>();
int boxes = 0;
foreach (Item item in World.Items.Values)
{
if (item.Map == null)
{
items.Add(item);
continue;
}
else if (item is CommodityDeed)
{
CommodityDeed deed = (CommodityDeed)item;
if (deed.Commodity != null)
validItems.Add(deed.Commodity);
continue;
}
else if (item is BaseHouse)
{
BaseHouse house = (BaseHouse)item;
foreach (RelocatedEntity relEntity in house.RelocatedEntities)
{
if (relEntity.Entity is Item)
validItems.Add((Item)relEntity.Entity);
}
foreach (VendorInventory inventory in house.VendorInventories)
{
foreach (Item subItem in inventory.Items)
validItems.Add(subItem);
}
}
else if (item is BankBox)
{
BankBox box = (BankBox)item;
Mobile owner = box.Owner;
if (owner == null)
{
items.Add(box);
++boxes;
}
else if (box.Items.Count == 0)
{
items.Add(box);
++boxes;
}
continue;
}
else if ((item.Layer == Layer.Hair || item.Layer == Layer.FacialHair))
{
object rootParent = item.RootParent;
if (rootParent is Mobile)
{
Mobile rootMobile = (Mobile)rootParent;
if (item.Parent != rootMobile && rootMobile.IsPlayer())
{
items.Add(item);
continue;
}
else if (item.Parent == rootMobile)
{
hairCleanup.Add(rootMobile);
continue;
}
}
}
if (item.Parent != null || item.Map != Map.Internal || item.HeldBy != null)
continue;
if (item.Location != Point3D.Zero)
continue;
if (!IsBuggable(item))
continue;
if (item is BaseBoat || item is BaseDockedBoat)
continue;
items.Add(item);
}
for (int i = 0; i < validItems.Count; ++i)
items.Remove(validItems[i]);
if (items.Count > 0)
{
if (boxes > 0)
Console.WriteLine("Cleanup: Detected {0} inaccessible items, including {1} bank boxes, removing..", items.Count, boxes);
else
Console.WriteLine("Cleanup: Detected {0} inaccessible items, removing..", items.Count);
for (int i = 0; i < items.Count; ++i)
{
Console.WriteLine(items[i].ToString());
items[i].Delete();
}
}
if (hairCleanup.Count > 0)
{
Console.WriteLine("Cleanup: Detected {0} hair and facial hair items being worn, converting to their virtual counterparts..", hairCleanup.Count);
for (int i = 0; i < hairCleanup.Count; i++)
hairCleanup[i].ConvertHair();
}
}
public static bool IsBuggable(Item item)
{
if (item is Fists)
return false;
if (item is ICommodity || item is Multis.BaseBoat ||
item is Fish || item is BigFish ||
item is BasePotion || item is Food || item is CookableFood ||
item is SpecialFishingNet || item is BaseMagicFish ||
item is Shoes || item is Sandals ||
item is Boots || item is ThighBoots ||
item is TreasureMap || item is MessageInABottle ||
item is BaseArmor || item is BaseWeapon ||
item is BaseClothing ||
(item is BaseJewel && Core.AOS) ||
(item is BasePotion && Core.ML)
#region Champion artifacts
||
item is SkullPole ||
item is EvilIdolSkull ||
item is MonsterStatuette ||
item is Pier ||
item is ArtifactLargeVase ||
item is ArtifactVase ||
item is MinotaurStatueDeed ||
item is SwampTile ||
item is WallBlood ||
item is TatteredAncientMummyWrapping ||
item is LavaTile ||
item is DemonSkull ||
item is Web ||
item is WaterTile ||
item is WindSpirit ||
item is DirtPatch ||
item is Futon)
#endregion
return true;
return false;
}
}
}

View File

@@ -0,0 +1,242 @@
using System;
using System.Diagnostics;
using System.IO;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Misc
{
public class ClientVerification
{
private static readonly bool m_DetectClientRequirement = true;
private static readonly OldClientResponse m_OldClientResponse = OldClientResponse.LenientKick;
private static readonly TimeSpan m_AgeLeniency = TimeSpan.FromDays(10);
private static readonly TimeSpan m_GameTimeLeniency = TimeSpan.FromHours(25);
private static ClientVersion m_Required;
private static ClientVersion m_RequiredEC;
public static TimeSpan KickDelay = TimeSpan.FromSeconds(Config.Get("Client.KickDelay", 20.0));
public static bool AllowRegular = Config.Get("Client.AllowRegular", true);
public static bool AllowUOTD = Config.Get("Client.AllowUOTD", true);
public static bool AllowGod = Config.Get("Client.AllowGod", true);
public static bool AllowEC = Config.Get("Client.AllowEC", true);
private enum OldClientResponse
{
Ignore,
Warn,
Annoy,
LenientKick,
Kick
}
public static ClientVersion Required
{
get
{
return m_Required;
}
set
{
m_Required = value;
}
}
public static ClientVersion RequiredEC
{
get
{
return m_RequiredEC;
}
set
{
m_RequiredEC = value;
}
}
public static void Initialize()
{
EventSink.ClientVersionReceived += new ClientVersionReceivedHandler(EventSink_ClientVersionReceived);
EventSink.ClientTypeReceived += new ClientTypeReceivedHandler(EventSink_ClientTypeReceived);
m_RequiredEC = new ClientVersion(67, 0, 59, 0, ClientType.SA);
if (m_DetectClientRequirement)
{
string path = Core.FindDataFile("client.exe");
if (File.Exists(path))
{
FileVersionInfo info = FileVersionInfo.GetVersionInfo(path);
if (info.FileMajorPart != 0 || info.FileMinorPart != 0 || info.FileBuildPart != 0 || info.FilePrivatePart != 0)
{
Required = new ClientVersion(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart);
}
}
}
if (Required != null)
{
Utility.PushColor(ConsoleColor.White);
Console.WriteLine("Restricting classic client version to {0}. Action to be taken: {1}", Required, m_OldClientResponse);
Utility.PopColor();
}
if (RequiredEC != null)
{
Utility.PushColor(ConsoleColor.White);
Console.WriteLine("Restricting enhanced client version to {0}. Action to be taken: {1}", RequiredEC, "Kick");
Utility.PopColor();
}
}
private static void EventSink_ClientVersionReceived(ClientVersionReceivedArgs e)
{
string kickMessage = null;
NetState state = e.State;
ClientVersion version = e.Version;
if (state.Mobile != null && state.Mobile.IsStaff())
return;
ClientVersion required = Required;
if (required != null && version < required && (m_OldClientResponse == OldClientResponse.Kick || (m_OldClientResponse == OldClientResponse.LenientKick && (DateTime.UtcNow - state.Mobile.CreationTime) > m_AgeLeniency && state.Mobile is PlayerMobile && ((PlayerMobile)state.Mobile).GameTime > m_GameTimeLeniency)))
{
kickMessage = String.Format("This server requires your client version be at least {0}.", required);
}
else if (!AllowGod || !AllowRegular || !AllowUOTD)
{
if (!AllowGod && version.Type == ClientType.God)
kickMessage = "This server does not allow god clients to connect.";
else if (!AllowRegular && version.Type == ClientType.Regular)
kickMessage = "This server does not allow regular clients to connect.";
else if (!AllowUOTD && state.IsUOTDClient)
kickMessage = "This server does not allow UO:TD clients to connect.";
if (!AllowGod && !AllowRegular && !AllowUOTD)
{
kickMessage = "This server does not allow any clients to connect.";
}
else if (AllowGod && !AllowRegular && !AllowUOTD && version.Type != ClientType.God)
{
kickMessage = "This server requires you to use the god client.";
}
else if (kickMessage != null)
{
if (AllowRegular && AllowUOTD)
kickMessage += " You can use regular or UO:TD clients.";
else if (AllowRegular)
kickMessage += " You can use regular clients.";
else if (AllowUOTD)
kickMessage += " You can use UO:TD clients.";
}
}
if (kickMessage != null)
{
state.Mobile.SendMessage(0x22, kickMessage);
state.Mobile.SendMessage(0x22, "You will be disconnected in {0} seconds.", KickDelay.TotalSeconds);
Timer.DelayCall(KickDelay, delegate
{
if (state.Socket != null)
{
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Client: {0}: Disconnecting, bad version", state);
Utility.PopColor();
state.Dispose();
}
});
}
else if (Required != null && version < Required)
{
switch( m_OldClientResponse )
{
case OldClientResponse.Warn:
{
state.Mobile.SendMessage(0x22, "Your client is out of date. Please update your client.", Required);
state.Mobile.SendMessage(0x22, "This server recommends that your client version be at least {0}.", Required);
break;
}
case OldClientResponse.LenientKick:
case OldClientResponse.Annoy:
{
SendAnnoyGump(state.Mobile);
break;
}
}
}
}
private static void EventSink_ClientTypeReceived(ClientTypeReceivedArgs e)
{
var state = e.State;
ClientVersion version = state.Version;
if (state.IsEnhancedClient)
{
if (!AllowEC)
{
Utility.PushColor(ConsoleColor.DarkRed);
Console.WriteLine("Client: {0}: Disconnecting, Enhanced Client", state);
Utility.PopColor();
state.Dispose();
}
else
{
ClientVersion required = RequiredEC;
if (required != null && version < required)
{
Timer.DelayCall(TimeSpan.FromSeconds(5), () =>
{
if (state.Mobile != null && !state.Mobile.IsStaff())
{
state.Mobile.SendMessage("This server requires your enhanced client version be at least {0}. You will be disconnected in 5 seconds.", required);
Timer.DelayCall(TimeSpan.FromSeconds(5), () =>
{
Utility.PushColor(ConsoleColor.DarkRed);
Console.WriteLine("Client: {0}: Disconnecting, bad enhanced client version.", state);
Utility.PopColor();
state.Dispose();
});
}
});
}
}
return;
}
}
private static void SendAnnoyGump(Mobile m)
{
if (m.NetState != null && m.NetState.Version < Required)
{
Gump g = new WarningGump(1060637, 30720, String.Format("Your client is out of date. Please update your client.<br>This server recommends that your client version be at least {0}.<br> <br>You are currently using version {1}.<br> <br>To patch, run UOPatch.exe inside your Ultima Online folder.", Required, m.NetState.Version), 0xFFC000, 480, 360,
delegate(Mobile mob, bool selection, object o)
{
m.SendMessage("You will be reminded of this again.");
if (m_OldClientResponse == OldClientResponse.LenientKick)
m.SendMessage("Old clients will be kicked after {0} days of character age and {1} hours of play time", m_AgeLeniency, m_GameTimeLeniency);
Timer.DelayCall(TimeSpan.FromMinutes(Utility.Random(5, 15)), delegate { SendAnnoyGump(m); });
}, null, false);
g.Dragable = false;
g.Closable = false;
g.Resizable = false;
m.SendGump(g);
}
}
}
}

View File

@@ -0,0 +1,526 @@
#region References
using System;
using System.Linq;
using System.Threading;
using Server.Accounting;
using Server.Engines.Help;
using Server.Network;
#endregion
namespace Server.Misc
{
internal static class ServerConsole
{
private static readonly Func<string> _Listen = Console.ReadLine;
private static string _Command;
private static Timer _PollTimer;
private static bool _HearConsole;
public static void Initialize()
{
EventSink.ServerStarted += () =>
{
PollCommands();
if (_HearConsole)
{
Console.WriteLine("Now listening to the whole shard.");
}
};
EventSink.Speech += args =>
{
if (args.Mobile == null || !_HearConsole)
{
return;
}
try
{
if (args.Mobile.Region.Name.Length > 0)
{
Console.WriteLine(args.Mobile.Name + " (" + args.Mobile.Region.Name + "): " + args.Speech);
}
else
{
Console.WriteLine("" + args.Mobile.Name + ": " + args.Speech + "");
}
}
catch
{ }
};
}
private static void PollCommands()
{
_PollTimer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromMilliseconds(100), ProcessCommand);
_Listen.BeginInvoke(r => ProcessInput(_Listen.EndInvoke(r)), null);
}
private static void ProcessInput(string input)
{
if (!Core.Crashed && !Core.Closing)
{
Interlocked.Exchange(ref _Command, input);
}
}
private static void ProcessCommand()
{
if (Core.Crashed || Core.Closing || World.Loading || World.Saving)
{
return;
}
if (String.IsNullOrEmpty(_Command))
{
return;
}
ProcessCommand(_Command);
Interlocked.Exchange(ref _Command, String.Empty);
_Listen.BeginInvoke(r => ProcessInput(_Listen.EndInvoke(r)), null);
}
private static PageEntry[] _Pages;
private static void ProcessCommand(string input)
{
input = input.Trim();
if (_Pages != null)
{
HandlePaging(input);
return;
}
if (input.StartsWith("pages", StringComparison.OrdinalIgnoreCase))
{
HandlePaging(input.Substring(5).Trim());
return;
}
if (input.StartsWith("bc", StringComparison.OrdinalIgnoreCase))
{
var sub = input.Substring(2).Trim();
BroadcastMessage(AccessLevel.Player, 0x35, String.Format("[Admin] {0}", sub));
Console.WriteLine("[World]: {0}", sub);
return;
}
if (input.StartsWith("sc", StringComparison.OrdinalIgnoreCase))
{
var sub = input.Substring(2).Trim();
BroadcastMessage(AccessLevel.Counselor, 0x32, String.Format("[Admin] {0}", sub));
Console.WriteLine("[Staff]: {0}", sub);
return;
}
if (input.StartsWith("ban", StringComparison.OrdinalIgnoreCase))
{
var sub = input.Substring(3).Trim();
var states = NetState.Instances;
if (states.Count == 0)
{
Console.WriteLine("There are no players online.");
return;
}
var ns = states.Find(o => o.Account != null && o.Mobile != null && Insensitive.StartsWith(sub, o.Mobile.RawName));
if (ns != null)
{
Console.WriteLine("[Ban]: {0}: Mobile: '{1}' Account: '{2}'", ns, ns.Mobile.RawName, ns.Account.Username);
ns.Dispose();
}
return;
}
if (input.StartsWith("kick", StringComparison.OrdinalIgnoreCase))
{
var sub = input.Substring(4).Trim();
var states = NetState.Instances;
if (states.Count == 0)
{
Console.WriteLine("There are no players online.");
return;
}
var ns = states.Find(o => o.Account != null && o.Mobile != null && Insensitive.StartsWith(sub, o.Mobile.RawName));
if (ns != null)
{
Console.WriteLine("[Kick]: {0}: Mobile: '{1}' Account: '{2}'", ns, ns.Mobile.RawName, ns.Account.Username);
ns.Dispose();
}
return;
}
switch (input.Trim())
{
case "crash":
{
Timer.DelayCall(() => { throw new Exception("Forced Crash"); });
}
break;
case "shutdown":
{
AutoSave.Save();
Core.Kill(false);
}
break;
case "shutdown nosave":
{
Core.Kill(false);
}
break;
case "restart":
{
AutoSave.Save();
Core.Kill(true);
}
break;
case "restart nosave":
{
Core.Kill(true);
}
break;
case "online":
{
var states = NetState.Instances;
if (states.Count == 0)
{
Console.WriteLine("There are no users online at this time.");
}
foreach (var t in states)
{
var a = t.Account as Account;
if (a == null)
{
continue;
}
var m = t.Mobile;
if (m != null)
{
Console.WriteLine("- Account: {0}, Name: {1}, IP: {2}", a.Username, m.Name, t);
}
}
}
break;
case "save":
AutoSave.Save();
break;
case "hear": // Credit to Zippy for the HearAll script!
{
_HearConsole = !_HearConsole;
Console.WriteLine("{0} sending speech to the console.", _HearConsole ? "Now" : "No longer");
}
break;
default:
DisplayHelp();
break;
}
}
private static void DisplayHelp()
{
Console.WriteLine(" ");
Console.WriteLine("Commands:");
Console.WriteLine("crash - Forces an exception to be thrown.");
Console.WriteLine("save - Performs a forced save.");
Console.WriteLine("shutdown - Performs a forced save then shuts down the server.");
Console.WriteLine("shutdown nosave - Shuts down the server without saving.");
Console.WriteLine("restart - Sends a message to players informing them that the server is");
Console.WriteLine(" restarting, performs a forced save, then shuts down and");
Console.WriteLine(" restarts the server.");
Console.WriteLine("restart nosave - Restarts the server without saving.");
Console.WriteLine("online - Shows a list of every person online:");
Console.WriteLine(" Account, Char Name, IP.");
Console.WriteLine("bc <message> - Type this command and your message after it.");
Console.WriteLine(" It will then be sent to all players.");
Console.WriteLine("sc <message> - Type this command and your message after it.");
Console.WriteLine(" It will then be sent to all staff.");
Console.WriteLine("hear - Copies all local speech to this console:");
Console.WriteLine(" Char Name (Region name): Speech.");
Console.WriteLine("ban <name> - Kicks and bans the users account.");
Console.WriteLine("kick <name> - Kicks the user.");
Console.WriteLine("pages - Enter page mode to handle help requests.");
Console.WriteLine("help|? - Shows this list.");
Console.WriteLine(" ");
}
private static void DisplayPagingHelp()
{
Console.WriteLine(" ");
Console.WriteLine("Paging Commands:");
Console.WriteLine("view <id> - View sender message.");
Console.WriteLine("remove <id> - Remove without message.");
Console.WriteLine("handle <id> <message> - Remove with message.");
Console.WriteLine("clear - Clears the page queue.");
Console.WriteLine("exit - Exit page mode.");
Console.WriteLine("help|? - Shows this list.");
Console.WriteLine(" ");
}
private static void HandlePaging(string sub)
{
if (sub.StartsWith("help", StringComparison.OrdinalIgnoreCase) ||
sub.StartsWith("?", StringComparison.OrdinalIgnoreCase))
{
DisplayPagingHelp();
HandlePaging(String.Empty);
return;
}
if (PageQueue.List.Count == 0)
{
Console.WriteLine("There are no pages in the queue.");
if (_Pages != null)
{
_Pages = null;
Console.WriteLine("[Pages]: Disabled page mode.");
}
return;
}
if (String.IsNullOrWhiteSpace(sub))
{
if (_Pages == null)
{
Console.WriteLine("[Pages]: Enabled page mode.");
DisplayPagingHelp();
}
_Pages = PageQueue.List.Cast<PageEntry>().ToArray();
const string format = "{0:D3}:\t{1}\t{2}";
for (var i = 0; i < _Pages.Length; i++)
{
Console.WriteLine(format, i + 1, _Pages[i].Type, _Pages[i].Sender);
}
return;
}
if (sub.StartsWith("exit", StringComparison.OrdinalIgnoreCase))
{
if (_Pages != null)
{
_Pages = null;
Console.WriteLine("[Pages]: Disabled page mode.");
}
return;
}
if (sub.StartsWith("clear", StringComparison.OrdinalIgnoreCase))
{
if (_Pages != null)
{
foreach (var page in _Pages)
{
PageQueue.Remove(page);
}
Console.WriteLine("[Pages]: Queue cleared.");
Array.Clear(_Pages, 0, _Pages.Length);
_Pages = null;
Console.WriteLine("[Pages]: Disabled page mode.");
}
return;
}
if (sub.StartsWith("remove", StringComparison.OrdinalIgnoreCase))
{
string[] args;
var page = FindPage(sub, out args);
if (page == null)
{
Console.WriteLine("[Pages]: Invalid page entry.");
}
else
{
PageQueue.Remove(page);
Console.WriteLine("[Pages]: Removed from queue.");
}
HandlePaging(String.Empty);
return;
}
if (sub.StartsWith("handle", StringComparison.OrdinalIgnoreCase))
{
string[] args;
var page = FindPage(sub, out args);
if (page == null)
{
Console.WriteLine("[Pages]: Invalid page entry.");
HandlePaging(String.Empty);
return;
}
if (args.Length <= 0)
{
Console.WriteLine("[Pages]: Message required.");
HandlePaging(String.Empty);
return;
}
page.Sender.SendGump(new MessageSentGump(page.Sender, ServerList.ServerName, String.Join(" ", args)));
Console.WriteLine("[Pages]: Message sent.");
PageQueue.Remove(page);
Console.WriteLine("[Pages]: Removed from queue.");
HandlePaging(String.Empty);
return;
}
if (sub.StartsWith("view", StringComparison.OrdinalIgnoreCase))
{
string[] args;
var page = FindPage(sub, out args);
if (page == null)
{
Console.WriteLine("[Pages]: Invalid page entry.");
HandlePaging(String.Empty);
return;
}
var idx = Array.IndexOf(_Pages, page) + 1;
Console.WriteLine("[Pages]: {0:D3}:\t{1}\t{2}", idx, page.Type, page.Sender);
if (!String.IsNullOrWhiteSpace(page.Message))
{
Console.WriteLine("[Pages]: {0}", page.Message);
}
else
{
Console.WriteLine("[Pages]: No message supplied.");
}
HandlePaging(String.Empty);
return;
}
if (_Pages != null)
{
string[] args;
var page = FindPage(sub, out args);
if (page != null)
{
var idx = Array.IndexOf(_Pages, page) + 1;
Console.WriteLine("[Pages]: {0:D3}:\t{1}\t{2}", idx, page.Type, page.Sender);
if (!String.IsNullOrWhiteSpace(page.Message))
{
Console.WriteLine("[Pages]: {0}", page.Message);
}
else
{
Console.WriteLine("[Pages]: No message supplied.");
}
HandlePaging(String.Empty);
return;
}
Array.Clear(_Pages, 0, _Pages.Length);
_Pages = null;
Console.WriteLine("[Pages]: Disabled page mode.");
}
}
private static PageEntry FindPage(string sub, out string[] args)
{
args = sub.Split(' ');
if (args.Length > 1)
{
sub = args[1];
if (args.Length > 2)
{
args = args.Skip(2).ToArray();
}
else
{
args = args.Skip(1).ToArray();
}
}
int id;
if (Int32.TryParse(sub, out id) && --id >= 0 && id < _Pages.Length)
{
var page = _Pages[id];
if (PageQueue.List.Contains(page))
{
return page;
}
}
return null;
}
public static void BroadcastMessage(AccessLevel ac, int hue, string message)
{
World.Broadcast(hue, false, ac, message);
}
}
}

268
Scripts/Misc/CrashGuard.cs Normal file
View File

@@ -0,0 +1,268 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Mail;
using Server.Accounting;
using Server.Network;
namespace Server.Misc
{
public class CrashGuard
{
private static readonly bool Enabled = true;
private static readonly bool SaveBackup = true;
private static readonly bool RestartServer = true;
private static readonly bool GenerateReport = true;
public static void Initialize()
{
if (Enabled) // If enabled, register our crash event handler
EventSink.Crashed += new CrashedEventHandler(CrashGuard_OnCrash);
}
public static void CrashGuard_OnCrash(CrashedEventArgs e)
{
if (GenerateReport)
GenerateCrashReport(e);
World.WaitForWriteCompletion();
if (SaveBackup)
Backup();
/*if ( Core.Service )
e.Close = true;
else */ if (RestartServer)
Restart(e);
}
private static void SendEmail(string filePath)
{
Console.Write("Crash: Sending email...");
MailMessage message = new MailMessage(Email.FromAddress, Email.CrashAddresses);
message.Subject = "Automated ServUO Crash Report";
message.Body = "Automated ServUO Crash Report. See attachment for details.";
message.Attachments.Add(new Attachment(filePath));
if (Email.Send(message))
Console.WriteLine("done");
else
Console.WriteLine("failed");
}
private static string GetRoot()
{
try
{
return Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
}
catch
{
return "";
}
}
private static string Combine(string path1, string path2)
{
if (path1.Length == 0)
return path2;
return Path.Combine(path1, path2);
}
private static void Restart(CrashedEventArgs e)
{
string root = GetRoot();
Console.Write("Crash: Restarting...");
try
{
Process.Start(Core.ExePath, Core.Arguments);
Console.WriteLine("done");
e.Close = true;
}
catch
{
Console.WriteLine("failed");
}
}
private static void CreateDirectory(string path)
{
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
private static void CreateDirectory(string path1, string path2)
{
CreateDirectory(Combine(path1, path2));
}
private static void CopyFile(string rootOrigin, string rootBackup, string path)
{
string originPath = Combine(rootOrigin, path);
string backupPath = Combine(rootBackup, path);
try
{
if (File.Exists(originPath))
File.Copy(originPath, backupPath);
}
catch
{
}
}
private static void Backup()
{
Console.Write("Crash: Backing up...");
try
{
string timeStamp = GetTimeStamp();
string root = GetRoot();
string rootBackup = Combine(root, String.Format("Backups/Crashed/{0}/", timeStamp));
string rootOrigin = Combine(root, String.Format("Saves/"));
// Create new directories
CreateDirectory(rootBackup);
CreateDirectory(rootBackup, "Accounts/");
CreateDirectory(rootBackup, "Items/");
CreateDirectory(rootBackup, "Mobiles/");
CreateDirectory(rootBackup, "Guilds/");
CreateDirectory(rootBackup, "Regions/");
// Copy files
CopyFile(rootOrigin, rootBackup, "Accounts/Accounts.xml");
CopyFile(rootOrigin, rootBackup, "Items/Items.bin");
CopyFile(rootOrigin, rootBackup, "Items/Items.idx");
CopyFile(rootOrigin, rootBackup, "Items/Items.tdb");
CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.bin");
CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.idx");
CopyFile(rootOrigin, rootBackup, "Mobiles/Mobiles.tdb");
CopyFile(rootOrigin, rootBackup, "Guilds/Guilds.bin");
CopyFile(rootOrigin, rootBackup, "Guilds/Guilds.idx");
CopyFile(rootOrigin, rootBackup, "Regions/Regions.bin");
CopyFile(rootOrigin, rootBackup, "Regions/Regions.idx");
Console.WriteLine("done");
}
catch
{
Console.WriteLine("failed");
}
}
private static void GenerateCrashReport(CrashedEventArgs e)
{
Console.Write("Crash: Generating report...");
try
{
string timeStamp = GetTimeStamp();
string fileName = String.Format("Crash {0}.log", timeStamp);
string root = GetRoot();
string filePath = Combine(root, fileName);
using (StreamWriter op = new StreamWriter(filePath))
{
Version ver = Core.Assembly.GetName().Version;
op.WriteLine("Server Crash Report");
op.WriteLine("===================");
op.WriteLine();
op.WriteLine("ServUO Version {0}.{1}, Build {2}.{3}", ver.Major, ver.Minor, ver.Build, ver.Revision);
op.WriteLine("Operating System: {0}", Environment.OSVersion);
op.WriteLine(".NET Framework: {0}", Environment.Version);
op.WriteLine("Time: {0}", DateTime.UtcNow);
try
{
op.WriteLine("Mobiles: {0}", World.Mobiles.Count);
}
catch
{
}
try
{
op.WriteLine("Items: {0}", World.Items.Count);
}
catch
{
}
op.WriteLine("Exception:");
op.WriteLine(e.Exception);
op.WriteLine();
op.WriteLine("Clients:");
try
{
List<NetState> states = NetState.Instances;
op.WriteLine("- Count: {0}", states.Count);
for (int i = 0; i < states.Count; ++i)
{
NetState state = states[i];
op.Write("+ {0}:", state);
Account a = state.Account as Account;
if (a != null)
op.Write(" (account = {0})", a.Username);
Mobile m = state.Mobile;
if (m != null)
op.Write(" (mobile = 0x{0:X} '{1}')", m.Serial.Value, m.Name);
op.WriteLine();
}
}
catch
{
op.WriteLine("- Failed");
}
}
Console.WriteLine("done");
if (Email.FromAddress != null && Email.CrashAddresses != null)
SendEmail(filePath);
}
catch
{
Console.WriteLine("failed");
}
}
private static string GetTimeStamp()
{
DateTime now = DateTime.UtcNow;
return String.Format("{0}-{1}-{2}-{3}-{4}-{5}",
now.Day,
now.Month,
now.Year,
now.Hour,
now.Minute,
now.Second);
}
}
}

View File

@@ -0,0 +1,50 @@
#region References
using System;
using Server.Accounting;
using Server.Network;
using Server.Services.TownCryer;
#endregion
namespace Server
{
public class CurrentExpansion
{
public static readonly Expansion Expansion = Config.GetEnum("Expansion.CurrentExpansion", Expansion.EJ);
[CallPriority(Int32.MinValue)]
public static void Configure()
{
Core.Expansion = Expansion;
AccountGold.Enabled = Core.TOL;
AccountGold.ConvertOnBank = true;
AccountGold.ConvertOnTrade = false;
VirtualCheck.UseEditGump = true;
TownCryerSystem.Enabled = Core.TOL;
ObjectPropertyList.Enabled = Core.AOS;
Mobile.InsuranceEnabled = Core.AOS && !Siege.SiegeShard;
Mobile.VisibleDamageType = Core.AOS ? VisibleDamageType.Related : VisibleDamageType.None;
Mobile.GuildClickMessage = !Core.AOS;
Mobile.AsciiClickMessage = !Core.AOS;
if (!Core.AOS)
{
return;
}
AOS.DisableStatInfluences();
if (ObjectPropertyList.Enabled)
{
PacketHandlers.SingleClickProps = true; // single click for everything is overriden to check object property list
}
Mobile.ActionDelay = Core.TOL ? 500 : Core.AOS ? 1000 : 500;
Mobile.AOSStatusHandler = AOS.GetStatus;
}
}
}

118
Scripts/Misc/DataPath.cs Normal file
View File

@@ -0,0 +1,118 @@
#region References
using System;
using System.IO;
using Microsoft.Win32;
using Ultima;
#endregion
namespace Server.Misc
{
public class DataPath
{
/* If you have not installed Ultima Online,
* or wish the server to use a separate set of datafiles,
* change the 'CustomPath' value.
* Example:
* private static string CustomPath = @"C:\Program Files\Ultima Online";
*/
private static readonly string CustomPath = Config.Get(@"DataPath.CustomPath", default(string));
static DataPath()
{
string path;
if (CustomPath != null)
{
path = CustomPath;
}
else if (!Core.Unix)
{
path = Files.LoadDirectory();
}
else
{
path = null;
}
if (!String.IsNullOrWhiteSpace(path))
{
Core.DataDirectories.Add(path);
}
}
/* The following is a list of files which a required for proper execution:
*
* Multi.idx
* Multi.mul
* VerData.mul
* TileData.mul
* Map*.mul or Map*LegacyMUL.uop
* StaIdx*.mul
* Statics*.mul
* MapDif*.mul
* MapDifL*.mul
* StaDif*.mul
* StaDifL*.mul
* StaDifI*.mul
*/
public static void Configure()
{
if (Core.DataDirectories.Count == 0 && !Core.Service)
{
Console.WriteLine("Enter the Ultima Online directory:");
Console.Write("> ");
Core.DataDirectories.Add(Console.ReadLine());
}
foreach (var path in Core.DataDirectories)
{
Files.SetMulPath(path);
}
Utility.PushColor(ConsoleColor.DarkYellow);
Console.WriteLine("DataPath: " + Core.DataDirectories[0]);
Utility.PopColor();
}
private static string GetPath(string subName, string keyName)
{
try
{
string keyString;
if (Core.Is64Bit)
keyString = @"SOFTWARE\Wow6432Node\{0}";
else
keyString = @"SOFTWARE\{0}";
using (var key = Registry.LocalMachine.OpenSubKey(String.Format(keyString, subName)))
{
if (key == null)
return null;
var v = key.GetValue(keyName) as string;
if (String.IsNullOrEmpty(v))
return null;
if (keyName == "InstallDir")
v = v + @"\";
v = Path.GetDirectoryName(v);
if (String.IsNullOrEmpty(v))
return null;
return v;
}
}
catch
{
return null;
}
}
}
}

View File

@@ -0,0 +1,9 @@
using System;
namespace Server.Misc
{
[AttributeUsage(AttributeTargets.Class)]
public class DispellableAttribute : Attribute
{
}
}

View File

@@ -0,0 +1,9 @@
using System;
namespace Server.Misc
{
[AttributeUsage(AttributeTargets.Class)]
public class DispellableFieldAttribute : Attribute
{
}
}

92
Scripts/Misc/Email.cs Normal file
View File

@@ -0,0 +1,92 @@
using System;
using System.Net.Mail;
using System.Text.RegularExpressions;
using System.Threading;
namespace Server.Misc
{
public class Email
{
/* In order to support emailing, fill in EmailServer and FromAddress:
* Example:
* public static readonly string EmailServer = "mail.domain.com";
* public static readonly string FromAddress = "runuo@domain.com";
*
* If you want to add crash reporting emailing, fill in CrashAddresses:
* Example:
* public static readonly string CrashAddresses = "first@email.here,second@email.here,third@email.here";
*
* If you want to add speech log page emailing, fill in SpeechLogPageAddresses:
* Example:
* public static readonly string SpeechLogPageAddresses = "first@email.here,second@email.here,third@email.here";
*/
public static readonly string EmailServer = Config.Get("Email.EmailServer", default(string));
public static readonly int EmailPort = Config.Get("Email.EmailPort", 25);
public static readonly bool EmailSsl = Config.Get("Email.EmailSsl", false);
public static readonly string FromAddress = Config.Get("Email.FromAddress", default(string));
public static readonly string CrashAddresses = Config.Get("Email.CrashAddresses", default(string));
public static readonly string SpeechLogPageAddresses = Config.Get("Email.SpeechLogPageAddresses", default(string));
public static readonly string EmailUsername = Config.Get("Email.EmailUsername", default(string));
public static readonly string EmailPassword = Config.Get("Email.EmailPassword", default(string));
private static readonly Regex _pattern = new Regex(@"^[a-z0-9.+_-]+@([a-z0-9-]+\.)+[a-z]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static SmtpClient _Client;
public static bool IsValid(string address)
{
if (address == null || address.Length > 320)
return false;
return _pattern.IsMatch(address);
}
public static void Configure()
{
if (EmailServer != null)
{
_Client = new SmtpClient(EmailServer, EmailPort);
if (EmailUsername != null)
{
_Client.Credentials = new System.Net.NetworkCredential(EmailUsername, EmailPassword);
}
if (EmailSsl)
_Client.EnableSsl = true;
}
}
public static bool Send(MailMessage message)
{
try
{
lock (_Client)
{
_Client.Send(message);
}
}
catch
{
return false;
}
return true;
}
public static void AsyncSend(MailMessage message)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(SendCallback), message);
}
private static void SendCallback(object state)
{
MailMessage message = (MailMessage)state;
if (Send(message))
Console.WriteLine("Sent e-mail '{0}' to '{1}'.", message.Subject, message.To);
else
Console.WriteLine("Failure sending e-mail '{0}' to '{1}'.", message.Subject, message.To);
}
}
}

713
Scripts/Misc/Emitter.cs Normal file
View File

@@ -0,0 +1,713 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace Server
{
public class AssemblyEmitter
{
private readonly string m_AssemblyName;
private readonly AppDomain m_AppDomain;
private readonly AssemblyBuilder m_AssemblyBuilder;
private readonly ModuleBuilder m_ModuleBuilder;
public AssemblyEmitter(string assemblyName, bool canSave)
{
this.m_AssemblyName = assemblyName;
this.m_AppDomain = AppDomain.CurrentDomain;
this.m_AssemblyBuilder = this.m_AppDomain.DefineDynamicAssembly(
new AssemblyName(assemblyName),
canSave ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run);
if (canSave)
{
this.m_ModuleBuilder = this.m_AssemblyBuilder.DefineDynamicModule(
assemblyName,
String.Format("{0}.dll", assemblyName.ToLower()),
false);
}
else
{
this.m_ModuleBuilder = this.m_AssemblyBuilder.DefineDynamicModule(
assemblyName,
false);
}
}
public TypeBuilder DefineType(string typeName, TypeAttributes attrs, Type parentType)
{
return this.m_ModuleBuilder.DefineType(typeName, attrs, parentType);
}
public void Save()
{
this.m_AssemblyBuilder.Save(
String.Format("{0}.dll", this.m_AssemblyName.ToLower()));
}
}
public class MethodEmitter
{
private readonly TypeBuilder m_TypeBuilder;
private MethodBuilder m_Builder;
private ILGenerator m_Generator;
private Type[] m_ArgumentTypes;
public TypeBuilder Type
{
get
{
return this.m_TypeBuilder;
}
}
public ILGenerator Generator
{
get
{
return this.m_Generator;
}
}
private class CallInfo
{
public readonly Type type;
public readonly MethodInfo method;
public int index;
public readonly ParameterInfo[] parms;
public CallInfo(Type type, MethodInfo method)
{
this.type = type;
this.method = method;
this.parms = method.GetParameters();
}
}
private readonly Stack<Type> m_Stack;
private readonly Stack<CallInfo> m_Calls;
private readonly Dictionary<Type, Queue<LocalBuilder>> m_Temps;
public MethodBuilder Method
{
get
{
return this.m_Builder;
}
}
public MethodEmitter(TypeBuilder typeBuilder)
{
this.m_TypeBuilder = typeBuilder;
this.m_Temps = new Dictionary<Type, Queue<LocalBuilder>>();
this.m_Stack = new Stack<Type>();
this.m_Calls = new Stack<CallInfo>();
}
public void Define(string name, MethodAttributes attr, Type returnType, Type[] parms)
{
this.m_Builder = this.m_TypeBuilder.DefineMethod(name, attr, returnType, parms);
this.m_Generator = this.m_Builder.GetILGenerator();
this.m_ArgumentTypes = parms;
}
public LocalBuilder CreateLocal(Type localType)
{
return this.m_Generator.DeclareLocal(localType);
}
public LocalBuilder AcquireTemp(Type localType)
{
Queue<LocalBuilder> list;
if (!this.m_Temps.TryGetValue(localType, out list))
this.m_Temps[localType] = list = new Queue<LocalBuilder>();
if (list.Count > 0)
return list.Dequeue();
return this.CreateLocal(localType);
}
public void ReleaseTemp(LocalBuilder local)
{
Queue<LocalBuilder> list;
if (!this.m_Temps.TryGetValue(local.LocalType, out list))
this.m_Temps[local.LocalType] = list = new Queue<LocalBuilder>();
list.Enqueue(local);
}
public void Branch(Label label)
{
this.m_Generator.Emit(OpCodes.Br, label);
}
public void BranchIfFalse(Label label)
{
this.Pop(typeof(object));
this.m_Generator.Emit(OpCodes.Brfalse, label);
}
public void BranchIfTrue(Label label)
{
this.Pop(typeof(object));
this.m_Generator.Emit(OpCodes.Brtrue, label);
}
public Label CreateLabel()
{
return this.m_Generator.DefineLabel();
}
public void MarkLabel(Label label)
{
this.m_Generator.MarkLabel(label);
}
public void Pop()
{
this.m_Stack.Pop();
}
public void Pop(Type expected)
{
if (expected == null)
throw new InvalidOperationException("Expected type cannot be null.");
Type onStack = this.m_Stack.Pop();
if (expected == typeof(bool))
expected = typeof(int);
if (onStack == typeof(bool))
onStack = typeof(int);
if (!expected.IsAssignableFrom(onStack))
throw new InvalidOperationException("Unexpected stack state.");
}
public void Push(Type type)
{
this.m_Stack.Push(type);
}
public void Return()
{
if (this.m_Stack.Count != (this.m_Builder.ReturnType == typeof(void) ? 0 : 1))
throw new InvalidOperationException("Stack return mismatch.");
this.m_Generator.Emit(OpCodes.Ret);
}
public void LoadNull()
{
this.LoadNull(typeof(object));
}
public void LoadNull(Type type)
{
this.Push(type);
this.m_Generator.Emit(OpCodes.Ldnull);
}
public void Load(string value)
{
this.Push(typeof(string));
if (value != null)
this.m_Generator.Emit(OpCodes.Ldstr, value);
else
this.m_Generator.Emit(OpCodes.Ldnull);
}
public void Load(Enum value)
{
int toLoad = ((IConvertible)value).ToInt32(null);
this.Load(toLoad);
this.Pop();
this.Push(value.GetType());
}
public void Load(long value)
{
this.Push(typeof(long));
this.m_Generator.Emit(OpCodes.Ldc_I8, value);
}
public void Load(float value)
{
this.Push(typeof(float));
this.m_Generator.Emit(OpCodes.Ldc_R4, value);
}
public void Load(double value)
{
this.Push(typeof(double));
this.m_Generator.Emit(OpCodes.Ldc_R8, value);
}
public void Load(char value)
{
this.Load((int)value);
this.Pop();
this.Push(typeof(char));
}
public void Load(bool value)
{
this.Push(typeof(bool));
if (value)
this.m_Generator.Emit(OpCodes.Ldc_I4_1);
else
this.m_Generator.Emit(OpCodes.Ldc_I4_0);
}
public void Load(int value)
{
this.Push(typeof(int));
switch ( value )
{
case -1:
this.m_Generator.Emit(OpCodes.Ldc_I4_M1);
break;
case 0:
this.m_Generator.Emit(OpCodes.Ldc_I4_0);
break;
case 1:
this.m_Generator.Emit(OpCodes.Ldc_I4_1);
break;
case 2:
this.m_Generator.Emit(OpCodes.Ldc_I4_2);
break;
case 3:
this.m_Generator.Emit(OpCodes.Ldc_I4_3);
break;
case 4:
this.m_Generator.Emit(OpCodes.Ldc_I4_4);
break;
case 5:
this.m_Generator.Emit(OpCodes.Ldc_I4_5);
break;
case 6:
this.m_Generator.Emit(OpCodes.Ldc_I4_6);
break;
case 7:
this.m_Generator.Emit(OpCodes.Ldc_I4_7);
break;
case 8:
this.m_Generator.Emit(OpCodes.Ldc_I4_8);
break;
default:
if (value >= sbyte.MinValue && value <= sbyte.MaxValue)
this.m_Generator.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
else
this.m_Generator.Emit(OpCodes.Ldc_I4, value);
break;
}
}
public void LoadField(FieldInfo field)
{
this.Pop(field.DeclaringType);
this.Push(field.FieldType);
this.m_Generator.Emit(OpCodes.Ldfld, field);
}
public void LoadLocal(LocalBuilder local)
{
this.Push(local.LocalType);
int index = local.LocalIndex;
switch ( index )
{
case 0:
this.m_Generator.Emit(OpCodes.Ldloc_0);
break;
case 1:
this.m_Generator.Emit(OpCodes.Ldloc_1);
break;
case 2:
this.m_Generator.Emit(OpCodes.Ldloc_2);
break;
case 3:
this.m_Generator.Emit(OpCodes.Ldloc_3);
break;
default:
if (index >= byte.MinValue && index <= byte.MinValue)
this.m_Generator.Emit(OpCodes.Ldloc_S, (byte)index);
else
this.m_Generator.Emit(OpCodes.Ldloc, (short)index);
break;
}
}
public void StoreLocal(LocalBuilder local)
{
this.Pop(local.LocalType);
this.m_Generator.Emit(OpCodes.Stloc, local);
}
public void LoadArgument(int index)
{
if (index > 0)
this.Push(this.m_ArgumentTypes[index - 1]);
else
this.Push(this.m_TypeBuilder);
switch ( index )
{
case 0:
this.m_Generator.Emit(OpCodes.Ldarg_0);
break;
case 1:
this.m_Generator.Emit(OpCodes.Ldarg_1);
break;
case 2:
this.m_Generator.Emit(OpCodes.Ldarg_2);
break;
case 3:
this.m_Generator.Emit(OpCodes.Ldarg_3);
break;
default:
if (index >= byte.MinValue && index <= byte.MaxValue)
this.m_Generator.Emit(OpCodes.Ldarg_S, (byte)index);
else
this.m_Generator.Emit(OpCodes.Ldarg, (short)index);
break;
}
}
public void CastAs(Type type)
{
this.Pop(typeof(object));
this.Push(type);
this.m_Generator.Emit(OpCodes.Isinst, type);
}
public void Neg()
{
this.Pop(typeof(int));
this.Push(typeof(int));
this.m_Generator.Emit(OpCodes.Neg);
}
public void Compare(OpCode opCode)
{
this.Pop();
this.Pop();
this.Push(typeof(int));
this.m_Generator.Emit(opCode);
}
public void LogicalNot()
{
this.Pop(typeof(int));
this.Push(typeof(int));
this.m_Generator.Emit(OpCodes.Ldc_I4_0);
this.m_Generator.Emit(OpCodes.Ceq);
}
public void Xor()
{
this.Pop(typeof(int));
this.Pop(typeof(int));
this.Push(typeof(int));
this.m_Generator.Emit(OpCodes.Xor);
}
public Type Active
{
get
{
return this.m_Stack.Peek();
}
}
public void Chain(Property prop)
{
for (int i = 0; i < prop.Chain.Length; ++i)
this.Call(prop.Chain[i].GetGetMethod());
}
public void Call(MethodInfo method)
{
this.BeginCall(method);
CallInfo call = this.m_Calls.Peek();
if (call.parms.Length > 0)
throw new InvalidOperationException("Method requires parameters.");
this.FinishCall();
}
public delegate void Callback();
public bool CompareTo(int sign, Callback argGenerator)
{
Type active = this.Active;
MethodInfo compareTo = active.GetMethod("CompareTo", new Type[] { active });
if (compareTo == null)
{
/* This gets a little tricky...
*
* There's a scenario where we might be trying to use CompareTo on an interface
* which, while it doesn't explicitly implement CompareTo itself, is said to
* extend IComparable indirectly. The implementation is implicitly passed off
* to implementers...
*
* interface ISomeInterface : IComparable
* {
* void SomeMethod();
* }
*
* class SomeClass : ISomeInterface
* {
* void SomeMethod() { ... }
* int CompareTo( object other ) { ... }
* }
*
* In this case, calling ISomeInterface.GetMethod( "CompareTo" ) will return null.
*
* Bleh.
*/
Type[] ifaces = active.FindInterfaces(delegate(Type type, object obj)
{
return (type.IsGenericType) &&
(type.GetGenericTypeDefinition() == typeof(IComparable<>)) &&
(type.GetGenericArguments()[0].IsAssignableFrom(active));
}, null);
if (ifaces.Length > 0)
{
compareTo = ifaces[0].GetMethod("CompareTo", new Type[] { active });
}
else
{
ifaces = active.FindInterfaces(delegate(Type type, object obj)
{
return (type == typeof(IComparable));
}, null);
if (ifaces.Length > 0)
compareTo = ifaces[0].GetMethod("CompareTo", new Type[] { active });
}
}
if (compareTo == null)
return false;
if (!active.IsValueType)
{
/* This object is a reference type, so we have to make it behave
*
* null.CompareTo( null ) = 0
* real.CompareTo( null ) = -1
* null.CompareTo( real ) = +1
*
*/
LocalBuilder aValue = this.AcquireTemp(active);
LocalBuilder bValue = this.AcquireTemp(active);
this.StoreLocal(aValue);
argGenerator();
this.StoreLocal(bValue);
/* if ( aValue == null )
* {
* if ( bValue == null )
* v = 0;
* else
* v = +1;
* }
* else if ( bValue == null )
* {
* v = -1;
* }
* else
* {
* v = aValue.CompareTo( bValue );
* }
*/
Label store = this.CreateLabel();
Label aNotNull = this.CreateLabel();
this.LoadLocal(aValue);
this.BranchIfTrue(aNotNull);
// if ( aValue == null )
{
Label bNotNull = this.CreateLabel();
this.LoadLocal(bValue);
this.BranchIfTrue(bNotNull);
// if ( bValue == null )
{
this.Load(0);
this.Pop(typeof(int));
this.Branch(store);
}
this.MarkLabel(bNotNull);
// else
{
this.Load(sign);
this.Pop(typeof(int));
this.Branch(store);
}
}
this.MarkLabel(aNotNull);
// else
{
Label bNotNull = this.CreateLabel();
this.LoadLocal(bValue);
this.BranchIfTrue(bNotNull);
// bValue == null
{
this.Load(-sign);
this.Pop(typeof(int));
this.Branch(store);
}
this.MarkLabel(bNotNull);
// else
{
this.LoadLocal(aValue);
this.BeginCall(compareTo);
this.LoadLocal(bValue);
this.ArgumentPushed();
this.FinishCall();
if (sign == -1)
this.Neg();
}
}
this.MarkLabel(store);
this.ReleaseTemp(aValue);
this.ReleaseTemp(bValue);
}
else
{
this.BeginCall(compareTo);
argGenerator();
this.ArgumentPushed();
this.FinishCall();
if (sign == -1)
this.Neg();
}
return true;
}
public void BeginCall(MethodInfo method)
{
Type type;
if ((method.CallingConvention & CallingConventions.HasThis) != 0)
type = this.m_Stack.Peek();
else
type = method.DeclaringType;
this.m_Calls.Push(new CallInfo(type, method));
if (type.IsValueType)
{
LocalBuilder temp = this.AcquireTemp(type);
this.m_Generator.Emit(OpCodes.Stloc, temp);
this.m_Generator.Emit(OpCodes.Ldloca, temp);
this.ReleaseTemp(temp);
}
}
public void FinishCall()
{
CallInfo call = this.m_Calls.Pop();
if ((call.type.IsValueType || call.type.IsByRef) && call.method.DeclaringType != call.type)
this.m_Generator.Emit(OpCodes.Constrained, call.type);
if (call.method.DeclaringType.IsValueType || call.method.IsStatic)
this.m_Generator.Emit(OpCodes.Call, call.method);
else
this.m_Generator.Emit(OpCodes.Callvirt, call.method);
for (int i = call.parms.Length - 1; i >= 0; --i)
this.Pop(call.parms[i].ParameterType);
if ((call.method.CallingConvention & CallingConventions.HasThis) != 0)
this.Pop(call.method.DeclaringType);
if (call.method.ReturnType != typeof(void))
this.Push(call.method.ReturnType);
}
public void ArgumentPushed()
{
CallInfo call = this.m_Calls.Peek();
ParameterInfo parm = call.parms[call.index++];
Type argumentType = this.m_Stack.Peek();
if (!parm.ParameterType.IsAssignableFrom(argumentType))
throw new InvalidOperationException("Parameter type mismatch.");
if (argumentType.IsValueType && !parm.ParameterType.IsValueType)
this.m_Generator.Emit(OpCodes.Box, argumentType);
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using Server;
using Server.Mobiles;
using Server.Items;
namespace Server.Network
{
public class EquipLastWeaponPacket
{
public static void Initialize()
{
PacketHandlers.RegisterEncoded(0x1E, true, new OnEncodedPacketReceive(EquipLastWeaponRequest));
}
public static void EquipLastWeaponRequest(NetState state, IEntity e, EncodedReader reader)
{
PlayerMobile from = state.Mobile as PlayerMobile;
if (from == null || from.Backpack == null)
return;
if (from.IsStaff() || Core.TickCount - from.NextActionTime >= 0)
{
BaseWeapon toEquip = from.LastWeapon;
BaseWeapon toDisarm = from.FindItemOnLayer(Layer.OneHanded) as BaseWeapon;
if (toDisarm == null)
toDisarm = from.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon;
if (toDisarm != null)
{
from.Backpack.DropItem(toDisarm);
from.NextActionTime = Core.TickCount + Mobile.ActionDelay;
}
if (toEquip != toDisarm && toEquip != null && toEquip.Movable && toEquip.IsChildOf(from.Backpack))
{
from.EquipItem(toEquip);
from.NextActionTime = Core.TickCount + Mobile.ActionDelay;
}
}
else
{
from.SendActionMessage();
}
}
}
}

32
Scripts/Misc/Fastwalk.cs Normal file
View File

@@ -0,0 +1,32 @@
using System;
namespace Server.Misc
{
// This fastwalk detection is no longer required
// As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds
public class Fastwalk
{
private static readonly int MaxSteps = 4;// Maximum number of queued steps until fastwalk is detected
private static readonly bool Enabled = false;// Is fastwalk detection enabled?
private static readonly bool UOTDOverride = false;// Should UO:TD clients not be checked for fastwalk?
private static readonly AccessLevel AccessOverride = AccessLevel.Decorator;// Anyone with this or higher access level is not checked for fastwalk
public static void Initialize()
{
Mobile.FwdMaxSteps = MaxSteps;
Mobile.FwdEnabled = Enabled;
Mobile.FwdUOTDOverride = UOTDOverride;
Mobile.FwdAccessOverride = AccessOverride;
if (Enabled)
EventSink.FastWalk += new FastWalkEventHandler(OnFastWalk);
}
public static void OnFastWalk(FastWalkEventArgs e)
{
e.Blocked = true;//disallow this fastwalk
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Client: {0}: Fast movement detected! (name={1})", e.NetState, e.NetState.Mobile.Name);
Utility.PopColor();
}
}
}

45
Scripts/Misc/FoodDecay.cs Normal file
View File

@@ -0,0 +1,45 @@
using System;
using Server.Network;
namespace Server.Misc
{
public class FoodDecayTimer : Timer
{
public FoodDecayTimer()
: base(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5))
{
this.Priority = TimerPriority.OneMinute;
}
public static void Initialize()
{
new FoodDecayTimer().Start();
}
public static void FoodDecay()
{
foreach (NetState state in NetState.Instances)
{
HungerDecay(state.Mobile);
ThirstDecay(state.Mobile);
}
}
public static void HungerDecay(Mobile m)
{
if (m != null && m.Hunger >= 1)
m.Hunger -= 1;
}
public static void ThirstDecay(Mobile m)
{
if (m != null && m.Thirst >= 1)
m.Thirst -= 1;
}
protected override void OnTick()
{
FoodDecay();
}
}
}

240
Scripts/Misc/Geometry.cs Normal file
View File

@@ -0,0 +1,240 @@
using System;
namespace Server.Misc
{
public delegate void DoEffect_Callback(Point3D p, Map map);
public static class Geometry
{
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
public static double RadiansToDegrees(double angle)
{
return angle * (180.0 / Math.PI);
}
public static double DegreesToRadians(double angle)
{
return angle * (Math.PI / 180.0);
}
public static Point2D ArcPoint(Point3D loc, int radius, int angle)
{
int sideA, sideB;
if (angle < 0)
angle = 0;
if (angle > 90)
angle = 90;
sideA = (int)Math.Round(radius * Math.Sin(DegreesToRadians(angle)));
sideB = (int)Math.Round(radius * Math.Cos(DegreesToRadians(angle)));
return new Point2D(loc.X - sideB, loc.Y - sideA);
}
public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect)
{
Circle2D(loc, map, radius, effect, 0, 360);
}
public static void Circle2D(Point3D loc, Map map, int radius, DoEffect_Callback effect, int angleStart, int angleEnd)
{
if (angleStart < 0 || angleStart > 360)
angleStart = 0;
if (angleEnd > 360 || angleEnd < 0)
angleEnd = 360;
if (angleStart == angleEnd)
return;
bool opposite = angleStart > angleEnd;
int startQuadrant = angleStart / 90;
int endQuadrant = angleEnd / 90;
Point2D start = ArcPoint(loc, radius, angleStart % 90);
Point2D end = ArcPoint(loc, radius, angleEnd % 90);
if (opposite)
{
Swap(ref start, ref end);
Swap(ref startQuadrant, ref endQuadrant);
}
CirclePoint startPoint = new CirclePoint(start, angleStart, startQuadrant);
CirclePoint endPoint = new CirclePoint(end, angleEnd, endQuadrant);
int error = -radius;
int x = radius;
int y = 0;
while (x > y)
{
plot4points(loc, map, x, y, startPoint, endPoint, effect, opposite);
plot4points(loc, map, y, x, startPoint, endPoint, effect, opposite);
error += (y * 2) + 1;
++y;
if (error >= 0)
{
--x;
error -= x * 2;
}
}
plot4points(loc, map, x, y, startPoint, endPoint, effect, opposite);
}
public static void plot4points(Point3D loc, Map map, int x, int y, CirclePoint start, CirclePoint end, DoEffect_Callback effect, bool opposite)
{
Point2D pointA = new Point2D(loc.X - x, loc.Y - y);
Point2D pointB = new Point2D(loc.X - y, loc.Y - x);
int quadrant = 2;
if (x == 0 && start.Quadrant == 3)
quadrant = 3;
if (WithinCircleBounds(quadrant == 3 ? pointB : pointA, quadrant, loc, start, end, opposite))
effect(new Point3D(loc.X + x, loc.Y + y, loc.Z), map);
quadrant = 3;
if (y == 0 && start.Quadrant == 0)
quadrant = 0;
if (x != 0 && WithinCircleBounds(quadrant == 0 ? pointA : pointB, quadrant, loc, start, end, opposite))
effect(new Point3D(loc.X - x, loc.Y + y, loc.Z), map);
if (y != 0 && WithinCircleBounds(pointB, 1, loc, start, end, opposite))
effect(new Point3D(loc.X + x, loc.Y - y, loc.Z), map);
if (x != 0 && y != 0 && WithinCircleBounds(pointA, 0, loc, start, end, opposite))
effect(new Point3D(loc.X - x, loc.Y - y, loc.Z), map);
}
public static bool WithinCircleBounds(Point2D pointLoc, int pointQuadrant, Point3D center, CirclePoint start, CirclePoint end, bool opposite)
{
if (start.Angle == 0 && end.Angle == 360)
return true;
int startX = start.Point.X;
int startY = start.Point.Y;
int endX = end.Point.X;
int endY = end.Point.Y;
int x = pointLoc.X;
int y = pointLoc.Y;
if (pointQuadrant < start.Quadrant || pointQuadrant > end.Quadrant)
return opposite;
if (pointQuadrant > start.Quadrant && pointQuadrant < end.Quadrant)
return !opposite;
bool withinBounds = true;
if (start.Quadrant == end.Quadrant)
{
if (startX == endX && (x > startX || y > startY || y < endY))
withinBounds = false;
else if (startY == endY && (y < startY || x < startX || x > endX))
withinBounds = false;
else if (x < startX || x > endX || y > startY || y < endY)
withinBounds = false;
}
else if (pointQuadrant == start.Quadrant && (x < startX || y > startY))
withinBounds = false;
else if (pointQuadrant == end.Quadrant && (x > endX || y < endY))
withinBounds = false;
return opposite ? !withinBounds : withinBounds;
}
public static void Line2D(Point3D start, Point3D end, Map map, DoEffect_Callback effect)
{
bool steep = Math.Abs(end.Y - start.Y) > Math.Abs(end.X - start.X);
int x0 = start.X;
int x1 = end.X;
int y0 = start.Y;
int y1 = end.Y;
if (steep)
{
Swap(ref x0, ref y0);
Swap(ref x1, ref y1);
}
if (x0 > x1)
{
Swap(ref x0, ref x1);
Swap(ref y0, ref y1);
}
int deltax = x1 - x0;
int deltay = Math.Abs(y1 - y0);
int error = deltax / 2;
int ystep = y0 < y1 ? 1 : -1;
int y = y0;
for (int x = x0; x <= x1; x++)
{
if (steep)
effect(new Point3D(y, x, start.Z), map);
else
effect(new Point3D(x, y, start.Z), map);
error -= deltay;
if (error < 0)
{
y += ystep;
error += deltax;
}
}
}
public class CirclePoint
{
private readonly Point2D point;
private readonly int angle;
private readonly int quadrant;
public CirclePoint(Point2D point, int angle, int quadrant)
{
this.point = point;
this.angle = angle;
this.quadrant = quadrant;
}
public Point2D Point
{
get
{
return this.point;
}
}
public int Angle
{
get
{
return this.angle;
}
}
public int Quadrant
{
get
{
return this.quadrant;
}
}
}
}
}

2014
Scripts/Misc/Guild.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,206 @@
#region References
using System;
using Server.Accounting;
using Server.Commands;
using Server.Gumps;
using Server.Network;
using Server.Targeting;
#endregion
namespace Server
{
[PropertyObject]
public class HardwareInfo
{
private int m_InstanceID;
private int m_OSMajor, m_OSMinor, m_OSRevision;
private int m_CpuManufacturer, m_CpuFamily, m_CpuModel, m_CpuClockSpeed, m_CpuQuantity;
private int m_PhysicalMemory;
private int m_ScreenWidth, m_ScreenHeight, m_ScreenDepth;
private int m_DXMajor, m_DXMinor;
private int m_VCVendorID, m_VCDeviceID, m_VCMemory;
private int m_Distribution, m_ClientsRunning, m_ClientsInstalled, m_PartialInstalled;
private string m_VCDescription;
private string m_Language;
private string m_Unknown;
private DateTime m_TimeReceived;
[CommandProperty(AccessLevel.GameMaster)]
public int CpuModel { get { return m_CpuModel; } }
[CommandProperty(AccessLevel.GameMaster)]
public int CpuClockSpeed { get { return m_CpuClockSpeed; } }
[CommandProperty(AccessLevel.GameMaster)]
public int CpuQuantity { get { return m_CpuQuantity; } }
[CommandProperty(AccessLevel.GameMaster)]
public int OSMajor { get { return m_OSMajor; } }
[CommandProperty(AccessLevel.GameMaster)]
public int OSMinor { get { return m_OSMinor; } }
[CommandProperty(AccessLevel.GameMaster)]
public int OSRevision { get { return m_OSRevision; } }
[CommandProperty(AccessLevel.GameMaster)]
public int InstanceID { get { return m_InstanceID; } }
[CommandProperty(AccessLevel.GameMaster)]
public int ScreenWidth { get { return m_ScreenWidth; } }
[CommandProperty(AccessLevel.GameMaster)]
public int ScreenHeight { get { return m_ScreenHeight; } }
[CommandProperty(AccessLevel.GameMaster)]
public int ScreenDepth { get { return m_ScreenDepth; } }
[CommandProperty(AccessLevel.GameMaster)]
public int PhysicalMemory { get { return m_PhysicalMemory; } }
[CommandProperty(AccessLevel.GameMaster)]
public int CpuManufacturer { get { return m_CpuManufacturer; } }
[CommandProperty(AccessLevel.GameMaster)]
public int CpuFamily { get { return m_CpuFamily; } }
[CommandProperty(AccessLevel.GameMaster)]
public int VCVendorID { get { return m_VCVendorID; } }
[CommandProperty(AccessLevel.GameMaster)]
public int VCDeviceID { get { return m_VCDeviceID; } }
[CommandProperty(AccessLevel.GameMaster)]
public int VCMemory { get { return m_VCMemory; } }
[CommandProperty(AccessLevel.GameMaster)]
public int DXMajor { get { return m_DXMajor; } }
[CommandProperty(AccessLevel.GameMaster)]
public int DXMinor { get { return m_DXMinor; } }
[CommandProperty(AccessLevel.GameMaster)]
public string VCDescription { get { return m_VCDescription; } }
[CommandProperty(AccessLevel.GameMaster)]
public string Language { get { return m_Language; } }
[CommandProperty(AccessLevel.GameMaster)]
public int Distribution { get { return m_Distribution; } }
[CommandProperty(AccessLevel.GameMaster)]
public int ClientsRunning { get { return m_ClientsRunning; } }
[CommandProperty(AccessLevel.GameMaster)]
public int ClientsInstalled { get { return m_ClientsInstalled; } }
[CommandProperty(AccessLevel.GameMaster)]
public int PartialInstalled { get { return m_PartialInstalled; } }
[CommandProperty(AccessLevel.GameMaster)]
public string Unknown { get { return m_Unknown; } }
[CommandProperty(AccessLevel.GameMaster)]
public DateTime TimeReceived { get { return m_TimeReceived; } }
public static void Initialize()
{
PacketHandlers.Register(0xD9, 0x10C, false, OnReceive);
CommandSystem.Register("HWInfo", AccessLevel.GameMaster, HWInfo_OnCommand);
}
[Usage("HWInfo")]
[Description("Displays information about a targeted player's hardware.")]
public static void HWInfo_OnCommand(CommandEventArgs e)
{
e.Mobile.BeginTarget(-1, false, TargetFlags.None, HWInfo_OnTarget);
e.Mobile.SendMessage("Target a player to view their hardware information.");
}
public static void HWInfo_OnTarget(Mobile from, object obj)
{
if (obj is Mobile && ((Mobile)obj).Player)
{
var m = (Mobile)obj;
var acct = m.Account as Account;
if (acct != null)
{
var hwInfo = acct.HardwareInfo;
if (hwInfo != null)
{
CommandLogging.WriteLine(
from,
"{0} {1} viewing hardware info of {2}",
from.AccessLevel,
CommandLogging.Format(from),
CommandLogging.Format(m));
}
if (hwInfo != null)
{
from.SendGump(new PropertiesGump(from, hwInfo));
}
else
{
from.SendMessage("No hardware information for that account was found.");
}
}
else
{
from.SendMessage("No account has been attached to that player.");
}
}
else
{
from.BeginTarget(-1, false, TargetFlags.None, HWInfo_OnTarget);
from.SendMessage("That is not a player. Try again.");
}
}
public static void OnReceive(NetState state, PacketReader pvSrc)
{
pvSrc.ReadByte(); // 1: <4.0.1a, 2>=4.0.1a
var info = new HardwareInfo
{
m_InstanceID = pvSrc.ReadInt32(),
m_OSMajor = pvSrc.ReadInt32(),
m_OSMinor = pvSrc.ReadInt32(),
m_OSRevision = pvSrc.ReadInt32(),
m_CpuManufacturer = pvSrc.ReadByte(),
m_CpuFamily = pvSrc.ReadInt32(),
m_CpuModel = pvSrc.ReadInt32(),
m_CpuClockSpeed = pvSrc.ReadInt32(),
m_CpuQuantity = pvSrc.ReadByte(),
m_PhysicalMemory = pvSrc.ReadInt32(),
m_ScreenWidth = pvSrc.ReadInt32(),
m_ScreenHeight = pvSrc.ReadInt32(),
m_ScreenDepth = pvSrc.ReadInt32(),
m_DXMajor = pvSrc.ReadInt16(),
m_DXMinor = pvSrc.ReadInt16(),
m_VCDescription = pvSrc.ReadUnicodeStringLESafe(64),
m_VCVendorID = pvSrc.ReadInt32(),
m_VCDeviceID = pvSrc.ReadInt32(),
m_VCMemory = pvSrc.ReadInt32(),
m_Distribution = pvSrc.ReadByte(),
m_ClientsRunning = pvSrc.ReadByte(),
m_ClientsInstalled = pvSrc.ReadByte(),
m_PartialInstalled = pvSrc.ReadByte(),
m_Language = pvSrc.ReadUnicodeStringLESafe(4),
m_Unknown = pvSrc.ReadStringSafe(64),
m_TimeReceived = DateTime.UtcNow
};
var acct = state.Account as Account;
if (acct != null)
{
acct.HardwareInfo = info;
}
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
namespace Server
{
public interface IDynamicEnum
{
String Value { get; set; }
String[] Values { get; }
Boolean IsValid { get; }
}
}

View File

@@ -0,0 +1,606 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Server.Misc
{
[Flags]
public enum IHSFlags
{
None = 0x00,
OnDamaged = 0x01,
OnDeath = 0x02,
OnMovement = 0x04,
OnSpeech = 0x08,
All = OnDamaged | OnDeath | OnMovement
}
// NOTE: To enable monster conversations, add " | OnSpeech" to the "All" line
public class InhumanSpeech
{
private static InhumanSpeech m_RatmanSpeech;
private static InhumanSpeech m_OrcSpeech;
private static InhumanSpeech m_LizardmanSpeech;
private static InhumanSpeech m_WispSpeech;
private string[] m_Syllables;
private string[] m_Keywords;
private string[] m_Responses;
private Dictionary<string, string> m_KeywordHash;
private int m_Hue;
private int m_Sound;
private IHSFlags m_Flags;
public InhumanSpeech()
{
}
public static InhumanSpeech Ratman
{
get
{
if (m_RatmanSpeech == null)
{
m_RatmanSpeech = new InhumanSpeech();
m_RatmanSpeech.Hue = 149;
m_RatmanSpeech.Sound = 438;
m_RatmanSpeech.Flags = IHSFlags.All;
m_RatmanSpeech.Keywords = new string[]
{
"meat", "gold", "kill", "killing", "slay",
"sword", "axe", "spell", "magic", "spells",
"swords", "axes", "mace", "maces", "monster",
"monsters", "food", "run", "escape", "away",
"help", "dead", "die", "dying", "lose",
"losing", "life", "lives", "death", "ghost",
"ghosts", "british", "blackthorn", "guild",
"guilds", "dragon", "dragons", "game", "games",
"ultima", "silly", "stupid", "dumb", "idiot",
"idiots", "cheesy", "cheezy", "crazy", "dork",
"jerk", "fool", "foolish", "ugly", "insult", "scum"
};
m_RatmanSpeech.Responses = new string[]
{
"meat", "kill", "pound", "crush", "yum yum",
"crunch", "destroy", "murder", "eat", "munch",
"massacre", "food", "monster", "evil", "run",
"die", "lose", "dumb", "idiot", "fool", "crazy",
"dinner", "lunch", "breakfast", "fight", "battle",
"doomed", "rip apart", "tear apart", "smash",
"edible?", "shred", "disembowel", "ugly", "smelly",
"stupid", "hideous", "smell", "tasty", "invader",
"attack", "raid", "plunder", "pillage", "treasure",
"loser", "lose", "scum"
};
m_RatmanSpeech.Syllables = new string[]
{
"skrit",
"ch", "ch",
"it", "ti", "it", "ti",
"ak", "ek", "ik", "ok", "uk", "yk",
"ka", "ke", "ki", "ko", "ku", "ky",
"at", "et", "it", "ot", "ut", "yt",
"cha", "che", "chi", "cho", "chu", "chy",
"ach", "ech", "ich", "och", "uch", "ych",
"att", "ett", "itt", "ott", "utt", "ytt",
"tat", "tet", "tit", "tot", "tut", "tyt",
"tta", "tte", "tti", "tto", "ttu", "tty",
"tak", "tek", "tik", "tok", "tuk", "tyk",
"ack", "eck", "ick", "ock", "uck", "yck",
"cka", "cke", "cki", "cko", "cku", "cky",
"rak", "rek", "rik", "rok", "ruk", "ryk",
"tcha", "tche", "tchi", "tcho", "tchu", "tchy",
"rach", "rech", "rich", "roch", "ruch", "rych",
"rrap", "rrep", "rrip", "rrop", "rrup", "rryp",
"ccka", "ccke", "ccki", "ccko", "ccku", "ccky"
};
}
return m_RatmanSpeech;
}
}
public static InhumanSpeech Orc
{
get
{
if (m_OrcSpeech == null)
{
m_OrcSpeech = new InhumanSpeech();
m_OrcSpeech.Hue = 34;
m_OrcSpeech.Sound = 432;
m_OrcSpeech.Flags = IHSFlags.All;
m_OrcSpeech.Keywords = new string[]
{
"meat", "gold", "kill", "killing", "slay",
"sword", "axe", "spell", "magic", "spells",
"swords", "axes", "mace", "maces", "monster",
"monsters", "food", "run", "escape", "away",
"help", "dead", "die", "dying", "lose",
"losing", "life", "lives", "death", "ghost",
"ghosts", "british", "blackthorn", "guild",
"guilds", "dragon", "dragons", "game", "games",
"ultima", "silly", "stupid", "dumb", "idiot",
"idiots", "cheesy", "cheezy", "crazy", "dork",
"jerk", "fool", "foolish", "ugly", "insult", "scum"
};
m_OrcSpeech.Responses = new string[]
{
"meat", "kill", "pound", "crush", "yum yum",
"crunch", "destroy", "murder", "eat", "munch",
"massacre", "food", "monster", "evil", "run",
"die", "lose", "dumb", "idiot", "fool", "crazy",
"dinner", "lunch", "breakfast", "fight", "battle",
"doomed", "rip apart", "tear apart", "smash",
"edible?", "shred", "disembowel", "ugly", "smelly",
"stupid", "hideous", "smell", "tasty", "invader",
"attack", "raid", "plunder", "pillage", "treasure",
"loser", "lose", "scum"
};
m_OrcSpeech.Syllables = new string[]
{
"bu", "du", "fu", "ju", "gu",
"ulg", "gug", "gub", "gur", "oog",
"gub", "log", "ru", "stu", "glu",
"ug", "ud", "og", "log", "ro", "flu",
"bo", "duf", "fun", "nog", "dun", "bog",
"dug", "gh", "ghu", "gho", "nug", "ig",
"igh", "ihg", "luh", "duh", "bug", "dug",
"dru", "urd", "gurt", "grut", "grunt",
"snarf", "urgle", "igg", "glu", "glug",
"foo", "bar", "baz", "ghat", "ab", "ad",
"gugh", "guk", "ag", "alm", "thu", "log",
"bilge", "augh", "gha", "gig", "goth",
"zug", "pig", "auh", "gan", "azh", "bag",
"hig", "oth", "dagh", "gulg", "ugh", "ba",
"bid", "gug", "bug", "rug", "hat", "brui",
"gagh", "buad", "buil", "buim", "bum",
"hug", "hug", "buo", "ma", "buor", "ghed",
"buu", "ca", "guk", "clog", "thurg", "car",
"cro", "thu", "da", "cuk", "gil", "cur", "dak",
"dar", "deak", "der", "dil", "dit", "at", "ag",
"dor", "gar", "dre", "tk", "dri", "gka", "rim",
"eag", "egg", "ha", "rod", "eg", "lat", "eichel",
"ek", "ep", "ka", "it", "ut", "ewk", "ba", "dagh",
"faugh", "foz", "fog", "fid", "fruk", "gag", "fub",
"fud", "fur", "bog", "fup", "hagh", "gaa", "kt",
"rekk", "lub", "lug", "tug", "gna", "urg", "l",
"gno", "gnu", "gol", "gom", "kug", "ukk", "jak",
"jek", "rukk", "jja", "akt", "nuk", "hok", "hrol",
"olm", "natz", "i", "i", "o", "u", "ikk", "ign",
"juk", "kh", "kgh", "ka", "hig", "ke", "ki", "klap",
"klu", "knod", "kod", "knu", "thnu", "krug", "nug",
"nar", "nag", "neg", "neh", "oag", "ob", "ogh", "oh",
"om", "dud", "oo", "pa", "hrak", "qo", "quad", "quil",
"ghig", "rur", "sag", "sah", "sg"
};
}
return m_OrcSpeech;
}
}
public static InhumanSpeech Lizardman
{
get
{
if (m_LizardmanSpeech == null)
{
m_LizardmanSpeech = new InhumanSpeech();
m_LizardmanSpeech.Hue = 58;
m_LizardmanSpeech.Sound = 418;
m_LizardmanSpeech.Flags = IHSFlags.All;
m_LizardmanSpeech.Keywords = new string[]
{
"meat", "gold", "kill", "killing", "slay",
"sword", "axe", "spell", "magic", "spells",
"swords", "axes", "mace", "maces", "monster",
"monsters", "food", "run", "escape", "away",
"help", "dead", "die", "dying", "lose",
"losing", "life", "lives", "death", "ghost",
"ghosts", "british", "blackthorn", "guild",
"guilds", "dragon", "dragons", "game", "games",
"ultima", "silly", "stupid", "dumb", "idiot",
"idiots", "cheesy", "cheezy", "crazy", "dork",
"jerk", "fool", "foolish", "ugly", "insult", "scum"
};
m_LizardmanSpeech.Responses = new string[]
{
"meat", "kill", "pound", "crush", "yum yum",
"crunch", "destroy", "murder", "eat", "munch",
"massacre", "food", "monster", "evil", "run",
"die", "lose", "dumb", "idiot", "fool", "crazy",
"dinner", "lunch", "breakfast", "fight", "battle",
"doomed", "rip apart", "tear apart", "smash",
"edible?", "shred", "disembowel", "ugly", "smelly",
"stupid", "hideous", "smell", "tasty", "invader",
"attack", "raid", "plunder", "pillage", "treasure",
"loser", "lose", "scum"
};
m_LizardmanSpeech.Syllables = new string[]
{
"ss", "sth", "iss", "is", "ith", "kth",
"sith", "this", "its", "sit", "tis", "tsi",
"ssi", "sil", "lis", "sis", "lil", "thil",
"lith", "sthi", "lish", "shi", "shash", "sal",
"miss", "ra", "tha", "thes", "ses", "sas", "las",
"les", "sath", "sia", "ais", "isa", "asi", "asth",
"stha", "sthi", "isth", "asa", "ath", "tha", "als",
"sla", "thth", "ci", "ce", "cy", "yss", "ys", "yth",
"syth", "thys", "yts", "syt", "tys", "tsy", "ssy",
"syl", "lys", "sys", "lyl", "thyl", "lyth", "sthy",
"lysh", "shy", "myss", "ysa", "sthy", "ysth"
};
}
return m_LizardmanSpeech;
}
}
public static InhumanSpeech Wisp
{
get
{
if (m_WispSpeech == null)
{
m_WispSpeech = new InhumanSpeech();
m_WispSpeech.Hue = 89;
m_WispSpeech.Sound = 466;
m_WispSpeech.Flags = IHSFlags.OnMovement;
m_WispSpeech.Syllables = new string[]
{
"b", "c", "d", "f", "g", "h", "i",
"j", "k", "l", "m", "n", "p", "r",
"s", "t", "v", "w", "x", "z", "c",
"c", "x", "x", "x", "x", "x", "y",
"y", "y", "y", "t", "t", "k", "k",
"l", "l", "m", "m", "m", "m", "z"
};
}
return m_WispSpeech;
}
}
public string[] Syllables
{
get
{
return this.m_Syllables;
}
set
{
this.m_Syllables = value;
}
}
public string[] Keywords
{
get
{
return this.m_Keywords;
}
set
{
this.m_Keywords = value;
this.m_KeywordHash = new Dictionary<string, string>(this.m_Keywords.Length, StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < this.m_Keywords.Length; ++i)
this.m_KeywordHash[this.m_Keywords[i]] = this.m_Keywords[i];
}
}
public string[] Responses
{
get
{
return this.m_Responses;
}
set
{
this.m_Responses = value;
}
}
public int Hue
{
get
{
return this.m_Hue;
}
set
{
this.m_Hue = value;
}
}
public int Sound
{
get
{
return this.m_Sound;
}
set
{
this.m_Sound = value;
}
}
public IHSFlags Flags
{
get
{
return this.m_Flags;
}
set
{
this.m_Flags = value;
}
}
public string GetRandomSyllable()
{
return this.m_Syllables[Utility.Random(this.m_Syllables.Length)];
}
public string ConstructWord(int syllableCount)
{
string[] syllables = new string[syllableCount];
for (int i = 0; i < syllableCount; ++i)
syllables[i] = this.GetRandomSyllable();
return String.Concat(syllables);
}
public string ConstructSentance(int wordCount)
{
StringBuilder sentance = new StringBuilder();
bool needUpperCase = true;
for (int i = 0; i < wordCount; ++i)
{
if (i > 0) // not first word )
{
int random = Utility.RandomMinMax(1, 15);
if (random < 11)
{
sentance.Append(' ');
}
else
{
needUpperCase = true;
if (random > 13)
sentance.Append("! ");
else
sentance.Append(". ");
}
}
int syllableCount;
if (30 > Utility.Random(100))
syllableCount = Utility.Random(1, 5);
else
syllableCount = Utility.Random(1, 3);
string word = this.ConstructWord(syllableCount);
sentance.Append(word);
if (needUpperCase)
sentance.Replace(word[0], Char.ToUpper(word[0]), sentance.Length - word.Length, 1);
needUpperCase = false;
}
if (Utility.RandomMinMax(1, 5) == 1)
sentance.Append('!');
else
sentance.Append('.');
return sentance.ToString();
}
public void SayRandomTranslate(Mobile mob, params string[] sentancesInEnglish)
{
this.SaySentance(mob, Utility.RandomMinMax(2, 3));
mob.Say(sentancesInEnglish[Utility.Random(sentancesInEnglish.Length)]);
}
public bool OnSpeech(Mobile mob, Mobile speaker, string text)
{
if ((this.m_Flags & IHSFlags.OnSpeech) == 0 || this.m_Keywords == null || this.m_Responses == null || this.m_KeywordHash == null)
return false; // not enabled
if (!speaker.Alive)
return false;
if (!speaker.InRange(mob, 3))
return false;
if ((speaker.Direction & Direction.Mask) != speaker.GetDirectionTo(mob))
return false;
if ((mob.Direction & Direction.Mask) != mob.GetDirectionTo(speaker))
return false;
string[] split = text.Split(' ');
List<string> keywordsFound = new List<string>();
for (int i = 0; i < split.Length; ++i)
{
string keyword;
this.m_KeywordHash.TryGetValue(split[i], out keyword);
if (keyword != null)
keywordsFound.Add(keyword);
}
if (keywordsFound.Count > 0)
{
string responseWord;
if (Utility.RandomBool())
responseWord = this.GetRandomResponseWord(keywordsFound);
else
responseWord = keywordsFound[Utility.Random(keywordsFound.Count)];
string secondResponseWord = this.GetRandomResponseWord(keywordsFound);
StringBuilder response = new StringBuilder();
switch ( Utility.Random(6) )
{
default:
case 0:
{
response.Append("Me ").Append(responseWord).Append('?');
break;
}
case 1:
{
response.Append(responseWord).Append(" thee!");
response.Replace(responseWord[0], Char.ToUpper(responseWord[0]), 0, 1);
break;
}
case 2:
{
response.Append(responseWord).Append('?');
response.Replace(responseWord[0], Char.ToUpper(responseWord[0]), 0, 1);
break;
}
case 3:
{
response.Append(responseWord).Append("! ").Append(secondResponseWord).Append('.');
response.Replace(responseWord[0], Char.ToUpper(responseWord[0]), 0, 1);
response.Replace(secondResponseWord[0], Char.ToUpper(secondResponseWord[0]), responseWord.Length + 2, 1);
break;
}
case 4:
{
response.Append(responseWord).Append('.');
response.Replace(responseWord[0], Char.ToUpper(responseWord[0]), 0, 1);
break;
}
case 5:
{
response.Append(responseWord).Append("? ").Append(secondResponseWord).Append('.');
response.Replace(responseWord[0], Char.ToUpper(responseWord[0]), 0, 1);
response.Replace(secondResponseWord[0], Char.ToUpper(secondResponseWord[0]), responseWord.Length + 2, 1);
break;
}
}
int maxWords = (split.Length / 2) + 1;
if (maxWords < 2)
maxWords = 2;
else if (maxWords > 6)
maxWords = 6;
this.SaySentance(mob, Utility.RandomMinMax(2, maxWords));
mob.Say(response.ToString());
return true;
}
return false;
}
public void OnDeath(Mobile mob)
{
if ((this.m_Flags & IHSFlags.OnDeath) == 0)
return; // not enabled
if (90 > Utility.Random(100))
return; // 90% chance to do nothing; 10% chance to talk
this.SayRandomTranslate(mob,
"Revenge!",
"NOOooo!",
"I... I...",
"Me no die!",
"Me die!",
"Must... not die...",
"Oooh, me hurt...",
"Me dying?");
}
public void OnMovement(Mobile mob, Mobile mover, Point3D oldLocation)
{
if ((this.m_Flags & IHSFlags.OnMovement) == 0)
return; // not enabled
if (!mover.Player || (mover.Hidden && mover.IsStaff()))
return;
if (!mob.InRange(mover, 5) || mob.InRange(oldLocation, 5))
return; // only talk when they enter 5 tile range
if (90 > Utility.Random(100))
return; // 90% chance to do nothing; 10% chance to talk
this.SaySentance(mob, 6);
}
public void OnDamage(Mobile mob, int amount)
{
if ((this.m_Flags & IHSFlags.OnDamaged) == 0)
return; // not enabled
if (90 > Utility.Random(100))
return; // 90% chance to do nothing; 10% chance to talk
if (amount < 5)
{
this.SayRandomTranslate(mob,
"Ouch!",
"Me not hurt bad!",
"Thou fight bad.",
"Thy blows soft!",
"You bad with weapon!");
}
else
{
this.SayRandomTranslate(mob,
"Ouch! Me hurt!",
"No, kill me not!",
"Me hurt!",
"Away with thee!",
"Oof! That hurt!",
"Aaah! That hurt...",
"Good blow!");
}
}
public void OnConstruct(Mobile mob)
{
mob.SpeechHue = this.m_Hue;
}
public void SaySentance(Mobile mob, int wordCount)
{
mob.Say(this.ConstructSentance(wordCount));
mob.PlaySound(this.m_Sound);
}
private string GetRandomResponseWord(List<string> keywordsFound)
{
int random = Utility.Random(keywordsFound.Count + this.m_Responses.Length);
if (random < keywordsFound.Count)
return keywordsFound[random];
return this.m_Responses[random - keywordsFound.Count];
}
}
}

67
Scripts/Misc/Keywords.cs Normal file
View File

@@ -0,0 +1,67 @@
using System;
using Server.Guilds;
using Server.Gumps;
using Server.Mobiles;
namespace Server.Misc
{
public class Keywords
{
public static void Initialize()
{
// Register our speech handler
EventSink.Speech += EventSink_Speech;
}
public static void EventSink_Speech(SpeechEventArgs args)
{
Mobile from = args.Mobile;
int[] keywords = args.Keywords;
for (int i = 0; i < keywords.Length; ++i)
{
switch (keywords[i])
{
case 0x002A: // *i resign from my guild*
{
if (from.Guild != null)
((Guild)from.Guild).RemoveMember(from);
break;
}
case 0x0032: // *i must consider my sins*
{
if (!Core.SE)
{
from.SendMessage("Short Term Murders : {0}", from.ShortTermMurders);
from.SendMessage("Long Term Murders : {0}", from.Kills);
}
else
{
from.SendMessage(0x3B2, "Short Term Murders: {0} Long Term Murders: {1}", from.ShortTermMurders, from.Kills);
}
break;
}
case 0x0035: // i renounce my young player status*
{
if (from is PlayerMobile && ((PlayerMobile)from).Young && !from.HasGump(typeof(RenounceYoungGump)))
{
from.SendGump(new RenounceYoungGump());
}
break;
}
case 0x6: // guild
{
if (from is PlayerMobile && from.Guild != null)
{
((PlayerMobile)from).SendGump(new GuildInfoGump((PlayerMobile)from, from.Guild as Guild));
}
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,406 @@
using System;
using System.Collections.Generic;
using System.IO;
using Server.Accounting;
using Server.Commands;
namespace Server.Misc
{
/**
* This file requires to be saved in a Unicode
* compatible format.
*
* Warning: if you change String.Format methods,
* please note that the following character
* is suggested before any left-to-right text
* in order to prevent undesired formatting
* resulting from mixing LR and RL text:
*
* Use this one if you need to force RL:
*
* If you do not see the above chars, please
* enable showing of unicode control chars
**/
public class LanguageStatistics
{
private static readonly InternationalCode[] InternationalCodes =
{
new InternationalCode("ARA", "Arabic", "Saudi Arabia", "العربية", "السعودية"),
new InternationalCode("ARI", "Arabic", "Iraq", "العربية", "العراق"),
new InternationalCode("ARE", "Arabic", "Egypt", "العربية", "مصر"),
new InternationalCode("ARL", "Arabic", "Libya", "العربية", "ليبيا"),
new InternationalCode("ARG", "Arabic", "Algeria", "العربية", "الجزائر"),
new InternationalCode("ARM", "Arabic", "Morocco", "العربية", "المغرب"),
new InternationalCode("ART", "Arabic", "Tunisia", "العربية", "تونس"),
new InternationalCode("ARO", "Arabic", "Oman", "العربية", "عمان"),
new InternationalCode("ARY", "Arabic", "Yemen", "العربية", "اليمن"),
new InternationalCode("ARS", "Arabic", "Syria", "العربية", "سورية"),
new InternationalCode("ARJ", "Arabic", "Jordan", "العربية", "الأردن"),
new InternationalCode("ARB", "Arabic", "Lebanon", "العربية", "لبنان"),
new InternationalCode("ARK", "Arabic", "Kuwait", "العربية", "الكويت"),
new InternationalCode("ARU", "Arabic", "U.A.E.", "العربية", "الامارات"),
new InternationalCode("ARH", "Arabic", "Bahrain", "العربية", "البحرين"),
new InternationalCode("ARQ", "Arabic", "Qatar", "العربية", "قطر"),
new InternationalCode("BGR", "Bulgarian", "Bulgaria", "Български", "България"),
new InternationalCode("CAT", "Catalan", "Spain", "Català", "Espanya"),
new InternationalCode("CHT", "Chinese", "Taiwan", "台語", "臺灣"),
new InternationalCode("CHS", "Chinese", "PRC", "中文", "中国"),
new InternationalCode("ZHH", "Chinese", "Hong Kong", "中文", "香港"),
new InternationalCode("ZHI", "Chinese", "Singapore", "中文", "新加坡"),
new InternationalCode("ZHM", "Chinese", "Macau", "中文", "澳門"),
new InternationalCode("CSY", "Czech", "Czech Republic", "Čeština", "Česká republika"),
new InternationalCode("DAN", "Danish", "Denmark", "Dansk", "Danmark"),
new InternationalCode("DEU", "German", "Germany", "Deutsch", "Deutschland"),
new InternationalCode("DES", "German", "Switzerland", "Deutsch", "der Schweiz"),
new InternationalCode("DEA", "German", "Austria", "Deutsch", "Österreich"),
new InternationalCode("DEL", "German", "Luxembourg", "Deutsch", "Luxembourg"),
new InternationalCode("DEC", "German", "Liechtenstein", "Deutsch", "Liechtenstein"),
new InternationalCode("ELL", "Greek", "Greece", "Ελληνικά", "Ελλάδα"),
new InternationalCode("ENU", "English", "United States"),
new InternationalCode("ENG", "English", "United Kingdom"),
new InternationalCode("ENA", "English", "Australia"),
new InternationalCode("ENC", "English", "Canada"),
new InternationalCode("ENZ", "English", "New Zealand"),
new InternationalCode("ENI", "English", "Ireland"),
new InternationalCode("ENS", "English", "South Africa"),
new InternationalCode("ENJ", "English", "Jamaica"),
new InternationalCode("ENB", "English", "Caribbean"),
new InternationalCode("ENL", "English", "Belize"),
new InternationalCode("ENT", "English", "Trinidad"),
new InternationalCode("ENW", "English", "Zimbabwe"),
new InternationalCode("ENP", "English", "Philippines"),
new InternationalCode("ESP", "Spanish", "Spain (Traditional Sort)", "Español", "España (tipo tradicional)"),
new InternationalCode("ESM", "Spanish", "Mexico", "Español", "México"),
new InternationalCode("ESN", "Spanish", "Spain (International Sort)", "Español", "España (tipo internacional)"),
new InternationalCode("ESG", "Spanish", "Guatemala", "Español", "Guatemala"),
new InternationalCode("ESC", "Spanish", "Costa Rica", "Español", "Costa Rica"),
new InternationalCode("ESA", "Spanish", "Panama", "Español", "Panama"),
new InternationalCode("ESD", "Spanish", "Dominican Republic", "Español", "Republica Dominicana"),
new InternationalCode("ESV", "Spanish", "Venezuela", "Español", "Venezuela"),
new InternationalCode("ESO", "Spanish", "Colombia", "Español", "Colombia"),
new InternationalCode("ESR", "Spanish", "Peru", "Español", "Peru"),
new InternationalCode("ESS", "Spanish", "Argentina", "Español", "Argentina"),
new InternationalCode("ESF", "Spanish", "Ecuador", "Español", "Ecuador"),
new InternationalCode("ESL", "Spanish", "Chile", "Español", "Chile"),
new InternationalCode("ESY", "Spanish", "Uruguay", "Español", "Uruguay"),
new InternationalCode("ESZ", "Spanish", "Paraguay", "Español", "Paraguay"),
new InternationalCode("ESB", "Spanish", "Bolivia", "Español", "Bolivia"),
new InternationalCode("ESE", "Spanish", "El Salvador", "Español", "El Salvador"),
new InternationalCode("ESH", "Spanish", "Honduras", "Español", "Honduras"),
new InternationalCode("ESI", "Spanish", "Nicaragua", "Español", "Nicaragua"),
new InternationalCode("ESU", "Spanish", "Puerto Rico", "Español", "Puerto Rico"),
new InternationalCode("FIN", "Finnish", "Finland", "Suomi", "Suomi"),
new InternationalCode("FRA", "French", "France", "Français", "France"),
new InternationalCode("FRB", "French", "Belgium", "Français", "Belgique"),
new InternationalCode("FRC", "French", "Canada", "Français", "Canada"),
new InternationalCode("FRS", "French", "Switzerland", "Français", "Suisse"),
new InternationalCode("FRL", "French", "Luxembourg", "Français", "Luxembourg"),
new InternationalCode("FRM", "French", "Monaco", "Français", "Monaco"),
new InternationalCode("HEB", "Hebrew", "Israel", "עִבְרִית", "ישׂראל"),
new InternationalCode("HUN", "Hungarian", "Hungary", "Magyar", "Magyarország"),
new InternationalCode("ISL", "Icelandic", "Iceland", "Íslenska", "Ísland"),
new InternationalCode("ITA", "Italian", "Italy", "Italiano", "Italia"),
new InternationalCode("ITS", "Italian", "Switzerland", "Italiano", "Svizzera"),
new InternationalCode("JPN", "Japanese", "Japan", "日本語", "日本"),
new InternationalCode("KOR", "Korean (Extended Wansung)", "Korea", "한국어", "한국"),
new InternationalCode("NLD", "Dutch", "Netherlands", "Nederlands", "Nederland"),
new InternationalCode("NLB", "Dutch", "Belgium", "Nederlands", "België"),
new InternationalCode("NOR", "Norwegian", "Norway (Bokmål)", "Norsk", "Norge (Bokmål)"),
new InternationalCode("NON", "Norwegian", "Norway (Nynorsk)", "Norsk", "Norge (Nynorsk)"),
new InternationalCode("PLK", "Polish", "Poland", "Polski", "Polska"),
new InternationalCode("PTB", "Portuguese", "Brazil", "Português", "Brasil"),
new InternationalCode("PTG", "Portuguese", "Portugal", "Português", "Brasil"),
new InternationalCode("ROM", "Romanian", "Romania", "Limba Română", "România"),
new InternationalCode("RUS", "Russian", "Russia", "Русский", "Россия"),
new InternationalCode("HRV", "Croatian", "Croatia", "Hrvatski", "Hrvatska"),
new InternationalCode("SRL", "Serbian", "Serbia (Latin)", "Srpski", "Srbija i Crna Gora"),
new InternationalCode("SRB", "Serbian", "Serbia (Cyrillic)", "Српски", "Србија и Црна Гора"),
new InternationalCode("SKY", "Slovak", "Slovakia", "Slovenčina", "Slovensko"),
new InternationalCode("SQI", "Albanian", "Albania", "Shqip", "Shqipëria"),
new InternationalCode("SVE", "Swedish", "Sweden", "Svenska", "Sverige"),
new InternationalCode("SVF", "Swedish", "Finland", "Svenska", "Finland"),
new InternationalCode("THA", "Thai", "Thailand", "ภาษาไทย", "ประเทศไทย"),
new InternationalCode("TRK", "Turkish", "Turkey", "Türkçe", "Türkiye"),
new InternationalCode("URP", "Urdu", "Pakistan", "اردو", "پاکستان"),
new InternationalCode("IND", "Indonesian", "Indonesia", "Bahasa Indonesia", "Indonesia"),
new InternationalCode("UKR", "Ukrainian", "Ukraine", "Українська", "Украина"),
new InternationalCode("BEL", "Belarusian", "Belarus", "Беларускі", "Беларусь"),
new InternationalCode("SLV", "Slovene", "Slovenia", "Slovenščina", "Slovenija"),
new InternationalCode("ETI", "Estonian", "Estonia", "Eesti", "Eesti"),
new InternationalCode("LVI", "Latvian", "Latvia", "Latviešu", "Latvija"),
new InternationalCode("LTH", "Lithuanian", "Lithuania", "Lietuvių", "Lietuva"),
new InternationalCode("LTC", "Classic Lithuanian", "Lithuania", "Lietuviškai", "Lietuva"),
new InternationalCode("FAR", "Farsi", "Iran", "فارسى", "ايران"),
new InternationalCode("VIT", "Vietnamese", "Viet Nam", "tiếng Việt", "Việt Nam"),
new InternationalCode("HYE", "Armenian", "Armenia", "Հայերէն", "Հայաստան"),
new InternationalCode("AZE", "Azeri", "Azerbaijan (Latin)", "Azərbaycanca", "Azərbaycan"),
new InternationalCode("AZE", "Azeri", "Azerbaijan (Cyrillic)", "Азәрбајҹанҹа", "Азәрбајҹан"),
new InternationalCode("EUQ", "Basque", "Spain", "Euskera", "Espainia"),
new InternationalCode("MKI", "Macedonian", "Macedonia", "Македонски", "Македонија"),
new InternationalCode("AFK", "Afrikaans", "South Africa", "Afrikaans", "Republiek van Suid-Afrika"),
new InternationalCode("KAT", "Georgian", "Georgia", "ქართული", "საკარტველო"),
new InternationalCode("FOS", "Faeroese", "Faeroe Islands", "Føroyska", "Føroya"),
new InternationalCode("HIN", "Hindi", "India", "हिन्दी", "भारत"),
new InternationalCode("MSL", "Malay", "Malaysia", "Bahasa melayu", "Malaysia"),
new InternationalCode("MSB", "Malay", "Brunei Darussalam", "Bahasa melayu", "Negara Brunei Darussalam"),
new InternationalCode("KAZ", "Kazak", "Kazakstan", "Қазақ", "Қазақстан"),
new InternationalCode("SWK", "Swahili", "Kenya", "Kiswahili", "Kenya"),
new InternationalCode("UZB", "Uzbek", "Uzbekistan (Latin)", "O'zbek", "O'zbekiston"),
new InternationalCode("UZB", "Uzbek", "Uzbekistan (Cyrillic)", "Ўзбек", "Ўзбекистон"),
new InternationalCode("TAT", "Tatar", "Tatarstan", "Татарча", "Татарстан"),
new InternationalCode("BEN", "Bengali", "India", "বাংলা", "ভারত"),
new InternationalCode("PAN", "Punjabi", "India", "ਪੰਜਾਬੀ", "ਭਾਰਤ"),
new InternationalCode("GUJ", "Gujarati", "India", "ગુજરાતી", "ભારત"),
new InternationalCode("ORI", "Oriya", "India", "ଓଡ଼ିଆ", "ଭାରତ"),
new InternationalCode("TAM", "Tamil", "India", "தமிழ்", "இந்தியா"),
new InternationalCode("TEL", "Telugu", "India", "తెలుగు", "భారత"),
new InternationalCode("KAN", "Kannada", "India", "ಕನ್ನಡ", "ಭಾರತ"),
new InternationalCode("MAL", "Malayalam", "India", "മലയാളം", "ഭാരത"),
new InternationalCode("ASM", "Assamese", "India", "অসমিয়া", "Bhārat"), // missing correct country name
new InternationalCode("MAR", "Marathi", "India", "मराठी", "भारत"),
new InternationalCode("SAN", "Sanskrit", "India", "संस्कृत", "भारतम्"),
new InternationalCode("KOK", "Konkani", "India", "कोंकणी", "भारत")
};
private static readonly bool DefaultLocalNames = false;
private static readonly bool ShowAlternatives = true;
private static readonly bool CountAccounts = true;// will consider only first character's valid language
public static void Initialize()
{
CommandSystem.Register("LanguageStatistics", AccessLevel.Administrator, new CommandEventHandler(LanguageStatistics_OnCommand));
}
[Usage("LanguageStatistics")]
[Description("Generate a file containing the list of languages for each PlayerMobile.")]
public static void LanguageStatistics_OnCommand(CommandEventArgs e)
{
Dictionary<string, InternationalCodeCounter> ht = new Dictionary<string, InternationalCodeCounter>();
using (StreamWriter writer = new StreamWriter("languages.txt"))
{
if (CountAccounts)
{
// count accounts
foreach (Account acc in Accounts.GetAccounts())
{
for (int i = 0; i < acc.Length; i++)
{
Mobile mob = acc[i];
if (mob == null)
continue;
string lang = mob.Language;
if (lang != null)
{
lang = lang.ToUpper();
if (!ht.ContainsKey(lang))
ht[lang] = new InternationalCodeCounter(lang);
else
ht[lang].Increase();
break;
}
}
}
}
else
{
// count playermobiles
foreach (Mobile mob in World.Mobiles.Values)
{
if (mob.Player)
{
string lang = mob.Language;
if (lang != null)
{
lang = lang.ToUpper();
if (!ht.ContainsKey(lang))
ht[lang] = new InternationalCodeCounter(lang);
else
ht[lang].Increase();
}
}
}
}
writer.WriteLine(String.Format("Language statistics. Numbers show how many {0} use the specified language.", CountAccounts ? "accounts" : "playermobile"));
writer.WriteLine("====================================================================================================");
writer.WriteLine();
// sort the list
List<InternationalCodeCounter> list = new List<InternationalCodeCounter>(ht.Values);
list.Sort(InternationalCodeComparer.Instance);
foreach (InternationalCodeCounter c in list)
writer.WriteLine(String.Format("{0} : {1}", GetFormattedInfo(c.Code), c.Count));
e.Mobile.SendMessage("Languages list generated.");
}
}
private static string GetFormattedInfo(string code)
{
if (code == null || code.Length != 3)
return String.Format("Unknown code {0}", code);
for (int i = 0; i < InternationalCodes.Length; i++)
{
if (code == InternationalCodes[i].Code)
{
return String.Format("{0}", InternationalCodes[i].GetName());
}
}
return String.Format("Unknown code {0}", code);
}
struct InternationalCode
{
readonly string m_Code;
readonly string m_Language;
readonly string m_Country;
readonly string m_Language_LocalName;
readonly string m_Country_LocalName;
readonly bool m_HasLocalInfo;
public InternationalCode(string code, string language, string country)
: this(code, language, country, null, null)
{
this.m_HasLocalInfo = false;
}
public InternationalCode(string code, string language, string country, string language_localname, string country_localname)
{
this.m_Code = code;
this.m_Language = language;
this.m_Country = country;
this.m_Language_LocalName = language_localname;
this.m_Country_LocalName = country_localname;
this.m_HasLocalInfo = true;
}
public string Code
{
get
{
return this.m_Code;
}
}
public string Language
{
get
{
return this.m_Language;
}
}
public string Country
{
get
{
return this.m_Country;
}
}
public string Language_LocalName
{
get
{
return this.m_Language_LocalName;
}
}
public string Country_LocalName
{
get
{
return this.m_Country_LocalName;
}
}
public string GetName()
{
string s;
if (this.m_HasLocalInfo)
{
s = String.Format("{0} - {1}", DefaultLocalNames ? this.m_Language_LocalName : this.m_Language, DefaultLocalNames ? this.m_Country_LocalName : this.m_Country);
if (ShowAlternatives)
s += String.Format(" 【{0} - {1}‎】", DefaultLocalNames ? this.m_Language : this.m_Language_LocalName, DefaultLocalNames ? this.m_Country : this.m_Country_LocalName);
}
else
{
s = String.Format("{0} - {1}", this.m_Language, this.m_Country);
}
return s;
}
}
private class InternationalCodeCounter
{
private readonly string m_Code;
private int m_Count;
public InternationalCodeCounter(string code)
{
this.m_Code = code;
this.m_Count = 1;
}
public string Code
{
get
{
return this.m_Code;
}
}
public int Count
{
get
{
return this.m_Count;
}
}
public void Increase()
{
this.m_Count++;
}
}
private class InternationalCodeComparer : IComparer<InternationalCodeCounter>
{
public static readonly InternationalCodeComparer Instance = new InternationalCodeComparer();
public InternationalCodeComparer()
{
}
public int Compare(InternationalCodeCounter x, InternationalCodeCounter y)
{
string a = null, b = null;
int ca = 0, cb = 0;
a = x.Code;
ca = x.Count;
b = y.Code;
cb = y.Count;
if (ca > cb)
return -1;
if (ca < cb)
return 1;
if (a == null && b == null)
return 0;
if (a == null)
return 1;
if (b == null)
return -1;
return a.CompareTo(b);
}
}
}
}

157
Scripts/Misc/LightCycle.cs Normal file
View File

@@ -0,0 +1,157 @@
#region References
using System;
using Server.Commands;
using Server.Items;
using Server.Network;
#endregion
namespace Server
{
public static class LightCycle
{
public const int DayLevel = 0;
public const int NightLevel = 12;
public const int DungeonLevel = 26;
public const int JailLevel = 9;
private static int _LevelOverride = Int32.MinValue;
public static int LevelOverride
{
get { return _LevelOverride; }
set
{
_LevelOverride = value;
CheckLightLevels();
}
}
public static void Initialize()
{
new LightCycleTimer(Clock.SecondsPerUOMinute).Start();
EventSink.Login += OnLogin;
CommandSystem.Register("GlobalLight", AccessLevel.GameMaster, Light_OnCommand);
}
public static void OnLogin(LoginEventArgs args)
{
var m = args.Mobile;
if (m != null)
m.CheckLightLevels(true);
}
public static int ComputeLevelFor(Mobile from)
{
if (_LevelOverride > int.MinValue)
return _LevelOverride;
int hours, minutes;
Clock.GetTime(from.Map, from.X, from.Y, out hours, out minutes);
/* OSI times:
*
* Midnight -> 3:59 AM : Night
* 4:00 AM -> 11:59 PM : Day
*
* RunUO times:
*
* 10:00 PM -> 11:59 PM : Scale to night
* Midnight -> 3:59 AM : Night
* 4:00 AM -> 5:59 AM : Scale to day
* 6:00 AM -> 9:59 PM : Day
*/
if (hours < 4)
return NightLevel;
if (hours < 6)
return NightLevel + (((((hours - 4) * 60) + minutes) * (DayLevel - NightLevel)) / 120);
if (hours < 22)
return DayLevel;
if (hours < 24)
return DayLevel + (((((hours - 22) * 60) + minutes) * (NightLevel - DayLevel)) / 120);
return NightLevel; // should never be
}
public static void CheckLightLevels()
{
var i = NetState.Instances.Count;
while (--i >= 0)
{
if (i >= NetState.Instances.Count)
continue;
var ns = NetState.Instances[i];
if (ns == null)
continue;
var m = ns.Mobile;
if (m != null)
m.CheckLightLevels(false);
}
}
[Usage("GlobalLight <value>")]
[Description("Sets the current global light level.")]
private static void Light_OnCommand(CommandEventArgs e)
{
if (e.Length >= 1)
{
LevelOverride = e.GetInt32(0);
e.Mobile.SendMessage("Global light level override has been changed to {0}.", _LevelOverride);
}
else
{
LevelOverride = int.MinValue;
e.Mobile.SendMessage("Global light level override has been cleared.");
}
}
public class NightSightTimer : Timer
{
private readonly Mobile m_Owner;
public NightSightTimer(Mobile owner)
: base(TimeSpan.FromMinutes(Utility.Random(15, 25)))
{
m_Owner = owner;
Priority = TimerPriority.OneMinute;
}
protected override void OnTick()
{
m_Owner.EndAction(typeof(LightCycle));
m_Owner.LightLevel = 0;
BuffInfo.RemoveBuff(m_Owner, BuffIcon.NightSight);
}
}
private class LightCycleTimer : Timer
{
public LightCycleTimer(double interval)
: base(TimeSpan.Zero, TimeSpan.FromSeconds(interval))
{
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
CheckLightLevels();
}
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using Server.Network;
using Server.Engines.Quests;
using Server.Mobiles;
using System.Collections.Generic;
using System.Linq;
namespace Server.Misc
{
public class LoginStats
{
public static void Initialize()
{
// Register our event handler
EventSink.Login += new LoginEventHandler(EventSink_Login);
}
private static void EventSink_Login(LoginEventArgs args)
{
int userCount = NetState.Instances.Count;
int itemCount = World.Items.Count;
int mobileCount = World.Mobiles.Count;
Mobile m = args.Mobile;
m.SendMessage("Welcome, {0}! There {1} currently {2} user{3} online, with {4} item{5} and {6} mobile{7} in the world.",
args.Mobile.Name,
userCount == 1 ? "is" : "are",
userCount, userCount == 1 ? "" : "s",
itemCount, itemCount == 1 ? "" : "s",
mobileCount, mobileCount == 1 ? "" : "s");
if (m.IsStaff())
{
Server.Engines.Help.PageQueue.Pages_OnCalled(m);
}
}
}
}

1084
Scripts/Misc/Loot.cs Normal file

File diff suppressed because it is too large Load Diff

1140
Scripts/Misc/LootPack.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
using System;
namespace Server.Misc
{
public class MapDefinitions
{
public static void Configure()
{
/* Here we configure all maps. Some notes:
*
* 1) The first 32 maps are reserved for core use.
* 2) Map 0x7F is reserved for core use.
* 3) Map 0xFF is reserved for core use.
* 4) Changing or removing any predefined maps may cause server instability.
*/
if (Siege.SiegeShard)
{
RegisterMap(0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules);
RegisterMap(1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.FeluccaRules);
RegisterMap(2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.FeluccaRules);
RegisterMap(3, 3, 3, 2560, 2048, 1, "Malas", MapRules.FeluccaRules);
RegisterMap(4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.FeluccaRules);
RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.FeluccaRules);
}
else
{
RegisterMap(0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules);
RegisterMap(1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.TrammelRules);
RegisterMap(2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.TrammelRules);
RegisterMap(3, 3, 3, 2560, 2048, 1, "Malas", MapRules.TrammelRules);
RegisterMap(4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.TrammelRules);
RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.TrammelRules);
RegisterMap(32, 0, 0, 7168, 4096, 4, "Shattered Lands", MapRules.FeluccaRules);
RegisterMap(33, 1, 1, 7168, 4096, 0, "Sosaria", MapRules.TrammelRules);
RegisterMap(34, 2, 2, 2304, 1600, 1, "Valaria", MapRules.TrammelRules);
RegisterMap(35, 3, 3, 2560, 2048, 1, "Agearis", MapRules.TrammelRules);
//RegisterMap(4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.TrammelRules);
//RegisterMap(5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.TrammelRules);
}
RegisterMap(0x7F, 0x7F, 0x7F, Map.SectorSize, Map.SectorSize, 1, "Internal", MapRules.Internal);
//RegisterMap(35, 9, 9, 2560, 2048, 3, "Atlantis", MapRules.TrammelRules);
/* Example of registering a custom map:
* RegisterMap( 32, 0, 0, 6144, 4096, 3, "Iceland", MapRules.FeluccaRules );
*
* Defined:
* RegisterMap( <index>, <mapID>, <fileIndex>, <width>, <height>, <season>, <name>, <rules> );
* - <index> : An unreserved unique index for this map
* - <mapID> : An identification number used in client communications. For any visible maps, this value must be from 0-5
* - <fileIndex> : A file identification number. For any visible maps, this value must be from 0-5
* - <width>, <height> : Size of the map (in tiles)
* - <season> : Season of the map. 0 = Spring, 1 = Summer, 2 = Fall, 3 = Winter, 4 = Desolation
* - <name> : Reference name for the map, used in props gump, get/set commands, region loading, etc
* - <rules> : Rules and restrictions associated with the map. See documentation for details
*/
TileMatrixPatch.Enabled = false; // OSI Client Patch 6.0.0.0
MultiComponentList.PostHSFormat = true; // OSI Client Patch 7.0.9.0
}
public static void RegisterMap(int mapIndex, int mapID, int fileIndex, int width, int height, int season, string name, MapRules rules)
{
Map newMap = new Map(mapID, mapIndex, fileIndex, width, height, season, name, rules);
Map.Maps[mapIndex] = newMap;
Map.AllMaps.Add(newMap);
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using Server.Network;
namespace Server
{
public class MessageHelper
{
public static void SendLocalizedMessageTo(Item from, Mobile to, int number, int hue)
{
SendLocalizedMessageTo(from, to, number, "", hue);
}
public static void SendLocalizedMessageTo(Item from, Mobile to, int number, string args, int hue)
{
to.Send(new MessageLocalized(from.Serial, from.ItemID, MessageType.Regular, hue, 3, number, "", args));
}
}
}

116
Scripts/Misc/NameList.cs Normal file
View File

@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
namespace Server
{
public class NameList
{
private static Dictionary<string, NameList> m_Table;
private readonly string m_Type;
private readonly string[] m_List;
public NameList(string type, XmlElement xml)
{
this.m_Type = type;
this.m_List = xml.InnerText.Split(',');
for (int i = 0; i < this.m_List.Length; ++i)
this.m_List[i] = Utility.Intern(this.m_List[i].Trim());
}
static NameList()
{
m_Table = new Dictionary<string, NameList>(StringComparer.OrdinalIgnoreCase);
string filePath = Path.Combine(Core.BaseDirectory, "Data/names.xml");
if (!File.Exists(filePath))
return;
try
{
Load(filePath);
}
catch (Exception e)
{
Console.WriteLine("Warning: Exception caught loading name lists:");
Console.WriteLine(e);
}
}
public string Type
{
get
{
return this.m_Type;
}
}
public string[] List
{
get
{
return this.m_List;
}
}
public static NameList GetNameList(string type)
{
NameList n = null;
m_Table.TryGetValue(type, out n);
return n;
}
public static string RandomName(string type)
{
NameList list = GetNameList(type);
if (list != null)
return list.GetRandomName();
return "";
}
public bool ContainsName(string name)
{
for (int i = 0; i < this.m_List.Length; i++)
if (name == this.m_List[i])
return true;
return false;
}
public string GetRandomName()
{
if (this.m_List.Length > 0)
return this.m_List[Utility.Random(this.m_List.Length)];
return "";
}
private static void Load(string filePath)
{
XmlDocument doc = new XmlDocument();
doc.Load(filePath);
XmlElement root = doc["names"];
foreach (XmlElement element in root.GetElementsByTagName("namelist"))
{
string type = element.GetAttribute("type");
if (String.IsNullOrEmpty(type))
continue;
try
{
NameList list = new NameList(type, element);
m_Table[type] = list;
}
catch
{
}
}
}
}
}

View File

@@ -0,0 +1,213 @@
using System;
using Server.Commands;
namespace Server.Misc
{
public class NameVerification
{
public static readonly char[] SpaceDashPeriodQuote = new char[]
{
' ', '-', '.', '\''
};
public static readonly char[] Empty = new char[0];
private static readonly string[] m_StartDisallowed = new string[]
{
"seer",
"counselor",
"gm",
"admin",
"lady",
"lord"
};
private static readonly string[] m_Disallowed = new string[]
{
"jigaboo",
"chigaboo",
"wop",
"kyke",
"kike",
"tit",
"spic",
"prick",
"piss",
"lezbo",
"lesbo",
"felatio",
"dyke",
"dildo",
"chinc",
"chink",
"cunnilingus",
"cum",
"cocksucker",
"cock",
"clitoris",
"clit",
"ass",
"hitler",
"penis",
"nigga",
"nigger",
"klit",
"kunt",
"jiz",
"jism",
"jerkoff",
"jackoff",
"goddamn",
"fag",
"blowjob",
"bitch",
"asshole",
"dick",
"pussy",
"snatch",
"cunt",
"twat",
"shit",
"fuck",
"tailor",
"smith",
"scholar",
"rogue",
"novice",
"neophyte",
"merchant",
"medium",
"master",
"mage",
"lb",
"journeyman",
"grandmaster",
"fisherman",
"expert",
"chef",
"carpenter",
"british",
"blackthorne",
"blackthorn",
"beggar",
"archer",
"apprentice",
"adept",
"gamemaster",
"frozen",
"squelched",
"invulnerable",
"osi",
"origin"
};
public static string[] StartDisallowed
{
get
{
return m_StartDisallowed;
}
}
public static string[] Disallowed
{
get
{
return m_Disallowed;
}
}
public static void Initialize()
{
CommandSystem.Register("ValidateName", AccessLevel.Administrator, new CommandEventHandler(ValidateName_OnCommand));
}
[Usage("ValidateName")]
[Description("Checks the result of NameValidation on the specified name.")]
public static void ValidateName_OnCommand(CommandEventArgs e)
{
if (Validate(e.ArgString, 2, 16, true, false, true, 1, SpaceDashPeriodQuote))
e.Mobile.SendMessage(0x59, "That name is considered valid.");
else
e.Mobile.SendMessage(0x22, "That name is considered invalid.");
}
public static bool Validate(string name, int minLength, int maxLength, bool allowLetters, bool allowDigits, bool noExceptionsAtStart, int maxExceptions, char[] exceptions)
{
return Validate(name, minLength, maxLength, allowLetters, allowDigits, noExceptionsAtStart, maxExceptions, exceptions, m_Disallowed, m_StartDisallowed);
}
public static bool Validate(string name, int minLength, int maxLength, bool allowLetters, bool allowDigits, bool noExceptionsAtStart, int maxExceptions, char[] exceptions, string[] disallowed, string[] startDisallowed)
{
if (name == null || name.Length < minLength || name.Length > maxLength)
return false;
int exceptCount = 0;
name = name.ToLower();
if (!allowLetters || !allowDigits || (exceptions.Length > 0 && (noExceptionsAtStart || maxExceptions < int.MaxValue)))
{
for (int i = 0; i < name.Length; ++i)
{
char c = name[i];
if (c >= 'a' && c <= 'z')
{
if (!allowLetters)
return false;
exceptCount = 0;
}
else if (c >= '0' && c <= '9')
{
if (!allowDigits)
return false;
exceptCount = 0;
}
else
{
bool except = false;
for (int j = 0; !except && j < exceptions.Length; ++j)
if (c == exceptions[j])
except = true;
if (!except || (i == 0 && noExceptionsAtStart))
return false;
if (exceptCount++ == maxExceptions)
return false;
}
}
}
for (int i = 0; i < disallowed.Length; ++i)
{
int indexOf = name.IndexOf(disallowed[i]);
if (indexOf == -1)
continue;
bool badPrefix = (indexOf == 0);
for (int j = 0; !badPrefix && j < exceptions.Length; ++j)
badPrefix = (name[indexOf - 1] == exceptions[j]);
if (!badPrefix)
continue;
bool badSuffix = ((indexOf + disallowed[i].Length) >= name.Length);
for (int j = 0; !badSuffix && j < exceptions.Length; ++j)
badSuffix = (name[indexOf + disallowed[i].Length] == exceptions[j]);
if (badSuffix)
return false;
}
for (int i = 0; i < startDisallowed.Length; ++i)
{
if (name.StartsWith(startDisallowed[i]))
return false;
}
return true;
}
}
}

569
Scripts/Misc/Notoriety.cs Normal file
View File

@@ -0,0 +1,569 @@
#region References
using System;
using System.Collections.Generic;
using Server.Engines.ArenaSystem;
using Server.Engines.PartySystem;
using Server.Engines.Quests;
using Server.Engines.VvV;
using Server.Factions;
using Server.Guilds;
using Server.Items;
using Server.Mobiles;
using Server.Multis;
using Server.SkillHandlers;
using Server.Spells.Chivalry;
using Server.Spells.Seventh;
#endregion
namespace Server.Misc
{
public class NotorietyHandlers
{
public static void Initialize()
{
Notoriety.Hues[Notoriety.Innocent] = 0x59;
Notoriety.Hues[Notoriety.Ally] = 0x3F;
Notoriety.Hues[Notoriety.CanBeAttacked] = 0x3B2;
Notoriety.Hues[Notoriety.Criminal] = 0x3B2;
Notoriety.Hues[Notoriety.Enemy] = 0x90;
Notoriety.Hues[Notoriety.Murderer] = 0x22;
Notoriety.Hues[Notoriety.Invulnerable] = 0x35;
Notoriety.Handler = MobileNotoriety;
Mobile.AllowBeneficialHandler = Mobile_AllowBeneficial;
Mobile.AllowHarmfulHandler = Mobile_AllowHarmful;
}
private enum GuildStatus
{
None,
Peaceful,
Warring
}
private static GuildStatus GetGuildStatus(Mobile m)
{
if (m.Guild == null)
return GuildStatus.None;
if (((Guild)m.Guild).Enemies.Count == 0 && m.Guild.Type == GuildType.Regular)
return GuildStatus.Peaceful;
return GuildStatus.Warring;
}
private static bool CheckBeneficialStatus(GuildStatus from, GuildStatus target)
{
if (from == GuildStatus.Warring || target == GuildStatus.Warring)
return false;
return true;
}
public static bool Mobile_AllowBeneficial(Mobile from, Mobile target)
{
if (from == null || target == null || from.IsStaff() || target.IsStaff())
return true;
var map = from.Map;
#region Factions/VvV
if (Settings.Enabled)
{
var targetFaction = Faction.Find(target, true);
if ((!Core.ML || map == Faction.Facet) && targetFaction != null)
{
if (Faction.Find(from, true) != targetFaction)
return false;
}
}
if (ViceVsVirtueSystem.Enabled && ViceVsVirtueSystem.IsEnemy(from, target))
{
return false;
}
#endregion
if (map != null && (map.Rules & MapRules.BeneficialRestrictions) == 0)
return true; // In felucca, anything goes
if (!from.Player)
return true; // NPCs have no restrictions
if (target is BaseCreature && !((BaseCreature)target).Controlled)
return false; // Players cannot heal uncontrolled mobiles
if (from is PlayerMobile && ((PlayerMobile)from).Young && target is BaseCreature &&
((BaseCreature)target).Controlled)
return true;
if (from is PlayerMobile && ((PlayerMobile)from).Young &&
(!(target is PlayerMobile) || !((PlayerMobile)target).Young))
return false; // Young players cannot perform beneficial actions towards older players
var fromGuild = from.Guild as Guild;
var targetGuild = target.Guild as Guild;
if (fromGuild != null && targetGuild != null)
{
if (targetGuild == fromGuild || fromGuild.IsAlly(targetGuild))
return true; // Guild members can be beneficial
}
return CheckBeneficialStatus(GetGuildStatus(from), GetGuildStatus(target));
}
public static bool Mobile_AllowHarmful(Mobile from, IDamageable damageable)
{
var target = damageable as Mobile;
if (from == null || target == null || from.IsStaff() || target.IsStaff())
return true;
var map = from.Map;
if (map != null && (map.Rules & MapRules.HarmfulRestrictions) == 0)
return true; // In felucca, anything goes
// Summons should follow the same rules as their masters
if (from is BaseCreature && ((BaseCreature)from).Summoned && ((BaseCreature)from).SummonMaster != null)
from = ((BaseCreature)from).SummonMaster;
if (target is BaseCreature && ((BaseCreature)target).Summoned && ((BaseCreature)target).SummonMaster != null)
target = ((BaseCreature)target).SummonMaster;
var bc = from as BaseCreature;
if (!from.Player && !(bc != null && bc.GetMaster() != null && bc.GetMaster().IsPlayer()))
{
if (!CheckAggressor(from.Aggressors, target) && !CheckAggressed(from.Aggressed, target) && target is PlayerMobile &&
((PlayerMobile)target).CheckYoungProtection(from))
return false;
return true; // Uncontrolled NPCs are only restricted by the young system
}
var fromGuild = GetGuildFor(from.Guild as Guild, from);
var targetGuild = GetGuildFor(target.Guild as Guild, target);
if (fromGuild != null && targetGuild != null)
{
if (fromGuild == targetGuild || fromGuild.IsAlly(targetGuild) || fromGuild.IsEnemy(targetGuild))
return true; // Guild allies or enemies can be harmful
}
if (ViceVsVirtueSystem.Enabled && ViceVsVirtueSystem.EnhancedRules && ViceVsVirtueSystem.IsEnemy(from, damageable))
return true;
if (target is BaseCreature)
{
if (((BaseCreature)target).Controlled)
return false; // Cannot harm other controlled mobiles
if (((BaseCreature)target).Summoned && from != ((BaseCreature)target).SummonMaster)
return false; // Cannot harm other controlled mobiles
}
if (target.Player)
return false; // Cannot harm other players
if (!(target is BaseCreature && ((BaseCreature)target).InitialInnocent))
{
if (Notoriety.Compute(from, target) == Notoriety.Innocent)
return false; // Cannot harm innocent mobiles
}
return true;
}
public static Guild GetGuildFor(Guild def, Mobile m)
{
var g = def;
var c = m as BaseCreature;
if (c != null && c.Controlled && c.ControlMaster != null && !c.ForceNotoriety)
{
c.DisplayGuildTitle = false;
if (c.Map != null && c.Map != Map.Internal)
{
if (Core.AOS || Guild.NewGuildSystem || c.ControlOrder == OrderType.Attack || c.ControlOrder == OrderType.Guard)
g = (Guild)(c.Guild = c.ControlMaster.Guild);
else if (c.Map == null || c.Map == Map.Internal || c.ControlMaster.Guild == null)
g = (Guild)(c.Guild = null);
}
else
{
if (c.Map == null || c.Map == Map.Internal || c.ControlMaster.Guild == null)
g = (Guild)(c.Guild = null);
}
}
return g;
}
public static int CorpseNotoriety(Mobile source, Corpse target)
{
if (target.AccessLevel > AccessLevel.VIP)
return Notoriety.CanBeAttacked;
Body body = target.Amount;
var cretOwner = target.Owner as BaseCreature;
if (cretOwner != null)
{
var sourceGuild = GetGuildFor(source.Guild as Guild, source);
var targetGuild = GetGuildFor(target.Guild, target.Owner);
if (sourceGuild != null && targetGuild != null)
{
if (sourceGuild == targetGuild)
return Notoriety.Ally;
if (sourceGuild.IsAlly(targetGuild))
return Notoriety.Ally;
if (sourceGuild.IsEnemy(targetGuild))
return Notoriety.Enemy;
}
if (Settings.Enabled)
{
var srcFaction = Faction.Find(source, true, true);
var trgFaction = Faction.Find(cretOwner, true, true);
if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet)
return Notoriety.Enemy;
}
if (ViceVsVirtueSystem.Enabled && ViceVsVirtueSystem.IsEnemy(source, cretOwner) && (ViceVsVirtueSystem.EnhancedRules || source.Map == Faction.Facet))
return Notoriety.Enemy;
if (CheckHouseFlag(source, cretOwner, target.Location, target.Map))
return Notoriety.CanBeAttacked;
var actual = Notoriety.CanBeAttacked;
if (target.Murderer)
actual = Notoriety.Murderer;
else if (body.IsMonster && IsSummoned(cretOwner))
actual = Notoriety.Murderer;
else if (cretOwner.AlwaysMurderer || cretOwner.IsAnimatedDead)
actual = Notoriety.Murderer;
if (DateTime.UtcNow >= (target.TimeOfDeath + Corpse.MonsterLootRightSacrifice))
return actual;
var sourceParty = Party.Get(source);
foreach (var m in target.Aggressors)
{
if (m == source || (sourceParty != null && Party.Get(m) == sourceParty) || (sourceGuild != null && m.Guild == sourceGuild))
return actual;
}
return Notoriety.Innocent;
}
else
{
if (target.Murderer)
return Notoriety.Murderer;
if (target.Criminal && target.Map != null && ((target.Map.Rules & MapRules.HarmfulRestrictions) == 0))
return Notoriety.Criminal;
var sourceGuild = GetGuildFor(source.Guild as Guild, source);
var targetGuild = GetGuildFor(target.Guild, target.Owner);
if (sourceGuild != null && targetGuild != null)
{
if (sourceGuild == targetGuild || sourceGuild.IsAlly(targetGuild))
return Notoriety.Ally;
if (sourceGuild.IsEnemy(targetGuild))
return Notoriety.Enemy;
}
var srcFaction = Faction.Find(source, true, true);
var trgFaction = Faction.Find(target.Owner, true, true);
if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet)
{
foreach (var m in target.Aggressors)
{
if (m == source || m is BaseFactionGuard)
return Notoriety.Enemy;
}
}
if (CheckHouseFlag(source, target.Owner, target.Location, target.Map))
return Notoriety.CanBeAttacked;
if (!(target.Owner is PlayerMobile) && !IsPet(target.Owner as BaseCreature))
return Notoriety.CanBeAttacked;
var list = target.Aggressors;
foreach (var m in list)
{
if (m == source)
return Notoriety.CanBeAttacked;
}
return Notoriety.Innocent;
}
}
public static int MobileNotoriety(Mobile source, IDamageable damageable)
{
if (damageable is PublicMoongate)
{
return Notoriety.Innocent;
}
var target = damageable as Mobile;
if (target == null)
return Notoriety.CanBeAttacked;
if (Core.AOS)
{
if (target.Blessed)
return Notoriety.Invulnerable;
if (target is BaseVendor && ((BaseVendor)target).IsInvulnerable)
return Notoriety.Invulnerable;
if (target is PlayerVendor || target is TownCrier)
return Notoriety.Invulnerable;
}
var context = EnemyOfOneSpell.GetContext(source);
if (context != null && context.IsEnemy(target))
return Notoriety.Enemy;
if (PVPArenaSystem.IsEnemy(source, target))
return Notoriety.Enemy;
if (PVPArenaSystem.IsFriendly(source, target))
return Notoriety.Ally;
if (target.IsStaff())
return Notoriety.CanBeAttacked;
if (source.Player && target is BaseCreature)
{
var bc = (BaseCreature)target;
var master = bc.GetMaster();
if (master != null && master.IsStaff())
return Notoriety.CanBeAttacked;
master = bc.ControlMaster;
if (Core.ML && master != null && !bc.ForceNotoriety)
{
if (source == master && CheckAggressor(target.Aggressors, source))
return Notoriety.CanBeAttacked;
if (CheckAggressor(source.Aggressors, bc))
return Notoriety.CanBeAttacked;
return MobileNotoriety(source, master);
}
}
if (target.Murderer)
return Notoriety.Murderer;
if (target.Body.IsMonster && IsSummoned(target as BaseCreature))
{
if (!(target is BaseFamiliar) && !(target is ArcaneFey) && !(target is Golem))
return Notoriety.Murderer;
}
if (target is BaseCreature)
{
if (((BaseCreature)target).AlwaysMurderer || ((BaseCreature)target).IsAnimatedDead)
return Notoriety.Murderer;
}
if (source.Player && target is BaseEscort)
return Notoriety.Innocent;
if (target.Criminal)
return Notoriety.Criminal;
var sourceGuild = GetGuildFor(source.Guild as Guild, source);
var targetGuild = GetGuildFor(target.Guild as Guild, target);
if (sourceGuild != null && targetGuild != null)
{
if (sourceGuild == targetGuild)
return Notoriety.Ally;
if (sourceGuild.IsAlly(targetGuild))
return Notoriety.Ally;
if (sourceGuild.IsEnemy(targetGuild))
return Notoriety.Enemy;
}
if (Settings.Enabled)
{
var srcFaction = Faction.Find(source, true, true);
var trgFaction = Faction.Find(target, true, true);
if (srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet)
return Notoriety.Enemy;
}
if (ViceVsVirtueSystem.Enabled && ViceVsVirtueSystem.IsEnemy(source, target) && (ViceVsVirtueSystem.EnhancedRules || source.Map == Faction.Facet))
return Notoriety.Enemy;
if (Stealing.ClassicMode && target is PlayerMobile && ((PlayerMobile)target).PermaFlags.Contains(source))
return Notoriety.CanBeAttacked;
if (target is BaseCreature && ((BaseCreature)target).AlwaysAttackable)
return Notoriety.CanBeAttacked;
if (CheckHouseFlag(source, target, target.Location, target.Map))
return Notoriety.CanBeAttacked;
//If Target is NOT A baseCreature, OR it's a BC and the BC is initial innocent...
if (!(target is BaseCreature && ((BaseCreature)target).InitialInnocent))
{
if (!target.Body.IsHuman && !target.Body.IsGhost && !IsPet(target as BaseCreature) && !(target is PlayerMobile))
return Notoriety.CanBeAttacked;
if (!Core.ML && !target.CanBeginAction(typeof(PolymorphSpell)))
return Notoriety.CanBeAttacked;
}
if (CheckAggressor(source.Aggressors, target))
return Notoriety.CanBeAttacked;
if(source is PlayerMobile && CheckPetAggressor((PlayerMobile)source, target))
return Notoriety.CanBeAttacked;
if (CheckAggressed(source.Aggressed, target))
return Notoriety.CanBeAttacked;
if(source is PlayerMobile && CheckPetAggressed((PlayerMobile)source, target))
return Notoriety.CanBeAttacked;
if (target is BaseCreature)
{
var bc = (BaseCreature)target;
if (bc.Controlled && bc.ControlOrder == OrderType.Guard && bc.ControlTarget == source)
return Notoriety.CanBeAttacked;
}
if (source is BaseCreature)
{
var bc = (BaseCreature)source;
var master = bc.GetMaster();
if (master != null)
{
if (CheckAggressor(master.Aggressors, target))
{
return Notoriety.CanBeAttacked;
}
if (MobileNotoriety(master, target) == Notoriety.CanBeAttacked)
{
return Notoriety.CanBeAttacked;
}
if (target is BaseCreature)
{
return Notoriety.CanBeAttacked;
}
}
}
return Notoriety.Innocent;
}
public static bool CheckHouseFlag(Mobile from, Mobile m, Point3D p, Map map)
{
var house = BaseHouse.FindHouseAt(p, map, 16);
if (house == null || house.Public || !house.IsFriend(from))
return false;
if (m != null && house.IsFriend(m))
return false;
var c = m as BaseCreature;
if (c != null && !c.Deleted && c.Controlled && c.ControlMaster != null)
return !house.IsFriend(c.ControlMaster);
return true;
}
public static bool IsPet(BaseCreature c)
{
return (c != null && c.Controlled);
}
public static bool IsSummoned(BaseCreature c)
{
return (c != null && /*c.Controlled &&*/ c.Summoned);
}
public static bool CheckAggressor(List<AggressorInfo> list, Mobile target)
{
foreach (var o in list)
{
if (o.Attacker == target)
return true;
}
return false;
}
public static bool CheckAggressed(List<AggressorInfo> list, Mobile target)
{
foreach (var info in list)
{
if (!info.CriminalAggression && info.Defender == target)
return true;
}
return false;
}
public static bool CheckPetAggressor(PlayerMobile source, Mobile target)
{
foreach (var bc in source.AllFollowers)
{
if (CheckAggressor(bc.Aggressors, target))
return true;
}
return false;
}
public static bool CheckPetAggressed(PlayerMobile source, Mobile target)
{
foreach (var bc in source.AllFollowers)
{
if (CheckAggressed(bc.Aggressed, target))
return true;
}
return false;
}
}
}

32
Scripts/Misc/Paperdoll.cs Normal file
View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using Server.Network;
namespace Server.Misc
{
public class Paperdoll
{
public static void Initialize()
{
EventSink.PaperdollRequest += new PaperdollRequestEventHandler(EventSink_PaperdollRequest);
}
public static void EventSink_PaperdollRequest(PaperdollRequestEventArgs e)
{
Mobile beholder = e.Beholder;
Mobile beheld = e.Beheld;
beholder.Send(new DisplayPaperdoll(beheld, Titles.ComputeTitle(beholder, beheld), beheld.AllowEquipFrom(beholder)));
if (beholder.ViewOPL)
{
List<Item> items = beheld.Items;
for (int i = 0; i < items.Count; ++i)
beholder.Send(items[i].OPLPacket);
// NOTE: OSI sends MobileUpdate when opening your own paperdoll.
// It has a very bad rubber-banding affect. What positive affects does it have?
}
}
}
}

283
Scripts/Misc/Poison.cs Normal file
View File

@@ -0,0 +1,283 @@
#region References
using System;
using System.Globalization;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Services.Virtues;
using Server.Spells;
using Server.Spells.Necromancy;
using Server.Spells.Ninjitsu;
#endregion
namespace Server
{
public class PoisonImpl : Poison
{
[CallPriority(10)]
public static void Configure()
{
if (Core.AOS)
{
Register(new PoisonImpl("Lesser", 0, 4, 16, 7.5, 3.0, 2.25, 10, 4));
Register(new PoisonImpl("Regular", 1, 8, 18, 10.0, 3.0, 3.25, 10, 3));
Register(new PoisonImpl("Greater", 2, 12, 20, 15.0, 3.0, 4.25, 10, 2));
Register(new PoisonImpl("Deadly", 3, 16, 30, 30.0, 3.0, 5.25, 15, 2));
Register(new PoisonImpl("Lethal", 4, 20, 50, 35.0, 3.0, 5.25, 20, 2));
}
else
{
Register(new PoisonImpl("Lesser", 0, 4, 26, 2.500, 3.5, 3.0, 10, 2));
Register(new PoisonImpl("Regular", 1, 5, 26, 3.125, 3.5, 3.0, 10, 2));
Register(new PoisonImpl("Greater", 2, 6, 26, 6.250, 3.5, 3.0, 10, 2));
Register(new PoisonImpl("Deadly", 3, 7, 26, 12.500, 3.5, 4.0, 10, 2));
Register(new PoisonImpl("Lethal", 4, 9, 26, 25.000, 3.5, 5.0, 10, 2));
}
#region Mondain's Legacy
if (Core.ML)
{
Register(new PoisonImpl("LesserDarkglow", 10, 4, 16, 7.5, 3.0, 2.25, 10, 4));
Register(new PoisonImpl("RegularDarkglow", 11, 8, 18, 10.0, 3.0, 3.25, 10, 3));
Register(new PoisonImpl("GreaterDarkglow", 12, 12, 20, 15.0, 3.0, 4.25, 10, 2));
Register(new PoisonImpl("DeadlyDarkglow", 13, 16, 30, 30.0, 3.0, 5.25, 15, 2));
Register(new PoisonImpl("LesserParasitic", 14, 4, 16, 7.5, 3.0, 2.25, 10, 4));
Register(new PoisonImpl("RegularParasitic", 15, 8, 18, 10.0, 3.0, 3.25, 10, 3));
Register(new PoisonImpl("GreaterParasitic", 16, 12, 20, 15.0, 3.0, 4.25, 10, 2));
Register(new PoisonImpl("DeadlyParasitic", 17, 16, 30, 30.0, 3.0, 5.25, 15, 2));
Register(new PoisonImpl("LethalParasitic", 18, 20, 50, 35.0, 3.0, 5.25, 20, 2));
}
#endregion
}
public static Poison IncreaseLevel(Poison oldPoison)
{
Poison newPoison = oldPoison == null ? null : GetPoison(oldPoison.Level + 1);
return newPoison ?? oldPoison;
}
public static Poison DecreaseLevel(Poison oldPoison)
{
Poison newPoison = (oldPoison == null ? null : GetPoison(oldPoison.Level - 1));
return (newPoison == null ? oldPoison : newPoison);
}
// Info
private readonly string m_Name;
private readonly int m_Level;
// Damage
private readonly int m_Minimum;
private readonly int m_Maximum;
private readonly double m_Scalar;
// Timers
private readonly TimeSpan m_Delay;
private readonly TimeSpan m_Interval;
private readonly int m_Count;
private readonly int m_MessageInterval;
public override string Name { get { return m_Name; } }
public override int Level { get { return m_Level; } }
#region Mondain's Legacy
public override int RealLevel
{
get
{
if (m_Level >= 14)
{
return m_Level - 14;
}
if (m_Level >= 10)
{
return m_Level - 10;
}
return m_Level;
}
}
public override int LabelNumber
{
get
{
if (m_Level >= 14)
{
return 1072852; // parasitic poison charges: ~1_val~
}
if (m_Level >= 10)
{
return 1072853; // darkglow poison charges: ~1_val~
}
return 1062412 + m_Level; // ~poison~ poison charges: ~1_val~
}
}
#endregion
public PoisonImpl(
string name,
int level,
int min,
int max,
double percent,
double delay,
double interval,
int count,
int messageInterval)
{
m_Name = name;
m_Level = level;
m_Minimum = min;
m_Maximum = max;
m_Scalar = percent * 0.01;
m_Delay = TimeSpan.FromSeconds(delay);
m_Interval = TimeSpan.FromSeconds(interval);
m_Count = count;
m_MessageInterval = messageInterval;
}
public override Timer ConstructTimer(Mobile m)
{
return new PoisonTimer(m, this);
}
public class PoisonTimer : Timer
{
private readonly PoisonImpl m_Poison;
private readonly Mobile m_Mobile;
private Mobile m_From;
private int m_LastDamage;
private int m_Index;
public Mobile From { get { return m_From; } set { m_From = value; } }
public PoisonTimer(Mobile m, PoisonImpl p)
: base(p.m_Delay, p.m_Interval)
{
m_From = m;
m_Mobile = m;
m_Poison = p;
int damage = 1 + (int)(m.Hits * p.m_Scalar);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Poison, 1017383, 1075633, TimeSpan.FromSeconds((int)((p.m_Count + 1) * p.m_Interval.TotalSeconds)), m, String.Format("{0}\t{1}", damage, (int)p.m_Interval.TotalSeconds)));
}
protected override void OnTick()
{
bool usingPetals = OrangePetals.UnderEffect(m_Mobile);
if (Core.SA && usingPetals && m_Poison.RealLevel >= 3 && 0.25 > Utility.RandomDouble())
{
OrangePetals.RemoveContext(m_Mobile);
usingPetals = false;
m_Mobile.LocalOverheadMessage(MessageType.Regular, 0x3F, 1053093); // * The strength of the poison overcomes your resistance! *
}
if ((Core.AOS && m_Poison.RealLevel < 4 && TransformationSpellHelper.UnderTransformation(m_Mobile, typeof(VampiricEmbraceSpell))) ||
(m_Poison.RealLevel <= 3 && usingPetals) ||
AnimalForm.UnderTransformation(m_Mobile, typeof(Unicorn)))
{
if (m_Mobile.CurePoison(m_Mobile))
{
m_Mobile.LocalOverheadMessage(MessageType.Emote, 0x3F, 1053092); // * You feel yourself resisting the effects of the poison *
m_Mobile.NonlocalOverheadMessage(MessageType.Emote, 0x3F, 1114442, m_Mobile.Name); // * ~1_NAME~ seems resistant to the poison *
Stop();
return;
}
}
if (m_Index++ == m_Poison.m_Count)
{
m_Mobile.SendLocalizedMessage(502136); // The poison seems to have worn off.
m_Mobile.Poison = null;
if (m_Mobile is PlayerMobile)
BuffInfo.RemoveBuff((PlayerMobile)m_Mobile, BuffIcon.Poison);
Stop();
return;
}
int damage;
if (!Core.AOS && m_LastDamage != 0 && Utility.RandomBool())
{
damage = m_LastDamage;
}
else
{
damage = 1 + (int)(m_Mobile.Hits * m_Poison.m_Scalar);
if (damage < m_Poison.m_Minimum)
damage = m_Poison.m_Minimum;
else if (damage > m_Poison.m_Maximum)
damage = m_Poison.m_Maximum;
m_LastDamage = damage;
}
if (m_From != null)
{
if (m_From is BaseCreature && ((BaseCreature)m_From).RecentSetControl && ((BaseCreature)m_From).GetMaster() == m_Mobile)
{
m_From = null;
}
else
{
m_From.DoHarmful(m_Mobile, true);
}
}
IHonorTarget honorTarget = m_Mobile as IHonorTarget;
if (honorTarget != null && honorTarget.ReceivedHonorContext != null)
honorTarget.ReceivedHonorContext.OnTargetPoisoned();
#region Mondain's Legacy
if (Core.ML)
{
if (m_From != null && m_Mobile != m_From && !m_From.InRange(m_Mobile.Location, 1) && m_Poison.m_Level >= 10 && m_Poison.m_Level <= 13) // darkglow
{
m_From.SendLocalizedMessage(1072850); // Darkglow poison increases your damage!
damage = (int)Math.Floor(damage * 1.1);
}
if (m_From != null && m_Mobile != m_From && m_From.InRange(m_Mobile.Location, 1) && m_Poison.m_Level >= 14 && m_Poison.m_Level <= 18) // parasitic
{
int toHeal = Math.Min(m_From.HitsMax - m_From.Hits, damage);
if (toHeal > 0)
{
m_From.SendLocalizedMessage(1060203, toHeal.ToString()); // You have had ~1_HEALED_AMOUNT~ hit points of damage healed.
m_From.Heal(toHeal, m_Mobile, false);
}
}
}
#endregion
AOS.Damage(m_Mobile, m_From, damage, 0, 0, 0, 100, 0);
if (damage > 0)
{
m_Mobile.RevealingAction();
}
if ((m_Index % m_Poison.m_MessageInterval) == 0)
m_Mobile.OnPoisoned(m_From, m_Poison, m_Poison);
}
}
}
}

View File

@@ -0,0 +1,142 @@
using System;
using Server.Network;
namespace Server.Misc
{
public enum ProfanityAction
{
None, // no action taken
Disallow, // speech is not displayed
Criminal, // makes the player criminal, not killable by guards
CriminalAction, // makes the player criminal, can be killed by guards
Disconnect, // player is kicked
Other // some other implementation
}
public class ProfanityProtection
{
private static readonly bool Enabled = false;
private static readonly ProfanityAction Action = ProfanityAction.Disallow;// change here what to do when profanity is detected
private static readonly char[] m_Exceptions = new char[]
{
' ', '-', '.', '\'', '"', ',', '_', '+', '=', '~', '`', '!', '^', '*', '\\', '/', ';', ':', '<', '>', '[', ']', '{', '}', '?', '|', '(', ')', '%', '$', '&', '#', '@'
};
private static readonly string[] m_StartDisallowed = new string[] { };
private static readonly string[] m_Disallowed = new string[]
{
"jigaboo",
"chigaboo",
"wop",
"kyke",
"kike",
"tit",
"spic",
"prick",
"piss",
"lezbo",
"lesbo",
"felatio",
"dyke",
"dildo",
"chinc",
"chink",
"cunnilingus",
"cum",
"cocksucker",
"cock",
"clitoris",
"clit",
"ass",
"hitler",
"penis",
"nigga",
"nigger",
"klit",
"kunt",
"jiz",
"jism",
"jerkoff",
"jackoff",
"goddamn",
"fag",
"blowjob",
"bitch",
"asshole",
"dick",
"pussy",
"snatch",
"cunt",
"twat",
"shit",
"fuck"
};
public static char[] Exceptions
{
get
{
return m_Exceptions;
}
}
public static string[] StartDisallowed
{
get
{
return m_StartDisallowed;
}
}
public static string[] Disallowed
{
get
{
return m_Disallowed;
}
}
public static void Initialize()
{
if (Enabled)
EventSink.Speech += new SpeechEventHandler(EventSink_Speech);
}
private static bool OnProfanityDetected(Mobile from, string speech)
{
switch ( Action )
{
case ProfanityAction.None:
return true;
case ProfanityAction.Disallow:
return false;
case ProfanityAction.Criminal:
from.Criminal = true;
return true;
case ProfanityAction.CriminalAction:
from.CriminalAction(false);
return true;
case ProfanityAction.Disconnect:
{
NetState ns = from.NetState;
if (ns != null)
ns.Dispose();
return false;
}
default:
case ProfanityAction.Other: // TODO: Provide custom implementation if this is chosen
{
return true;
}
}
}
private static void EventSink_Speech(SpeechEventArgs e)
{
Mobile from = e.Mobile;
if (from.IsStaff())
return;
if (!NameVerification.Validate(e.Speech, 0, int.MaxValue, true, true, false, int.MaxValue, m_Exceptions, m_Disallowed, m_StartDisallowed))
e.Blocked = !OnProfanityDetected(from, e.Speech);
}
}
}

103
Scripts/Misc/Profile.cs Normal file
View File

@@ -0,0 +1,103 @@
using System;
using Server.Accounting;
using Server.Network;
namespace Server.Misc
{
public class Profile
{
public static void Initialize()
{
EventSink.ProfileRequest += new ProfileRequestEventHandler(EventSink_ProfileRequest);
EventSink.ChangeProfileRequest += new ChangeProfileRequestEventHandler(EventSink_ChangeProfileRequest);
}
public static void EventSink_ChangeProfileRequest(ChangeProfileRequestEventArgs e)
{
if (e.Beholder != e.Beheld && e.Beholder.AccessLevel <= e.Beheld.AccessLevel)
{
e.Beholder.SendMessage("You do not have permission to do that.");
return;
}
Mobile from = e.Beholder;
if (from.ProfileLocked)
from.SendMessage("Your profile is locked. You may not change it.");
else
from.Profile = e.Text;
}
public static void EventSink_ProfileRequest(ProfileRequestEventArgs e)
{
Mobile beholder = e.Beholder;
Mobile beheld = e.Beheld;
if (!beheld.Player)
return;
if (beholder.Map != beheld.Map || !beholder.InRange(beheld, 12) || !beholder.CanSee(beheld))
return;
string header = Titles.ComputeTitle(beholder, beheld);
string footer = "";
if (beheld.ProfileLocked)
{
if (beholder == beheld)
footer = "Your profile has been locked.";
else if (beholder.IsStaff())
footer = "This profile has been locked.";
}
if (footer.Length == 0 && beholder == beheld)
footer = GetAccountDuration(beheld);
string body = beheld.Profile;
if (body == null || body.Length <= 0)
body = "";
beholder.Send(new DisplayProfile(beholder != beheld || !beheld.ProfileLocked, beheld, header, body, footer));
}
public static bool Format(double value, string format, out string op)
{
if (value >= 1.0)
{
op = String.Format(format, (int)value, (int)value != 1 ? "s" : "");
return true;
}
op = null;
return false;
}
private static string GetAccountDuration(Mobile m)
{
Account a = m.Account as Account;
if (a == null)
return "";
TimeSpan ts = DateTime.UtcNow - a.Created;
string v;
if (Format(ts.TotalDays, "This account is {0} day{1} old.", out v))
return v;
if (Format(ts.TotalHours, "This account is {0} hour{1} old.", out v))
return v;
if (Format(ts.TotalMinutes, "This account is {0} minute{1} old.", out v))
return v;
if (Format(ts.TotalSeconds, "This account is {0} second{1} old.", out v))
return v;
return "";
}
}
}

View File

@@ -0,0 +1,169 @@
using System;
using Server.Engines.PartySystem;
using Server.Guilds;
using Server.Network;
namespace Server.Misc
{
public class ProtocolExtensions
{
private static readonly PacketHandler[] m_Handlers = new PacketHandler[0x100];
public static void Initialize()
{
PacketHandlers.Register(0xF0, 0, false, new OnPacketReceive(DecodeBundledPacket));
Register(0x00, true, new OnPacketReceive(QueryPartyLocations));
Register(0x01, true, new OnPacketReceive(QueryGuildsLocations));
}
public static void QueryPartyLocations(NetState state, PacketReader pvSrc)
{
Mobile from = state.Mobile;
Party party = Party.Get(from);
if (party != null)
{
AckPartyLocations ack = new AckPartyLocations(from, party);
if (ack.UnderlyingStream.Length > 8)
state.Send(ack);
}
}
private static void QueryGuildsLocations(NetState state, PacketReader pvSrc)
{
Mobile from = state.Mobile;
Guild guild = from.Guild as Guild;
if (guild != null)
{
bool locations = pvSrc.ReadByte() != 0;
AckGuildsLocations packet = new AckGuildsLocations(from, guild, locations);
if (packet.UnderlyingStream.Length > (locations ? 9 : 5))
state.Send(packet);
}
else
state.Send(new AckGuildsLocations());
}
public static void Register(int packetID, bool ingame, OnPacketReceive onReceive)
{
m_Handlers[packetID] = new PacketHandler(packetID, 0, ingame, onReceive);
}
public static PacketHandler GetHandler(int packetID)
{
if (packetID >= 0 && packetID < m_Handlers.Length)
return m_Handlers[packetID];
return null;
}
public static void DecodeBundledPacket(NetState state, PacketReader pvSrc)
{
int packetID = pvSrc.ReadByte();
PacketHandler ph = GetHandler(packetID);
if (ph != null)
{
if (ph.Ingame && state.Mobile == null)
{
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Client: {0}: Sent ingame packet (0xF0x{1:X2}) before having been attached to a mobile", state, packetID);
Utility.PopColor();
state.Dispose();
}
else if (ph.Ingame && state.Mobile.Deleted)
{
state.Dispose();
}
else
{
ph.OnReceive(state, pvSrc);
}
}
}
}
public abstract class ProtocolExtension : Packet
{
public ProtocolExtension(int packetID, int capacity)
: base(0xF0)
{
this.EnsureCapacity(4 + capacity);
this.m_Stream.Write((byte)packetID);
}
}
public class AckPartyLocations : ProtocolExtension
{
public AckPartyLocations(Mobile from, Party party)
: base(0x01, ((party.Members.Count - 1) * 9) + 4)
{
for (int i = 0; i < party.Members.Count; ++i)
{
PartyMemberInfo pmi = (PartyMemberInfo)party.Members[i];
if (pmi == null || pmi.Mobile == from)
continue;
Mobile mob = pmi.Mobile;
if (Utility.InUpdateRange(from, mob) && from.CanSee(mob))
continue;
this.m_Stream.Write((int)mob.Serial);
this.m_Stream.Write((short)mob.X);
this.m_Stream.Write((short)mob.Y);
this.m_Stream.Write((byte)(mob.Map == null ? 0 : mob.Map.MapID));
}
this.m_Stream.Write((int)0);
}
}
public class AckGuildsLocations : ProtocolExtension
{
public AckGuildsLocations() : base(0x02, 5)
{
m_Stream.Write((byte)0);
m_Stream.Write((int)0);
}
public AckGuildsLocations(Mobile from, Guild guild, bool locations) : base(0x02, ((guild.Members.Count - 1) * (locations ? 10 : 4)) + 5)
{
m_Stream.Write((byte)(locations ? 1 : 0));
for (int i = 0; i < guild.Members.Count; ++i)
{
Mobile mob = guild.Members[i];
if (mob == null || mob == from || mob.NetState == null)
continue;
if (locations && Utility.InUpdateRange(from, mob) && from.CanSee(mob))
continue;
m_Stream.Write((int)mob.Serial);
if (locations)
{
m_Stream.Write((short)mob.X);
m_Stream.Write((short)mob.Y);
m_Stream.Write((byte)(mob.Map == null ? 0 : mob.Map.MapID));
if (mob.Alive)
m_Stream.Write((byte)(mob.Hits / Math.Max(mob.HitsMax, 1.0) * 100));
else
m_Stream.Write((byte)0);
}
}
m_Stream.Write((int)0);
}
}
}

View File

@@ -0,0 +1,430 @@
using System;
namespace Server.Misc
{
public class RaceDefinitions
{
public static void Configure()
{
/* Here we configure all races. Some notes:
*
* 1) The first 32 races are reserved for core use.
* 2) Race 0x7F is reserved for core use.
* 3) Race 0xFF is reserved for core use.
* 4) Changing or removing any predefined races may cause server instability.
*/
RegisterRace(new Human(0, 0));
RegisterRace(new Elf(1, 1));
#region Stygian Abyss
RegisterRace(new Gargoyle(2, 2));
#endregion
}
public static void RegisterRace(Race race)
{
Race.Races[race.RaceIndex] = race;
Race.AllRaces.Add(race);
}
private class Human : Race
{
public Human(int raceID, int raceIndex)
: base(raceID, raceIndex, "Human", "Humans", 400, 401, 402, 403, Expansion.None)
{
}
public override bool ValidateHair(bool female, int itemID)
{
if (itemID == 0)
return true;
if ((female && itemID == 0x2048) || (!female && itemID == 0x2046))
return false; //Buns & Receeding Hair
if (itemID >= 0x203B && itemID <= 0x203D)
return true;
if (itemID >= 0x2044 && itemID <= 0x204A)
return true;
return false;
}
public override int RandomHair(bool female) //Random hair doesn't include baldness
{
switch( Utility.Random(9) )
{
case 0:
return 0x203B; //Short
case 1:
return 0x203C; //Long
case 2:
return 0x203D; //Pony Tail
case 3:
return 0x2044; //Mohawk
case 4:
return 0x2045; //Pageboy
case 5:
return 0x2047; //Afro
case 6:
return 0x2049; //Pig tails
case 7:
return 0x204A; //Krisna
default:
return (female ? 0x2046 : 0x2048); //Buns or Receeding Hair
}
}
public override bool ValidateFacialHair(bool female, int itemID)
{
if (itemID == 0)
return true;
if (female)
return false;
if (itemID >= 0x203E && itemID <= 0x2041)
return true;
if (itemID >= 0x204B && itemID <= 0x204D)
return true;
return false;
}
public override int RandomFacialHair(bool female)
{
if (female)
return 0;
int rand = Utility.Random(7);
return ((rand < 4) ? 0x203E : 0x2047) + rand;
}
public override bool ValidateFace(bool female, int itemID)
{
if (itemID.Equals(0))
return false;
if (itemID >= 0x3B44 && itemID <= 0x3B4D)
return true;
return false;
}
public override int RandomFace(bool female)
{
int rand = Utility.Random(9);
return 15172 + rand;
}
public override int ClipSkinHue(int hue)
{
if (hue < 1002)
return 1002;
else if (hue > 1058)
return 1058;
else
return hue;
}
public override int RandomSkinHue()
{
return Utility.Random(1002, 57) | 0x8000;
}
public override int ClipHairHue(int hue)
{
if (hue < 1102)
return 1102;
else if (hue > 1149)
return 1149;
else
return hue;
}
public override int RandomHairHue()
{
return Utility.Random(1102, 48);
}
public override int ClipFaceHue(int hue)
{
return ClipSkinHue(hue);
}
public override int RandomFaceHue()
{
return RandomSkinHue();
}
}
private class Elf : Race
{
private static readonly int[] m_SkinHues = new int[]
{
0x4DE, 0x76C, 0x835, 0x430, 0x24D, 0x24E, 0x24F, 0x0BF,
0x4A7, 0x361, 0x375, 0x367, 0x3E8, 0x3DE, 0x353, 0x903,
0x76D, 0x384, 0x579, 0x3E9, 0x374, 0x389, 0x385, 0x376,
0x53F, 0x381, 0x382, 0x383, 0x76B, 0x3E5, 0x51D, 0x3E6
};
private static readonly int[] m_HairHues = new int[]
{
0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x058, 0x08E,
0x08F, 0x090, 0x091, 0x092, 0x101, 0x159, 0x15A, 0x15B,
0x15C, 0x15D, 0x15E, 0x128, 0x12F, 0x1BD, 0x1E4, 0x1F3,
0x207, 0x211, 0x239, 0x251, 0x26C, 0x2C3, 0x2C9, 0x31D,
0x31E, 0x31F, 0x320, 0x321, 0x322, 0x323, 0x324, 0x325,
0x326, 0x369, 0x386, 0x387, 0x388, 0x389, 0x38A, 0x59D,
0x6B8, 0x725, 0x853
};
public Elf(int raceID, int raceIndex)
: base(raceID, raceIndex, "Elf", "Elves", 605, 606, 607, 608, Expansion.ML)
{
}
public override bool ValidateHair(bool female, int itemID)
{
if (itemID == 0)
return true;
if ((female && (itemID == 0x2FCD || itemID == 0x2FBF)) || (!female && (itemID == 0x2FCC || itemID == 0x2FD0)))
return false;
if (itemID >= 0x2FBF && itemID <= 0x2FC2)
return true;
if (itemID >= 0x2FCC && itemID <= 0x2FD1)
return true;
return false;
}
public override int RandomHair(bool female) //Random hair doesn't include baldness
{
switch( Utility.Random(8) )
{
case 0:
return 0x2FC0; //Long Feather
case 1:
return 0x2FC1; //Short
case 2:
return 0x2FC2; //Mullet
case 3:
return 0x2FCE; //Knob
case 4:
return 0x2FCF; //Braided
case 5:
return 0x2FD1; //Spiked
case 6:
return (female ? 0x2FCC : 0x2FBF); //Flower or Mid-long
default:
return (female ? 0x2FD0 : 0x2FCD); //Bun or Long
}
}
public override bool ValidateFacialHair(bool female, int itemID)
{
return (itemID == 0);
}
public override int RandomFacialHair(bool female)
{
return 0;
}
public override bool ValidateFace(bool female, int itemID)
{
if (itemID.Equals(0))
return false;
if (itemID >= 0x3B44 && itemID <= 0x3B4D)
return true;
return false;
}
public override int RandomFace(bool female)
{
int rand = Utility.Random(9);
return 15172 + rand;
}
public override int ClipSkinHue(int hue)
{
for (int i = 0; i < m_SkinHues.Length; i++)
if (m_SkinHues[i] == hue)
return hue;
return m_SkinHues[0];
}
public override int RandomSkinHue()
{
return m_SkinHues[Utility.Random(m_SkinHues.Length)] | 0x8000;
}
public override int ClipHairHue(int hue)
{
for (int i = 0; i < m_HairHues.Length; i++)
if (m_HairHues[i] == hue)
return hue;
return m_HairHues[0];
}
public override int RandomHairHue()
{
return m_HairHues[Utility.Random(m_HairHues.Length)];
}
public override int ClipFaceHue(int hue)
{
return ClipSkinHue(hue);
}
public override int RandomFaceHue()
{
return RandomSkinHue();
}
}
#region SA
private class Gargoyle : Race
{
public Gargoyle(int raceID, int raceIndex)
: base(raceID, raceIndex, "Gargoyle", "Gargoyles", 666, 667, 695, 694, Expansion.SA)
{
}
public override bool ValidateHair(bool female, int itemID)
{
if (female == false)
{
return itemID >= 0x4258 && itemID <= 0x425F;
}
else
{
return ((itemID == 0x4261 || itemID == 0x4262) || (itemID >= 0x4273 && itemID <= 0x4275) || (itemID == 0x42B0 || itemID == 0x42B1) || (itemID == 0x42AA || itemID == 0x42AB));
}
}
public override int RandomHair(bool female)
{
if (Utility.Random(9) == 0)
return 0;
else if (!female)
return 0x4258 + Utility.Random(8);
else
{
switch (Utility.Random(9))
{
case 0:
return 0x4261;
case 1:
return 0x4262;
case 2:
return 0x4273;
case 3:
return 0x4274;
case 4:
return 0x4275;
case 5:
return 0x42B0;
case 6:
return 0x42B1;
case 7:
return 0x42AA;
case 8:
return 0x42AB;
}
return 0;
}
}
public override bool ValidateFacialHair(bool female, int itemID)
{
if (female)
return false;
else
return itemID >= 0x42AD && itemID <= 0x42B0;
}
public override int RandomFacialHair(bool female)
{
if (female)
return 0;
else
return Utility.RandomList(0, 0x42AD, 0x42AE, 0x42AF, 0x42B0);
}
public override bool ValidateFace(bool female, int itemID)
{
if (itemID.Equals(0))
{
return false;
}
if (itemID >= 0x5679 && itemID <= 0x567E)
{
return true;
}
return false;
}
public override int RandomFace(bool female)
{
int rand = Utility.Random(5);
return 22137 + rand;
}
public override int ClipSkinHue(int hue)
{
return hue; // for hue infomation gathering
}
public override int RandomSkinHue()
{
return Utility.Random(1755, 25) | 0x8000;
}
private static readonly int[] m_HornHues = new int[]
{
0x709, 0x70B, 0x70D, 0x70F, 0x711, 0x763,
0x765, 0x768, 0x76B, 0x6F3, 0x6F1, 0x6EF,
0x6E4, 0x6E2, 0x6E0, 0x709, 0x70B, 0x70D
};
public override int ClipHairHue(int hue)
{
for (int i = 0; i < m_HornHues.Length; i++)
if (m_HornHues[i] == hue)
return hue;
return m_HornHues[0];
}
public override int RandomHairHue()
{
return m_HornHues[Utility.Random(m_HornHues.Length)];
}
public override int ClipFaceHue(int hue)
{
return ClipSkinHue(hue);
}
public override int RandomFaceHue()
{
return RandomSkinHue();
}
}
#endregion
}
}

315
Scripts/Misc/RegenRates.cs Normal file
View File

@@ -0,0 +1,315 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Spells.Necromancy;
using Server.Spells.Ninjitsu;
using Server.Spells.SkillMasteries;
namespace Server.Misc
{
public delegate Int32 RegenBonusHandler(Mobile from);
public class RegenRates
{
public static List<RegenBonusHandler> HitsBonusHandlers = new List<RegenBonusHandler>();
public static List<RegenBonusHandler> StamBonusHandlers = new List<RegenBonusHandler>();
public static List<RegenBonusHandler> ManaBonusHandlers = new List<RegenBonusHandler>();
[CallPriority(10)]
public static void Configure()
{
Mobile.DefaultHitsRate = TimeSpan.FromSeconds(11.0);
Mobile.DefaultStamRate = TimeSpan.FromSeconds(7.0);
Mobile.DefaultManaRate = TimeSpan.FromSeconds(7.0);
Mobile.ManaRegenRateHandler = new RegenRateHandler(Mobile_ManaRegenRate);
if (Core.AOS)
{
Mobile.StamRegenRateHandler = new RegenRateHandler(Mobile_StamRegenRate);
Mobile.HitsRegenRateHandler = new RegenRateHandler(Mobile_HitsRegenRate);
}
}
public static double GetArmorOffset(Mobile from)
{
double rating = 0.0;
if (!Core.AOS)
rating += GetArmorMeditationValue(from.ShieldArmor as BaseArmor);
rating += GetArmorMeditationValue(from.NeckArmor as BaseArmor);
rating += GetArmorMeditationValue(from.HandArmor as BaseArmor);
rating += GetArmorMeditationValue(from.HeadArmor as BaseArmor);
rating += GetArmorMeditationValue(from.ArmsArmor as BaseArmor);
rating += GetArmorMeditationValue(from.LegsArmor as BaseArmor);
rating += GetArmorMeditationValue(from.ChestArmor as BaseArmor);
return rating / 4;
}
private static void CheckBonusSkill(Mobile m, int cur, int max, SkillName skill)
{
if (!m.Alive)
return;
double n = (double)cur / max;
double v = Math.Sqrt(m.Skills[skill].Value * 0.005);
n *= (1.0 - v);
n += v;
m.CheckSkill(skill, n);
}
public static bool CheckTransform(Mobile m, Type type)
{
return TransformationSpellHelper.UnderTransformation(m, type);
}
public static bool CheckAnimal(Mobile m, Type type)
{
return AnimalForm.UnderTransformation(m, type);
}
private static TimeSpan Mobile_HitsRegenRate(Mobile from)
{
return TimeSpan.FromSeconds(1.0 / (0.1 * (1 + HitPointRegen(from))));
}
private static TimeSpan Mobile_StamRegenRate(Mobile from)
{
if (from.Skills == null)
return Mobile.DefaultStamRate;
CheckBonusSkill(from, from.Stam, from.StamMax, SkillName.Focus);
double bonus = from.Skills[SkillName.Focus].Value * 0.1;
bonus += StamRegen(from);
if (Core.SA)
{
double rate = 1.0 / (1.42 + (bonus / 100));
if (from is BaseCreature && ((BaseCreature)from).IsMonster)
{
rate *= 1.95;
}
return TimeSpan.FromSeconds(rate);
}
else
{
return TimeSpan.FromSeconds(1.0 / (0.1 * (2 + bonus)));
}
}
private static TimeSpan Mobile_ManaRegenRate(Mobile from)
{
if (from.Skills == null)
return Mobile.DefaultManaRate;
if (!from.Meditating)
CheckBonusSkill(from, from.Mana, from.ManaMax, SkillName.Meditation);
double rate;
double armorPenalty = GetArmorOffset(from);
if (Core.ML)
{
double med = from.Skills[SkillName.Meditation].Value;
double focus = from.Skills[SkillName.Focus].Value;
double focusBonus = focus / 200;
double medBonus = 0;
CheckBonusSkill(from, from.Mana, from.ManaMax, SkillName.Focus);
if (armorPenalty == 0)
{
medBonus = (0.0075 * med) + (0.0025 * from.Int);
if (medBonus >= 100.0)
medBonus *= 1.1;
if (from.Meditating)
{
medBonus *= 2;
}
}
double itemBase = ((((med / 2) + (focus / 4)) / 90) * .65) + 2.35;
double intensityBonus = Math.Sqrt(ManaRegen(from));
if (intensityBonus > 5.5)
intensityBonus = 5.5;
double itemBonus = ((itemBase * intensityBonus) - (itemBase - 1)) / 10;
rate = 1.0 / (0.2 + focusBonus + medBonus + itemBonus);
}
else if (Core.AOS)
{
double medPoints = from.Int + (from.Skills[SkillName.Meditation].Value * 3);
medPoints *= (from.Skills[SkillName.Meditation].Value < 100.0) ? 0.025 : 0.0275;
CheckBonusSkill(from, from.Mana, from.ManaMax, SkillName.Focus);
double focusPoints = (from.Skills[SkillName.Focus].Value * 0.05);
if (armorPenalty > 0)
medPoints = 0; // In AOS, wearing any meditation-blocking armor completely removes meditation bonus
double totalPoints = focusPoints + medPoints + (from.Meditating ? (medPoints > 13.0 ? 13.0 : medPoints) : 0.0);
totalPoints += ManaRegen(from);
if (totalPoints < -1)
totalPoints = -1;
if (Core.ML)
totalPoints = Math.Floor(totalPoints);
rate = 1.0 / (0.1 * (2 + totalPoints));
}
else
{
double medPoints = (from.Int + from.Skills[SkillName.Meditation].Value) * 0.5;
if (medPoints <= 0)
rate = 7.0;
else if (medPoints <= 100)
rate = 7.0 - (239 * medPoints / 2400) + (19 * medPoints * medPoints / 48000);
else if (medPoints < 120)
rate = 1.0;
else
rate = 0.75;
rate += armorPenalty;
if (from.Meditating)
rate *= 0.5;
if (rate < 0.5)
rate = 0.5;
else if (rate > 7.0)
rate = 7.0;
}
if (double.IsNaN(rate))
{
return Mobile.DefaultManaRate;
}
return TimeSpan.FromSeconds(rate);
}
public static double HitPointRegen(Mobile from)
{
double points = AosAttributes.GetValue(from, AosAttribute.RegenHits);
if (from is BaseCreature)
points += ((BaseCreature)from).DefaultHitsRegen;
if (Core.ML && from is PlayerMobile && from.Race == Race.Human) //Is this affected by the cap?
points += 2;
if (points < 0)
points = 0;
if (Core.ML && from is PlayerMobile) //does racial bonus go before/after?
points = Math.Min(points, 18);
if (CheckTransform(from, typeof(HorrificBeastSpell)))
points += 20;
if (CheckAnimal(from, typeof(Dog)) || CheckAnimal(from, typeof(Cat)))
points += from.Skills[SkillName.Ninjitsu].Fixed / 30;
// Skill Masteries - goes after cap
points += RampageSpell.GetBonus(from, RampageSpell.BonusType.HitPointRegen);
points += CombatTrainingSpell.RegenBonus(from);
points += BarrabHemolymphConcentrate.HPRegenBonus(from);
if (Core.AOS)
foreach (RegenBonusHandler handler in HitsBonusHandlers)
points += handler(from);
return points;
}
public static double StamRegen(Mobile from)
{
double points = AosAttributes.GetValue(from, AosAttribute.RegenStam);
if (from is BaseCreature)
points += ((BaseCreature)from).DefaultStamRegen;
if (CheckTransform(from, typeof(VampiricEmbraceSpell)))
points += 15;
if (CheckAnimal(from, typeof(Kirin)))
points += 20;
if (Core.ML && from is PlayerMobile)
points = Math.Min(points, 24);
// Skill Masteries - goes after cap
points += RampageSpell.GetBonus(from, RampageSpell.BonusType.StamRegen);
if (points < -1)
points = -1;
if (Core.AOS)
foreach (RegenBonusHandler handler in StamBonusHandlers)
points += handler(from);
return points;
}
public static double ManaRegen(Mobile from)
{
double points = AosAttributes.GetValue(from, AosAttribute.RegenMana);
if (from is BaseCreature)
points += ((BaseCreature)from).DefaultManaRegen;
if (CheckTransform(from, typeof(VampiricEmbraceSpell)))
points += 3;
else if (CheckTransform(from, typeof(LichFormSpell)))
points += 13;
if (from is PlayerMobile && from.Race == Race.Gargoyle)
points += 2;
if (!Core.ML && from is PlayerMobile)
points = Math.Min(points, 18);
foreach (RegenBonusHandler handler in ManaBonusHandlers)
points += handler(from);
return points;
}
public static double GetArmorMeditationValue(BaseArmor ar)
{
if (ar == null || ar.ArmorAttributes.MageArmor != 0 || ar.Attributes.SpellChanneling != 0)
return 0.0;
switch ( ar.MeditationAllowance )
{
default:
case ArmorMeditationAllowance.None:
return ar.BaseArmorRatingScaled;
case ArmorMeditationAllowance.Half:
return ar.BaseArmorRatingScaled / 2.0;
case ArmorMeditationAllowance.All:
return 0.0;
}
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using Server.Mobiles;
namespace Server.Misc
{
public class RenameRequests
{
public static void Initialize()
{
EventSink.RenameRequest += new RenameRequestEventHandler(EventSink_RenameRequest);
}
private static void EventSink_RenameRequest(RenameRequestEventArgs e)
{
Mobile from = e.From;
Mobile targ = e.Target;
string name = e.Name;
if (from.CanSee(targ) && from.InRange(targ, 12) && targ.CanBeRenamedBy(from))
{
name = name.Trim();
var numExceptions = 0;
var exceptions = NameVerification.Empty;
if (targ is BaseCreature)
{
exceptions = new char[] { ' ' };
numExceptions = 5;
}
if (NameVerification.Validate(name, 1, 16, true, false, true, numExceptions, exceptions, NameVerification.StartDisallowed, (Core.ML ? NameVerification.Disallowed : new string[] { })))
{
if (Core.ML)
{
string[] disallowed = ProfanityProtection.Disallowed;
for (int i = 0; i < disallowed.Length; i++)
{
if (name.IndexOf(disallowed[i]) != -1)
{
from.SendLocalizedMessage(1072622); // That name isn't very polite.
return;
}
}
from.SendLocalizedMessage(1072623, String.Format("{0}\t{1}", targ.Name, name)); // Pet ~1_OLDPETNAME~ renamed to ~2_NEWPETNAME~.
}
targ.Name = name;
}
else
{
from.SendMessage("That name is unacceptable.");
}
}
}
}
}

63
Scripts/Misc/Replacer.cs Normal file
View File

@@ -0,0 +1,63 @@
using System;
using Server.Items;
using Server.Mobiles;
namespace Server
{
public class Replacer
{
public static void Replace(Item item1, Item item2)
{
Timer.DelayCall<Item, Item>(TimeSpan.FromSeconds(1), (oldItem, newItem) =>
{
var parent = oldItem.Parent;
if (parent == null)
{
Server.Multis.BaseHouse house = Server.Multis.BaseHouse.FindHouseAt(oldItem);
newItem.MoveToWorld(oldItem.Location, oldItem.Map);
newItem.IsLockedDown = oldItem.IsLockedDown;
newItem.IsSecure = oldItem.IsSecure;
newItem.Movable = oldItem.Movable;
if (house != null && house.LockDowns.ContainsKey(oldItem))
{
house.LockDowns.Remove(oldItem);
house.LockDowns.Add(newItem, house.Owner);
}
else if (house != null && house.IsSecure(oldItem))
{
house.ReleaseSecure(house.Owner, oldItem);
house.AddSecure(house.Owner, newItem);
}
oldItem.Delete();
}
else
{
newItem.Movable = oldItem.Movable;
if (parent is Container)
{
oldItem.Delete();
((Container)parent).DropItem(newItem);
}
else if (parent is Mobile)
{
oldItem.Delete();
((Mobile)parent).AddItem(newItem);
}
else
{
newItem.Delete();
oldItem.Delete();
Console.WriteLine("Item replacement failed: {0}", newItem.GetType());
}
}
}, item1, item2);
}
}
}

View File

@@ -0,0 +1,979 @@
using System;
using System.Collections;
namespace Server.Items
{
public enum CraftResource
{
None = 0,
Iron = 1,
DullCopper,
ShadowIron,
Copper,
Bronze,
Gold,
Agapite,
Verite,
Valorite,
RegularLeather = 101,
SpinedLeather,
HornedLeather,
BarbedLeather,
RedScales = 201,
YellowScales,
BlackScales,
GreenScales,
WhiteScales,
BlueScales,
RegularWood = 301,
OakWood,
AshWood,
YewWood,
Heartwood,
Bloodwood,
Frostwood
}
public enum CraftResourceType
{
None,
Metal,
Leather,
Scales,
Wood
}
public class CraftAttributeInfo
{
private int m_WeaponFireDamage;
private int m_WeaponColdDamage;
private int m_WeaponPoisonDamage;
private int m_WeaponEnergyDamage;
private int m_WeaponChaosDamage;
private int m_WeaponDirectDamage;
private int m_WeaponDurability;
private int m_WeaponLuck;
private int m_WeaponGoldIncrease;
private int m_WeaponLowerRequirements;
private int m_WeaponDamage;
private int m_WeaponHitChance;
private int m_WeaponHitLifeLeech;
private int m_WeaponRegenHits;
private int m_WeaponSwingSpeed;
private int m_ArmorPhysicalResist;
private int m_ArmorFireResist;
private int m_ArmorColdResist;
private int m_ArmorPoisonResist;
private int m_ArmorEnergyResist;
private int m_ArmorDurability;
private int m_ArmorLuck;
private int m_ArmorGoldIncrease;
private int m_ArmorLowerRequirements;
private int m_ArmorDamage;
private int m_ArmorHitChance;
private int m_ArmorRegenHits;
private int m_ArmorMage;
private int m_ShieldPhysicalResist;
private int m_ShieldFireResist;
private int m_ShieldColdResist;
private int m_ShieldPoisonResist;
private int m_ShieldEnergyResist;
private int m_ShieldPhysicalRandom;
private int m_ShieldColdRandom;
private int m_ShieldSpellChanneling;
private int m_ShieldLuck;
private int m_ShieldLowerRequirements;
private int m_ShieldRegenHits;
private int m_ShieldBonusDex;
private int m_ShieldBonusStr;
private int m_ShieldReflectPhys;
private int m_SelfRepair;
private int m_OtherSpellChanneling;
private int m_OtherLuck;
private int m_OtherRegenHits;
private int m_OtherLowerRequirements;
private int m_RunicMinAttributes;
private int m_RunicMaxAttributes;
private int m_RunicMinIntensity;
private int m_RunicMaxIntensity;
public int WeaponFireDamage { get { return m_WeaponFireDamage; } set { m_WeaponFireDamage = value; } }
public int WeaponColdDamage { get { return m_WeaponColdDamage; } set { m_WeaponColdDamage = value; } }
public int WeaponPoisonDamage { get { return m_WeaponPoisonDamage; } set { m_WeaponPoisonDamage = value; } }
public int WeaponEnergyDamage { get { return m_WeaponEnergyDamage; } set { m_WeaponEnergyDamage = value; } }
public int WeaponChaosDamage { get { return m_WeaponChaosDamage; } set { m_WeaponChaosDamage = value; } }
public int WeaponDirectDamage { get { return m_WeaponDirectDamage; } set { m_WeaponDirectDamage = value; } }
public int WeaponDurability { get { return m_WeaponDurability; } set { m_WeaponDurability = value; } }
public int WeaponLuck { get { return m_WeaponLuck; } set { m_WeaponLuck = value; } }
public int WeaponGoldIncrease { get { return m_WeaponGoldIncrease; } set { m_WeaponGoldIncrease = value; } }
public int WeaponLowerRequirements { get { return m_WeaponLowerRequirements; } set { m_WeaponLowerRequirements = value; } }
public int WeaponDamage { get { return m_WeaponDamage; } set { m_WeaponDamage = value; } }
public int WeaponHitChance { get { return m_WeaponHitChance; } set { m_WeaponHitChance = value; } }
public int WeaponHitLifeLeech { get { return m_WeaponHitLifeLeech; } set { m_WeaponHitLifeLeech = value; } }
public int WeaponRegenHits { get { return m_WeaponRegenHits; } set { m_WeaponRegenHits = value; } }
public int WeaponSwingSpeed { get { return m_WeaponSwingSpeed; } set { m_WeaponSwingSpeed = value; } }
public int ArmorPhysicalResist { get { return m_ArmorPhysicalResist; } set { m_ArmorPhysicalResist = value; } }
public int ArmorFireResist { get { return m_ArmorFireResist; } set { m_ArmorFireResist = value; } }
public int ArmorColdResist { get { return m_ArmorColdResist; } set { m_ArmorColdResist = value; } }
public int ArmorPoisonResist { get { return m_ArmorPoisonResist; } set { m_ArmorPoisonResist = value; } }
public int ArmorEnergyResist { get { return m_ArmorEnergyResist; } set { m_ArmorEnergyResist = value; } }
public int ArmorDurability { get { return m_ArmorDurability; } set { m_ArmorDurability = value; } }
public int ArmorLuck { get { return m_ArmorLuck; } set { m_ArmorLuck = value; } }
public int ArmorGoldIncrease { get { return m_ArmorGoldIncrease; } set { m_ArmorGoldIncrease = value; } }
public int ArmorLowerRequirements { get { return m_ArmorLowerRequirements; } set { m_ArmorLowerRequirements = value; } }
public int ArmorDamage { get { return m_ArmorDamage; } set { m_ArmorDamage = value; } }
public int ArmorHitChance { get { return m_ArmorHitChance; } set { m_ArmorHitChance = value; } }
public int ArmorRegenHits { get { return m_ArmorRegenHits; } set { m_ArmorRegenHits = value; } }
public int ArmorMage { get { return m_ArmorMage; } set { m_ArmorMage = value; } }
public int ShieldPhysicalResist { get { return m_ShieldPhysicalResist; } set { m_ShieldPhysicalResist = value; } }
public int ShieldFireResist { get { return m_ShieldFireResist; } set { m_ShieldFireResist = value; } }
public int ShieldColdResist { get { return m_ShieldColdResist; } set { m_ShieldColdResist = value; } }
public int ShieldPoisonResist { get { return m_ShieldPoisonResist; } set { m_ShieldPoisonResist = value; } }
public int ShieldEnergyResist { get { return m_ShieldEnergyResist; } set { m_ShieldEnergyResist = value; } }
public int ShieldPhysicalRandom { get { return m_ShieldPhysicalRandom; } set { m_ShieldPhysicalRandom = value; } }
public int ShieldColdRandom { get { return m_ShieldColdRandom; } set { m_ShieldColdRandom = value; } }
public int ShieldSpellChanneling { get { return m_ShieldSpellChanneling; } set { m_ShieldSpellChanneling = value; } }
public int ShieldLuck { get { return m_ShieldLuck; } set { m_ShieldLuck = value; } }
public int ShieldLowerRequirements { get { return m_ShieldLowerRequirements; } set { m_ShieldLowerRequirements = value; } }
public int ShieldRegenHits { get { return m_ShieldRegenHits; } set { m_ShieldRegenHits = value; } }
public int ShieldBonusDex { get { return m_ShieldBonusDex; } set { m_ShieldBonusDex = value; } }
public int ShieldBonusStr { get { return m_ShieldBonusStr; } set { m_ShieldBonusStr = value; } }
public int ShieldReflectPhys { get { return m_ShieldReflectPhys; } set { m_ShieldReflectPhys = value; } }
public int ShieldSelfRepair { get { return m_SelfRepair; } set { m_SelfRepair = value; } }
public int OtherSpellChanneling { get { return m_OtherSpellChanneling; } set { m_OtherSpellChanneling = value; } }
public int OtherLuck { get { return m_OtherLuck; } set { m_OtherLuck = value; } }
public int OtherRegenHits { get { return m_OtherRegenHits; } set { m_OtherRegenHits = value; } }
public int OtherLowerRequirements { get { return m_OtherLowerRequirements; } set { m_OtherLowerRequirements = value; } }
public int RunicMinAttributes { get { return m_RunicMinAttributes; } set { m_RunicMinAttributes = value; } }
public int RunicMaxAttributes { get { return m_RunicMaxAttributes; } set { m_RunicMaxAttributes = value; } }
public int RunicMinIntensity { get { return m_RunicMinIntensity; } set { m_RunicMinIntensity = value; } }
public int RunicMaxIntensity { get { return m_RunicMaxIntensity; } set { m_RunicMaxIntensity = value; } }
public CraftAttributeInfo()
{
}
public static readonly CraftAttributeInfo Blank;
public static readonly CraftAttributeInfo DullCopper, ShadowIron, Copper, Bronze, Golden, Agapite, Verite, Valorite;
public static readonly CraftAttributeInfo Spined, Horned, Barbed;
public static readonly CraftAttributeInfo RedScales, YellowScales, BlackScales, GreenScales, WhiteScales, BlueScales;
public static readonly CraftAttributeInfo OakWood, AshWood, YewWood, Heartwood, Bloodwood, Frostwood;
static CraftAttributeInfo()
{
Blank = new CraftAttributeInfo();
CraftAttributeInfo dullCopper = DullCopper = new CraftAttributeInfo();
dullCopper.ArmorPhysicalResist = 10;
dullCopper.ArmorDurability = 50;
dullCopper.ArmorLowerRequirements = 20;
dullCopper.WeaponDurability = 100;
dullCopper.WeaponLowerRequirements = 50;
dullCopper.RunicMinAttributes = 1;
dullCopper.RunicMaxAttributes = 2;
if (Core.ML)
{
dullCopper.RunicMinIntensity = 40;
dullCopper.RunicMaxIntensity = 100;
}
else
{
dullCopper.RunicMinIntensity = 10;
dullCopper.RunicMaxIntensity = 35;
}
CraftAttributeInfo shadowIron = ShadowIron = new CraftAttributeInfo();
shadowIron.ArmorPhysicalResist = 3;
shadowIron.ArmorFireResist = 2;
shadowIron.ArmorEnergyResist = 7;
shadowIron.ArmorDurability = 100;
shadowIron.WeaponColdDamage = 20;
shadowIron.WeaponDurability = 50;
shadowIron.RunicMinAttributes = 2;
shadowIron.RunicMaxAttributes = 2;
if (Core.ML)
{
shadowIron.RunicMinIntensity = 45;
shadowIron.RunicMaxIntensity = 100;
}
else
{
shadowIron.RunicMinIntensity = 20;
shadowIron.RunicMaxIntensity = 45;
}
CraftAttributeInfo copper = Copper = new CraftAttributeInfo();
copper.ArmorPhysicalResist = 2;
copper.ArmorFireResist = 2;
copper.ArmorPoisonResist = 7;
copper.ArmorEnergyResist = 2;
copper.WeaponPoisonDamage = 10;
copper.WeaponEnergyDamage = 20;
copper.RunicMinAttributes = 2;
copper.RunicMaxAttributes = 3;
if (Core.ML)
{
copper.RunicMinIntensity = 50;
copper.RunicMaxIntensity = 100;
}
else
{
copper.RunicMinIntensity = 25;
copper.RunicMaxIntensity = 50;
}
CraftAttributeInfo bronze = Bronze = new CraftAttributeInfo();
bronze.ArmorPhysicalResist = 3;
bronze.ArmorColdResist = 7;
bronze.ArmorPoisonResist = 2;
bronze.ArmorEnergyResist = 2;
bronze.WeaponFireDamage = 40;
bronze.RunicMinAttributes = 3;
bronze.RunicMaxAttributes = 3;
if (Core.ML)
{
bronze.RunicMinIntensity = 55;
bronze.RunicMaxIntensity = 100;
}
else
{
bronze.RunicMinIntensity = 30;
bronze.RunicMaxIntensity = 65;
}
CraftAttributeInfo golden = Golden = new CraftAttributeInfo();
golden.ArmorPhysicalResist = 2;
golden.ArmorFireResist = 2;
golden.ArmorColdResist = 2;
golden.ArmorEnergyResist = 3;
golden.ArmorLuck = 40;
golden.ArmorLowerRequirements = 30;
golden.WeaponLuck = 40;
golden.WeaponLowerRequirements = 50;
golden.RunicMinAttributes = 3;
golden.RunicMaxAttributes = 4;
if (Core.ML)
{
golden.RunicMinIntensity = 60;
golden.RunicMaxIntensity = 100;
}
else
{
golden.RunicMinIntensity = 35;
golden.RunicMaxIntensity = 75;
}
CraftAttributeInfo agapite = Agapite = new CraftAttributeInfo();
agapite.ArmorPhysicalResist = 2;
agapite.ArmorFireResist = 7;
agapite.ArmorColdResist = 2;
agapite.ArmorPoisonResist = 2;
agapite.ArmorEnergyResist = 2;
agapite.WeaponColdDamage = 30;
agapite.WeaponEnergyDamage = 20;
agapite.RunicMinAttributes = 4;
agapite.RunicMaxAttributes = 4;
if (Core.ML)
{
agapite.RunicMinIntensity = 65;
agapite.RunicMaxIntensity = 100;
}
else
{
agapite.RunicMinIntensity = 40;
agapite.RunicMaxIntensity = 80;
}
CraftAttributeInfo verite = Verite = new CraftAttributeInfo();
verite.ArmorPhysicalResist = 4;
verite.ArmorFireResist = 4;
verite.ArmorColdResist = 3;
verite.ArmorPoisonResist = 4;
verite.ArmorEnergyResist = 1;
verite.WeaponPoisonDamage = 40;
verite.WeaponEnergyDamage = 20;
verite.RunicMinAttributes = 4;
verite.RunicMaxAttributes = 5;
if (Core.ML)
{
verite.RunicMinIntensity = 70;
verite.RunicMaxIntensity = 100;
}
else
{
verite.RunicMinIntensity = 45;
verite.RunicMaxIntensity = 90;
}
CraftAttributeInfo valorite = Valorite = new CraftAttributeInfo();
valorite.ArmorPhysicalResist = 5;
valorite.ArmorColdResist = 4;
valorite.ArmorPoisonResist = 4;
valorite.ArmorEnergyResist = 4;
valorite.ArmorDurability = 50;
valorite.WeaponFireDamage = 10;
valorite.WeaponColdDamage = 20;
valorite.WeaponPoisonDamage = 10;
valorite.WeaponEnergyDamage = 20;
valorite.RunicMinAttributes = 5;
valorite.RunicMaxAttributes = 5;
if (Core.ML)
{
valorite.RunicMinIntensity = 85;
valorite.RunicMaxIntensity = 100;
}
else
{
valorite.RunicMinIntensity = 50;
valorite.RunicMaxIntensity = 100;
}
CraftAttributeInfo spined = Spined = new CraftAttributeInfo();
spined.ArmorPhysicalResist = 9;
spined.ArmorLuck = 40;
spined.RunicMinAttributes = 1;
spined.RunicMaxAttributes = 3;
if (Core.ML)
{
spined.RunicMinIntensity = 40;
spined.RunicMaxIntensity = 100;
}
else
{
spined.RunicMinIntensity = 20;
spined.RunicMaxIntensity = 40;
}
CraftAttributeInfo horned = Horned = new CraftAttributeInfo();
horned.ArmorPhysicalResist = 2;
horned.ArmorFireResist = 4;
horned.ArmorColdResist = 3;
horned.ArmorPoisonResist = 3;
horned.ArmorEnergyResist = 3;
horned.RunicMinAttributes = 3;
horned.RunicMaxAttributes = 4;
if (Core.ML)
{
horned.RunicMinIntensity = 45;
horned.RunicMaxIntensity = 100;
}
else
{
horned.RunicMinIntensity = 30;
horned.RunicMaxIntensity = 70;
}
CraftAttributeInfo barbed = Barbed = new CraftAttributeInfo();
barbed.ArmorPhysicalResist = 3;
barbed.ArmorFireResist = 2;
barbed.ArmorColdResist = 3;
barbed.ArmorPoisonResist = 3;
barbed.ArmorEnergyResist = 5;
barbed.RunicMinAttributes = 4;
barbed.RunicMaxAttributes = 5;
if (Core.ML)
{
barbed.RunicMinIntensity = 50;
barbed.RunicMaxIntensity = 100;
}
else
{
barbed.RunicMinIntensity = 40;
barbed.RunicMaxIntensity = 100;
}
CraftAttributeInfo red = RedScales = new CraftAttributeInfo();
red.ArmorPhysicalResist = 1;
red.ArmorFireResist = 11;
red.ArmorColdResist = -3;
red.ArmorPoisonResist = 1;
red.ArmorEnergyResist = 1;
CraftAttributeInfo yellow = YellowScales = new CraftAttributeInfo();
yellow.ArmorPhysicalResist = -3;
yellow.ArmorFireResist = 1;
yellow.ArmorColdResist = 1;
yellow.ArmorPoisonResist = 1;
yellow.ArmorPoisonResist = 1;
yellow.ArmorLuck = 20;
CraftAttributeInfo black = BlackScales = new CraftAttributeInfo();
black.ArmorPhysicalResist = 11;
black.ArmorEnergyResist = -3;
black.ArmorFireResist = 1;
black.ArmorPoisonResist = 1;
black.ArmorColdResist = 1;
CraftAttributeInfo green = GreenScales = new CraftAttributeInfo();
green.ArmorFireResist = -3;
green.ArmorPhysicalResist = 1;
green.ArmorColdResist = 1;
green.ArmorEnergyResist = 1;
green.ArmorPoisonResist = 11;
CraftAttributeInfo white = WhiteScales = new CraftAttributeInfo();
white.ArmorPhysicalResist = -3;
white.ArmorFireResist = 1;
white.ArmorEnergyResist = 1;
white.ArmorPoisonResist = 1;
white.ArmorColdResist = 11;
CraftAttributeInfo blue = BlueScales = new CraftAttributeInfo();
blue.ArmorPhysicalResist = 1;
blue.ArmorFireResist = 1;
blue.ArmorColdResist = 1;
blue.ArmorPoisonResist = -3;
blue.ArmorEnergyResist = 11;
#region Mondain's Legacy
CraftAttributeInfo oak = OakWood = new CraftAttributeInfo();
oak.ArmorPhysicalResist = 3;
oak.ArmorFireResist = 3;
oak.ArmorPoisonResist = 2;
oak.ArmorEnergyResist = 3;
oak.ArmorLuck = 40;
oak.ShieldPhysicalResist = 1;
oak.ShieldFireResist = 1;
oak.ShieldColdResist = 1;
oak.ShieldPoisonResist = 1;
oak.ShieldEnergyResist = 1;
oak.WeaponLuck = 40;
oak.WeaponDamage = 5;
oak.RunicMinAttributes = 1;
oak.RunicMaxAttributes = 2;
oak.RunicMinIntensity = 1;
oak.RunicMaxIntensity = 50;
CraftAttributeInfo ash = AshWood = new CraftAttributeInfo();
ash.ArmorPhysicalResist = 2;
ash.ArmorColdResist = 4;
ash.ArmorPoisonResist = 1;
ash.ArmorEnergyResist = 6;
ash.ArmorLowerRequirements = 20;
ash.ShieldEnergyResist = 3;
ash.ShieldLowerRequirements = 3;
ash.WeaponSwingSpeed = 10;
ash.WeaponLowerRequirements = 20;
ash.OtherLowerRequirements = 20;
ash.RunicMinAttributes = 2;
ash.RunicMaxAttributes = 3;
ash.RunicMinIntensity = 35;
ash.RunicMaxIntensity = 75;
CraftAttributeInfo yew = YewWood = new CraftAttributeInfo();
yew.ArmorPhysicalResist = 6;
yew.ArmorFireResist = 3;
yew.ArmorColdResist = 3;
yew.ArmorEnergyResist = 3;
yew.ArmorRegenHits = 1;
yew.ShieldPhysicalResist = 3;
yew.ShieldRegenHits = 1;
yew.WeaponHitChance = 5;
yew.WeaponDamage = 10;
yew.OtherRegenHits = 2;
yew.RunicMinAttributes = 3;
yew.RunicMaxAttributes = 3;
yew.RunicMinIntensity = 40;
yew.RunicMaxIntensity = 90;
CraftAttributeInfo heartwood = Heartwood = new CraftAttributeInfo();
heartwood.ArmorPhysicalResist = 2;
heartwood.ArmorFireResist = 3;
heartwood.ArmorColdResist = 2;
heartwood.ArmorPoisonResist = 7;
heartwood.ArmorEnergyResist = 2;
// one of below
heartwood.ArmorDamage = 10;
heartwood.ArmorHitChance = 5;
heartwood.ArmorLuck = 40;
heartwood.ArmorLowerRequirements = 20;
heartwood.ArmorMage = 1;
// one of below
heartwood.WeaponDamage = 10;
heartwood.WeaponHitChance = 5;
heartwood.WeaponHitLifeLeech = 13;
heartwood.WeaponLuck = 40;
heartwood.WeaponLowerRequirements = 20;
heartwood.WeaponSwingSpeed = 10;
heartwood.ShieldBonusDex = 2;
heartwood.ShieldBonusStr = 2;
heartwood.ShieldPhysicalRandom = 5;
heartwood.ShieldReflectPhys = 5;
heartwood.ShieldSelfRepair = 2;
heartwood.ShieldColdRandom = 3;
heartwood.ShieldSpellChanneling = 1;
heartwood.RunicMinAttributes = 4;
heartwood.RunicMaxAttributes = 4;
heartwood.RunicMinIntensity = 50;
heartwood.RunicMaxIntensity = 100;
CraftAttributeInfo bloodwood = Bloodwood = new CraftAttributeInfo();
bloodwood.ArmorPhysicalResist = 3;
bloodwood.ArmorFireResist = 8;
bloodwood.ArmorColdResist = 1;
bloodwood.ArmorPoisonResist = 3;
bloodwood.ArmorEnergyResist = 3;
bloodwood.ArmorRegenHits = 2;
bloodwood.ShieldFireResist = 3;
bloodwood.ShieldLuck = 40;
bloodwood.ShieldRegenHits = 2;
bloodwood.WeaponRegenHits = 2;
bloodwood.WeaponHitLifeLeech = 16;
bloodwood.OtherLuck = 20;
bloodwood.OtherRegenHits = 2;
CraftAttributeInfo frostwood = Frostwood = new CraftAttributeInfo();
frostwood.ArmorPhysicalResist = 2;
frostwood.ArmorFireResist = 1;
frostwood.ArmorColdResist = 8;
frostwood.ArmorPoisonResist = 3;
frostwood.ArmorEnergyResist = 4;
frostwood.ShieldColdResist = 3;
frostwood.ShieldSpellChanneling = 1;
frostwood.WeaponColdDamage = 40;
frostwood.WeaponDamage = 12;
frostwood.OtherSpellChanneling = 1;
#endregion
}
}
public class CraftResourceInfo
{
private readonly int m_Hue;
private readonly int m_Number;
private readonly string m_Name;
private readonly CraftAttributeInfo m_AttributeInfo;
private readonly CraftResource m_Resource;
private readonly Type[] m_ResourceTypes;
public int Hue
{
get
{
return this.m_Hue;
}
}
public int Number
{
get
{
return this.m_Number;
}
}
public string Name
{
get
{
return this.m_Name;
}
}
public CraftAttributeInfo AttributeInfo
{
get
{
return this.m_AttributeInfo;
}
}
public CraftResource Resource
{
get
{
return this.m_Resource;
}
}
public Type[] ResourceTypes
{
get
{
return this.m_ResourceTypes;
}
}
public CraftResourceInfo(int hue, int number, string name, CraftAttributeInfo attributeInfo, CraftResource resource, params Type[] resourceTypes)
{
this.m_Hue = hue;
this.m_Number = number;
this.m_Name = name;
this.m_AttributeInfo = attributeInfo;
this.m_Resource = resource;
this.m_ResourceTypes = resourceTypes;
for (int i = 0; i < resourceTypes.Length; ++i)
CraftResources.RegisterType(resourceTypes[i], resource);
}
}
public class CraftResources
{
private static readonly CraftResourceInfo[] m_MetalInfo = new CraftResourceInfo[]
{
new CraftResourceInfo(0x000, 1053109, "Iron", CraftAttributeInfo.Blank, CraftResource.Iron, typeof(IronIngot), typeof(IronOre), typeof(Granite)),
new CraftResourceInfo(0x973, 1053108, "Dull Copper", CraftAttributeInfo.DullCopper, CraftResource.DullCopper, typeof(DullCopperIngot), typeof(DullCopperOre), typeof(DullCopperGranite)),
new CraftResourceInfo(0x966, 1053107, "Shadow Iron", CraftAttributeInfo.ShadowIron, CraftResource.ShadowIron, typeof(ShadowIronIngot), typeof(ShadowIronOre), typeof(ShadowIronGranite)),
new CraftResourceInfo(0x96D, 1053106, "Copper", CraftAttributeInfo.Copper, CraftResource.Copper, typeof(CopperIngot), typeof(CopperOre), typeof(CopperGranite)),
new CraftResourceInfo(0x972, 1053105, "Bronze", CraftAttributeInfo.Bronze, CraftResource.Bronze, typeof(BronzeIngot), typeof(BronzeOre), typeof(BronzeGranite)),
new CraftResourceInfo(0x8A5, 1053104, "Gold", CraftAttributeInfo.Golden, CraftResource.Gold, typeof(GoldIngot), typeof(GoldOre), typeof(GoldGranite)),
new CraftResourceInfo(0x979, 1053103, "Agapite", CraftAttributeInfo.Agapite, CraftResource.Agapite, typeof(AgapiteIngot), typeof(AgapiteOre), typeof(AgapiteGranite)),
new CraftResourceInfo(0x89F, 1053102, "Verite", CraftAttributeInfo.Verite, CraftResource.Verite, typeof(VeriteIngot), typeof(VeriteOre), typeof(VeriteGranite)),
new CraftResourceInfo(0x8AB, 1053101, "Valorite", CraftAttributeInfo.Valorite, CraftResource.Valorite, typeof(ValoriteIngot), typeof(ValoriteOre), typeof(ValoriteGranite)),
};
private static readonly CraftResourceInfo[] m_ScaleInfo = new CraftResourceInfo[]
{
new CraftResourceInfo(0x66D, 1053129, "Red Scales", CraftAttributeInfo.RedScales, CraftResource.RedScales, typeof(RedScales)),
new CraftResourceInfo(0x8A8, 1053130, "Yellow Scales", CraftAttributeInfo.YellowScales, CraftResource.YellowScales, typeof(YellowScales)),
new CraftResourceInfo(0x455, 1053131, "Black Scales", CraftAttributeInfo.BlackScales, CraftResource.BlackScales, typeof(BlackScales)),
new CraftResourceInfo(0x851, 1053132, "Green Scales", CraftAttributeInfo.GreenScales, CraftResource.GreenScales, typeof(GreenScales)),
new CraftResourceInfo(0x8FD, 1053133, "White Scales", CraftAttributeInfo.WhiteScales, CraftResource.WhiteScales, typeof(WhiteScales)),
new CraftResourceInfo(0x8B0, 1053134, "Blue Scales", CraftAttributeInfo.BlueScales, CraftResource.BlueScales, typeof(BlueScales))
};
private static readonly CraftResourceInfo[] m_LeatherInfo = new CraftResourceInfo[]
{
new CraftResourceInfo(0x000, 1049353, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularLeather, typeof(Leather), typeof(Hides)),
new CraftResourceInfo(0x283, 1049354, "Spined", CraftAttributeInfo.Spined, CraftResource.SpinedLeather, typeof(SpinedLeather), typeof(SpinedHides)),
new CraftResourceInfo(0x227, 1049355, "Horned", CraftAttributeInfo.Horned, CraftResource.HornedLeather, typeof(HornedLeather), typeof(HornedHides)),
new CraftResourceInfo(0x1C1, 1049356, "Barbed", CraftAttributeInfo.Barbed, CraftResource.BarbedLeather, typeof(BarbedLeather), typeof(BarbedHides))
};
private static readonly CraftResourceInfo[] m_AOSLeatherInfo = new CraftResourceInfo[]
{
new CraftResourceInfo(0x000, 1049353, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularLeather, typeof(Leather), typeof(Hides)),
new CraftResourceInfo(0x8AC, 1049354, "Spined", CraftAttributeInfo.Spined, CraftResource.SpinedLeather, typeof(SpinedLeather), typeof(SpinedHides)),
new CraftResourceInfo(0x845, 1049355, "Horned", CraftAttributeInfo.Horned, CraftResource.HornedLeather, typeof(HornedLeather), typeof(HornedHides)),
new CraftResourceInfo(0x851, 1049356, "Barbed", CraftAttributeInfo.Barbed, CraftResource.BarbedLeather, typeof(BarbedLeather), typeof(BarbedHides)),
};
private static readonly CraftResourceInfo[] m_WoodInfo = new CraftResourceInfo[]
{
new CraftResourceInfo(0x000, 1011542, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularWood, typeof(Log), typeof(Board)),
new CraftResourceInfo(0x7DA, 1072533, "Oak", CraftAttributeInfo.OakWood, CraftResource.OakWood, typeof(OakLog), typeof(OakBoard)),
new CraftResourceInfo(0x4A7, 1072534, "Ash", CraftAttributeInfo.AshWood, CraftResource.AshWood, typeof(AshLog), typeof(AshBoard)),
new CraftResourceInfo(0x4A8, 1072535, "Yew", CraftAttributeInfo.YewWood, CraftResource.YewWood, typeof(YewLog), typeof(YewBoard)),
new CraftResourceInfo(0x4A9, 1072536, "Heartwood", CraftAttributeInfo.Heartwood, CraftResource.Heartwood, typeof(HeartwoodLog), typeof(HeartwoodBoard)),
new CraftResourceInfo(0x4AA, 1072538, "Bloodwood", CraftAttributeInfo.Bloodwood, CraftResource.Bloodwood, typeof(BloodwoodLog), typeof(BloodwoodBoard)),
new CraftResourceInfo(0x47F, 1072539, "Frostwood", CraftAttributeInfo.Frostwood, CraftResource.Frostwood, typeof(FrostwoodLog), typeof(FrostwoodBoard))
};
/// <summary>
/// Returns true if '<paramref name="resource"/>' is None, Iron, RegularLeather or RegularWood. False if otherwise.
/// </summary>
public static bool IsStandard(CraftResource resource)
{
return (resource == CraftResource.None || resource == CraftResource.Iron || resource == CraftResource.RegularLeather || resource == CraftResource.RegularWood);
}
private static Hashtable m_TypeTable;
/// <summary>
/// Registers that '<paramref name="resourceType"/>' uses '<paramref name="resource"/>' so that it can later be queried by <see cref="CraftResources.GetFromType"/>
/// </summary>
public static void RegisterType(Type resourceType, CraftResource resource)
{
if (m_TypeTable == null)
m_TypeTable = new Hashtable();
m_TypeTable[resourceType] = resource;
}
/// <summary>
/// Returns the <see cref="CraftResource"/> value for which '<paramref name="resourceType"/>' uses -or- CraftResource.None if an unregistered type was specified.
/// </summary>
public static CraftResource GetFromType(Type resourceType)
{
if (m_TypeTable == null)
return CraftResource.None;
object obj = m_TypeTable[resourceType];
if (!(obj is CraftResource))
return CraftResource.None;
return (CraftResource)obj;
}
/// <summary>
/// Returns a <see cref="CraftResourceInfo"/> instance describing '<paramref name="resource"/>' -or- null if an invalid resource was specified.
/// </summary>
public static CraftResourceInfo GetInfo(CraftResource resource)
{
CraftResourceInfo[] list = null;
switch (GetType(resource))
{
case CraftResourceType.Metal:
list = m_MetalInfo;
break;
case CraftResourceType.Leather:
list = Core.AOS ? m_AOSLeatherInfo : m_LeatherInfo;
break;
case CraftResourceType.Scales:
list = m_ScaleInfo;
break;
case CraftResourceType.Wood:
list = m_WoodInfo;
break;
}
if (list != null)
{
int index = GetIndex(resource);
if (index >= 0 && index < list.Length)
return list[index];
}
return null;
}
/// <summary>
/// Returns a <see cref="CraftResourceType"/> value indiciating the type of '<paramref name="resource"/>'.
/// </summary>
public static CraftResourceType GetType(CraftResource resource)
{
if (resource >= CraftResource.Iron && resource <= CraftResource.Valorite)
return CraftResourceType.Metal;
if (resource >= CraftResource.RegularLeather && resource <= CraftResource.BarbedLeather)
return CraftResourceType.Leather;
if (resource >= CraftResource.RedScales && resource <= CraftResource.BlueScales)
return CraftResourceType.Scales;
if (resource >= CraftResource.RegularWood && resource <= CraftResource.Frostwood)
return CraftResourceType.Wood;
return CraftResourceType.None;
}
/// <summary>
/// Returns the first <see cref="CraftResource"/> in the series of resources for which '<paramref name="resource"/>' belongs.
/// </summary>
public static CraftResource GetStart(CraftResource resource)
{
switch (GetType(resource))
{
case CraftResourceType.Metal:
return CraftResource.Iron;
case CraftResourceType.Leather:
return CraftResource.RegularLeather;
case CraftResourceType.Scales:
return CraftResource.RedScales;
case CraftResourceType.Wood:
return CraftResource.RegularWood;
}
return CraftResource.None;
}
/// <summary>
/// Returns the index of '<paramref name="resource"/>' in the seriest of resources for which it belongs.
/// </summary>
public static int GetIndex(CraftResource resource)
{
CraftResource start = GetStart(resource);
if (start == CraftResource.None)
return 0;
return (int)(resource - start);
}
/// <summary>
/// Returns the <see cref="CraftResourceInfo.Number"/> property of '<paramref name="resource"/>' -or- 0 if an invalid resource was specified.
/// </summary>
public static int GetLocalizationNumber(CraftResource resource)
{
CraftResourceInfo info = GetInfo(resource);
return (info == null ? 0 : info.Number);
}
/// <summary>
/// Returns the <see cref="CraftResourceInfo.Hue"/> property of '<paramref name="resource"/>' -or- 0 if an invalid resource was specified.
/// </summary>
public static int GetHue(CraftResource resource)
{
CraftResourceInfo info = GetInfo(resource);
return (info == null ? 0 : info.Hue);
}
/// <summary>
/// Returns the <see cref="CraftResourceInfo.Name"/> property of '<paramref name="resource"/>' -or- an empty string if the resource specified was invalid.
/// </summary>
public static string GetName(CraftResource resource)
{
CraftResourceInfo info = GetInfo(resource);
return (info == null ? String.Empty : info.Name);
}
/// <summary>
/// Returns the <see cref="CraftResource"/> value which represents '<paramref name="info"/>' -or- CraftResource.None if unable to convert.
/// </summary>
public static CraftResource GetFromOreInfo(OreInfo info)
{
if (info.Name.IndexOf("Spined") >= 0)
return CraftResource.SpinedLeather;
else if (info.Name.IndexOf("Horned") >= 0)
return CraftResource.HornedLeather;
else if (info.Name.IndexOf("Barbed") >= 0)
return CraftResource.BarbedLeather;
else if (info.Name.IndexOf("Leather") >= 0)
return CraftResource.RegularLeather;
if (info.Level == 0)
return CraftResource.Iron;
else if (info.Level == 1)
return CraftResource.DullCopper;
else if (info.Level == 2)
return CraftResource.ShadowIron;
else if (info.Level == 3)
return CraftResource.Copper;
else if (info.Level == 4)
return CraftResource.Bronze;
else if (info.Level == 5)
return CraftResource.Gold;
else if (info.Level == 6)
return CraftResource.Agapite;
else if (info.Level == 7)
return CraftResource.Verite;
else if (info.Level == 8)
return CraftResource.Valorite;
return CraftResource.None;
}
/// <summary>
/// Returns the <see cref="CraftResource"/> value which represents '<paramref name="info"/>', using '<paramref name="material"/>' to help resolve leather OreInfo instances.
/// </summary>
public static CraftResource GetFromOreInfo(OreInfo info, ArmorMaterialType material)
{
if (material == ArmorMaterialType.Studded || material == ArmorMaterialType.Leather || material == ArmorMaterialType.Spined ||
material == ArmorMaterialType.Horned || material == ArmorMaterialType.Barbed)
{
if (info.Level == 0)
return CraftResource.RegularLeather;
else if (info.Level == 1)
return CraftResource.SpinedLeather;
else if (info.Level == 2)
return CraftResource.HornedLeather;
else if (info.Level == 3)
return CraftResource.BarbedLeather;
return CraftResource.None;
}
return GetFromOreInfo(info);
}
}
// NOTE: This class is only for compatability with very old RunUO versions.
// No changes to it should be required for custom resources.
public class OreInfo
{
public static readonly OreInfo Iron = new OreInfo(0, 0x000, "Iron");
public static readonly OreInfo DullCopper = new OreInfo(1, 0x973, "Dull Copper");
public static readonly OreInfo ShadowIron = new OreInfo(2, 0x966, "Shadow Iron");
public static readonly OreInfo Copper = new OreInfo(3, 0x96D, "Copper");
public static readonly OreInfo Bronze = new OreInfo(4, 0x972, "Bronze");
public static readonly OreInfo Gold = new OreInfo(5, 0x8A5, "Gold");
public static readonly OreInfo Agapite = new OreInfo(6, 0x979, "Agapite");
public static readonly OreInfo Verite = new OreInfo(7, 0x89F, "Verite");
public static readonly OreInfo Valorite = new OreInfo(8, 0x8AB, "Valorite");
private readonly int m_Level;
private readonly int m_Hue;
private readonly string m_Name;
public OreInfo(int level, int hue, string name)
{
this.m_Level = level;
this.m_Hue = hue;
this.m_Name = name;
}
public int Level
{
get
{
return this.m_Level;
}
}
public int Hue
{
get
{
return this.m_Hue;
}
}
public string Name
{
get
{
return this.m_Name;
}
}
}
}

263
Scripts/Misc/ServerList.cs Normal file
View File

@@ -0,0 +1,263 @@
#region References
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading;
#endregion
namespace Server.Misc
{
public class ServerList
{
/*
* The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses
* are private network addresses and AutoDetect is 'true' then ServUO will attempt to discover your public IP address
* for you automatically.
*
* If you do not plan on allowing clients outside of your LAN to connect, you can set AutoDetect to 'false' and leave
* Address set to 'null'.
*
* If your public IP address cannot be determined, you must change the value of Address to your public IP address
* manually to allow clients outside of your LAN to connect to your server. Address can be either an IP address or
* a hostname that will be resolved when ServUO starts.
*
* If you want players outside your LAN to be able to connect to your server and you are behind a router, you must also
* forward TCP port 2593 to your private IP address. The procedure for doing this varies by manufacturer but generally
* involves configuration of the router through your web browser.
*
* ServerList will direct connecting clients depending on both the address they are connecting from and the address and
* port they are connecting to. If it is determined that both ends of a connection are private IP addresses, ServerList
* will direct the client to the local private IP address. If a client is connecting to a local public IP address, they
* will be directed to whichever address and port they initially connected to. This allows multihomed servers to function
* properly and fully supports listening on multiple ports. If a client with a public IP address is connecting to a
* locally private address, the server will direct the client to either the AutoDetected IP address or the manually entered
* IP address or hostname, whichever is applicable. Loopback clients will be directed to loopback.
*
* If you would like to listen on additional ports (i.e. 22, 23, 80, for clients behind highly restrictive egress
* firewalls) or specific IP adddresses you can do so by modifying the file SocketOptions.cs found in this directory.
*/
public static readonly string Address = Config.Get("Server.Address", default(string));
public static readonly bool AutoDetect = Config.Get("Server.AutoDetect", true);
public static string ServerName = Config.Get("Server.Name", "My Shard");
private static IPAddress _PublicAddress;
private static readonly Regex _AddressPattern = new Regex(@"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})");
public static void Initialize()
{
if (Address == null)
{
if (AutoDetect)
{
AutoDetection();
}
}
else
{
Resolve(Address, out _PublicAddress);
}
EventSink.ServerList += EventSink_ServerList;
}
private static void EventSink_ServerList(ServerListEventArgs e)
{
try
{
var ns = e.State;
var s = ns.Socket;
var ipep = (IPEndPoint)s.LocalEndPoint;
var localAddress = ipep.Address;
var localPort = ipep.Port;
if (IsPrivateNetwork(localAddress))
{
ipep = (IPEndPoint)s.RemoteEndPoint;
if (!IsPrivateNetwork(ipep.Address) && _PublicAddress != null)
{
localAddress = _PublicAddress;
}
}
e.AddServer(ServerName, new IPEndPoint(localAddress, localPort));
}
catch
{
e.Rejected = true;
}
}
public static string[] IPServices =
{
"http://services.servuo.com/ip.php", "http://api.ipify.org",
"http://checkip.dyndns.org/"
};
private static void AutoDetection()
{
if (!HasPublicIPAddress())
{
Utility.PushColor(ConsoleColor.Yellow);
Console.WriteLine("ServerList: Auto-detecting public IP address...");
_PublicAddress = FindPublicAddress(IPServices);
if (_PublicAddress != null)
{
Console.WriteLine("ServerList: Done: '{0}'", _PublicAddress);
}
else
{
_PublicAddress = IPAddress.Any;
Console.WriteLine("ServerList: Failed: reverting to private IP address...");
}
Utility.PopColor();
}
}
private static void Resolve(string addr, out IPAddress outValue)
{
if (IPAddress.TryParse(addr, out outValue))
{
return;
}
try
{
var iphe = Dns.GetHostEntry(addr);
if (iphe.AddressList.Length > 0)
{
outValue = iphe.AddressList[iphe.AddressList.Length - 1];
}
}
catch
{ }
}
private static bool HasPublicIPAddress()
{
var adapters = NetworkInterface.GetAllNetworkInterfaces();
var uips = adapters.Select(a => a.GetIPProperties())
.SelectMany(p => p.UnicastAddresses.Cast<IPAddressInformation>(), (p, u) => u.Address);
return
uips.Any(
ip => !IPAddress.IsLoopback(ip) && ip.AddressFamily != AddressFamily.InterNetworkV6 && !IsPrivateNetwork(ip));
}
private static bool IsPrivateNetwork(IPAddress ip)
{
// 10.0.0.0/8
// 172.16.0.0/12
// 192.168.0.0/16
// 169.254.0.0/16
// 100.64.0.0/10 RFC 6598
if (ip.AddressFamily == AddressFamily.InterNetworkV6)
{
return false;
}
if (Utility.IPMatch("192.168.*", ip))
{
return true;
}
if (Utility.IPMatch("10.*", ip))
{
return true;
}
if (Utility.IPMatch("172.16-31.*", ip))
{
return true;
}
if (Utility.IPMatch("169.254.*", ip))
{
return true;
}
if (Utility.IPMatch("100.64-127.*", ip))
{
return true;
}
return false;
}
public static IPAddress FindPublicAddress(params string[] services)
{
if (services == null || services.Length == 0)
{
services = IPServices;
}
if (services == null || services.Length == 0)
{
return null;
}
IPAddress ip = null;
Uri uri;
string data;
Match match;
foreach (var service in services.Where(s => !String.IsNullOrWhiteSpace(s)))
{
try
{
uri = new Uri(service);
Console.WriteLine("ServerList: >>> {0}", uri.Host);
using (var client = new WebClient())
{
data = client.DownloadString(uri);
}
Console.WriteLine("ServerList: <<< {0}", data);
match = _AddressPattern.Match(data);
if (!match.Success || !IPAddress.TryParse(match.Value, out ip))
{
ip = null;
}
}
catch (UriFormatException)
{
Console.WriteLine("ServerList: Invalid IP service Uri '{0}'", service);
ip = null;
}
catch
{
ip = null;
}
if (ip != null)
{
break;
}
}
return ip;
}
}
}

699
Scripts/Misc/ShardPoller.cs Normal file
View File

@@ -0,0 +1,699 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using Server.Gumps;
using Server.Network;
using Server.Prompts;
namespace Server.Misc
{
public class ShardPoller : Item
{
private static readonly List<ShardPoller> m_ActivePollers = new List<ShardPoller>();
private string m_Title;
private ShardPollOption[] m_Options;
private IPAddress[] m_Addresses;
private TimeSpan m_Duration;
private DateTime m_StartTime;
private bool m_Active;
[Constructable(AccessLevel.Administrator)]
public ShardPoller()
: base(0x1047)
{
this.m_Duration = TimeSpan.FromHours(24.0);
this.m_Options = new ShardPollOption[0];
this.m_Addresses = new IPAddress[0];
this.Movable = false;
}
public ShardPoller(Serial serial)
: base(serial)
{
}
public ShardPollOption[] Options
{
get
{
return this.m_Options;
}
set
{
this.m_Options = value;
}
}
public IPAddress[] Addresses
{
get
{
return this.m_Addresses;
}
set
{
this.m_Addresses = value;
}
}
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public string Title
{
get
{
return this.m_Title;
}
set
{
this.m_Title = ShardPollPrompt.UrlToHref(value);
}
}
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public TimeSpan Duration
{
get
{
return this.m_Duration;
}
set
{
this.m_Duration = value;
}
}
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public DateTime StartTime
{
get
{
return this.m_StartTime;
}
set
{
this.m_StartTime = value;
}
}
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public TimeSpan TimeRemaining
{
get
{
if (this.m_StartTime == DateTime.MinValue || !this.m_Active)
return TimeSpan.Zero;
try
{
TimeSpan ts = (this.m_StartTime + this.m_Duration) - DateTime.UtcNow;
if (ts < TimeSpan.Zero)
return TimeSpan.Zero;
return ts;
}
catch
{
return TimeSpan.Zero;
}
}
}
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public bool Active
{
get
{
return this.m_Active;
}
set
{
if (this.m_Active == value)
return;
this.m_Active = value;
if (this.m_Active)
{
this.m_StartTime = DateTime.UtcNow;
m_ActivePollers.Add(this);
}
else
{
m_ActivePollers.Remove(this);
}
}
}
public override string DefaultName
{
get
{
return "shard poller";
}
}
public static void Initialize()
{
EventSink.Login += new LoginEventHandler(EventSink_Login);
}
public bool HasAlreadyVoted(NetState ns)
{
for (int i = 0; i < this.m_Options.Length; ++i)
{
if (this.m_Options[i].HasAlreadyVoted(ns))
return true;
}
return false;
}
public void AddVote(NetState ns, ShardPollOption option)
{
option.AddVote(ns);
}
public void RemoveOption(ShardPollOption option)
{
int index = Array.IndexOf(this.m_Options, option);
if (index < 0)
return;
ShardPollOption[] old = this.m_Options;
this.m_Options = new ShardPollOption[old.Length - 1];
for (int i = 0; i < index; ++i)
this.m_Options[i] = old[i];
for (int i = index; i < this.m_Options.Length; ++i)
this.m_Options[i] = old[i + 1];
}
public void AddOption(ShardPollOption option)
{
ShardPollOption[] old = this.m_Options;
this.m_Options = new ShardPollOption[old.Length + 1];
for (int i = 0; i < old.Length; ++i)
this.m_Options[i] = old[i];
this.m_Options[old.Length] = option;
}
public void SendQueuedPoll_Callback(object state)
{
object[] states = (object[])state;
Mobile from = (Mobile)states[0];
Queue<ShardPoller> queue = (Queue<ShardPoller>)states[1];
from.SendGump(new ShardPollGump(from, this, false, queue));
}
public override void OnDoubleClick(Mobile from)
{
if (from.AccessLevel >= AccessLevel.Administrator)
from.SendGump(new ShardPollGump(from, this, true, null));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write(this.m_Title);
writer.Write(this.m_Duration);
writer.Write(this.m_StartTime);
writer.Write(this.m_Active);
writer.Write(this.m_Options.Length);
for (int i = 0; i < this.m_Options.Length; ++i)
this.m_Options[i].Serialize(writer);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
this.m_Title = reader.ReadString();
this.m_Duration = reader.ReadTimeSpan();
this.m_StartTime = reader.ReadDateTime();
this.m_Active = reader.ReadBool();
this.m_Options = new ShardPollOption[reader.ReadInt()];
for (int i = 0; i < this.m_Options.Length; ++i)
this.m_Options[i] = new ShardPollOption(reader);
if (this.m_Active)
m_ActivePollers.Add(this);
break;
}
}
}
public override void OnDelete()
{
base.OnDelete();
this.Active = false;
}
private static void EventSink_Login(LoginEventArgs e)
{
if (m_ActivePollers.Count == 0)
return;
Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerStateCallback(EventSink_Login_Callback), e.Mobile);
}
private static void EventSink_Login_Callback(object state)
{
Mobile from = (Mobile)state;
NetState ns = from.NetState;
if (ns == null)
return;
ShardPollGump spg = null;
for (int i = 0; i < m_ActivePollers.Count; ++i)
{
ShardPoller poller = m_ActivePollers[i];
if (poller.Deleted || !poller.Active)
continue;
if (poller.TimeRemaining > TimeSpan.Zero)
{
if (poller.HasAlreadyVoted(ns))
continue;
if (spg == null)
{
spg = new ShardPollGump(from, poller, false, null);
from.SendGump(spg);
}
else
{
spg.QueuePoll(poller);
}
}
else
{
poller.Active = false;
}
}
}
}
public class ShardPollOption
{
private string m_Title;
private int m_LineBreaks;
private IPAddress[] m_Voters;
public ShardPollOption(string title)
{
this.m_Title = title;
this.m_LineBreaks = this.GetBreaks(this.m_Title);
this.m_Voters = new IPAddress[0];
}
public ShardPollOption(GenericReader reader)
{
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
this.m_Title = reader.ReadString();
this.m_LineBreaks = this.GetBreaks(this.m_Title);
this.m_Voters = new IPAddress[reader.ReadInt()];
for (int i = 0; i < this.m_Voters.Length; ++i)
this.m_Voters[i] = Utility.Intern(reader.ReadIPAddress());
break;
}
}
}
public string Title
{
get
{
return this.m_Title;
}
set
{
this.m_Title = value;
this.m_LineBreaks = this.GetBreaks(this.m_Title);
}
}
public int LineBreaks
{
get
{
return this.m_LineBreaks;
}
}
public int Votes
{
get
{
return this.m_Voters.Length;
}
}
public IPAddress[] Voters
{
get
{
return this.m_Voters;
}
set
{
this.m_Voters = value;
}
}
public bool HasAlreadyVoted(NetState ns)
{
if (ns == null)
return false;
IPAddress ipAddress = ns.Address;
for (int i = 0; i < this.m_Voters.Length; ++i)
{
if (Utility.IPMatchClassC(this.m_Voters[i], ipAddress))
return true;
}
return false;
}
public void AddVote(NetState ns)
{
if (ns == null)
return;
IPAddress[] old = this.m_Voters;
this.m_Voters = new IPAddress[old.Length + 1];
for (int i = 0; i < old.Length; ++i)
this.m_Voters[i] = old[i];
this.m_Voters[old.Length] = ns.Address;
}
public int ComputeHeight()
{
int height = this.m_LineBreaks * 18;
if (height > 30)
return height;
return 30;
}
public int GetBreaks(string title)
{
if (title == null)
return 1;
int count = 0;
int index = -1;
do
{
++count;
index = title.IndexOf("<br>", index + 1);
}
while (index >= 0);
return count;
}
public void Serialize(GenericWriter writer)
{
writer.Write((int)0); // version
writer.Write(this.m_Title);
writer.Write(this.m_Voters.Length);
for (int i = 0; i < this.m_Voters.Length; ++i)
writer.Write(this.m_Voters[i]);
}
}
public class ShardPollGump : Gump
{
private const int LabelColor32 = 0xFFFFFF;
private readonly Mobile m_From;
private readonly ShardPoller m_Poller;
private readonly bool m_Editing;
private Queue<ShardPoller> m_Polls;
public ShardPollGump(Mobile from, ShardPoller poller, bool editing, Queue<ShardPoller> polls)
: base(50, 50)
{
this.m_From = from;
this.m_Poller = poller;
this.m_Editing = editing;
this.m_Polls = polls;
this.Closable = false;
this.AddPage(0);
int totalVotes = 0;
int totalOptionHeight = 0;
for (int i = 0; i < poller.Options.Length; ++i)
{
totalVotes += poller.Options[i].Votes;
totalOptionHeight += poller.Options[i].ComputeHeight() + 5;
}
bool isViewingResults = editing && poller.Active;
bool isCompleted = totalVotes > 0 && !poller.Active;
if (editing && !isViewingResults)
totalOptionHeight += 35;
int height = 115 + totalOptionHeight;
this.AddBackground(1, 1, 398, height - 2, 3600);
this.AddAlphaRegion(16, 15, 369, height - 31);
this.AddItem(308, 30, 0x1E5E);
string title;
if (editing)
title = (isCompleted ? "Poll Completed" : "Poll Editor");
else
title = "Shard Poll";
this.AddHtml(22, 22, 294, 20, this.Color(this.Center(title), LabelColor32), false, false);
if (editing)
{
this.AddHtml(22, 22, 294, 20, this.Color(String.Format("{0} total", totalVotes), LabelColor32), false, false);
this.AddButton(287, 23, 0x2622, 0x2623, 2, GumpButtonType.Reply, 0);
}
this.AddHtml(22, 50, 294, 40, this.Color(poller.Title, 0x99CC66), false, false);
this.AddImageTiled(32, 88, 264, 1, 9107);
this.AddImageTiled(42, 90, 264, 1, 9157);
int y = 100;
for (int i = 0; i < poller.Options.Length; ++i)
{
ShardPollOption option = poller.Options[i];
string text = option.Title;
if (editing && totalVotes > 0)
{
double perc = option.Votes / (double)totalVotes;
text = String.Format("[{1}: {2}%] {0}", text, option.Votes, (int)(perc * 100));
}
int optHeight = option.ComputeHeight();
y += optHeight / 2;
if (isViewingResults)
this.AddImage(24, y - 15, 0x25FE);
else
this.AddRadio(24, y - 15, 0x25F9, 0x25FC, false, 1 + i);
this.AddHtml(60, y - (9 * option.LineBreaks), 250, 18 * option.LineBreaks, this.Color(text, LabelColor32), false, false);
y += optHeight / 2;
y += 5;
}
if (editing && !isViewingResults)
{
this.AddRadio(24, y + 15 - 15, 0x25F9, 0x25FC, false, 1 + poller.Options.Length);
this.AddHtml(60, y + 15 - 9, 250, 18, this.Color("Create new option.", 0x99CC66), false, false);
}
this.AddButton(314, height - 73, 247, 248, 1, GumpButtonType.Reply, 0);
this.AddButton(314, height - 47, 242, 241, 0, GumpButtonType.Reply, 0);
}
public bool Editing
{
get
{
return this.m_Editing;
}
}
public void QueuePoll(ShardPoller poller)
{
if (this.m_Polls == null)
this.m_Polls = new Queue<ShardPoller>(4);
this.m_Polls.Enqueue(poller);
}
public string Center(string text)
{
return String.Format("<CENTER>{0}</CENTER>", text);
}
public string Color(string text, int color)
{
return String.Format("<BASEFONT COLOR=#{0:X6}>{1}</BASEFONT>", color, text);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (this.m_Polls != null && this.m_Polls.Count > 0)
{
ShardPoller poller = this.m_Polls.Dequeue();
if (poller != null)
Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerStateCallback(poller.SendQueuedPoll_Callback), new object[] { this.m_From, this.m_Polls });
}
if (info.ButtonID == 1)
{
int[] switches = info.Switches;
if (switches.Length == 0)
return;
int switched = switches[0] - 1;
ShardPollOption opt = null;
if (switched >= 0 && switched < this.m_Poller.Options.Length)
opt = this.m_Poller.Options[switched];
if (opt == null && !this.m_Editing)
return;
if (this.m_Editing)
{
if (!this.m_Poller.Active)
{
this.m_From.SendMessage("Enter a title for the option. Escape to cancel.{0}", opt == null ? "" : " Use \"DEL\" to delete.");
this.m_From.Prompt = new ShardPollPrompt(this.m_Poller, opt);
}
else
{
this.m_From.SendMessage("You may not edit an active poll. Deactivate it first.");
this.m_From.SendGump(new ShardPollGump(this.m_From, this.m_Poller, this.m_Editing, this.m_Polls));
}
}
else
{
if (!this.m_Poller.Active)
this.m_From.SendMessage("The poll has been deactivated.");
else if (this.m_Poller.HasAlreadyVoted(sender))
this.m_From.SendMessage("You have already voted on this poll.");
else
this.m_Poller.AddVote(sender, opt);
}
}
else if (info.ButtonID == 2 && this.m_Editing)
{
this.m_From.SendGump(new ShardPollGump(this.m_From, this.m_Poller, this.m_Editing, this.m_Polls));
this.m_From.SendGump(new PropertiesGump(this.m_From, this.m_Poller));
}
}
}
public class ShardPollPrompt : Prompt
{
private static readonly Regex m_UrlRegex = new Regex(@"\[url(?:=(.*?))?\](.*?)\[/url\]", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private readonly ShardPoller m_Poller;
private readonly ShardPollOption m_Option;
public ShardPollPrompt(ShardPoller poller, ShardPollOption opt)
{
this.m_Poller = poller;
this.m_Option = opt;
}
public static string UrlToHref(string text)
{
if (text == null)
return null;
return m_UrlRegex.Replace(text, new MatchEvaluator(UrlRegex_Match));
}
public override void OnCancel(Mobile from)
{
from.SendGump(new ShardPollGump(from, this.m_Poller, true, null));
}
public override void OnResponse(Mobile from, string text)
{
if (this.m_Poller.Active)
{
from.SendMessage("You may not edit an active poll. Deactivate it first.");
}
else if (text == "DEL")
{
if (this.m_Option != null)
this.m_Poller.RemoveOption(this.m_Option);
}
else
{
text = UrlToHref(text);
if (this.m_Option == null)
this.m_Poller.AddOption(new ShardPollOption(text));
else
this.m_Option.Title = text;
}
from.SendGump(new ShardPollGump(from, this.m_Poller, true, null));
}
private static string UrlRegex_Match(Match m)
{
if (m.Groups[1].Success)
{
if (m.Groups[2].Success)
return String.Format("<a href=\"{0}\">{1}</a>", m.Groups[1].Value, m.Groups[2].Value);
}
else if (m.Groups[2].Success)
{
return String.Format("<a href=\"{0}\">{0}</a>", m.Groups[2].Value);
}
return m.Value;
}
}
}

View File

@@ -0,0 +1,84 @@
using System;
using System.IO;
namespace Server
{
public class ShrinkTable
{
public const int DefaultItemID = 0x1870;// Yellow virtue stone
private static int[] m_Table;
public static int Lookup(Mobile m)
{
return Lookup(m.Body.BodyID, DefaultItemID);
}
public static int Lookup(int body)
{
return Lookup(body, DefaultItemID);
}
public static int Lookup(Mobile m, int defaultValue)
{
return Lookup(m.Body.BodyID, defaultValue);
}
public static int Lookup(int body, int defaultValue)
{
if (m_Table == null)
Load();
int val = 0;
if (body >= 0 && body < m_Table.Length)
val = m_Table[body];
if (val == 0)
val = defaultValue;
return val;
}
private static void Load()
{
string path = Path.Combine(Core.BaseDirectory, "Data/shrink.cfg");
if (!File.Exists(path))
{
m_Table = new int[0];
return;
}
m_Table = new int[1500];
using (StreamReader ip = new StreamReader(path))
{
string line;
while ((line = ip.ReadLine()) != null)
{
line = line.Trim();
if (line.Length == 0 || line.StartsWith("#"))
continue;
try
{
string[] split = line.Split('\t');
if (split.Length >= 2)
{
int body = Utility.ToInt32(split[0]);
int item = Utility.ToInt32(split[1]);
if (body >= 0 && body < m_Table.Length)
m_Table[body] = item;
}
}
catch
{
}
}
}
}
}
}

496
Scripts/Misc/Siege.cs Normal file
View File

@@ -0,0 +1,496 @@
#region References
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Server.Commands;
using Server.Items;
using Server.Mobiles;
using Server.Regions;
using Server.Spells;
#endregion
namespace Server
{
public static class Siege
{
public static bool SiegeShard = Config.Get("Siege.IsSiege", false);
public static int CharacterSlots = Config.Get("Siege.CharacterSlots", 1);
public static string FilePath = Path.Combine("Saves", "Siege.bin");
public static int StatsPerDay = 15;
public static Dictionary<PlayerMobile, Dictionary<SkillName, DateTime>> ROTTable { get; private set; }
public static Dictionary<PlayerMobile, int> StatsTable { get; private set; }
public static DateTime LastReset { get; private set; }
static Siege()
{
ROTTable = new Dictionary<PlayerMobile, Dictionary<SkillName, DateTime>>();
StatsTable = new Dictionary<PlayerMobile, int>();
}
public static void Configure()
{
if (SiegeShard)
{
EventSink.AfterWorldSave += OnAfterSave;
EventSink.Login += OnLogin;
EventSink.WorldSave += OnSave;
EventSink.WorldLoad += OnLoad;
}
}
public static void OnSave(WorldSaveEventArgs e)
{
Persistence.Serialize(FilePath, OnSerialize);
}
public static void OnLoad()
{
Persistence.Deserialize(FilePath, OnDeserialize);
}
private static void OnSerialize(GenericWriter writer)
{
writer.Write(0);
writer.Write(LastReset);
writer.Write(ROTTable.Count);
foreach (var kvp in ROTTable)
{
writer.Write(kvp.Key);
writer.Write(kvp.Value.Count);
foreach (var kvp2 in kvp.Value)
{
writer.Write((int)kvp2.Key);
writer.Write(kvp2.Value);
}
}
writer.Write(StatsTable.Count);
foreach (var kvp in StatsTable)
{
writer.Write(kvp.Key);
writer.Write(kvp.Value);
}
}
private static void OnDeserialize(GenericReader reader)
{
reader.ReadInt();
LastReset = reader.ReadDateTime();
var count = reader.ReadInt();
for (var i = 0; i < count; i++)
{
var pm = reader.ReadMobile<PlayerMobile>();
var dict = new Dictionary<SkillName, DateTime>();
var c = reader.ReadInt();
for (var j = 0; j < c; j++)
{
var sk = (SkillName)reader.ReadInt();
var next = reader.ReadDateTime();
dict[sk] = next;
}
if (pm != null)
{
ROTTable[pm] = dict;
}
}
count = reader.ReadInt();
for (var i = 0; i < count; i++)
{
var pm = reader.ReadMobile<PlayerMobile>();
var total = reader.ReadInt();
if (pm != null)
{
StatsTable[pm] = total;
}
}
CheckTime();
}
public static void OnLogin(LoginEventArgs e)
{
var pm = e.Mobile as PlayerMobile;
if (pm != null && pm.Map == Map.Trammel && pm.AccessLevel == AccessLevel.Player)
{
pm.MoveToWorld(new Point3D(989, 519, -50), Map.Malas);
pm.SendMessage("You have been removed from Trammel.");
}
}
public static void Initialize()
{
if (SiegeShard)
{
CommandSystem.Register(
"ResetROT",
AccessLevel.GameMaster,
e =>
{
LastReset = DateTime.Now;
e.Mobile.SendMessage("Rate over Time reset!");
});
CommandSystem.Register(
"GetROTInfo",
AccessLevel.GameMaster,
e =>
{
foreach (var kvp in ROTTable)
{
Console.WriteLine("Player: {0}", kvp.Key.Name);
var stats = 0;
if (StatsTable.ContainsKey(kvp.Key))
{
stats = StatsTable[kvp.Key];
}
Console.WriteLine("Stats gained today: {0} of {1}", stats, StatsPerDay.ToString());
Utility.PushColor(ConsoleColor.Magenta);
foreach (var kvp2 in kvp.Value)
{
var pergain = MinutesPerGain(kvp.Key, kvp.Key.Skills[kvp2.Key]);
var last = kvp2.Value;
var next = last.AddMinutes(pergain);
var nextg = next < DateTime.Now
? "now"
: "in " + ((int)(next - DateTime.Now).TotalMinutes).ToString() + " minutes";
Console.WriteLine(
" {0}: last gained {1}, can gain {2} (every {3} minutes)",
kvp2.Key.ToString(),
last.ToShortTimeString(),
nextg,
pergain.ToString());
}
Utility.PopColor();
}
Console.WriteLine("---");
Console.WriteLine(
"Next Reset: {0} minutes",
((LastReset + TimeSpan.FromHours(24) - DateTime.Now)).TotalMinutes.ToString());
});
Utility.PushColor(ConsoleColor.Red);
Console.Write("Initializing Siege Perilous Shard...");
var tick = Core.TickCount;
var toReset = new List<XmlSpawner>();
foreach (var item in World.Items.Values.OfType<XmlSpawner>().Where(sp => sp.Map == Map.Trammel && sp.Running))
{
toReset.Add(item);
}
foreach (var item in toReset)
{
item.DoReset = true;
}
Console.WriteLine("Reset {1} trammel spawners in {0} milliseconds!", Core.TickCount - tick, toReset.Count);
Utility.PopColor();
ColUtility.Free(toReset);
EventSink.ContainerDroppedTo += OnDropped;
}
}
public static void OnDropped(ContainerDroppedToEventArgs e)
{
if (!SiegeShard)
return;
var item = e.Dropped;
var from = e.Mobile;
var cont = e.Container;
if (item != null)
{
if (cont != from.Backpack && from is PlayerMobile && ((PlayerMobile)from).BlessedItem != null && ((PlayerMobile)from).BlessedItem == item)
{
((PlayerMobile)from).BlessedItem = null;
item.LootType = LootType.Regular;
from.SendLocalizedMessage(1075292, item.Name != null ? item.Name : "#" + item.LabelNumber.ToString()); // ~1_NAME~ has been unblessed.
}
}
}
/// <summary>
/// Called in SpellHelper.cs CheckTravel method
/// </summary>
/// <param name="m"></param>
/// <param name="p"></param>
/// <param name="map"></param>
/// <param name="type"></param>
/// <returns>False fails travel check. True must pass other travel checks in SpellHelper.cs</returns>
public static bool CheckTravel(Mobile m, Point3D p, Map map, TravelCheckType type)
{
if (m.AccessLevel > AccessLevel.Player)
return true;
switch (type)
{
case TravelCheckType.RecallFrom:
case TravelCheckType.RecallTo:
{
return false;
}
case TravelCheckType.GateFrom:
case TravelCheckType.GateTo:
case TravelCheckType.Mark:
{
return CanTravelTo(m, p, map);
}
case TravelCheckType.TeleportFrom:
case TravelCheckType.TeleportTo:
{
return true;
}
}
return true;
}
public static bool CanTravelTo(Mobile m, Point3D p, Map map)
{
return !(Region.Find(p, map) is DungeonRegion) && !SpellHelper.IsAnyT2A(map, p) && !SpellHelper.IsIlshenar(map, p);
}
public static void OnAfterSave(AfterWorldSaveEventArgs e)
{
CheckTime();
}
public static void CheckTime()
{
var now = DateTime.Now;
if (LastReset.AddHours(24) < now)
{
var reset = new DateTime(now.Year, now.Month, now.Day, 20, 0, 0);
if (now < reset)
{
LastReset = reset - TimeSpan.FromHours(24);
}
else
{
ROTTable.Clear();
StatsTable.Clear();
LastReset = reset;
}
}
}
public static bool CheckSkillGain(PlayerMobile pm, int minutesPerSkill, Skill skill)
{
if (minutesPerSkill == 0)
{
return true;
}
var sk = skill.SkillName;
if (ROTTable.ContainsKey(pm))
{
if (ROTTable[pm].ContainsKey(sk))
{
var lastGain = ROTTable[pm][sk];
if (lastGain + TimeSpan.FromMinutes(minutesPerSkill) < DateTime.Now)
{
ROTTable[pm][sk] = DateTime.Now;
return true;
}
return false;
}
ROTTable[pm][sk] = DateTime.Now;
return true;
}
ROTTable[pm] = new Dictionary<SkillName, DateTime>();
ROTTable[pm][sk] = DateTime.Now;
return true;
}
public static int MinutesPerGain(Mobile m, Skill skill)
{
var value = skill.Base;
if (value < 70.0)
{
return 0;
}
if (value <= 79.9)
{
return 5;
}
if (value <= 89.9)
{
return 8;
}
if (value <= 99.9)
{
return 12;
}
return 15;
}
public static bool CanGainStat(PlayerMobile m)
{
if (!StatsTable.ContainsKey(m))
{
return true;
}
return StatsTable[m] < StatsPerDay;
}
public static void IncreaseStat(PlayerMobile m)
{
if (!StatsTable.ContainsKey(m))
{
StatsTable[m] = 1;
}
else
{
StatsTable[m]++;
}
}
public static bool VendorCanSell(Type t)
{
if (t == null)
{
return false;
}
foreach (var type in _NoSellList)
{
if (t == type || t.IsSubclassOf(type))
{
return false;
}
}
return true;
}
private static readonly Type[] _NoSellList =
{
typeof(BaseIngot), typeof(BaseWoodBoard), typeof(BaseLog), typeof(BaseLeather), typeof(BaseHides), typeof(Cloth),
typeof(BoltOfCloth), typeof(UncutCloth), typeof(Wool), typeof(Cotton), typeof(Flax), typeof(SpoolOfThread),
typeof(Feather), typeof(Shaft), typeof(Arrow), typeof(Bolt)
};
public static void TryBlessItem(PlayerMobile pm, object targeted)
{
var item = targeted as Item;
if (item != null)
{
if (CanBlessItem(pm, item))
{
if (pm.BlessedItem != null && pm.BlessedItem == item)
{
pm.BlessedItem.LootType = LootType.Regular;
pm.SendLocalizedMessage(
1075292,
pm.BlessedItem.Name ?? "#" + pm.BlessedItem.LabelNumber); // ~1_NAME~ has been unblessed.
pm.BlessedItem = null;
}
else if (item.LootType == LootType.Regular && !(item is Container))
{
var old = pm.BlessedItem;
pm.BlessedItem = item;
pm.BlessedItem.LootType = LootType.Blessed;
pm.SendLocalizedMessage(
1075293,
pm.BlessedItem.Name ?? "#" + pm.BlessedItem.LabelNumber); // ~1_NAME~ has been blessed.
if (old != null)
{
old.LootType = LootType.Regular;
pm.SendLocalizedMessage(1075292, old.Name ?? "#" + old.LabelNumber); // ~1_NAME~ has been unblessed.
}
}
}
else
{
pm.SendLocalizedMessage(1045114); // You cannot bless that item
}
}
}
public static bool CanBlessItem(PlayerMobile pm, Item item)
{
return (pm.Items.Contains(item) || (pm.Backpack != null && pm.Backpack.Items.Contains(item)) && !item.Stackable &&
(item is BaseArmor || item is BaseJewel || item is BaseClothing || item is BaseWeapon));
}
public static void CheckUsesRemaining(Mobile from, Item item)
{
var uses = item as IUsesRemaining;
if (uses != null)
{
uses.ShowUsesRemaining = true;
uses.UsesRemaining--;
if (uses.UsesRemaining <= 0)
{
item.Delete();
from.SendLocalizedMessage(1044038); // You have worn out your tool!
}
}
}
}
}

808
Scripts/Misc/SkillCheck.cs Normal file
View File

@@ -0,0 +1,808 @@
#region References
using System;
using Server.Engines.Quests;
using Server.Factions;
using Server.Items;
using Server.Mobiles;
using Server.Multis;
using Server.Regions;
using Server.Spells.SkillMasteries;
#endregion
namespace Server.Misc
{
public class SkillCheck
{
private static readonly TimeSpan _StatGainDelay;
private static readonly TimeSpan _PetStatGainDelay;
private static readonly int _PlayerChanceToGainStats;
private static readonly int _PetChanceToGainStats;
private static readonly bool _AntiMacroCode;
/// <summary>
/// How long do we remember targets/locations?
/// </summary>
public static TimeSpan AntiMacroExpire = TimeSpan.FromMinutes(5.0);
/// <summary>
/// How many times may we use the same location/target for gain
/// </summary>
public const int Allowance = 3;
/// <summary>
/// The size of each location, make this smaller so players dont have to move as far
/// </summary>
private const int LocationSize = 4;
public static bool GGSActive { get { return !Siege.SiegeShard; } }
static SkillCheck()
{
_AntiMacroCode = Config.Get("PlayerCaps.EnableAntiMacro", false);
_StatGainDelay = Config.Get("PlayerCaps.PlayerStatTimeDelay", TimeSpan.FromMinutes(15.0));
_PetStatGainDelay = Config.Get("PlayerCaps.PetStatTimeDelay", TimeSpan.FromMinutes(5.0));
_PlayerChanceToGainStats = Config.Get("PlayerCaps.PlayerChanceToGainStats", 5);
_PetChanceToGainStats = Config.Get("PlayerCaps.PetChanceToGainStats", 5);
if (!Config.Get("PlayerCaps.EnablePlayerStatTimeDelay", false))
_StatGainDelay = TimeSpan.FromSeconds(0.5);
if (!Config.Get("PlayerCaps.EnablePetStatTimeDelay", false))
_PetStatGainDelay = TimeSpan.FromSeconds(0.5);
}
private static readonly bool[] UseAntiMacro =
{
// true if this skill uses the anti-macro code, false if it does not
false, // Alchemy = 0,
true, // Anatomy = 1,
true, // AnimalLore = 2,
true, // ItemID = 3,
true, // ArmsLore = 4,
false, // Parry = 5,
true, // Begging = 6,
false, // Blacksmith = 7,
false, // Fletching = 8,
true, // Peacemaking = 9,
true, // Camping = 10,
false, // Carpentry = 11,
false, // Cartography = 12,
false, // Cooking = 13,
true, // DetectHidden = 14,
true, // Discordance = 15,
true, // EvalInt = 16,
true, // Healing = 17,
true, // Fishing = 18,
true, // Forensics = 19,
true, // Herding = 20,
true, // Hiding = 21,
true, // Provocation = 22,
false, // Inscribe = 23,
true, // Lockpicking = 24,
true, // Magery = 25,
true, // MagicResist = 26,
false, // Tactics = 27,
true, // Snooping = 28,
true, // Musicianship = 29,
true, // Poisoning = 30,
false, // Archery = 31,
true, // SpiritSpeak = 32,
true, // Stealing = 33,
false, // Tailoring = 34,
true, // AnimalTaming = 35,
true, // TasteID = 36,
false, // Tinkering = 37,
true, // Tracking = 38,
true, // Veterinary = 39,
false, // Swords = 40,
false, // Macing = 41,
false, // Fencing = 42,
false, // Wrestling = 43,
true, // Lumberjacking = 44,
true, // Mining = 45,
true, // Meditation = 46,
true, // Stealth = 47,
true, // RemoveTrap = 48,
true, // Necromancy = 49,
false, // Focus = 50,
true, // Chivalry = 51
true, // Bushido = 52
true, //Ninjitsu = 53
true, // Spellweaving = 54
#region Stygian Abyss
true, // Mysticism = 55
true, // Imbuing = 56
false // Throwing = 57
#endregion
};
public static void Initialize()
{
Mobile.SkillCheckLocationHandler = XmlSpawnerSkillCheck.Mobile_SkillCheckLocation;
Mobile.SkillCheckDirectLocationHandler = XmlSpawnerSkillCheck.Mobile_SkillCheckDirectLocation;
Mobile.SkillCheckTargetHandler = XmlSpawnerSkillCheck.Mobile_SkillCheckTarget;
Mobile.SkillCheckDirectTargetHandler = XmlSpawnerSkillCheck.Mobile_SkillCheckDirectTarget;
}
public static bool Mobile_SkillCheckLocation(Mobile from, SkillName skillName, double minSkill, double maxSkill)
{
var skill = from.Skills[skillName];
if (skill == null)
return false;
var value = skill.Value;
//TODO: Is there any other place this can go?
if (skillName == SkillName.Fishing && BaseGalleon.FindGalleonAt(from, from.Map) is TokunoGalleon)
value += 1;
if (value < minSkill)
return false; // Too difficult
if (value >= maxSkill)
return true; // No challenge
var chance = (value - minSkill) / (maxSkill - minSkill);
CrystalBallOfKnowledge.TellSkillDifficulty(from, skillName, chance);
return CheckSkill(from, skill, new Point2D(from.Location.X / LocationSize, from.Location.Y / LocationSize), chance);
}
public static bool Mobile_SkillCheckDirectLocation(Mobile from, SkillName skillName, double chance)
{
var skill = from.Skills[skillName];
if (skill == null)
return false;
CrystalBallOfKnowledge.TellSkillDifficulty(from, skillName, chance);
if (chance < 0.0)
return false; // Too difficult
if (chance >= 1.0)
return true; // No challenge
return CheckSkill(from, skill, new Point2D(from.Location.X / LocationSize, from.Location.Y / LocationSize), chance);
}
#region Craft All Gains
/// <summary>
/// This should be a successful skill check, where a system can register several skill gains at once. Only system
/// using this currently is UseAllRes for CraftItem.cs
/// </summary>
/// <param name="from"></param>
/// <param name="skill"></param>
/// <param name="amount"></param>
/// <returns></returns>
public static bool CheckSkill(Mobile from, SkillName sk, double minSkill, double maxSkill, int amount)
{
if (from.Skills.Cap == 0)
return false;
var skill = from.Skills[sk];
var value = skill.Value;
var gains = 0;
for (int i = 0; i < amount; i++)
{
var gc = GetGainChance(from, skill, (value - minSkill) / (maxSkill - minSkill), value) / 10;
if (AllowGain(from, skill, new Point2D(from.Location.X / LocationSize, from.Location.Y / LocationSize)))
{
if (from.Alive && (skill.Base < 10.0 || Utility.RandomDouble() <= gc || CheckGGS(from, skill)))
{
gains++;
value += 0.1;
}
}
}
if (gains > 0)
{
Gain(from, skill, gains);
EventSink.InvokeSkillCheck(new SkillCheckEventArgs(from, skill, true));
return true;
}
return false;
}
private static double GetGainChance(Mobile from, Skill skill, double gains, double chance)
{
var gc = (double)(from.Skills.Cap - (from.Skills.Total + (gains * 10))) / from.Skills.Cap;
gc += (skill.Cap - (skill.Base + (gains * 10))) / skill.Cap;
gc /= 4;
gc *= skill.Info.GainFactor;
if (gc < 0.01)
gc = 0.01;
if (gc > 1.00)
gc = 1.00;
return gc;
}
#endregion
public static bool CheckSkill(Mobile from, Skill skill, object obj, double chance)
{
if (from.Skills.Cap == 0)
return false;
var success = Utility.Random(100) <= (int)(chance * 100);
var gc = GetGainChance(from, skill, chance, success);
if (AllowGain(from, skill, obj))
{
if (from.Alive && (skill.Base < 10.0 || Utility.RandomDouble() <= gc || CheckGGS(from, skill)))
{
Gain(from, skill);
}
}
EventSink.InvokeSkillCheck(new SkillCheckEventArgs(from, skill, success));
return success;
}
private static double GetGainChance(Mobile from, Skill skill, double chance, bool success)
{
var gc = (double)(from.Skills.Cap - from.Skills.Total) / from.Skills.Cap;
gc += (skill.Cap - skill.Base) / skill.Cap;
gc /= 2;
gc += (1.0 - chance) * (success ? 0.5 : (Core.AOS ? 0.0 : 0.2));
gc /= 2;
gc *= skill.Info.GainFactor;
if (gc < 0.01)
gc = 0.01;
// Pets get a 100% bonus
if (from is BaseCreature && ((BaseCreature)from).Controlled)
gc += gc * 1.00;
if (gc > 1.00)
gc = 1.00;
return gc;
}
public static bool Mobile_SkillCheckTarget(
Mobile from,
SkillName skillName,
object target,
double minSkill,
double maxSkill)
{
var skill = from.Skills[skillName];
if (skill == null)
return false;
var value = skill.Value;
if (value < minSkill)
return false; // Too difficult
if (value >= maxSkill)
return true; // No challenge
var chance = (value - minSkill) / (maxSkill - minSkill);
CrystalBallOfKnowledge.TellSkillDifficulty(from, skillName, chance);
return CheckSkill(from, skill, target, chance);
}
public static bool Mobile_SkillCheckDirectTarget(Mobile from, SkillName skillName, object target, double chance)
{
var skill = from.Skills[skillName];
if (skill == null)
return false;
CrystalBallOfKnowledge.TellSkillDifficulty(from, skillName, chance);
if (chance < 0.0)
return false; // Too difficult
if (chance >= 1.0)
return true; // No challenge
return CheckSkill(from, skill, target, chance);
}
private static bool AllowGain(Mobile from, Skill skill, object obj)
{
if (Core.AOS && Faction.InSkillLoss(from)) //Changed some time between the introduction of AoS and SE.
return false;
if (from is PlayerMobile)
{
#region SA
if (skill.Info.SkillID == (int)SkillName.Archery && from.Race == Race.Gargoyle)
return false;
if (skill.Info.SkillID == (int)SkillName.Throwing && @from.Race != Race.Gargoyle)
return false;
#endregion
if (_AntiMacroCode && UseAntiMacro[skill.Info.SkillID])
return ((PlayerMobile)from).AntiMacroCheck(skill, obj);
}
return true;
}
public enum Stat
{
Str,
Dex,
Int
}
public static void Gain(Mobile from, Skill skill)
{
Gain(from, skill, (int)(from.Region.SkillGain(from) * 10));
}
public static void Gain(Mobile from, Skill skill, int toGain)
{
if (from.Region.IsPartOf<Jail>())
return;
if (from is BaseCreature && ((BaseCreature)from).IsDeadPet)
return;
if (skill.SkillName == SkillName.Focus && from is BaseCreature &&
(!PetTrainingHelper.Enabled || !((BaseCreature)from).Controlled))
return;
if (skill.Base < skill.Cap && skill.Lock == SkillLock.Up)
{
var skills = from.Skills;
if (from is PlayerMobile && Siege.SiegeShard)
{
var minsPerGain = Siege.MinutesPerGain(from, skill);
if (minsPerGain > 0)
{
if (Siege.CheckSkillGain((PlayerMobile)from, minsPerGain, skill))
{
CheckReduceSkill(skills, toGain, skill);
if (skills.Total + toGain <= skills.Cap)
{
skill.BaseFixedPoint += toGain;
}
}
return;
}
}
if (toGain == 1 && skill.Base <= 10.0)
toGain = Utility.Random(4) + 1;
#region Mondain's Legacy
if (from is PlayerMobile && QuestHelper.EnhancedSkill((PlayerMobile)from, skill))
{
toGain *= Utility.RandomMinMax(2, 4);
}
#endregion
#region Scroll of Alacrity
if (from is PlayerMobile && skill.SkillName == ((PlayerMobile)from).AcceleratedSkill &&
((PlayerMobile)from).AcceleratedStart > DateTime.UtcNow)
{
// You are infused with intense energy. You are under the effects of an accelerated skillgain scroll.
((PlayerMobile)from).SendLocalizedMessage(1077956);
toGain = Utility.RandomMinMax(2, 5);
}
#endregion
#region Skill Masteries
else if (from is BaseCreature && !(from is Server.Engines.Despise.DespiseCreature) && (((BaseCreature)from).Controlled || ((BaseCreature)from).Summoned))
{
var master = ((BaseCreature)from).GetMaster();
if (master != null)
{
var spell = SkillMasterySpell.GetSpell(master, typeof(WhisperingSpell)) as WhisperingSpell;
if (spell != null && master.InRange(from.Location, spell.PartyRange) && master.Map == from.Map &&
spell.EnhancedGainChance >= Utility.Random(100))
{
toGain = Utility.RandomMinMax(2, 5);
}
}
}
#endregion
if (from is PlayerMobile)
{
CheckReduceSkill(skills, toGain, skill);
}
if (!from.Player || (skills.Total + toGain <= skills.Cap))
{
skill.BaseFixedPoint = Math.Min(skill.CapFixedPoint, skill.BaseFixedPoint + toGain);
EventSink.InvokeSkillGain(new SkillGainEventArgs(from, skill, toGain));
if (from is PlayerMobile)
UpdateGGS(from, skill);
}
}
#region Mondain's Legacy
if (from is PlayerMobile)
QuestHelper.CheckSkill((PlayerMobile)from, skill);
#endregion
if (skill.Lock == SkillLock.Up &&
(!Siege.SiegeShard || !(from is PlayerMobile) || Siege.CanGainStat((PlayerMobile)from)))
{
var info = skill.Info;
// Old gain mechanic
if (!Core.ML)
{
var scalar = 1.0;
if (from.StrLock == StatLockType.Up && (info.StrGain / 33.3) * scalar > Utility.RandomDouble())
GainStat(from, Stat.Str);
else if (from.DexLock == StatLockType.Up && (info.DexGain / 33.3) * scalar > Utility.RandomDouble())
GainStat(from, Stat.Dex);
else if (from.IntLock == StatLockType.Up && (info.IntGain / 33.3) * scalar > Utility.RandomDouble())
GainStat(from, Stat.Int);
}
else
{
TryStatGain(info, from);
}
}
}
private static void CheckReduceSkill(Skills skills, int toGain, Skill gainSKill)
{
if (skills.Total / skills.Cap >= Utility.RandomDouble())
{
foreach (var toLower in skills)
{
if (toLower != gainSKill && toLower.Lock == SkillLock.Down && toLower.BaseFixedPoint >= toGain)
{
toLower.BaseFixedPoint -= toGain;
break;
}
}
}
}
public static void TryStatGain(SkillInfo info, Mobile from)
{
// Chance roll
double chance;
if (from is BaseCreature && ((BaseCreature)from).Controlled)
{
chance = _PetChanceToGainStats / 100.0;
}
else
{
chance = _PlayerChanceToGainStats / 100.0;
}
if (Utility.RandomDouble() >= chance)
{
return;
}
// Selection
var primaryLock = StatLockType.Locked;
var secondaryLock = StatLockType.Locked;
switch (info.Primary)
{
case StatCode.Str:
primaryLock = from.StrLock;
break;
case StatCode.Dex:
primaryLock = from.DexLock;
break;
case StatCode.Int:
primaryLock = from.IntLock;
break;
}
switch (info.Secondary)
{
case StatCode.Str:
secondaryLock = from.StrLock;
break;
case StatCode.Dex:
secondaryLock = from.DexLock;
break;
case StatCode.Int:
secondaryLock = from.IntLock;
break;
}
// Gain
// Decision block of both are selected to gain
if (primaryLock == StatLockType.Up && secondaryLock == StatLockType.Up)
{
if (Utility.Random(4) == 0)
GainStat(from, (Stat)info.Secondary);
else
GainStat(from, (Stat)info.Primary);
}
else // Will not do anything if neither are selected to gain
{
if (primaryLock == StatLockType.Up)
GainStat(from, (Stat)info.Primary);
else if (secondaryLock == StatLockType.Up)
GainStat(from, (Stat)info.Secondary);
}
}
public static bool CanLower(Mobile from, Stat stat)
{
switch (stat)
{
case Stat.Str:
return (from.StrLock == StatLockType.Down && from.RawStr > 10);
case Stat.Dex:
return (from.DexLock == StatLockType.Down && from.RawDex > 10);
case Stat.Int:
return (from.IntLock == StatLockType.Down && from.RawInt > 10);
}
return false;
}
public static bool CanRaise(Mobile from, Stat stat, bool atTotalCap)
{
switch (stat)
{
case Stat.Str:
if (from.RawStr < from.StrCap)
{
if (atTotalCap && from is PlayerMobile)
{
return CanLower(from, Stat.Dex) || CanLower(from, Stat.Int);
}
else
{
return true;
}
}
return false;
case Stat.Dex:
if (from.RawDex < from.DexCap)
{
if (atTotalCap && from is PlayerMobile)
{
return CanLower(from, Stat.Str) || CanLower(from, Stat.Int);
}
else
{
return true;
}
}
return false;
case Stat.Int:
if (from.RawInt < from.IntCap)
{
if (atTotalCap && from is PlayerMobile)
{
return CanLower(from, Stat.Str) || CanLower(from, Stat.Dex);
}
else
{
return true;
}
}
return false;
}
return false;
}
public static void IncreaseStat(Mobile from, Stat stat)
{
bool atTotalCap = from.RawStatTotal >= from.StatCap;
switch (stat)
{
case Stat.Str:
{
if (CanRaise(from, Stat.Str, atTotalCap))
{
if (atTotalCap)
{
if (CanLower(from, Stat.Dex) && (from.RawDex < from.RawInt || !CanLower(from, Stat.Int)))
--from.RawDex;
else if (CanLower(from, Stat.Int))
--from.RawInt;
}
++from.RawStr;
if (from is BaseCreature && ((BaseCreature)from).HitsMaxSeed > -1 && ((BaseCreature)from).HitsMaxSeed < from.StrCap)
{
((BaseCreature)from).HitsMaxSeed++;
}
if (Siege.SiegeShard && from is PlayerMobile)
{
Siege.IncreaseStat((PlayerMobile)from);
}
}
break;
}
case Stat.Dex:
{
if (CanRaise(from, Stat.Dex, atTotalCap))
{
if (atTotalCap)
{
if (CanLower(from, Stat.Str) && (from.RawStr < from.RawInt || !CanLower(from, Stat.Int)))
--from.RawStr;
else if (CanLower(from, Stat.Int))
--from.RawInt;
}
++from.RawDex;
if (from is BaseCreature && ((BaseCreature)from).StamMaxSeed > -1 && ((BaseCreature)from).StamMaxSeed < from.DexCap)
{
((BaseCreature)from).StamMaxSeed++;
}
if (Siege.SiegeShard && from is PlayerMobile)
{
Siege.IncreaseStat((PlayerMobile)from);
}
}
break;
}
case Stat.Int:
{
if (CanRaise(from, Stat.Int, atTotalCap))
{
if (atTotalCap)
{
if (CanLower(from, Stat.Str) && (from.RawStr < from.RawDex || !CanLower(from, Stat.Dex)))
--from.RawStr;
else if (CanLower(from, Stat.Dex))
--from.RawDex;
}
++from.RawInt;
if (from is BaseCreature && ((BaseCreature)from).ManaMaxSeed > -1 && ((BaseCreature)from).ManaMaxSeed < from.IntCap)
{
((BaseCreature)from).ManaMaxSeed++;
}
if (Siege.SiegeShard && from is PlayerMobile)
{
Siege.IncreaseStat((PlayerMobile)from);
}
}
break;
}
}
}
public static void GainStat(Mobile from, Stat stat)
{
if (!CheckStatTimer(from, stat))
return;
IncreaseStat(from, stat);
}
public static bool CheckStatTimer(Mobile from, Stat stat)
{
switch (stat)
{
case Stat.Str:
{
if (from is BaseCreature && ((BaseCreature)from).Controlled)
{
if ((from.LastStrGain + _PetStatGainDelay) >= DateTime.UtcNow)
return false;
}
else if ((from.LastStrGain + _StatGainDelay) >= DateTime.UtcNow)
return false;
from.LastStrGain = DateTime.UtcNow;
break;
}
case Stat.Dex:
{
if (from is BaseCreature && ((BaseCreature)from).Controlled)
{
if ((from.LastDexGain + _PetStatGainDelay) >= DateTime.UtcNow)
return false;
}
else if ((from.LastDexGain + _StatGainDelay) >= DateTime.UtcNow)
return false;
from.LastDexGain = DateTime.UtcNow;
break;
}
case Stat.Int:
{
if (from is BaseCreature && ((BaseCreature)from).Controlled)
{
if ((from.LastIntGain + _PetStatGainDelay) >= DateTime.UtcNow)
return false;
}
else if ((from.LastIntGain + _StatGainDelay) >= DateTime.UtcNow)
return false;
from.LastIntGain = DateTime.UtcNow;
break;
}
}
return true;
}
private static bool CheckGGS(Mobile from, Skill skill)
{
if (!GGSActive)
return false;
if (from is PlayerMobile && skill.NextGGSGain < DateTime.UtcNow)
{
return true;
}
return false;
}
public static void UpdateGGS(Mobile from, Skill skill)
{
if (!GGSActive)
return;
var list = (int)Math.Min(GGSTable.Length - 1, skill.Base / 5);
var column = from.Skills.Total >= 7000 ? 2 : from.Skills.Total >= 3500 ? 1 : 0;
skill.NextGGSGain = DateTime.UtcNow + TimeSpan.FromMinutes(GGSTable[list][column]);
}
private static readonly int[][] GGSTable =
{
new[] {1, 3, 5}, // 0.0 - 4.9
new[] {4, 10, 18}, new[] {7, 17, 30}, new[] {9, 24, 44}, new[] {12, 31, 57}, new[] {14, 38, 90}, new[] {17, 45, 84},
new[] {20, 52, 96}, new[] {23, 60, 106}, new[] {25, 66, 120}, new[] {27, 72, 138}, new[] {33, 90, 162},
new[] {55, 150, 264}, new[] {78, 216, 390}, new[] {114, 294, 540}, new[] {144, 384, 708}, new[] {180, 492, 900},
new[] {228, 606, 1116}, new[] {276, 744, 1356}, new[] {336, 894, 1620}, new[] {396, 1056, 1920},
new[] {468, 1242, 2280}, new[] {540, 1440, 2580}, new[] {618, 1662, 3060}
};
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Net;
using System.Net.Sockets;
using Server.Network;
namespace Server
{
public class SocketOptions
{
public static readonly int Port = Config.Get("Server.Port", 2593);
private static readonly IPEndPoint[] m_ListenerEndPoints = new IPEndPoint[]
{
new IPEndPoint(IPAddress.Any, Port), // Default: Listen on port 2593 on all IP addresses
// Examples:
// new IPEndPoint( IPAddress.Any, 80 ), // Listen on port 80 on all IP addresses
// new IPEndPoint( IPAddress.Parse( "1.2.3.4" ), 2593 ), // Listen on port 2593 on IP address 1.2.3.4
};
public static bool NagleEnabled = false;// Should the Nagle algorithm be enabled? This may reduce performance
public static int CoalesceBufferSize = 512;// MSS that the core will use when buffering packets
public static void Initialize()
{
SendQueue.CoalesceBufferSize = CoalesceBufferSize;
EventSink.SocketConnect += new SocketConnectEventHandler(EventSink_SocketConnect);
Listener.EndPoints = m_ListenerEndPoints;
}
private static void EventSink_SocketConnect(SocketConnectEventArgs e)
{
if (!e.AllowConnection)
return;
if (!NagleEnabled)
e.Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1); // RunUO uses its own algorithm
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
using System;
using System.Threading.Tasks;
namespace Server
{
public class TaskPollingTimer<T> : Timer
{
private Task<T> m_Task;
private Action<T> m_Callback;
public TaskPollingTimer(Task<T> task, Action<T> callback)
: base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
{
m_Task = task;
m_Callback = callback;
}
protected override void OnTick()
{
if (m_Task.IsCompleted)
{
m_Callback(m_Task.Result);
Stop();
}
}
}
}

View File

@@ -0,0 +1,209 @@
using System;
using System.Globalization;
using Server.Gumps;
namespace Server
{
[Parsable]
public class TextDefinition
{
private readonly int m_Number;
private readonly string m_String;
public TextDefinition()
: this(0, null)
{
}
public TextDefinition(int number)
: this(number, null)
{
}
public TextDefinition(string text)
: this(0, text)
{
}
public TextDefinition(int number, string text)
{
this.m_Number = number;
this.m_String = text;
}
public int Number
{
get
{
return this.m_Number;
}
}
public string String
{
get
{
return this.m_String;
}
}
public static void Serialize(GenericWriter writer, TextDefinition def)
{
if (def == null)
{
writer.WriteEncodedInt(3);
}
else if (def.m_Number > 0)
{
writer.WriteEncodedInt(1);
writer.WriteEncodedInt(def.m_Number);
}
else if (def.m_String != null)
{
writer.WriteEncodedInt(2);
writer.Write(def.m_String);
}
else
{
writer.WriteEncodedInt(0);
}
}
public static TextDefinition Deserialize(GenericReader reader)
{
int type = reader.ReadEncodedInt();
switch ( type )
{
case 0:
return new TextDefinition();
case 1:
return new TextDefinition(reader.ReadEncodedInt());
case 2:
return new TextDefinition(reader.ReadString());
}
return null;
}
public static void AddTo(ObjectPropertyList list, TextDefinition def)
{
if (def == null)
return;
if (def.m_Number > 0)
list.Add(def.m_Number);
else if (def.m_String != null)
list.Add(def.m_String);
}
public static void AddHtmlText(Gump g, int x, int y, int width, int height, TextDefinition def, bool back, bool scroll, int numberColor, int stringColor)
{
if (def == null)
return;
if (def.m_Number > 0)
{
if (numberColor >= 0)
g.AddHtmlLocalized(x, y, width, height, def.m_Number, numberColor, back, scroll);
else
g.AddHtmlLocalized(x, y, width, height, def.m_Number, back, scroll);
}
else if (def.m_String != null)
{
if (stringColor >= 0)
g.AddHtml(x, y, width, height, String.Format("<BASEFONT COLOR=#{0:X6}>{1}</BASEFONT>", stringColor, def.m_String), back, scroll);
else
g.AddHtml(x, y, width, height, def.m_String, back, scroll);
}
}
public static void AddHtmlText(Gump g, int x, int y, int width, int height, TextDefinition def, bool back, bool scroll)
{
AddHtmlText(g, x, y, width, height, def, back, scroll, -1, -1);
}
public static void SendMessageTo(Mobile m, TextDefinition def)
{
if (def == null)
return;
if (def.m_Number > 0)
m.SendLocalizedMessage(def.m_Number);
else if (def.m_String != null)
m.SendMessage(def.m_String);
}
public static TextDefinition Parse(string value)
{
if (value == null)
return null;
int i;
bool isInteger;
if (value.StartsWith("0x"))
isInteger = int.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out i);
else
isInteger = int.TryParse(value, out i);
if (isInteger)
return new TextDefinition(i);
else
return new TextDefinition(value);
}
public override string ToString()
{
if (this.m_Number > 0)
return String.Concat("#", this.m_Number.ToString());
else if (this.m_String != null)
return this.m_String;
return "";
}
public string Format(bool propsGump)
{
if (this.m_Number > 0)
return String.Format("{0} (0x{0:X})", this.m_Number);
else if (this.m_String != null)
return String.Format("\"{0}\"", this.m_String);
return propsGump ? "-empty-" : "empty";
}
public string GetValue()
{
if (this.m_Number > 0)
return this.m_Number.ToString();
else if (this.m_String != null)
return this.m_String;
return "";
}
public static implicit operator TextDefinition(int v)
{
return new TextDefinition(v);
}
public static implicit operator TextDefinition(string s)
{
return new TextDefinition(s);
}
public static implicit operator int(TextDefinition m)
{
if (m == null)
return 0;
return m.m_Number;
}
public static implicit operator string(TextDefinition m)
{
if (m == null)
return null;
return m.m_String;
}
}
}

66
Scripts/Misc/Timestamp.cs Normal file
View File

@@ -0,0 +1,66 @@
using System;
using System.IO;
using System.Text;
namespace System
{
public class ConsoleHook : TextWriter
{
#if DEBUG
private static readonly bool _Enabled = false;
#else
private static readonly bool _Enabled = true;
#endif
private static Stream m_OldOutput;
private static bool m_Newline;
public override Encoding Encoding
{
get
{
return Encoding.ASCII;
}
}
private string Timestamp
{
get
{
return String.Format("{0:D2}:{1:D2}:{2:D2} ", DateTime.UtcNow.Hour, DateTime.UtcNow.Minute, DateTime.UtcNow.Second);
}
}
public static void Initialize()
{
if (_Enabled)
{
m_OldOutput = Console.OpenStandardOutput();
Console.SetOut(new ConsoleHook());
m_Newline = true;
}
}
public override void WriteLine(string value)
{
if (m_Newline)
{
value = this.Timestamp + value;
}
byte[] data = this.Encoding.GetBytes(value);
m_OldOutput.Write(data, 0, data.Length);
m_OldOutput.WriteByte(10);
m_Newline = true;
}
public override void Write(string value)
{
if (m_Newline)
{
value = this.Timestamp + value;
}
byte[] data = this.Encoding.GetBytes(value);
m_OldOutput.Write(data, 0, data.Length);
m_Newline = false;
}
}
}

541
Scripts/Misc/Titles.cs Normal file
View File

@@ -0,0 +1,541 @@
using System;
using System.Text;
using Server.Engines.CannedEvil;
using Server.Items;
using Server.Mobiles;
using System.Collections.Generic;
using Server.Accounting;
namespace Server.Misc
{
public class Titles
{
public const int MinFame = 0;
public const int MaxFame = 32000;
public static void AwardFame(Mobile m, int offset, bool message)
{
var fame = m.Fame;
if (offset > 0)
{
if (fame >= MaxFame)
return;
offset -= fame / 100;
if (offset < 0)
offset = 0;
}
else if (offset < 0)
{
if (fame <= MinFame)
return;
offset -= fame / 100;
if (offset > 0)
offset = 0;
}
if ((fame + offset) > MaxFame)
offset = MaxFame - fame;
else if ((fame + offset) < MinFame)
offset = MinFame - fame;
m.Fame += offset;
if (message)
{
if (offset > 40)
m.SendLocalizedMessage(1019054); // You have gained a lot of fame.
else if (offset > 20)
m.SendLocalizedMessage(1019053); // You have gained a good amount of fame.
else if (offset > 10)
m.SendLocalizedMessage(1019052); // You have gained some fame.
else if (offset > 0)
m.SendLocalizedMessage(1019051); // You have gained a little fame.
else if (offset < -40)
m.SendLocalizedMessage(1019058); // You have lost a lot of fame.
else if (offset < -20)
m.SendLocalizedMessage(1019057); // You have lost a good amount of fame.
else if (offset < -10)
m.SendLocalizedMessage(1019056); // You have lost some fame.
else if (offset < 0)
m.SendLocalizedMessage(1019055); // You have lost a little fame.
}
}
public const int MinKarma = -32000;
public const int MaxKarma = 32000;
public static void AwardKarma(Mobile m, int offset, bool message)
{
var karma = m.Karma;
if (m.Talisman is BaseTalisman)
{
BaseTalisman talisman = (BaseTalisman)m.Talisman;
if (talisman.KarmaLoss > 0)
offset *= (1 + (int)(((double)talisman.KarmaLoss) / 100));
else if (talisman.KarmaLoss < 0)
offset *= (1 - (int)(((double)-talisman.KarmaLoss) / 100));
}
int karmaLoss = AosAttributes.GetValue(m, AosAttribute.IncreasedKarmaLoss);
if (karmaLoss != 0 && offset < 0)
{
offset -= (int)(offset * (karmaLoss / 100.0));
}
if (offset > 0)
{
if (m is PlayerMobile && ((PlayerMobile)m).KarmaLocked)
return;
if (karma >= MaxKarma)
return;
offset -= karma / 100;
if (offset < 0)
offset = 0;
}
else if (offset < 0)
{
if (karma <= MinKarma)
return;
offset -= karma / 100;
if (offset > 0)
offset = 0;
}
if ((karma + offset) > MaxKarma)
offset = MaxKarma - karma;
else if ((karma + offset) < MinKarma)
offset = MinKarma - karma;
bool wasPositiveKarma = (karma >= 0);
m.Karma += offset;
if (message)
{
if (offset > 40)
m.SendLocalizedMessage(1019062); // You have gained a lot of karma.
else if (offset > 20)
m.SendLocalizedMessage(1019061); // You have gained a good amount of karma.
else if (offset > 10)
m.SendLocalizedMessage(1019060); // You have gained some karma.
else if (offset > 0)
m.SendLocalizedMessage(1019059); // You have gained a little karma.
else if (offset < -40)
m.SendLocalizedMessage(1019066); // You have lost a lot of karma.
else if (offset < -20)
m.SendLocalizedMessage(1019065); // You have lost a good amount of karma.
else if (offset < -10)
m.SendLocalizedMessage(1019064); // You have lost some karma.
else if (offset < 0)
m.SendLocalizedMessage(1019063); // You have lost a little karma.
}
if (!Core.AOS && wasPositiveKarma && m.Karma < 0 && m is PlayerMobile && !((PlayerMobile)m).KarmaLocked)
{
((PlayerMobile)m).KarmaLocked = true;
m.SendLocalizedMessage(1042511, "", 0x22); // Karma is locked. A mantra spoken at a shrine will unlock it again.
}
}
public static List<string> GetFameKarmaEntries(Mobile m)
{
List<string> list = new List<string>();
int fame = m.Fame;
int karma = m.Karma;
for (int i = 0; i < m_FameEntries.Length; ++i)
{
FameEntry fe = m_FameEntries[i];
if (fame >= fe.m_Fame)
{
KarmaEntry[] karmaEntries = fe.m_Karma;
for (int j = 0; j < karmaEntries.Length; ++j)
{
KarmaEntry ke = karmaEntries[j];
StringBuilder title = new StringBuilder();
if ((karma >= 0 && ke.m_Karma >= 0 && karma >= ke.m_Karma) || (karma < 0 && ke.m_Karma < 0 && karma < ke.m_Karma))
{
list.Add(title.AppendFormat(ke.m_Title, m.Name, m.Female ? "Lady" : "Lord").ToString());
}
}
}
}
return list;
}
public static string[] HarrowerTitles = new string[] { "Spite", "Opponent", "Hunter", "Venom", "Executioner", "Annihilator", "Champion", "Assailant", "Purifier", "Nullifier" };
public static string ComputeFameTitle(Mobile beheld)
{
int fame = beheld.Fame;
int karma = beheld.Karma;
for (int i = 0; i < m_FameEntries.Length; ++i)
{
FameEntry fe = m_FameEntries[i];
if (fame <= fe.m_Fame || i == (m_FameEntries.Length - 1))
{
KarmaEntry[] karmaEntries = fe.m_Karma;
for (int j = 0; j < karmaEntries.Length; ++j)
{
KarmaEntry ke = karmaEntries[j];
if (karma <= ke.m_Karma || j == (karmaEntries.Length - 1))
{
return String.Format(ke.m_Title, beheld.Name, beheld.Female ? "Lady" : "Lord");
}
}
return String.Empty;
}
}
return String.Empty;
}
public static string ComputeTitle(Mobile beholder, Mobile beheld)
{
StringBuilder title = new StringBuilder();
bool showSkillTitle = beheld.ShowFameTitle && ((beholder == beheld) || (beheld.Fame >= 5000));
if (Core.SA && beheld.ShowFameTitle && beheld is PlayerMobile && ((PlayerMobile)beheld).FameKarmaTitle != null)
{
title.AppendFormat(((PlayerMobile)beheld).FameKarmaTitle, beheld.Name, beheld.Female ? "Lady" : "Lord");
}
else if (beheld.ShowFameTitle || (beholder == beheld))
{
title.Append(ComputeFameTitle(beheld));
}
else
{
title.Append(beheld.Name);
}
if (beheld is PlayerMobile && ((PlayerMobile)beheld).DisplayChampionTitle)
{
PlayerMobile.ChampionTitleInfo info = ((PlayerMobile)beheld).ChampionTitles;
if (Core.SA)
{
if (((PlayerMobile)beheld).CurrentChampTitle != null)
title.AppendFormat(((PlayerMobile)beheld).CurrentChampTitle);
}
else if (info.Harrower > 0)
title.AppendFormat(": {0} of Evil", HarrowerTitles[Math.Min(HarrowerTitles.Length, info.Harrower) - 1]);
else
{
int highestValue = 0, highestType = 0;
for (int i = 0; i < ChampionSpawnInfo.Table.Length; i++)
{
int v = info.GetValue(i);
if (v > highestValue)
{
highestValue = v;
highestType = i;
}
}
int offset = 0;
if (highestValue > 800)
offset = 3;
else if (highestValue > 300)
offset = (int)(highestValue / 300);
if (offset > 0)
{
ChampionSpawnInfo champInfo = ChampionSpawnInfo.GetInfo((ChampionSpawnType)highestType);
title.AppendFormat(": {0} of the {1}", champInfo.LevelNames[Math.Min(offset, champInfo.LevelNames.Length) - 1], champInfo.Name);
}
}
}
string customTitle = beheld.Title;
if (Core.SA)
{
if (beheld is PlayerMobile && ((PlayerMobile)beheld).PaperdollSkillTitle != null)
title.Append(", ").Append(((PlayerMobile)beheld).PaperdollSkillTitle);
else if (beheld is BaseVendor)
title.AppendFormat(" {0}", customTitle);
}
else if (customTitle != null && (customTitle = customTitle.Trim()).Length > 0)
{
title.AppendFormat(" {0}", customTitle);
}
else if (showSkillTitle && beheld.Player)
{
string skillTitle = GetSkillTitle(beheld);
if (skillTitle != null)
{
title.Append(", ").Append(skillTitle);
}
}
return title.ToString();
}
public static string GetSkillTitle(Mobile mob)
{
Skill highest = GetHighestSkill(mob);// beheld.Skills.Highest;
if (highest != null && highest.BaseFixedPoint >= 300)
{
string skillLevel = GetSkillLevel(highest);
string skillTitle = highest.Info.Title;
if (mob.Female && skillTitle.EndsWith("man"))
skillTitle = skillTitle.Substring(0, skillTitle.Length - 3) + "woman";
return String.Concat(skillLevel, " ", skillTitle);
}
return null;
}
public static string GetSkillTitle(Mobile mob, Skill skill)
{
if (skill != null && skill.BaseFixedPoint >= 300)
{
string skillLevel = GetSkillLevel(skill);
string skillTitle = skill.Info.Title;
if (mob.Female && skillTitle.EndsWith("man"))
skillTitle = skillTitle.Substring(0, skillTitle.Length - 3) + "woman";
return String.Concat(skillLevel, " ", skillTitle);
}
return null;
}
private static Skill GetHighestSkill(Mobile m)
{
Skills skills = m.Skills;
if (!Core.AOS)
return skills.Highest;
Skill highest = null;
for (int i = 0; i < m.Skills.Length; ++i)
{
Skill check = m.Skills[i];
if (highest == null || check.BaseFixedPoint > highest.BaseFixedPoint)
highest = check;
else if (highest != null && highest.Lock != SkillLock.Up && check.Lock == SkillLock.Up && check.BaseFixedPoint == highest.BaseFixedPoint)
highest = check;
}
return highest;
}
private static readonly string[,] m_Levels = new string[,]
{
{ "Neophyte", "Neophyte", "Neophyte" },
{ "Novice", "Novice", "Novice" },
{ "Apprentice", "Apprentice", "Apprentice" },
{ "Journeyman", "Journeyman", "Journeyman" },
{ "Expert", "Expert", "Expert" },
{ "Adept", "Adept", "Adept" },
{ "Master", "Master", "Master" },
{ "Grandmaster", "Grandmaster", "Grandmaster" },
{ "Elder", "Tatsujin", "Shinobi" },
{ "Legendary", "Kengo", "Ka-ge" }
};
private static string GetSkillLevel(Skill skill)
{
return m_Levels[GetTableIndex(skill), GetTableType(skill)];
}
private static int GetTableType(Skill skill)
{
switch ( skill.SkillName )
{
default:
return 0;
case SkillName.Bushido:
return 1;
case SkillName.Ninjitsu:
return 2;
}
}
private static int GetTableIndex(Skill skill)
{
int fp = skill == null ? 300 : skill.BaseFixedPoint;
fp = Math.Min(fp, 1200);
return (fp - 300) / 100;
}
private static readonly FameEntry[] m_FameEntries = new FameEntry[]
{
new FameEntry(1249, new KarmaEntry[]
{
new KarmaEntry(-10000, "The Outcast {0}"),
new KarmaEntry(-5000, "The Despicable {0}"),
new KarmaEntry(-2500, "The Scoundrel {0}"),
new KarmaEntry(-1250, "The Unsavory {0}"),
new KarmaEntry(-625, "The Rude {0}"),
new KarmaEntry(624, "{0}"),
new KarmaEntry(1249, "The Fair {0}"),
new KarmaEntry(2499, "The Kind {0}"),
new KarmaEntry(4999, "The Good {0}"),
new KarmaEntry(9999, "The Honest {0}"),
new KarmaEntry(10000, "The Trustworthy {0}")
}),
new FameEntry(2499, new KarmaEntry[]
{
new KarmaEntry(-10000, "The Wretched {0}"),
new KarmaEntry(-5000, "The Dastardly {0}"),
new KarmaEntry(-2500, "The Malicious {0}"),
new KarmaEntry(-1250, "The Dishonorable {0}"),
new KarmaEntry(-625, "The Disreputable {0}"),
new KarmaEntry(624, "The Notable {0}"),
new KarmaEntry(1249, "The Upstanding {0}"),
new KarmaEntry(2499, "The Respectable {0}"),
new KarmaEntry(4999, "The Honorable {0}"),
new KarmaEntry(9999, "The Commendable {0}"),
new KarmaEntry(10000, "The Estimable {0}")
}),
new FameEntry(4999, new KarmaEntry[]
{
new KarmaEntry(-10000, "The Nefarious {0}"),
new KarmaEntry(-5000, "The Wicked {0}"),
new KarmaEntry(-2500, "The Vile {0}"),
new KarmaEntry(-1250, "The Ignoble {0}"),
new KarmaEntry(-625, "The Notorious {0}"),
new KarmaEntry(624, "The Prominent {0}"),
new KarmaEntry(1249, "The Reputable {0}"),
new KarmaEntry(2499, "The Proper {0}"),
new KarmaEntry(4999, "The Admirable {0}"),
new KarmaEntry(9999, "The Famed {0}"),
new KarmaEntry(10000, "The Great {0}")
}),
new FameEntry(9999, new KarmaEntry[]
{
new KarmaEntry(-10000, "The Dread {0}"),
new KarmaEntry(-5000, "The Evil {0}"),
new KarmaEntry(-2500, "The Villainous {0}"),
new KarmaEntry(-1250, "The Sinister {0}"),
new KarmaEntry(-625, "The Infamous {0}"),
new KarmaEntry(624, "The Renowned {0}"),
new KarmaEntry(1249, "The Distinguished {0}"),
new KarmaEntry(2499, "The Eminent {0}"),
new KarmaEntry(4999, "The Noble {0}"),
new KarmaEntry(9999, "The Illustrious {0}"),
new KarmaEntry(10000, "The Glorious {0}")
}),
new FameEntry(10000, new KarmaEntry[]
{
new KarmaEntry(-10000, "The Dread {1} {0}"),
new KarmaEntry(-5000, "The Evil {1} {0}"),
new KarmaEntry(-2500, "The Dark {1} {0}"),
new KarmaEntry(-1250, "The Sinister {1} {0}"),
new KarmaEntry(-625, "The Dishonored {1} {0}"),
new KarmaEntry(624, "{1} {0}"),
new KarmaEntry(1249, "The Distinguished {1} {0}"),
new KarmaEntry(2499, "The Eminent {1} {0}"),
new KarmaEntry(4999, "The Noble {1} {0}"),
new KarmaEntry(9999, "The Illustrious {1} {0}"),
new KarmaEntry(10000, "The Glorious {1} {0}")
})
};
public static VeteranTitle[] VeteranTitles { get; set; }
public static void Initialize()
{
VeteranTitles = new VeteranTitle[9];
for (int i = 0; i < 9; i++)
{
VeteranTitles[i] = new VeteranTitle(1154341 + i, 2 * (i + 1));
}
}
public static List<VeteranTitle> GetVeteranTitles(Mobile m)
{
Account a = m.Account as Account;
if (a == null)
return null;
int years = (int)(DateTime.UtcNow - a.Created).TotalDays;
years /= 365;
if (years < 2)
return null;
List<VeteranTitle> titles = new List<VeteranTitle>();
foreach (VeteranTitle title in VeteranTitles)
{
if (years >= title.Years)
titles.Add(title);
}
return titles;
}
}
public class FameEntry
{
public int m_Fame;
public KarmaEntry[] m_Karma;
public FameEntry(int fame, KarmaEntry[] karma)
{
this.m_Fame = fame;
this.m_Karma = karma;
}
}
public class KarmaEntry
{
public int m_Karma;
public string m_Title;
public KarmaEntry(int karma, string title)
{
this.m_Karma = karma;
this.m_Title = title;
}
}
public class VeteranTitle
{
public int Title { get; set; }
public int Years { get; set; }
public VeteranTitle(int title, int years)
{
Title = title;
Years = years;
}
}
}

144
Scripts/Misc/ToggleItem.cs Normal file
View File

@@ -0,0 +1,144 @@
using System;
using Server.Commands;
using Server.Commands.Generic;
namespace Server.Items
{
public class ToggleItem : Item
{
private int m_InactiveItemID;
private int m_ActiveItemID;
private bool m_PlayersCanToggle;
[Constructable]
public ToggleItem(int inactiveItemID, int activeItemID)
: this(inactiveItemID, activeItemID, false)
{
}
[Constructable]
public ToggleItem(int inactiveItemID, int activeItemID, bool playersCanToggle)
: base(inactiveItemID)
{
this.Movable = false;
this.m_InactiveItemID = inactiveItemID;
this.m_ActiveItemID = activeItemID;
this.m_PlayersCanToggle = playersCanToggle;
}
public ToggleItem(Serial serial)
: base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public int InactiveItemID
{
get
{
return this.m_InactiveItemID;
}
set
{
this.m_InactiveItemID = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public int ActiveItemID
{
get
{
return this.m_ActiveItemID;
}
set
{
this.m_ActiveItemID = value;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public bool PlayersCanToggle
{
get
{
return this.m_PlayersCanToggle;
}
set
{
this.m_PlayersCanToggle = value;
}
}
public static void Initialize()
{
TargetCommands.Register(new ToggleCommand());
}
public override void OnDoubleClick(Mobile from)
{
if (from.AccessLevel >= AccessLevel.GameMaster)
{
this.Toggle();
}
else if (this.m_PlayersCanToggle)
{
if (from.InRange(this.GetWorldLocation(), 1))
this.Toggle();
else
from.SendLocalizedMessage(500446); // That is too far away.
}
}
public void Toggle()
{
this.ItemID = (this.ItemID == this.m_ActiveItemID) ? this.m_InactiveItemID : this.m_ActiveItemID;
this.Visible = (this.ItemID != 0x1);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write(this.m_InactiveItemID);
writer.Write(this.m_ActiveItemID);
writer.Write(this.m_PlayersCanToggle);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
this.m_InactiveItemID = reader.ReadInt();
this.m_ActiveItemID = reader.ReadInt();
this.m_PlayersCanToggle = reader.ReadBool();
}
public class ToggleCommand : BaseCommand
{
public ToggleCommand()
{
this.AccessLevel = AccessLevel.GameMaster;
this.Supports = CommandSupport.AllItems;
this.Commands = new string[] { "Toggle" };
this.ObjectTypes = ObjectTypes.Items;
this.Usage = "Toggle";
this.Description = "Toggles a targeted ToggleItem.";
}
public override void Execute(CommandEventArgs e, object obj)
{
if (obj is ToggleItem)
{
((ToggleItem)obj).Toggle();
this.AddResponse("The item has been toggled.");
}
else
{
this.LogFailure("That is not a ToggleItem.");
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Server.Mobiles
{
public class UntamedPetsCleaning
{
public static void Initialize()
{
CleanUntamedPets();
Timer.DelayCall(TimeSpan.FromHours(12.0), TimeSpan.FromHours(12.0), new TimerCallback(CleanUntamedPets));
}
private static void CleanUntamedPets()
{
List<Mobile> list = new List<Mobile>();
foreach (BaseCreature b in World.Mobiles.Values.OfType<BaseCreature>().Where(bc => bc.RemoveOnSave && !bc.Controlled && bc.ControlMaster == null))
{
list.Add(b);
}
for (int i = 0; i < list.Count; i++)
{
list[i].Delete();
}
list.Clear();
list.TrimExcess();
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Server
{
public delegate void ValidationEventHandler();
public static class ValidationQueue
{
public static event ValidationEventHandler StartValidation;
public static void Initialize()
{
if (StartValidation != null)
StartValidation();
StartValidation = null;
}
}
public static class ValidationQueue<T>
{
private static List<T> m_Queue;
static ValidationQueue()
{
m_Queue = new List<T>();
ValidationQueue.StartValidation += new ValidationEventHandler(ValidateAll);
}
public static void Add(T obj)
{
m_Queue.Add(obj);
}
private static void ValidateAll()
{
Type type = typeof(T);
if (type != null)
{
MethodInfo m = type.GetMethod("Validate", BindingFlags.Instance | BindingFlags.Public);
if (m != null)
{
for (int i = 0; i < m_Queue.Count; ++i)
m.Invoke(m_Queue[i], null);
}
}
m_Queue.Clear();
m_Queue = null;
}
}
}

214
Scripts/Misc/Waypoints.cs Normal file
View File

@@ -0,0 +1,214 @@
using System;
using Server.Network;
using Server.Engines.Quests;
using Server.Mobiles;
using System.Collections.Generic;
using Server.Engines.PartySystem;
using System.Linq;
namespace Server
{
/* We need to add:
* MondainQuesters when alive, so on MapChange
* MondainQuesters are displayed on EA by subserver, so we'll have to do it by map
*
* Corpse, when dead
* Healers, when dead
*
* Remove: healers when rezzed
* Questers when you leave their map
*/
public class Waypoints
{
public static void Create(Mobile m, Mobile mob, WaypointType type, bool ignoreObject = false)
{
NetState ns = m.NetState;
if (ns != null && mob != null && !mob.Deleted)
{
ns.Send(new DisplayWaypoint(mob.Serial, mob.X, mob.Y, mob.Z, mob.Map.MapID, type, mob.Name + " " + mob.Title, ignoreObject));
}
}
public static void Create(Mobile m, IEntity e, WaypointType type, string arg, bool ignoreObject = false)
{
NetState ns = m.NetState;
if (ns != null && e != null && !e.Deleted && (!(e is Mobile) || ((Mobile)e).Alive))
{
ns.Send(new DisplayWaypoint(e.Serial, e.X, e.Y, e.Z, e.Map.MapID, type, arg, ignoreObject));
}
}
public static void Remove(Mobile m, IEntity e)
{
NetState ns = m.NetState;
if (ns != null)
{
ns.Send(new RemoveWaypoint(e.Serial));
}
}
public static void OnMapChange(Mobile m, Map oldMap)
{
NetState ns = m.NetState;
if (ns == null || !ns.IsEnhancedClient)
return;
if (m.Alive)
{
RemoveQuesters(m, ns, oldMap);
AddQuesters(m);
}
else if(m.Corpse != null)
{
AddCorpse(m);
RemoveHealers(m, oldMap);
AddHealers(m);
}
}
public static void OnDeath(Mobile m)
{
NetState ns = m.NetState;
if (ns == null /*|| !ns.IsEnhancedClient*/)
return;
AddHealers(m);
}
public static void AddCorpse(Mobile m)
{
if (m.Corpse != null)
{
Create(m, m.Corpse, WaypointType.Corpse, m.Name);
}
}
public static void RemoveQuesters(Mobile m, NetState ns, Map oldMap)
{
if (m == null || oldMap == null)
return;
foreach (var vendor in BaseVendor.AllVendors.Where(q => q is MondainQuester && !q.Deleted && q.Map == oldMap))
{
ns.Send(new RemoveWaypoint(vendor.Serial));
}
}
public static void AddQuesters(Mobile m)
{
if (m == null || m.Map == null || m.Deleted)
return;
foreach (var vendor in BaseVendor.AllVendors.Where(q => q is MondainQuester && !q.Deleted && q.Map == m.Map))
{
Create(m, vendor, WaypointType.QuestGiver);
}
}
private static void AddHealers(Mobile m)
{
if (m == null || m.Map == null || m.Deleted)
return;
foreach (var healer in BaseVendor.AllVendors.OfType<BaseHealer>().Where(h => h != null && !h.Deleted && h.Map == m.Map))
{
Create(m, healer, WaypointType.Resurrection);
}
}
public static void RemoveHealers(Mobile m, Map oldMap)
{
if (m == null || oldMap == null)
return;
NetState ns = m.NetState;
if (ns == null)
return;
foreach (var healer in BaseVendor.AllVendors.OfType<BaseHealer>().Where(h => h != null && !h.Deleted && h.Map == oldMap))
{
ns.Send(new RemoveWaypoint(healer.Serial));
}
}
public static void UpdateToParty(Mobile m)
{
Party p = Party.Get(m);
if (p != null)
{
foreach (var mob in p.Members.Select(i => i.Mobile).Where(mobile => mobile != m && mobile.NetState != null && mobile.NetState.IsEnhancedClient))
{
Create(mob, m, WaypointType.PartyMember);
}
}
}
}
public enum WaypointType : ushort
{
Corpse = 0x01,
PartyMember = 0x02,
RallyPoint = 0x03,
QuestGiver = 0x04,
QuestDestination = 0x05,
Resurrection = 0x06,
PointOfInterest = 0x07,
Landmark = 0x08,
Town = 0x09,
Dungeon = 0x0A,
Moongate = 0x0B,
Shop = 0x0C,
Player = 0x0D,
}
public sealed class DisplayWaypoint : Packet
{
public DisplayWaypoint(Serial serial, int x, int y, int z, int mapID, WaypointType type, string name)
: this(serial, x, y, z, mapID, type, name, false)
{
}
public DisplayWaypoint(Serial serial, int x, int y, int z, int mapID, WaypointType type, string name, bool ignoreObject)
: base(0xE5)
{
EnsureCapacity(21 + (name.Length * 2));
m_Stream.Write((int)serial);
m_Stream.Write((ushort)x);
m_Stream.Write((ushort)y);
m_Stream.Write((sbyte)z);
m_Stream.Write((byte)mapID); //map
m_Stream.Write((ushort)type);
m_Stream.Write((ushort)(ignoreObject ? 1 : 0));
if(type == WaypointType.Corpse)
m_Stream.Write((int)1046414);
else
m_Stream.Write((int)1062613);
m_Stream.WriteLittleUniNull(name);
m_Stream.Write((short)0); // terminate
}
}
public class RemoveWaypoint : Packet
{
public RemoveWaypoint(Serial serial)
: base(0xE6, 5)
{
m_Stream.Write((int)serial);
}
}
}

View File

@@ -0,0 +1,236 @@
#region References
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
#endregion
namespace Server
{
public static class WeakEntityCollection
{
public sealed class EntityCollection : List<IEntity>
{
public IEnumerable<Item> Items { get { return this.OfType<Item>(); } }
public IEnumerable<Mobile> Mobiles { get { return this.OfType<Mobile>(); } }
public EntityCollection()
: this(0x400)
{ }
public EntityCollection(int capacity)
: base(capacity)
{ }
}
private static readonly string _FilePath = Path.Combine("Saves", "WeakEntityCollection", "WeakEntityCollection.bin");
private static readonly Dictionary<string, EntityCollection> _Collections =
new Dictionary<string, EntityCollection>(StringComparer.OrdinalIgnoreCase);
public static void Configure()
{
EventSink.WorldSave += OnWorldSave;
EventSink.WorldLoad += OnWorldLoad;
}
private static void OnWorldSave(WorldSaveEventArgs e)
{
Save();
}
private static void OnWorldLoad()
{
Load();
}
public static void Save()
{
Persistence.Serialize(
_FilePath,
writer =>
{
writer.Write(1); // Version
writer.Write(_Collections.Count);
foreach (var kv in _Collections)
{
writer.Write(kv.Key);
kv.Value.RemoveAll(ent => ent == null || ent.Deleted);
writer.Write(kv.Value.Count);
foreach (var ent in kv.Value)
{
writer.Write(ent.Serial);
}
}
});
}
public static void Load()
{
Persistence.Deserialize(
_FilePath,
reader =>
{
var version = reader.ReadInt();
switch (version)
{
case 1:
{
var entries = reader.ReadInt();
while (--entries >= 0)
{
var key = reader.ReadString();
var ents = reader.ReadInt();
var col = new EntityCollection(ents);
IEntity ent;
while (--ents >= 0)
{
ent = World.FindEntity(reader.ReadInt());
if (ent != null && !ent.Deleted)
{
col.Add(ent);
}
}
_Collections[key] = col;
}
}
break;
case 0:
{
var entries = reader.ReadInt();
while (--entries >= 0)
{
var key = reader.ReadString();
var items = reader.ReadStrongItemList();
var mobiles = reader.ReadStrongMobileList();
var col = new EntityCollection(items.Count + mobiles.Count);
col.AddRange(items);
col.AddRange(mobiles);
_Collections[key] = col;
}
}
break;
}
});
}
public static EntityCollection GetCollection(string name)
{
EntityCollection col;
if (!_Collections.TryGetValue(name, out col) || col == null)
{
_Collections[name] = col = new EntityCollection();
}
return col;
}
public static bool HasCollection(string name)
{
return name != null && _Collections.ContainsKey(name);
}
public static void Add(string key, IEntity entity)
{
if (entity == null || entity.Deleted)
{
return;
}
var col = GetCollection(key);
if (col != null && !col.Contains(entity))
{
col.Add(entity);
}
}
public static bool Remove(string key, IEntity entity)
{
if (entity == null)
{
return false;
}
var col = GetCollection(key);
if (col != null)
{
return col.Remove(entity);
}
return false;
}
public static int Clean(string key)
{
var removed = 0;
var col = GetCollection(key);
if (col != null)
{
var ents = col.Count;
while (--ents >= 0)
{
if (ents < col.Count && col[ents].Deleted)
{
col.RemoveAt(ents);
++removed;
}
}
}
return removed;
}
public static int Delete(string key)
{
var deleted = 0;
var col = GetCollection(key);
if (col != null)
{
var ents = col.Count;
while (--ents >= 0)
{
if (ents < col.Count)
{
col[ents].Delete();
++deleted;
}
}
col.Clear();
}
_Collections.Remove(key);
return deleted;
}
}
}

474
Scripts/Misc/Weather.cs Normal file
View File

@@ -0,0 +1,474 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Network;
namespace Server.Misc
{
public class Weather
{
private static readonly Dictionary<Map, List<Weather>> m_WeatherByFacet = new Dictionary<Map, List<Weather>>();
private static Map[] m_Facets;
private readonly Map m_Facet;
private Rectangle2D[] m_Area;
private int m_Temperature;
private int m_ChanceOfPercipitation;
private int m_ChanceOfExtremeTemperature;
// For dynamic weather:
private Rectangle2D m_Bounds;
private int m_MoveSpeed;
private int m_MoveAngleX, m_MoveAngleY;
private int m_Stage;
private bool m_Active;
private bool m_ExtremeTemperature;
public Weather(Map facet, Rectangle2D[] area, int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, TimeSpan interval)
{
this.m_Facet = facet;
this.m_Area = area;
this.m_Temperature = temperature;
this.m_ChanceOfPercipitation = chanceOfPercipitation;
this.m_ChanceOfExtremeTemperature = chanceOfExtremeTemperature;
List<Weather> list = GetWeatherList(facet);
if (list != null)
list.Add(this);
Timer.DelayCall(TimeSpan.FromSeconds((0.2 + (Utility.RandomDouble() * 0.8)) * interval.TotalSeconds), interval, new TimerCallback(OnTick));
}
public Map Facet
{
get
{
return this.m_Facet;
}
}
public Rectangle2D[] Area
{
get
{
return this.m_Area;
}
set
{
this.m_Area = value;
}
}
public int Temperature
{
get
{
return this.m_Temperature;
}
set
{
this.m_Temperature = value;
}
}
public int ChanceOfPercipitation
{
get
{
return this.m_ChanceOfPercipitation;
}
set
{
this.m_ChanceOfPercipitation = value;
}
}
public int ChanceOfExtremeTemperature
{
get
{
return this.m_ChanceOfExtremeTemperature;
}
set
{
this.m_ChanceOfExtremeTemperature = value;
}
}
public Rectangle2D Bounds
{
get
{
return this.m_Bounds;
}
set
{
this.m_Bounds = value;
}
}
public int MoveSpeed
{
get
{
return this.m_MoveSpeed;
}
set
{
this.m_MoveSpeed = value;
}
}
public int MoveAngleX
{
get
{
return this.m_MoveAngleX;
}
set
{
this.m_MoveAngleX = value;
}
}
public int MoveAngleY
{
get
{
return this.m_MoveAngleY;
}
set
{
this.m_MoveAngleY = value;
}
}
public static void Initialize()
{
m_Facets = new Map[] { Map.Felucca, Map.Trammel };
/* Static weather:
*
* Format:
* AddWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, <area ...> );
*/
// ice island
AddWeather(-15, 100, 5, new Rectangle2D(3850, 160, 390, 320), new Rectangle2D(3900, 480, 380, 180), new Rectangle2D(4160, 660, 150, 110));
// covetous entrance, around vesper and minoc
AddWeather(+15, 50, 5, new Rectangle2D(2425, 725, 250, 250));
// despise entrance, north of britain
AddWeather(+15, 50, 5, new Rectangle2D(1245, 1045, 250, 250));
/* Dynamic weather:
*
* Format:
* AddDynamicWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, moveSpeed, width, height, bounds );
*/
for (int i = 0; i < 15; ++i)
AddDynamicWeather(+15, 100, 5, 8, 400, 400, new Rectangle2D(0, 0, 5120, 4096));
}
public static List<Weather> GetWeatherList(Map facet)
{
if (facet == null)
return null;
List<Weather> list = null;
m_WeatherByFacet.TryGetValue(facet, out list);
if (list == null)
m_WeatherByFacet[facet] = list = new List<Weather>();
return list;
}
public static void AddDynamicWeather(int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, int moveSpeed, int width, int height, Rectangle2D bounds)
{
for (int i = 0; i < m_Facets.Length; ++i)
{
Rectangle2D area = new Rectangle2D();
bool isValid = false;
for (int j = 0; j < 10; ++j)
{
area = new Rectangle2D(bounds.X + Utility.Random(bounds.Width - width), bounds.Y + Utility.Random(bounds.Height - height), width, height);
if (!CheckWeatherConflict(m_Facets[i], null, area))
isValid = true;
if (isValid)
break;
}
if (!isValid)
continue;
Weather w = new Weather(m_Facets[i], new Rectangle2D[] { area }, temperature, chanceOfPercipitation, chanceOfExtremeTemperature, TimeSpan.FromSeconds(30.0));
w.m_Bounds = bounds;
w.m_MoveSpeed = moveSpeed;
}
}
public static void AddWeather(int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, params Rectangle2D[] area)
{
for (int i = 0; i < m_Facets.Length; ++i)
new Weather(m_Facets[i], area, temperature, chanceOfPercipitation, chanceOfExtremeTemperature, TimeSpan.FromSeconds(30.0));
}
public static bool CheckWeatherConflict(Map facet, Weather exclude, Rectangle2D area)
{
List<Weather> list = GetWeatherList(facet);
if (list == null)
return false;
for (int i = 0; i < list.Count; ++i)
{
Weather w = list[i];
if (w != exclude && w.IntersectsWith(area))
return true;
}
return false;
}
public static bool CheckIntersection(Rectangle2D r1, Rectangle2D r2)
{
if (r1.X >= (r2.X + r2.Width))
return false;
if (r2.X >= (r1.X + r1.Width))
return false;
if (r1.Y >= (r2.Y + r2.Height))
return false;
if (r2.Y >= (r1.Y + r1.Height))
return false;
return true;
}
public static bool CheckContains(Rectangle2D big, Rectangle2D small)
{
if (small.X < big.X)
return false;
if (small.Y < big.Y)
return false;
if ((small.X + small.Width) > (big.X + big.Width))
return false;
if ((small.Y + small.Height) > (big.Y + big.Height))
return false;
return true;
}
public virtual bool IntersectsWith(Rectangle2D area)
{
for (int i = 0; i < this.m_Area.Length; ++i)
{
if (CheckIntersection(area, this.m_Area[i]))
return true;
}
return false;
}
public virtual void Reposition()
{
if (this.m_Area.Length == 0)
return;
int width = this.m_Area[0].Width;
int height = this.m_Area[0].Height;
Rectangle2D area = new Rectangle2D();
bool isValid = false;
for (int j = 0; j < 10; ++j)
{
area = new Rectangle2D(this.m_Bounds.X + Utility.Random(this.m_Bounds.Width - width), this.m_Bounds.Y + Utility.Random(this.m_Bounds.Height - height), width, height);
if (!CheckWeatherConflict(this.m_Facet, this, area))
isValid = true;
if (isValid)
break;
}
if (!isValid)
return;
this.m_Area[0] = area;
}
public virtual void RecalculateMovementAngle()
{
double angle = Utility.RandomDouble() * Math.PI * 2.0;
double cos = Math.Cos(angle);
double sin = Math.Sin(angle);
this.m_MoveAngleX = (int)(100 * cos);
this.m_MoveAngleY = (int)(100 * sin);
}
public virtual void MoveForward()
{
if (this.m_Area.Length == 0)
return;
for (int i = 0; i < 5; ++i) // try 5 times to find a valid spot
{
int xOffset = (this.m_MoveSpeed * this.m_MoveAngleX) / 100;
int yOffset = (this.m_MoveSpeed * this.m_MoveAngleY) / 100;
Rectangle2D oldArea = this.m_Area[0];
Rectangle2D newArea = new Rectangle2D(oldArea.X + xOffset, oldArea.Y + yOffset, oldArea.Width, oldArea.Height);
if (!CheckWeatherConflict(this.m_Facet, this, newArea) && CheckContains(this.m_Bounds, newArea))
{
this.m_Area[0] = newArea;
break;
}
this.RecalculateMovementAngle();
}
}
public virtual void OnTick()
{
if (this.m_Stage == 0)
{
this.m_Active = (this.m_ChanceOfPercipitation > Utility.Random(100));
this.m_ExtremeTemperature = (this.m_ChanceOfExtremeTemperature > Utility.Random(100));
if (this.m_MoveSpeed > 0)
{
this.Reposition();
this.RecalculateMovementAngle();
}
}
if (this.m_Active)
{
if (this.m_Stage > 0 && this.m_MoveSpeed > 0)
this.MoveForward();
int type, density, temperature;
temperature = this.m_Temperature;
if (this.m_ExtremeTemperature)
temperature *= -1;
if (this.m_Stage < 15)
{
density = this.m_Stage * 5;
}
else
{
density = 150 - (this.m_Stage * 5);
if (density < 10)
density = 10;
else if (density > 70)
density = 70;
}
if (density == 0)
type = 0xFE;
else if (temperature > 0)
type = 0;
else
type = 2;
List<NetState> states = NetState.Instances;
Packet weatherPacket = null;
for (int i = 0; i < states.Count; ++i)
{
NetState ns = states[i];
Mobile mob = ns.Mobile;
if (mob == null || mob.Map != this.m_Facet)
continue;
bool contains = (this.m_Area.Length == 0);
for (int j = 0; !contains && j < this.m_Area.Length; ++j)
contains = this.m_Area[j].Contains(mob.Location);
if (!contains)
continue;
if (weatherPacket == null)
weatherPacket = Packet.Acquire(new Server.Network.Weather(type, density, temperature));
ns.Send(weatherPacket);
}
Packet.Release(weatherPacket);
}
this.m_Stage++;
this.m_Stage %= 30;
}
}
public class WeatherMap : MapItem
{
[Constructable]
public WeatherMap()
{
this.SetDisplay(0, 0, 5119, 4095, 400, 400);
}
public WeatherMap(Serial serial)
: base(serial)
{
}
public override string DefaultName
{
get
{
return "weather map";
}
}
public override void OnDoubleClick(Mobile from)
{
Map facet = from.Map;
if (facet == null)
return;
List<Weather> list = Weather.GetWeatherList(facet);
this.ClearPins();
for (int i = 0; i < list.Count; ++i)
{
Weather w = list[i];
for (int j = 0; j < w.Area.Length; ++j)
this.AddWorldPin(w.Area[j].X + (w.Area[j].Width / 2), w.Area[j].Y + (w.Area[j].Height / 2));
}
base.OnDoubleClick(from);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

194
Scripts/Misc/WebStatus.cs Normal file
View File

@@ -0,0 +1,194 @@
#region References
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using Server.Guilds;
using Server.Network;
#endregion
namespace Server.Misc
{
public class StatusPage : Timer
{
public static readonly bool Enabled = false;
private static HttpListener _Listener;
private static string _StatusPage = String.Empty;
private static byte[] _StatusBuffer = new byte[0];
private static readonly object _StatusLock = new object();
public static void Initialize()
{
if (!Enabled)
{
return;
}
new StatusPage().Start();
Listen();
}
private static void Listen()
{
if (!HttpListener.IsSupported)
{
return;
}
if (_Listener == null)
{
_Listener = new HttpListener();
_Listener.Prefixes.Add("http://*:80/status/");
_Listener.Start();
}
else if (!_Listener.IsListening)
{
_Listener.Start();
}
if (_Listener.IsListening)
{
_Listener.BeginGetContext(ListenerCallback, null);
}
}
private static void ListenerCallback(IAsyncResult result)
{
try
{
var context = _Listener.EndGetContext(result);
byte[] buffer;
lock (_StatusLock)
{
buffer = _StatusBuffer;
}
context.Response.ContentLength64 = buffer.Length;
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.OutputStream.Close();
}
catch
{ }
Listen();
}
private static string Encode(string input)
{
var sb = new StringBuilder(input);
sb.Replace("&", "&amp;");
sb.Replace("<", "&lt;");
sb.Replace(">", "&gt;");
sb.Replace("\"", "&quot;");
sb.Replace("'", "&apos;");
return sb.ToString();
}
public StatusPage()
: base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(60.0))
{
Priority = TimerPriority.FiveSeconds;
}
protected override void OnTick()
{
if (!Directory.Exists("web"))
{
Directory.CreateDirectory("web");
}
using (var op = new StreamWriter("web/status.html"))
{
op.WriteLine("<!DOCTYPE html>");
op.WriteLine("<html>");
op.WriteLine(" <head>");
op.WriteLine(" <title>" + ServerList.ServerName + " Server Status</title>");
op.WriteLine(" </head>");
op.WriteLine(" <style type=\"text/css\">");
op.WriteLine(" body { background: #999; }");
op.WriteLine(" table { width: 100%; }");
op.WriteLine(" tr.ruo-header td { background: #000; color: #FFF; }");
op.WriteLine(" tr.odd td { background: #222; color: #DDD; }");
op.WriteLine(" tr.even td { background: #DDD; color: #222; }");
op.WriteLine(" </style>");
op.WriteLine(" <body>");
op.WriteLine(" <h1>" + ServerList.ServerName + "Server Status</h1>");
op.WriteLine(" <h3>Online clients</h3>");
op.WriteLine(" <table cellpadding=\"0\" cellspacing=\"0\">");
op.WriteLine(" <tr class=\"ruo-header\"><td>Name</td><td>Location</td><td>Kills</td><td>Karma/Fame</td></tr>");
var index = 0;
foreach (var m in NetState.Instances.Where(state => state.Mobile != null).Select(state => state.Mobile))
{
++index;
var g = m.Guild as Guild;
op.Write(" <tr class=\"ruo-result " + (index % 2 == 0 ? "even" : "odd") + "\"><td>");
if (g != null)
{
op.Write(Encode(m.Name));
op.Write(" [");
var title = m.GuildTitle;
title = title != null ? title.Trim() : String.Empty;
if (title.Length > 0)
{
op.Write(Encode(title));
op.Write(", ");
}
op.Write(Encode(g.Abbreviation));
op.Write(']');
}
else
{
op.Write(Encode(m.Name));
}
op.Write("</td><td>");
op.Write(m.X);
op.Write(", ");
op.Write(m.Y);
op.Write(", ");
op.Write(m.Z);
op.Write(" (");
op.Write(m.Map);
op.Write(")</td><td>");
op.Write(m.Kills);
op.Write("</td><td>");
op.Write(m.Karma);
op.Write(" / ");
op.Write(m.Fame);
op.WriteLine("</td></tr>");
}
op.WriteLine(" <tr>");
op.WriteLine(" </table>");
op.WriteLine(" </body>");
op.WriteLine("</html>");
}
lock (_StatusLock)
{
_StatusPage = File.ReadAllText("web/status.html");
_StatusBuffer = Encoding.UTF8.GetBytes(_StatusPage);
}
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Items;
namespace Server.Misc
{
public class WeightOverloading
{
public const int OverloadAllowance = 4;// We can be four stones overweight without getting fatigued
public static void Initialize()
{
EventSink.Movement += new MovementEventHandler(EventSink_Movement);
Mobile.FatigueHandler = FatigueOnDamage;
}
public static void FatigueOnDamage(Mobile m, int damage, DFAlgorithm df)
{
double fatigue = 0.0;
var hits = Math.Max(1, m.Hits);
switch (m.DFA)
{
case DFAlgorithm.Standard:
{
fatigue = (damage * (m.HitsMax / hits) * ((double)m.Stam / m.StamMax)) - 5;
}
break;
case DFAlgorithm.PainSpike:
{
fatigue = (damage * ((m.HitsMax / hits) + ((50.0 + m.Stam) / m.StamMax) - 1.0)) - 5;
}
break;
}
var reduction = BaseArmor.GetInherentStaminaLossReduction(m) + 1;
if (reduction > 1)
{
fatigue = fatigue / reduction;
}
if (fatigue > 0)
{
// On EA, if follows this special rule to reduce the chances of your stamina being dropped to 0
if (m.Stam - fatigue <= 10)
{
m.Stam -= (int)(fatigue * ((double)m.Hits / (double)m.HitsMax));
}
else
{
m.Stam -= (int)fatigue;
}
}
}
public static void EventSink_Movement(MovementEventArgs e)
{
Mobile from = e.Mobile;
if (!from.Alive || from.IsStaff())
return;
if (!from.Player)
{
return;
}
int maxWeight = from.MaxWeight + OverloadAllowance;
int overWeight = (Mobile.BodyWeight + from.TotalWeight) - maxWeight;
if (overWeight > 0)
{
from.Stam -= GetStamLoss(from, overWeight, (e.Direction & Direction.Running) != 0);
if (from.Stam == 0)
{
from.SendLocalizedMessage(500109); // You are too fatigued to move, because you are carrying too much weight!
e.Blocked = true;
return;
}
}
if (!Core.SA && ((from.Stam * 100) / Math.Max(from.StamMax, 1)) < 10)
{
--from.Stam;
}
if (from.Stam == 0)
{
from.SendLocalizedMessage(from.Mounted ? 500108 : 500110); // Your mount is too fatigued to move. : You are too fatigued to move.
e.Blocked = true;
return;
}
var pm = from as PlayerMobile;
if (pm != null)
{
int amt = Core.SA ? 10 : (from.Mounted ? 48 : 16);
if ((++pm.StepsTaken % amt) == 0)
--from.Stam;
}
}
public static int GetStamLoss(Mobile from, int overWeight, bool running)
{
int loss = 5 + (overWeight / 25);
if (from.Mounted)
loss /= 3;
if (running)
loss *= 2;
return loss;
}
public static bool IsOverloaded(Mobile m)
{
if (!m.Player || !m.Alive || m.IsStaff())
return false;
return ((Mobile.BodyWeight + m.TotalWeight) > (m.MaxWeight + OverloadAllowance));
}
}
}

View File

@@ -0,0 +1,59 @@
#region References
using System;
#endregion
namespace Server.Misc
{
/// <summary>
/// This timer spouts some welcome messages to a user at a set interval. It is used on character creation and login.
/// </summary>
public class WelcomeTimer : Timer
{
private static readonly string[] m_Messages =
{
"Welcome to " + ServerList.ServerName + ".", //
"Please enjoy your stay!"
};
private static readonly string[] m_TCMessages =
{
"Welcome to " + ServerList.ServerName + ".", //
"You are able to customize your character's stats and skills at anytime to anything you wish. To see the commands to do this just say 'help'.", //
"You will find a bank check worth 1,000,000 gold in your bank!", //
"A spellbook and a bag of reagents has been placed into your bank box.", //
"Various tools have been placed into your bank.", //
"Various raw materials like ingots, logs, feathers, hides, bottles, etc, have been placed into your bank.", //
"5 unmarked recall runes, 5 Felucca moonstones and 5 Trammel moonstones have been placed into your bank box.", //
"One of each level of treasure map has been placed in your bank box.", //
"You will find 9000 silver pieces deposited into your bank box. Spend it as you see fit and enjoy yourself!", //
"You will find 9000 gold pieces deposited into your bank box. Spend it as you see fit and enjoy yourself!", //
"A bag of PowerScrolls has been placed in your bank box.", //
"Enjoy playing in Test Center mode!"
};
private readonly Mobile m_Mobile;
private readonly string[] m_Lines;
private int m_State;
public WelcomeTimer(Mobile m)
: this(m, TestCenter.Enabled ? m_TCMessages : m_Messages)
{ }
public WelcomeTimer(Mobile m, string[] lines)
: base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(10.0))
{
m_Mobile = m;
m_Lines = lines;
}
protected override void OnTick()
{
if (m_State < m_Lines.Length)
m_Mobile.SendMessage(0x35, m_Lines[m_State++]);
if (m_State == m_Lines.Length)
Stop();
}
}
}

View File

@@ -0,0 +1,213 @@
using System;
using Server.Regions;
using Server.Commands;
namespace Server
{
public class WorldLocationInfo
{
public static void Initialize()
{
CommandSystem.Register("GetLocation", AccessLevel.Administrator, new CommandEventHandler(GetLocation_OnCommand));
}
private string m_RegionName;
private Rectangle2D[] m_Bounds;
public string RegionName { get { return m_RegionName; } }
public Rectangle2D[] Bounds { get { return m_Bounds; } }
public WorldLocationInfo(string regionName, params Rectangle2D[] bounds)
{
m_RegionName = regionName;
m_Bounds = bounds;
}
public static WorldLocationInfo[][] Locations { get { return m_Locations; } }
private static WorldLocationInfo[][] m_Locations = new WorldLocationInfo[][]
{
new WorldLocationInfo[] // Felucca
{
new WorldLocationInfo("an island southeast of Britain", new Rectangle2D(1620, 1900, 594, 150),
new Rectangle2D(1810, 2040, 200, 120),
new Rectangle2D(1980, 2040, 250, 380)),
new WorldLocationInfo("near Buccaneer's Den", new Rectangle2D(2560, 1900, 400, 500)),
new WorldLocationInfo("a jungle near Serpent's Hold", new Rectangle2D(2750, 3320, 340, 340)),
new WorldLocationInfo("a forest near Ocllo", new Rectangle2D(3330, 2350, 500, 600)),
new WorldLocationInfo("a forest near Magincia", new Rectangle2D(3510, 2000, 310, 320)),
new WorldLocationInfo("a desert near Nujel'm", new Rectangle2D(3480, 1020, 350, 410)),
new WorldLocationInfo("the arctic island north of Moonglow", new Rectangle2D(3850, 160, 500, 600)),
new WorldLocationInfo("a forest near Moonglow", new Rectangle2D(4250, 780, 500, 800)),
new WorldLocationInfo("the isle of fire", new Rectangle2D(4080, 3060, 800, 940)),
new WorldLocationInfo("an island north of Jhelom", new Rectangle2D(1030, 3330, 200, 400)),
new WorldLocationInfo("the island of Jhelom", new Rectangle2D(1230, 3600, 300, 330)),
new WorldLocationInfo("the island south of Jhelom", new Rectangle2D(1360, 3940, 200, 200)),
new WorldLocationInfo("the island of Jhelom", new Rectangle2D(1230, 3600, 300, 330)),
new WorldLocationInfo("somewhere on Dragon Island", new Rectangle2D(1020, 3080, 100, 150)),
new WorldLocationInfo("somewhere on Amoeba Island", new Rectangle2D(2100, 3870, 120, 150)),
new WorldLocationInfo("somewhere on Valor Island", new Rectangle2D(2380, 3870, 200, 200)),
new WorldLocationInfo("near bog of desolation", new Rectangle2D(1950, 920, 160, 195)),
new WorldLocationInfo("near compassion desert", new Rectangle2D(1800, 800, 242, 180)),
new WorldLocationInfo("a forest northeast of Yew", new Rectangle2D(636, 0, 914, 744)),
new WorldLocationInfo("a froest east of Yew", new Rectangle2D(506, 743, 756, 535)),
new WorldLocationInfo("a forest west of Britain", new Rectangle2D(106, 1280, 1252, 750)),
new WorldLocationInfo("a forest north of Britain", new Rectangle2D(1260, 0, 860, 1628)),
new WorldLocationInfo("a forest south of Britain", new Rectangle2D(1078, 1660, 582, 370)),
new WorldLocationInfo("a forest east of cove", new Rectangle2D(2210, 1030, 600, 240)),
new WorldLocationInfo("a forest north of Minoc", new Rectangle2D(2300, 0, 500, 370)),
new WorldLocationInfo("a forest east of Minoc", new Rectangle2D(2300, 370, 500, 230)),
new WorldLocationInfo("a forest near Minoc and Vesper", new Rectangle2D(2230, 520, 620, 510)),
new WorldLocationInfo("a forest north of Vesper", new Rectangle2D(2800, 0, 700, 832)),
new WorldLocationInfo("a forest outside of Skara Brae", new Rectangle2D(700, 2030, 560, 490)),
new WorldLocationInfo("a swamp west of Trinsic", new Rectangle2D(1070, 2720, 210, 350)),
new WorldLocationInfo("a forest north of Trinsic", new Rectangle2D(1260, 2030, 540, 600)),
new WorldLocationInfo("a jungle north of Trinsic", new Rectangle2D(1800, 2160, 400, 406)),
new WorldLocationInfo("a forest west of Trinsic", new Rectangle2D(770, 2630, 1089, 100)),
new WorldLocationInfo("a jungle west of Trinsic", new Rectangle2D(1070, 2720, 1167, 356)),
new WorldLocationInfo("a forest south of Trinsic", new Rectangle2D(1800, 2720, 188, 290)),
new WorldLocationInfo("a jungle south of Trinsic", new Rectangle2D(1070, 2820, 1174, 846)),
new WorldLocationInfo("an unknown island in the Lost Lands", new Rectangle2D(5840, 2440, 45, 60)),
new WorldLocationInfo("a frozen tundra of the Lost Lands", new Rectangle2D(5120, 2300, 500, 130),
new Rectangle2D(5700, 2300, 440, 260)),
new WorldLocationInfo("somewhere in the Lost Lands", new Rectangle2D(5120, 2300, 1020, 1800))
//new WorldLocationInfo("", new Rectangle2D()),
},
new WorldLocationInfo[] // Trammel
{
new WorldLocationInfo("an island southeast of Britain", new Rectangle2D(1620, 1900, 594, 150),
new Rectangle2D(1810, 2040, 200, 120),
new Rectangle2D(1980, 2040, 250, 380)),
new WorldLocationInfo("near Buccaneer's Den", new Rectangle2D(2560, 1900, 400, 500)),
new WorldLocationInfo("a jungle near Serpent's Hold", new Rectangle2D(2750, 3320, 340, 340)),
new WorldLocationInfo("a forest near New Haven", new Rectangle2D(3330, 2350, 500, 600)),
new WorldLocationInfo("a forest near Magincia", new Rectangle2D(3510, 2000, 310, 320)),
new WorldLocationInfo("a desert near Nujel'm", new Rectangle2D(3480, 1020, 350, 410)),
new WorldLocationInfo("the arctic island north of Moonglow", new Rectangle2D(3850, 160, 500, 600)),
new WorldLocationInfo("a forest near Moonglow", new Rectangle2D(4250, 780, 500, 800)),
new WorldLocationInfo("the isle of fire", new Rectangle2D(4080, 3060, 800, 940)),
new WorldLocationInfo("an island north of Jhelom", new Rectangle2D(1030, 3330, 200, 400)),
new WorldLocationInfo("the island of Jhelom", new Rectangle2D(1230, 3600, 300, 330)),
new WorldLocationInfo("the island south of Jhelom", new Rectangle2D(1360, 3940, 200, 200)),
new WorldLocationInfo("the island of Jhelom", new Rectangle2D(1230, 3600, 300, 330)),
new WorldLocationInfo("somewhere on Dragon Island", new Rectangle2D(1020, 3080, 100, 150)),
new WorldLocationInfo("somewhere on Amoeba Island", new Rectangle2D(2100, 3870, 120, 150)),
new WorldLocationInfo("somewhere on Valor Island", new Rectangle2D(2380, 3870, 200, 200)),
new WorldLocationInfo("near bog of desolation", new Rectangle2D(1950, 920, 160, 195)),
new WorldLocationInfo("near compassion desert", new Rectangle2D(1800, 800, 242, 180)),
new WorldLocationInfo("a forest northeast of Yew", new Rectangle2D(636, 0, 914, 744)),
new WorldLocationInfo("a froest east of Yew", new Rectangle2D(506, 743, 756, 535)),
new WorldLocationInfo("a forest west of Britain", new Rectangle2D(106, 1280, 1252, 750)),
new WorldLocationInfo("a forest north of Britain", new Rectangle2D(1260, 0, 860, 1628)),
new WorldLocationInfo("a forest south of Britain", new Rectangle2D(1078, 1660, 582, 370)),
new WorldLocationInfo("a forest east of cove", new Rectangle2D(2210, 1030, 600, 240)),
new WorldLocationInfo("a forest north of Minoc", new Rectangle2D(2300, 0, 500, 370)),
new WorldLocationInfo("a forest east of Minoc", new Rectangle2D(2300, 370, 500, 230)),
new WorldLocationInfo("a forest near Minoc and Vesper", new Rectangle2D(2230, 520, 620, 510)),
new WorldLocationInfo("a forest north of Vesper", new Rectangle2D(2800, 0, 700, 832)),
new WorldLocationInfo("a forest outside of Skara Brae", new Rectangle2D(700, 2030, 560, 490)),
new WorldLocationInfo("a swamp west of Trinsic", new Rectangle2D(1070, 2720, 210, 350)),
new WorldLocationInfo("a forest north of Trinsic", new Rectangle2D(1260, 2030, 540, 600)),
new WorldLocationInfo("a jungle north of Trinsic", new Rectangle2D(1800, 2160, 400, 406)),
new WorldLocationInfo("a forest west of Trinsic", new Rectangle2D(770, 2630, 1089, 100)),
new WorldLocationInfo("a jungle west of Trinsic", new Rectangle2D(1070, 2720, 1167, 356)),
new WorldLocationInfo("a forest south of Trinsic", new Rectangle2D(1800, 2720, 188, 290)),
new WorldLocationInfo("a jungle south of Trinsic", new Rectangle2D(1070, 2820, 1174, 846)),
new WorldLocationInfo("an unknown island in the Lost Lands", new Rectangle2D(5840, 2440, 45, 60)),
new WorldLocationInfo("a frozen tundra of the Lost Lands", new Rectangle2D(5120, 2300, 500, 130),
new Rectangle2D(5700, 2300, 440, 260)),
new WorldLocationInfo("somewhere in the Lost Lands", new Rectangle2D(5120, 2300, 1020, 1800))
},
new WorldLocationInfo[] // Ilshenar
{
new WorldLocationInfo("somewhere in Ilshenar", new Rectangle2D(0, 0, 2300, 1598))
},
new WorldLocationInfo[] // Malas
{
new WorldLocationInfo("somewhere in Malas", new Rectangle2D(0, 0, 2558, 2046))
},
new WorldLocationInfo[] // Tokuno
{
new WorldLocationInfo("somewhere in Tokuno", new Rectangle2D(0, 0, 1446, 1446))
},
new WorldLocationInfo[] // TerMur
{
new WorldLocationInfo("somewhere in TerMur", new Rectangle2D(270, 2754, 1000, 1339))
},
};
public static string GetLocationString(IEntity e)
{
return GetLocationString(e.Location, e.Map);
}
public static string GetLocationString(Point3D p, Map map)
{
Region r = Region.Find(p, map);
if (r.Name != null && r is TownRegion)
{
return string.Format("somewhere near {0}.", r.Name);
}
else if (r.Name != null && r is DungeonRegion)
{
return string.Format("somewhere in dungeon {0}.", r.Name);
}
int mapID = map.MapID;
if (mapID < 0 || mapID > m_Locations.Length)
return "an unknown location";
WorldLocationInfo[] infos = m_Locations[mapID];
foreach (WorldLocationInfo info in infos)
{
foreach (Rectangle2D rec in info.m_Bounds)
{
if (rec.Contains(p))
return info.m_RegionName;
}
}
return "an unknown location";
}
public static void GetLocation_OnCommand(CommandEventArgs e)
{
e.Mobile.SendMessage(GetLocationString(e.Mobile.Location, e.Mobile.Map));
}
}
}