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 } } }