using System;
using System.IO;
using System.Text.RegularExpressions;
using Decal.Adapter;
using Decal.Adapter.Wrappers;
using Decal.Filters;
namespace Mag.Shared
{
public static class Util
{
public static CoordsObject GetCoords(int landBlock, double x, double y)
{
int ilbLng = (int)(Math.Floor(landBlock / (double)(0x1000000))) & 0xFF;
int ilbLat = (int)(Math.Floor(landBlock / (double)(0x10000))) & 0xFF;
double latOut = ((double)(ilbLat - 0x7F) * 192 + y - 84) / 240;
double lngOut = ((double)(ilbLng - 0x7F) * 192 + x - 84) / 240;
return new CoordsObject(latOut, lngOut);
}
///
/// This function will return the distance in meters.
/// The manual distance units are in map compass units, while the distance units used in the UI are meters.
/// In AC there are 240 meters in a kilometer; thus if you set your attack range to 1 in the UI it
/// will showas 0.00416666666666667in the manual options (0.00416666666666667 being 1/240).
///
///
///
///
/// Object passed with an Id of 0
public static double GetDistance(WorldObject obj1, WorldObject obj2)
{
if (obj1.Id == 0)
throw new ArgumentOutOfRangeException("obj1", "Object passed with an Id of 0");
if (obj2.Id == 0)
throw new ArgumentOutOfRangeException("obj2", "Object passed with an Id of 0");
return CoreManager.Current.WorldFilter.Distance(obj1.Id, obj2.Id) * 240;
}
///
/// This function will return the distance in meters.
/// The manual distance units are in map compass units, while the distance units used in the UI are meters.
/// In AC there are 240 meters in a kilometer; thus if you set your attack range to 1 in the UI it
/// will showas 0.00416666666666667in the manual options (0.00416666666666667 being 1/240).
///
///
///
/// CharacterFilder.Id or Object passed with an Id of 0
public static double GetDistanceFromPlayer(WorldObject destObj)
{
if (CoreManager.Current.CharacterFilter.Id == 0)
throw new ArgumentOutOfRangeException("destObj", "CharacterFilter.Id of 0");
if (destObj.Id == 0)
throw new ArgumentOutOfRangeException("destObj", "Object passed with an Id of 0");
return CoreManager.Current.WorldFilter.Distance(CoreManager.Current.CharacterFilter.Id, destObj.Id) * 240;
}
///
/// Gets the closest object found of the specified object class. If no object is found, null is returned.
///
///
public static WorldObject GetClosestObject(ObjectClass objectClass)
{
WorldObject closest = null;
foreach (WorldObject obj in CoreManager.Current.WorldFilter.GetLandscape())
{
if (obj.ObjectClass != objectClass)
continue;
if (closest == null || GetDistanceFromPlayer(obj) < GetDistanceFromPlayer(closest))
closest = obj;
}
return closest;
}
public static WorldObject GetClosestObject(string objectName, bool partialMatch = false)
{
WorldObject closest = null;
foreach (WorldObject obj in CoreManager.Current.WorldFilter.GetLandscape())
{
if (!partialMatch && String.Compare(obj.Name, objectName, StringComparison.OrdinalIgnoreCase) != 0)
continue;
if (partialMatch && !obj.Name.ToLower().Contains(objectName.ToLower()))
continue;
if (closest == null || GetDistanceFromPlayer(obj) < GetDistanceFromPlayer(closest))
closest = obj;
}
return closest;
}
///
///
///
///
///
///
public static int GetFreePackSlots(int container)
{
if (container == 0)
throw new ArgumentOutOfRangeException("container", "Invalid container passed, id of 0.");
WorldObject target = CoreManager.Current.WorldFilter[container];
if (target == null || (target.ObjectClass != ObjectClass.Player && target.ObjectClass != ObjectClass.Container))
throw new ArgumentOutOfRangeException("container", "Invalid container passed, null reference");
int slotsFilled = 0;
foreach (WorldObject obj in CoreManager.Current.WorldFilter.GetByContainer(container))
{
if (obj.ObjectClass == ObjectClass.Container || obj.ObjectClass == ObjectClass.Foci || obj.Values(LongValueKey.EquippedSlots) != 0)
continue;
slotsFilled++;
}
return CoreManager.Current.WorldFilter[container].Values(LongValueKey.ItemSlots) - slotsFilled;
}
// http://www.regular-expressions.info/reference.html
// Local Chat
// You say, "test"
private static readonly Regex YouSay = new Regex("^You say, \"(?.*)\"$");
// PlayerName<\Tell> says, "asdf"
private static readonly Regex PlayerSaysLocal = new Regex("^[\\w\\s'-]+)>[\\w\\s'-]+<\\\\Tell> says, \"(?.*)\"$");
//
// Master Arbitrator says, "Arena Three is now available for new warriors!"
private static readonly Regex NpcSays = new Regex("^(?[\\w\\s'-]+) says, \"(?.*)\"$");
// Channel Chat
// [Allegiance] PlayerName<\Tell> says, "kk"
// [General] PlayerName<\Tell> says, "asdfasdfasdf"
// [Fellowship] PlayerName<\Tell> says, "test"
private static readonly Regex PlayerSaysChannel = new Regex("^\\[(?.+)]+ [\\w\\s'-]+)>[\\w\\s'-]+<\\\\Tell> says, \"(?.*)\"$");
//
// [Fellowship] Master Arbitrator<\Tell> says, "Good Luck!"
// Tells
// You tell PlayerName, "test"
private static readonly Regex YouTell = new Regex("^You tell .+, \"(?.*)\"$");
// PlayerName<\Tell> tells you, "test"
private static readonly Regex PlayerTellsYou = new Regex("^[\\w\\s'-]+)>[\\w\\s'-]+<\\\\Tell> tells you, \"(?.*)\"$");
//
// Master Arbitrator tells you, "You fought in the Colosseum's Arenas too recently. I cannot reward you for 4s."
private static readonly Regex NpcTellsYou = new Regex("^(?[\\w\\s'-]+) tells you, \"(?.*)\"$");
[Flags]
public enum ChatFlags : byte
{
None = 0x00,
PlayerSaysLocal = 0x01,
PlayerSaysChannel = 0x02,
YouSay = 0x04,
PlayerTellsYou = 0x08,
YouTell = 0x10,
NpcSays = 0x20,
NpcTellsYou = 0x40,
All = 0xFF,
}
///
/// Returns true if the text was said by a person, envoy, npc, monster, etc..
///
///
///
///
public static bool IsChat(string text, ChatFlags chatFlags = ChatFlags.All)
{
if ((chatFlags & ChatFlags.PlayerSaysLocal) == ChatFlags.PlayerSaysLocal && PlayerSaysLocal.IsMatch(text))
return true;
if ((chatFlags & ChatFlags.PlayerSaysChannel) == ChatFlags.PlayerSaysChannel && PlayerSaysChannel.IsMatch(text))
return true;
if ((chatFlags & ChatFlags.YouSay) == ChatFlags.YouSay && YouSay.IsMatch(text))
return true;
if ((chatFlags & ChatFlags.PlayerTellsYou) == ChatFlags.PlayerTellsYou && PlayerTellsYou.IsMatch(text))
return true;
if ((chatFlags & ChatFlags.YouTell) == ChatFlags.YouTell && YouTell.IsMatch(text))
return true;
if ((chatFlags & ChatFlags.NpcSays) == ChatFlags.NpcSays && NpcSays.IsMatch(text))
return true;
if ((chatFlags & ChatFlags.NpcTellsYou) == ChatFlags.NpcTellsYou && NpcTellsYou.IsMatch(text))
return true;
return false;
}
///
/// This will return the name of the person/monster/npc of a chat message or tell.
///
///
///
public static string GetSourceOfChat(string text)
{
bool isSays = IsChat(text, ChatFlags.NpcSays | ChatFlags.PlayerSaysChannel | ChatFlags.PlayerSaysLocal);
bool isTell = IsChat(text, ChatFlags.NpcTellsYou | ChatFlags.PlayerTellsYou);
if (isSays && isTell)
{
int indexOfSays = text.IndexOf(" says, \"", StringComparison.Ordinal);
int indexOfTell = text.IndexOf(" tells you", StringComparison.Ordinal);
if (indexOfSays <= indexOfTell)
isTell = false;
else
isSays = false;
}
string source = string.Empty;
if (isSays)
source = text.Substring(0, text.IndexOf(" says, \"", StringComparison.Ordinal));
else if (isTell)
source = text.Substring(0, text.IndexOf(" tells you", StringComparison.Ordinal));
else
return source;
source = source.Trim();
if (source.Contains(">") && source.Contains("<"))
{
source = source.Remove(0, source.IndexOf('>') + 1);
if (source.Contains("<"))
source = source.Substring(0, source.IndexOf('<'));
}
return source;
}
[Flags]
public enum ChatChannels : ushort
{
None = 0x0000,
Area = 0x0001,
Tells = 0x0002,
Fellowship = 0x0004,
Allegiance = 0x0008,
General = 0x0010,
Trade = 0x0020,
LFG = 0x0040,
Roleplay = 0x0080,
Society = 0x0100,
All = 0xFFFF,
}
public static ChatChannels GetChatChannel(string text)
{
if (IsChat(text, ChatFlags.PlayerSaysLocal | ChatFlags.YouSay | ChatFlags.NpcSays))
return ChatChannels.Area;
if (IsChat(text, ChatFlags.PlayerTellsYou | ChatFlags.YouTell | ChatFlags.NpcTellsYou))
return ChatChannels.Tells;
if (IsChat(text, ChatFlags.PlayerSaysChannel))
{
Match match = PlayerSaysChannel.Match(text);
if (match.Success)
{
string channel = match.Groups["channel"].Value;
if (channel == "Fellowship") return ChatChannels.Fellowship;
if (channel == "Allegiance") return ChatChannels.Allegiance;
if (channel == "General") return ChatChannels.General;
if (channel == "Trade") return ChatChannels.Trade;
if (channel == "LFG") return ChatChannels.LFG;
if (channel == "Roleplay") return ChatChannels.Roleplay;
if (channel == "Society") return ChatChannels.Society;
}
}
return ChatChannels.None;
}
///
/// Converts a message of:
/// [Allegiance] <Tell:IIDString:0:PlayerName>PlayerName<\Tell> says, "kk"
/// to:
/// [Allegiance] PlayerName says, "kk"
///
///
///
public static string CleanMessage(string text)
{
string output = text;
int ltIndex = output.IndexOf('<');
int gtIndex = output.IndexOf('>');
int cIndex = output.IndexOf(',');
if (ltIndex != -1 && ltIndex < gtIndex && gtIndex < cIndex)
output = output.Substring(0, ltIndex) + output.Substring(gtIndex + 1, output.Length - gtIndex - 1);
ltIndex = output.IndexOf('<');
gtIndex = output.IndexOf('>');
cIndex = output.IndexOf(',');
if (ltIndex != -1 && ltIndex < gtIndex && gtIndex < cIndex)
output = output.Substring(0, ltIndex) + output.Substring(gtIndex + 1, output.Length - gtIndex - 1);
return output;
}
// You say, "Zojak ...."
private static readonly Regex YouSaySpellCast = new Regex("^You say, \"(Zojak|Malar|Puish|Cruath|Volae|Quavosh|Shurov|Boquar|Helkas|Equin|Roiga|Malar|Jevak|Tugak|Slavu|Drostu|Traku|Yanoi|Drosta|Feazh) .*\"$");
// Player says, "Zojak ...."
private static readonly Regex PlayerSaysSpellCast = new Regex("^[\\w\\s'-]+)>[\\w\\s'-]+<\\\\Tell> says, \"(Zojak|Malar|Puish|Cruath|Volae|Quavosh|Shurov|Boquar|Helkas|Equin|Roiga|Malar|Jevak|Tugak|Slavu|Drostu|Traku|Yanoi|Drosta|Feazh) .*\"$");
///
/// Returns true for messages that are like:
/// You say, "Zojak....
/// or
/// Somebody says, "Zojak...
///
///
///
///
///
public static bool IsSpellCastingMessage(string text, bool isMine = true, bool isPlayer = true)
{
if (isMine && YouSaySpellCast.IsMatch(text))
return true;
if (isPlayer && PlayerSaysSpellCast.IsMatch(text))
return true;
return false;
}
public static void ExportSpells(string targetFileName)
{
using (StreamWriter writer = new StreamWriter(targetFileName, true))
{
writer.WriteLine("Id,Name,Description,Difficulty,Duration,Family,Flags,Generation,IconId,IsDebuff,IsFastWindup,IsFellowship,IsIrresistible,IsOffensive,IsUntargetted,Mana,School,SortKey,Speed,TargetEffect,TargetMask,Type,Unknown1,Unknown2,Unknown3,Unknown4,Unknown5,Unknown6,Unknown7,Unknown8,Unknown9,Unknown10");
FileService service = CoreManager.Current.Filter();
for (int i = 0 ; i < service.SpellTable.Length ; i++)
{
Spell spell = service.SpellTable[i];
string flags = "";
flags += ((spell.Flags & 0x80000) == 0x80000) ? "1" : "0";
flags += ((spell.Flags & 0x40000) == 0x40000) ? "1" : "0";
flags += ((spell.Flags & 0x20000) == 0x20000) ? "1" : "0";
flags += ((spell.Flags & 0x10000) == 0x10000) ? "1" : "0";
flags += ((spell.Flags & 0x8000) == 0x8000) ? "1" : "0";
flags += ((spell.Flags & 0x4000) == 0x4000) ? "1" : "0";
flags += ((spell.Flags & 0x2000) == 0x2000) ? "1" : "0";
flags += ((spell.Flags & 0x1000) == 0x1000) ? "1" : "0";
flags += ((spell.Flags & 0x800) == 0x800) ? "1" : "0";
flags += ((spell.Flags & 0x400) == 0x400) ? "1" : "0";
flags += ((spell.Flags & 0x200) == 0x200) ? "1" : "0";
flags += ((spell.Flags & 0x100) == 0x100) ? "1" : "0";
flags += ((spell.Flags & 0x80) == 0x80) ? "1" : "0";
flags += ((spell.Flags & 0x40) == 0x40) ? "1" : "0";
flags += ((spell.Flags & 0x20) == 0x20) ? "1" : "0";
flags += ((spell.Flags & 0x10) == 0x10) ? "1" : "0";
flags += ((spell.Flags & 0x8) == 0x8) ? "1" : "0";
flags += ((spell.Flags & 0x4) == 0x4) ? "1" : "0";
flags += ((spell.Flags & 0x2) == 0x2) ? "1" : "0";
flags += ((spell.Flags & 0x1) == 0x1) ? "1" : "0";
writer.WriteLine(spell.Id + "," + spell.Name.Replace(",", ".") + "," + spell.Description.Replace(",", ".") + "," + spell.Difficulty + "," + spell.Duration + "," + spell.Family + "," + flags + "," + spell.Generation + "," + spell.IconId + "," + spell.IsDebuff + "," + spell.IsFastWindup + "," + spell.IsFellowship + "," + spell.IsIrresistible + "," + spell.IsOffensive + "," + spell.IsUntargetted + "," + spell.Mana + "," + spell.School + "," + spell.SortKey + "," + spell.Speed + "," + spell.TargetEffect + "," + spell.TargetMask + "," + spell.Type + "," + spell.Unknown1 + "," + spell.Unknown2 + "," + spell.Unknown3 + "," + spell.Unknown4 + "," + spell.Unknown5 + "," + spell.Unknown6 + "," + spell.Unknown7 + "," + spell.Unknown8 + "," + spell.Unknown9 + "," + spell.Unknown10);
}
writer.Close();
}
}
public static string NumberFormatter(long number, string format, int largestViewableNumber, string reducedFormat = "#,##0")
{
if (number <= largestViewableNumber)
return number.ToString(format);
int spaces = largestViewableNumber.ToString(format).Length;
if (((float)number / 1000).ToString(reducedFormat).Length <= spaces)
return ((float)number / 1000).ToString(reducedFormat) + "k"; // thousand
if (((float)number / 1000000).ToString(reducedFormat).Length <= spaces)
return ((float)number / 1000000).ToString(reducedFormat) + "M"; // million
return ((float)number / 1000000000).ToString(reducedFormat) + "G"; // billion
}
}
}