Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
3533
Scripts/Misc/AOS.cs
Normal file
3533
Scripts/Misc/AOS.cs
Normal file
File diff suppressed because it is too large
Load Diff
41
Scripts/Misc/AccountPrompt.cs
Normal file
41
Scripts/Misc/AccountPrompt.cs
Normal 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
152
Scripts/Misc/Aggression.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Scripts/Misc/Animations.cs
Normal file
44
Scripts/Misc/Animations.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
284
Scripts/Misc/ArchivedSaves.cs
Normal file
284
Scripts/Misc/ArchivedSaves.cs
Normal 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
145
Scripts/Misc/AutoRestart.cs
Normal 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
182
Scripts/Misc/AutoSave.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Scripts/Misc/Broadcasts.cs
Normal file
35
Scripts/Misc/Broadcasts.cs
Normal 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
498
Scripts/Misc/BuffIcons.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
1457
Scripts/Misc/CharacterCreation.cs
Normal file
1457
Scripts/Misc/CharacterCreation.cs
Normal file
File diff suppressed because it is too large
Load Diff
176
Scripts/Misc/Cleanup.cs
Normal file
176
Scripts/Misc/Cleanup.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
242
Scripts/Misc/ClientVerification.cs
Normal file
242
Scripts/Misc/ClientVerification.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
526
Scripts/Misc/ConsoleCommands.cs
Normal file
526
Scripts/Misc/ConsoleCommands.cs
Normal 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
268
Scripts/Misc/CrashGuard.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Scripts/Misc/CurrentExpansion.cs
Normal file
50
Scripts/Misc/CurrentExpansion.cs
Normal 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
118
Scripts/Misc/DataPath.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Scripts/Misc/DispellableAttribute.cs
Normal file
9
Scripts/Misc/DispellableAttribute.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Misc
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class DispellableAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
9
Scripts/Misc/DispellableFieldAttribute.cs
Normal file
9
Scripts/Misc/DispellableFieldAttribute.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Misc
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class DispellableFieldAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
92
Scripts/Misc/Email.cs
Normal file
92
Scripts/Misc/Email.cs
Normal 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
713
Scripts/Misc/Emitter.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Scripts/Misc/EquipLastWeapon.cs
Normal file
48
Scripts/Misc/EquipLastWeapon.cs
Normal 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
32
Scripts/Misc/Fastwalk.cs
Normal 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
45
Scripts/Misc/FoodDecay.cs
Normal 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
240
Scripts/Misc/Geometry.cs
Normal 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
2014
Scripts/Misc/Guild.cs
Normal file
File diff suppressed because it is too large
Load Diff
206
Scripts/Misc/HardwareInfo.cs
Normal file
206
Scripts/Misc/HardwareInfo.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/Misc/IDynamicEnum.cs
Normal file
11
Scripts/Misc/IDynamicEnum.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public interface IDynamicEnum
|
||||
{
|
||||
String Value { get; set; }
|
||||
String[] Values { get; }
|
||||
Boolean IsValid { get; }
|
||||
}
|
||||
}
|
||||
606
Scripts/Misc/InhumanSpeech.cs
Normal file
606
Scripts/Misc/InhumanSpeech.cs
Normal 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
67
Scripts/Misc/Keywords.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
406
Scripts/Misc/LanguageStatistics.cs
Normal file
406
Scripts/Misc/LanguageStatistics.cs
Normal 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
157
Scripts/Misc/LightCycle.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Scripts/Misc/LoginStats.cs
Normal file
39
Scripts/Misc/LoginStats.cs
Normal 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
1084
Scripts/Misc/Loot.cs
Normal file
File diff suppressed because it is too large
Load Diff
1140
Scripts/Misc/LootPack.cs
Normal file
1140
Scripts/Misc/LootPack.cs
Normal file
File diff suppressed because it is too large
Load Diff
72
Scripts/Misc/MapDefinitions.cs
Normal file
72
Scripts/Misc/MapDefinitions.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Scripts/Misc/MessageHelper.cs
Normal file
18
Scripts/Misc/MessageHelper.cs
Normal 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
116
Scripts/Misc/NameList.cs
Normal 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
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
213
Scripts/Misc/NameVerification.cs
Normal file
213
Scripts/Misc/NameVerification.cs
Normal 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
569
Scripts/Misc/Notoriety.cs
Normal 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
32
Scripts/Misc/Paperdoll.cs
Normal 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
283
Scripts/Misc/Poison.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
142
Scripts/Misc/ProfanityProtection.cs
Normal file
142
Scripts/Misc/ProfanityProtection.cs
Normal 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
103
Scripts/Misc/Profile.cs
Normal 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 "";
|
||||
}
|
||||
}
|
||||
}
|
||||
169
Scripts/Misc/ProtocolExtensions.cs
Normal file
169
Scripts/Misc/ProtocolExtensions.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
430
Scripts/Misc/RaceDefinitions.cs
Normal file
430
Scripts/Misc/RaceDefinitions.cs
Normal 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
315
Scripts/Misc/RegenRates.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Scripts/Misc/RenameRequests.cs
Normal file
60
Scripts/Misc/RenameRequests.cs
Normal 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
63
Scripts/Misc/Replacer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
979
Scripts/Misc/ResourceInfo.cs
Normal file
979
Scripts/Misc/ResourceInfo.cs
Normal 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
263
Scripts/Misc/ServerList.cs
Normal 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
699
Scripts/Misc/ShardPoller.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
84
Scripts/Misc/ShrinkTable.cs
Normal file
84
Scripts/Misc/ShrinkTable.cs
Normal 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
496
Scripts/Misc/Siege.cs
Normal 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
808
Scripts/Misc/SkillCheck.cs
Normal 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}
|
||||
};
|
||||
}
|
||||
}
|
||||
42
Scripts/Misc/SocketOptions.cs
Normal file
42
Scripts/Misc/SocketOptions.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
1623
Scripts/Misc/SpawnerPersistence.cs
Normal file
1623
Scripts/Misc/SpawnerPersistence.cs
Normal file
File diff suppressed because it is too large
Load Diff
27
Scripts/Misc/TaskPollingTimer.cs
Normal file
27
Scripts/Misc/TaskPollingTimer.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
209
Scripts/Misc/TextDefinition.cs
Normal file
209
Scripts/Misc/TextDefinition.cs
Normal 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
66
Scripts/Misc/Timestamp.cs
Normal 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
541
Scripts/Misc/Titles.cs
Normal 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
144
Scripts/Misc/ToggleItem.cs
Normal 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Scripts/Misc/UntamedPetsCleaning.cs
Normal file
33
Scripts/Misc/UntamedPetsCleaning.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Scripts/Misc/ValidationQueue.cs
Normal file
54
Scripts/Misc/ValidationQueue.cs
Normal 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
214
Scripts/Misc/Waypoints.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
236
Scripts/Misc/WeakEntityCollection.cs
Normal file
236
Scripts/Misc/WeakEntityCollection.cs
Normal 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
474
Scripts/Misc/Weather.cs
Normal 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
194
Scripts/Misc/WebStatus.cs
Normal 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("&", "&");
|
||||
sb.Replace("<", "<");
|
||||
sb.Replace(">", ">");
|
||||
sb.Replace("\"", """);
|
||||
sb.Replace("'", "'");
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Scripts/Misc/WeightOverloading.cs
Normal file
130
Scripts/Misc/WeightOverloading.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Scripts/Misc/WelcomeTimer.cs
Normal file
59
Scripts/Misc/WelcomeTimer.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
213
Scripts/Misc/WorldLocationInfo.cs
Normal file
213
Scripts/Misc/WorldLocationInfo.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user