diff --git a/FastColoredTextBox/SyntaxHighlighter.cs b/FastColoredTextBox/SyntaxHighlighter.cs index eab77164..032b3e82 100644 --- a/FastColoredTextBox/SyntaxHighlighter.cs +++ b/FastColoredTextBox/SyntaxHighlighter.cs @@ -360,17 +360,17 @@ protected void InitRazorRegex() RazorCommandRegex = new Regex( - @"\b(attack|cast|dress|undress|dressconfig|target|targettype|targetloc|targetrelloc|dress|drop|waitfortarget|wft|dclick|dclicktype|dclickvar|usetype|useobject|droprelloc|lift|lifttype|waitforgump|gumpresponse|gumpclose|menu|menuresponse|waitformenu|promptresponse|waitforprompt|hotkey|say|msg|overhead|sysmsg|wait|pause|waitforstat|setability|setlasttarget|lasttarget|setvar|skill|useskill|walk|script|useonce|organizer|organize|org|restock|scav|scavenger|potion|clearsysmsg|clearjournal|whisper|yell|guild|alliance|emote|waitforsysmsg|wfsysmsg|clearall|virtue)\b", + @"\b(attack|cast|dress|undress|dressconfig|target|targettype|targetloc|targetrelloc|dress|drop|waitfortarget|wft|dclick|dclicktype|dclickvar|usetype|useobject|droprelloc|lift|lifttype|waitforgump|gumpresponse|gumpclose|menu|menuresponse|waitformenu|promptresponse|waitforprompt|hotkey|say|msg|overhead|sysmsg|wait|pause|waitforstat|setability|setlasttarget|lasttarget|setvar|skill|useskill|walk|script|useonce|organizer|organize|org|restock|scav|scavenger|potion|clearsysmsg|clearjournal|whisper|yell|guild|alliance|emote|waitforsysmsg|wfsysmsg|clearall|virtue|rename|setskill|ignore|clearignore|poplist|pushlist|removelist|createlist|clearlist|settimer|removetimer|createtimer|settimer|removetimer|getlabel|unsetvar)\b", RegexCompiledOption); - RazorLayerRegex = + RazorLayerRegex = new Regex( @"\b(RightHand|LeftHand|Shoes|Pants|Shirt|Head|Gloves|Ring|Talisman|Neck|Hair|Waist|InnerTorso|Bracelet|FacialHair|MiddleTorso|Earrings|Arms|Cloak|Backpack|OuterTorso|OuterLegs|InnerLegs|backpack|true|false|criminal|enemy|friend|friendly|grey|gray|innocent|murderer|red|blue|nonfriendly|cancel|clear)\b", RegexCompiledOption); RazorExpressionRegex = new Regex( - @"\b(queued|position|insysmsg|insysmessage|findtype|findbuff|finddebuff|stam|maxstam|hp|maxhp|maxhits|hits|mana|maxmana|str|dex|int|poisoned|hidden|mounted|rhandempty|lhandempty|skill|count|counter|weight|dead|closest|close|rand|random|next|prev|previous|human|humanoid|monster)\b", + @"\b(queued|position|insysmsg|insysmessage|findtype|findbuff|finddebuff|stam|maxstam|hp|maxhp|maxhits|hits|mana|maxmana|str|dex|int|poisoned|hidden|mounted|rhandempty|lhandempty|skill|count|counter|weight|dead|closest|close|rand|random|next|prev|previous|human|humanoid|monster|findlayer|dead|find|counttype|listexists|list|inlist|timer|timerexists|followers|hue|name|maxweight|diffweight|diffhits|diffstam|diffmana|paralyzed|invul|noto|dead|gumpexists|ingump|targetexists|counttype)\b", RegexCompiledOption); } diff --git a/Razor/Agents/BuyAgent.cs b/Razor/Agents/BuyAgent.cs index 294d0021..63a3f9a4 100644 --- a/Razor/Agents/BuyAgent.cs +++ b/Razor/Agents/BuyAgent.cs @@ -29,6 +29,9 @@ namespace Assistant.Agents { public class BuyAgent : Agent { + // For Outlands user don not have to have money in backpack + private static bool EnableGoldCheck = false; + public class BuyEntry { public BuyEntry(ushort id, ushort amount) @@ -136,14 +139,11 @@ private static void DisplayBuy(PacketReader p, PacketHandlerEventArgs args) { return; } - - pack.Contains.Sort(ItemXYComparer.Instance); - + int total = 0; int cost = 0; List buyList = new List(); Dictionary found = new Dictionary(); - bool lowGoldWarn = false; for (int i = 0; i < pack.Contains.Count; i++) { Item item = (Item) pack.Contains[i]; @@ -221,9 +221,8 @@ private static void DisplayBuy(PacketReader p, PacketHandlerEventArgs args) } } - if (cost > World.Player.Gold && cost < 2000 && buyList.Count > 0) + if (cost > World.Player.Gold && cost > 2000 && buyList.Count > 0 && !EnableGoldCheck) { - lowGoldWarn = true; do { VendorBuyItem vbi = (VendorBuyItem) buyList[0]; @@ -250,18 +249,14 @@ private static void DisplayBuy(PacketReader p, PacketHandlerEventArgs args) } while (cost > World.Player.Gold && buyList.Count > 0); } - if (buyList.Count > 0) - { - args.Block = true; - BuyLists[serial] = buyList; - Client.Instance.SendToServer(new VendorBuyResponse(serial, buyList)); - World.Player.SendMessage(MsgLevel.Force, LocString.BuyTotals, total, cost); - } + if (buyList.Count <= 0) + return; + + args.Block = true; + BuyLists[serial] = buyList; + Client.Instance.SendToServer(new VendorBuyResponse(serial, buyList)); + World.Player.SendMessage(MsgLevel.Force, LocString.BuyTotals, total, cost); - if (lowGoldWarn) - { - World.Player.SendMessage(MsgLevel.Force, LocString.BuyLowGold); - } } private static readonly Dictionary> BuyLists = new Dictionary>(); @@ -281,7 +276,6 @@ private static void ExtBuyInfo(PacketReader p, PacketHandlerEventArgs args) "Buy Agent Warning: Contains Count {0} does not match ExtInfo {1}.", pack.Contains.Count, count); } - pack.Contains.Sort(ItemXYComparer.Instance); for (int i = count - 1; i >= 0; i--) { @@ -471,7 +465,7 @@ public void Add(BuyEntry entry) { m_Items?.Add(entry); - m_SubList?.Items.Add(entry); + Engine.MainWindow.SafeAction(_ => m_SubList?.Items.Add(entry)); World.Player?.SendMessage(MsgLevel.Force, LocString.ItemAdded); } diff --git a/Razor/Agents/IgnoreAgent.cs b/Razor/Agents/IgnoreAgent.cs index 281a1a69..bcd1e934 100644 --- a/Razor/Agents/IgnoreAgent.cs +++ b/Razor/Agents/IgnoreAgent.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.Windows.Forms; using System.Xml; +using Assistant.Core; using Assistant.UI; namespace Assistant.Agents @@ -33,6 +34,21 @@ public class IgnoreAgent : Agent public static void Initialize() { Agent.Add(Instance = new IgnoreAgent()); + + MessageManager.OnMobileMessage += HandleMobileMessage; + } + + public static void HandleMobileMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string text) + { + if (Instance == null) + return; + + if (Instance.IsSerialIgnored(source)) + { + args.Block = true; + } } public static bool IsIgnored(Serial ser) @@ -55,8 +71,6 @@ public IgnoreAgent() HotKey.Add(HKCategory.Targets, LocString.AddToIgnore, new HotKeyCallback(AddToIgnoreList)); HotKey.Add(HKCategory.Targets, LocString.RemoveFromIgnore, new HotKeyCallback(RemoveFromIgnoreList)); - - Agent.OnMobileCreated += new MobileCreatedEventHandler(OPLCheckIgnore); } public override void Clear() @@ -167,18 +181,6 @@ public override void OnButtonPress(int num) if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { - foreach (Serial s in m_Chars) - { - Mobile m = World.FindMobile(s); - if (m != null) - { - if (m.ObjPropList.Remove(Language.GetString(LocString.RazorIgnored))) - { - m.OPLChanged(); - } - } - } - m_Chars.Clear(); m_SubList.Items.Clear(); } @@ -195,14 +197,6 @@ public override void OnButtonPress(int num) } } - private void OPLCheckIgnore(Mobile m) - { - if (IsIgnored(m.Serial)) - { - m.ObjPropList.Add(Language.GetString(LocString.RazorIgnored)); - } - } - private void OnAddTarget(bool location, Serial serial, Point3D loc, ushort gfx) { Engine.MainWindow.SafeAction(s => s.ShowMe()); @@ -215,13 +209,6 @@ private void OnAddTarget(bool location, Serial serial, Point3D loc, ushort gfx) m_Chars.Add(serial); Add2List(serial); - - Mobile m = World.FindMobile(serial); - if (m != null) - { - m.ObjPropList.Add(Language.GetString(LocString.RazorIgnored)); - m.OPLChanged(); - } } } } @@ -273,15 +260,6 @@ private void OnRemoveTarget(bool location, Serial serial, Point3D loc, ushort gf } m_SubList.EndUpdate(); - - Mobile m = World.FindMobile(serial); - if (m != null) - { - if (m.ObjPropList.Remove(Language.GetString(LocString.RazorIgnored))) - { - m.OPLChanged(); - } - } } } diff --git a/Razor/Agents/OrganizerAgent.cs b/Razor/Agents/OrganizerAgent.cs index 2674d2d2..fd7ee965 100644 --- a/Razor/Agents/OrganizerAgent.cs +++ b/Razor/Agents/OrganizerAgent.cs @@ -65,16 +65,6 @@ public OrganizerAgent(int num) $"{Language.GetString(LocString.SetOrganizerHB)}-{Number:D2}", new HotKeyCallback(SetHotBag)); PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnSingleClick)); - - Agent.OnItemCreated += new ItemCreatedEventHandler(CheckContOPL); - } - - public void CheckContOPL(Item item) - { - if (item.Serial == m_Cont) - { - item.ObjPropList.Add(Language.Format(LocString.OrganizerHBA1, Number)); - } } private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args) @@ -170,13 +160,6 @@ public override void OnButtonPress(int num) if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { - Item bag = World.FindItem(m_Cont); - if (bag != null) - { - bag.ObjPropList.Remove(Language.Format(LocString.OrganizerHBA1, Number)); - bag.OPLChanged(); - } - m_SubList.Items.Clear(); m_Items.Clear(); m_Cont = 0; @@ -305,13 +288,6 @@ private void OnTargetBag(bool location, Serial serial, Point3D loc, ushort gfx) if (!location && serial > 0 && serial <= 0x7FFFFF00) { - Item bag = World.FindItem(m_Cont); - if (bag != null && bag.ObjPropList != null) - { - bag.ObjPropList.Remove(Language.Format(LocString.OrganizerHBA1, Number)); - bag.OPLChanged(); - } - m_Cont = serial; if (m_BagBTN != null) { @@ -322,13 +298,6 @@ private void OnTargetBag(bool location, Serial serial, Point3D loc, ushort gfx) { World.Player.SendMessage(MsgLevel.Force, LocString.ContSet); } - - bag = World.FindItem(m_Cont); - if (bag != null && bag.ObjPropList != null) - { - bag.ObjPropList.Add(Language.Format(LocString.OrganizerHBA1, Number)); - bag.OPLChanged(); - } } } diff --git a/Razor/Agents/RestockAgent.cs b/Razor/Agents/RestockAgent.cs index 1d915942..922b07b6 100644 --- a/Razor/Agents/RestockAgent.cs +++ b/Razor/Agents/RestockAgent.cs @@ -65,16 +65,6 @@ public RestockAgent(int num) $"{Language.GetString(LocString.SetRestockHB)}-{Number:D2}", new HotKeyCallback(SetHB)); PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnSingleClick)); - - Agent.OnItemCreated += new ItemCreatedEventHandler(CheckHBOPL); - } - - public void CheckHBOPL(Item item) - { - if (item.Serial == m_HotBag) - { - item.ObjPropList.Add(Language.Format(LocString.RestockHBA1, Number)); - } } private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args) @@ -247,15 +237,6 @@ private void OnHBTarget(bool location, Serial serial, Point3D loc, ushort gfx) { Engine.MainWindow.SafeAction(s => s.ShowMe()); - Item hb = World.FindItem(m_HotBag); - if (hb != null) - { - if (hb.ObjPropList.Remove(Language.Format(LocString.RestockHBA1, Number))) - { - hb.OPLChanged(); - } - } - if (!location && serial.IsItem) { m_HotBag = serial; @@ -265,13 +246,6 @@ private void OnHBTarget(bool location, Serial serial, Point3D loc, ushort gfx) m_HotBag = Serial.Zero; } - hb = World.FindItem(m_HotBag); - if (hb != null) - { - hb.ObjPropList.Add(Language.Format(LocString.RestockHBA1, Number)); - hb.OPLChanged(); - } - SetHBText(); } @@ -416,7 +390,7 @@ private void OnItemTarget(bool location, Serial serial, Point3D loc, ushort gfx) gfx = item.ItemID; } - if (gfx == 0 || gfx >= 0x4000) + if (gfx == 0) { return; } @@ -446,7 +420,7 @@ public void Add(RestockItem item) } m_Items.Add(item); - m_SubList.Items.Add(item); + Engine.MainWindow.SafeAction(m => m_SubList.Items.Add(item)); World.Player?.SendMessage(MsgLevel.Force, LocString.ItemAdded); } diff --git a/Razor/Agents/ScavengerAgent.cs b/Razor/Agents/ScavengerAgent.cs index 91d85015..bc9ecc4c 100644 --- a/Razor/Agents/ScavengerAgent.cs +++ b/Razor/Agents/ScavengerAgent.cs @@ -63,8 +63,6 @@ public ScavengerAgent() HotKey.Add(HKCategory.Agents, LocString.ScavengerAddTarget, new HotKeyCallback(OnAddToHotBag)); PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnSingleClick)); - - Agent.OnItemCreated += new ItemCreatedEventHandler(CheckBagOPL); } public void ToggleEnabled() @@ -113,14 +111,6 @@ public void OnSetHotBag() Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetBag)); } - private void CheckBagOPL(Item item) - { - if (item.Serial == m_Bag) - { - item.ObjPropList.Add(Language.GetString(LocString.ScavengerHB)); - } - } - private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args) { Serial serial = pvSrc.ReadUInt32(); @@ -288,20 +278,8 @@ private void OnTargetBag(bool location, Serial serial, Point3D loc, ushort gfx) m_BagRef = World.FindItem(m_Bag); } - if (m_BagRef != null) - { - m_BagRef.ObjPropList.Remove(Language.GetString(LocString.ScavengerHB)); - m_BagRef.OPLChanged(); - } - DebugLog("Set bag to {0}", serial); m_Bag = serial; - m_BagRef = World.FindItem(m_Bag); - if (m_BagRef != null) - { - m_BagRef.ObjPropList.Add(Language.GetString(LocString.ScavengerHB)); - m_BagRef.OPLChanged(); - } World.Player.SendMessage(MsgLevel.Force, LocString.ContSet, m_Bag); } diff --git a/Razor/Agents/SellAgent.cs b/Razor/Agents/SellAgent.cs index 1bef2f38..004147ad 100644 --- a/Razor/Agents/SellAgent.cs +++ b/Razor/Agents/SellAgent.cs @@ -53,16 +53,6 @@ public SellAgent() HotKey.Add(HKCategory.Agents, HKSubCat.None, Language.GetString(LocString.SetSellAgentHotBag), new HotKeyCallback(SetHotBag)); - - Agent.OnItemCreated += new ItemCreatedEventHandler(CheckHBOPL); - } - - private void CheckHBOPL(Item item) - { - if (item.Serial == m_HotBag) - { - item.ObjPropList.Add(Language.GetString(LocString.SellHB)); - } } private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args) @@ -234,15 +224,6 @@ public override void OnButtonPress(int num) } else { - Item hb = World.FindItem(m_HotBag); - if (hb != null) - { - if (hb.ObjPropList.Remove(Language.GetString(LocString.SellHB))) - { - hb.OPLChanged(); - } - } - m_HotBag = Serial.Zero; SetHBText(); } @@ -304,13 +285,6 @@ private void OnHBTarget(bool location, Serial serial, Point3D loc, ushort gfx) { m_HotBag = serial; SetHBText(); - - Item hb = World.FindItem(m_HotBag); - if (hb != null) - { - hb.ObjPropList.Add(Language.GetString(LocString.SellHB)); - hb.OPLChanged(); - } } } diff --git a/Razor/Agents/UseOnceAgent.cs b/Razor/Agents/UseOnceAgent.cs index 3f3a255b..5dd5e704 100644 --- a/Razor/Agents/UseOnceAgent.cs +++ b/Razor/Agents/UseOnceAgent.cs @@ -48,7 +48,7 @@ public UseOnceAgent() Number = 0; - Agent.OnItemCreated += new ItemCreatedEventHandler(CheckItemOPL); + Agent.OnItemCreated += new ItemCreatedEventHandler(OnItemCreated); } public override void Clear() @@ -56,7 +56,7 @@ public override void Clear() m_Items.Clear(); } - private void CheckItemOPL(Item newItem) + private void OnItemCreated(Item newItem) { for (int i = 0; i < m_Items.Count; i++) { @@ -65,7 +65,6 @@ private void CheckItemOPL(Item newItem) if (newItem.Serial == (Serial) m_Items[i]) { m_Items[i] = newItem; - newItem.ObjPropList.Add(Language.GetString(LocString.UseOnce)); break; } } @@ -172,17 +171,6 @@ public override void OnButtonPress(int num) if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { - for (int i = 0; i < m_Items.Count; i++) - { - if (m_Items[i] is Item) - { - Item item = (Item) m_Items[i]; - - item.ObjPropList.Remove(Language.GetString(LocString.UseOnce)); - item.OPLChanged(); - } - } - m_SubList.Items.Clear(); m_Items.Clear(); } @@ -219,9 +207,6 @@ private void OnTarget(bool location, Serial serial, Point3D loc, ushort gfx) return; } - item.ObjPropList.Add(Language.GetString(LocString.UseOnce)); - item.OPLChanged(); - m_Items.Add(item); if (m_SubList != null) { @@ -244,9 +229,6 @@ private void OnTargetRemove(bool location, Serial serial, Point3D loc, ushort gf { if (((Item) m_Items[i]).Serial == serial) { - ((Item) m_Items[i]).ObjPropList.Remove(Language.GetString(LocString.UseOnce)); - ((Item) m_Items[i]).OPLChanged(); - rem = true; } } @@ -290,8 +272,6 @@ private void OnTargetBag(bool location, Serial serial, Point3D loc, ushort gfx) if (toAdd != null) { - toAdd.ObjPropList.Add(Language.GetString(LocString.UseOnce)); - toAdd.OPLChanged(); m_Items.Add(toAdd); if (m_SubList != null) @@ -377,9 +357,6 @@ public void OnHotKey() if (item != null) { - item.ObjPropList.Remove(Language.GetString(LocString.UseOnce)); - item.OPLChanged(); - World.Player.SendMessage(LocString.UseOnceStatus, item, m_Items.Count); PlayerData.DoubleClick(item); } diff --git a/Razor/Client/ClassicUO.cs b/Razor/Client/ClassicUO.cs index e1a28ea5..c73b4dba 100644 --- a/Razor/Client/ClassicUO.cs +++ b/Razor/Client/ClassicUO.cs @@ -249,6 +249,7 @@ public unsafe override bool InstallHooks(IntPtr pluginPtr) private void Tick() { Timer.Slice(); + ScriptManager.Tick(); } private void OnPlayerPositionChanged(int x, int y, int z) diff --git a/Razor/Client/OSI.cs b/Razor/Client/OSI.cs index f2e109ed..22b8ecc7 100644 --- a/Razor/Client/OSI.cs +++ b/Razor/Client/OSI.cs @@ -903,7 +903,7 @@ public override string GetClientVersion() public override string GetUoFilePath() { - return ConfigurationManager.AppSettings["UODataDir"]; + return Config.GetAppSetting("UODataDir"); } public override IntPtr GetWindowHandle() diff --git a/Razor/Core/BandageTimer.cs b/Razor/Core/BandageTimer.cs index 1d9136b5..b2c697fd 100644 --- a/Razor/Core/BandageTimer.cs +++ b/Razor/Core/BandageTimer.cs @@ -18,6 +18,7 @@ #endregion +using Assistant.Core; using System; namespace Assistant @@ -58,6 +59,8 @@ public class BandageTimer static BandageTimer() { m_Timer = new InternalTimer(); + + MessageManager.OnSystemMessage += OnSystemMessage; } public static void OnLocalizedMessage(int num) @@ -97,7 +100,9 @@ public static void OnLocalizedMessage(int num) } } - public static void OnAsciiMessage(string msg) + private static void OnSystemMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string msg) { if (Running) { diff --git a/Razor/Core/ContainerLabels.cs b/Razor/Core/ContainerLabels.cs index 32876b55..0c340621 100644 --- a/Razor/Core/ContainerLabels.cs +++ b/Razor/Core/ContainerLabels.cs @@ -76,6 +76,57 @@ public static void Load(XmlElement node) catch { } + + MessageManager.OnLabelMessage += HandleLabelMessage; + } + + private static void HandleLabelMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string text) + { + if (!Config.GetBool("ShowContainerLabels")) + return; + + if (!source.IsItem) + return; + + Item item = World.FindItem(source); + + if (item == null) + return; + + if (!item.IsContainer) + return; + + foreach (var label in ContainerLabelList) + { + // Check if its the serial match and if the text matches the name (since we override that for the label) + if (Serial.Parse(label.Id) == source && + (item.ItemID.ItemData.Name.Equals(text) || + label.Alias.Equals(text, StringComparison.InvariantCultureIgnoreCase))) + { + string labelDisplay = + $"{Config.GetString("ContainerLabelFormat").Replace("{label}", label.Label).Replace("{type}", text)}"; + + //ContainerLabelStyle + if (Config.GetInt("ContainerLabelStyle") == 0) + { + Client.Instance.SendToClient(new AsciiMessage(source, item.ItemID.Value, MessageType.Label, + label.Hue, 3, Language.CliLocName, labelDisplay)); + } + else + { + Client.Instance.SendToClient(new UnicodeMessage(source, item.ItemID.Value, + MessageType.Label, label.Hue, 3, Language.CliLocName, "", labelDisplay)); + } + + // block the actual message from coming through since we have it in the label + args.Block = true; + + LastContainerLabelDisplayed = source; + break; + } + } } public static void ClearAll() diff --git a/Razor/Core/FriendsManager.cs b/Razor/Core/FriendsManager.cs index 165665a5..a9bbf080 100644 --- a/Razor/Core/FriendsManager.cs +++ b/Razor/Core/FriendsManager.cs @@ -157,12 +157,7 @@ public void OnAddFriendTarget(bool location, Serial serial, Point3D loc, ushort if (m == null) return; - if (AddFriend(m.Name, serial)) - { - m.ObjPropList.Add(Language.GetString(LocString.RazorFriend)); - m.OPLChanged(); - } - else + if (!AddFriend(m.Name, serial)) { World.Player.SendMessage(MsgLevel.Warning, $"'{m.Name}' is already in '{GroupName}'"); } @@ -202,11 +197,7 @@ public void AddAllMobileAsFriends() { if (!IsFriend(mobile.Serial) && mobile.Serial.IsMobile && mobile.Serial != World.Player.Serial) { - if (AddFriend(mobile.Name, mobile.Serial)) - { - mobile.ObjPropList.Add(Language.GetString(LocString.RazorFriend)); - mobile.OPLChanged(); - } + AddFriend(mobile.Name, mobile.Serial); } } } @@ -220,11 +211,7 @@ public void AddAllHumanoidsAsFriends() if (!IsFriend(mobile.Serial) && mobile.Serial.IsMobile && mobile.Serial != World.Player.Serial && mobile.IsHuman) { - if (AddFriend(mobile.Name, mobile.Serial)) - { - mobile.ObjPropList.Add(Language.GetString(LocString.RazorFriend)); - mobile.OPLChanged(); - } + AddFriend(mobile.Name, mobile.Serial); } } } diff --git a/Razor/Core/GateTimer.cs b/Razor/Core/GateTimer.cs index 98d3d83b..b8f17696 100644 --- a/Razor/Core/GateTimer.cs +++ b/Razor/Core/GateTimer.cs @@ -18,6 +18,7 @@ #endregion +using Assistant.Core; using System; using System.Linq; @@ -35,6 +36,8 @@ public class GateTimer static GateTimer() { m_Timer = new InternalTimer(); + + MessageManager.OnSystemMessage += OnSystemMessage; } public static int Count @@ -42,7 +45,9 @@ public static int Count get { return m_Count; } } - public static void OnAsciiMessage(string msg) + private static void OnSystemMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string msg) { if (Running) { diff --git a/Razor/Core/Item.cs b/Razor/Core/Item.cs index 461548eb..eaf174bc 100644 --- a/Razor/Core/Item.cs +++ b/Razor/Core/Item.cs @@ -92,102 +92,6 @@ public class Item : UOEntity private byte m_GridNum; - public override void SaveState(BinaryWriter writer) - { - base.SaveState(writer); - - writer.Write((ushort) m_ItemID); - writer.Write(m_Amount); - writer.Write(m_Direction); - writer.Write((byte) GetPacketFlags()); - writer.Write((byte) m_Layer); - writer.Write(m_Name == null ? "" : m_Name); - if (m_Parent is UOEntity) - writer.Write((uint) ((UOEntity) m_Parent).Serial); - else if (m_Parent is Serial) - writer.Write((uint) ((Serial) m_Parent)); - else - writer.Write((uint) 0); - - //writer.Write( m_Items.Count ); - //for(int i=0;i(count); - - for (int i = 0; i < count; i++) - Serial.Serials.Add(reader.ReadUInt32()); - - if (version > 2) - { - m_HouseRev = reader.ReadInt32(); - if (m_HouseRev != 0) - { - int len = reader.ReadUInt16(); - m_HousePacket = reader.ReadBytes(len); - } - } - else - { - m_HouseRev = 0; - m_HousePacket = null; - } - } - - public override void AfterLoad() - { - m_Items = new List(); - - for (int i = 0; i < Serial.Serials.Count; i++) - { - Serial s = Serial.Serials[i]; - if (s.IsItem) - { - Item item = World.FindItem(s); - - if (item != null) - { - m_Items[i] = item; - } - - Serial.Serials.RemoveAt(i); - i--; - } - } - - UpdateContainer(); - } - public Item(Serial serial) : base(serial) { m_Items = new List(); @@ -250,8 +154,6 @@ public string Name } } - public string DisplayName => m_ItemID.Value < Ultima.TileData.ItemTable.Length ? Ultima.TileData.ItemTable[m_ItemID.Value].Name : string.Empty; - public Layer Layer { get @@ -547,14 +449,6 @@ public byte GetPacketFlags() return flags; } - public int DistanceTo(Mobile m) - { - int x = Math.Abs(this.Position.X - m.Position.X); - int y = Math.Abs(this.Position.Y - m.Position.Y); - - return x > y ? x : y; - } - public void ProcessPacketFlags(byte flags) { m_Visible = ((flags & 0x80) == 0); @@ -786,81 +680,5 @@ public byte[] HousePacket get { return m_HousePacket; } set { m_HousePacket = value; } } - - public void MakeHousePacket() - { - m_HousePacket = null; - - try - { - // 3 locations... which is right? all of them? wtf? - //"Desktop/{0}/{1}/{2}/Multicache.dat", World.AccountName, World.ShardName, World.OrigPlayerName - //"Desktop/{0}/{1}/{2}/Multicache.dat", World.AccountName, World.ShardName, World.Player.Name ); - //"Desktop/{0}/Multicache.dat", World.AccountName ); - string path = Ultima.Files.GetFilePath( - $"Desktop/{World.AccountName}/{World.ShardName}/{World.OrigPlayerName}/Multicache.dat"); - if (string.IsNullOrEmpty(path) || !File.Exists(path)) - return; - - using (StreamReader reader = - new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) - { - string line; - reader.ReadLine(); // ver - int skip = 0; - int count = 0; - while ((line = reader.ReadLine()) != null) - { - if (count++ < skip || line == "" || line[0] == ';') - continue; - - string[] split = line.Split(' ', '\t'); - if (split.Length <= 0) - return; - - skip = 0; - Serial ser = (uint) Utility.ToInt32(split[0], 0); - int rev = Utility.ToInt32(split[1], 0); - int lines = Utility.ToInt32(split[2], 0); - - if (ser == this.Serial) - { - m_HouseRev = rev; - MultiTileEntry[] tiles = new MultiTileEntry[lines]; - count = 0; - - Ultima.MultiComponentList mcl = Ultima.Multis.GetComponents(m_ItemID); - - while ((line = reader.ReadLine()) != null && count < lines) - { - split = line.Split(' ', '\t'); - - tiles[count] = new MultiTileEntry(); - tiles[count].m_ItemID = (ushort) Utility.ToInt32(split[0], 0); - tiles[count].m_OffsetX = (short) (Utility.ToInt32(split[1], 0) + mcl.Center.X); - tiles[count].m_OffsetX = (short) (Utility.ToInt32(split[2], 0) + mcl.Center.Y); - tiles[count].m_OffsetX = (short) Utility.ToInt32(split[3], 0); - - count++; - } - - m_HousePacket = new DesignStateDetailed(Serial, m_HouseRev, mcl.Min.X, mcl.Min.Y, mcl.Max.X, - mcl.Max.Y, tiles).Compile(); - break; - } - else - { - skip = lines; - } - - count = 0; - } - } - } - catch // ( Exception e ) - { - //Engine.LogCrash( e ); - } - } } } \ No newline at end of file diff --git a/Razor/Core/MessageManager.cs b/Razor/Core/MessageManager.cs new file mode 100644 index 00000000..210b670a --- /dev/null +++ b/Razor/Core/MessageManager.cs @@ -0,0 +1,93 @@ +#region license + +// Razor: An Ultima Online Assistant +// Copyright (C) 2021 Razor Development Community on GitHub +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#endregion + +using Assistant.Agents; +using System; +using System.IO; + +namespace Assistant.Core +{ + public static class MessageManager + { + public static Action OnSpellMessage; + public static Action OnLabelMessage; + public static Action OnSystemMessage; + public static Action OnMobileMessage; + + public static bool GetLabelCommand = false; + + public static void Initialize() + { + OnMobileMessage += HandleMobileMessage; + } + + public static void HandleMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string text) + { + if (World.Player == null) + return; + + switch (type) + { + case MessageType.Spell: + OnSpellMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text); + break; + case MessageType.Label: + if (source.IsMobile) + { + Mobile m = World.FindMobile(source); + if (m != null) + { + m.Name = sourceName; + } + } + + OnLabelMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text); + break; + default: + if (source == Serial.MinusOne && sourceName == "System") + { + OnSystemMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text); + } + + if (source.IsMobile && source != World.Player.Serial) + { + if(GetLabelCommand) + OnLabelMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text); + else + OnMobileMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text); + } + break; + } + } + + public static void HandleMobileMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string text) + { + if (Config.GetBool("ForceSpeechHue")) + { + p.Seek(10, SeekOrigin.Begin); + p.Write((ushort)Config.GetInt("SpeechHue")); + } + } + } +} diff --git a/Razor/Core/Mobile.cs b/Razor/Core/Mobile.cs index ad12f2cc..f5b15e83 100644 --- a/Razor/Core/Mobile.cs +++ b/Razor/Core/Mobile.cs @@ -43,16 +43,6 @@ public enum Direction : byte ValueMask = 0x87 } - //public enum BodyType : byte - //{ - // Empty, - // Monster, - // Sea_Monster, - // Animal, - // Human, - // Equipment - //} - public class Mobile : UOEntity { private ushort m_Body; @@ -61,19 +51,17 @@ public class Mobile : UOEntity private byte m_Notoriety; - private bool m_Visible; + // Mobile flags + private bool m_Paralyzed; private bool m_Female; - private bool m_Poisoned; + private bool m_Flying; private bool m_Blessed; private bool m_Warmode; + private bool m_Hidden; - //new - private bool m_Unknown; - private bool m_Unknown2; - private bool m_Unknown3; + private bool m_Poisoned; private bool m_CanRename; - //end new private ushort m_HitsMax, m_Hits; protected ushort m_StamMax, m_Stam, m_ManaMax, m_Mana; @@ -83,90 +71,17 @@ public class Mobile : UOEntity private byte m_Map; - //private static BodyType[] m_Types; - - //public static void Initialize() - //{ - // using (StreamReader ip = new StreamReader(Path.Combine(Ultima.Files.RootDir, "mobtypes.txt"))) - // { - // m_Types = new BodyType[0x1000]; - - // string line; - - // while ((line = ip.ReadLine()) != null) - // { - // if (line.Length == 0 || line.StartsWith("#")) - // continue; - - // string[] split = line.Split('\t'); - - // BodyType type; - // int bodyID; - - // if (int.TryParse(split[0], out bodyID) && Enum.TryParse(split[1], true, out type) && bodyID >= 0 && - // bodyID < m_Types.Length) - // { - // m_Types[bodyID] = type; - // } - // } - // } - //} - - public override void SaveState(BinaryWriter writer) - { - base.SaveState(writer); - - writer.Write(m_Body); - writer.Write((byte) m_Direction); - writer.Write(m_Name == null ? "" : m_Name); - writer.Write(m_Notoriety); - writer.Write((byte) GetPacketFlags()); - writer.Write(m_HitsMax); - writer.Write(m_Hits); - writer.Write(m_Map); - - writer.Write((int) m_Items.Count); - for (int i = 0; i < m_Items.Count; i++) - writer.Write((uint) (((Item) m_Items[i]).Serial)); - //writer.Write( (int)0 ); - } - - public Mobile(BinaryReader reader, int version) : base(reader, version) - { - m_Body = reader.ReadUInt16(); - m_Direction = (Direction) reader.ReadByte(); - m_Name = reader.ReadString(); - m_Notoriety = reader.ReadByte(); - ProcessPacketFlags(reader.ReadByte()); - m_HitsMax = reader.ReadUInt16(); - m_Hits = reader.ReadUInt16(); - m_Map = reader.ReadByte(); - - int count = reader.ReadInt32(); - m_LoadSerials = new List(); - - for (int i = count - 1; i >= 0; --i) - m_LoadSerials.Add(reader.ReadUInt32()); - } + private bool m_Dead; - public override void AfterLoad() + public bool Dead { - int count = m_LoadSerials.Count; - - for (int i = count - 1; i >= 0; --i) - { - Item it = World.FindItem(m_LoadSerials[i]); - if (it != null) - m_Items.Add(it); - } - - m_LoadSerials = null; //per il GC e per liberare RAM + get => m_Dead; + set => m_Dead = value; } public Mobile(Serial serial) : base(serial) { m_Map = World.Player == null ? (byte) 0 : World.Player.Map; - m_Visible = true; Agent.InvokeMobileCreated(this); } @@ -243,8 +158,8 @@ public Direction Direction public bool Visible { - get { return m_Visible; } - set { m_Visible = value; } + get { return !m_Hidden; } + set { m_Hidden = !value; } } public bool Poisoned @@ -293,31 +208,17 @@ public bool IsMonster get { return !IsHuman; } } - //new - public bool Unknown + public bool Paralyzed { - get { return m_Unknown; } - set { m_Unknown = value; } + get { return m_Paralyzed; } + set { m_Paralyzed = value; } } - public bool Unknown2 - { - get { return m_Unknown2; } - set { m_Unknown2 = value; } - } - - public bool Unknown3 - { - get { return m_Unknown3; } - set { m_Unknown3 = value; } - } - - public bool CanRename //A pet! (where the health bar is open, we can add this to an arraylist of mobiles... + public bool CanRename { get { return m_CanRename; } set { m_CanRename = value; } } - //end new public bool Warmode { @@ -544,10 +445,13 @@ public int GetPacketFlags() { int flags = 0x0; + if (m_Paralyzed) + flags |= 0x01; + if (m_Female) flags |= 0x02; - if (m_Poisoned) + if (m_Flying) flags |= 0x04; if (m_Blessed) @@ -556,18 +460,9 @@ public int GetPacketFlags() if (m_Warmode) flags |= 0x40; - if (!m_Visible) + if (m_Hidden) flags |= 0x80; - if (m_Unknown) - flags |= 0x01; - - if (m_Unknown2) - flags |= 0x10; - - if (m_Unknown3) - flags |= 0x20; - return flags; } @@ -576,13 +471,12 @@ public void ProcessPacketFlags(byte flags) if (!PacketHandlers.UseNewStatus) m_Poisoned = (flags & 0x04) != 0; - m_Unknown = (flags & 0x01) != 0; //new + m_Paralyzed = (flags & 0x01) != 0; m_Female = (flags & 0x02) != 0; + m_Flying = (flags & 0x04) != 0; m_Blessed = (flags & 0x08) != 0; - m_Unknown2 = (flags & 0x10) != 0; //new - m_Unknown3 = (flags & 0x10) != 0; //new m_Warmode = (flags & 0x40) != 0; - m_Visible = (flags & 0x80) == 0; + m_Hidden = (flags & 0x80) != 0; } public List Contains @@ -652,91 +546,5 @@ internal void OverheadMessage(LocString str, params object[] args) { OverheadMessage(Language.Format(str, args)); } - - private Point2D m_ButtonPoint = Point2D.Zero; - - internal Point2D ButtonPoint - { - get { return m_ButtonPoint; } - set { m_ButtonPoint = value; } - } - - private static List _layers = new List - { - Layer.Backpack, - Layer.Invalid, - Layer.FirstValid, - Layer.RightHand, - Layer.LeftHand, - Layer.Shoes, - Layer.Pants, - Layer.Shirt, - Layer.Head, - Layer.Neck, - Layer.Gloves, - Layer.InnerTorso, - Layer.MiddleTorso, - Layer.Arms, - Layer.Cloak, - Layer.OuterTorso, - Layer.OuterLegs, - Layer.InnerLegs, - Layer.LastUserValid, - Layer.Mount, - Layer.LastValid, - Layer.Hair - }; - - internal void ResetLayerHue() - { - if (IsGhost) - return; - - foreach (Layer l in _layers) - { - Item i = GetItemOnLayer(l); - - if (i == null) - continue; - - if (i.ItemID == 0x204E && i.Hue == 0x08FD) // death shroud - i.ItemID = 0x1F03; - - Client.Instance.SendToClient(new EquipmentItem(i, i.Hue, Serial)); - } - } - - internal void SetLayerHue(int hue) - { - if (IsGhost) - return; - - foreach (Layer l in _layers) - { - Item i = GetItemOnLayer(l); - if (i == null) - continue; - - Client.Instance.SendToClient(new EquipmentItem(i, (ushort) hue, Serial)); - } - } - - internal Packet SetMobileHue(Packet p, int hue) - { - if (IsGhost) - return p; - - p = WriteHueToPacket(p, (ushort) hue); - - return p; - } - - private static Packet WriteHueToPacket(Packet p, ushort color) - { - p.Seek(-3, SeekOrigin.Current); - p.Write((short) color); - p.Seek(+1, SeekOrigin.Current); - return p; - } } } \ No newline at end of file diff --git a/Razor/Core/ObjectPropertyList.cs b/Razor/Core/ObjectPropertyList.cs deleted file mode 100644 index 1b48201a..00000000 --- a/Razor/Core/ObjectPropertyList.cs +++ /dev/null @@ -1,432 +0,0 @@ -#region license - -// Razor: An Ultima Online Assistant -// Copyright (C) 2021 Razor Development Community on GitHub -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#endregion - -using System; -using System.Text; -using System.Collections.Generic; - -namespace Assistant -{ - public class ObjectPropertyList - { - private class OPLEntry - { - public int Number = 0; - public string Args = null; - - public OPLEntry(int num) : this(num, null) - { - } - - public OPLEntry(int num, string args) - { - Number = num; - Args = args; - } - } - - private List m_StringNums = new List(); - - private int m_Hash = 0; - private List m_Content = new List(); - - private int m_CustomHash = 0; - private List m_CustomContent = new List(); - - - private UOEntity m_Owner = null; - - public int Hash - { - get { return m_Hash ^ m_CustomHash; } - set { m_Hash = value; } - } - - public int ServerHash - { - get { return m_Hash; } - } - - public bool Customized - { - get { return m_CustomHash != 0; } - } - - public ObjectPropertyList(UOEntity owner) - { - m_Owner = owner; - - m_StringNums.AddRange(m_DefaultStringNums); - } - - public UOEntity Owner - { - get { return m_Owner; } - } - - public void Read(PacketReader p) - { - m_Content.Clear(); - - p.Seek(5, System.IO.SeekOrigin.Begin); // seek to packet data - - p.ReadUInt32(); // serial - p.ReadByte(); // 0 - p.ReadByte(); // 0 - m_Hash = p.ReadInt32(); - - m_StringNums.Clear(); - m_StringNums.AddRange(m_DefaultStringNums); - - while (p.Position < p.Length) - { - int num = p.ReadInt32(); - if (num == 0) - break; - - m_StringNums.Remove(num); - - short bytes = p.ReadInt16(); - string args = null; - if (bytes > 0) - args = p.ReadUnicodeStringBE(bytes >> 1); - - m_Content.Add(new OPLEntry(num, args)); - } - - for (int i = 0; i < m_CustomContent.Count; i++) - { - OPLEntry ent = (OPLEntry) m_CustomContent[i]; - if (m_StringNums.Contains(ent.Number)) - { - m_StringNums.Remove(ent.Number); - } - else - { - for (int s = 0; s < m_DefaultStringNums.Length; s++) - { - if (ent.Number == m_DefaultStringNums[s]) - { - ent.Number = GetStringNumber(); - break; - } - } - } - } - } - - public void Add(int number) - { - if (number == 0) - return; - - AddHash(number); - - m_CustomContent.Add(new OPLEntry(number)); - } - - private static byte[] m_Buffer = new byte[0]; - - public void AddHash(int val) - { - m_CustomHash ^= (val & 0x3FFFFFF); - m_CustomHash ^= (val >> 26) & 0x3F; - } - - public void Add(int number, string arguments) - { - if (number == 0) - return; - - AddHash(number); - m_CustomContent.Add(new OPLEntry(number, arguments)); - } - - public void Add(int number, string format, object arg0) - { - Add(number, String.Format(format, arg0)); - } - - public void Add(int number, string format, object arg0, object arg1) - { - Add(number, String.Format(format, arg0, arg1)); - } - - public void Add(int number, string format, object arg0, object arg1, object arg2) - { - Add(number, String.Format(format, arg0, arg1, arg2)); - } - - public void Add(int number, string format, params object[] args) - { - Add(number, String.Format(format, args)); - } - - private static int[] m_DefaultStringNums = new int[] - { - 1042971, // ~1_NOTHING~ - 1070722, // ~1_NOTHING~ - 1063483, // ~1_MATERIAL~ ~2_ITEMNAME~ - 1076228, // ~1_DUMMY~ ~2_DUMMY~ - 1060847, // ~1_val~ ~2_val~ - 1050039 // ~1_NUMBER~ ~2_ITEMNAME~ - // these are ugly: - //1062613, // "~1_NAME~" (orange) - //1049644, // [~1_stuff~] - }; - - private int GetStringNumber() - { - if (m_StringNums.Count > 0) - { - int num = (int) m_StringNums[0]; - m_StringNums.RemoveAt(0); - return num; - } - else - { - return 1049644; - } - } - - private const string RazorHTMLFormat = "
{0}
"; - - public void Add(string text) - { - Add(GetStringNumber(), String.Format(RazorHTMLFormat, text)); - } - - public void Add(string format, string arg0) - { - Add(GetStringNumber(), String.Format(format, arg0)); - } - - public void Add(string format, string arg0, string arg1) - { - Add(GetStringNumber(), String.Format(format, arg0, arg1)); - } - - public void Add(string format, string arg0, string arg1, string arg2) - { - Add(GetStringNumber(), String.Format(format, arg0, arg1, arg2)); - } - - public void Add(string format, params object[] args) - { - Add(GetStringNumber(), String.Format(format, args)); - } - - public bool Remove(int number) - { - for (int i = 0; i < m_Content.Count; i++) - { - OPLEntry ent = (OPLEntry) m_Content[i]; - if (ent == null) - continue; - - if (ent.Number == number) - { - for (int s = 0; s < m_DefaultStringNums.Length; s++) - { - if (m_DefaultStringNums[s] == ent.Number) - { - m_StringNums.Insert(0, ent.Number); - break; - } - } - - m_Content.RemoveAt(i); - AddHash(ent.Number); - if (!string.IsNullOrEmpty(ent.Args)) - AddHash(ent.Args.GetHashCode()); - - return true; - } - } - - for (int i = 0; i < m_CustomContent.Count; i++) - { - OPLEntry ent = (OPLEntry) m_CustomContent[i]; - if (ent == null) - continue; - - if (ent.Number == number) - { - for (int s = 0; s < m_DefaultStringNums.Length; s++) - { - if (m_DefaultStringNums[s] == ent.Number) - { - m_StringNums.Insert(0, ent.Number); - break; - } - } - - m_CustomContent.RemoveAt(i); - AddHash(ent.Number); - if (!string.IsNullOrEmpty(ent.Args)) - AddHash(ent.Args.GetHashCode()); - if (m_CustomContent.Count == 0) - m_CustomHash = 0; - return true; - } - } - - return false; - } - - public bool Remove(string str) - { - string htmlStr = String.Format(RazorHTMLFormat, str); - - /*for ( int i = 0; i < m_Content.Count; i++ ) - { - OPLEntry ent = (OPLEntry)m_Content[i]; - if ( ent == null ) - continue; - - for (int s=0;s m_Buffer.Length) - m_Buffer = new byte[byteCount]; - - byteCount = Encoding.Unicode.GetBytes(ent.Args, 0, ent.Args.Length, m_Buffer, 0); - - p.Write((short) byteCount); - p.Write(m_Buffer, 0, byteCount); - } - else - { - p.Write((short) 0); - } - } - } - - foreach (OPLEntry ent in m_CustomContent) - { - try - { - if (ent != null && ent.Number != 0) - { - string arguments = ent.Args; - - p.Write((int) ent.Number); - - if (string.IsNullOrEmpty(arguments)) - arguments = " "; - arguments += "\t "; - - if (!string.IsNullOrEmpty(arguments)) - { - int byteCount = Encoding.Unicode.GetByteCount(arguments); - - if (byteCount > m_Buffer.Length) - m_Buffer = new byte[byteCount]; - - byteCount = Encoding.Unicode.GetBytes(arguments, 0, arguments.Length, m_Buffer, 0); - - p.Write((short) byteCount); - p.Write(m_Buffer, 0, byteCount); - } - else - { - p.Write((short) 0); - } - } - } - catch - { - } - } - - p.Write((int) 0); - - return p; - } - } - - public class OPLInfo : Packet - { - public OPLInfo(Serial ser, int hash) : base(0xDC, 9) - { - Write((uint) ser); - Write((int) hash); - } - } -} \ No newline at end of file diff --git a/Razor/Core/Player.cs b/Razor/Core/Player.cs index b2192619..e870c08a 100644 --- a/Razor/Core/Player.cs +++ b/Razor/Core/Player.cs @@ -330,135 +330,6 @@ public List OpenedCorpses get { return m_OpenedCorpses; } } - - public override void SaveState(BinaryWriter writer) - { - base.SaveState(writer); - - writer.Write(m_Str); - writer.Write(m_Dex); - writer.Write(m_Int); - writer.Write(m_StamMax); - writer.Write(m_Stam); - writer.Write(m_ManaMax); - writer.Write(m_Mana); - writer.Write((byte) m_StrLock); - writer.Write((byte) m_DexLock); - writer.Write((byte) m_IntLock); - writer.Write(m_Gold); - writer.Write(m_Weight); - - writer.Write((byte) Skill.Count); - for (int i = 0; i < Skill.Count; i++) - { - writer.Write(m_Skills[i].FixedBase); - writer.Write(m_Skills[i].FixedCap); - writer.Write(m_Skills[i].FixedValue); - writer.Write((byte) m_Skills[i].Lock); - } - - writer.Write(m_AR); - writer.Write(m_StatCap); - writer.Write(m_Followers); - writer.Write(m_FollowersMax); - writer.Write(m_Tithe); - - writer.Write(m_LocalLight); - writer.Write(m_GlobalLight); - writer.Write(m_Features); - writer.Write(m_Season); - - writer.Write((byte) m_MapPatches.Length); - for (int i = 0; i < m_MapPatches.Length; i++) - writer.Write((int) m_MapPatches[i]); - } - - public PlayerData(BinaryReader reader, int version) : base(reader, version) - { - int c; - m_Str = reader.ReadUInt16(); - m_Dex = reader.ReadUInt16(); - m_Int = reader.ReadUInt16(); - m_StamMax = reader.ReadUInt16(); - m_Stam = reader.ReadUInt16(); - m_ManaMax = reader.ReadUInt16(); - m_Mana = reader.ReadUInt16(); - m_StrLock = (LockType) reader.ReadByte(); - m_DexLock = (LockType) reader.ReadByte(); - m_IntLock = (LockType) reader.ReadByte(); - m_Gold = reader.ReadUInt32(); - m_Weight = reader.ReadUInt16(); - - if (version >= 4) - { - Skill.Count = c = reader.ReadByte(); - } - else if (version == 3) - { - long skillStart = reader.BaseStream.Position; - c = 0; - reader.BaseStream.Seek(7 * 49, SeekOrigin.Current); - for (int i = 48; i < 60; i++) - { - ushort Base, Cap, Val; - byte Lock; - - Base = reader.ReadUInt16(); - Cap = reader.ReadUInt16(); - Val = reader.ReadUInt16(); - Lock = reader.ReadByte(); - - if (Base > 2000 || Cap > 2000 || Val > 2000 || Lock > 2) - { - c = i; - break; - } - } - - if (c == 0) - c = 52; - else if (c > 54) - c = 54; - - Skill.Count = c; - - reader.BaseStream.Seek(skillStart, SeekOrigin.Begin); - } - else - { - Skill.Count = c = 52; - } - - m_Skills = new Skill[c]; - for (int i = 0; i < c; i++) - { - m_Skills[i] = new Skill(i); - m_Skills[i].FixedBase = reader.ReadUInt16(); - m_Skills[i].FixedCap = reader.ReadUInt16(); - m_Skills[i].FixedValue = reader.ReadUInt16(); - m_Skills[i].Lock = (LockType) reader.ReadByte(); - } - - m_AR = reader.ReadUInt16(); - m_StatCap = reader.ReadUInt16(); - m_Followers = reader.ReadByte(); - m_FollowersMax = reader.ReadByte(); - m_Tithe = reader.ReadInt32(); - - m_LocalLight = reader.ReadSByte(); - m_GlobalLight = reader.ReadByte(); - m_Features = reader.ReadUInt16(); - m_Season = reader.ReadByte(); - - if (version >= 4) - c = reader.ReadByte(); - else - c = 8; - m_MapPatches = new int[c]; - for (int i = 0; i < c; i++) - m_MapPatches[i] = reader.ReadInt32(); - } - public PlayerData(Serial serial) : base(serial) { m_Skills = new Skill[Skill.Count]; @@ -960,7 +831,7 @@ internal void Alliance(string msg, int hue) public uint CurrentGumpS, CurrentGumpI; public GumpResponseAction LastGumpResponseAction; public bool HasGump; - public bool HasCompressedGump; + public bool HasCompressedGump => GumpList.Count > 0; public List CurrentGumpStrings = new List(); public string CurrentGumpRawData; public uint CurrentMenuS; @@ -973,6 +844,46 @@ internal void Alliance(string msg, int hue) public uint PromptType; public string PromptInputText; + public Dictionary GumpList = new Dictionary(); + + public class GumpInfo + { + private uint _serial; + private uint _gumpId; + List _gumpContext; + + public uint GumpSerial + { + set => _serial = value; + get => _serial; + } + + public uint GumpId + { + set => _gumpId = value; + get => _gumpId; + } + + public List GumpContext + { + set => _gumpContext = value; + get => _gumpContext; + } + + public GumpInfo(uint serial, uint gumpId, List gumpContext) + { + _serial = serial; + _gumpId = gumpId; + _gumpContext = gumpContext; + } + + public GumpInfo(uint serial, uint gumpId) + { + _serial = serial; + _gumpId = gumpId; + } + } + public GumpCollection InternalGumps { get; set; } = new GumpCollection(); public void CancelPrompt() @@ -1112,6 +1023,11 @@ public int LastSpell //private UOEntity m_LastCtxM = null; //public UOEntity LastContextMenu { get { return m_LastCtxM; } set { m_LastCtxM = value; } } + public void RenameMobile(Serial serial, string newName) + { + Client.Instance.SendToServer(new RenamePacket(serial.Value, newName)); + } + public bool UseItem(Item cont, ushort find) { if (!Client.Instance.AllowBit(FeatureBit.PotionHotkeys)) diff --git a/Razor/Core/ScreenCapture.cs b/Razor/Core/ScreenCapture.cs index 126b93b5..b24d4ddd 100644 --- a/Razor/Core/ScreenCapture.cs +++ b/Razor/Core/ScreenCapture.cs @@ -84,8 +84,9 @@ public static void CaptureNow() path = Config.GetUserDirectory("ScreenShots"); Config.SetProperty("CapPath", path); } - catch + catch (Exception e) { + MessageBox.Show(e.Message); path = ""; } } @@ -100,15 +101,19 @@ public static void CaptureNow() try { - IntPtr hBmp = Platform.CaptureScreen(Client.Instance.GetWindowHandle(), Config.GetBool("CapFullScreen"), - imageTimestampTag); - using (Image img = Image.FromHbitmap(hBmp)) - img.Save(filename, GetFormat(type)); - DeleteObject(hBmp); + Rectangle bounds = Screen.GetBounds(Point.Empty); + using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height)) + { + using (Graphics g = Graphics.FromImage(bitmap)) + { + g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size); + } + bitmap.Save(filename, GetFormat(type)); + } } - catch + catch (Exception e) { - // ignored + MessageBox.Show(e.Message); } LastMobileDeathName = string.Empty; @@ -118,25 +123,29 @@ public static void CaptureNow() private static ImageFormat GetFormat(string fmt) { - //string fmt = Config.GetString( "ImageFormat" ).ToLower(); - if (fmt == "jpeg" || fmt == "jpg") - return ImageFormat.Jpeg; - else if (fmt == "png") - return ImageFormat.Png; - else if (fmt == "bmp") - return ImageFormat.Bmp; - else if (fmt == "gif") - return ImageFormat.Gif; - else if (fmt == "tiff" || fmt == "tif") - return ImageFormat.Tiff; - else if (fmt == "wmf") - return ImageFormat.Wmf; - else if (fmt == "exif") - return ImageFormat.Exif; - else if (fmt == "emf") - return ImageFormat.Emf; - else - return ImageFormat.Jpeg; + switch (fmt) + { + case "jpeg": + case "jpg": + return ImageFormat.Jpeg; + case "png": + return ImageFormat.Png; + case "bmp": + return ImageFormat.Bmp; + case "gif": + return ImageFormat.Gif; + case "tiff": + case "tif": + return ImageFormat.Tiff; + case "wmf": + return ImageFormat.Wmf; + case "exif": + return ImageFormat.Exif; + case "emf": + return ImageFormat.Emf; + default: + return ImageFormat.Jpeg; + } } public static void DisplayTo(ListBox list) diff --git a/Razor/Core/Serial.cs b/Razor/Core/Serial.cs index 6c7f09a6..fc107d51 100644 --- a/Razor/Core/Serial.cs +++ b/Razor/Core/Serial.cs @@ -31,6 +31,9 @@ public struct Serial : IComparable public static readonly Serial MinusOne = new Serial(0xFFFFFFFF); public static readonly Serial Zero = new Serial(0); + public static readonly Serial SelfAndBackpack = new Serial(0xFFFFFFFE); + public static readonly Serial SelfBackpackAndGround = new Serial(0xFFFFFFFD); + private Serial(uint serial) { m_Serial = serial; diff --git a/Razor/Core/Spells.cs b/Razor/Core/Spells.cs index dd8a571d..e737e947 100644 --- a/Razor/Core/Spells.cs +++ b/Razor/Core/Spells.cs @@ -22,6 +22,8 @@ using System.IO; using System.Collections.Generic; using System.Windows.Forms; +using Assistant.Core; +using System.Text; namespace Assistant { @@ -345,6 +347,55 @@ static Spell() HotKey.Add(HKCategory.Spells, LocString.MiniHealOrCureSelf, new HotKeyCallback(MiniHealOrCureSelf)); HotKey.Add(HKCategory.Spells, LocString.GHealOrCureSelf, new HotKeyCallback(GHealOrCureSelf)); HotKey.Add(HKCategory.Spells, LocString.Interrupt, new HotKeyCallback(Interrupt)); + + MessageManager.OnSpellMessage += HandleSpellMessage; + } + + private static StringBuilder SpellPowerwordsBuilder { get; set; } = new StringBuilder(Config.GetString("SpellFormat")); + + private static void ResetSpellPowerwordsBuilder() + { + SpellPowerwordsBuilder.Remove(0, SpellPowerwordsBuilder.Length); + SpellPowerwordsBuilder.Insert(0, Config.GetString("SpellFormat")); + } + + private static void HandleSpellMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string text) + { + Spell s = Get(text.Trim()); + + if (Config.GetBool("OverrideSpellFormat") && s != null) + { + ResetSpellPowerwordsBuilder(); + + StringBuilder sb = SpellPowerwordsBuilder; + sb.Replace(@"{power}", s.WordsOfPower); + string spell = Language.GetString(s.Name); + sb.Replace(@"{spell}", spell); + sb.Replace(@"{name}", spell); + sb.Replace(@"{circle}", s.Circle.ToString()); + + string newText = sb.ToString(); + + if (newText != null && newText != "" && newText != text) + { + Client.Instance.SendToClient(new AsciiMessage(source, graphic, MessageType.Spell, s.GetHue(hue), font, + sourceName, newText)); + + args.Block = true; + return; + } + } + + if (Config.GetBool("ForceSpellHue")) + { + p.Seek(10, SeekOrigin.Begin); + if (s != null) + p.Write((ushort)s.GetHue(hue)); + else + p.Write((ushort)Config.GetInt("NeutralSpellHue")); + } } public static void HealOrCureSelf() diff --git a/Razor/Core/SystemMessages.cs b/Razor/Core/SystemMessages.cs index 3ac3aad5..081e81d9 100644 --- a/Razor/Core/SystemMessages.cs +++ b/Razor/Core/SystemMessages.cs @@ -27,6 +27,43 @@ public static class SystemMessages { public static List Messages { get; } = new List(); + public static void Initialize() + { + MessageManager.OnSystemMessage += HandleSystemMessage; + } + + private static void HandleSystemMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string text) + { + if (Config.GetBool("FilterSnoopMsg") && text.IndexOf(World.Player.Name) == -1 && + text.StartsWith("You notice") && text.IndexOf("attempting to peek into") != -1 && + text.IndexOf("belongings") != -1) + { + args.Block = true; + return; + } + + if (text.StartsWith("You've committed a criminal act") || text.StartsWith("You are now a criminal")) + { + World.Player.ResetCriminalTimer(); + } + + if (Config.GetBool("FilterSystemMessages")) + { + if (!MessageQueue.Enqueue(source, null, graphic, type, hue, font, lang, sourceName, text)) + { + args.Block = true; + return; + } + } + + // Overhead message override + OverheadManager.DisplayOverheadMessage(text); + + Add(text); + } + public static void Add(string text) { if (string.IsNullOrEmpty(text)) @@ -36,13 +73,13 @@ public static void Add(string text) Messages.Add(text); - if (Messages.Count >= 25) + if (Messages.Count >= 100) { - Messages.RemoveRange(0, 10); + Messages.RemoveRange(0, 5); } } - public static bool Exists(string text) + public static bool Exists(string text, bool consume = true) { if (string.IsNullOrEmpty(text)) { @@ -51,11 +88,13 @@ public static bool Exists(string text) for (int i = Messages.Count - 1; i >= 0; i--) { - if (Messages[i].IndexOf(text, StringComparison.OrdinalIgnoreCase) != -1) - { - Messages.RemoveRange(0, i + 1); - return true; - } + if (Messages[i].IndexOf(text, StringComparison.OrdinalIgnoreCase) == -1) + continue; + + if(consume) + Messages.RemoveAt( i ); + + return true; } return false; diff --git a/Razor/Core/Targeting.cs b/Razor/Core/Targeting.cs index 933cde02..8496fffb 100644 --- a/Razor/Core/Targeting.cs +++ b/Razor/Core/Targeting.cs @@ -92,6 +92,11 @@ public static bool HasTarget get { return m_HasTarget; } } + public static short CursorType => m_CurFlags; + + public static bool HasBeneficialTarget => m_LastBeneTarg != null; + public static bool HasHarmfulTarget => m_LastHarmTarg != null; + public static TargetInfo LastTargetInfo { get { return m_LastTarget; } @@ -458,80 +463,23 @@ private static void OnSetLastTargetHarmful(bool location, Serial serial, Point3D private static Serial m_OldBeneficialLT = Serial.Zero; private static Serial m_OldHarmfulLT = Serial.Zero; - private static void RemoveTextFlags(UOEntity m) - { - if (m != null) - { - bool oplchanged = false; - - oplchanged |= m.ObjPropList.Remove(Language.GetString(LocString.LastTarget)); - oplchanged |= m.ObjPropList.Remove(Language.GetString(LocString.HarmfulTarget)); - oplchanged |= m.ObjPropList.Remove(Language.GetString(LocString.BeneficialTarget)); - - if (oplchanged) - m.OPLChanged(); - } - } - - private static void AddTextFlags(UOEntity m) - { - if (m != null) - { - bool oplchanged = false; - - if (IsSmartTargetingEnabled()) - { - if (m_LastHarmTarg != null && m_LastHarmTarg.Serial == m.Serial) - { - oplchanged = true; - m.ObjPropList.Add(Language.GetString(LocString.HarmfulTarget)); - } - - if (m_LastBeneTarg != null && m_LastBeneTarg.Serial == m.Serial) - { - oplchanged = true; - m.ObjPropList.Add(Language.GetString(LocString.BeneficialTarget)); - } - } - - if (!oplchanged && m_LastTarget != null && m_LastTarget.Serial == m.Serial) - { - oplchanged = true; - m.ObjPropList.Add(Language.GetString(LocString.LastTarget)); - } - - if (oplchanged) - m.OPLChanged(); - } - } - private static void LastTargetChanged() { if (m_LastTarget != null) { bool lth = Config.GetInt("LTHilight") != 0; - if (m_OldLT.IsItem) - { - RemoveTextFlags(World.FindItem(m_OldLT)); - } - else + if (!m_OldLT.IsItem) { Mobile m = World.FindMobile(m_OldLT); if (m != null) { if (lth) Client.Instance.SendToClient(new MobileIncoming(m)); - - RemoveTextFlags(m); } } - if (m_LastTarget.Serial.IsItem) - { - AddTextFlags(World.FindItem(m_LastTarget.Serial)); - } - else + if (!m_LastTarget.Serial.IsItem) { Mobile m = World.FindMobile(m_LastTarget.Serial); if (m != null) @@ -540,8 +488,6 @@ private static void LastTargetChanged() Client.Instance.SendToClient(new MobileIncoming(m)); CheckLastTargetRange(m); - - AddTextFlags(m); } } @@ -553,31 +499,12 @@ private static void LastBeneficialTargetChanged() { if (m_LastBeneTarg != null) { - if (m_OldBeneficialLT.IsItem) - { - RemoveTextFlags(World.FindItem(m_OldBeneficialLT)); - } - else - { - Mobile m = World.FindMobile(m_OldBeneficialLT); - if (m != null) - { - RemoveTextFlags(m); - } - } - - if (m_LastBeneTarg.Serial.IsItem) - { - AddTextFlags(World.FindItem(m_LastBeneTarg.Serial)); - } - else + if (!m_LastBeneTarg.Serial.IsItem) { Mobile m = World.FindMobile(m_LastBeneTarg.Serial); if (m != null) { CheckLastTargetRange(m); - - AddTextFlags(m); } } @@ -589,31 +516,12 @@ private static void LastHarmfulTargetChanged() { if (m_LastHarmTarg != null) { - if (m_OldHarmfulLT.IsItem) - { - RemoveTextFlags(World.FindItem(m_OldHarmfulLT)); - } - else - { - Mobile m = World.FindMobile(m_OldHarmfulLT); - if (m != null) - { - RemoveTextFlags(m); - } - } - - if (m_LastHarmTarg.Serial.IsItem) - { - AddTextFlags(World.FindItem(m_LastHarmTarg.Serial)); - } - else + if (!m_LastHarmTarg.Serial.IsItem) { Mobile m = World.FindMobile(m_LastHarmTarg.Serial); if (m != null) { CheckLastTargetRange(m); - - AddTextFlags(m); } } @@ -765,8 +673,20 @@ public static void LastTarget(bool forceQ) if (m_HasTarget) { + var wasIntercept = m_Intercept; if (!DoLastTarget()) ResendTarget(); + // in case we call the last target hotkey and the target was intercepted, regenerate the previous target + else if (wasIntercept && m_PreviousID != 0) + { + m_CurrentID = m_PreviousID; + m_AllowGround = m_PreviousGround; + m_CurFlags = m_PrevFlags; + + m_PreviousID = 0; + + Client.Instance.SendToClient(new Target(m_CurrentID, m_AllowGround, m_CurFlags)); + } } else if (forceQ || Config.GetBool("QueueTargets")) { @@ -876,8 +796,12 @@ public static bool DoLastTarget() if (CheckHealPoisonTarg(m_CurrentID, targ.Serial)) return false; - CancelClientTarget(); - m_HasTarget = false; + // only cancel when there is no intercept happening or no previous target we need to regenerate + if (!m_Intercept || m_PreviousID == 0) + { + m_HasTarget = false; + CancelClientTarget(); + } targ.TargID = m_CurrentID; @@ -929,7 +853,6 @@ public static void CancelTarget() m_FromGrabHotKey = false; - ScriptManager.SetVariableActive = false; ScriptManager.SetLastTargetActive = false; if (m_HasTarget) @@ -951,6 +874,7 @@ private static void CancelClientTarget() public static void Target(TargetInfo info) { + var wasIntercept = m_Intercept; if (m_Intercept) { OneTimeResponse(info); @@ -962,9 +886,27 @@ public static void Target(TargetInfo info) Client.Instance.SendToServer(new TargetResponse(info)); } - CancelClientTarget(); - m_HasTarget = false; - m_FromGrabHotKey = false; + // When the targeting is done from an intercepted target (i.e. a hotkey) and called by a script + // (thus calling this method and not TargetResponse), also check if previous "natural" target existed + // and resend it if that's the case. Otherwise cancel target. + if (wasIntercept && m_PreviousID != 0) + { + m_CurrentID = m_PreviousID; + m_AllowGround = m_PreviousGround; + m_CurFlags = m_PrevFlags; + m_HasTarget = false; + m_FromGrabHotKey = false; + + m_PreviousID = 0; + + ResendTarget(); + } + else + { + CancelClientTarget(); + m_HasTarget = false; + m_FromGrabHotKey = false; + } } public static void Target(Point3D pt) @@ -1221,6 +1163,8 @@ private static void TargetResponse(PacketReader p, PacketHandlerEventArgs args) m_HasTarget = false; m_FromGrabHotKey = false; + m_OnCancel?.Invoke(); + if (m_Intercept) { args.Block = true; diff --git a/Razor/Core/TextFilterManager.cs b/Razor/Core/TextFilterManager.cs index e5fe4949..31170f7d 100644 --- a/Razor/Core/TextFilterManager.cs +++ b/Razor/Core/TextFilterManager.cs @@ -33,6 +33,28 @@ public static class TextFilterManager public static List FilteredText = new List(); + public static void Initialize() + { + MessageManager.OnMobileMessage += HandleMobileMessage; + } + + public static void HandleMobileMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, + MessageType type, ushort hue, ushort font, string lang, string sourceName, + string text) + { + if (!Config.GetBool("EnableTextFilter")) + return; + + foreach (string filteredText in FilteredText) + { + if (text.IndexOf(filteredText, StringComparison.OrdinalIgnoreCase) != -1) + { + args.Block = true; + return; + } + } + } + public static void SetControls(ListBox filterTextList) { _filterTextList = filterTextList; @@ -62,22 +84,6 @@ public static void Save(XmlTextWriter xml) } } - public static bool IsFiltered(string text) - { - if (!Config.GetBool("EnableTextFilter")) - return false; - - foreach (string filteredText in FilteredText) - { - if (text.IndexOf(filteredText, StringComparison.OrdinalIgnoreCase) != -1) - { - return true; - } - } - - return false; - } - public static void Load(XmlElement node) { ClearAll(); diff --git a/Razor/Core/UOEntity.cs b/Razor/Core/UOEntity.cs index 72d98787..c2b3c966 100644 --- a/Razor/Core/UOEntity.cs +++ b/Razor/Core/UOEntity.cs @@ -39,40 +39,9 @@ public void Add(ushort key, ushort value) private ushort m_Hue; private bool m_Deleted; private ContextMenuList m_ContextMenu = new ContextMenuList(); - protected ObjectPropertyList m_ObjPropList = null; - - public ObjectPropertyList ObjPropList - { - get { return m_ObjPropList; } - } - - public virtual void SaveState(BinaryWriter writer) - { - writer.Write((uint) m_Serial); - writer.Write((int) m_Pos.X); - writer.Write((int) m_Pos.Y); - writer.Write((int) m_Pos.Z); - writer.Write((ushort) m_Hue); - } - - public UOEntity(BinaryReader reader, int version) - { - m_Serial = reader.ReadUInt32(); - m_Pos = new Point3D(reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32()); - m_Hue = reader.ReadUInt16(); - m_Deleted = false; - - m_ObjPropList = new ObjectPropertyList(this); - } - - public virtual void AfterLoad() - { - } public UOEntity(Serial ser) { - m_ObjPropList = new ObjectPropertyList(this); - m_Serial = ser; m_Deleted = false; } @@ -125,42 +94,5 @@ public override int GetHashCode() { return m_Serial.GetHashCode(); } - - public int OPLHash - { - get - { - if (m_ObjPropList != null) - return m_ObjPropList.Hash; - else - return 0; - } - set - { - if (m_ObjPropList != null) - m_ObjPropList.Hash = value; - } - } - - public bool ModifiedOPL - { - get { return m_ObjPropList.Customized; } - } - - public void ReadPropertyList(PacketReader p) - { - m_ObjPropList.Read(p); - } - - /*public Packet BuildOPLPacket() - { - return m_ObjPropList.BuildPacket(); - }*/ - - public void OPLChanged() - { - //Client.Instance.SendToClient( m_ObjPropList.BuildPacket() ); - Client.Instance.SendToClient(new OPLInfo(Serial, OPLHash)); - } } } \ No newline at end of file diff --git a/Razor/Core/Utility.cs b/Razor/Core/Utility.cs index f080e5a0..a61bf898 100644 --- a/Razor/Core/Utility.cs +++ b/Razor/Core/Utility.cs @@ -421,9 +421,7 @@ public static void LaunchBrowser(string url) { try { - Process.Start(url); - - /*if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { ProcessStartInfo psi = new ProcessStartInfo { @@ -439,7 +437,7 @@ public static void LaunchBrowser(string url) else { Process.Start("xdg-open", url); - }*/ + } } catch (Exception ex) { diff --git a/Razor/HotKeys/Misc.cs b/Razor/HotKeys/Misc.cs index dfbe3f32..06a9095e 100644 --- a/Razor/HotKeys/Misc.cs +++ b/Razor/HotKeys/Misc.cs @@ -445,9 +445,6 @@ private static void OnSetGrabItemHotBag(bool loc, Serial serial, Point3D pt, ush _grabHotBag = serial; Config.SetProperty("GrabHotBag", serial.Value.ToString()); - hb.ObjPropList.Add(Language.GetString(LocString.GrabHB)); - hb.OPLChanged(); - World.Player.SendMessage(MsgLevel.Force, "Grab Item HotBag Set"); } else diff --git a/Razor/HotKeys/SpecialMoves.cs b/Razor/HotKeys/SpecialMoves.cs index 89a06fb2..99cb8313 100644 --- a/Razor/HotKeys/SpecialMoves.cs +++ b/Razor/HotKeys/SpecialMoves.cs @@ -198,13 +198,13 @@ private static void ToggleWarPeace() Client.Instance.SendToServer(new SetWarMode(!World.Player.Warmode)); } - private static void ToggleWar() + public static void ToggleWar() { Client.Instance.ForceSendToClient(new SetWarMode(true)); Client.Instance.SendToServer(new SetWarMode(true)); } - private static void TogglePeace() + public static void TogglePeace() { Client.Instance.ForceSendToClient(new SetWarMode(false)); Client.Instance.SendToServer(new SetWarMode(false)); diff --git a/Razor/Macros/Actions.cs b/Razor/Macros/Actions.cs index d3a3fd81..a1013048 100644 --- a/Razor/Macros/Actions.cs +++ b/Razor/Macros/Actions.cs @@ -910,7 +910,6 @@ public override bool Perform() Client.Instance.SendToServer(new GumpResponse(World.Player.CurrentGumpS, World.Player.CurrentGumpI, m_ButtonID, m_Switches, m_TextEntries)); World.Player.HasGump = false; - World.Player.HasCompressedGump = false; return true; } diff --git a/Razor/Network/Handlers.cs b/Razor/Network/Handlers.cs index 48cee7e0..5451e624 100644 --- a/Razor/Network/Handlers.cs +++ b/Razor/Network/Handlers.cs @@ -48,7 +48,6 @@ public static void Initialize() { //Client -> Server handlers PacketHandler.RegisterClientToServerViewer(0x00, new PacketViewerCallback(CreateCharacter)); - //PacketHandler.RegisterClientToServerViewer(0x01, new PacketViewerCallback(Disconnect)); PacketHandler.RegisterClientToServerFilter(0x02, new PacketFilterCallback(MovementRequest)); PacketHandler.RegisterClientToServerFilter(0x05, new PacketFilterCallback(AttackRequest)); PacketHandler.RegisterClientToServerViewer(0x06, new PacketViewerCallback(ClientDoubleClick)); @@ -57,7 +56,6 @@ public static void Initialize() PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(ClientSingleClick)); PacketHandler.RegisterClientToServerViewer(0x12, new PacketViewerCallback(ClientTextCommand)); PacketHandler.RegisterClientToServerViewer(0x13, new PacketViewerCallback(EquipRequest)); - // 0x29 - UOKR confirm drop. 0 bytes payload (just a single byte, 0x29, no length or data) PacketHandler.RegisterClientToServerViewer(0x3A, new PacketViewerCallback(SetSkillLock)); PacketHandler.RegisterClientToServerViewer(0x5D, new PacketViewerCallback(PlayCharacter)); PacketHandler.RegisterClientToServerViewer(0x7D, new PacketViewerCallback(MenuResponse)); @@ -67,7 +65,6 @@ public static void Initialize() PacketHandler.RegisterClientToServerViewer(0xA0, new PacketViewerCallback(PlayServer)); PacketHandler.RegisterClientToServerViewer(0xB1, new PacketViewerCallback(ClientGumpResponse)); PacketHandler.RegisterClientToServerFilter(0xBF, new PacketFilterCallback(ExtendedClientCommand)); - //PacketHandler.RegisterClientToServerViewer( 0xD6, new PacketViewerCallback( BatchQueryProperties ) ); PacketHandler.RegisterClientToServerFilter(0xC2, new PacketFilterCallback(UnicodePromptSend)); PacketHandler.RegisterClientToServerViewer(0xD7, new PacketViewerCallback(ClientEncodedPacket)); PacketHandler.RegisterClientToServerViewer(0xF8, new PacketViewerCallback(CreateCharacter)); @@ -78,19 +75,22 @@ public static void Initialize() PacketHandler.RegisterServerToClientViewer(0x17, new PacketViewerCallback(NewMobileStatus)); PacketHandler.RegisterServerToClientViewer(0x1A, new PacketViewerCallback(WorldItem)); PacketHandler.RegisterServerToClientViewer(0x1B, new PacketViewerCallback(LoginConfirm)); - PacketHandler.RegisterServerToClientViewer(0x55, new PacketViewerCallback(CompleteLogin)); PacketHandler.RegisterServerToClientFilter(0x1C, new PacketFilterCallback(AsciiSpeech)); PacketHandler.RegisterServerToClientViewer(0x1D, new PacketViewerCallback(RemoveObject)); PacketHandler.RegisterServerToClientFilter(0x20, new PacketFilterCallback(MobileUpdate)); PacketHandler.RegisterServerToClientViewer(0x24, new PacketViewerCallback(BeginContainerContent)); PacketHandler.RegisterServerToClientFilter(0x25, new PacketFilterCallback(ContainerContentUpdate)); PacketHandler.RegisterServerToClientViewer(0x27, new PacketViewerCallback(LiftReject)); + PacketHandler.RegisterServerToClientViewer(0x2C, new PacketViewerCallback(ResurrectionGump)); PacketHandler.RegisterServerToClientViewer(0x2D, new PacketViewerCallback(MobileStatInfo)); PacketHandler.RegisterServerToClientFilter(0x2E, new PacketFilterCallback(EquipmentUpdate)); PacketHandler.RegisterServerToClientViewer(0x3A, new PacketViewerCallback(Skills)); PacketHandler.RegisterServerToClientFilter(0x3C, new PacketFilterCallback(ContainerContent)); PacketHandler.RegisterServerToClientViewer(0x4E, new PacketViewerCallback(PersonalLight)); PacketHandler.RegisterServerToClientViewer(0x4F, new PacketViewerCallback(GlobalLight)); + PacketHandler.RegisterServerToClientFilter(0x54, new PacketFilterCallback(PlaySoundEffect)); + PacketHandler.RegisterServerToClientViewer(0x55, new PacketViewerCallback(CompleteLogin)); + PacketHandler.RegisterServerToClientFilter(0x6D, new PacketFilterCallback(PlayMusic)); PacketHandler.RegisterServerToClientViewer(0x6F, new PacketViewerCallback(TradeRequest)); PacketHandler.RegisterServerToClientViewer(0x72, new PacketViewerCallback(ServerSetWarMode)); PacketHandler.RegisterServerToClientViewer(0x73, new PacketViewerCallback(PingResponse)); @@ -103,7 +103,6 @@ public static void Initialize() PacketHandler.RegisterServerToClientViewer(0xA2, new PacketViewerCallback(ManaUpdate)); PacketHandler.RegisterServerToClientViewer(0xA3, new PacketViewerCallback(StamUpdate)); PacketHandler.RegisterServerToClientViewer(0xA8, new PacketViewerCallback(ServerList)); - PacketHandler.RegisterServerToClientViewer(0xAB, new PacketViewerCallback(DisplayStringQuery)); PacketHandler.RegisterServerToClientViewer(0xAF, new PacketViewerCallback(DeathAnimation)); PacketHandler.RegisterServerToClientFilter(0xAE, new PacketFilterCallback(UnicodeSpeech)); PacketHandler.RegisterServerToClientViewer(0xB0, new PacketViewerCallback(SendGump)); @@ -115,35 +114,11 @@ public static void Initialize() PacketHandler.RegisterServerToClientFilter(0xC2, new PacketFilterCallback(UnicodePromptReceived)); PacketHandler.RegisterServerToClientFilter(0xC8, new PacketFilterCallback(SetUpdateRange)); PacketHandler.RegisterServerToClientFilter(0xCC, new PacketFilterCallback(OnLocalizedMessageAffix)); - PacketHandler.RegisterServerToClientViewer(0xD6, - new PacketViewerCallback(EncodedPacket)); //0xD6 "encoded" packets PacketHandler.RegisterServerToClientViewer(0xD8, new PacketViewerCallback(CustomHouseInfo)); - //PacketHandler.RegisterServerToClientFilter( 0xDC, new PacketFilterCallback( ServOPLHash ) ); PacketHandler.RegisterServerToClientViewer(0xDD, new PacketViewerCallback(CompressedGump)); - PacketHandler.RegisterServerToClientViewer(0xF0, - new PacketViewerCallback(RunUOProtocolExtention)); // Special RunUO protocol extentions (for KUOC/Razor) - - PacketHandler.RegisterServerToClientViewer(0xF3, new PacketViewerCallback(SAWorldItem)); - - PacketHandler.RegisterServerToClientViewer(0x2C, new PacketViewerCallback(ResurrectionGump)); - PacketHandler.RegisterServerToClientViewer(0xDF, new PacketViewerCallback(BuffDebuff)); - - PacketHandler.RegisterServerToClientFilter(0x54, new PacketFilterCallback(PlaySoundEffect)); - PacketHandler.RegisterServerToClientFilter(0x6D, new PacketFilterCallback(PlayMusic)); - } - - private static void DisplayStringQuery(PacketReader p, PacketHandlerEventArgs args) - { - // See also Packets.cs: StringQueryResponse - /*if ( MacroManager.AcceptActions ) - { - int serial = p.ReadInt32(); - byte type = p.ReadByte(); - byte index = p.ReadByte(); - - MacroManager.Action( new WaitForTextEntryAction( serial, type, index ) ); - }*/ + PacketHandler.RegisterServerToClientViewer(0xF0, new PacketViewerCallback(RunUOProtocolExtention)); + PacketHandler.RegisterServerToClientViewer(0xF3, new PacketViewerCallback(SAWorldItem)); } private static void SetUpdateRange(Packet p, PacketHandlerEventArgs args) @@ -152,74 +127,6 @@ private static void SetUpdateRange(Packet p, PacketHandlerEventArgs args) World.Player.VisRange = p.ReadByte(); } - private static void EncodedPacket(PacketReader p, PacketHandlerEventArgs args) - { - /*ushort id = p.ReadUInt16(); - - switch ( id ) - { - case 1: // object property list - { - Serial s = p.ReadUInt32(); - - if ( s.IsItem ) - { - Item item = World.FindItem( s ); - if ( item == null ) - World.AddItem( item=new Item( s ) ); - - item.ReadPropertyList( p ); - if ( item.ModifiedOPL ) - { - args.Block = true; - Client.Instance.SendToClient( item.ObjPropList.BuildPacket() ); - } - } - else if ( s.IsMobile ) - { - Mobile m = World.FindMobile( s ); - if ( m == null ) - World.AddMobile( m=new Mobile( s ) ); - - m.ReadPropertyList( p ); - if ( m.ModifiedOPL ) - { - args.Block = true; - Client.Instance.SendToClient( m.ObjPropList.BuildPacket() ); - } - } - break; - } - }*/ - } - - private static void ServOPLHash(Packet p, PacketHandlerEventArgs args) - { - /*Serial s = p.ReadUInt32(); - int hash = p.ReadInt32(); - - if ( s.IsItem ) - { - Item item = World.FindItem( s ); - if ( item != null && item.OPLHash != hash ) - { - item.OPLHash = hash; - p.Seek( -4, SeekOrigin.Current ); - p.Write( (uint)item.OPLHash ); - } - } - else if ( s.IsMobile ) - { - Mobile m = World.FindMobile( s ); - if ( m != null && m.OPLHash != hash ) - { - m.OPLHash = hash; - p.Seek( -4, SeekOrigin.Current ); - p.Write( (uint)m.OPLHash ); - } - }*/ - } - private static void ClientSingleClick(PacketReader p, PacketHandlerEventArgs args) { Serial ser = p.ReadUInt32(); @@ -381,8 +288,6 @@ private static void ExtendedClientCommand(Packet p, PacketHandlerEventArgs args) p.Write((byte) 0x30); } - //using ( StreamWriter w = new StreamWriter( "bf24.txt", true ) ) - // w.WriteLine( "{0} : 0x{1:X2}", Engine.MistedDateTime.ToString( "HH:mm:ss.ffff" ), b ); break; } } @@ -502,8 +407,6 @@ private static void PlayCharacter(PacketReader p, PacketHandlerEventArgs args) if (Engine.MainWindow != null) Engine.MainWindow.SafeAction(s => s.UpdateControlLocks()); - - //Client.TranslateLogin( World.OrigPlayerName, World.ShardName ); } private static void ServerList(PacketReader p, PacketHandlerEventArgs args) @@ -551,14 +454,12 @@ private static void LiftRequest(PacketReader p, PacketHandlerEventArgs args) } DragDropManager.Drag(item, amount, true); - //Client.Instance.SendToClient( new RemoveObject( serial ) ); // remove the object from the client view args.Block = true; } if (Macros.MacroManager.AcceptActions) { MacroManager.Action(new LiftAction(serial, amount, iid)); - //MacroManager.Action( new PauseAction( TimeSpan.FromMilliseconds( Config.GetInt( "ObjectDelay" ) ) ) ); } ScriptManager.AddToScript($"lift {serial} {amount}"); @@ -566,15 +467,10 @@ private static void LiftRequest(PacketReader p, PacketHandlerEventArgs args) private static void LiftReject(PacketReader p, PacketHandlerEventArgs args) { - /* - if ( ActionQueue.FilterLiftReject() ) - args.Block = true; - */ - int reason = p.ReadByte(); + p.ReadByte(); if (!DragDropManager.LiftReject()) args.Block = true; - //MacroManager.PlayError( MacroError.LiftRej ); } private static void EquipRequest(PacketReader p, PacketHandlerEventArgs args) @@ -1335,7 +1231,6 @@ private static void MobileStatus(PacketReader p, PacketHandlerEventArgs args) m.Hits = p.ReadUInt16(); m.HitsMax = p.ReadUInt16(); - //p.ReadBoolean();//CanBeRenamed if (p.ReadBoolean()) m.CanRename = true; @@ -1791,52 +1686,6 @@ private static void WorldItem(PacketReader p, PacketHandlerEventArgs args) private static void SAWorldItem(PacketReader p, PacketHandlerEventArgs args) { - /* - New World Item Packet - PacketID: 0xF3 - PacketLen: 24 - Format: - - BYTE - 0xF3 packetId - WORD - 0x01 - BYTE - ArtDataID: 0x00 if the item uses art from TileData table, 0x02 if the item uses art from MultiData table) - DWORD - item Serial - WORD - item ID - BYTE - item direction (same as old) - WORD - amount - WORD - amount - WORD - X - WORD - Y - SBYTE - Z - BYTE - item light - WORD - item Hue - BYTE - item flags (same as old packet) - */ - - // Post-7.0.9.0 - /* - New World Item Packet - PacketID: 0xF3 - PacketLen: 26 - Format: - - BYTE - 0xF3 packetId - WORD - 0x01 - BYTE - ArtDataID: 0x00 if the item uses art from TileData table, 0x02 if the item uses art from MultiData table) - DWORD - item Serial - WORD - item ID - BYTE - item direction (same as old) - WORD - amount - WORD - amount - WORD - X - WORD - Y - SBYTE - Z - BYTE - item light - WORD - item Hue - BYTE - item flags (same as old packet) - WORD ??? - */ - ushort _unk1 = p.ReadUInt16(); byte _artDataID = p.ReadByte(); @@ -1918,284 +1767,96 @@ New World Item Packet args.Block = WallStaticFilter.MakeWallStatic(item); } - public static System.Text.StringBuilder SpellPowerwordsBuilder { get; set; } = new System.Text.StringBuilder(Config.GetString("SpellFormat")); - - private static void ResetSpellPowerwordsBuilder() - { - SpellPowerwordsBuilder.Remove(0, SpellPowerwordsBuilder.Length); - SpellPowerwordsBuilder.Insert(0, Config.GetString("SpellFormat")); - } - - public static void HandleSpeech(Packet p, PacketHandlerEventArgs args, Serial ser, ushort body, - MessageType type, ushort hue, ushort font, string lang, string name, string text) - { - if (World.Player == null) - return; - - if (type == MessageType.Spell) - { - Spell s = Spell.Get(text.Trim()); - bool replaced = false; - - if (Config.GetBool("OverrideSpellFormat") && s != null) - { - ResetSpellPowerwordsBuilder(); - - System.Text.StringBuilder sb = SpellPowerwordsBuilder; - sb.Replace(@"{power}", s.WordsOfPower); - string spell = Language.GetString(s.Name); - sb.Replace(@"{spell}", spell); - sb.Replace(@"{name}", spell); - sb.Replace(@"{circle}", s.Circle.ToString()); - - string newText = sb.ToString(); - - if (newText != null && newText != "" && newText != text) - { - Client.Instance.SendToClient(new AsciiMessage(ser, body, MessageType.Spell, s.GetHue(hue), font, - name, newText)); - - replaced = true; - args.Block = true; - } - } - - if (!replaced && Config.GetBool("ForceSpellHue")) - { - p.Seek(10, SeekOrigin.Begin); - if (s != null) - p.Write((ushort) s.GetHue(hue)); - else - p.Write((ushort) Config.GetInt("NeutralSpellHue")); - } - } - else if (ser.IsMobile && type == MessageType.Label) - { - Mobile m = World.FindMobile(ser); - if (m != null /*&& ( m.Name == null || m.Name == "" || m.Name == "(Not Seen)" )*/ && - m.Name.IndexOf(text) != 5 && m != World.Player && !(text.StartsWith("(") && text.EndsWith(")"))) - m.Name = text; - } - /*else if ( Spell.Get( text.Trim() ) != null ) - { // send fake spells to bottom left - p.Seek( 3, SeekOrigin.Begin ); - p.Write( (uint)0xFFFFFFFF ); - }*/ - else - { - if (ser == Serial.MinusOne && name == "System") - { - if (Config.GetBool("FilterSnoopMsg") && text.IndexOf(World.Player.Name) == -1 && - text.StartsWith("You notice") && text.IndexOf("attempting to peek into") != -1 && - text.IndexOf("belongings") != -1) - { - args.Block = true; - return; - } - - if (text.StartsWith("You've committed a criminal act") || text.StartsWith("You are now a criminal")) - { - World.Player.ResetCriminalTimer(); - } - - // Overhead message override - OverheadManager.DisplayOverheadMessage(text); - } - - if (Config.GetBool("ShowContainerLabels") && ser.IsItem) - { - Item item = World.FindItem(ser); - - if (item == null || !item.IsContainer) - return; - - foreach (ContainerLabels.ContainerLabel label in ContainerLabels.ContainerLabelList) - { - // Check if its the serial match and if the text matches the name (since we override that for the label) - if (Serial.Parse(label.Id) == ser && - (item.ItemID.ItemData.Name.Equals(text) || - label.Alias.Equals(text, StringComparison.InvariantCultureIgnoreCase))) - { - string labelDisplay = - $"{Config.GetString("ContainerLabelFormat").Replace("{label}", label.Label).Replace("{type}", text)}"; - - //ContainerLabelStyle - if (Config.GetInt("ContainerLabelStyle") == 0) - { - Client.Instance.SendToClient(new AsciiMessage(ser, item.ItemID.Value, MessageType.Label, - label.Hue, 3, Language.CliLocName, labelDisplay)); - } - else - { - Client.Instance.SendToClient(new UnicodeMessage(ser, item.ItemID.Value, - MessageType.Label, label.Hue, 3, Language.CliLocName, "", labelDisplay)); - } - - // block the actual message from coming through since we have it in the label - args.Block = true; - - ContainerLabels.LastContainerLabelDisplayed = ser; - - break; - } - } - } - - if ((type == MessageType.Emote || type == MessageType.Regular || type == MessageType.Whisper || - type == MessageType.Yell) && ser.IsMobile && ser != World.Player.Serial) - { - if (ser.IsMobile && IgnoreAgent.IsIgnored(ser)) - { - args.Block = true; - return; - } - - if (ser.IsMobile && TextFilterManager.IsFiltered(text)) - { - args.Block = true; - return; - } - - if (Config.GetBool("ForceSpeechHue")) - { - p.Seek(10, SeekOrigin.Begin); - p.Write((ushort) Config.GetInt("SpeechHue")); - } - } - - if (!ser.IsValid || ser == World.Player.Serial || ser.IsItem) - { - SystemMessages.Add(text); - } - - if (Config.GetBool("FilterSystemMessages") && ser == Serial.MinusOne || ser == Serial.Zero) - { - if (!MessageQueue.Enqueue(ser, null, body, type, hue, font, lang, name, text)) - { - args.Block = true; - } - } - } - } - public static void AsciiSpeech(Packet p, PacketHandlerEventArgs args) { - // 0, 1, 2 - Serial serial = p.ReadUInt32(); // 3, 4, 5, 6 - ushort body = p.ReadUInt16(); // 7, 8 - MessageType type = (MessageType) p.ReadByte(); // 9 - ushort hue = p.ReadUInt16(); // 10, 11 + Serial serial = p.ReadUInt32(); + ushort graphic = p.ReadUInt16(); + MessageType type = (MessageType)p.ReadByte(); + ushort hue = p.ReadUInt16(); ushort font = p.ReadUInt16(); - string name = p.ReadStringSafe(30); + string sourceName = p.ReadStringSafe(30); string text = p.ReadStringSafe(); - if (World.Player != null && serial == Serial.Zero && body == 0 && type == MessageType.Regular && - hue == 0xFFFF && font == 0xFFFF && name == "SYSTEM") - { - args.Block = true; - - Client.Instance.SendToServer(new ACKTalk()); - } - else - { - HandleSpeech(p, args, serial, body, type, hue, font, "A", name, text); - - if (!serial.IsValid) - { - BandageTimer.OnAsciiMessage(text); - } - - GateTimer.OnAsciiMessage(text); - } + MessageManager.HandleMessage(p, args, serial, graphic, type, hue, font, "A", sourceName, text); } public static void UnicodeSpeech(Packet p, PacketHandlerEventArgs args) { - // 0, 1, 2 - Serial serial = p.ReadUInt32(); // 3, 4, 5, 6 - ushort body = p.ReadUInt16(); // 7, 8 - MessageType type = (MessageType) p.ReadByte(); // 9 - ushort hue = p.ReadUInt16(); // 10, 11 + Serial serial = p.ReadUInt32(); + ushort graphic = p.ReadUInt16(); + MessageType type = (MessageType)p.ReadByte(); + ushort hue = p.ReadUInt16(); ushort font = p.ReadUInt16(); string lang = p.ReadStringSafe(4); string name = p.ReadStringSafe(30); string text = p.ReadUnicodeStringSafe(); - HandleSpeech(p, args, serial, body, type, hue, font, lang, name, text); - - if (!serial.IsValid) - { - BandageTimer.OnAsciiMessage(text); - } + MessageManager.HandleMessage(p, args, serial, graphic, type, hue, font, lang, name, text); } private static void OnLocalizedMessage(Packet p, PacketHandlerEventArgs args) { - // 0, 1, 2 - Serial serial = p.ReadUInt32(); // 3, 4, 5, 6 - ushort body = p.ReadUInt16(); // 7, 8 - MessageType type = (MessageType) p.ReadByte(); // 9 - ushort hue = p.ReadUInt16(); // 10, 11 + Serial serial = p.ReadUInt32(); + ushort graphic = p.ReadUInt16(); + MessageType type = (MessageType)p.ReadByte(); + ushort hue = p.ReadUInt16(); ushort font = p.ReadUInt16(); - int num = p.ReadInt32(); + int cliloc = p.ReadInt32(); string name = p.ReadStringSafe(30); - string ext_str = p.ReadUnicodeStringLESafe(); + string parameters = p.ReadUnicodeStringLESafe(); - if ((num >= 3002011 && num < 3002011 + 64) || // reg spells - (num >= 1060509 && num < 1060509 + 16) || // necro - (num >= 1060585 && num < 1060585 + 10) || // chiv - (num >= 1060493 && num < 1060493 + 10) || // chiv - (num >= 1060595 && num < 1060595 + 6) || // bush - (num >= 1060610 && num < 1060610 + 8)) // ninj + if ((cliloc >= 3002011 && cliloc < 3002011 + 64) || // reg spells + (cliloc >= 1060509 && cliloc < 1060509 + 16) || // necro + (cliloc >= 1060585 && cliloc < 1060585 + 10) || // chiv + (cliloc >= 1060493 && cliloc < 1060493 + 10) || // chiv + (cliloc >= 1060595 && cliloc < 1060595 + 6) || // bush + (cliloc >= 1060610 && cliloc < 1060610 + 8)) // ninj { type = MessageType.Spell; } - BandageTimer.OnLocalizedMessage(num); + string text = Language.ClilocFormat(cliloc, parameters); - try - { - string text = Language.ClilocFormat(num, ext_str); - HandleSpeech(p, args, serial, body, type, hue, font, Language.CliLocName.ToUpper(), name, text); - } - catch (Exception e) - { - Engine.LogCrash(new Exception($"Exception in Ultima.dll cliloc: {num}, {ext_str}", - e)); - } + MessageManager.HandleMessage(p, args, serial, graphic, type, hue, font, Language.CliLocName.ToUpper(), name, text); } private static void OnLocalizedMessageAffix(Packet p, PacketHandlerEventArgs phea) { - // 0, 1, 2 - Serial serial = p.ReadUInt32(); // 3, 4, 5, 6 - ushort body = p.ReadUInt16(); // 7, 8 - MessageType type = (MessageType) p.ReadByte(); // 9 - ushort hue = p.ReadUInt16(); // 10, 11 + Serial serial = p.ReadUInt32(); + ushort body = p.ReadUInt16(); + MessageType type = (MessageType)p.ReadByte(); + ushort hue = p.ReadUInt16(); ushort font = p.ReadUInt16(); - int num = p.ReadInt32(); + int cliloc = p.ReadInt32(); byte affixType = p.ReadByte(); - string name = p.ReadStringSafe(30); + string sourceName = p.ReadStringSafe(30); string affix = p.ReadStringSafe(); string args = p.ReadUnicodeStringSafe(); - if ((num >= 3002011 && num < 3002011 + 64) || // reg spells - (num >= 1060509 && num < 1060509 + 16) || // necro - (num >= 1060585 && num < 1060585 + 10) || // chiv - (num >= 1060493 && num < 1060493 + 10) || // chiv - (num >= 1060595 && num < 1060595 + 6) || // bush - (num >= 1060610 && num < 1060610 + 8) // ninj + if ((cliloc >= 3002011 && cliloc < 3002011 + 64) || // reg spells + (cliloc >= 1060509 && cliloc < 1060509 + 16) || // necro + (cliloc >= 1060585 && cliloc < 1060585 + 10) || // chiv + (cliloc >= 1060493 && cliloc < 1060493 + 10) || // chiv + (cliloc >= 1060595 && cliloc < 1060595 + 6) || // bush + (cliloc >= 1060610 && cliloc < 1060610 + 8) // ninj ) { type = MessageType.Spell; } string text; - if ((affixType & 1) != 0) // prepend - text = $"{affix}{Language.ClilocFormat(num, args)}"; - else // 0 == append, 2 = system - text = $"{Language.ClilocFormat(num, args)}{affix}"; - HandleSpeech(p, phea, serial, body, type, hue, font, Language.CliLocName.ToUpper(), name, text); + if ((affixType & 1) != 0) + { + // prepend + text = $"{affix}{Language.ClilocFormat(cliloc, args)}"; + } + else + { + // 0 == append, 2 = system + text = $"{Language.ClilocFormat(cliloc, args)}{affix}"; + } + + MessageManager.HandleMessage(p, phea, serial, body, type, hue, font, Language.CliLocName.ToUpper(), sourceName, text); } private static void SendGump(PacketReader p, PacketHandlerEventArgs args) @@ -2206,6 +1867,7 @@ private static void SendGump(PacketReader p, PacketHandlerEventArgs args) World.Player.CurrentGumpS = p.ReadUInt32(); World.Player.CurrentGumpI = p.ReadUInt32(); World.Player.HasGump = true; + World.Player.GumpList.Add(World.Player.CurrentGumpI, new PlayerData.GumpInfo(World.Player.CurrentGumpS, World.Player.CurrentGumpI)); //byte[] data = p.CopyBytes( 11, p.Length - 11 ); if (Macros.MacroManager.AcceptActions && @@ -2224,8 +1886,9 @@ private static void ClientGumpResponse(PacketReader p, PacketHandlerEventArgs ar uint gumpId = p.ReadUInt32(); int buttonId = p.ReadInt32(); + World.Player.GumpList.Remove(gumpId); + World.Player.HasGump = false; - World.Player.HasCompressedGump = false; int switchCount = p.ReadInt32(); if (switchCount < 0 || switchCount > 2000) @@ -2292,7 +1955,6 @@ private static void ExtendedPacket(PacketReader p, PacketHandlerEventArgs args) if (World.Player != null) { World.Player.HasGump = false; - World.Player.HasCompressedGump = false; } break; @@ -2378,18 +2040,36 @@ private static void ExtendedPacket(PacketReader p, PacketHandlerEventArgs args) case 0x19: // stat locks { - if (p.ReadByte() == 0x02) + var subCmd = p.ReadByte(); + + switch (subCmd) { - Mobile m = World.FindMobile(p.ReadUInt32()); - if (World.Player == m && m != null) + case 0x02: { - p.ReadByte(); // 0? + Mobile m = World.FindMobile(p.ReadUInt32()); + if (World.Player == m && m != null) + { + p.ReadByte(); // 0? + + byte locks = p.ReadByte(); + + World.Player.StrLock = (LockType) ((locks >> 4) & 3); + World.Player.DexLock = (LockType) ((locks >> 2) & 3); + World.Player.IntLock = (LockType) (locks & 3); + } - byte locks = p.ReadByte(); + break; + } + case 0x00: + { + Mobile m = World.FindMobile(p.ReadUInt32()); + if (m != null) + { + byte deadStatus = p.ReadByte(); + m.Dead = deadStatus == 0x1; + } - World.Player.StrLock = (LockType) ((locks >> 4) & 3); - World.Player.DexLock = (LockType) ((locks >> 2) & 3); - World.Player.IntLock = (LockType) (locks & 3); + break; } } @@ -2524,14 +2204,11 @@ private static void OnPartyMessage(PacketReader p, PacketHandlerEventArgs args) case 0x04: // 3 = private, 4 = public { - //Serial from = p.ReadUInt32(); - //string text = p.ReadUnicodeStringSafe(); break; } case 0x07: // party invite { - //Serial leader = p.ReadUInt32(); PartyLeader = p.ReadUInt32(); if (Config.GetBool("BlockPartyInvites")) @@ -2822,7 +2499,6 @@ private static void CompressedGump(PacketReader p, PacketHandlerEventArgs args) World.Player.CurrentGumpS = p.ReadUInt32(); World.Player.CurrentGumpI = p.ReadUInt32(); - World.Player.HasCompressedGump = true; if (Macros.MacroManager.AcceptActions && MacroManager.Action(new WaitForGumpAction(World.Player.CurrentGumpI))) @@ -2890,6 +2566,11 @@ private static void CompressedGump(PacketReader p, PacketHandlerEventArgs args) } World.Player.CurrentGumpStrings.AddRange(gumpStrings); + + if (World.Player.GumpList.ContainsKey(World.Player.CurrentGumpI)) + World.Player.GumpList.Remove(World.Player.CurrentGumpI); + + World.Player.GumpList.Add(World.Player.CurrentGumpI, new PlayerData.GumpInfo(World.Player.CurrentGumpS, World.Player.CurrentGumpI, gumpStrings)); World.Player.CurrentGumpRawData = layout; // Get raw data of current gump } catch @@ -2938,25 +2619,14 @@ private static List ParseGumpString(string[] gumpPieces, string[] gumpLi { case "croppedtext": gumpText.Add(gumpLines[int.Parse(gumpParams[6])]); - // CroppedText [x] [y] [width] [height] [color] [text-id] - // Adds a text field to the gump. gump is similar to the text command, but the text is cropped to the defined area. - //gump.AddControl(new CroppedText(gump, gumpParams, gumpLines), currentGUMPPage); - //(gump.LastControl as CroppedText).Hue = 1; break; case "htmlgump": gumpText.Add(gumpLines[int.Parse(gumpParams[5])]); - // HtmlGump [x] [y] [width] [height] [text-id] [background] [scrollbar] - // Defines a text-area where Html-commands are allowed. - // [background] and [scrollbar] can be 0 or 1 and define whether the background is transparent and a scrollbar is displayed. - // gump.AddControl(new HtmlGumpling(gump, gumpParams, gumpLines), currentGUMPPage); break; case "text": gumpText.Add(gumpLines[int.Parse(gumpParams[4])]); - // Text [x] [y] [color] [text-id] - // Defines the position and color of a text (data) entry. - //gump.AddControl(new TextLabel(gump, gumpParams, gumpLines), currentGUMPPage); break; } } @@ -3043,7 +2713,7 @@ private static void BuffDebuff(PacketReader p, PacketHandlerEventArgs args) break; case 0x0: // remove - if (World.Player != null) // && World.Player.BuffsDebuffs.Any(b => b.BuffIcon == buff)) + if (World.Player != null) { if (Config.GetBool("ShowBuffDebuffOverhead")) { @@ -3103,10 +2773,6 @@ private static void UnicodePromptSend(Packet p, PacketHandlerEventArgs args) if (World.Player == null) return; - //uint serial = p.ReadUInt32(); - //uint id = p.ReadUInt32(); - //uint type = p.ReadUInt32(); - uint serial = p.ReadUInt32(); uint id = p.ReadUInt32(); uint type = p.ReadUInt32(); @@ -3149,11 +2815,6 @@ private static void UnicodePromptReceived(Packet p, PacketHandlerEventArgs args) } ScriptManager.AddToScript($"waitforprompt {id}"); - - //args.Block = true; - - //string lang = p.ReadStringSafe(4); - //string message = p.ReadUnicodeStringSafe(); } private static void PlaySoundEffect(Packet p, PacketHandlerEventArgs args) diff --git a/Razor/Network/Packets.cs b/Razor/Network/Packets.cs index 2220d832..bde01329 100644 --- a/Razor/Network/Packets.cs +++ b/Razor/Network/Packets.cs @@ -266,6 +266,15 @@ public TargetResponse(uint id, Item item) : base(0x6C, 19) } } + public sealed class RenamePacket : Packet + { + public RenamePacket(uint serial, string newName) : base(0x75, 35) + { + Write(serial); + WriteAsciiFixed(newName, 30); + } + } + public sealed class TargetCancelResponse : Packet { public TargetCancelResponse(uint id) : base(0x6C, 19) @@ -736,6 +745,8 @@ public GumpResponse(uint serial, uint tid, int bid, int[] switches, GumpTextEntr Write((ushort) (gte.Text.Length * 2)); WriteBigUniFixed(gte.Text, gte.Text.Length); } + + World.Player.GumpList.Remove(tid); } } @@ -1062,51 +1073,6 @@ public ResyncReq() : base(0x22, 3) } } - public sealed class ACKTalk : Packet - { - public ACKTalk() : base(0x03) - { - EnsureCapacity(40); - Write((byte) 0x20); - Write((byte) 0x00); - Write((byte) 0x34); - Write((byte) 0x00); - Write((byte) 0x03); - Write((byte) 0xdb); - Write((byte) 0x13); - Write((byte) 0x14); - Write((byte) 0x3f); - Write((byte) 0x45); - Write((byte) 0x2c); - Write((byte) 0x58); - Write((byte) 0x0f); - Write((byte) 0x5d); - Write((byte) 0x44); - Write((byte) 0x2e); - Write((byte) 0x50); - Write((byte) 0x11); - Write((byte) 0xdf); - Write((byte) 0x75); - Write((byte) 0x5c); - Write((byte) 0xe0); - Write((byte) 0x3e); - Write((byte) 0x71); - Write((byte) 0x4f); - Write((byte) 0x31); - Write((byte) 0x34); - Write((byte) 0x05); - Write((byte) 0x4e); - Write((byte) 0x18); - Write((byte) 0x1e); - Write((byte) 0x72); - Write((byte) 0x0f); - Write((byte) 0x59); - Write((byte) 0xad); - Write((byte) 0xf5); - Write((byte) 0x00); - } - } - public sealed class WorldItem : Packet { public WorldItem(Item item) : base(0x1A) diff --git a/Razor/Platform.cs b/Razor/Platform.cs index 186f342e..8705959d 100644 --- a/Razor/Platform.cs +++ b/Razor/Platform.cs @@ -469,14 +469,6 @@ internal static ushort GetAsyncKeyState(int key) return 0; } - internal static IntPtr CaptureScreen(IntPtr handle, bool isFullScreen, string msgStr) - { - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - return Win32Platform.CaptureScreen(handle, isFullScreen, msgStr); - else - return IntPtr.Zero; - } - internal static void BringToFront(IntPtr window) { try diff --git a/Razor/Razor.csproj b/Razor/Razor.csproj index a90c3870..2d803b2b 100644 --- a/Razor/Razor.csproj +++ b/Razor/Razor.csproj @@ -172,6 +172,7 @@ + @@ -292,6 +293,7 @@ + @@ -332,9 +334,6 @@ Code - - Code - Code @@ -605,4 +604,4 @@ xcopy /S /Q /Y "$(SolutionDir)etc\*" "$(SolutionDir)bin\Win32\$(Configuration)\" - \ No newline at end of file + diff --git a/Razor/Scripts/AgentCommands.cs b/Razor/Scripts/AgentCommands.cs index 5f94ed07..2209017d 100644 --- a/Razor/Scripts/AgentCommands.cs +++ b/Razor/Scripts/AgentCommands.cs @@ -39,11 +39,11 @@ public static void Register() Interpreter.RegisterCommandHandler("sell", SellAgentCommand); } - private static bool RestockAgentCommand(string command, Argument[] args, bool quiet, bool force) + private static bool RestockAgentCommand(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: restock (number) ['set']"); + throw new RunTimeError("Usage: restock (number) ['set']"); } int agentNum = args[0].AsInt(); @@ -70,7 +70,7 @@ private static bool RestockAgentCommand(string command, Argument[] args, bool qu return true; } - private static bool UseOnceCommand(string command, Argument[] args, bool quiet, bool force) + private static bool UseOnceCommand(string command, Variable[] args, bool quiet, bool force) { bool add = false; bool container = false; @@ -103,11 +103,11 @@ private static bool UseOnceCommand(string command, Argument[] args, bool quiet, return true; } - private static bool OrganizerAgentCommand(string command, Argument[] args, bool quiet, bool force) + private static bool OrganizerAgentCommand(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: organizer (number) ['set']"); + throw new RunTimeError("Usage: organizer (number) ['set']"); } int agentNum = args[0].AsInt(); @@ -134,11 +134,11 @@ private static bool OrganizerAgentCommand(string command, Argument[] args, bool return true; } - private static bool ScavAgentCommand(string command, Argument[] args, bool quiet, bool force) + private static bool ScavAgentCommand(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: scavenger ['clear'/'add'/'on'/'off'/'set']"); + throw new RunTimeError("Usage: scavenger ['clear'/'add'/'on'/'off'/'set']"); } bool clear = false; @@ -200,7 +200,7 @@ private static bool ScavAgentCommand(string command, Argument[] args, bool quiet return true; } - private static bool SellAgentCommand(string command, Argument[] args, bool quiet, bool force) + private static bool SellAgentCommand(string command, Variable[] args, bool quiet, bool force) { SellAgent.Instance.SetHotBag(); diff --git a/Razor/Scripts/Aliases.cs b/Razor/Scripts/Aliases.cs index f209f39b..5bcf6427 100644 --- a/Razor/Scripts/Aliases.cs +++ b/Razor/Scripts/Aliases.cs @@ -34,6 +34,7 @@ public static void Register() Interpreter.RegisterAliasHandler("righthand", RightHand); Interpreter.RegisterAliasHandler("lefthand", LeftHand); Interpreter.RegisterAliasHandler("hand", Hand); + Interpreter.RegisterAliasHandler("ground", Ground); } private static uint RightHand(string alias) @@ -63,6 +64,11 @@ private static uint Hand(string alias) : 0; } + private static uint Ground(string alias) + { + return 0; + } + private static uint Backpack(string alias) { if (World.Player == null || World.Player.Backpack == null) diff --git a/Razor/Scripts/Commands.cs b/Razor/Scripts/Commands.cs index 3f7c2e27..7a09f2da 100644 --- a/Razor/Scripts/Commands.cs +++ b/Razor/Scripts/Commands.cs @@ -19,10 +19,8 @@ #endregion using System; -using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Windows.Forms; using Assistant.Core; using Assistant.HotKeys; using Assistant.Scripts.Engine; @@ -72,7 +70,7 @@ public static void Register() // Hotkey execution Interpreter.RegisterCommandHandler("hotkey", Hotkey); //HotKeyAction - + Interpreter.RegisterCommandHandler("overhead", HeadMsg); //OverheadMessageAction Interpreter.RegisterCommandHandler("headmsg", HeadMsg); //OverheadMessageAction @@ -116,12 +114,12 @@ public static void Register() private static string[] virtues = new string[3] { "honor", "sacrifice", "valor" }; - private static bool Virtue(string command, Argument[] args, bool quiet, bool force) + private static bool Virtue(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0 || !virtues.Contains(args[0].AsString())) { - throw new RunTimeError(null, "Usage: virtue ('honor'/'sacrifice'/'valor')"); + throw new RunTimeError("Usage: virtue ('honor'/'sacrifice'/'valor')"); } switch (args[0].AsString()) @@ -140,7 +138,7 @@ private static bool Virtue(string command, Argument[] args, bool quiet, bool for return true; } - private static bool ClearAll(string command, Argument[] args, bool quiet, bool force) + private static bool ClearAll(string command, Variable[] args, bool quiet, bool force) { DragDropManager.GracefulStop(); // clear drag/drop queue @@ -150,7 +148,7 @@ private static bool ClearAll(string command, Argument[] args, bool quiet, bool f return true; } - private static bool SetLastTarget(string command, Argument[] args, bool quiet, bool force) + private static bool SetLastTarget(string command, Variable[] args, bool quiet, bool force) { if (!ScriptManager.SetLastTargetActive) { @@ -169,63 +167,96 @@ private static bool SetLastTarget(string command, Argument[] args, bool quiet, b return false; } - private static bool SetVar(string command, Argument[] args, bool quiet, bool force) + private enum SetVarState { - if (args.Length < 1) + INITIAL_PROMPT, + WAIT_FOR_TARGET, + COMPLETE, + }; + + private static SetVarState _setVarState = SetVarState.INITIAL_PROMPT; + + private static bool SetVar(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length < 1 || args.Length > 2) { - throw new RunTimeError(null, "Usage: setvar ('variable') [timeout]"); + throw new RunTimeError("Usage: setvar ('variable') [serial]"); } - string varname = args[0].AsString(); - - ScriptVariables.ScriptVariable variable = ScriptVariables.GetVariable(varname); + string name = args[0].AsString(false); - if (variable == null) + if (args.Length == 2) { - World.Player.SendMessage(Config.GetInt("SysColor"), $"'{varname}' not found, creating new variable"); + // No need to target anything. We have the serial. + var serial = args[1].AsSerial(); - variable = new ScriptVariables.ScriptVariable(varname, new TargetInfo()); + if (force) + { + Interpreter.SetVariable(name, serial.ToString(), true); + return true; + } - ScriptVariables.ScriptVariableList.Add(variable); + if (ScriptVariables.GetVariable(name) == Serial.MinusOne && !quiet) + { + CommandHelper.SendMessage($"'{name}' not found, creating new variable", quiet); + } - ScriptVariables.RegisterVariable(varname); + ScriptVariables.RegisterVariable(name, serial); + CommandHelper.SendMessage($"'{name}' script variable updated to '{serial}'", quiet); - ScriptManager.RedrawScriptVariables(); + Assistant.Engine.MainWindow.SaveScriptVariables(); + + return true; } - Interpreter.Timeout(args.Length == 2 ? args[1].AsUInt() : 30000, () => { return true; }); - + Interpreter.Timeout(args.Length == 2 ? args[1].AsUInt() : 30000, () => { _setVarState = SetVarState.INITIAL_PROMPT; return true; } ); - if (!ScriptManager.SetVariableActive) + switch (_setVarState) { - variable.SetTarget(); - ScriptManager.SetVariableActive = true; + case SetVarState.INITIAL_PROMPT: + if (ScriptVariables.GetVariable(name) == Serial.MinusOne) + { + CommandHelper.SendMessage($"'{name}' not found, creating new variable", quiet); + } + World.Player.SendMessage(MsgLevel.Force, $"Select target for variable '{name}'"); - return false; - } + _setVarState = SetVarState.WAIT_FOR_TARGET; - if (variable.TargetWasSet) - { - Interpreter.ClearTimeout(); - ScriptManager.SetVariableActive = false; - return true; + Targeting.OneTimeTarget((ground, serial, pt, gfx) => + { + ScriptVariables.RegisterVariable(name, serial); + CommandHelper.SendMessage($"'{name}' script variable updated to '{serial}'", quiet); + + Assistant.Engine.MainWindow.SaveScriptVariables(); + _setVarState = SetVarState.COMPLETE; + }, + () => + { + _setVarState = SetVarState.COMPLETE; + }); + break; + case SetVarState.WAIT_FOR_TARGET: + break; + case SetVarState.COMPLETE: + _setVarState = SetVarState.INITIAL_PROMPT; + return true; } return false; } - private static bool Stop(string command, Argument[] args, bool quiet, bool force) + private static bool Stop(string command, Variable[] args, bool quiet, bool force) { ScriptManager.StopScript(); return true; } - private static bool Hotkey(string command, Argument[] args, bool quiet, bool force) + private static bool Hotkey(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: hotkey ('name of hotkey') OR (hotkeyId)"); + throw new RunTimeError("Usage: hotkey ('name of hotkey') OR (hotkeyId)"); } string query = args[0].AsString(); @@ -234,7 +265,7 @@ private static bool Hotkey(string command, Argument[] args, bool quiet, bool for if (hk == null) { - throw new RunTimeError(null, $"{command} - Hotkey '{query}' not found"); + throw new RunTimeError($"{command} - Hotkey '{query}' not found"); } hk.Callback(); @@ -242,21 +273,12 @@ private static bool Hotkey(string command, Argument[] args, bool quiet, bool for return true; } - private static bool WaitForGump(string command, Argument[] args, bool quiet, bool force) + private static bool WaitForGump(string command, Variable[] args, bool quiet, bool force) { - if (args.Length < 1) - { - throw new RunTimeError(null, "Usage: waitforgump (gumpId/'any') [timeout]"); - } - uint gumpId = 0; bool strict = false; - if (args[0].AsString().IndexOf("any", StringComparison.InvariantCultureIgnoreCase) != -1) - { - strict = false; - } - else + if (args.Length > 0) { gumpId = Utility.ToUInt32(args[0].AsString(), 0); @@ -269,7 +291,7 @@ private static bool WaitForGump(string command, Argument[] args, bool quiet, boo Interpreter.Timeout(args.Length == 2 ? args[1].AsUInt() : 30000, () => { return true; }); if ((World.Player.HasGump || World.Player.HasCompressedGump) && - (World.Player.CurrentGumpI == gumpId || !strict || gumpId == 0)) + (World.Player.GumpList.ContainsKey(gumpId) || !strict || gumpId == 0)) { Interpreter.ClearTimeout(); return true; @@ -278,11 +300,11 @@ private static bool WaitForGump(string command, Argument[] args, bool quiet, boo return false; } - private static bool WaitForMenu(string command, Argument[] args, bool quiet, bool force) + private static bool WaitForMenu(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: waitformenu (menuId/'any') [timeout]"); + throw new RunTimeError("Usage: waitformenu (menuId/'any') [timeout]"); } uint menuId = 0; @@ -303,11 +325,11 @@ private static bool WaitForMenu(string command, Argument[] args, bool quiet, boo return false; } - private static bool WaitForPrompt(string command, Argument[] args, bool quiet, bool force) + private static bool WaitForPrompt(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: waitforprompt (promptId/'any') [timeout]"); + throw new RunTimeError("Usage: waitforprompt (promptId/'any') [timeout]"); } uint promptId = 0; @@ -341,11 +363,11 @@ private static bool WaitForPrompt(string command, Argument[] args, bool quiet, b private static string[] abilities = new string[4] {"primary", "secondary", "stun", "disarm"}; - private static bool SetAbility(string command, Argument[] args, bool quiet, bool force) + private static bool SetAbility(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1 || !abilities.Contains(args[0].AsString())) { - throw new RunTimeError(null, "Usage: setability ('primary'/'secondary'/'stun'/'disarm') ['on'/'off']"); + throw new RunTimeError("Usage: setability ('primary'/'secondary'/'stun'/'disarm') ['on'/'off']"); } if (args.Length == 2 && args[1].AsString() == "on" || args.Length == 1) @@ -379,11 +401,11 @@ private static bool SetAbility(string command, Argument[] args, bool quiet, bool private static string[] hands = new string[4] {"left", "right", "both", "hands"}; - private static bool ClearHands(string command, Argument[] args, bool quiet, bool force) + private static bool ClearHands(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0 || !hands.Contains(args[0].AsString())) { - throw new RunTimeError(null, "Usage: clearhands ('left'/'right'/'both')"); + throw new RunTimeError("Usage: clearhands ('left'/'right'/'both')"); } switch (args[0].AsString()) @@ -403,12 +425,12 @@ private static bool ClearHands(string command, Argument[] args, bool quiet, bool return true; } - private static bool DClickType(string command, Argument[] args, bool quiet, bool force) + private static bool DClickType(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, - "Usage: dclicktype ('name of item') OR (graphicID) [inrangecheck (true/false)/backpack]"); + throw new RunTimeError( + "Usage: dclicktype ('name of item') OR (graphicID) [src] [hue] [qty] [range]"); } string gfxStr = args[0].AsString(); @@ -416,41 +438,28 @@ private static bool DClickType(string command, Argument[] args, bool quiet, bool List items; List mobiles = new List(); - bool inRangeCheck = false; - bool backpack = false; - - if (args.Length == 2) - { - if (args[1].AsString().IndexOf("pack", StringComparison.InvariantCultureIgnoreCase) > 0) - { - backpack = true; - } - else - { - inRangeCheck = args[1].AsBool(); - } - } + (Serial src, int hue, int qty, int range) = CommandHelper.ParseFindArguments(args); // No graphic id, maybe searching by name? if (gfx == 0) { - items = CommandHelper.GetItemsByName(gfxStr, backpack, inRangeCheck); + items = CommandHelper.GetItemsByName(gfxStr, hue, src, (short)qty, range); if (items.Count == 0) // no item found, search mobile by name { - mobiles = CommandHelper.GetMobilesByName(gfxStr, inRangeCheck); + mobiles = CommandHelper.GetMobilesByName(gfxStr, range); } } else // Provided graphic id for type, check backpack first (same behavior as DoubleClickAction in macros { ushort id = Utility.ToUInt16(gfxStr, 0); - items = CommandHelper.GetItemsById(id, backpack, inRangeCheck); - + items = CommandHelper.GetItemsById(id, hue, src, (short)qty, range); + // Still no item? Mobile check! if (items.Count == 0) { - mobiles = CommandHelper.GetMobilesById(id, inRangeCheck); + mobiles = CommandHelper.GetMobilesById(id, range); } } @@ -470,11 +479,11 @@ private static bool DClickType(string command, Argument[] args, bool quiet, bool return true; } - private static bool DClick(string command, Argument[] args, bool quiet, bool force) + private static bool DClick(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: dclick (serial) or dclick ('left'/'right'/'hands')"); + throw new RunTimeError("Usage: dclick (serial) or dclick ('left'/'right'/'hands')"); } if (hands.Contains(args[0].AsString())) @@ -509,7 +518,7 @@ private static bool DClick(string command, Argument[] args, bool quiet, bool for if (!serial.IsValid) { - throw new RunTimeError(null, "dclick - invalid serial"); + throw new RunTimeError("dclick - invalid serial"); } PlayerData.DoubleClick(serial); @@ -518,11 +527,11 @@ private static bool DClick(string command, Argument[] args, bool quiet, bool for return true; } - private static bool DropItem(string command, Argument[] args, bool quiet, bool force) + private static bool DropItem(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: drop (serial) (x y z/layername)"); + throw new RunTimeError("Usage: drop (serial) (x y z/layername)"); } Serial serial = args[0].AsString().IndexOf("ground", StringComparison.InvariantCultureIgnoreCase) > 0 @@ -570,11 +579,11 @@ private static bool DropItem(string command, Argument[] args, bool quiet, bool f return true; } - private static bool DropRelLoc(string command, Argument[] args, bool quiet, bool force) + private static bool DropRelLoc(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 2) { - throw new RunTimeError(null, "Usage: droprelloc (x) (y)"); + throw new RunTimeError("Usage: droprelloc (x) (y)"); } int x = args[0].AsInt(); @@ -596,18 +605,18 @@ private static bool DropRelLoc(string command, Argument[] args, bool quiet, bool private static int _lastLiftId; - private static bool LiftItem(string command, Argument[] args, bool quiet, bool force) + private static bool LiftItem(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: lift (serial) [amount]"); + throw new RunTimeError("Usage: lift (serial) [amount]"); } Serial serial = args[0].AsSerial(); if (!serial.IsValid) { - throw new RunTimeError(null, $"{command} - Invalid serial"); + throw new RunTimeError($"{command} - Invalid serial"); } ushort amount = 1; @@ -652,20 +661,50 @@ private static bool LiftItem(string command, Argument[] args, bool quiet, bool f private static int _lastLiftTypeId; - private static bool LiftType(string command, Argument[] args, bool quiet, bool force) + private static bool LiftType(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: lifttype (gfx/'name of item') [amount]"); + throw new RunTimeError("Usage: lifttype ('name') OR ('graphic') [qty] [src] [hue] [range]"); } string gfxStr = args[0].AsString(); ushort gfx = Utility.ToUInt16(gfxStr, 0); - ushort amount = 1; - if (args.Length == 2) + + ushort qty = 1; + Serial src = World.Player.Backpack.Serial; + int hue = -1; + int range = -1; + + if (args.Length > 1) { - amount = Utility.ToUInt16(args[1].AsString(), 1); + qty = (ushort)Math.Max(CommandHelper.IsNumberOrAny(args[1].AsString()), 1); + } + + if (args.Length > 2) + { + var tSrc = args[2].AsSerial(); + if (tSrc != 0 && tSrc != World.Player.Backpack.Serial && tSrc != World.Player.Serial) + { + throw new RunTimeError("src can be only 'ground', 'backpack' or 'self'"); + } + src = tSrc; + } + + if (args.Length > 3) + { + hue = CommandHelper.IsNumberOrAny(args[3].AsString()); + } + + if (args.Length > 4) + { + range = CommandHelper.IsNumberOrAny(args[1].AsString()); + } + + if (range <= 0) + { + range = 18; } if (_lastLiftTypeId > 0) @@ -690,7 +729,7 @@ private static bool LiftType(string command, Argument[] args, bool quiet, bool f // No graphic id, maybe searching by name? if (gfx == 0) { - item = World.Player.Backpack?.FindItemByName(gfxStr, true); + item = CommandHelper.GetItemsByName(gfxStr, hue, src, (short)qty, range).FirstOrDefault(); if (item == null) { @@ -700,15 +739,15 @@ private static bool LiftType(string command, Argument[] args, bool quiet, bool f } else { - item = World.Player.Backpack?.FindItemByID(gfx); + item = CommandHelper.GetItemsById(gfx, hue, src, (short)qty, range).FirstOrDefault(); } if (item != null) { - if (item.Amount < amount) - amount = item.Amount; + if (item.Amount < qty) + qty = item.Amount; - _lastLiftTypeId = DragDropManager.Drag(item, amount); + _lastLiftTypeId = DragDropManager.Drag(item, qty); } else { @@ -720,11 +759,11 @@ private static bool LiftType(string command, Argument[] args, bool quiet, bool f return false; } - private static bool Walk(string command, Argument[] args, bool quiet, bool force) + private static bool Walk(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: walk ('direction')"); + throw new RunTimeError("Usage: walk ('direction')"); } if (ScriptManager.LastWalk + TimeSpan.FromSeconds(0.4) >= DateTime.UtcNow) @@ -740,11 +779,11 @@ private static bool Walk(string command, Argument[] args, bool quiet, bool force return true; } - private static bool UseSkill(string command, Argument[] args, bool quiet, bool force) + private static bool UseSkill(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: skill ('skill name'/'last')"); + throw new RunTimeError("Usage: skill ('skill name'/'last')"); } int skillId = 0; @@ -773,28 +812,28 @@ private static bool UseSkill(string command, Argument[] args, bool quiet, bool f return true; } - private static bool Pause(string command, Argument[] args, bool quiet, bool force) + private static bool Pause(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) - throw new RunTimeError(null, "Usage: pause/wait (timeout)"); + throw new RunTimeError("Usage: pause/wait (timeout)"); Interpreter.Pause(args[0].AsUInt()); return true; } - private static bool Attack(string command, Argument[] args, bool quiet, bool force) + private static bool Attack(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: attack (serial)"); + throw new RunTimeError("Usage: attack (serial)"); } Serial serial = args[0].AsSerial(); if (!serial.IsValid) { - throw new RunTimeError(null, $"{command} - Invalid serial"); + throw new RunTimeError($"{command} - Invalid serial"); } if (serial == Targeting.LastTargetInfo.Serial) @@ -810,11 +849,11 @@ private static bool Attack(string command, Argument[] args, bool quiet, bool for return true; } - private static bool Cast(string command, Argument[] args, bool quiet, bool force) + private static bool Cast(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: cast 'name of spell'"); + throw new RunTimeError("Usage: cast 'name of spell'"); } Spell spell = int.TryParse(args[0].AsString(), out int spellnum) @@ -827,17 +866,17 @@ private static bool Cast(string command, Argument[] args, bool quiet, bool force } else { - throw new RunTimeError(null, $"{command} - Spell name or number not valid"); + throw new RunTimeError($"{command} - Spell name or number not valid"); } return true; } - private static bool HeadMsg(string command, Argument[] args, bool quiet, bool force) + private static bool HeadMsg(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: overhead ('text') [color] [serial]"); + throw new RunTimeError("Usage: overhead ('text') [color] [serial]"); } if (args.Length == 1) @@ -863,11 +902,11 @@ private static bool HeadMsg(string command, Argument[] args, bool quiet, bool fo return true; } - private static bool SysMsg(string command, Argument[] args, bool quiet, bool force) + private static bool SysMsg(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: sysmsg ('text') [color]"); + throw new RunTimeError("Usage: sysmsg ('text') [color]"); } if (args.Length == 1) @@ -882,7 +921,7 @@ private static bool SysMsg(string command, Argument[] args, bool quiet, bool for return true; } - private static bool ClearSysMsg(string command, Argument[] args, bool quiet, bool force) + private static bool ClearSysMsg(string command, Variable[] args, bool quiet, bool force) { SystemMessages.Messages.Clear(); @@ -891,11 +930,11 @@ private static bool ClearSysMsg(string command, Argument[] args, bool quiet, boo private static DressList _lastDressList; - private static bool DressCommand(string command, Argument[] args, bool quiet, bool force) + private static bool DressCommand(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: dress ('name of dress list')"); + throw new RunTimeError("Usage: dress ('name of dress list')"); } if (_lastDressList == null) @@ -925,7 +964,7 @@ private static bool DressCommand(string command, Argument[] args, bool quiet, bo private static bool _undressAll; private static bool _undressLayer; - private static bool UnDressCommand(string command, Argument[] args, bool quiet, bool force) + private static bool UnDressCommand(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0 && !_undressAll) // full naked! @@ -950,7 +989,7 @@ private static bool UnDressCommand(string command, Argument[] args, bool quiet, } else { - throw new RunTimeError(null, $"'{args[0].AsString()}' not found"); + throw new RunTimeError($"'{args[0].AsString()}' not found"); } } } @@ -965,51 +1004,62 @@ private static bool UnDressCommand(string command, Argument[] args, bool quiet, return false; } - private static bool GumpResponse(string command, Argument[] args, bool quiet, bool force) + private static bool GumpResponse(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: gumpresponse (buttondId)"); - //throw new RunTimeError(null, "Usage: gumpresponse (buttondId) [option] ['text1'|fieldId] ['text2'|fieldId]"); + throw new RunTimeError("Usage: gumpresponse (buttondId) [gumpId]"); } int buttonId = args[0].AsInt(); - /*private int m_ButtonID; - private int[] m_Switches; - private GumpTextEntry[] m_TextEntries;*/ + var gumpId = World.Player.CurrentGumpI; + + if (args.Length > 1) + gumpId = args[1].AsUInt(); + + if (!World.Player.GumpList.ContainsKey(gumpId)) + return true; - //Assistant.Macros.GumpResponseAction|9|0|0 - //Assistant.Macros.GumpResponseAction|1|0|1|0&Hello How are you? - //Assistant.Macros.GumpResponseAction|501|0|2|1&box2|0&box1 + var gumpS = World.Player.GumpList[gumpId].GumpSerial; - Client.Instance.SendToClient(new CloseGump(World.Player.CurrentGumpI)); - Client.Instance.SendToServer(new GumpResponse(World.Player.CurrentGumpS, World.Player.CurrentGumpI, + Client.Instance.SendToServer(new GumpResponse(gumpS, gumpId, buttonId, new int[] { }, new GumpTextEntry[] { })); + Client.Instance.SendToClient(new CloseGump(gumpId)); World.Player.HasGump = false; - World.Player.HasCompressedGump = false; return true; } - private static bool GumpClose(string command, Argument[] args, bool quiet, bool force) + private static bool GumpClose(string command, Variable[] args, bool quiet, bool force) { - Client.Instance.SendToClient(new CloseGump(World.Player.CurrentGumpI)); - Client.Instance.SendToServer(new GumpResponse(World.Player.CurrentGumpS, World.Player.CurrentGumpI, 0, + var gumpI = World.Player.CurrentGumpI; + + if (args.Length > 0) + { + gumpI = args[0].AsUInt(); + } + + if (!World.Player.GumpList.ContainsKey(gumpI)) + return true; + var gumpS = World.Player.GumpList[gumpI].GumpSerial; + + + Client.Instance.SendToClient(new CloseGump(gumpI)); + Client.Instance.SendToServer(new GumpResponse(gumpS, gumpI, 0, new int[] { }, new GumpTextEntry[] { })); World.Player.HasGump = false; - World.Player.HasCompressedGump = false; return true; } - private static bool ContextMenu(string command, Argument[] args, bool quiet, bool force) + private static bool ContextMenu(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 2) { - throw new RunTimeError(null, "Usage: menu (serial) (index)"); + throw new RunTimeError("Usage: menu (serial) (index)"); } Serial s = args[0].AsSerial(); @@ -1031,11 +1081,11 @@ private static bool ContextMenu(string command, Argument[] args, bool quiet, boo return true; } - private static bool MenuResponse(string command, Argument[] args, bool quiet, bool force) + private static bool MenuResponse(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 2) { - throw new RunTimeError(null, "Usage: menuresponse (index) (menuId) [hue]"); + throw new RunTimeError("Usage: menuresponse (index) (menuId) [hue]"); } ushort index = args[0].AsUShort(); @@ -1051,18 +1101,18 @@ private static bool MenuResponse(string command, Argument[] args, bool quiet, bo return true; } - private static bool PromptResponse(string command, Argument[] args, bool quiet, bool force) + private static bool PromptResponse(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: promptresponse ('response to the prompt')"); + throw new RunTimeError("Usage: promptresponse ('response to the prompt')"); } World.Player.ResponsePrompt(args[0].AsString()); return true; } - private static bool LastTarget(string command, Argument[] args, bool quiet, bool force) + private static bool LastTarget(string command, Variable[] args, bool quiet, bool force) { if (!Targeting.DoLastTarget()) Targeting.ResendTarget(); @@ -1070,11 +1120,11 @@ private static bool LastTarget(string command, Argument[] args, bool quiet, bool return true; } - private static bool PlayScript(string command, Argument[] args, bool quiet, bool force) + private static bool PlayScript(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: script 'name of script'"); + throw new RunTimeError("Usage: script 'name of script'"); } ScriptManager.PlayScript(args[0].AsString()); @@ -1095,11 +1145,11 @@ private static bool PlayScript(string command, Argument[] args, bool quiet, bool {"agility", 3848} }; - private static bool Potion(string command, Argument[] args, bool quiet, bool force) + private static bool Potion(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: potion ('type')"); + throw new RunTimeError("Usage: potion ('type')"); } Item pack = World.Player.Backpack; @@ -1122,52 +1172,60 @@ private static bool Potion(string command, Argument[] args, bool quiet, bool for } else { - throw new RunTimeError(null, $"{command} - Unknown potion type"); + throw new RunTimeError($"{command} - Unknown potion type"); } return true; } - private static bool WaitForSysMsg(string command, Argument[] args, bool quiet, bool force) + /// + /// Wait for specific system message in journal + /// + /// Command + /// Args + /// Quiet mode - not used + /// Flag determine removing message in journal or not + /// + private static bool WaitForSysMsg(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: waitforsysmsg 'message to wait for' [timeout]"); + throw new RunTimeError("Usage: waitforsysmsg 'message to wait for' [timeout]"); } - - if (SystemMessages.Exists(args[0].AsString())) + + if (SystemMessages.Exists(args[0].AsString(), !force)) { Interpreter.ClearTimeout(); return true; } - Interpreter.Timeout(args.Length > 1 ? args[1].AsUInt() : 30000, () => { return true; }); + Interpreter.Timeout(args.Length > 1 ? args[1].AsUInt() : 30000, () => true ); return false; } - private static bool Random(string command, Argument[] args, bool quiet, bool force) + private static bool Random(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: random 'max value'"); + throw new RunTimeError("Usage: random 'max value'"); } int max = args[0].AsInt(); - World.Player.SendMessage(MsgLevel.Info, $"Random: {Utility.Random(1, max)}"); + CommandHelper.SendInfo($"Random: {Utility.Random(1, max)}", quiet); return true; } - private static bool ClearDragDrop(string command, Argument[] args, bool quiet, bool force) + private static bool ClearDragDrop(string command, Variable[] args, bool quiet, bool force) { DragDropManager.GracefulStop(); return true; } - - private static bool Interrupt(string command, Argument[] args, bool quiet, bool force) + + private static bool Interrupt(string command, Variable[] args, bool quiet, bool force) { Spell.Interrupt(); diff --git a/Razor/Scripts/Engine/Interpreter.cs b/Razor/Scripts/Engine/Interpreter.cs index 8356358b..d1a7b76f 100644 --- a/Razor/Scripts/Engine/Interpreter.cs +++ b/Razor/Scripts/Engine/Interpreter.cs @@ -26,11 +26,8 @@ namespace Assistant.Scripts.Engine { public class RunTimeError : Exception { - public ASTNode Node; - - public RunTimeError(ASTNode node, string error) : base(error) + public RunTimeError(string error) : base(error) { - Node = node; } } @@ -48,7 +45,7 @@ public static int ToInt(string token) else if (int.TryParse(token, out val)) return val; - throw new RunTimeError(null, "Cannot convert argument to int"); + throw new RunTimeError("Cannot convert argument to int"); } public static uint ToUInt(string token) @@ -63,7 +60,7 @@ public static uint ToUInt(string token) else if (uint.TryParse(token, out val)) return val; - throw new RunTimeError(null, "Cannot convert argument to uint"); + throw new RunTimeError("Cannot convert argument to uint"); } public static ushort ToUShort(string token) @@ -78,7 +75,7 @@ public static ushort ToUShort(string token) else if (ushort.TryParse(token, out val)) return val; - throw new RunTimeError(null, "Cannot convert argument to ushort"); + throw new RunTimeError("Cannot convert argument to ushort"); } public static double ToDouble(string token) @@ -88,7 +85,7 @@ public static double ToDouble(string token) if (double.TryParse(token, out val)) return val; - throw new RunTimeError(null, "Cannot convert argument to double"); + throw new RunTimeError("Cannot convert argument to double"); } public static bool ToBool(string token) @@ -98,13 +95,14 @@ public static bool ToBool(string token) if (bool.TryParse(token, out val)) return val; - throw new RunTimeError(null, "Cannot convert argument to bool"); + throw new RunTimeError("Cannot convert argument to bool"); } } internal class Scope { - private Dictionary _namespace = new Dictionary(); + private Dictionary _namespace = new Dictionary(); + private readonly HashSet _ignoreList = new HashSet(); public readonly ASTNode StartNode; public readonly Scope Parent; @@ -115,9 +113,9 @@ public Scope(Scope parent, ASTNode start) StartNode = start; } - public Argument GetVar(string name) + public Variable GetVariable(string name) { - Argument arg; + Variable arg; if (_namespace.TryGetValue(name, out arg)) return arg; @@ -125,109 +123,138 @@ public Argument GetVar(string name) return null; } - public void SetVar(string name, Argument val) + public void SetVariable(string name, Variable val) { _namespace[name] = val; } - public void ClearVar(string name) + public void ClearVariable(string name) { _namespace.Remove(name); } + + public bool ExistVariable(string name) + { + return _namespace.ContainsKey(name); + } + + public void AddIgnore(Serial serial) + { + _ignoreList.Add(serial); + } + + public void ClearIgnore() + { + _ignoreList.Clear(); + } + + public bool CheckIgnored(Serial serial) + { + return _ignoreList.Contains(serial); + } + } - public class Argument + public class Variable { - private ASTNode _node; - private Script _script; + private string _value; - public Argument(Script script, ASTNode node) + public Variable(string value) { - _node = node; - _script = script; + _value = value; } // Treat the argument as an integer public int AsInt() { - if (_node.Lexeme == null) - throw new RunTimeError(_node, "Cannot convert argument to int"); + if (_value == null) + throw new RunTimeError("Cannot convert argument to int"); // Try to resolve it as a scoped variable first - var arg = _script.Lookup(_node.Lexeme); + var arg = Interpreter.GetVariable(_value); if (arg != null) return arg.AsInt(); - return TypeConverter.ToInt(_node.Lexeme); + return TypeConverter.ToInt(_value); } // Treat the argument as an unsigned integer public uint AsUInt() { - if (_node.Lexeme == null) - throw new RunTimeError(_node, "Cannot convert argument to uint"); + if (_value == null) + throw new RunTimeError("Cannot convert argument to uint"); // Try to resolve it as a scoped variable first - var arg = _script.Lookup(_node.Lexeme); + var arg = Interpreter.GetVariable(_value); if (arg != null) return arg.AsUInt(); - return TypeConverter.ToUInt(_node.Lexeme); + return TypeConverter.ToUInt(_value); } public ushort AsUShort() { - if (_node.Lexeme == null) - throw new RunTimeError(_node, "Cannot convert argument to ushort"); + if (_value == null) + throw new RunTimeError("Cannot convert argument to ushort"); // Try to resolve it as a scoped variable first - var arg = _script.Lookup(_node.Lexeme); + var arg = Interpreter.GetVariable(_value); if (arg != null) return arg.AsUShort(); - return TypeConverter.ToUShort(_node.Lexeme); + return TypeConverter.ToUShort(_value); } // Treat the argument as a serial or an alias. Aliases will // be automatically resolved to serial numbers. public uint AsSerial() { - if (_node.Lexeme == null) - throw new RunTimeError(_node, "Cannot convert argument to serial"); + if (_value == null) + throw new RunTimeError("Cannot convert argument to serial"); // Try to resolve it as a scoped variable first - var arg = _script.Lookup(_node.Lexeme); + var arg = Interpreter.GetVariable(_value); if (arg != null) return arg.AsSerial(); // Resolve it as a global alias next - uint serial = Interpreter.GetAlias(_node.Lexeme); + uint serial = Interpreter.GetAlias(_value); if (serial != uint.MaxValue) return serial; - return AsUInt(); + try + { + return AsUInt(); + } + catch (RunTimeError) + { } + + return Serial.MinusOne; } // Treat the argument as a string - public string AsString() + public string AsString(bool resolve = true) { - if (_node.Lexeme == null) - throw new RunTimeError(_node, "Cannot convert argument to string"); + if (_value == null) + throw new RunTimeError("Cannot convert argument to string"); - // Try to resolve it as a scoped variable first - var arg = _script.Lookup(_node.Lexeme); - if (arg != null) - return arg.AsString(); + if (resolve) + { + // Try to resolve it as a scoped variable first + var arg = Interpreter.GetVariable(_value); + if (arg != null) + return arg.AsString(); + } - return _node.Lexeme; + return _value; } public bool AsBool() { - if (_node.Lexeme == null) - throw new RunTimeError(_node, "Cannot convert argument to bool"); + if (_value == null) + throw new RunTimeError("Cannot convert argument to bool"); - return TypeConverter.ToBool(_node.Lexeme); + return TypeConverter.ToBool(_value); } public override bool Equals(object obj) @@ -235,7 +262,7 @@ public override bool Equals(object obj) if (obj == null) return false; - Argument arg = obj as Argument; + Variable arg = obj as Variable; if (arg == null) return false; @@ -243,12 +270,12 @@ public override bool Equals(object obj) return Equals(arg); } - public bool Equals(Argument other) + public bool Equals(Variable other) { if (other == null) return false; - return (other._node.Lexeme == _node.Lexeme); + return (other._value == _value); } } @@ -256,41 +283,17 @@ public class Script { private ASTNode _statement; - // Delegate fires when this script executes a new statement - public Action StatementExecuted; - - private Scope _scope; - - public Argument Lookup(string name) + public int CurrentLine { - var scope = _scope; - Argument result = null; - - while (scope != null) + get { - result = scope.GetVar(name); - if (result != null) - return result; - - scope = scope.Parent; + return _statement == null ? 0 : _statement.LineNumber; } - - return result; - } - - private void PushScope(ASTNode node) - { - _scope = new Scope(_scope, node); - } - - private void PopScope() - { - _scope = _scope.Parent; } - private Argument[] ConstructArguments(ref ASTNode node) + private Variable[] ConstructArguments(ref ASTNode node) { - List args = new List(); + List args = new List(); node = node.Next(); @@ -306,10 +309,12 @@ private Argument[] ConstructArguments(ref ASTNode node) case ASTNodeType.LESS_THAN_OR_EQUAL: case ASTNodeType.GREATER_THAN: case ASTNodeType.GREATER_THAN_OR_EQUAL: + case ASTNodeType.IN: + case ASTNodeType.AS: return args.ToArray(); } - args.Add(new Argument(this, node)); + args.Add(new Variable(node.Lexeme)); node = node.Next(); } @@ -327,9 +332,11 @@ public Script(ASTNode root) { // Set current to the first statement _statement = root.FirstChild(); + } - // Create a default scope - _scope = new Scope(null, _statement); + public void Initialize() + { + Interpreter.PushScope(_statement); } public bool ExecuteNext() @@ -338,12 +345,12 @@ public bool ExecuteNext() return false; if (_statement.Type != ASTNodeType.STATEMENT) - throw new RunTimeError(_statement, "Invalid script"); + throw new RunTimeError("Invalid script"); var node = _statement.FirstChild(); if (node == null) - throw new RunTimeError(_statement, "Invalid statement"); + throw new RunTimeError("Invalid statement"); int depth = 0; @@ -351,13 +358,13 @@ public bool ExecuteNext() { case ASTNodeType.IF: { - PushScope(node); + Interpreter.PushScope(node); var expr = node.FirstChild(); var result = EvaluateExpression(ref expr); // Advance to next statement - _statement = _statement.Next(); + Advance(); // Evaluated true. Jump right into execution. if (result) @@ -386,7 +393,7 @@ public bool ExecuteNext() // Evaluated true. Jump right into execution if (result) { - _statement = _statement.Next(); + Advance(); break; } } @@ -396,7 +403,7 @@ public bool ExecuteNext() if (depth == 0) { // Jump into the else clause - _statement = _statement.Next(); + Advance(); break; } } @@ -408,11 +415,11 @@ public bool ExecuteNext() depth--; } - _statement = _statement.Next(); + Advance(); } if (_statement == null) - throw new RunTimeError(node, "If with no matching endif"); + throw new RunTimeError("If with no matching endif"); break; } @@ -437,16 +444,16 @@ public bool ExecuteNext() depth--; } - _statement = _statement.Next(); + Advance(); } if (_statement == null) - throw new RunTimeError(node, "If with no matching endif"); + throw new RunTimeError("If with no matching endif"); break; case ASTNodeType.ENDIF: - PopScope(); - _statement = _statement.Next(); + Interpreter.PopScope(); + Advance(); break; case ASTNodeType.ELSE: // If we hit the else statement during normal advancing, skip over it. The only way @@ -469,26 +476,26 @@ public bool ExecuteNext() depth--; } - _statement = _statement.Next(); + Advance(); } if (_statement == null) - throw new RunTimeError(node, "If with no matching endif"); + throw new RunTimeError("If with no matching endif"); break; case ASTNodeType.WHILE: { // When we first enter the loop, push a new scope - if (_scope.StartNode != node) + if (Interpreter.CurrentScope.StartNode != node) { - PushScope(node); + Interpreter.PushScope(node); } var expr = node.FirstChild(); var result = EvaluateExpression(ref expr); // Advance to next statement - _statement = _statement.Next(); + Advance(); // The expression evaluated false, so keep advancing until // we hit an endwhile statement. @@ -508,16 +515,16 @@ public bool ExecuteNext() { if (depth == 0) { - PopScope(); + Interpreter.PopScope(); // Go one past the endwhile so the loop doesn't repeat - _statement = _statement.Next(); + Advance(); break; } depth--; } - _statement = _statement.Next(); + Advance(); } } break; @@ -548,7 +555,7 @@ public bool ExecuteNext() } if (_statement == null) - throw new RunTimeError(node, "Unexpected endwhile"); + throw new RunTimeError("Unexpected endwhile"); break; case ASTNodeType.FOR: @@ -557,47 +564,42 @@ public bool ExecuteNext() var iterName = node.GetHashCode().ToString(); // When we first enter the loop, push a new scope - if (_scope.StartNode != node) + if (Interpreter.CurrentScope.StartNode != node) { - PushScope(node); + Interpreter.PushScope(node); // Grab the arguments var max = node.FirstChild(); if (max.Type != ASTNodeType.INTEGER) - throw new RunTimeError(max, "Invalid for loop syntax"); + throw new RunTimeError("Invalid for loop syntax"); // Create a dummy argument that acts as our loop variable - var iter = new ASTNode(ASTNodeType.INTEGER, "0", node, 0); - - _scope.SetVar(iterName, new Argument(this, iter)); + Interpreter.SetVariable(iterName, "0"); } else { // Increment the iterator argument - var arg = _scope.GetVar(iterName); - - var iter = new ASTNode(ASTNodeType.INTEGER, (arg.AsUInt() + 1).ToString(), node, 0); - - _scope.SetVar(iterName, new Argument(this, iter)); + var arg = Interpreter.GetVariable(iterName); + Interpreter.SetVariable(iterName, (arg.AsUInt() + 1).ToString()); } // Check loop condition - var i = _scope.GetVar(iterName); + var i = Interpreter.GetVariable(iterName); // Grab the max value to iterate to node = node.FirstChild(); - var end = new Argument(this, node); + var end = new Variable(node.Lexeme); if (i.AsUInt() < end.AsUInt()) { // enter the loop - _statement = _statement.Next(); + Advance(); } else { // Walk until the end of the loop - _statement = _statement.Next(); + Advance(); depth = 0; @@ -605,7 +607,8 @@ public bool ExecuteNext() { node = _statement.FirstChild(); - if (node.Type == ASTNodeType.FOR) + if (node.Type == ASTNodeType.FOR || + node.Type == ASTNodeType.FOREACH) { depth++; } @@ -613,20 +616,101 @@ public bool ExecuteNext() { if (depth == 0) { - PopScope(); + Interpreter.PopScope(); // Go one past the end so the loop doesn't repeat - _statement = _statement.Next(); + Advance(); break; } depth--; } - _statement = _statement.Next(); + Advance(); } } } break; + case ASTNodeType.FOREACH: + { + // foreach VAR in LIST + // The iterator's name is the hash code of the for loop's ASTNode. + var varName = node.FirstChild().Lexeme; + var listName = node.FirstChild().Next().Lexeme; + var iterName = node.GetHashCode().ToString(); + + // When we first enter the loop, push a new scope + if (Interpreter.CurrentScope.StartNode != node) + { + Interpreter.PushScope(node); + + // Create a dummy argument that acts as our iterator object + Interpreter.SetVariable(iterName, "0"); + + // Make the user-chosen variable have the value for the front of the list + var arg = Interpreter.GetListValue(listName, 0); + + if (arg != null) + Interpreter.SetVariable(varName, arg.AsString()); + else + Interpreter.ClearVariable(varName); + } + else + { + // Increment the iterator argument + var idx = Interpreter.GetVariable(iterName).AsInt() + 1; + Interpreter.SetVariable(iterName, idx.ToString()); + + // Update the user-chosen variable + var arg = Interpreter.GetListValue(listName, idx); + + if (arg != null) + Interpreter.SetVariable(varName, arg.AsString()); + else + Interpreter.ClearVariable(varName); + } + + // Check loop condition + var i = Interpreter.GetVariable(varName); + + if (i != null) + { + // enter the loop + Advance(); + } + else + { + // Walk until the end of the loop + Advance(); + + depth = 0; + + while (_statement != null) + { + node = _statement.FirstChild(); + + if (node.Type == ASTNodeType.FOR || + node.Type == ASTNodeType.FOREACH) + { + depth++; + } + else if (node.Type == ASTNodeType.ENDFOR) + { + if (depth == 0) + { + Interpreter.PopScope(); + // Go one past the end so the loop doesn't repeat + Advance(); + break; + } + + depth--; + } + + Advance(); + } + } + break; + } case ASTNodeType.ENDFOR: // Walk backward to the for statement _statement = _statement.Prev(); @@ -642,7 +726,8 @@ public bool ExecuteNext() { depth++; } - else if (node.Type == ASTNodeType.FOR) + else if (node.Type == ASTNodeType.FOR || + node.Type == ASTNodeType.FOREACH) { if (depth == 0) { @@ -655,12 +740,12 @@ public bool ExecuteNext() } if (_statement == null) - throw new RunTimeError(node, "Unexpected endfor"); + throw new RunTimeError("Unexpected endfor"); break; case ASTNodeType.BREAK: // Walk until the end of the loop - _statement = _statement.Next(); + Advance(); depth = 0; @@ -669,7 +754,8 @@ public bool ExecuteNext() node = _statement.FirstChild(); if (node.Type == ASTNodeType.WHILE || - node.Type == ASTNodeType.FOR) + node.Type == ASTNodeType.FOR || + node.Type == ASTNodeType.FOREACH) { depth++; } @@ -679,17 +765,17 @@ public bool ExecuteNext() if (depth == 0) { // Go one past the end so the loop doesn't repeat - _statement = _statement.Next(); + Advance(); break; } depth--; } - _statement = _statement.Next(); + Advance(); } - PopScope(); + Interpreter.PopScope(); break; case ASTNodeType.CONTINUE: // Walk backward to the loop statement @@ -707,7 +793,8 @@ public bool ExecuteNext() depth++; } else if (node.Type == ASTNodeType.WHILE || - node.Type == ASTNodeType.FOR) + node.Type == ASTNodeType.FOR || + node.Type == ASTNodeType.FOREACH) { if (depth == 0) break; @@ -719,7 +806,7 @@ public bool ExecuteNext() } if (_statement == null) - throw new RunTimeError(node, "Unexpected continue"); + throw new RunTimeError("Unexpected continue"); break; case ASTNodeType.STOP: _statement = null; @@ -731,7 +818,7 @@ public bool ExecuteNext() case ASTNodeType.FORCE: case ASTNodeType.COMMAND: if (ExecuteCommand(node)) - _statement = _statement.Next(); + Advance(); break; } @@ -739,7 +826,11 @@ public bool ExecuteNext() return (_statement != null) ? true : false; } - public void Advance() { _statement = _statement.Next(); } + public void Advance() + { + Interpreter.ClearTimeout(); + _statement = _statement.Next(); + } private ASTNode EvaluateModifiers(ASTNode node, out bool quiet, out bool force, out bool not) { @@ -770,34 +861,30 @@ private ASTNode EvaluateModifiers(ASTNode node, out bool quiet, out bool force, private bool ExecuteCommand(ASTNode node) { - StatementExecuted.Invoke(node); - node = EvaluateModifiers(node, out bool quiet, out bool force, out _); var handler = Interpreter.GetCommandHandler(node.Lexeme); if (handler == null) - throw new RunTimeError(node, "Unknown command"); + throw new RunTimeError("Unknown command"); var cont = handler(node.Lexeme, ConstructArguments(ref node), quiet, force); if (node != null) - throw new RunTimeError(node, "Command did not consume all available arguments"); + throw new RunTimeError("Command did not consume all available arguments"); return cont; } private bool EvaluateExpression(ref ASTNode expr) { - StatementExecuted.Invoke(expr); - if (expr == null || (expr.Type != ASTNodeType.UNARY_EXPRESSION && expr.Type != ASTNodeType.BINARY_EXPRESSION && expr.Type != ASTNodeType.LOGICAL_EXPRESSION)) - throw new RunTimeError(expr, "No expression following control statement"); + throw new RunTimeError("No expression following control statement"); var node = expr.FirstChild(); if (node == null) - throw new RunTimeError(expr, "Empty expression following control statement"); + throw new RunTimeError("Empty expression following control statement"); switch (expr.Type) { @@ -818,7 +905,7 @@ private bool EvaluateExpression(ref ASTNode expr) node = node.Next(); if (node == null) - throw new RunTimeError(node, "Invalid logical expression"); + throw new RunTimeError("Invalid logical expression"); bool rhs; @@ -833,7 +920,7 @@ private bool EvaluateExpression(ref ASTNode expr) rhs = EvaluateBinaryExpression(ref e); break; default: - throw new RunTimeError(node, "Nested logical expressions are not possible"); + throw new RunTimeError("Nested logical expressions are not possible"); } switch (op) @@ -845,7 +932,7 @@ private bool EvaluateExpression(ref ASTNode expr) lhs = lhs || rhs; break; default: - throw new RunTimeError(node, "Invalid logical operator"); + throw new RunTimeError("Invalid logical operator"); } node = node.Next(); @@ -854,44 +941,41 @@ private bool EvaluateExpression(ref ASTNode expr) return lhs; } - private bool EvaluateUnaryExpression(ref ASTNode node) - { - node = EvaluateModifiers(node, out bool quiet, out _, out bool not); - - var handler = Interpreter.GetExpressionHandler(node.Lexeme); - - if (handler == null) - throw new RunTimeError(node, "Unknown expression"); - - var result = handler(node.Lexeme, ConstructArguments(ref node), quiet); - - if (not) - return result.CompareTo(true) != 0; - else - return result.CompareTo(true) == 0; - } - - private bool EvaluateBinaryExpression(ref ASTNode node) + private bool CompareOperands(ASTNodeType op, IComparable lhs, IComparable rhs) { - // Evaluate the left hand side - var lhs = EvaluateBinaryOperand(ref node); - - // Capture the operator - var op = node.Type; - node = node.Next(); - - // Evaluate the right hand side - var rhs = EvaluateBinaryOperand(ref node); + if (op == ASTNodeType.IN) + { + if (lhs.GetType() != typeof(string) || rhs.GetType() != typeof(string)) + { + throw new RunTimeError("The 'in' operator only works on string operands."); + } + } + else if (op == ASTNodeType.AS) + { + if (lhs.GetType() != typeof(uint)) + { + throw new RunTimeError("The left hand side of an 'as' expression must evaluate to a serial"); + } - if (lhs.GetType() != rhs.GetType()) + if (rhs.GetType() != typeof(string)) + { + throw new RunTimeError("The right hand side of an 'as' expression must evaluate to a string"); + } + } + else if (lhs.GetType() != rhs.GetType()) { // Different types. Try to convert one to match the other. - // Special case for rhs doubles because we don't want to lose precision. if (rhs is double) { - double tmp = (double)lhs; - lhs = tmp; + // Special case for rhs doubles because we don't want to lose precision. + lhs = (double)lhs; + } + else if (rhs is bool) + { + // Special case for rhs bools because we want to down-convert the lhs. + var tmp = Convert.ChangeType(lhs, typeof(bool)); + lhs = (IComparable)tmp; } else { @@ -917,53 +1001,105 @@ private bool EvaluateBinaryExpression(ref ASTNode node) return lhs.CompareTo(rhs) > 0; case ASTNodeType.GREATER_THAN_OR_EQUAL: return lhs.CompareTo(rhs) >= 0; + case ASTNodeType.IN: + return ((string)rhs).Contains((string)lhs); + case ASTNodeType.AS: + Interpreter.SetVariable(rhs.ToString(), lhs.ToString()); + return CompareOperands(ASTNodeType.EQUAL, lhs, true); } } catch (ArgumentException e) { - throw new RunTimeError(node, e.Message); + throw new RunTimeError(e.Message); } - throw new RunTimeError(node, "Unknown operator in expression"); + throw new RunTimeError("Unknown operator in expression"); + + } + + private bool EvaluateUnaryExpression(ref ASTNode node) + { + node = EvaluateModifiers(node, out bool quiet, out bool force, out bool not); + + var handler = Interpreter.GetExpressionHandler(node.Lexeme); + + if (handler == null) + throw new RunTimeError("Unknown expression"); + + var result = handler(node.Lexeme, ConstructArguments(ref node), quiet, force); + + if (not) + return CompareOperands(ASTNodeType.EQUAL, result, false); + else + return CompareOperands(ASTNodeType.EQUAL, result, true); + } + + private bool EvaluateBinaryExpression(ref ASTNode node) + { + // Evaluate the left hand side + var lhs = EvaluateBinaryOperand(ref node); + + // Capture the operator + var op = node.Type; + node = node.Next(); + + // Evaluate the right hand side + var rhs = EvaluateBinaryOperand(ref node); + + return CompareOperands(op, lhs, rhs); } private IComparable EvaluateBinaryOperand(ref ASTNode node) { IComparable val; - node = EvaluateModifiers(node, out bool quiet, out _, out _); + node = EvaluateModifiers(node, out bool quiet, out bool force, out _); switch (node.Type) { case ASTNodeType.INTEGER: val = TypeConverter.ToInt(node.Lexeme); + node = node.Next(); break; case ASTNodeType.SERIAL: val = TypeConverter.ToUInt(node.Lexeme); + node = node.Next(); break; case ASTNodeType.STRING: val = node.Lexeme; + node = node.Next(); break; case ASTNodeType.DOUBLE: val = TypeConverter.ToDouble(node.Lexeme); + node = node.Next(); break; case ASTNodeType.OPERAND: { // This might be a registered keyword, so do a lookup var handler = Interpreter.GetExpressionHandler(node.Lexeme); - if (handler == null) + if (handler != null) { - // It's just a string - val = node.Lexeme; + val = handler(node.Lexeme, ConstructArguments(ref node), quiet, force); + break; } - else + + // It could be a variable + var arg = Interpreter.GetVariable(node.Lexeme); + if (arg != null) { - val = handler(node.Lexeme, ConstructArguments(ref node), quiet); + // TODO: Should really look at the type of arg here + val = arg.AsString(); + node = node.Next(); + break; } + + // It's just a string + val = node.Lexeme; + node = node.Next(); break; } default: - throw new RunTimeError(node, "Invalid type found in expression"); + throw new RunTimeError("Invalid type found in expression"); } return val; @@ -972,16 +1108,25 @@ private IComparable EvaluateBinaryOperand(ref ASTNode node) public static class Interpreter { - // Aliases only hold serial numbers - private static Dictionary _aliases = new Dictionary(); + // The "global" scope + private readonly static Scope _scope = new Scope(null, null); + + // The current scope + private static Scope _currentScope = _scope; + + // Lists + private static Dictionary> _lists = new Dictionary>(); + + // Timers + private static Dictionary _timers = new Dictionary(); // Expressions - public delegate IComparable ExpressionHandler(string expression, Argument[] args, bool quiet); - public delegate T ExpressionHandler(string expression, Argument[] args, bool quiet) where T : IComparable; + public delegate IComparable ExpressionHandler(string expression, Variable[] args, bool quiet, bool force); + public delegate T ExpressionHandler(string expression, Variable[] args, bool quiet, bool force) where T : IComparable; private static Dictionary _exprHandlers = new Dictionary(); - public delegate bool CommandHandler(string command, Argument[] args, bool quiet, bool force); + public delegate bool CommandHandler(string command, Variable[] args, bool quiet, bool force); private static Dictionary _commandHandlers = new Dictionary(); @@ -991,7 +1136,13 @@ public static class Interpreter private static Script _activeScript = null; - public static Action ActiveScriptStatementExecuted; + public static int CurrentLine + { + get + { + return _activeScript == null ? 0 : _activeScript.CurrentLine; + } + } private enum ExecutionState { @@ -1006,7 +1157,7 @@ private enum ExecutionState private static long _pauseTimeout = long.MaxValue; private static TimeoutCallback _timeoutCallback = null; - public static CultureInfo Culture; + internal static CultureInfo Culture; static Interpreter() { @@ -1017,7 +1168,7 @@ static Interpreter() public static void RegisterExpressionHandler(string keyword, ExpressionHandler handler) where T : IComparable { - _exprHandlers[keyword] = (expression, args, quiet) => handler(expression, args, quiet); + _exprHandlers[keyword] = (expression, args, quiet, force) => handler(expression, args, quiet, force); } public static ExpressionHandler GetExpressionHandler(string keyword) @@ -1049,37 +1200,219 @@ public static void UnregisterAliasHandler(string keyword) _aliasHandlers.Remove(keyword); } + public static void PushScope(ASTNode node) + { + _currentScope = new Scope(_currentScope, node); + } + + public static void PopScope() + { + if (_currentScope == _scope) + throw new RunTimeError("Attempted to remove global scope"); + + _currentScope = _currentScope.Parent; + } + + internal static Scope CurrentScope => _currentScope; + + public static void SetVariable(string name, string value, bool global = false) + { + Scope scope = global ? _scope : _currentScope; + + scope.SetVariable(name, new Variable(value)); + } + + public static void AddIgnore(Serial serial, bool global = true) + { + Scope scope = global ? _scope : _currentScope; + scope.AddIgnore(serial); + } + + public static void ClearIgnore(bool global = true) + { + Scope scope = global ? _scope : _currentScope; + scope.ClearIgnore(); + } + + + public static bool CheckIgnored(Serial serial,bool global = true) + { + Scope scope = global ? _scope : _currentScope; + return scope.CheckIgnored(serial); + } + + public static Variable GetVariable(string name) + { + var scope = _currentScope; + Variable result = null; + + while (scope != null) + { + result = scope.GetVariable(name); + if (result != null) + return result; + + scope = scope.Parent; + } + + return result; + } + + public static void ClearVariable(string name) + { + _currentScope.ClearVariable(name); + } + + public static bool ExistVariable(string name) + { + return _currentScope.ExistVariable(name); + } + public static uint GetAlias(string alias) { // If a handler is explicitly registered, call that. if (_aliasHandlers.TryGetValue(alias, out AliasHandler handler)) return handler(alias); - uint value; - if (_aliases.TryGetValue(alias, out value)) - return value; + var arg = GetVariable(alias); - return uint.MaxValue; + return arg?.AsUInt() ?? uint.MaxValue; } public static void SetAlias(string alias, uint serial) { - _aliases[alias] = serial; + SetVariable(alias, serial.ToString(), true); } - private static void SetActiveScript(Script script) + public static void ClearAlias(string alias) { - if (script != null) - { - script.StatementExecuted += ActiveScriptStatementExecuted; - } + _scope.ClearVariable(alias); + } - if (_activeScript != null) - { - _activeScript.StatementExecuted -= ActiveScriptStatementExecuted; - } + public static bool ExistAlias(string alias) + { + return _scope.ExistVariable(alias); + } - _activeScript = script; + public static void CreateList(string name) + { + if (_lists.ContainsKey(name)) + return; + + _lists[name] = new List(); + } + + public static void DestroyList(string name) + { + _lists.Remove(name); + } + + public static void ClearList(string name) + { + if (!_lists.ContainsKey(name)) + return; + + _lists[name].Clear(); + } + + public static bool ListExists(string name) + { + return _lists.ContainsKey(name); + } + + public static bool ListContains(string name, Variable arg) + { + if (!_lists.ContainsKey(name)) + throw new RunTimeError("List does not exist"); + + return _lists[name].Contains(arg); + } + + public static int ListLength(string name) + { + if (!_lists.ContainsKey(name)) + throw new RunTimeError("List does not exist"); + + return _lists[name].Count; + } + + public static void PushList(string name, Variable arg, bool front, bool unique) + { + if (!_lists.ContainsKey(name)) + throw new RunTimeError("List does not exist"); + + if (unique && _lists[name].Contains(arg)) + return; + + if (front) + _lists[name].Insert(0, arg); + else + _lists[name].Add(arg); + } + + public static bool PopList(string name, Variable arg) + { + if (!_lists.ContainsKey(name)) + throw new RunTimeError("List does not exist"); + + return _lists[name].Remove(arg); + } + + public static bool PopList(string name, bool front) + { + if (!_lists.ContainsKey(name)) + throw new RunTimeError("List does not exist"); + + var idx = front ? 0 : _lists[name].Count - 1; + + _lists[name].RemoveAt(idx); + + return _lists[name].Count > 0; + } + + public static Variable GetListValue(string name, int idx) + { + if (!_lists.ContainsKey(name)) + throw new RunTimeError("List does not exist"); + + var list = _lists[name]; + + if (idx < list.Count) + return list[idx]; + + return null; + } + + public static void CreateTimer(string name) + { + _timers[name] = DateTime.UtcNow; + } + + public static TimeSpan GetTimer(string name) + { + if (!_timers.TryGetValue(name, out DateTime timestamp)) + throw new RunTimeError("Timer does not exist"); + + TimeSpan elapsed = DateTime.UtcNow - timestamp; + + return elapsed; + } + + public static void SetTimer(string name, int elapsed) + { + // Setting a timer to start at a given value is equivalent to + // starting the timer that number of milliseconds in the past. + _timers[name] = DateTime.UtcNow.AddMilliseconds(-elapsed); + } + + public static void RemoveTimer(string name) + { + _timers.Remove(name); + } + + public static bool TimerExists(string name) + { + return _timers.ContainsKey(name); } public static bool StartScript(Script script) @@ -1087,7 +1420,9 @@ public static bool StartScript(Script script) if (_activeScript != null) return false; - SetActiveScript(script); + _currentScope = _scope; + _activeScript = script; + _activeScript.Initialize(); _executionState = ExecutionState.RUNNING; ExecuteScript(); @@ -1097,7 +1432,8 @@ public static bool StartScript(Script script) public static void StopScript() { - SetActiveScript(null); + _activeScript = null; + _currentScope = _scope; _executionState = ExecutionState.RUNNING; } @@ -1133,7 +1469,7 @@ public static bool ExecuteScript() */ if (_executionState != ExecutionState.RUNNING) { - SetActiveScript(null); + _activeScript = null; return false; } } @@ -1141,7 +1477,7 @@ public static bool ExecuteScript() if (!_activeScript.ExecuteNext()) { - SetActiveScript(null); + _activeScript = null; return false; } @@ -1186,6 +1522,9 @@ public static void Timeout(long duration, TimeoutCallback callback) // called any time the script advances a statement. public static void ClearTimeout() { + if (_executionState != ExecutionState.TIMING_OUT) + return; + _pauseTimeout = 0; _executionState = ExecutionState.RUNNING; } diff --git a/Razor/Scripts/Engine/Lexer.cs b/Razor/Scripts/Engine/Lexer.cs index 11fc7b95..17d093ba 100644 --- a/Razor/Scripts/Engine/Lexer.cs +++ b/Razor/Scripts/Engine/Lexer.cs @@ -21,6 +21,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; namespace Assistant.Scripts.Engine { @@ -55,6 +56,7 @@ public enum ASTNodeType WHILE, ENDWHILE, FOR, + FOREACH, ENDFOR, BREAK, CONTINUE, @@ -68,6 +70,8 @@ public enum ASTNodeType LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, + IN, + AS, // Logical Operators NOT, @@ -79,6 +83,7 @@ public enum ASTNodeType SERIAL, INTEGER, DOUBLE, + LIST, // Modifiers QUIET, // @ symbol @@ -241,7 +246,6 @@ public static ASTNode Lex(string fname) } private static TextParser _tfp = new TextParser("", new char[] { ' ' }, new char[] { }, new char[] { '\'', '\'', '"', '"' }); - private static void ParseLine(ASTNode node, string line) { line = line.Trim(); @@ -319,32 +323,44 @@ private static void ParseOperand(ASTNode node, string lexeme) node.Push(ASTNodeType.OPERAND, lexeme, _curLine); } - private static void ParseOperator(ASTNode node, string lexeme) + private static ASTNodeType ParseOperator(ASTNode node, string lexeme) { + ASTNodeType type; + switch (lexeme) { case "==": case "=": - node.Push(ASTNodeType.EQUAL, null, _curLine); + type = ASTNodeType.EQUAL; break; case "!=": - node.Push(ASTNodeType.NOT_EQUAL, null, _curLine); + type = ASTNodeType.NOT_EQUAL; break; case "<": - node.Push(ASTNodeType.LESS_THAN, null, _curLine); + type = ASTNodeType.LESS_THAN; break; case "<=": - node.Push(ASTNodeType.LESS_THAN_OR_EQUAL, null, _curLine); + type = ASTNodeType.LESS_THAN_OR_EQUAL; break; case ">": - node.Push(ASTNodeType.GREATER_THAN, null, _curLine); + type = ASTNodeType.GREATER_THAN; break; case ">=": - node.Push(ASTNodeType.GREATER_THAN_OR_EQUAL, null, _curLine); + type = ASTNodeType.GREATER_THAN_OR_EQUAL; + break; + case "in": + type = ASTNodeType.IN; + break; + case "as": + type = ASTNodeType.AS; break; default: throw new SyntaxError(node, "Invalid operator in binary expression"); } + + node.Push(type, null, _curLine); + + return type; } private static void ParseStatement(ASTNode node, string[] lexemes) @@ -413,6 +429,14 @@ private static void ParseStatement(ASTNode node, string[] lexemes) ParseForLoop(statement, lexemes.Slice(1, lexemes.Length - 1)); break; } + case "foreach": + { + if (lexemes.Length != 4) + throw new SyntaxError(node, "Script compilation error"); + + ParseForEachLoop(statement, lexemes.Slice(1, lexemes.Length - 1)); + break; + } case "endfor": if (lexemes.Length > 1) throw new SyntaxError(node, "Script compilation error"); @@ -468,6 +492,8 @@ private static bool IsOperator(string lexeme) case "<=": case ">": case ">=": + case "in": + case "as": return true; } @@ -579,9 +605,16 @@ private static void ParseBinaryExpression(ASTNode node, string[] lexemes) ParseValue(expr, lexemes[i], ASTNodeType.STRING); } - ParseOperator(expr, lexemes[i++]); + var op = ParseOperator(expr, lexemes[i++]); - ParseOperand(expr, lexemes[i++]); + if (op == ASTNodeType.AS) + { + expr.Push(ASTNodeType.STRING, lexemes[i++], _curLine); + } + else + { + ParseOperand(expr, lexemes[i++]); + } for (; i < lexemes.Length; i++) { @@ -616,10 +649,31 @@ private static void ParseForLoop(ASTNode statement, string[] lexemes) ParseValue(loop, lexemes[0], ASTNodeType.STRING); } + else if (lexemes.Length == 3 && lexemes[1] == "to") + { + // for X to LIST + var loop = statement.Push(ASTNodeType.FOREACH, null, _curLine); + + loop.Push(ASTNodeType.STRING, lexemes[2], _curLine); + loop.Push(ASTNodeType.LIST, lexemes[2].Substring(0, lexemes[2].Length - 2), _curLine); + } else { throw new SyntaxError(statement, "Invalid for loop"); } } + + private static void ParseForEachLoop(ASTNode statement, string[] lexemes) + { + // foreach X in LIST + var loop = statement.Push(ASTNodeType.FOREACH, null, _curLine); + + if (lexemes[1] != "in") + throw new SyntaxError(statement, "Invalid foreach loop"); + + // This is the iterator name + ParseValue(loop, lexemes[0], ASTNodeType.STRING); + loop.Push(ASTNodeType.LIST, lexemes[2], _curLine); + } } -} \ No newline at end of file +} diff --git a/Razor/Scripts/Expressions.cs b/Razor/Scripts/Expressions.cs index 27291ff7..5ae9c485 100644 --- a/Razor/Scripts/Expressions.cs +++ b/Razor/Scripts/Expressions.cs @@ -71,16 +71,16 @@ public static void Register() Interpreter.RegisterExpressionHandler("queued", Queued); } - private static bool Queued(string expression, Argument[] args, bool quiet) + private static bool Queued(string expression, Variable[] args, bool quiet, bool force) { return !ActionQueue.Empty; } - private static bool FindBuffDebuff(string expression, Argument[] args, bool quiet) + private static bool FindBuffDebuff(string expression, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, + throw new RunTimeError( "Usage: findbuff/finddebuff ('name of buff')"); } @@ -95,11 +95,11 @@ private static bool FindBuffDebuff(string expression, Argument[] args, bool quie return false; } - private static bool FindType(string expression, Argument[] args, bool quiet) + private static uint FindType(string expression, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: findtype ('name of item') OR (graphicID) [inrangecheck (true/false)/backpack]"); + throw new RunTimeError("Usage: findtype ('name of item') OR ('graphic') [src] [hue] [qty] [range]"); } string gfxStr = args[0].AsString(); @@ -107,98 +107,93 @@ private static bool FindType(string expression, Argument[] args, bool quiet) List items; List mobiles; - bool inRangeCheck = false; - bool backpack = false; - - if (args.Length == 2) - { - if (args[1].AsString().IndexOf("pack", StringComparison.InvariantCultureIgnoreCase) > 0) - { - backpack = true; - } - else - { - inRangeCheck = args[1].AsBool(); - } - } + (Serial src, int hue, int qty, int range) = CommandHelper.ParseFindArguments(args); // No graphic id, maybe searching by name? if (gfx == 0) { - items = CommandHelper.GetItemsByName(gfxStr, backpack, inRangeCheck); + items = CommandHelper.GetItemsByName(gfxStr, hue, src, (short)qty, range); if (items.Count == 0) // no item found, search mobile by name { - mobiles = CommandHelper.GetMobilesByName(gfxStr, inRangeCheck); + mobiles = CommandHelper.GetMobilesByName(gfxStr, range); if (mobiles.Count > 0) { - return true; + return mobiles[0].Serial; } } else { - return true; + return items[0].Serial; } } else // Provided graphic id for type, check backpack first (same behavior as DoubleClickAction in macros { ushort id = Utility.ToUInt16(gfxStr, 0); - items = CommandHelper.GetItemsById(id, backpack, inRangeCheck); + items = CommandHelper.GetItemsById(id, hue, src, (short)qty, range); // Still no item? Mobile check! if (items.Count == 0) { - mobiles = CommandHelper.GetMobilesById(id, inRangeCheck); + mobiles = CommandHelper.GetMobilesById(id, range); if (mobiles.Count > 0) { - return true; + return mobiles[0].Serial; } } else { - return true; + return items[0].Serial; } } - return false; + return Serial.Zero; } - private static bool Mounted(string expression, Argument[] args, bool quiet) + private static bool Mounted(string expression, Variable[] args, bool quiet, bool force) { return World.Player != null && World.Player.GetItemOnLayer(Layer.Mount) != null; } - private static bool RHandEmpty(string expression, Argument[] args, bool quiet) + private static bool RHandEmpty(string expression, Variable[] args, bool quiet, bool force) { return World.Player != null && World.Player.GetItemOnLayer(Layer.RightHand) == null; } - private static bool LHandEmpty(string expression, Argument[] args, bool quiet) + private static bool LHandEmpty(string expression, Variable[] args, bool quiet, bool force) { return World.Player != null && World.Player.GetItemOnLayer(Layer.LeftHand) == null; } - private static bool Dead(string expression, Argument[] args, bool quiet) + private static bool Dead(string expression, Variable[] args, bool quiet, bool force) { return World.Player != null && World.Player.IsGhost; } - private static bool InSysMessage(string expression, Argument[] args, bool quiet) + /// + /// Check whenever message is in journal + /// + /// Expression + /// args + /// quiet mode - not used + /// Remove message in list or not + /// + private static bool InSysMessage(string expression, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: insysmsg ('text')"); + throw new RunTimeError("Usage: insysmsg ('text')"); } string text = args[0].AsString(); - return SystemMessages.Exists(text); + return SystemMessages.Exists(text, !force); } - private static int Mana(string expression, Argument[] args, bool quiet) + private static int Mana(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -206,7 +201,7 @@ private static int Mana(string expression, Argument[] args, bool quiet) return World.Player.Mana; } - private static int MaxMana(string expression, Argument[] args, bool quiet) + private static int MaxMana(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -214,18 +209,20 @@ private static int MaxMana(string expression, Argument[] args, bool quiet) return World.Player.ManaMax; } - private static bool Poisoned(string expression, Argument[] args, bool quiet) + private static bool Poisoned(string expression, Variable[] args, bool quiet, bool force) { - return World.Player != null && Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned) && - World.Player.Poisoned; + if (World.Player == null) + return false; + + return World.Player.Poisoned; } - private static bool Hidden(string expression, Argument[] args, bool quiet) + private static bool Hidden(string expression, Variable[] args, bool quiet, bool force) { return World.Player != null && !World.Player.Visible; } - private static int Hp(string expression, Argument[] args, bool quiet) + private static int Hp(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -233,7 +230,7 @@ private static int Hp(string expression, Argument[] args, bool quiet) return World.Player.Hits; } - private static int MaxHp(string expression, Argument[] args, bool quiet) + private static int MaxHp(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -241,7 +238,7 @@ private static int MaxHp(string expression, Argument[] args, bool quiet) return World.Player.HitsMax; } - private static int Stam(string expression, Argument[] args, bool quiet) + private static int Stam(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -249,7 +246,7 @@ private static int Stam(string expression, Argument[] args, bool quiet) return World.Player.Stam; } - private static int MaxStam(string expression, Argument[] args, bool quiet) + private static int MaxStam(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -257,7 +254,7 @@ private static int MaxStam(string expression, Argument[] args, bool quiet) return World.Player.StamMax; } - private static int Str(string expression, Argument[] args, bool quiet) + private static int Str(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -265,7 +262,7 @@ private static int Str(string expression, Argument[] args, bool quiet) return World.Player.Str; } - private static int Dex(string expression, Argument[] args, bool quiet) + private static int Dex(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -273,7 +270,7 @@ private static int Dex(string expression, Argument[] args, bool quiet) return World.Player.Dex; } - private static int Int(string expression, Argument[] args, bool quiet) + private static int Int(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -281,7 +278,7 @@ private static int Int(string expression, Argument[] args, bool quiet) return World.Player.Int; } - private static int Weight(string expression, Argument[] args, bool quiet) + private static int Weight(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return 0; @@ -289,10 +286,10 @@ private static int Weight(string expression, Argument[] args, bool quiet) return World.Player.Weight; } - private static double SkillExpression(string expression, Argument[] args, bool quiet) + private static double SkillExpression(string expression, Variable[] args, bool quiet, bool force) { if (args.Length < 1) - throw new RunTimeError(null, "Usage: skill ('name of skill')"); + throw new RunTimeError("Usage: skill ('name of skill')"); if (World.Player == null) return 0; @@ -308,10 +305,10 @@ private static double SkillExpression(string expression, Argument[] args, bool q return 0; } - private static int CountExpression(string expression, Argument[] args, bool quiet) + private static int CountExpression(string expression, Variable[] args, bool quiet, bool force) { if (args.Length < 1) - throw new RunTimeError(null, "Usage: count ('name of counter item')"); + throw new RunTimeError("Usage: count ('name of counter item')"); if (World.Player == null) return 0; @@ -324,17 +321,17 @@ private static int CountExpression(string expression, Argument[] args, bool quie } } - throw new RunTimeError(null, $"Counter '{args[0].AsString()}' doesn't exist. Set it up in Razor under Display->Counters."); + throw new RunTimeError($"Counter '{args[0].AsString()}' doesn't exist. Set it up in Razor under Display->Counters."); } - private static bool Position(string expression, Argument[] args, bool quiet) + private static bool Position(string expression, Variable[] args, bool quiet, bool force) { if (World.Player == null) return false; if (args.Length < 2) { - throw new RunTimeError(null, + throw new RunTimeError( "Usage: position (x, y) or position (x, y, z)"); } diff --git a/Razor/Scripts/Helpers/CommandHelper.cs b/Razor/Scripts/Helpers/CommandHelper.cs index 6bb125f6..5c795778 100644 --- a/Razor/Scripts/Helpers/CommandHelper.cs +++ b/Razor/Scripts/Helpers/CommandHelper.cs @@ -1,122 +1,329 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using Assistant.Filters; using Assistant.Scripts.Engine; namespace Assistant.Scripts.Helpers { public static class CommandHelper { + public static IEnumerable FilterItems(IEnumerable items, int hue, short qt, Serial src, int range) + { + foreach (var item in items) + { + if (hue != -1 && item.Hue != hue) + { + continue; + } + // For items that are not stackable Amount is equal 0 + if (qt > 1 && item.Amount < qt) + { + continue; + } + + if (src == Serial.SelfAndBackpack) + { + if (!CheckInContainer(item, World.Player.Serial, range) && + !CheckInContainer(item, World.Player.Backpack.Serial, range)) + continue; + } + else if (src == Serial.SelfBackpackAndGround) + { + if (!CheckInContainer(item, World.Player.Serial, range) && + !CheckInContainer(item, World.Player.Backpack.Serial, range) && + !(item.Container == null && Utility.InRange(World.Player.Position, item.Position, 2))) + continue; + } + else if (src != 0) + { + if (!CheckInContainer(item, src, range)) + continue; + } + else if (item.Container != null) + { + continue; + } + + if (range > 0 && src <= 0 && !Utility.InRange(World.Player.Position, item.Position, range)) + { + continue; + } + + if (Interpreter.CheckIgnored(item.Serial)) + continue; + + yield return item; + } + } + + /// + /// Check if the item is (recursively) inside the given container + /// + /// Item to check + /// Serial of container that we are looking for + /// Maximum depth to allow for nested containers + /// + private static bool CheckInContainer(Item item, Serial serial, int maxDepth) + { + if (item == null) + return false; + + if (maxDepth < 0) + maxDepth = 100; + + do + { + if (item.IsCorpse) + return false; + + if (item.Serial == serial) + { + return true; + } + + switch (item.Container) + { + case Item i: + item = i; + break; + case Serial s: + item = World.FindItem(s); + break; + case Mobile m: + // Mobile is always at the top + return m.Serial == serial; + default: + item = null; + break; + } + } while (item != null && maxDepth-- > 0); + + return false; + } + /// /// Common logic for dclicktype and targettype to find items by name /// /// - /// - /// + /// Hue number + /// Source name + /// Quantity + /// Range /// - public static List GetItemsByName(string name, bool backpack, bool inRange) + public static List GetItemsByName(string name, int hue, Serial src, short qt, int range) { - List items = new List(); + return FilterItems(World.FindItemsByName(name), hue, qt, src, range).ToList(); + } - if (backpack && World.Player.Backpack != null) // search backpack only - { - Item i = World.Player.Backpack.FindItemByName(name, true); + /// + /// Common logic for dclicktype and targettype to find items by id + /// + /// + /// Hue number + /// Source name + /// Quantity + /// Range + /// + public static List GetItemsById(ushort id, int hue, Serial src, short qt, int range) + { + return FilterItems(World.FindItemsById(id), hue, qt, src, range).ToList(); + } - if (i != null) - items.Add(i); - } - else if (inRange) // inrange includes both backpack and within 2 tiles + /// + /// Common logic for dclicktype and targettype to find mobiles by name + /// + /// + /// Range + /// + public static List GetMobilesByName(string name, int range) + { + List mobiles = new List(); + + if (range == -1) { - items.AddRange(World.FindItemsByName(name).Where(item => - !item.IsInBank && (Utility.InRange(World.Player.Position, item.Position, 2) || - item.RootContainer == World.Player)).ToList()); + range = 18; } - else + + foreach (var m in World.FindMobilesByName(name)) { - items.AddRange(World.FindItemsByName(name).Where(item => !item.IsInBank).ToList()); + if (m.IsGhost || m.IsHuman) + { + continue; + } + + if (!Utility.InRange(World.Player.Position, m.Position, range)) + { + continue; + } + + if (Interpreter.CheckIgnored(m.Serial)) + continue; + + mobiles.Add(m); } - return items; + return mobiles; } /// - /// Common logic for dclicktype and targettype to find items by id + /// Common logic for dclicktype and targettype to find mobiles by id /// /// - /// - /// + /// Range /// - public static List GetItemsById(ushort id, bool backpack, bool inRange) + public static List GetMobilesById(ushort id, int range) + { + List mobiles = new List(); + + if (range == -1) + { + range = 18; + } + + foreach (var m in World.MobilesInRange(range)) + { + if (m.IsGhost || m.IsHuman) + { + continue; + } + + if (m.Body != id) + { + continue; + } + + if (!Utility.InRange(World.Player.Position, m.Position, range)) + { + continue; + } + + if (Interpreter.CheckIgnored(m.Serial)) + continue; + + mobiles.Add(m); + } + + return mobiles; + } + + /// + /// Check if passed string is number and assign out variable to that number + /// + /// String with number + public static int IsNumberOrAny(string sNumber) { - List items = new List(); + var num = Utility.ToInt32(sNumber, -2); + if (num != -2) + { + return num; + } - if (backpack && World.Player.Backpack != null) + if (sNumber.ToLower() != "any") { - Item i = World.Player.Backpack.FindItemByID(id); + throw new RunTimeError("Wrong parameter"); + } + + return -1; + } - if (i != null) - items.Add(i); - } - else if (inRange) + /// + /// Check if passed string is number and assign out variable to that number + /// + /// String with number + public static uint IsUNumberOrAny(string sNumber) + { + var num = Utility.ToUInt32(sNumber, 0); + if (num != 0) { - items.AddRange(World.FindItemsById(id).Where(item => - !item.IsInBank && (Utility.InRange(World.Player.Position, item.Position, 2) || - item.RootContainer == World.Player)).ToList()); + return num; } - else + + if (sNumber.ToLower() != "any") { - items.AddRange(World.FindItemsById(id).Where(item => !item.IsInBank).ToList()); + throw new RunTimeError("Wrong parameter"); } - return items; + return UInt32.MaxValue; } /// - /// Common logic for dclicktype and targettype to find mobiles by name + /// Deconstruct arguments /// - /// - /// - /// - public static List GetMobilesByName(string name, bool inRange) + /// Array with arguments + public static (Serial, int, int, int) ParseFindArguments(Variable[] args) { - List mobiles; + int[] result = { -1, -1, -1 }; + + Serial src = Serial.SelfAndBackpack; - if (inRange) + if (args.Length > 1) { - mobiles = World.FindMobilesByName(name) - .Where(m => Utility.InRange(World.Player.Position, m.Position, 2)).ToList(); + if (args[1].AsString(false) == "true") + { + src = Serial.SelfBackpackAndGround; + } + else + { + src = args[1].AsSerial(); + } } - else + + // Hue + if (args.Length > 2) { - mobiles = World.FindMobilesByName(name); + result[0] = IsNumberOrAny(args[2].AsString()); } - return mobiles; + // Qty + if (args.Length > 3) + { + result[1] = IsNumberOrAny(args[3].AsString()); + } + + // Range + if (args.Length > 4) + { + result[2] = IsNumberOrAny(args[4].AsString()); + } + + return (src, result[0], result[1], result[2]); } /// - /// Common logic for dclicktype and targettype to find mobiles by id + /// Deconstruct arguments /// - /// - /// - /// - public static List GetMobilesById(ushort id, bool inRange) + /// Array with arguments + public static (Serial, int, int) ParseCountArguments(Variable[] args) { - List mobiles; + int[] result = { -1, -1 }; - if (inRange) + Serial src = Serial.SelfAndBackpack; + + if (args.Length > 1) { - mobiles = World.MobilesInRange() - .Where(m => Utility.InRange(World.Player.Position, m.Position, 2) && m.Body == id).ToList(); + if (args[1].AsString(false) == "true") + { + src = Serial.SelfBackpackAndGround; + } + else + { + src = args[1].AsSerial(); + } } - else + + // Hue + if (args.Length > 2) { - mobiles = World.MobilesInRange().Where(m => m.Body == id).ToList(); + result[0] = IsNumberOrAny(args[2].AsString()); } - return mobiles; + // Range + if (args.Length > 3) + { + result[1] = IsNumberOrAny(args[3].AsString()); + } + + return (src, result[0], result[1]); } public static void SendWarning(string command, string message, bool quiet) @@ -127,6 +334,22 @@ public static void SendWarning(string command, string message, bool quiet) } } + public static void SendMessage(string message, bool quiet) + { + if (!quiet) + { + World.Player.SendMessage(MsgLevel.Force, message); + } + } + + public static void SendInfo(string message, bool quiet) + { + if (!quiet) + { + World.Player.SendMessage(MsgLevel.Info, message); + } + } + /// /// Parse the script input to target the correct mobile /// @@ -135,7 +358,7 @@ public static void SendWarning(string command, string message, bool quiet) /// /// /// - public static void FindTarget(Argument[] args, bool closest, bool random = false, bool next = false, bool prev = false) + public static void FindTarget(Variable[] args, bool closest, bool random = false, bool next = false, bool prev = false) { ScriptManager.TargetFound = false; @@ -210,7 +433,7 @@ public static void FindTarget(Argument[] args, bool closest, bool random = false break; default: - throw new RunTimeError(null, + throw new RunTimeError( $"Unknown target type: '{args[1].AsString()}' - Missing type? (human/monster)"); } } @@ -240,7 +463,7 @@ public static void FindTarget(Argument[] args, bool closest, bool random = false /// /// /// - private static void FindTargetNotoriety(Argument[] args, bool closest, bool random, bool next) + private static void FindTargetNotoriety(Variable[] args, bool closest, bool random, bool next) { string[] notoList = args[1].AsString().Split(','); @@ -361,7 +584,7 @@ private static void FindTargetNotoriety(Argument[] args, bool closest, bool rand /// /// /// - private static void FindTargetPriority(Argument[] args, bool closest, bool random, bool next) + private static void FindTargetPriority(Variable[] args, bool closest, bool random, bool next) { string[] notoList = args[1].AsString().Split('!'); @@ -789,7 +1012,7 @@ private static void FindTargetPriority(Argument[] args, bool closest, bool rando break; default: - throw new RunTimeError(null, $"Unknown target type: '{args[1].AsString()}'"); + throw new RunTimeError($"Unknown target type: '{args[1].AsString()}'"); } } } diff --git a/Razor/Scripts/Outlands.cs b/Razor/Scripts/Outlands.cs new file mode 100644 index 00000000..62d312bb --- /dev/null +++ b/Razor/Scripts/Outlands.cs @@ -0,0 +1,819 @@ +#region license + +// Razor: An Ultima Online Assistant +// Copyright (C) 2021 Razor Development Community on GitHub +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Assistant.Core; +using Assistant.Scripts.Engine; +using Assistant.Scripts.Helpers; +using Assistant.UI; +using Ultima; + +namespace Assistant.Scripts +{ + public static class Outlands + { + public static void Register() + { + // Lists + Interpreter.RegisterCommandHandler("poplist", PopList); + Interpreter.RegisterCommandHandler("pushlist", PushList); + Interpreter.RegisterCommandHandler("removelist", RemoveList); + Interpreter.RegisterCommandHandler("createlist", CreateList); + Interpreter.RegisterCommandHandler("clearlist", ClearList); + + // Timers + Interpreter.RegisterCommandHandler("settimer", SetTimer); + Interpreter.RegisterCommandHandler("removetimer", RemoveTimer); + Interpreter.RegisterCommandHandler("createtimer", CreateTimer); + + Interpreter.RegisterCommandHandler("getlabel", GetLabel); + Interpreter.RegisterCommandHandler("warmode", Warmode); + Interpreter.RegisterCommandHandler("unsetvar", UnsetVar); + Interpreter.RegisterCommandHandler("rename", Rename); + Interpreter.RegisterCommandHandler("setskill", SetSkill); + + Interpreter.RegisterExpressionHandler("listexists", ListExists); + Interpreter.RegisterExpressionHandler("list", ListLength); + Interpreter.RegisterExpressionHandler("inlist", InList); + Interpreter.RegisterExpressionHandler("varexist", VarExist); + + Interpreter.RegisterCommandHandler("ignore", AddIgnore); + Interpreter.RegisterCommandHandler("clearignore", ClearIgnore); + + Interpreter.RegisterExpressionHandler("timer", TimerValue); + Interpreter.RegisterExpressionHandler("timerexists", TimerExists); + + Interpreter.RegisterExpressionHandler("followers", Followers); + Interpreter.RegisterExpressionHandler("hue", Hue); + Interpreter.RegisterExpressionHandler("name", GetName); + Interpreter.RegisterExpressionHandler("findlayer", FindLayer); + Interpreter.RegisterExpressionHandler("find", Find); + Interpreter.RegisterExpressionHandler("targetexists", TargetExists); + Interpreter.RegisterExpressionHandler("maxweight", MaxWeight); + Interpreter.RegisterExpressionHandler("diffweight", Diffweight); + Interpreter.RegisterExpressionHandler("diffhits", Diffhits); + Interpreter.RegisterExpressionHandler("diffstam", Diffstam); + Interpreter.RegisterExpressionHandler("diffmana", Diffmana); + Interpreter.RegisterExpressionHandler("counttype", CountType); + + // Mobile flags + Interpreter.RegisterExpressionHandler("paralyzed", Paralyzed); + Interpreter.RegisterExpressionHandler("invul", Blessed); + Interpreter.RegisterExpressionHandler("warmode", InWarmode); + Interpreter.RegisterExpressionHandler("noto", Notoriety); + Interpreter.RegisterExpressionHandler("dead", Dead); + + // Gump + Interpreter.RegisterExpressionHandler("gumpexists", GumpExists); + Interpreter.RegisterExpressionHandler("ingump", InGump); + } + + private static bool PopList(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 2) + throw new RunTimeError("Usage: poplist ('list name') ('element value'/'front'/'back')"); + + if (args[1].AsString() == "front") + { + if (force) + while (Interpreter.PopList(args[0].AsString(), true)) { } + else + Interpreter.PopList(args[0].AsString(), true); + } + else if (args[1].AsString() == "back") + { + if (force) + while (Interpreter.PopList(args[0].AsString(), false)) { } + else + Interpreter.PopList(args[0].AsString(), false); + } + else + { + if (force) + while (Interpreter.PopList(args[0].AsString(), args[1])) { } + else + Interpreter.PopList(args[0].AsString(), args[1]); + } + + return true; + } + + private static bool PushList(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length < 2 || args.Length > 3) + throw new RunTimeError("Usage: pushlist ('list name') ('element value') ['front'/'back']"); + + bool front = false; + if (args.Length == 3) + { + if (args[2].AsString() == "front") + front = true; + } + + Interpreter.PushList(args[0].AsString(), new Variable(args[1].AsString()), front, force); + + return true; + } + + private static bool RemoveList(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: removelist ('list name')"); + + Interpreter.DestroyList(args[0].AsString()); + + return true; + } + + private static bool CreateList(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: createlist ('list name')"); + + Interpreter.CreateList(args[0].AsString()); + + return true; + } + + private static bool ClearList(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: clearlist ('list name')"); + + Interpreter.ClearList(args[0].AsString()); + + return true; + } + + private static bool SetTimer(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 2) + throw new RunTimeError("Usage: settimer (timer name) (value)"); + + + Interpreter.SetTimer(args[0].AsString(), args[1].AsInt()); + return true; + } + + private static bool RemoveTimer(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: removetimer (timer name)"); + + Interpreter.RemoveTimer(args[0].AsString()); + return true; + } + + private static bool CreateTimer(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: createtimer (timer name)"); + + Interpreter.CreateTimer(args[0].AsString()); + return true; + } + + private enum GetLabelState + { + NONE, + WAITING_FOR_FIRST_LABEL, + WAITING_FOR_REMAINING_LABELS + }; + + private static GetLabelState _getLabelState = GetLabelState.NONE; + private static Action _onLabelMessage; + + private static bool GetLabel(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 2) + throw new RunTimeError("Usage: getlabel (serial) (name)"); + + var serial = args[0].AsSerial(); + var name = args[1].AsString(false); + + switch (_getLabelState) + { + case GetLabelState.NONE: + _getLabelState = GetLabelState.WAITING_FOR_FIRST_LABEL; + Interpreter.Timeout(2000, () => + { + _onLabelMessage = null; + MessageManager.OnLabelMessage -= _onLabelMessage; + _getLabelState = GetLabelState.NONE; + MessageManager.GetLabelCommand = false; + return true; + }); + + // Single click the object + Client.Instance.SendToServer(new SingleClick((Serial)args[0].AsSerial())); + + // Capture all message responses + StringBuilder label = new StringBuilder(); + + // Some messages from Outlands server are send in sequence of LabelType and RegularType + // so we want to invoke that _onLabelMessage in both cases with delays + MessageManager.GetLabelCommand = true; + + _onLabelMessage = (p, a, source, graphic, type, hue, font, lang, sourceName, text) => + { + if (source != serial) + return; + + a.Block = true; + + if (_getLabelState == GetLabelState.WAITING_FOR_FIRST_LABEL) + { + // After the first message, switch to a pause instead of a timeout. + _getLabelState = GetLabelState.WAITING_FOR_REMAINING_LABELS; + Interpreter.Pause(500); + } + + label.AppendLine(text); + + Interpreter.SetVariable(name, label.ToString()); + }; + + MessageManager.OnLabelMessage += _onLabelMessage; + break; + case GetLabelState.WAITING_FOR_FIRST_LABEL: + break; + case GetLabelState.WAITING_FOR_REMAINING_LABELS: + // We get here after the pause has expired. + MessageManager.OnLabelMessage -= _onLabelMessage; + _onLabelMessage = null; + _getLabelState = GetLabelState.NONE; + MessageManager.GetLabelCommand = false; + return true; + } + + return false; + } + + private static bool Warmode(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: warmode ('on' / 'off' )"); + + if (args[0].AsString().ToLower() == "on") + { + SpecialMoves.ToggleWar(); + } + else + { + SpecialMoves.TogglePeace(); + } + + return true; + } + + private static bool UnsetVar(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: unsetvar ('name')"); + + var name = args[0].AsString(false); + + if (force) + { + if (quiet) + { + Interpreter.ClearVariable(name); + } + else + { + Interpreter.ClearAlias(name); + } + } + else + { + ScriptVariables.UnregisterVariable(name); + ScriptManager.RedrawScripts(); + } + + return true; + } + + /// + /// Check if variable of alias exist + /// + /// Cmd + /// Variable or Alias Name + /// True if variable, False if Alias + /// + private static bool VarExist(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: varexist (name)"); + + var varName = args[0].AsString(false); + + return quiet ? Interpreter.ExistVariable(varName) : Interpreter.ExistAlias(varName); + } + + private static bool Rename(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length != 2) + throw new RunTimeError("Usage: rename (serial) (new_name)"); + + var newName = args[1].AsString(); + if (newName.Length < 1) + throw new RunTimeError("Mobile name must be longer then 1 char"); + + if (World.Mobiles.TryGetValue(args[0].AsSerial(), out var follower)) + { + if (follower.CanRename) + { + World.Player.RenameMobile(follower.Serial, newName); + } + } + + return true; + } + + private static readonly Dictionary LockTypeMap = new Dictionary + { + { "up", LockType.Up }, + { "down", LockType.Down }, + { "lock", LockType.Locked }, + { "locked", LockType.Locked } + + }; + + private static bool SetSkill(string command, Variable[] args, bool quiet, bool force) + { + if (args.Length < 2) + throw new RunTimeError("Usage: setskill (skill_name) (up/down/lock)"); + + if (!LockTypeMap.TryGetValue(args[1].AsString(), out var lockType)) + throw new RunTimeError("Invalid set skill modifier - should be up/down/lock"); + + var skillInfo = Skills.SkillEntries.Find(x => string.Equals(x.Name, args[0].AsString(), StringComparison.CurrentCultureIgnoreCase)); + + if (skillInfo == null) + { + throw new RunTimeError("Invalid skill name"); + } + + // Send Information to Server + Client.Instance.SendToServer(new SetSkillLock(skillInfo.Index, lockType)); + + // Update razor window + var skill = World.Player.Skills[skillInfo.Index]; + skill.Lock = lockType; + Assistant.Engine.MainWindow.SafeAction(s => s.RedrawSkills()); + + // Send Information to Client + Client.Instance.SendToClient(new SkillUpdate(skill)); + + return true; + } + + private static bool ListExists(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: listexists ('list name')"); + + if (Interpreter.ListExists(args[0].AsString())) + return true; + + return false; + } + + private static int ListLength(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: list (list name) (operator) (value)"); + + return Interpreter.ListLength(args[0].AsString()); + } + + private static bool InList(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 2) + throw new RunTimeError("Usage: inlist (list name) (element)"); + + if (Interpreter.ListContains(args[0].AsString(), args[1])) + return true; + + return false; + } + + private static int TimerValue(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: timer ('timer name')"); + + var ts = Interpreter.GetTimer(args[0].AsString()); + + return (int)ts.TotalMilliseconds; + } + + private static bool TimerExists(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: timerexists ('timer name')"); + + return Interpreter.TimerExists(args[0].AsString()); + } + + private static int Followers(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 0) + throw new RunTimeError("Usage: followers"); + + return World.Player.Followers; + } + + private static int Hue(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: hue ('serial')"); + + var item = World.FindItem(args[0].AsSerial()); + + if (item == null) + return 0; + + return item.Hue; + } + + private static string GetName(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return null; + + return World.Player.Name; + } + + private static bool Paralyzed(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return false; + + return World.Player.Paralyzed; + } + + private static bool Blessed(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return false; + + return World.Player.Blessed; + } + + private static bool InWarmode(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return false; + + return World.Player.Warmode; + } + + /** + * Notoriety + 0x1: Innocent (Blue) + 0x2: Friend (Green) + 0x3: Gray (Gray - Animal) + 0x4: Criminal (Gray) + 0x5: Enemy (Orange) + 0x6: Murderer (Red) + 0x7: Invulnerable (Yellow) + */ + private static Dictionary _notorietyMap = new Dictionary + { + { 1, "innocent" }, + { 2, "friend" }, + { 3, "hostile" }, + { 4, "criminal" }, + { 5, "enemy" }, + { 6, "murderer" }, + { 7, "invulnerable" } + }; + + private static string Notoriety(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: noto (serial)"); + + var target = args[0].AsSerial(); + + var m = World.FindMobile(target); + + if (m == null) + { + CommandHelper.SendWarning(expression, $"Mobile '{target}' not found", quiet); + return string.Empty; + } + + return _notorietyMap[m.Notoriety]; + } + + /// + /// Dead expression + /// - if dead [serial] - default - self + /// + /// Expression + /// Args + /// Quiet messaging + /// Force flag + /// + private static bool Dead(string expression, Variable[] args, bool quiet, bool force) + { + // Default variable for dead = Self + var mob = World.Player as Mobile; + + // If Serial passed, get mobile + if (args.Length > 0) + { + var serial = args[0].AsSerial(); + mob = World.FindMobile(serial); + } + + // No mob = dead + if (mob == null) + return true; + + // Mob = ghost (body is ghost) or Mob.Dead from packet 0xBF + return mob.IsGhost || mob.Dead; + } + + private static readonly Dictionary LayerMap = new Dictionary + { + {"righthand", Layer.RightHand}, + {"lefthand", Layer.LeftHand}, + {"shoes", Layer.Shoes}, + {"pants", Layer.Pants}, + {"shirt", Layer.Shirt}, + {"head", Layer.Head}, + {"gloves", Layer.Gloves}, + {"ring", Layer.Ring}, + {"talisman", Layer.Talisman}, + {"neck", Layer.Neck}, + {"hair", Layer.Hair}, + {"waist", Layer.Waist}, + {"innertorso", Layer.InnerTorso}, + {"bracelet", Layer.Bracelet}, + {"face", Layer.Face}, + {"facialhair", Layer.FacialHair}, + {"middletorso", Layer.MiddleTorso}, + {"earrings", Layer.Earrings}, + {"arms", Layer.Arms}, + {"cloak", Layer.Cloak}, + {"backpack", Layer.Backpack}, + {"outertorso", Layer.OuterTorso}, + {"outerlegs", Layer.OuterLegs}, + {"innerlegs", Layer.InnerLegs}, + }; + + private static uint FindLayer(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 2) + throw new RunTimeError("Usage: findlayer (serial) (layer)"); + + var serial = args[0].AsSerial(); + + var m = World.FindMobile(serial); + + if (m == null) + { + CommandHelper.SendWarning(expression, $"Mobile {serial} not found", quiet); + return Serial.Zero; + } + + if (!LayerMap.TryGetValue(args[1].AsString(), out var layerName)) + throw new RunTimeError("Invalid layer name"); + + return m.GetItemOnLayer(layerName)?.Serial ?? Serial.Zero; + } + + private static bool AddIgnore(string commands, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: ignore (serial)"); + var serial = args[0].AsSerial(); + Interpreter.AddIgnore(serial); + CommandHelper.SendMessage($"Added {serial} to ignore list", quiet); + return true; + } + + private static bool ClearIgnore(string commands, Variable[] args, bool quiet, bool force) + { + Interpreter.ClearIgnore(); + CommandHelper.SendMessage("Ignore List cleared", quiet); + return true; + } + + private static uint Find(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length == 0) + { + throw new RunTimeError("Usage: find ('serial') [src] [hue] [qty] [range]"); + } + + var serial = args[0].AsSerial(); + + (Serial src, int hue, int qty, int range) = CommandHelper.ParseFindArguments(args); + + if (range == -1) + range = 18; + + // Check if is a mobile + if (World.Mobiles.TryGetValue(serial, out var m)) + { + if (m.IsHuman) + return Serial.Zero; + + if (hue != -1 && m.Hue != hue) + { + return Serial.Zero; + } + + if (!Utility.InRange(World.Player.Position, m.Position, range)) + { + return Serial.Zero; + } + + return m.Serial; + } + + // Check if passed serial is Item + if (!World.Items.TryGetValue(serial, out var i)) + return Serial.Zero; + + // Apply all filter + foreach (var item in CommandHelper.FilterItems(new[] { i }, hue, (short)qty, src, range)) + { + return item.Serial; + } + + return Serial.Zero; + } + + private static uint CountType(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length == 0) + { + throw new RunTimeError("Usage: counttype (name or graphic) [src] [hue] [range]"); + } + + var name = args[0].AsString(); + Serial gfx = Utility.ToUInt16(name, 0); + + (Serial src, int hue, int range) = CommandHelper.ParseCountArguments(args); + + List items; + + if (gfx == 0) + { + items = CommandHelper.GetItemsByName(name, hue, src, -1, range); + } + else + { + items = CommandHelper.GetItemsById((ushort)gfx.Value, hue, src, -1, range); + } + + return (uint)items.Sum(x => x.Amount); + } + + private static readonly Dictionary TargetMap = new Dictionary + { + {"neutral", 0 }, + {"harmful", 1 }, + {"beneficial",2 }, + {"any", 3 } + }; + + private static bool TargetExists(string expression, Variable[] args, bool quiet, bool force) + { + byte type = 3; + + if (args.Length > 0) + { + if (!TargetMap.TryGetValue(args[0].AsString().ToLower(), out type)) + { + throw new RunTimeError("Invalid target type"); + } + } + + if (!Targeting.HasTarget) + return false; + + if (type == 3) + return true; + + return Targeting.CursorType == type; + } + + + private static int MaxWeight(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return 0; + + return World.Player.MaxWeight; + } + + private static int Diffweight(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return 0; + + return World.Player.MaxWeight - World.Player.Weight; + } + + private static int Diffhits(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return 0; + + return World.Player.HitsMax - World.Player.Hits; + } + + private static int Diffstam(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return 0; + + return World.Player.StamMax - World.Player.Stam; + } + + private static int Diffmana(string expression, Variable[] args, bool quiet, bool force) + { + if (World.Player == null) + return 0; + + return World.Player.ManaMax - World.Player.Mana; + } + + /// + /// Return true if user has gump with id or any + /// + /// Expression + /// Args - should contain gump id or any + /// Not used + /// + private static bool GumpExists(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length != 1) + throw new RunTimeError("Usage: gumpexists (gumpId/'any')"); + + var gumpId = CommandHelper.IsUNumberOrAny(args[0].AsString()); + + // If any just return if user have gump + if (gumpId == uint.MaxValue) + return World.Player.GumpList.Count > 0; + + // If gumpId specific check for it + return World.Player.GumpList.ContainsKey(gumpId); + } + + /// + /// Look for specific text in gump + /// + /// Expression + /// Should contain text and optional gumpid or any + /// Not used + /// Force flag + /// + private static bool InGump(string expression, Variable[] args, bool quiet, bool force) + { + if (args.Length < 1) + throw new RunTimeError("Usage: ingump (text) [gumpId/'any']"); + + // Get text + var text = args[0].AsString(false); + + // If gumpId passed get it, otherwise look at any + var gumpId = args.Length > 1 ? CommandHelper.IsUNumberOrAny(args[1].AsString(false)) : uint.MaxValue; + + if (gumpId != uint.MaxValue) + { + // Look in specific gump text + return World.Player.GumpList.TryGetValue(gumpId, out var gumpInfo) && gumpInfo.GumpContext.Any(line => line.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0); + } + + //Look in all gumps text + return World.Player.GumpList.Any(gump => gump.Value.GumpContext.Any(line => line.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)); + } + } +} diff --git a/Razor/Scripts/ScriptManager.cs b/Razor/Scripts/ScriptManager.cs index 30fee0c8..0385f0b7 100644 --- a/Razor/Scripts/ScriptManager.cs +++ b/Razor/Scripts/ScriptManager.cs @@ -43,8 +43,6 @@ public static class ScriptManager public static DateTime LastWalk { get; set; } public static bool SetLastTargetActive { get; set; } - - public static bool SetVariableActive { get; set; } public static bool TargetFound { get; set; } @@ -83,93 +81,76 @@ private static HighlightType[] GetHighlightTypes() public static bool PopoutEditor { get; set; } - private class ScriptTimer : Timer + public static void Tick() { - // Only run scripts once every 25ms to avoid spamming. - public ScriptTimer() : base(TimeSpan.FromMilliseconds(25), TimeSpan.FromMilliseconds(25)) - { - } - - protected override void OnTick() + try { - try + if (!Client.Instance.ClientRunning) { - if (!Client.Instance.ClientRunning) + if (ScriptRunning) { - if (ScriptRunning) - { - ScriptRunning = false; - Interpreter.StopScript(); - } - - return; + ScriptRunning = false; + Interpreter.StopScript(); } - bool running; - - if (_queuedScript != null) - { - // Starting a new script. This relies on the atomicity for references in CLR - var script = _queuedScript; + return; + } - running = Interpreter.StartScript(script); + bool running; - _queuedScript = null; - } - else - { - running = Interpreter.ExecuteScript(); - } + if (_queuedScript != null) + { + // Starting a new script. This relies on the atomicity for references in CLR + var script = _queuedScript; + running = Interpreter.StartScript(script); + UpdateLineNumber(Interpreter.CurrentLine); + _queuedScript = null; + } + else + { + running = Interpreter.ExecuteScript(); if (running) - { - if (ScriptManager.Running == false) - { - if (Config.GetBool("ScriptDisablePlayFinish")) - World.Player?.SendMessage(LocString.ScriptPlaying); + UpdateLineNumber(Interpreter.CurrentLine); + } - Assistant.Engine.MainWindow.LockScriptUI(true); - Assistant.Engine.RazorScriptEditorWindow?.LockScriptUI(true); - ScriptRunning = true; - } - } - else - { - if (ScriptManager.Running) - { - if (Config.GetBool("ScriptDisablePlayFinish")) - World.Player?.SendMessage(LocString.ScriptFinished); - Assistant.Engine.MainWindow.LockScriptUI(false); - Assistant.Engine.RazorScriptEditorWindow?.LockScriptUI(false); - ScriptRunning = false; + if (running) + { + if (Running == false) + { + if (Config.GetBool("ScriptDisablePlayFinish")) + World.Player?.SendMessage(LocString.ScriptPlaying); - ClearHighlightLine(HighlightType.Execution); - } + Assistant.Engine.MainWindow.LockScriptUI(true); + Assistant.Engine.RazorScriptEditorWindow?.LockScriptUI(true); + ScriptRunning = true; } } - catch (RunTimeError ex) + else { - if (ex.Node != null) + if (Running) { - World.Player?.SendMessage(MsgLevel.Error, $"Script Error: {ex.Message} (Line: {ex.Node.LineNumber + 1})"); + if (Config.GetBool("ScriptDisablePlayFinish")) + World.Player?.SendMessage(LocString.ScriptFinished); - SetHighlightLine(ex.Node.LineNumber, HighlightType.Error); - } - else - { - World.Player?.SendMessage(MsgLevel.Error, $"Script Error: {ex.Message}"); - } + Assistant.Engine.MainWindow.LockScriptUI(false); + Assistant.Engine.RazorScriptEditorWindow?.LockScriptUI(false); + ScriptRunning = false; - StopScript(); - } - catch (Exception ex) - { - World.Player?.SendMessage(MsgLevel.Error, $"Script Error: {ex.Message}"); - StopScript(); + ClearHighlightLine(HighlightType.Execution); + } } } + catch (Exception ex) + { + World.Player?.SendMessage(MsgLevel.Error, $"Script Error: {ex.Message} (Line: {Interpreter.CurrentLine + 1})"); + + SetHighlightLine(Interpreter.CurrentLine, HighlightType.Error); + + StopScript(); + } } /// @@ -185,8 +166,6 @@ public static void Initialize() Recurse(null, Config.GetUserDirectory("Scripts")); - Interpreter.ActiveScriptStatementExecuted += ActiveScriptStatementExecuted; - foreach (HighlightType type in GetHighlightTypes()) { HighlightLines[type] = new List(); @@ -349,7 +328,6 @@ public static void PlayScript(string[] lines) StopScript(); // be sure nothing is running SetLastTargetActive = false; - SetVariableActive = false; if (_queuedScript != null) return; @@ -365,12 +343,10 @@ public static void PlayScript(string[] lines) _queuedScript = script; } - private static void ActiveScriptStatementExecuted(ASTNode statement) + private static void UpdateLineNumber(int lineNum) { - if (statement != null && PopoutEditor) + if (PopoutEditor) { - var lineNum = statement.LineNumber; - SetHighlightLine(lineNum, HighlightType.Execution); // Scrolls to relevant line, per this suggestion: https://github.com/PavelTorgashov/FastColoredTextBox/issues/115 ScriptEditor.Selection.Start = new Place(0, lineNum); @@ -378,13 +354,6 @@ private static void ActiveScriptStatementExecuted(ASTNode statement) } } - private static ScriptTimer Timer { get; } - - static ScriptManager() - { - Timer = new ScriptTimer(); - } - public static void SetEditor(FastColoredTextBox scriptEditor, bool popoutEditor) { ScriptEditor = scriptEditor; @@ -424,22 +393,16 @@ public static void OnLogin() Aliases.Register(); Expressions.Register(); - Timer.Start(); + Outlands.Register(); } public static void OnLogout() { StopScript(); - Timer.Stop(); Assistant.Engine.MainWindow.LockScriptUI(false); Assistant.Engine.RazorScriptEditorWindow?.LockScriptUI(false); } - public static void StartEngine() - { - Timer.Start(); - } - private static List _scriptList { get; set; } public static void RedrawScriptVariables() @@ -449,9 +412,9 @@ public static void RedrawScriptVariables() s.BeginUpdate(); s.Items.Clear(); - foreach (ScriptVariables.ScriptVariable at in ScriptVariables.ScriptVariableList) + foreach (var kv in ScriptVariables.Variables) { - s.Items.Add($"'{at.Name}' ({at.TargetInfo.Serial})"); + s.Items.Add($"{kv.Key} ({kv.Value})"); } s.EndUpdate(); @@ -587,7 +550,8 @@ public static void InitScriptEditor() string[] keywords = { "if", "elseif", "else", "endif", "while", "endwhile", "for", "endfor", "break", "continue", "stop", - "replay", "not", "and", "or" + "replay", "not", "and", "or", + "foreach", "as", "in" }; #endregion @@ -602,8 +566,11 @@ public static void InitScriptEditor() "setlasttarget", "setvar", "skill", "sysmsg", "target", "targettype", "targetrelloc", "undress", "useonce", "walk", "wait", "pause", "waitforgump", "waitformenu", "waitforprompt", "waitfortarget", "clearsysmsg", "clearjournal", - "waitforsysmsg", "clearhands", "clearall", "virtue", "random" - + "waitforsysmsg", "clearhands", "clearall", "virtue", "random", + "warmode", "getlabel", "createlist", "clearlist", "removelist", "pushlist", "poplist", "createtimer", "removetimer", "settimer", + "unsetvar", "ignore", "clearignore", "rename", "setskill", "noto", "ingump", "gumpexists", "dead", "invul", "paralyzed", + "counttype", "diffmana", "diffstam", "diffhits", "diffweight", "maxweight", "targetexists", "find", "findlayer", "name", + "followers", "hue", "timerexists", "timer", }; #endregion @@ -639,12 +606,39 @@ public static void InitScriptEditor() tooltip = new ToolTipDescriptions("dclicktype", new[] { - "dclicktype ('name of item') OR (graphicID) [inrange] or usetype ('name of item') OR (graphicID) [inrange]" + "dclicktype ('name') OR ('graphic') [source] [hue] [quantity] [range]" }, "N/A", - "This command will use (double-click) an item type either provided by the name or the graphic ID.\n\t\tIf you include the optional true parameter, items within range (2 tiles) will only be considered.", - "dclicktype 'dagger'\n\t\twaitfortarget\n\t\ttargettype 'robe'"); + "This command will use (double-click) an item type either provided by the name or the graphic ID.\n\tYou can specify the source, color and search distance (or depth)", + "dclicktype 'dagger' 'backpack' 'any' 1 2\n\t\twaitfortarget\n\t\ttargettype 'robe'"); descriptionCommands.Add("dclicktype", tooltip); + tooltip = new ToolTipDescriptions("findtype", + new[] + { + "findtype ('name') OR ('graphic') [source] [hue] [quantity] [range]" + }, "N/A", + "This expression will find item or mobile by type either provided by the name or the graphic ID.\n\tYou can specify the source, color and search distance (or depth)", + "findtype 'an eagle' 'ground' 31337 1 2"); + descriptionCommands.Add("findtype", tooltip); + + tooltip = new ToolTipDescriptions("find", + new[] + { + "find (serial) [src] [hue] [qty] [range]" + }, "True if mobile or item with given serial was found", + "Check if mobile or item with given has been found.\n\tYou can specify the source, color and search distance (or depth)", + "find 'an eagle' 'ground' 31337 1 2"); + descriptionCommands.Add("find", tooltip); + + tooltip = new ToolTipDescriptions("findlayer", + new[] + { + "findlayer (serial) (layer)" + }, "Serial of founded item in passed layer, otherwise zero", + "Check if mobile with specified serial have item on a passed layer name.", + "if 'targetMe' 'ring'\n\tsay 'Nice ring'\nendif"); + descriptionCommands.Add("findlayer", tooltip); + tooltip = new ToolTipDescriptions("dress", new[] { "dress ('name of dress list')" }, "N/A", "This command will execute a spec dress list you have defined in Razor.", "dress 'My Sunday Best'"); descriptionCommands.Add("dress", tooltip); @@ -687,8 +681,8 @@ public static void InitScriptEditor() descriptionCommands.Add("lift", tooltip); tooltip = new ToolTipDescriptions("lifttype", - new[] { "lifttype (gfx) [amount] or lifttype ('name of item') [amount]" }, "N/A", - "This command will lift a specific item by type either by the graphic id or by the name.\n\tIf no amount is provided, 1 is defaulted.", + new[] { "lifttype (name) OR (graphic) [amount] [src] [hue]" }, "N/A", + "This command will lift a specific item by type either by the graphic id or by the name.\n\tIf no amount is provided, 1 is defaulted.\n\tSrc parameter can be 'ground','self' or 'backpack'", "lifttype 'robe'\n\twait 1000\n\tdroprelloc 1 1 0\n\tlifttype 0x1FCD\n\twait 1000\n\tdroprelloc 1 1"); descriptionCommands.Add("lifttype", tooltip); @@ -771,9 +765,11 @@ public static void InitScriptEditor() "overhead 'set last target'\n\tsetlasttarget\n\toverhead 'set!'\n\tcast 'magic arrow'\n\twaitfortarget\n\ttarget 'last'"); descriptionCommands.Add("setlasttarget", tooltip); - tooltip = new ToolTipDescriptions("setvar", new[] { "setvar ('variable') or setvariable ('variable')" }, + tooltip = new ToolTipDescriptions("setvar", new[] { "setvar ('variable') ['name'] or setvariable ('variable') ['serial']" }, "N/A", - "This command will pause the script until you select a target to be assigned a variable.\n\tPlease note, the variable must exist before you can assign values to it.", + "If no serial is provided, this command will pause the script until you select a target to be assigned a variable.\n\t" + + "If '!' is specified, set a temporary variable that exists only until Razor exits. If both ! and @ are specified, set a variable" + + "only in the local scope", "setvar 'dummy'\n\tcast 'magic arrow'\n\twaitfortarget\n\ttarget 'dummy'"); descriptionCommands.Add("setvar", tooltip); @@ -793,8 +789,8 @@ public static void InitScriptEditor() descriptionCommands.Add("target", tooltip); tooltip = new ToolTipDescriptions("targettype", - new[] { "targettype (graphic) or targettype ('name of item or mobile type') [inrangecheck]" }, "N/A", - "This command will target a specific type of mobile or item based on the graphic id or based on\n\tthe name of the item or mobile. If the optional parameter is passed\n\tin as true only items within the range of 2 tiles will be considered.", + new[] { "targettype ('name') OR ('graphic') [source] [hue] [quantity] [range]" }, "N/A", + "This command will target item or mobile by type either provided by the name or the graphic ID.\n\tYou can specify the source, color and search distance (or depth)", "usetype 'dagger'\n\twaitfortarget\n\ttargettype 'robe'\n\tuseobject 0x4005ECAF\n\twaitfortarget\n\ttargettype 0x1f03\n\tuseobject 0x4005ECAF\n\twaitfortarget\n\ttargettype 0x1f03 true"); descriptionCommands.Add("targettype", tooltip); @@ -878,6 +874,214 @@ public static void InitScriptEditor() #endregion + #region Outlands + + tooltip = new ToolTipDescriptions("warmode", + new[] { "warmode ('on' / 'off')" }, "N/A", + "Set your current war mode to on or off", + "warmode on\n"); + descriptionCommands.Add("warmode", tooltip); + + tooltip = new ToolTipDescriptions("getlabel", + new[] { "getlabel ('serial') ('name')" }, "N/A", + "Retrieve the label for the item with the given serial and store it in name. A label is the text displayed when single clicking.", + "getlabel 0x1234 mylabel\n"); + descriptionCommands.Add("getlabel", tooltip); + + tooltip = new ToolTipDescriptions("createlist", + new[] { "createlist ('list name')" }, "N/A", + "Create a new list", + "createlist mylist\n"); + descriptionCommands.Add("createlist", tooltip); + + tooltip = new ToolTipDescriptions("clearlist", + new[] { "clearlist ('list name')" }, "N/A", + "Clear an existing list. The list still exists after this operation.", + "clearlist mylist\n"); + descriptionCommands.Add("clearlist", tooltip); + + tooltip = new ToolTipDescriptions("removelist", + new[] { "removelist ('list name')" }, "N/A", + "Remove a list", + "removelist mylist\n"); + descriptionCommands.Add("removelist", tooltip); + + tooltip = new ToolTipDescriptions("pushlist", + new[] { "pushlist ('list name') ('element value') ['front'/'back']" }, "N/A", + "Push an element to a list", + "pushlist mylist myvalue front\n"); + descriptionCommands.Add("pushlist", tooltip); + + tooltip = new ToolTipDescriptions("listexists", + new[] { "listexists ('list name')" }, "True if list specified by name exists", + "Check if list specified by list_name exist", + "if listexists myList\n\tpoplist mylist front\nendif\n"); + descriptionCommands.Add("listexists", tooltip); + + tooltip = new ToolTipDescriptions("poplist", + new[] { "poplist ('list name') ('element value'/'front'/'back')" }, "N/A", + "Pop an element from the list", + "poplist mylist front\n"); + descriptionCommands.Add("poplist", tooltip); + + tooltip = new ToolTipDescriptions("createtimer", + new[] { "createtimer ('timer name')" }, "N/A", + "Create and start a new timer", + "creatertimer atimer\n"); + descriptionCommands.Add("createtimer", tooltip); + + tooltip = new ToolTipDescriptions("removetimer", + new[] { "removetimer ('timer name')" }, "N/A", + "Stop and remove a timer", + "removetimer atimer\n"); + descriptionCommands.Add("removetimer", tooltip); + + tooltip = new ToolTipDescriptions("settimer", + new[] { "settimer ('timer name') ('value')" }, "N/A", + "Set a timer to the given time value", + "settimer atimer 10\n"); + descriptionCommands.Add("settimer", tooltip); + + tooltip = new ToolTipDescriptions("timerexists", + new[] { "timerexists ('timer name')" }, "Return true is target specified by name exists", + "Check if target with specified name exists", + "if timerexists 'clock'\n\tcreatetimer 'clock'\nendif\n"); + descriptionCommands.Add("timerexists", tooltip); + + tooltip = new ToolTipDescriptions("timer", + new[] { "timer ('timer name')" }, "Return value of timer specified by name", + "Get value of timer specified by name", + "if timer 'discoBuff' > 5000\n\tskill 'Discorance'\n\twft\n\ttarget 'spellBookSerial'\nendif\n"); + descriptionCommands.Add("timer", tooltip); + + tooltip = new ToolTipDescriptions("unsetvar", + new[] { "unsetvar ('name')" }, "N/A", + "Unset a variable. If '!' is specified, unset a temporary variable. If both ! and @ are specified, unset a temporary local variable.", + "unsetvar myvar\n"); + descriptionCommands.Add("unsetvar", tooltip); + + tooltip = new ToolTipDescriptions("rename", + new[] { "rename ('serial') ('name')" }, "N/A", + "Rename a creature (one of your followers) with the provided name", + "rename mypet fido\n"); + descriptionCommands.Add("rename", tooltip); + + tooltip = new ToolTipDescriptions("gumpexists", + new[] { "gumpexists ('gumpId or any')" }, "True if gump exists", + "Check if gump with specified id or any exist", + "gumpexists 0x41434\n"); + descriptionCommands.Add("gumpexists", tooltip); + + tooltip = new ToolTipDescriptions("ingump", + new[] { "ingump ('text') [gumpId/any]" }, "True if text exists in gumps", + "Check if text in gump with specified id or any exists", + "ingump test any\n"); + descriptionCommands.Add("ingump", tooltip); + + tooltip = new ToolTipDescriptions("dead", + new[] { "dead ['serial']" }, "True mobile with serial is dead", + "Check if mobile (default 'self') is dead", + "if dead 0x43434\n\tcast 'Resurrection'\nendif\n"); + descriptionCommands.Add("dead", tooltip); + + tooltip = new ToolTipDescriptions("noto", + new[] { "noto ('serial')" }, "Name of the notority flag of mobile", + "Return Notority name of mobile by serial", + "if noto 0x43434 = 'innocent'\n\tcast 'Heal'\nendif\n"); + descriptionCommands.Add("noto", tooltip); + + tooltip = new ToolTipDescriptions("invul", + new[] { "invul" }, "True if player is invaluable", + "Check if player is invaluable", + "if invul\n\toverhead 'WoW'\nendif\n"); + descriptionCommands.Add("invul", tooltip); + + tooltip = new ToolTipDescriptions("paralyzed", + new[] { "paralyzed" }, "True if player is paralyzed", + "Check if player is paralyzed", + "if paralyzed\n\tsay [pouch\nendif\n"); + descriptionCommands.Add("paralyzed", tooltip); + + tooltip = new ToolTipDescriptions("counttype", + new[] { "counttype (name or graphic) [src] [hue] [range]" }, "Number of items in container", + "Get number of items by name or graphic.\n\tYou can specify the source, color and search distance (or depth)", + "if counttype 'dagger' 'ground'\n\torganizer 1\nendif\n"); + descriptionCommands.Add("counttype", tooltip); + + tooltip = new ToolTipDescriptions("diffmana", + new[] { "diffmana" }, "Absolute value between max mana and current mana", + "Get absolute difference between max mana and mana", + "if diffmana > 20\n\tskill Meditiation\nendif\n"); + descriptionCommands.Add("diffmana", tooltip); + + tooltip = new ToolTipDescriptions("diffstam", + new[] { "diffstam" }, "Absolute value between max stamina and current stamina", + "Get absolute difference between max stamina and stamina", + "if diffstam > 20\n\toverhead 'I need a rest'\nendif\n"); + descriptionCommands.Add("diffstam", tooltip); + + tooltip = new ToolTipDescriptions("diffhits", + new[] { "diffhits" }, "Absolute value between max hp and current hp", + "Get absolute difference between max hp and hp", + "if diffhits > 20\n\tcast 'Heal'\n\twft\n\ttarget 'self'\nendif\n"); + descriptionCommands.Add("diffhits", tooltip); + + tooltip = new ToolTipDescriptions("diffweight", + new[] { "diffweight" }, "Absolute value between weight hp and current weight", + "Get absolute difference between max weight and weight", + "if diffweight > 20\n\tcast 'Bless'\n\twft\n\ttarget 'self'\nendif\n"); + descriptionCommands.Add("diffweight", tooltip); + + tooltip = new ToolTipDescriptions("maxweight", + new[] { "maxweight" }, "Return player current max weight", + "Get player current max weight", + "if maxweight < 500\n\tcast 'Bless'\n\twft\n\ttarget 'self'\nendif\n"); + descriptionCommands.Add("maxweight", tooltip); + + tooltip = new ToolTipDescriptions("targetexists", + new[] { "targetexists" }, "Return player current max weight", + "Get player current max weight", + "if targetexists < 500\n\tcast 'Bless'\n\twft\n\ttarget 'self'\nendif\n"); + descriptionCommands.Add("targetexists", tooltip); + + tooltip = new ToolTipDescriptions("name", + new[] { "name" }, "Return player name", + "Get player name", + "if name = 'Bob'\n\toverhead 'Good... Its me'\nendif\n"); + descriptionCommands.Add("name", tooltip); + + tooltip = new ToolTipDescriptions("hue", + new[] { "hue (serial)" }, "Return hue of item", + "Get hue of item specified by serial.", + "if hue 'boardSerial' = 1763\n\toverhead 'Yeah, averboard!'\nendif\n"); + descriptionCommands.Add("hue", tooltip); + + tooltip = new ToolTipDescriptions("followers", + new[] { "followers" }, "Return the number of followers", + "Get the number of followers for player", + "if followers > 0\n\tsay 'all release'\nendif\n"); + descriptionCommands.Add("followers", tooltip); + + tooltip = new ToolTipDescriptions("clearignore", + new[] { "clearignore" }, "N/A", + "Clear list of ignored serials", + "clearignore\n"); + descriptionCommands.Add("clearignore", tooltip); + + tooltip = new ToolTipDescriptions("ignore", + new[] { "ignore (serial)" }, "N/A", + "Add mobile or item serial to ignore list", + "if targettype 'an eagle' as mob\n\tskill 'Animal Lore'\n\twft\n\ttarget mob\n\tignore mob\nendif\n"); + descriptionCommands.Add("ignore", tooltip); + + tooltip = new ToolTipDescriptions("setskill", + new[] { "setskill (skill_name) (up/donw/lock)" }, "N/A", + "Set state of skill specified by skill_name to state specified by second argument\n\tUse the name of skill visible in Skills tab from Paperdoll", + "setskill 'Blacksmithy' 'lock'\n"); + descriptionCommands.Add("setskill", tooltip); + + #endregion + if (!Config.GetBool("DisableScriptTooltips")) { List items = new List(); diff --git a/Razor/Scripts/ScriptVariables.cs b/Razor/Scripts/ScriptVariables.cs index 585bd472..05bf276a 100644 --- a/Razor/Scripts/ScriptVariables.cs +++ b/Razor/Scripts/ScriptVariables.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Xml; using Assistant.Scripts.Engine; @@ -27,83 +28,17 @@ namespace Assistant.Scripts { public class ScriptVariables { - public class ScriptVariable - { - public TargetInfo TargetInfo { get; set; } - public string Name { get; set; } - public bool TargetWasSet { get; set; } - - public ScriptVariable(string targetVarName, TargetInfo t) - { - TargetInfo = t; - Name = targetVarName; - } - - public void SetTarget() - { - if (World.Player != null) - { - TargetWasSet = false; - - Targeting.OneTimeTarget(OnScriptVariableTarget); - World.Player.SendMessage(MsgLevel.Force, $"Select target for variable '{Name}'"); - - //OneTimeTarget(false, new Targeting.TargetResponseCallback(OnMacroVariableTarget), new Targeting.CancelTargetCallback(OnSLTCancel)); - } - } - - private void OnScriptVariableTarget(bool ground, Serial serial, Point3D pt, ushort gfx) - { - TargetInfo t = new TargetInfo - { - Gfx = gfx, - Serial = serial, - Type = (byte) (ground ? 1 : 0), - X = pt.X, - Y = pt.Y, - Z = pt.Z - }; - - bool foundVar = false; - - foreach (ScriptVariable sV in ScriptVariableList - ) - { - if (sV.Name.Equals(Name, StringComparison.OrdinalIgnoreCase)) - { - foundVar = true; - sV.TargetInfo = t; - - World.Player.SendMessage(MsgLevel.Force, - $"'{sV.Name}' script variable updated to '{t.Serial}'"); - - break; - } - } + private static Dictionary _variables = new Dictionary(); - // Save and reload the vars - if (foundVar) - Assistant.Engine.MainWindow.SaveScriptVariables(); - - TargetWasSet = true; - } - } - - public static List ScriptVariableList = new List(); + public static IEnumerable> Variables => _variables; public static void Save(XmlTextWriter xml) { - foreach (ScriptVariable target in ScriptVariableList) + foreach (var kv in _variables) { xml.WriteStartElement("scriptvariable"); - xml.WriteAttributeString("type", target.TargetInfo.Type.ToString()); - xml.WriteAttributeString("flags", target.TargetInfo.Flags.ToString()); - xml.WriteAttributeString("serial", target.TargetInfo.Serial.ToString()); - xml.WriteAttributeString("x", target.TargetInfo.X.ToString()); - xml.WriteAttributeString("y", target.TargetInfo.Y.ToString()); - xml.WriteAttributeString("z", target.TargetInfo.X.ToString()); - xml.WriteAttributeString("gfx", target.TargetInfo.Gfx.ToString()); - xml.WriteAttributeString("name", target.Name); + xml.WriteAttributeString("serial", kv.Value.ToString()); + xml.WriteAttributeString("name", kv.Key); xml.WriteEndElement(); } } @@ -116,21 +51,10 @@ public static void Load(XmlElement node) { foreach (XmlElement el in node.GetElementsByTagName("scriptvariable")) { - TargetInfo target = new TargetInfo - { - Type = Convert.ToByte(el.GetAttribute("type")), - Flags = Convert.ToByte(el.GetAttribute("flags")), - Serial = Convert.ToUInt32(Serial.Parse(el.GetAttribute("serial"))), - X = Convert.ToUInt16(el.GetAttribute("x")), - Y = Convert.ToUInt16(el.GetAttribute("y")), - Z = Convert.ToUInt16(el.GetAttribute("z")), - Gfx = Convert.ToUInt16(el.GetAttribute("gfx")) - }; - - ScriptVariable scriptVariable = new ScriptVariable(el.GetAttribute("name"), target); - ScriptVariableList.Add(scriptVariable); - - RegisterVariable(scriptVariable.Name); + var name = el.GetAttribute("name"); + var serial = Serial.Parse(el.GetAttribute("serial")); + + RegisterVariable(name, serial); } } catch @@ -139,50 +63,42 @@ public static void Load(XmlElement node) } } - public static void RegisterVariable(string name) + public static void RegisterVariable(string name, Serial serial) { - Interpreter.RegisterAliasHandler(name, ScriptVariableHandler); + name = name.Trim(); + + _variables[name] = serial; + Interpreter.SetAlias(name, serial); } public static void UnregisterVariable(string name) { - Interpreter.UnregisterAliasHandler(name); - } - - private static uint ScriptVariableHandler(string alias) - { - foreach (ScriptVariable scriptVariable in ScriptVariableList) - { - if (scriptVariable.Name.Equals(alias)) - { - return scriptVariable.TargetInfo.Serial; - } - } - - return 0; + name = name.Trim(); + Interpreter.ClearAlias(name); + _variables.Remove(name); } public static void ClearAll() { - foreach (ScriptVariable scriptVariable in ScriptVariableList) + var varList = _variables.ToList(); + foreach (var kv in varList) { - Interpreter.UnregisterAliasHandler(scriptVariable.Name); + UnregisterVariable(kv.Key); } - ScriptVariableList.Clear(); + _variables.Clear(); } - public static ScriptVariable GetVariable(string name) + public static Serial GetVariable(string name) { - foreach (ScriptVariable scriptVariable in ScriptVariableList) + name = name.Trim(); + + if (_variables.TryGetValue(name, out var val)) { - if (scriptVariable.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) - { - return scriptVariable; - } + return val; } - return null; + return Serial.MinusOne; } } } \ No newline at end of file diff --git a/Razor/Scripts/SpeechCommands.cs b/Razor/Scripts/SpeechCommands.cs index 451453ed..a542565b 100644 --- a/Razor/Scripts/SpeechCommands.cs +++ b/Razor/Scripts/SpeechCommands.cs @@ -36,11 +36,11 @@ public static void Register() Interpreter.RegisterCommandHandler("alliance", Alliance); } - private static bool Say(string command, Argument[] args, bool quiet, bool force) + private static bool Say(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: say ('text') [color]"); + throw new RunTimeError("Usage: say ('text') [color]"); } if (args.Length == 1) @@ -51,11 +51,11 @@ private static bool Say(string command, Argument[] args, bool quiet, bool force) return true; } - private static bool Whisper(string command, Argument[] args, bool quiet, bool force) + private static bool Whisper(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: whisper ('text') [color]"); + throw new RunTimeError("Usage: whisper ('text') [color]"); } MessageType type = MessageType.Whisper & ~MessageType.Encoded; @@ -68,11 +68,11 @@ private static bool Whisper(string command, Argument[] args, bool quiet, bool fo return true; } - private static bool Yell(string command, Argument[] args, bool quiet, bool force) + private static bool Yell(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: yell ('text') [color]"); + throw new RunTimeError("Usage: yell ('text') [color]"); } if (args.Length == 1) @@ -83,11 +83,11 @@ private static bool Yell(string command, Argument[] args, bool quiet, bool force return true; } - private static bool Emote(string command, Argument[] args, bool quiet, bool force) + private static bool Emote(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: emote ('text') [color]"); + throw new RunTimeError("Usage: emote ('text') [color]"); } if (args.Length == 1) @@ -98,11 +98,11 @@ private static bool Emote(string command, Argument[] args, bool quiet, bool forc return true; } - private static bool Guild(string command, Argument[] args, bool quiet, bool force) + private static bool Guild(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: guild ('text')"); + throw new RunTimeError("Usage: guild ('text')"); } if (args.Length == 1) @@ -113,11 +113,11 @@ private static bool Guild(string command, Argument[] args, bool quiet, bool forc return true; } - private static bool Alliance(string command, Argument[] args, bool quiet, bool force) + private static bool Alliance(string command, Variable[] args, bool quiet, bool force) { if (args.Length == 0) { - throw new RunTimeError(null, "Usage: alliance ('text')"); + throw new RunTimeError("Usage: alliance ('text')"); } if (args.Length == 1) diff --git a/Razor/Scripts/TargetCommands.cs b/Razor/Scripts/TargetCommands.cs index 12bfaf5c..ab7790b6 100644 --- a/Razor/Scripts/TargetCommands.cs +++ b/Razor/Scripts/TargetCommands.cs @@ -40,11 +40,11 @@ public static void Register() Interpreter.RegisterCommandHandler("wft", WaitForTarget); //WaitForTargetAction } - private static bool Target(string command, Argument[] args, bool quiet, bool force) + private static bool Target(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 1) { - throw new RunTimeError(null, "Usage: target (serial) OR target (closest/random/next/prev [noto] [type]"); + throw new RunTimeError("Usage: target (serial) OR target (closest/random/next/prev [noto] [type]"); } switch (args[0].AsString()) @@ -109,15 +109,15 @@ private static bool Target(string command, Argument[] args, bool quiet, bool for return true; } - private static bool TargetType(string command, Argument[] args, bool quiet, bool force) + private static bool TargetType(string command, Variable[] args, bool quiet, bool force) { if (Targeting.FromGrabHotKey) return false; if (args.Length < 1) { - throw new RunTimeError(null, - "Usage: targettype (graphic) OR ('name of item or mobile type') [inrangecheck/backpack]"); + throw new RunTimeError( + "Usage: targettype (graphic) OR ('name of item or mobile type') [src] [hue] [qty] [range]"); } string gfxStr = args[0].AsString(); @@ -125,41 +125,28 @@ private static bool TargetType(string command, Argument[] args, bool quiet, bool List items; List mobiles = new List(); - bool inRangeCheck = false; - bool backpack = false; - - if (args.Length == 2) - { - if (args[1].AsString().IndexOf("pack", StringComparison.InvariantCultureIgnoreCase) != -1) - { - backpack = true; - } - else - { - inRangeCheck = args[1].AsBool(); - } - } + (Serial src, int hue, int qty, int range) = CommandHelper.ParseFindArguments(args); // No graphic id, maybe searching by name? if (gfx == 0) { - items = CommandHelper.GetItemsByName(gfxStr, backpack, inRangeCheck); + items = CommandHelper.GetItemsByName(gfxStr, hue, src, (short)qty, range); if (items.Count == 0) // no item found, search mobile by name { - mobiles = CommandHelper.GetMobilesByName(gfxStr, inRangeCheck); + mobiles = CommandHelper.GetMobilesByName(gfxStr, range); } } else // Provided graphic id for type, check backpack first (same behavior as DoubleClickAction in macros { ushort id = Utility.ToUInt16(gfxStr, 0); - items = CommandHelper.GetItemsById(id, backpack, inRangeCheck); + items = CommandHelper.GetItemsById(id, hue, src, (short)qty, range); // Still no item? Mobile check! if (items.Count == 0) { - mobiles = CommandHelper.GetMobilesById(id, inRangeCheck); + mobiles = CommandHelper.GetMobilesById(id, range); } } @@ -179,14 +166,14 @@ private static bool TargetType(string command, Argument[] args, bool quiet, bool return true; } - private static bool TargetRelLoc(string command, Argument[] args, bool quiet, bool force) + private static bool TargetRelLoc(string command, Variable[] args, bool quiet, bool force) { if (Targeting.FromGrabHotKey) return false; if (args.Length < 2) { - throw new RunTimeError(null, "Usage: targetrelloc (x-offset) (y-offset)"); + throw new RunTimeError("Usage: targetrelloc (x-offset) (y-offset)"); } int xoffset = Utility.ToInt32(args[0].AsString(), 0); @@ -203,17 +190,17 @@ private static bool TargetRelLoc(string command, Argument[] args, bool quiet, bo } catch (Exception e) { - throw new RunTimeError(null, $"{command} - Error Executing: {e.Message}"); + throw new RunTimeError($"{command} - Error Executing: {e.Message}"); } return true; } - private static bool TargetLocation(string command, Argument[] args, bool quiet, bool force) + private static bool TargetLocation(string command, Variable[] args, bool quiet, bool force) { if (args.Length < 2) { - throw new RunTimeError(null, "Usage: targetloc (x) (y) (z)"); + throw new RunTimeError("Usage: targetloc (x) (y) (z)"); } Targeting.Target(new TargetInfo @@ -230,7 +217,7 @@ private static bool TargetLocation(string command, Argument[] args, bool quiet, return true; } - private static bool WaitForTarget(string command, Argument[] args, bool quiet, bool force) + private static bool WaitForTarget(string command, Variable[] args, bool quiet, bool force) { if (Targeting.HasTarget) { diff --git a/Razor/UI/Config.cs b/Razor/UI/Config.cs index 2bdf6660..62da3600 100644 --- a/Razor/UI/Config.cs +++ b/Razor/UI/Config.cs @@ -1,7 +1,7 @@ #region license // Razor: An Ultima Online Assistant -// Copyright (C) 2021 Razor Development Community on GitHub +// Copyright (C) 2020 Razor Development Community on GitHub // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -292,7 +292,11 @@ public void MakeDefault() AddProperty("AutoSaveScriptPlay", false); AddProperty("HighlightFriend", false); - + + AddProperty("ScriptTargetTypeRange", false); + AddProperty("ScriptDClickTypeRange", false); + AddProperty("ScriptFindTypeRange", false); + AddProperty("ScriptDisablePlayFinish", false); AddProperty("ShowWaypointOverhead", true); @@ -702,6 +706,52 @@ public class Config private static Profile m_Current; private static Dictionary m_Chars; + private static Dictionary m_AppSettings = new Dictionary(); + + static Config() + { + var path = Path.Combine(Engine.RootPath, "settings.csv"); + + // Set defaults + m_AppSettings["UODataDir"] = @"D:\Games\UO"; + m_AppSettings["UOClient"] = @"D:\Games\UO\client.exe"; + m_AppSettings["LastPort"] = "2593"; + m_AppSettings["LastProfile"] = "default"; + m_AppSettings["LastServer"] = "127.0.0.1"; + m_AppSettings["LastServerId"] = "0"; + m_AppSettings["ClientEncrypted"] = "1"; + m_AppSettings["ServerEncrypted"] = "0"; + m_AppSettings["ShowWelcome"] = "1"; + m_AppSettings["UId"] = "21613fcd"; + m_AppSettings["MaxOrganizerAgents"] = "20"; + m_AppSettings["MaxBuyAgents"] = "10"; + m_AppSettings["MaxRestockAgents"] = "10"; + m_AppSettings["ImportProfilesAndMacros"] = "true"; + m_AppSettings["BackupPath"] = @".\Backup"; + + try + { + if (!File.Exists(path)) + { + File.Create(path); + } + else + { + foreach (var line in File.ReadLines(path)) + { + var strs = line.Split(','); + + m_AppSettings[strs[0].Trim()] = strs[1].Trim(); + } + } + } + catch (Exception) + { } + finally + { + } + } + public static Profile CurrentProfile { get @@ -717,6 +767,7 @@ public static void Save() if (m_Current != null) m_Current.Save(); SaveCharList(); + SaveAppSettings(); } public static bool LoadProfile(string name) @@ -907,11 +958,31 @@ public static List GetProfileList() return list; } + private static void SaveAppSettings() + { + var path = Path.Combine(Engine.RootPath, "settings.csv"); + + Engine.EnsureDirectory(Engine.RootPath); + + if (!File.Exists(path)) + { + File.Create(path); + } + + var data = ""; + foreach (var setting in m_AppSettings) + { + data += $"{setting.Key}, {setting.Value}\n"; + } + + File.WriteAllText(path, data); + } + public static T GetAppSetting(string key) { try { - var appSetting = ConfigurationManager.AppSettings[key]; + var appSetting = m_AppSettings[key]; if (!string.IsNullOrWhiteSpace(appSetting)) { @@ -966,13 +1037,8 @@ public static bool SetAppSetting(string key, string value) { try { - Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); - config.AppSettings.Settings.Remove(key); - config.AppSettings.Settings.Add(key, value); - - config.Save(ConfigurationSaveMode.Modified, true); - - ConfigurationManager.RefreshSection("appSettings"); + m_AppSettings[key] = value; + SaveAppSettings(); return true; } diff --git a/Razor/UI/Razor.Designer.cs b/Razor/UI/Razor.Designer.cs index 9cd0ad01..1412e9da 100644 --- a/Razor/UI/Razor.Designer.cs +++ b/Razor/UI/Razor.Designer.cs @@ -314,7 +314,7 @@ public partial class MainForm : System.Windows.Forms.Form private ComboBox playableMusicList; private TreeView _macroTreeViewCache = new TreeView(); private TreeView _scriptTreeViewCache = new TreeView(); - + private ErrorProvider _objDelayErrorProvider; public Label WaitDisplay { @@ -1641,7 +1641,16 @@ private void InitializeComponent() this.txtObjDelay.Size = new System.Drawing.Size(32, 23); this.txtObjDelay.TabIndex = 56; this.txtObjDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - this.txtObjDelay.TextChanged += new System.EventHandler(this.txtObjDelay_TextChanged); + this.txtObjDelay.Validating += new System.ComponentModel.CancelEventHandler(this.textObjDelay_Validating); + this.txtObjDelay.Validated += new System.EventHandler(this.txtObjDelay_Validated); + this.txtObjDelay.Text = "500"; + // + // errorProvider for textObjDelay + // + this._objDelayErrorProvider = new ErrorProvider(); + this._objDelayErrorProvider.SetIconAlignment(this.txtObjDelay, ErrorIconAlignment.MiddleRight); + this._objDelayErrorProvider.SetIconPadding(this.txtObjDelay, 2); + this._objDelayErrorProvider.BlinkStyle = ErrorBlinkStyle.AlwaysBlink; // // objectDelay // @@ -1651,6 +1660,8 @@ private void InitializeComponent() this.objectDelay.TabIndex = 53; this.objectDelay.Text = "Object Delay:"; this.objectDelay.CheckedChanged += new System.EventHandler(this.objectDelay_CheckedChanged); + this.objectDelay.Checked = true; + this.objectDelay.Enabled = false; // // ltRange // @@ -1697,7 +1708,7 @@ private void InitializeComponent() // // label6 // - this.label6.Location = new System.Drawing.Point(147, 93); + this.label6.Location = new System.Drawing.Point(157, 93); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(32, 18); this.label6.TabIndex = 55; diff --git a/Razor/UI/Razor.cs b/Razor/UI/Razor.cs index 7e383148..66412d52 100644 --- a/Razor/UI/Razor.cs +++ b/Razor/UI/Razor.cs @@ -127,6 +127,10 @@ public void MainForm_EndLoad() private bool m_Initializing = false; + private readonly int MAX_OBJ_DELAY_VALUE = 4000; + + private readonly int MIN_OBJ_DELAY_VALUE = 50; + public void InitConfig() { m_Initializing = true; @@ -241,9 +245,9 @@ public void InitConfig() autoOpenDoors.SafeAction(s => { s.Checked = Config.GetBool("AutoOpenDoors"); }); - objectDelay.SafeAction(s => { s.Checked = Config.GetBool("ObjectDelayEnabled"); }); + //objectDelay.SafeAction(s => { s.Checked = Config.GetBool("ObjectDelayEnabled"); }); - txtObjDelay.SafeAction(s => { s.Enabled = Config.GetBool("ObjectDelayEnabled"); }); + //txtObjDelay.SafeAction(s => { s.Enabled = Config.GetBool("ObjectDelayEnabled"); }); msglvl.SafeAction(s => { s.SelectedIndex = Config.GetInt("MessageLevel"); }); @@ -2013,8 +2017,24 @@ private void QueueActions_CheckedChanged(object sender, System.EventArgs e) Config.SetProperty("QueueActions", QueueActions.Checked); } - private void txtObjDelay_TextChanged(object sender, System.EventArgs e) + private void textObjDelay_Validating(object sender, CancelEventArgs e) + { + if (!int.TryParse(txtObjDelay.Text, out var newValue)) + { + _objDelayErrorProvider.SetError(txtObjDelay, $"Value must be between number"); + e.Cancel = true; + } + + if (newValue > MAX_OBJ_DELAY_VALUE || newValue < MIN_OBJ_DELAY_VALUE) + { + _objDelayErrorProvider.SetError(txtObjDelay, $"Value must be between {MIN_OBJ_DELAY_VALUE} and {MAX_OBJ_DELAY_VALUE}"); + e.Cancel = true; + } + } + + private void txtObjDelay_Validated(object sender, System.EventArgs e) { + _objDelayErrorProvider.Clear(); Config.SetProperty("ObjectDelay", Utility.ToInt32(txtObjDelay.Text.Trim(), 500)); } @@ -4055,11 +4075,12 @@ private void msglvl_SelectedIndexChanged(object sender, System.EventArgs e) Config.SetProperty("MessageLevel", msglvl.SelectedIndex); } - private void screenPrev_Click(object sender, System.EventArgs e) + private void screenPrev_Click(object sender, EventArgs e) { - string file = screensList.SelectedItem as String; - if (file != null) - System.Diagnostics.Process.Start(Path.Combine(Config.GetString("CapPath"), file)); + if (screensList.SelectedItem is string file) + { + RunOpenProcess(Path.Combine(Config.GetString("CapPath"), file)); + } } private Timer m_ResizeTimer = Timer.DelayedCallback(TimeSpan.FromSeconds(1.0), new TimerCallback(ForceSize)); @@ -4492,7 +4513,6 @@ private void createBackup_Click(object sender, EventArgs e) { string backupTime = $"{DateTime.Now:yyyyMMdd-HHmmss}"; string backupDir = Path.Combine(Config.GetAppSetting("BackupPath"), backupTime); - ; if (string.IsNullOrEmpty(backupDir)) return; @@ -5452,10 +5472,14 @@ private void setBackupFolder_Click(object sender, EventArgs e) FolderBrowserDialog folder = new FolderBrowserDialog(); folder.Description = "Select Backup Folder"; - folder.SelectedPath = Config.GetAppSetting("BackupPath"); + if (Directory.Exists(Config.GetAppSetting("BackupPath"))) + { + folder.SelectedPath = Config.GetAppSetting("BackupPath"); + } + folder.ShowNewFolderButton = true; - if (folder.ShowDialog(this) == DialogResult.OK) + if (folder.ShowDialog(this) == DialogResult.OK && !string.IsNullOrWhiteSpace(folder.SelectedPath)) { Config.SetAppSetting("BackupPath", folder.SelectedPath); } @@ -5463,13 +5487,7 @@ private void setBackupFolder_Click(object sender, EventArgs e) private void openBackupFolder_Click(object sender, EventArgs e) { - try - { - Process.Start(Config.GetAppSetting("BackupPath")); - } - catch - { - } + RunOpenProcess(Config.GetAppSetting("BackupPath")); } private void targetIndicatorFormat_TextChanged(object sender, EventArgs e) @@ -6309,10 +6327,16 @@ private void scriptEditor_KeyDown(object sender, KeyEventArgs e) private void SaveScript() { - if (_selectedScript == null) + RazorScript selectedScript = GetScriptSel(); + + // If not found on Tree try to get it from Script Manager + if (selectedScript == null) + selectedScript = ScriptManager.SelectedScript; + + // Still nothing? create new + if (selectedScript == null) { string filePath = $"{Path.Combine(ScriptManager.ScriptPath, $"auto-{Guid.NewGuid().ToString().Substring(0, 4)}.razor")}"; - File.WriteAllText(filePath, scriptEditor.Text); RazorScript script = new RazorScript @@ -6321,7 +6345,7 @@ private void SaveScript() Name = Path.GetFileNameWithoutExtension(filePath), Path = filePath }; - + TreeNode node = ScriptManager.GetScriptDirNode(); ScriptManager.RedrawScripts(); @@ -6459,67 +6483,28 @@ private void addScriptVariable_Click(object sender, EventArgs e) if (ScriptManager.Running || ScriptManager.Recording || World.Player == null) return; - Targeting.OneTimeTarget(OnScriptVariableAddTarget); - - World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct); - } - - private void OnScriptVariableAddTarget(bool ground, Serial serial, Point3D pt, ushort gfx) - { - TargetInfo t = new TargetInfo - { - Gfx = gfx, - Serial = serial, - Type = (byte) (ground ? 1 : 0), - X = pt.X, - Y = pt.Y, - Z = pt.Z - }; - - if (InputBox.Show(this, Language.GetString(LocString.NewScriptVariable), - Language.GetString(LocString.EnterAName))) + Targeting.OneTimeTarget((ground, serial, pt, gfx) => { - string name = InputBox.GetString(); - - foreach (ScriptVariables.ScriptVariable mV in ScriptVariables.ScriptVariableList - ) + if (InputBox.Show(this, Language.GetString(LocString.NewScriptVariable), + Language.GetString(LocString.EnterAName))) { - if (mV.Name.ToLower().Equals(name.ToLower())) + string name = InputBox.GetString(); + + if (ScriptVariables.GetVariable(name) != Serial.MinusOne) { MessageBox.Show(this, "Pick a unique Script Variable name and try again", "New Script Variable", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - } - - ScriptVariables.ScriptVariableList.Add( - new ScriptVariables.ScriptVariable(name, t)); - - ScriptVariables.RegisterVariable(name); - ScriptManager.RedrawScripts(); - } - - Engine.MainWindow.ShowMe(); - } - - private void OnScriptVariableReTarget(bool ground, Serial serial, Point3D pt, ushort gfx) - { - TargetInfo t = new TargetInfo - { - Gfx = gfx, - Serial = serial, - Type = (byte) (ground ? 1 : 0), - X = pt.X, - Y = pt.Y, - Z = pt.Z - }; - - ScriptVariables.ScriptVariableList[scriptVariables.SelectedIndex].TargetInfo = t; + ScriptVariables.RegisterVariable(name, serial); + ScriptManager.RedrawScripts(); + } - ScriptManager.RedrawScripts(); + Engine.MainWindow.ShowMe(); + }); - Engine.MainWindow.ShowMe(); + World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct); } private void changeScriptVariable_Click(object sender, EventArgs e) @@ -6530,7 +6515,15 @@ private void changeScriptVariable_Click(object sender, EventArgs e) if (scriptVariables.SelectedIndex < 0) return; - Targeting.OneTimeTarget(OnScriptVariableReTarget); + var name = scriptVariables.SelectedItem.ToString(); + name = name.Split('(')[0].Trim(); + + Targeting.OneTimeTarget((ground, serial, pt, gfx) => + { + ScriptVariables.RegisterVariable(name, serial); + ScriptManager.RedrawScripts(); + Engine.MainWindow.ShowMe(); + }); World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct); } @@ -6543,9 +6536,10 @@ private void removeScriptVariable_Click(object sender, EventArgs e) if (scriptVariables.SelectedIndex < 0) return; - ScriptVariables.UnregisterVariable(ScriptVariables.ScriptVariableList[scriptVariables.SelectedIndex].Name); - ScriptVariables.ScriptVariableList.RemoveAt(scriptVariables.SelectedIndex); + var name = scriptVariables.SelectedItem.ToString(); + name = name.Split('(')[0].Trim(); + ScriptVariables.UnregisterVariable(name); ScriptManager.RedrawScripts(); } @@ -7541,14 +7535,24 @@ private void AddScriptCategory(object sender, EventArgs args) } private void openScreenshotFolder_Click(object sender, EventArgs e) + { + RunOpenProcess(Config.GetString("CapPath")); + } + + /// + /// Run Open Process + /// + /// Path to open file or folder + private void RunOpenProcess(string path) { try { - Process.Start(Config.GetString("CapPath")); + var psi = new ProcessStartInfo { FileName = path, UseShellExecute = true }; + Process.Start(psi); } catch (Exception ex) { - MessageBox.Show(this, ex.Message, "Unable to open directory", MessageBoxButtons.OK, + MessageBox.Show(this, ex.Message, "Unable to open", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } diff --git a/Razor/UI/RazorScriptEditor.Designer.cs b/Razor/UI/RazorScriptEditor.Designer.cs index 5fa570bd..0ae27a4f 100644 --- a/Razor/UI/RazorScriptEditor.Designer.cs +++ b/Razor/UI/RazorScriptEditor.Designer.cs @@ -50,7 +50,6 @@ private void InitializeComponent() this.scriptLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); this.scriptEditor = new FastColoredTextBoxNS.FastColoredTextBox(); this.scriptDocMap = new FastColoredTextBoxNS.DocumentMap(); - this.scriptStatusStrip = new System.Windows.Forms.StatusStrip(); this.scriptToolStrip.SuspendLayout(); this.scriptLayoutPanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.scriptEditor)).BeginInit(); @@ -222,20 +221,11 @@ private void InitializeComponent() this.scriptDocMap.TabIndex = 24; this.scriptDocMap.Target = null; // - // scriptStatusStrip - // - this.scriptStatusStrip.Location = new System.Drawing.Point(0, 514); - this.scriptStatusStrip.Name = "scriptStatusStrip"; - this.scriptStatusStrip.Size = new System.Drawing.Size(801, 22); - this.scriptStatusStrip.TabIndex = 25; - this.scriptStatusStrip.Text = "statusStrip1"; - // // RazorScriptEditor // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(801, 536); - this.Controls.Add(this.scriptStatusStrip); this.Controls.Add(this.scriptLayoutPanel); this.Controls.Add(this.scriptToolStrip); this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); @@ -269,6 +259,5 @@ private void InitializeComponent() private ToolStripButton scriptHelp; private ToolStripSeparator toolStripSeparator3; private ToolStripButton scriptInfo; - private StatusStrip scriptStatusStrip; } } \ No newline at end of file diff --git a/Razor/UltimaSDK/Files.cs b/Razor/UltimaSDK/Files.cs index 05894720..405ef411 100644 --- a/Razor/UltimaSDK/Files.cs +++ b/Razor/UltimaSDK/Files.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.Configuration; using System.IO; +using Assistant; using Microsoft.Win32; namespace Ultima @@ -338,7 +339,7 @@ internal static string GetFilePath(string format, params object[] args) private static string LoadDirectory() { - string dir = ConfigurationManager.AppSettings["UODataDir"]; + string dir = Config.GetAppSetting("UODataDir"); // If they're using the ClassicUO client, pull the UO data dir from the plugin if (!Assistant.Client.IsOSI)