diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4ded7c4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/bin/
+/obj/
diff --git a/App.config b/App.config
new file mode 100644
index 0000000..4bba09a
--- /dev/null
+++ b/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CEasyUO.csproj b/CEasyUO.csproj
new file mode 100644
index 0000000..5e9613a
--- /dev/null
+++ b/CEasyUO.csproj
@@ -0,0 +1,170 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {003E3EEF-9EDE-4188-B513-EDDA5722147B}
+ WinExe
+ CEasyUO
+ CEasyUO
+ v4.7.1
+ 512
+ true
+ false
+
+
+ x64
+ true
+ full
+ false
+ Z:\480gb\ClassicUO\bin\Debug\Data\Plugins\CEasyUO\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+ false
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ icons\easyuo2.ico
+
+
+
+ False
+ .\cuoapi.dll
+
+
+ C:\Users\James\Documents\Visual Studio 2017\Projects\EasyLoA\EasyAntlr\bin\Debug\EasyAntlr.exe
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ .\Ultima.dll
+
+
+
+
+
+
+
+
+
+
+
+
+ Component
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ CEasyUOMainForm.cs
+
+
+
+
+
+
+
+
+
+
+ Actions.cs
+
+
+ CEasyUOMainForm.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
\ No newline at end of file
diff --git a/CEasyUOMainForm.Designer.cs b/CEasyUOMainForm.Designer.cs
new file mode 100644
index 0000000..0c2b7ec
--- /dev/null
+++ b/CEasyUOMainForm.Designer.cs
@@ -0,0 +1,290 @@
+namespace CEasyUO
+{
+ partial class CEasyUOMainForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose( bool disposing )
+ {
+ if ( disposing && ( components != null ) )
+ {
+ components.Dispose();
+ }
+ base.Dispose( disposing );
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CEasyUOMainForm));
+ this.treeVarTree = new System.Windows.Forms.TreeView();
+ this.txtScriptEntry = new System.Windows.Forms.RichTextBox();
+ this.toolStrip1 = new System.Windows.Forms.ToolStrip();
+ this.btnNew = new System.Windows.Forms.ToolStripButton();
+ this.btnOpen = new System.Windows.Forms.ToolStripButton();
+ this.btnSave = new System.Windows.Forms.ToolStripButton();
+ this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ this.btnPlay = new System.Windows.Forms.ToolStripButton();
+ this.btnPause = new System.Windows.Forms.ToolStripButton();
+ this.btnStop = new System.Windows.Forms.ToolStripButton();
+ this.btnStep = new System.Windows.Forms.ToolStripButton();
+ this.btnCompile = new System.Windows.Forms.ToolStripButton();
+ this.txtDebug = new System.Windows.Forms.Label();
+ this.splitContainer1 = new System.Windows.Forms.SplitContainer();
+ this.splitContainer2 = new System.Windows.Forms.SplitContainer();
+ this.tree_AST = new System.Windows.Forms.TreeView();
+ this.toolStrip1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
+ this.splitContainer1.Panel1.SuspendLayout();
+ this.splitContainer1.Panel2.SuspendLayout();
+ this.splitContainer1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit();
+ this.splitContainer2.Panel1.SuspendLayout();
+ this.splitContainer2.Panel2.SuspendLayout();
+ this.splitContainer2.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // treeVarTree
+ //
+ this.treeVarTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.treeVarTree.Location = new System.Drawing.Point(0, 3);
+ this.treeVarTree.Name = "treeVarTree";
+ this.treeVarTree.Size = new System.Drawing.Size(212, 381);
+ this.treeVarTree.TabIndex = 0;
+ //
+ // txtScriptEntry
+ //
+ this.txtScriptEntry.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.txtScriptEntry.Location = new System.Drawing.Point(25, 3);
+ this.txtScriptEntry.MaxLength = 327670;
+ this.txtScriptEntry.Name = "txtScriptEntry";
+ this.txtScriptEntry.ShowSelectionMargin = true;
+ this.txtScriptEntry.Size = new System.Drawing.Size(683, 578);
+ this.txtScriptEntry.TabIndex = 1;
+ this.txtScriptEntry.Text = resources.GetString("txtScriptEntry.Text");
+ //
+ // toolStrip1
+ //
+ this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.btnNew,
+ this.btnOpen,
+ this.btnSave,
+ this.toolStripSeparator1,
+ this.btnPlay,
+ this.btnPause,
+ this.btnStop,
+ this.btnStep,
+ this.btnCompile});
+ this.toolStrip1.Location = new System.Drawing.Point(0, 0);
+ this.toolStrip1.Name = "toolStrip1";
+ this.toolStrip1.Size = new System.Drawing.Size(957, 25);
+ this.toolStrip1.TabIndex = 2;
+ this.toolStrip1.Text = "toolStrip1";
+ //
+ // btnNew
+ //
+ this.btnNew.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.btnNew.Image = ((System.Drawing.Image)(resources.GetObject("btnNew.Image")));
+ this.btnNew.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.btnNew.Name = "btnNew";
+ this.btnNew.Size = new System.Drawing.Size(23, 22);
+ this.btnNew.Text = "New";
+ this.btnNew.Click += new System.EventHandler(this.btnNew_Click);
+ //
+ // btnOpen
+ //
+ this.btnOpen.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.btnOpen.Image = ((System.Drawing.Image)(resources.GetObject("btnOpen.Image")));
+ this.btnOpen.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.btnOpen.Name = "btnOpen";
+ this.btnOpen.Size = new System.Drawing.Size(23, 22);
+ this.btnOpen.Text = "Open";
+ this.btnOpen.Click += new System.EventHandler(this.btnOpen_Click);
+ //
+ // btnSave
+ //
+ this.btnSave.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.btnSave.Image = ((System.Drawing.Image)(resources.GetObject("btnSave.Image")));
+ this.btnSave.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.btnSave.Name = "btnSave";
+ this.btnSave.Size = new System.Drawing.Size(23, 22);
+ this.btnSave.Text = "Save";
+ this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
+ //
+ // toolStripSeparator1
+ //
+ this.toolStripSeparator1.Name = "toolStripSeparator1";
+ this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25);
+ //
+ // btnPlay
+ //
+ this.btnPlay.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.btnPlay.Image = ((System.Drawing.Image)(resources.GetObject("btnPlay.Image")));
+ this.btnPlay.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.btnPlay.Name = "btnPlay";
+ this.btnPlay.Size = new System.Drawing.Size(23, 22);
+ this.btnPlay.Text = "Play";
+ this.btnPlay.Click += new System.EventHandler(this.btnPlayClicked);
+ //
+ // btnPause
+ //
+ this.btnPause.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.btnPause.Image = ((System.Drawing.Image)(resources.GetObject("btnPause.Image")));
+ this.btnPause.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.btnPause.Name = "btnPause";
+ this.btnPause.Size = new System.Drawing.Size(23, 22);
+ this.btnPause.Text = "Pause";
+ this.btnPause.Click += new System.EventHandler(this.btnPauseClicked);
+ //
+ // btnStop
+ //
+ this.btnStop.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.btnStop.Image = ((System.Drawing.Image)(resources.GetObject("btnStop.Image")));
+ this.btnStop.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.btnStop.Name = "btnStop";
+ this.btnStop.Size = new System.Drawing.Size(23, 22);
+ this.btnStop.Text = "Stop";
+ this.btnStop.Click += new System.EventHandler(this.btnStopClicked);
+ //
+ // btnStep
+ //
+ this.btnStep.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.btnStep.Image = ((System.Drawing.Image)(resources.GetObject("btnStep.Image")));
+ this.btnStep.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.btnStep.Name = "btnStep";
+ this.btnStep.Size = new System.Drawing.Size(23, 22);
+ this.btnStep.Text = "Step";
+ this.btnStep.Click += new System.EventHandler(this.btnStepClicked);
+ //
+ // btnCompile
+ //
+ this.btnCompile.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.btnCompile.Image = ((System.Drawing.Image)(resources.GetObject("btnCompile.Image")));
+ this.btnCompile.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.btnCompile.Name = "btnCompile";
+ this.btnCompile.Size = new System.Drawing.Size(23, 22);
+ this.btnCompile.Text = "Check";
+ this.btnCompile.Click += new System.EventHandler(this.btnCompile_Click);
+ //
+ // txtDebug
+ //
+ this.txtDebug.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.txtDebug.AutoSize = true;
+ this.txtDebug.Location = new System.Drawing.Point(12, 615);
+ this.txtDebug.Name = "txtDebug";
+ this.txtDebug.Size = new System.Drawing.Size(35, 13);
+ this.txtDebug.TabIndex = 3;
+ this.txtDebug.Text = "label1";
+ //
+ // splitContainer1
+ //
+ this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.splitContainer1.Location = new System.Drawing.Point(12, 28);
+ this.splitContainer1.Name = "splitContainer1";
+ //
+ // splitContainer1.Panel1
+ //
+ this.splitContainer1.Panel1.Controls.Add(this.txtScriptEntry);
+ //
+ // splitContainer1.Panel2
+ //
+ this.splitContainer1.Panel2.Controls.Add(this.splitContainer2);
+ this.splitContainer1.Size = new System.Drawing.Size(933, 584);
+ this.splitContainer1.SplitterDistance = 711;
+ this.splitContainer1.TabIndex = 4;
+ //
+ // splitContainer2
+ //
+ this.splitContainer2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.splitContainer2.Location = new System.Drawing.Point(3, 3);
+ this.splitContainer2.Name = "splitContainer2";
+ this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal;
+ //
+ // splitContainer2.Panel1
+ //
+ this.splitContainer2.Panel1.Controls.Add(this.treeVarTree);
+ //
+ // splitContainer2.Panel2
+ //
+ this.splitContainer2.Panel2.Controls.Add(this.tree_AST);
+ this.splitContainer2.Size = new System.Drawing.Size(215, 581);
+ this.splitContainer2.SplitterDistance = 387;
+ this.splitContainer2.TabIndex = 1;
+ //
+ // tree_AST
+ //
+ this.tree_AST.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tree_AST.Location = new System.Drawing.Point(0, 3);
+ this.tree_AST.Name = "tree_AST";
+ this.tree_AST.Size = new System.Drawing.Size(212, 184);
+ this.tree_AST.TabIndex = 0;
+ //
+ // CEasyUOMainForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(957, 637);
+ this.Controls.Add(this.splitContainer1);
+ this.Controls.Add(this.txtDebug);
+ this.Controls.Add(this.toolStrip1);
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Name = "CEasyUOMainForm";
+ this.Text = "CEasyUO 0.2";
+ this.toolStrip1.ResumeLayout(false);
+ this.toolStrip1.PerformLayout();
+ this.splitContainer1.Panel1.ResumeLayout(false);
+ this.splitContainer1.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
+ this.splitContainer1.ResumeLayout(false);
+ this.splitContainer2.Panel1.ResumeLayout(false);
+ this.splitContainer2.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit();
+ this.splitContainer2.ResumeLayout(false);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TreeView treeVarTree;
+ private System.Windows.Forms.RichTextBox txtScriptEntry;
+ private System.Windows.Forms.ToolStrip toolStrip1;
+ private System.Windows.Forms.ToolStripButton btnPlay;
+ private System.Windows.Forms.Label txtDebug;
+ private System.Windows.Forms.SplitContainer splitContainer1;
+ private System.Windows.Forms.ToolStripButton btnPause;
+ private System.Windows.Forms.ToolStripButton btnStop;
+ private System.Windows.Forms.ToolStripButton btnStep;
+ private System.Windows.Forms.ToolStripButton btnNew;
+ private System.Windows.Forms.ToolStripButton btnOpen;
+ private System.Windows.Forms.ToolStripButton btnSave;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
+ private System.Windows.Forms.SplitContainer splitContainer2;
+ private System.Windows.Forms.TreeView tree_AST;
+ private System.Windows.Forms.ToolStripButton btnCompile;
+ }
+}
+
diff --git a/CEasyUOMainForm.cs b/CEasyUOMainForm.cs
new file mode 100644
index 0000000..315a256
--- /dev/null
+++ b/CEasyUOMainForm.cs
@@ -0,0 +1,404 @@
+using Assistant;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace CEasyUO
+{
+ public partial class CEasyUOMainForm : Form
+ {
+ public CEasyUOMainForm()
+ {
+
+ InitializeComponent();
+ this.Text = $"CEasyUO {Assembly.GetExecutingAssembly().GetName().Version}";
+ SetupVarsTimer();
+ btnPause.Enabled = false;
+ btnStop.Enabled = false;
+ }
+
+ private void SetupVarsTimer()
+ {
+ treeVarTree.Nodes.Add( new TreeNode( "Character Info" ) );
+ treeVarTree.Nodes.Add( new TreeNode( "Status Bar" ) );
+ treeVarTree.Nodes.Add( new TreeNode( "Container Info" ) );
+ treeVarTree.Nodes.Add( new TreeNode( "Last Action" ) );
+ treeVarTree.Nodes.Add( new TreeNode( "Find Item" ) );
+ treeVarTree.Nodes.Add( new TreeNode( "Extended Info" ) );
+ Thread t = new Thread( new ThreadStart( () => {
+ while ( true )
+ {
+ Thread.Sleep( 1000 );
+ if(this.IsHandleCreated)
+ if ( InvokeRequired )
+ {
+ BeginInvoke( new MethodInvoker( UpdateVars ) );
+ }
+ else
+ {
+ UpdateVars();
+ // Do things
+ }
+ }
+
+
+
+ } ) );
+ t.IsBackground = true;
+ t.Start();
+
+ }
+
+ private void UpdateVars()
+ {
+ if(Interpreter != null && Interpreter.CurrentStatment != null)
+ {
+
+ }
+ try
+ {
+ //txtDebug.Text = "CurrentLine: " + Parser?.CurrentLine ?? "0";
+ if ( !Engine.IsInstalled || World.Player == null )
+ {
+ return;
+ }
+
+ Dictionary charinfo = BuildCharInfo();
+
+
+ Dictionary last = BuildLastInfo();
+
+ Dictionary container = new Dictionary();
+ container.Add( "#GUMPPOSX", EUOInterpreter.GetVariable( "#GUMPPOSX" ) );
+ container.Add( "#GUMPPOSY", EUOInterpreter.GetVariable( "#GUMPPOSY" ) );
+ container.Add( "#GUMPSIZEX", EUOInterpreter.GetVariable( "#GUMPSIZEX" ) );
+ container.Add( "#GUMPSIZEY", EUOInterpreter.GetVariable( "#GUMPSIZEY" ) );
+ container.Add( "#CONTKIND", EUOInterpreter.GetVariable( "#CONTKIND" ) );
+ container.Add( "#CONTID", EUOInterpreter.GetVariable( "#CONTID" ) );
+ container.Add( "#CONTTYPE", EUOInterpreter.GetVariable( "#CONTTYPE" ) );
+ container.Add( "#CONTHP", "N/A" );
+
+ container.Add( "#GUMPSERIAL", EUOInterpreter.GetVariable( "#GUMPSERIAL" ) );
+ container.Add( "#GUMPTYPE", EUOInterpreter.GetVariable( "#GUMPTYPE" ) );
+
+ Dictionary find = new Dictionary();
+ find.Add( "#FINDID", EUOInterpreter.GetVariable( "#findid" ) );
+ find.Add( "#FINDTYPE", EUOInterpreter.GetVariable( "#FINDTYPE" ) );
+ find.Add( "#FINDX", EUOInterpreter.GetVariable( "#FINDX" ) );
+ find.Add( "#FINDY", EUOInterpreter.GetVariable( "#FINDY" ) );
+ find.Add( "#FINDZ", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDDIST", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDKIND", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDSTACK", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDBAGID", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDMOD", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDREP", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDCOL", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDINDEX", EUOInterpreter.GetVariable( "#FINDZ" ) );
+ find.Add( "#FINDCNT", EUOInterpreter.GetVariable( "#FINDZ" ) );
+
+
+ Dictionary status = new Dictionary();
+ status.Add( "#CHARNAME", EUOInterpreter.GetVariable( "#CHARNAME" ) );
+ status.Add( "#SEX", EUOInterpreter.GetVariable( "#SEX" ) );
+ status.Add( "#STR", EUOInterpreter.GetVariable( "#STR" ) );
+ status.Add( "#DEX", EUOInterpreter.GetVariable( "#DEX" ) );
+ status.Add( "#INT", EUOInterpreter.GetVariable( "#INT" ) );
+ status.Add( "#HITS", EUOInterpreter.GetVariable( "#HITS" ) );
+ status.Add( "#MAXHITS", EUOInterpreter.GetVariable( "#MAXHITS" ) );
+ status.Add( "#MANA", EUOInterpreter.GetVariable( "#MANA" ) );
+ status.Add( "#MAXMANA", EUOInterpreter.GetVariable( "#MAXMANA" ) );
+ status.Add( "#STAMINA", EUOInterpreter.GetVariable( "#STAMINA" ) );
+ status.Add( "#MAXSTAM", EUOInterpreter.GetVariable( "#MAXSTAM" ) );
+ status.Add( "#MAXSTATS", EUOInterpreter.GetVariable( "#MAXSTATS" ) );
+ status.Add( "#LUCK", EUOInterpreter.GetVariable( "#LUCK" ) );
+ status.Add( "#WEIGHT", EUOInterpreter.GetVariable( "#WEIGHT" ) );
+ status.Add( "#MAXWEIGHT", EUOInterpreter.GetVariable( "#MAXWEIGHT" ) );
+ status.Add( "#MINDMG", EUOInterpreter.GetVariable( "#MINDMG" ) );
+ status.Add( "#MAXDMG", EUOInterpreter.GetVariable( "#MAXDMG" ) );
+ status.Add( "#GOLD", EUOInterpreter.GetVariable( "#GOLD" ) );
+ status.Add( "#FOLLOWERS", EUOInterpreter.GetVariable( "#FOLLOWERS" ) );
+ status.Add( "#MAXFOL", EUOInterpreter.GetVariable( "#MAXFOL" ) );
+ status.Add( "#AR", EUOInterpreter.GetVariable( "#AR" ) );
+ status.Add( "#FR", EUOInterpreter.GetVariable( "#FR" ) );
+ status.Add( "#CR", EUOInterpreter.GetVariable( "#CR" ) );
+ status.Add( "#PR", EUOInterpreter.GetVariable( "#PR" ) );
+ status.Add( "#ER", EUOInterpreter.GetVariable( "#ER" ) );
+
+ Dictionary extended = new Dictionary();
+ extended.Add( "#JOURNAL", EUOInterpreter.GetVariable( "#JOURNAL" ) );
+ extended.Add( "#JCOLOR", EUOInterpreter.GetVariable( "#JCOLOR" ) );
+ extended.Add( "#JINDEX", EUOInterpreter.GetVariable( "#JINDEX" ) );
+ extended.Add( "#SYSMSG", EUOInterpreter.GetVariable( "#SYSMSG" ) );
+ extended.Add( "#TARGCURS", EUOInterpreter.GetVariable( "#TARGCURS" ) );
+ extended.Add( "#CURSKIND", EUOInterpreter.GetVariable( "#CURSKIND" ) );
+ extended.Add( "#PROPERTY", EUOInterpreter.GetVariable( "#PROPERTY" ) );
+
+ Dictionary results = new Dictionary();
+ results.Add( "#RESULT", EUOInterpreter.GetVariable( "#RESULT" ) );
+ results.Add( "#STRRES", EUOInterpreter.GetVariable( "#STRRES" ) );
+ results.Add( "#MENURES", EUOInterpreter.GetVariable( "#MENURES" ) );
+ results.Add( "#DISPRES", EUOInterpreter.GetVariable( "#DISPRES" ) );
+
+ foreach ( TreeNode n in treeVarTree.Nodes )
+ {
+ if ( n.Text == "Last Action" )
+ UpdateChildren( (TreeNode)n, last );
+ if ( n.Text == "Character Info" )
+ UpdateChildren( (TreeNode)n, charinfo );
+ if ( n.Text == "Find Item" )
+ UpdateChildren( (TreeNode)n, find );
+ if ( n.Text == "Status Bar" )
+ UpdateChildren( (TreeNode)n, status );
+ if ( n.Text == "Container Info" )
+ UpdateChildren( (TreeNode)n, container );
+ if ( n.Text == "Result Variables" )
+ UpdateChildren( (TreeNode)n, results );
+ if ( n.Text == "Extended Info" )
+ UpdateChildren( (TreeNode)n, extended );
+ }
+ }
+ catch ( Exception e )
+ {
+
+ Console.WriteLine( e.Message + e.StackTrace );
+ }
+ }
+
+ private Dictionary BuildLastInfo()
+ {
+ var last = new Dictionary();
+ last.Add( "#LOBJECTID", EUOInterpreter.GetVariable( "#LOBJECTID" ) );
+ last.Add( "#LOBJECTTYPE", EUOInterpreter.GetVariable( "#LOBJECTTYPE" ) );
+ last.Add( "#LTARGETID", EUOInterpreter.GetVariable( "#LTARGETID" ) );
+ last.Add( "#LTARGETX", EUOInterpreter.GetVariable( "#LTARGETX" ) );
+ last.Add( "#LTARGETY", EUOInterpreter.GetVariable( "#LTARGETY" ) );
+ last.Add( "#LTARGETZ", EUOInterpreter.GetVariable( "#LTARGETZ" ) );
+ last.Add( "#LTARGETKIND", EUOInterpreter.GetVariable( "#LTARGETKIND" ) );
+ last.Add( "#LTARGETTILE", EUOInterpreter.GetVariable( "#LTARGETTILE" ) );
+ last.Add( "#LSKILL", EUOInterpreter.GetVariable( "#LSKILL" ) );
+ last.Add( "#LSPELL", EUOInterpreter.GetVariable( "#LSPELL" ) );
+
+ last.Add( "#LGUMPBUTTON", EUOInterpreter.GetVariable( "#LGUMPBUTTON" ) );
+
+ return last;
+ }
+
+ private Dictionary BuildCharInfo()
+ {
+ var charinfo = new Dictionary();
+ charinfo.Add( "#CHARPOSX", EUOInterpreter.GetVariable( "#CHARPOSX" ) );
+ charinfo.Add( "#CHARPOSY", EUOInterpreter.GetVariable( "#CHARPOSY" ) );
+ charinfo.Add( "#CHARPOSZ", EUOInterpreter.GetVariable( "#CHARPOSZ" ) );
+ charinfo.Add( "#CHARDIR", EUOInterpreter.GetVariable( "#CHARDIR" ) );
+ charinfo.Add( "#CHARSTATUS", EUOInterpreter.GetVariable( "#CHARSTATUS" ) ); ;
+ charinfo.Add( "#CHARID", EUOInterpreter.GetVariable( "#CHARID" ) );
+ charinfo.Add( "#CHARTYPE", EUOInterpreter.GetVariable( "#CHARTYPE" ) );
+ charinfo.Add( "#CHARGHOST", EUOInterpreter.GetVariable( "#CHARGHOST" ) );
+ charinfo.Add( "#CHARBACKPACKID", EUOInterpreter.GetVariable( "#CHARBACKPACKID" ) );
+ return charinfo;
+ }
+
+ private void UpdateChildren( TreeNode n, Dictionary dict )
+ { try
+ {
+ foreach ( var c in dict )
+ {
+ if ( n.Nodes.ContainsKey( c.Key ) )
+ n.Nodes[c.Key].Text = c.Key + ": " + c.Value.ToString();
+ else
+ n.Nodes.Add( c.Key, c.Key + ": " + c.Value.ToString() );
+ }
+ }
+ catch (Exception e)
+ {
+ Debugger.Break();
+ Console.WriteLine( e.Message + e.StackTrace );
+ }
+
+ }
+
+ public EUOInterpreter Interpreter;
+ private FileStream m_OpenFile;
+
+ public string m_FilePath { get; private set; }
+
+ private void btnPlayClicked( object sender, EventArgs e )
+ {
+ if ( Interpreter == null || Interpreter.Script != txtScriptEntry.Text )
+ {
+ Interpreter = new EUOInterpreter( txtScriptEntry.Text );
+ UpdateAST();
+ }
+
+ if(Interpreter.Running && Interpreter.Paused)
+ {
+ Interpreter.Paused = false;
+ }
+ else if ( !Interpreter.Running )
+ {
+ Interpreter.Run();
+ }
+
+ btnPlay.Enabled = false;
+ btnStop.Enabled = true;
+ btnPause.Enabled = true;
+ txtDebug.Text = "Running...";
+
+ }
+
+ private void btnPauseClicked( object sender, EventArgs e )
+ {
+ if ( Interpreter == null )
+ return;
+ if ( !Interpreter.Running )
+ return;
+
+ Interpreter.Paused = true;
+
+ btnPlay.Enabled = true;
+ btnStop.Enabled = true;
+ btnPause.Enabled = false;
+ txtDebug.Text = "Paused on Line: " + Interpreter.CurrentLine;
+ }
+
+ private void btnStopClicked( object sender, EventArgs e )
+ {
+ if ( Interpreter == null )
+ return;
+ if ( Interpreter.Running )
+ Interpreter.Stop();
+ btnPlay.Enabled = true;
+ btnStop.Enabled = false;
+ btnPause.Enabled = false;
+ txtDebug.Text = "Stopped...";
+ }
+
+ private void btnStepClicked( object sender, EventArgs e )
+ {
+ try
+ {
+ if ( Interpreter == null || Interpreter.Script != txtScriptEntry.Text )
+ {
+ Interpreter = new EUOInterpreter( txtScriptEntry.Text );
+ UpdateAST();
+ }
+
+
+ Interpreter.Statement();
+ txtDebug.Text = "Current Line: " + Interpreter.CurrentLine + " Current Statement: " + Interpreter.CurrentStatment?? "null";
+ var start = txtScriptEntry.GetFirstCharIndexFromLine( Interpreter.CurrentLine -1 );
+ var end = txtScriptEntry.GetFirstCharIndexFromLine( Interpreter.CurrentLine ) - 1;
+
+ txtScriptEntry.SelectionStart = 0;
+ txtScriptEntry.SelectionLength = txtScriptEntry.Text.Length;
+ txtScriptEntry.SelectionBackColor = SystemColors.Window;
+
+
+ txtScriptEntry.SelectionStart = start;
+ txtScriptEntry.SelectionLength = end - start;
+ txtScriptEntry.SelectionBackColor = Color.Red;
+ txtScriptEntry.SelectionBullet = true;
+ txtScriptEntry.SelectionLength = 0;
+
+ } catch(Exception ee )
+ {
+ txtDebug.Text = "E: " + ee.Message;
+ }
+
+
+ }
+
+ private void btnNew_Click( object sender, EventArgs e )
+ {
+ txtScriptEntry.Text = "";
+ if(m_OpenFile != null)
+ {
+ m_OpenFile.Close();
+ m_OpenFile = null;
+ }
+ m_FilePath = null;
+ }
+
+ private void btnOpen_Click( object sender, EventArgs e )
+ {
+ var diag = new OpenFileDialog();
+ if(diag.ShowDialog() == DialogResult.OK )
+ {
+ m_OpenFile = File.Open( diag.FileName, FileMode.OpenOrCreate );
+ m_FilePath = diag.FileName;
+ using(var sr = new StreamReader( m_OpenFile ) )
+ txtScriptEntry.Text = sr.ReadToEnd();
+ }
+ }
+
+ private void btnSave_Click( object sender, EventArgs e )
+ {
+ if ( m_FilePath != null )
+ {
+ m_OpenFile = File.Open( m_FilePath, FileMode.Truncate );
+ using ( var sw = new StreamWriter( m_OpenFile ) )
+ {
+ sw.Write( txtScriptEntry.Text );
+ //sw.Flush();
+ }
+
+ }
+ else
+ {
+ var diag = new SaveFileDialog();
+ if ( diag.ShowDialog() == DialogResult.OK )
+ {
+ m_OpenFile = File.Open( diag.FileName, FileMode.OpenOrCreate );
+ m_FilePath = diag.FileName;
+ using(var sw = new StreamWriter( m_OpenFile ) )
+ {
+ sw.Write( txtScriptEntry.Text );
+ //sw.Flush();
+ }
+
+ }
+ }
+
+ }
+
+ private void btnCompile_Click( object sender, EventArgs e )
+ {
+ UpdateVars();
+ UpdateAST();
+ }
+
+ public void UpdateAST()
+ {
+ if ( Interpreter == null || Interpreter.Script != txtScriptEntry.Text )
+ Interpreter = new EUOInterpreter( txtScriptEntry.Text );
+ tree_AST.Nodes.Clear();
+
+ foreach ( var n in ( Interpreter.AST.First() as Block ).statements )
+ tree_AST.Nodes.AddRange( AddTree( n ) );
+ }
+
+ private TreeNode[] AddTree( Stmt n )
+ {
+
+ var node = new TreeNode( n.ToString() );
+ if ( n is Block b )
+ {
+ foreach(var s in b.statements)
+ node.Nodes.AddRange( AddTree( s ) );
+ }
+ return new TreeNode[] { node };
+
+ }
+ }
+}
diff --git a/CEasyUOMainForm.resx b/CEasyUOMainForm.resx
new file mode 100644
index 0000000..d590e4c
--- /dev/null
+++ b/CEasyUOMainForm.resx
@@ -0,0 +1,743 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ; Configuration
+if ( #charName = Night )
+{
+ set %runebookId TJQDKMD ; Runebook ID
+ set %dropContainerId XWNAKMD
+ set %lumberjackSpots 8 ; Number of spots in runebook
+}
+if ( #charName = Dragono )
+{
+ set %runebookId TSNFKMD ; Runebook ID
+ set %dropContainerId BCCWJMD
+ set %lumberjackSpots 6 ; Number of spots in runebook
+}
+set %area 40 ; Area to scan
+set %pathfindTimeout 10 ; Maximum time allowed per pathfind (seconds)
+set %maximumPathfindDistance 17 ; Maximum distance to pathFind
+set %smartPathFindTimeout 60 ; Maximum time allowed per smart pathfind (seconds)
+set %rechargeRunebook #true ; Recharge runebook (#true/#false)
+set %maxRunebookCharges 10 ; Maximum charges in runebook
+set %toolsToCraft 10 ; When out of hatchets, amount to craft
+set %toolsRecharge 5 ; Amount of tools to have before going back lumberjacking (1 if you got newbied hatchet)
+set %deathTime 2400 ; Time to wait before resurrecting (20 = 1 second)
+
+; Constants
+set %tools FSF_ASF
+set %tinkeringTools GTL
+set %recallScrolls WTL
+set %treasureBalls DMF
+
+; Stats
+set %recallScrollsUsed 0
+set %toolsUsed 0
+
+; Variables
+set %currentLumberjackSpot 1
+set %ironRequiredTool 4
+set %bankingRequired #false
+
+tile init
+
+lumberjacking:
+set %bankingRequired #false
+gosub resetSpots
+for %currentSpot 1 %spots
+{
+ set %spotX %spotX . %currentSpot
+ set %spotY %spotY . %currentSpot
+ set %spotZ %spotZ . %currentSpot
+ set %spotTileType %spotTileType . %currentSpot
+
+ gosub smartPathFind %spotX %spotY %spotZ 1
+ gosub lumberjack %spotX %spotY %spotZ %spotTileType
+
+ if ( #charGhost = yes )
+ {
+ gosub resurrect
+ break
+ }
+
+ if ( %bankingRequired = #true )
+ break
+}
+set %currentLumberjackSpot %currentLumberjackSpot + 1
+if ( %currentLumberjackSpot > %lumberjackSpots )
+ set %currentLumberjackSpot 1
+gosub bank
+goto lumberjacking
+
+sub resetSpots
+linesPerCycle 1000
+set %_startX #charPosX - %area
+set %_endX #charPosX + %area
+set %_startY #charPosY - %area
+set %_endY #charPosY + %area
+set %spots 0
+for %_resetSpotsLoopX %_startX %_endX
+{
+ for %_resetSpotsLoopY %_startY %_endY
+ {
+ tile cnt %_resetSpotsLoopX %_resetSpotsLoopY
+
+ for %_resetSpotsLoopTile 1 #tileCnt
+ {
+ tile get %_resetSpotsLoopX %_resetSpotsLoopY %_resetSpotsLoopTile
+
+ if ( #tiletype >= 3277 && #tiletype <= 3302 )
+ {
+ set %spots %spots + 1
+ set %spotX . %spots %_resetSpotsLoopX
+ set %spotY . %spots %_resetSpotsLoopY
+ set %spotZ . %spots #tileZ
+ set %spotTileType . %spots #tileType
+ break
+ }
+ }
+ }
+}
+linesPerCycle 10
+return
+
+; gosub smartPathFind [x] [y] [z] [tolerance]
+sub smartPathFind
+linesPerCycle 1000
+set %_smartPathFindX %1
+set %_smartPathFindY %2
+set %_smartPathFindZ %3
+set %_smartPathFindTolerance %4
+set %_smartPathFindTimeout #scnt + %smartPathFindTimeout
+gosub isCharPosWithinTolerance %_smartPathFindX %_smartPathFindY %maximumPathfindDistance
+while ( #result = #false )
+{
+ if ( %_smartPathFindTimeout < #scnt )
+ break
+
+ set %_bestCandidateX #charPosX
+ set %_bestCandidateY #charPosY
+ set %_bestCandidateZ #charPosZ
+
+ for %_candidate 1 %spots
+ {
+ set %_candidateX %spotX . %_candidate
+ set %_candidateY %spotY . %_candidate
+ set %_candidateZ %spotZ . %_candidate
+
+ gosub isBetterSmartPathFindCandidate %_candidateX %_candidateY %_smartPathFindX %_smartPathFindY %_bestCandidateX %_bestCandidateY %maximumPathfindDistance
+ if ( #result = #true )
+ {
+ set %_bestCandidateX %_candidateX
+ set %_bestCandidateY %_candidateY
+ set %_bestCandidateZ %_candidateZ
+ }
+ }
+
+ if ( %_bestCandidateX = #charPosX && %_bestCandidateY = #charPosY )
+ goto _smartPathFindReturnFalse ; no candidate found
+
+ gosub pathFind %_bestCandidateX %_bestCandidateY %_bestCandidateZ %_smartPathFindTolerance
+ if ( #result = #false )
+ goto _smartPathFindReturnFalse
+ gosub isCharPosWithinTolerance %_smartPathFindX %_smartPathFindY %maximumPathfindDistance
+}
+linesPerCycle 10
+gosub pathFind %_smartPathFindX %_smartPathFindY %_smartPathFindZ %_smartPathFindTolerance %_smartPathFindTimeout
+return #result
+_smartPathFindReturnFalse:
+linesPerCycle 10
+return #false
+
+; gosub isBetterSmartPathFindCandidate candidateX candidateY destinationX destinationY bestCandidateX bestCandidateY maxDistance
+sub isBetterSmartPathFindCandidate
+set %_distanceToCandidateX #charPosX - %1 abs
+set %_distanceToCandidateY #charPosY - %2 abs
+
+if ( %_distanceToCandidateX > %7 || %_distanceToCandidateY > %7 )
+ return #false ; Candidate is out of reach
+
+set %_distanceCandidateToDestinationX %1 - %3 abs
+set %_distanceCandidateToDestinationY %2 - %4 abs
+set %_distanceCandidateToDestination %_distanceCandidateToDestinationX + %_distanceCandidateToDestinationY
+
+set %_distanceBestCandidateToDestinationX %5 - %3 abs
+set %_distanceBestCandidateToDestinationY %6 - %4 abs
+set %_distanceBestCandidateToDestination %_distanceBestCandidateToDestinationX + %_distanceBestCandidateToDestinationY
+
+if ( %_distanceCandidateToDestination < %_distanceBestCandidateToDestination )
+ return #true ; Candidate is in reach and nearer to wanted destination
+
+return #false ; Candidate is in reach, but farer to wanted destination
+
+; gosub pathfind [x] [y] [z] [tolerance]
+sub pathfind
+set %_pathFindX %1
+set %_pathFindY %2
+set %_pathFindZ %3
+set %_pathFindTolerance %4
+set %_pathfindMoved #false
+set %_timeout #scnt + %pathfindTimeout
+set %_journal #jIndex + 1
+gosub isCharPosWithinTolerance %_pathFindX %_pathFindY %_pathFindTolerance
+if ( #result = #true )
+{
+ if ( %_pathfindMoved = #true )
+ event pathfind 0 0 0
+ return #true
+}
+event pathfind %_pathFindX %_pathFindY %_pathFindZ
+_pathfind:
+gosub isCharPosWithinTolerance %_pathFindX %_pathFindY %_pathFindTolerance
+if ( #result = #true )
+{
+ if ( %_pathfindMoved = #true )
+ event pathfind 0 0 0
+ return #true
+}
+if ( %_timeout < #scnt )
+{
+ if ( %_pathfindMoved = #true )
+ event pathfind 0 0 0
+ return #false
+}
+if ( %_journal <= #jIndex )
+{
+ scanJournal %_journal
+ if ( get_there in #journal )
+ return #false
+ if ( pathfinding in #journal )
+ set %_pathfindMoved #true
+ set %_journal %_journal + 1
+}
+goto _pathfind
+
+sub isCharPosWithinTolerance
+set %_x %1
+set %_y %2
+set %_dist %3
+set %_distX #charPosX - %_x abs
+set %_distY #charPosY - %_y abs
+if ( %_distX <= %_dist && %_distY <= %_dist )
+ return #true
+return #false
+
+sub lumberjack
+set %_lumberjackX %1
+set %_lumberjackY %2
+set %_lumberjackZ %3
+set %_lumberjackTileType %4
+_lumberjack:
+findItem %tools C_
+if ( #findKind = -1 )
+{
+ set %bankingRequired #true
+ return
+}
+set #lObjectId #findId
+set #lTargetX %_lumberjackX
+set #lTargetY %_lumberjackY
+set #lTargetZ %_lumberjackZ
+set #lTargetTile %_lumberjackTileType
+set #lTargetKind 3
+set %_lumberjackJournal #jIndex
+event macro 17
+target
+event macro 22
+set %_lumberjackTimeout #scnt + 10
+_lumberjackJournal:
+if ( %_lumberjackTimeout < #scnt )
+ return
+if ( #jIndex <= %_journal )
+ goto _lumberjackJournal
+set %_journal %_journal + 1
+scanJournal %_journal
+if ( you_hack_at_the_tree in #journal )
+ goto _lumberjack
+if ( you_put in #journal )
+ goto _lumberjack
+if ( there_is_nothing in #journal )
+ return
+if ( it_appears_immune in #journal )
+ return
+if ( reach_this in #journal )
+ return
+goto _lumberjackJournal
+
+sub bank
+gosub recall 1
+gosub dropLogs
+gosub dropTreasureBalls
+gosub restockTools
+if ( %rechargeRunebook = #true )
+ gosub rechargeRunebook
+set %_currentLumberjackSpot %currentLumberjackSpot + 1
+gosub recall %_currentLumberjackSpot
+return
+
+sub restockTools
+ignoreItem reset
+_restockTools:
+findItem %tools C_ , #backPackId
+if ( #findCnt >= %toolsRecharge )
+ return
+set %toolsToGrab %toolsRecharge - #findCnt
+gosub openContainer %dropContainerId
+findItem %tools C_ , %dropContainerId
+if ( #findCnt < %toolsToGrab )
+{
+ gosub craftTools
+ gosub dropLogs ; safety
+ goto _restockTools
+}
+for %_loop 1 %toolsToGrab
+{
+ findItem %tools C_ , %dropContainerId
+ exevent drag #findId
+ exevent dropC #backPackId
+ wait 10
+}
+set %toolsUsed %toolsUsed + %toolsToGrab
+return
+
+sub craftTools
+ignoreItem reset
+findItem %tinkeringTools C_ , %dropContainerId
+if ( #findKind = -1 )
+ pause
+exevent drag #findId 1
+exevent dropC #backPackId
+wait 10
+_findIronIngots:
+findItem RMK C_ , %dropContainerId
+if ( #findKind = -1 )
+ pause
+if ( #findCol <> 0 )
+{
+ ignoreItem #findId
+ goto _findIronIngots
+}
+set %_ironAmount %ironRequiredTool * %toolsToCraft
+exevent drag #findId %_ironAmount
+exevent dropC #backPackId
+wait 10
+ignoreItem reset
+_craftTool:
+findItem RMK C_ , #backPackId
+if ( #findCol <> 0 )
+{
+ ignoreItem #findId
+ goto _craftTool
+}
+if ( #findKind = -1 || #findStack < %ironRequiredTool )
+ goto _dropTinkeringTools
+msg $,waitmenu 'Tinkering' 'Tools' 'Tools' 'hatchet'$
+findItem %tinkeringTools C_ , #backPackId
+set #lObjectId #findId
+event macro 17
+wait 80
+goto _craftTool
+_dropTinkeringTools:
+ignoreItem reset
+findItem %tinkeringTools C_ , #backPackId
+exevent drag #findId 1
+exevent dropC %dropContainerId
+wait 10
+_dropTools:
+findItem %tools C_ , #backPackId
+if ( #findKind = -1 )
+ return
+exevent drag #findId 1
+exevent dropC %dropContainerId 50 50
+wait 10
+goto _dropTools
+
+; gosub recall [rune]
+sub recall
+set %_rune %1
+if ( %_rune <= 8 )
+{
+ set %_runeX 85
+ set %_runeY 115 + ( ( %_rune - 1 ) * 14 )
+}
+else
+{
+ set %_runeX 245
+ set %_runeY 115 + ( ( %_rune - 9 ) * 14 )
+}
+set %_charPosX #charPosX
+set %_charPosY #charPosY
+_openRunebook:
+set %_openRunebook #scnt + 10
+set #lObjectId %runebookId
+event macro 17
+_waitOpenRunebook:
+if ( %_openRunebook < #scnt )
+ goto _openRunebook
+if ( #contSizeX <> 352 || #contSizeY <> 226 )
+ goto _waitOpenRunebook
+set %_recall #scnt + 10
+click %_runeX %_runeY
+_waitRecall:
+if ( %_recall < #scnt )
+ goto _openRunebook
+if ( #charPosX <> %_charPosX || #charPosY <> %_charPosY )
+ return
+goto _waitRecall
+
+sub rechargeRunebook
+ignoreItem reset
+gosub openContainer %dropContainerId
+_rechargeRunebook:
+findItem %recallScrolls C_ , %dropContainerId
+if ( #findKind = -1 )
+ pause ; Out of recall scrolls
+if ( #findCol <> 0 )
+{
+ ignoreItem #findId
+ goto rechargeRunebook
+}
+exevent drag #findId %maxRunebookCharges
+exevent dropC %runebookId
+wait 10
+findItem %recallScrolls C_ , #backPackId
+set %recallScrollsUsed %recallScrollsUsed + ( %maxRunebookCharges - #findStack )
+exevent drag #findId #findStack
+exevent dropC %dropContainerId
+wait 10
+return
+
+; gosub openContainer [containerId]
+sub openContainer
+set %_containerId %1
+_openContainer:
+set #lObjectId %_containerId
+event macro 17
+set %_timeout #scnt + 10
+_waitOpenContainer:
+if ( %_timeout < #scnt )
+ goto _openContainer
+if ( #contId = %_containerId )
+ return
+goto _openContainer
+
+sub dropLogs
+ignoreItem reset
+_dropLogs:
+findItem ZLK_RMK C_ , #backPackId
+if ( #findKind = -1 )
+ return
+exevent drag #findId #findStack
+exevent dropC %dropContainerId
+wait 10
+goto _dropLogs
+
+sub dropTreasureBalls
+ignoreItem reset
+_dropTreasureBalls:
+findItem %treasureBalls C_ , #backPackId
+if ( #findKind = -1 )
+ return
+exevent drag #findId 1
+exevent dropC %dropContainerId
+wait 10
+goto _dropTreasureBalls
+
+sub resurrect
+set %_resurrectX #charPosX
+set %_resurrectY #charPosY
+_resurrect:
+if ( #charGhost <> yes )
+ return
+msg $home home home$
+wait 10
+if ( #charPosX = %_resurrectX || #charPosY = %_resurrectY )
+ goto _resurrect
+wait %deathTime
+gosub pathfind 5182 1250 0 1
+gosub pathfind 5182 1237 0 1
+gosub pathfind 5182 1228 10 0
+gosub pathfind 5182 1223 40 1
+move 5182 1223 1 30s
+ignoreItem reset
+_clickResurrectionStone:
+findItem HTG G_1
+if ( #findKind = -1 )
+ pause
+if ( #findCol <> 66 )
+{
+ ignoreItem #findId
+ goto _clickResurrectionStone
+}
+ignoreItem reset
+set #lObjectId #findId
+event macro 17
+gosub waitGump 380 150
+if ( #result = #false )
+ goto _clickResurrectionStone
+click 72 100
+wait 120
+if ( #charGhost = yes )
+ goto _clickResurrectionStone
+event macro 8 1 ; open paperdoll
+event macro 8 2 ; open status
+event macro 8 7 ; open backpack
+wait 20
+move 5194 1229 0 10s
+return
+
+; gosub waitGump width height
+sub waitGump
+set %_waitGumpWidth %1
+set %_waitGumpHeight %2
+set %_waitGumpTimeout #scnt + 5
+_waitGump:
+if ( %_waitGumpTimeout < #scnt )
+ return #false
+if ( #contSizeX = %_waitGumpWidth && #contSizeY = %_waitGumpHeight )
+ return #true
+goto _waitGump
+
+
+
+ 17, 17
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABfSURBVDhPzcoxDgAhEELRuf+lNQg2i6KFxf5kMgWvXtYO
+ d6ztwqaLiXtzwx9y00CrsH1umXgOjtwTycGReyI5OHJPJAdH7onk4Mg9kRwcuSeSgyP3RHJw5N4cb+43
+ VXWxN5h2GtXL+gAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABdSURBVDhPzY4BCsAgDMR8uj/vCHJlruLUwljgKOqlWL7C
+ btnmKel8tEyE3+hiZWvomhmB7nGUIS7PJr1Wj3hpNum1esRLmtxtBLGXa32PZEjJkJIhJYMeVvI7SrkA
+ G1/vNRaHbsAAAAAASUVORK5CYII=
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABQSURBVDhP3YxJCgAgDAP7dH+uhJIggkvVgzgQLGaxW+RN
+ iZySf85gBi+KJDRQSYQGmEWR/DJQGV01OSFjVeh41WmNobYGCO43B4DCAZ1iVgBP6Iyo8QiMcwAAAABJ
+ RU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABNSURBVDhPrc47DgAgCERB7n8qboYEpdBo+KyvIRazkf4n
+ JMws61XPMDTiuDuy4dbIiasjV+w31Qv7jQpw4hcQ1iBsQViDsAXhGYSLEQ3oEK4fx9qumgAAAABJRU5E
+ rkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABuSURBVDhPrY1BCsAwDMP69Py8o4uz2GT4VEEwVIKui8SO
+ iH02j3EOVKCbOEfoLxo5ByrQTZwjOpiRc6AC3cQ5ooMZOQcq0E2cIzqYkXOgAt3EOaKDGTkHKtBNnCM6
+ mJFzHx3MyDniCD48v/y7tR6j8SJ+dmnfjQAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAB8SURBVDhPjY1BEsAgCAN5uj+34JgaEZSd2UMlSSWiifTI
+ ec75w026pjfnADzJil4aWlTL8BixBw683AbCv4Pke3TUMZL+3UO32oAJ3HttwEO39wAIvlG+D1w8Bozq
+ SFg28MhhlotQa+YiCmVqfC8T4xiVTNwt+ILDrEPkA426iyckmvhvAAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
+ YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
+ 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
+ bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
+ VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
+ c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
+ Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
+ mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
+ kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
+ TgDQASA1MVpwzwAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
+ YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
+ 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
+ bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
+ VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
+ c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
+ Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
+ mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
+ kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
+ TgDQASA1MVpwzwAAAABJRU5ErkJggg==
+
+
+
+
+ AAABAAEAICAIAAAAAACoCAAAFgAAACgAAAAgAAAAQAAAAAEACAAAAAAAAAQAAAAAAAAAAAAAAAEAAAAB
+ AAD/////iPkSAEibg3wIJoB8/////wAmgHxCJYB8mAAAACrakXzHJIB8mAAAAAAAAACY+RIAeldtdJgA
+ AAAAX210DDBudLC3FQCgAgkAhAHRAAAA0QCgAgkADDBudGT5EgB0+RIAmAAAAJgAAAAIX210/////wBf
+ bXTv92t08A8AAMbAAAACAAAAf/hrdBipAACo+xIAeFWDANj5EgAmizZ+eFWDAOz///8AAAAAqPsSADBK
+ NgAAAAAAAAAAAADw/X9E+hIAKiaAfAD6EgAAJoB8zPoSAAAAAAAAAAAAFAAAAAEAAAAAAAAAAAAAABAA
+ AACADwX9/////wCA/X8A8P1/FPoSAAAAAAD0+RIAAAAAAJT6EgBIm4N8CCaAfP////8AJoB8QiWAfJgA
+ AAAq2pF8xySAfJgAAAAAAAAApPoSAHpXbXSYAAAAKl1tdMz6EgAAAAAAAAAAAAQA0QDGwAAAwAAAALB3
+ N373dzd+nAEAAMbAAAAAAAAAAAAAANz6EgAq2pF8xySAfIAAAAAAAAAAZPsSAFFZanRWWWp08A8AAICK
+ Nn4AAAAAnAEAAAAAAAAAAAAAAAAAAAAAAADICzwAAAA8AMALPAAAADwAAAA8AAAAPAAAADwAoE29AKCc
+ xQDwDwAA6gIEAAAAPABE+xIAAAA8AFABAAAAADwAAAA8APYCBAAAAAAAAAAAAPAPAAAAAAAAXDBudEqA
+ TgABAAAAAgAAAAUAAADA+hIAbPsSALT7EgCm8W10MBdqdP////9WWWp0gPsSAAG0N36wA4AABAAAAAQA
+ CgAAAAAAxPsSADETa3SXAAIABAAAAAYDBgA2E2t0BAAAAAQACgAAAAAAAAA8AJcAAgCY+xIAAAAAACT8
+ EgCm8W10QBNrdP////82E2t0Ixk4fgQAAAAGAwYAAAAAAAAAAAB4Y0wAzPwSAADw/X8AAAAA6gIEAAQA
+ AAABAAAANPwSABezN34EAAoABgMGAAAAAAAmszd+AAAAAHhjTADM/BIAEPwSALj8EgC4/BIAjwQ5fjCz
+ N37/////EFTIAPlGQAA8VMgAf3NEAAQAAAAQVMgA/XBEABBUyAAUckQAAAAAAPSGwQDsqUMAsPwSAHlt
+ RAAAAAAAAAAAALD8EgAAAAAAEFTIAOypQwAdbUQANCtOAHCYvwBjf04AuPwSAHh/TgCAf04ANzZAAAIA
+ AAA8/RIApkZAAG5uQAA0K04AcJi/AKKFTgCqhU4ABgMGAHCYvwBYAAAABgMGAAAAQAB8AbcAAAAAAAAA
+ AABE/RIAikZAAE9tQAAEAAAAmm9AAET9EgAEAAAAOwAAAN1+QAD0hsEAOAAAAEz9EgAAAAAAAAAAAKDJ
+ yACOe0cAm5ubm5ubm5ubm5ubm5ubA5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmwNWA5ubm5ub
+ m5ubm5ubm5ubm5ubm5ubm5ubm5ubmwAAYgNi/v6bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmwD+JWJiA2Ji
+ JSUAm5ubm5ubm5ubm5ubm5ubm5ubm5sAJWJimwMDm5tiYiUAm5ubm5ubm5ubm5ubm5ubm5ubACVimwMD
+ A1YDAwMPYiUAm5ubm5ubm5ubm5ubm5ubmwAlYpsDm5ubA5ubmwObYiUAm5ubm5ubm5ubm5ubm5slJSWb
+ A5ubm5ubm5ubmwObYiUlm5ubm5ubm5ubm5ubm/4lYpubm5ubm5ubm5ubm5tiJf6bm5ubm5ubm5ubm5ub
+ /mKbA5ubm5ubm5ubm5ubA5ti/ptWVlabm5ubm5ubmwNiYpsDm5ubm5ubm5ubm5sDm2JiA5tWVpubm5ub
+ m5ubVgMDA1YDm5ubm5ubm5ubA1YDAwNWm1ZWVpubVlZWVlZWVlabA5tWVlabVlabm1ZWVlZiYgObVlZW
+ m5tWVlZWVlZWVpsDVlZWVlZWm5tWVlZWVlYlm5tWVlabm1ZWm5ubm/4lYptWVpubVlabm5ubm5tWVv6b
+ VlabVlabVlabm5ubmwBimwNWVptWVpubm1ZWVlZWm5tWVptWVptWVpubm5ub/iVimwNWVlZWm5tWVlZW
+ Vv6bm1ZWm1ZWm1ZWVlZWVlZW/iVimwMDVlZiA1ZWYiX+m5ubVlabVlabVlZWVlZWVlab/lZWVlZWVgNi
+ VlZWVlZWm1ZWm5ubVlZWVpubm5ubm5ubm1ZWVlZim1ZiVlZWVpubVlabm5tWVlZWm5ubm5ubm5sl/mhi
+ A5sDJWIAJZubm5ubm5ubm5ubVlZWVlZWVlYA/v4laCWbVpslaGL+AACbm5ubm5ubm5tWVlZWVlZWVv4l
+ aCWbm5ubm5ubJWIl/gCbm5ubm5ubm5ubm5ubm/7+JWglm5ubm5ubm5ubJWIl/gCbm5ubm5ubm5ubm5v+
+ ACViJZubm5ubm5ubm5ubJWIl/v6bm5ubm5ubm5ubm5tiYpubm5ubm5ubm5ubm5ubm2Jim5ubm5ubm5ub
+ m5ubAwMDA5ubm5ubm5ubm5ubm5sDAwMDm5ubm5ubm5ubm5ubJWKbm5ubm5ubm5ubm5ubm5tiYpubm5ub
+ m5ubm5ubm5sAJWKbm5ubm5ubm5ubm5ubYiX+m5ubm5ubm5ubm5ubm5v+JWKbm5ubm5ubm5ubm2IlJZub
+ m5ubm5ubm5ubm5ub/gD+/v6bm5ubm5ubm5sA/v7+/pubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ub
+ m5ubm5ubm5ubm//8f///8B///8AH//+AA///AAH//gAA//wAAH/4DuA/+B/wP/gf8AfwH/AH4A/gAwAC
+ YAMAAMAjOAzwCTwE4Ek8AABJAAAAyQAAAJw/gAGcPwAB/wAAAP8AAoB/+A/gP/Af8B/wP/gf8D/4H/A/
+ +B/4P/g//B/wf/gP4D/8H/B/
+
+
+
\ No newline at end of file
diff --git a/Core/ActionQueue.cs b/Core/ActionQueue.cs
new file mode 100644
index 0000000..d2142a3
--- /dev/null
+++ b/Core/ActionQueue.cs
@@ -0,0 +1,661 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Assistant
+{
+ public delegate void DropDoneCallback( Serial iser, Serial dser, Point3D newPos );
+
+ public class DragDropManager
+ {
+ public enum ProcStatus
+ {
+ Nothing,
+ Success,
+ KeepWaiting,
+ ReQueue
+ }
+
+ public static bool Debug = false;
+
+ private static void Log( string str, params object[] args )
+ {
+ if ( Debug )
+ {
+ try
+ {
+ using ( StreamWriter w = new StreamWriter( "DragDrop.log", true ) )
+ {
+ w.Write( ":: " );
+ w.WriteLine( str, args );
+ w.Flush();
+ }
+ }
+ catch
+ {
+ }
+ }
+ }
+
+ private class LiftReq
+ {
+ private static int NextID = 1;
+
+ public LiftReq( Serial s, int a, bool cli, bool last )
+ {
+ Serial = s;
+ Amount = a;
+ FromClient = cli;
+ DoLast = last;
+ Id = NextID++;
+ }
+
+ public readonly Serial Serial;
+ public readonly int Amount;
+ public readonly int Id;
+ public readonly bool FromClient;
+ public readonly bool DoLast;
+
+ public override string ToString()
+ {
+ return String.Format( "{2}({0},{1},{3},{4})", Serial, Amount, Id, FromClient, DoLast );
+ }
+
+ }
+
+ private class DropReq
+ {
+ public DropReq( Serial s, Point3D pt )
+ {
+ Serial = s; Point = pt;
+ }
+
+ public DropReq( Serial s, Layer layer )
+ {
+ Serial = s; Layer = layer;
+ }
+
+ public Serial Serial;
+ public readonly Point3D Point;
+ public readonly Layer Layer;
+ }
+
+ public static void Initialize()
+ {
+ try { File.Delete( "DragDrop.log" ); } catch {}
+ }
+
+ private static void DropCurrent()
+ {
+ Log( "Drop current requested on {0}", m_Holding );
+
+ if ( m_Holding.IsItem )
+ {
+ if ( World.Player.Backpack != null )
+ ClientCommunication.SendToServer( new DropRequest( m_Holding, Point3D.MinusOne, World.Player.Backpack.Serial ) );
+ else
+ ClientCommunication.SendToServer( new DropRequest( m_Holding, World.Player.Position, Serial.Zero ) );
+ }
+
+ Clear();
+ }
+
+ private static int m_LastID;
+
+ private static Serial m_Pending, m_Holding;
+ private static Item m_HoldingItem;
+ private static bool m_ClientLiftReq = false;
+ private static DateTime m_Lifted = DateTime.MinValue;
+
+ private static readonly Dictionary> m_DropReqs = new Dictionary>();
+
+ private static readonly LiftReq[] m_LiftReqs = new LiftReq[ 256 ];
+ private static byte m_Front, m_Back;
+
+ public static Item Holding { get { return m_HoldingItem; } }
+ public static Serial Pending { get { return m_Pending; } }
+
+ public static int LastIDLifted { get { return m_LastID; } }
+
+ public static void Clear()
+ {
+ Log( "Clearing...." );
+
+ m_DropReqs.Clear();
+ for(int i=0;i<256;i++)
+ m_LiftReqs[i] = null;
+ m_Front = m_Back = 0;
+ m_Holding = m_Pending = Serial.Zero;
+ m_HoldingItem = null;
+ m_Lifted = DateTime.MinValue;
+ }
+
+ public static void DragDrop( Item i, Serial to )
+ {
+ Drag( i, i.Amount );
+ Drop( i, to, Point3D.MinusOne );
+ }
+
+ public static void DragDrop( Item i, Item to )
+ {
+ Drag( i, i.Amount );
+ Drop( i, to.Serial, Point3D.MinusOne );
+ }
+
+ public static void DragDrop( Item i, Point3D dest )
+ {
+ Drag( i, i.Amount );
+ Drop( i, Serial.MinusOne, dest );
+ }
+
+ public static void DragDrop( Item i, int amount, Item to )
+ {
+ Drag( i, amount );
+ Drop( i, to.Serial, Point3D.MinusOne );
+ }
+
+ public static void DragDrop( Item i, Mobile to, Layer layer, bool doLast )
+ {
+ Drag( i, i.Amount, false, doLast );
+ Drop( i, to, layer );
+ }
+
+ public static void DragDrop( Item i, Mobile to, Layer layer )
+ {
+ Drag( i, i.Amount, false );
+ Drop( i, to, layer );
+ }
+
+ public static int Drag( Item i, int amount, bool fromClient )
+ {
+ return Drag( i, amount, fromClient, false );
+ }
+
+ public static int Drag( Item i, int amount )
+ {
+ return Drag( i, amount, false, false );
+ }
+
+ public static bool Empty { get { return m_Back == m_Front; } }
+ public static bool Full { get { return ((byte)(m_Back+1)) == m_Front; } }
+
+ public static int Drag( Item i, int amount, bool fromClient, bool doLast )
+ {
+ LiftReq lr = new LiftReq( i.Serial, amount, fromClient, doLast );
+ LiftReq prev = null;
+
+ if ( Full )
+ {
+ if ( fromClient )
+ ClientCommunication.SendToClient( new LiftRej() );
+ return 0;
+ }
+
+ Log( "Queuing Drag request {0}", lr );
+
+ if ( m_Back >= m_LiftReqs.Length )
+ m_Back = 0;
+
+ if ( m_Back <= 0 )
+ prev = m_LiftReqs[m_LiftReqs.Length-1];
+ else if ( m_Back <= m_LiftReqs.Length )
+ prev = m_LiftReqs[m_Back-1];
+
+ // if the current last req must stay last, then insert this one in its place
+ if ( prev != null && prev.DoLast )
+ {
+ Log( "Back-Queuing {0}", prev );
+ if ( m_Back <= 0 )
+ m_LiftReqs[m_LiftReqs.Length-1] = lr;
+ else if ( m_Back <= m_LiftReqs.Length )
+ m_LiftReqs[m_Back-1] = lr;
+
+ // and then re-insert it at the end
+ lr = prev;
+ }
+
+ m_LiftReqs[m_Back++] = lr;
+
+ ActionQueue.SignalLift( !fromClient );
+ return lr.Id;
+ }
+
+ public static bool Drop( Item i, Mobile to, Layer layer )
+ {
+ if ( m_Pending == i.Serial )
+ {
+ Log( "Equipping {0} to {1} (@{2})", i, to.Serial, layer );
+ ClientCommunication.SendToServer( new EquipRequest( i.Serial, to, layer ) );
+ m_Pending = Serial.Zero;
+ m_Lifted = DateTime.MinValue;
+ return true;
+ }
+ else
+ {
+ bool add = false;
+
+ for(byte j=m_Front;j!=m_Back && !add;j++)
+ {
+ if ( m_LiftReqs[j] != null && m_LiftReqs[j].Serial == i.Serial )
+ {
+ add = true;
+ break;
+ }
+ }
+
+ if ( add )
+ {
+ Log( "Queuing Equip {0} to {1} (@{2})", i, to.Serial, layer );
+
+ if (!m_DropReqs.TryGetValue(i.Serial, out var q) || q == null)
+ m_DropReqs[i.Serial] = q = new Queue();
+
+ q.Enqueue( new DropReq( to == null ? Serial.Zero : to.Serial, layer ) );
+ return true;
+ }
+ else
+ {
+ Log( "Drop/Equip for {0} (to {1} (@{2})) not found, skipped", i, to == null ? Serial.Zero : to.Serial, layer );
+ return false;
+ }
+ }
+ }
+
+ public static bool Drop( Item i, Serial dest, Point3D pt )
+ {
+ if ( m_Pending == i.Serial )
+ {
+ Log( "Dropping {0} to {1} (@{2})", i, dest, pt );
+
+ ClientCommunication.SendToServer( new DropRequest( i.Serial, pt, dest ) );
+ m_Pending = Serial.Zero;
+ m_Lifted = DateTime.MinValue;
+ return true;
+ }
+ else
+ {
+ bool add = false;
+
+ for(byte j=m_Front;j!=m_Back && !add;j++)
+ {
+ if ( m_LiftReqs[j] != null && m_LiftReqs[j].Serial == i.Serial )
+ {
+ add = true;
+ break;
+ }
+ }
+
+ if ( add )
+ {
+ Log( "Queuing Drop {0} (to {1} (@{2}))", i, dest, pt );
+
+ if (!m_DropReqs.TryGetValue(i.Serial, out var q) || q == null)
+ m_DropReqs[i.Serial] = q = new Queue();
+
+ q.Enqueue( new DropReq( dest, pt ) );
+ return true;
+ }
+ else
+ {
+ Log( "Drop for {0} (to {1} (@{2})) not found, skipped", i, dest, pt );
+ return false;
+ }
+ }
+ }
+
+ public static bool Drop( Item i, Item to, Point3D pt )
+ {
+ return Drop( i, to == null ? Serial.MinusOne : to.Serial, pt );
+ }
+
+ public static bool Drop( Item i, Item to )
+ {
+ return Drop( i, to.Serial, Point3D.MinusOne );
+ }
+
+ public static bool LiftReject()
+ {
+ Log( "Server rejected lift for item {0}", m_Holding );
+ if ( m_Holding == Serial.Zero )
+ return true;
+
+ m_Holding = m_Pending = Serial.Zero;
+ m_HoldingItem = null;
+ m_Lifted = DateTime.MinValue;
+
+ return m_ClientLiftReq;
+ }
+
+ public static bool HasDragFor( Serial s )
+ {
+ for(byte j=m_Front;j!=m_Back;j++)
+ {
+ if ( m_LiftReqs[j] != null && m_LiftReqs[j].Serial == s )
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool CancelDragFor( Serial s )
+ {
+ if ( Empty )
+ return false;
+
+ int skip = 0;
+ for(byte j=m_Front;j!=m_Back;j++)
+ {
+ if ( skip == 0 && m_LiftReqs[j] != null && m_LiftReqs[j].Serial == s )
+ {
+ m_LiftReqs[j] = null;
+ skip++;
+ if ( j == m_Front )
+ {
+ m_Front++;
+ break;
+ }
+ else
+ {
+ m_Back--;
+ }
+ }
+
+ if ( skip > 0 )
+ m_LiftReqs[j] = m_LiftReqs[(byte)(j+skip)];
+ }
+
+ if ( skip > 0 )
+ {
+ m_LiftReqs[m_Back] = null;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public static bool EndHolding( Serial s )
+ {
+ //if ( m_Pending == s )
+ // return false;
+
+ if ( m_Holding == s )
+ {
+ m_Holding = Serial.Zero;
+ m_HoldingItem = null;
+ }
+
+ return true;
+ }
+
+ private static DropReq DequeueDropFor( Serial s )
+ {
+ DropReq dr = null;
+ if (m_DropReqs.TryGetValue(s, out var q) && q != null)
+ {
+ if ( q.Count > 0 )
+ dr = q.Dequeue();
+ if ( q.Count <= 0 )
+ m_DropReqs.Remove( s );
+ }
+ return dr;
+ }
+
+ public static void GracefulStop()
+ {
+ m_Front = m_Back = 0;
+
+ if ( m_Pending.IsValid )
+ {
+ m_DropReqs.TryGetValue(m_Pending, out var q);
+ m_DropReqs.Clear();
+ m_DropReqs[m_Pending] = q;
+ }
+ }
+
+ public static ProcStatus ProcessNext( int numPending )
+ {
+ if ( m_Pending != Serial.Zero )
+ {
+ if ( m_Lifted + TimeSpan.FromMinutes( 2 ) < DateTime.UtcNow )
+ {
+ Item i = World.FindItem( m_Pending );
+
+ Log( "Lift timeout, forced drop to pack for {0}", m_Pending );
+
+ if ( World.Player != null )
+ {
+ if ( World.Player.Backpack != null )
+ ClientCommunication.SendToServer( new DropRequest( m_Pending, Point3D.MinusOne, World.Player.Backpack.Serial ) );
+ else
+ ClientCommunication.SendToServer( new DropRequest( m_Pending, World.Player.Position, Serial.Zero ) );
+ }
+
+ m_Holding = m_Pending = Serial.Zero;
+ m_HoldingItem = null;
+ m_Lifted = DateTime.MinValue;
+ }
+ else
+ {
+ return ProcStatus.KeepWaiting;
+ }
+ }
+
+ if ( m_Front == m_Back )
+ {
+ m_Front = m_Back = 0;
+ return ProcStatus.Nothing;
+ }
+
+ LiftReq lr = m_LiftReqs[m_Front];
+
+ if ( numPending > 0 && lr != null && lr.DoLast )
+ return ProcStatus.ReQueue;
+
+ m_LiftReqs[m_Front] = null;
+ m_Front++;
+ if ( lr != null )
+ {
+ Log( "Lifting {0}", lr );
+
+ Item item = World.FindItem( lr.Serial );
+ if ( item != null && item.Container == null )
+ { // if the item is on the ground and out of range then dont grab it
+ if ( Utility.Distance( item.GetWorldPosition(), World.Player.Position ) > 3 )
+ {
+ Log( "Item is too far away... uncaching." );
+ return ProcStatus.Nothing;
+ }
+ }
+
+ ClientCommunication.SendToServer( new LiftRequest( lr.Serial, lr.Amount ) );
+
+ m_LastID = lr.Id;
+ m_Holding = lr.Serial;
+ m_HoldingItem = World.FindItem( lr.Serial );
+ m_ClientLiftReq = lr.FromClient;
+
+ DropReq dr = DequeueDropFor( lr.Serial );
+ if ( dr != null )
+ {
+ m_Pending = Serial.Zero;
+ m_Lifted = DateTime.MinValue;
+
+ Log( "Dropping {0} to {1}", lr, dr.Serial );
+
+ if ( dr.Serial.IsMobile && dr.Layer > Layer.Invalid && dr.Layer <= Layer.LastUserValid )
+ ClientCommunication.SendToServer( new EquipRequest( lr.Serial, dr.Serial, dr.Layer ) );
+ else
+ ClientCommunication.SendToServer( new DropRequest( lr.Serial, dr.Point, dr.Serial ) );
+ }
+ else
+ {
+ m_Pending = lr.Serial;
+ m_Lifted = DateTime.UtcNow;
+ }
+
+ return ProcStatus.Success;
+ }
+ else
+ {
+ Log( "No lift to be done?!" );
+ return ProcStatus.Nothing;
+ }
+ }
+ }
+
+ public class ActionQueue
+ {
+ private static Serial m_Last = Serial.Zero;
+ private static readonly Queue m_Queue = new Queue();
+ private static readonly ProcTimer m_Timer = new ProcTimer();
+ private static int m_Total = 0;
+
+ public static void DoubleClick( bool silent, Serial s )
+ {
+ if ( s != Serial.Zero )
+ {
+ if ( m_Last != s )
+ {
+ m_Queue.Enqueue( s );
+ m_Last = s;
+ m_Total++;
+ if ( m_Queue.Count == 1 && !m_Timer.Running )
+ m_Timer.StartMe();
+
+ }
+
+ }
+ }
+
+ public static void SignalLift( bool silent )
+ {
+ m_Queue.Enqueue( Serial.Zero );
+ m_Total++;
+ if ( /*m_Queue.Count == 1 &&*/ !m_Timer.Running )
+ m_Timer.StartMe();
+
+ }
+
+ public static void Stop()
+ {
+ if ( m_Timer != null && m_Timer.Running )
+ m_Timer.Stop();
+ m_Queue.Clear();
+ DragDropManager.Clear();
+ }
+
+ public static bool Empty { get { return m_Queue.Count <= 0 && !m_Timer.Running; } }
+
+ public static string TimeLeft
+ {
+ get
+ {
+ if ( m_Timer.Running )
+ {
+ //Config.GetBool("ObjectDelayEnabled")
+ //double time = Config.GetInt( "ObjectDelay" ) / 1000.0;
+
+ double time = Config.GetInt("ObjectDelay") / 1000.0;
+
+ if (!Config.GetBool("ObjectDelayEnabled"))
+ {
+ time = 0;
+ }
+
+ double init = 0;
+ if ( m_Timer.LastTick != DateTime.MinValue )
+ init = time - ( DateTime.UtcNow - m_Timer.LastTick ).TotalSeconds;
+ time = init+time*m_Queue.Count;
+ if ( time < 0 )
+ time = 0;
+ return String.Format( "{0:F1} seconds", time );
+ }
+ else
+ {
+ return "0.0 seconds";
+ }
+ }
+ }
+
+ private class ProcTimer : Timer
+ {
+ private DateTime m_StartTime;
+ private DateTime m_LastTick;
+
+ public DateTime LastTick { get { return m_LastTick; } }
+
+ public ProcTimer() : base( TimeSpan.Zero, TimeSpan.Zero )
+ {
+ }
+
+ public void StartMe()
+ {
+ m_LastTick = DateTime.UtcNow;
+ m_StartTime = DateTime.UtcNow;
+
+ OnTick();
+
+ Delay = Interval;
+
+ Start();
+ }
+
+ protected override void OnTick()
+ {
+ ArrayList requeue = null;
+
+ m_LastTick = DateTime.UtcNow;
+
+ if ( m_Queue != null && m_Queue.Count > 0 )
+ {
+ this.Interval = TimeSpan.FromMilliseconds(Config.GetBool("ObjectDelayEnabled") ? Config.GetInt("ObjectDelay") : 0);
+
+ //this.Interval = TimeSpan.FromMilliseconds( Config.GetInt( "ObjectDelay" ) );
+
+ while ( m_Queue.Count > 0 )
+ {
+ Serial s = (Serial)m_Queue.Peek();
+ if ( s == Serial.Zero ) // dragdrop action
+ {
+ DragDropManager.ProcStatus status = DragDropManager.ProcessNext( m_Queue.Count - 1 );
+ if ( status != DragDropManager.ProcStatus.KeepWaiting )
+ {
+ m_Queue.Dequeue(); // if not waiting then dequeue it
+
+ if ( status == DragDropManager.ProcStatus.ReQueue )
+ m_Queue.Enqueue( s );
+ }
+
+ if ( status == DragDropManager.ProcStatus.KeepWaiting || status == DragDropManager.ProcStatus.Success )
+ break; // don't process more if we're waiting or we just processed something
+ }
+ else
+ {
+ m_Queue.Dequeue();
+ ClientCommunication.SendToServer( new DoubleClick( s ) );
+ break;
+ }
+ }
+
+ if ( requeue != null )
+ {
+ for(int i=0;i s.ShowMe());
+
+ if (m_Parent != null)
+ m_Parent.Update();
+ }
+ }
+
+ public class DoubleClickTypeAction : MacroAction
+ {
+ private ushort m_Gfx;
+ public bool m_Item;
+
+ public DoubleClickTypeAction(string[] args)
+ {
+ m_Gfx = Convert.ToUInt16(args[1]);
+ try
+ {
+ m_Item = Convert.ToBoolean(args[2]);
+ }
+ catch
+ {
+ }
+ }
+
+ public DoubleClickTypeAction(ushort gfx, bool item)
+ {
+ m_Gfx = gfx;
+ m_Item = item;
+ }
+
+ public override bool Perform()
+ {
+ Serial click = Serial.Zero;
+
+ if (m_Item)
+ {
+ Item item = World.Player.Backpack != null ? World.Player.Backpack.FindItemByID(m_Gfx) : null;
+ ArrayList list = new ArrayList();
+ if (item == null)
+ {
+ foreach (Item i in World.Items.Values)
+ {
+ if (i.ItemID == m_Gfx && i.RootContainer == null)
+ {
+ if (Config.GetBool("RangeCheckDoubleClick"))
+ {
+ if (Utility.InRange(World.Player.Position, i.Position, 2))
+ {
+ list.Add(i);
+ }
+ }
+ else
+ {
+ list.Add(i);
+ }
+ }
+
+ }
+ if (list.Count == 0)
+ {
+ foreach (Item i in World.Items.Values)
+ {
+ if (i.ItemID == m_Gfx && !i.IsInBank)
+ {
+ if (Config.GetBool("RangeCheckDoubleClick"))
+ {
+ if (Utility.InRange(World.Player.Position, i.Position, 2))
+ {
+ list.Add(i);
+ }
+ }
+ else
+ {
+ list.Add(i);
+ }
+ }
+ }
+ }
+
+ if (list.Count > 0)
+ click = ((Item)list[Utility.Random(list.Count)]).Serial;
+ }
+ else
+ {
+ click = item.Serial;
+ }
+ }
+ else
+ {
+ ArrayList list = new ArrayList();
+ foreach (Mobile m in World.MobilesInRange())
+ {
+ if (m.Body == m_Gfx)
+ {
+ if (Config.GetBool("RangeCheckDoubleClick"))
+ {
+ if (Utility.InRange(World.Player.Position, m.Position, 2))
+ {
+ list.Add(m);
+ }
+ }
+ else
+ {
+ list.Add(m);
+ }
+ }
+ }
+
+ if (list.Count > 0)
+ click = ((Mobile)list[Utility.Random(list.Count)]).Serial;
+ }
+
+ if (click != Serial.Zero)
+ PlayerData.DoubleClick(click);
+ else
+ World.Player.SendMessage(MsgLevel.Force, LocString.NoItemOfType, m_Item ? ((ItemID)m_Gfx).ToString() : String.Format("(Character) 0x{0:X}", m_Gfx));
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Gfx, m_Item);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.DClickA1, m_Item ? ((ItemID)m_Gfx).ToString() : String.Format("(Character) 0x{0:X}", m_Gfx));
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.ReTarget, new MacroMenuCallback( ReTarget ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void ReTarget(object[] args)
+ {
+ Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnReTarget));
+ World.Player.SendMessage(LocString.SelTargAct);
+ }
+
+ private void OnReTarget(bool ground, Serial serial, Point3D pt, ushort gfx)
+ {
+ m_Gfx = gfx;
+ m_Item = serial.IsItem;
+
+ Engine.MainWindow.SafeAction(s => s.ShowMe());
+ if (m_Parent != null)
+ m_Parent.Update();
+ }
+ }
+
+ public class LiftAction : MacroWaitAction
+ {
+ private ushort m_Amount;
+ private Serial m_Serial;
+ private ushort m_Gfx;
+
+ private static Item m_LastLift;
+ public static Item LastLift { get { return m_LastLift; } set { m_LastLift = value; } }
+
+ public LiftAction(string[] args)
+ {
+ m_Serial = Serial.Parse(args[1]);
+ m_Amount = Convert.ToUInt16(args[2]);
+ m_Gfx = Convert.ToUInt16(args[3]);
+ }
+
+ public LiftAction(Serial ser, ushort amount, ushort gfx)
+ {
+ m_Serial = ser;
+ m_Amount = amount;
+ m_Gfx = gfx;
+ }
+
+ private int m_Id;
+
+ public override bool Perform()
+ {
+ Item item = World.FindItem(m_Serial);
+ if (item != null)
+ {
+ //DragDropManager.Holding = item;
+ m_LastLift = item;
+ m_Id = DragDropManager.Drag(item, m_Amount <= item.Amount ? m_Amount : item.Amount);
+ }
+ else
+ {
+ World.Player.SendMessage(MsgLevel.Warning, LocString.MacroItemOutRange);
+ }
+ return false;
+ }
+
+ public override bool PerformWait()
+ {
+ return DragDropManager.LastIDLifted < m_Id;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Serial.Value, m_Amount, m_Gfx);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.LiftA10, m_Serial, m_Amount);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.ConvLiftByType, new MacroMenuCallback( ConvertToByType ) ),
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( EditAmount ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void EditAmount(object[] args)
+ {
+ if (InputBox.Show(Engine.MainWindow, Language.GetString(LocString.EnterAmount), Language.GetString(LocString.InputReq), m_Amount.ToString()))
+ {
+ m_Amount = (ushort)InputBox.GetInt(m_Amount);
+
+ if (m_Parent != null)
+ m_Parent.Update();
+ }
+ }
+
+ private void ConvertToByType(object[] args)
+ {
+ if (m_Gfx != 0 && m_Parent != null)
+ m_Parent.Convert(this, new LiftTypeAction(m_Gfx, m_Amount));
+ }
+ }
+
+ public class LiftTypeAction : MacroWaitAction
+ {
+ private ushort m_Gfx;
+ private ushort m_Amount;
+
+ public LiftTypeAction(string[] args)
+ {
+ m_Gfx = Convert.ToUInt16(args[1]);
+ m_Amount = Convert.ToUInt16(args[2]);
+ }
+
+ public LiftTypeAction(ushort gfx, ushort amount)
+ {
+ m_Gfx = gfx;
+ m_Amount = amount;
+ }
+
+ private int m_Id;
+ public override bool Perform()
+ {
+ Item item = World.Player.Backpack != null ? World.Player.Backpack.FindItemByID(m_Gfx) : null;
+ /*if ( item == null )
+ {
+ ArrayList list = new ArrayList();
+
+ foreach ( Item i in World.Items.Values )
+ {
+ if ( i.ItemID == m_Gfx && ( i.RootContainer == null || i.IsChildOf( World.Player.Quiver ) ) )
+ list.Add( i );
+ }
+
+ if ( list.Count > 0 )
+ item = (Item)list[ Utility.Random( list.Count ) ];
+ }*/
+
+ if (item != null)
+ {
+ //DragDropManager.Holding = item;
+ ushort amount = m_Amount;
+ if (item.Amount < amount)
+ amount = item.Amount;
+ LiftAction.LastLift = item;
+ //ActionQueue.Enqueue( new LiftRequest( item, amount ) );
+ m_Id = DragDropManager.Drag(item, amount);
+ }
+ else
+ {
+ World.Player.SendMessage(MsgLevel.Warning, LocString.NoItemOfType, (ItemID)m_Gfx);
+ //MacroManager.Stop();
+ }
+ return false;
+ }
+
+ public override bool PerformWait()
+ {
+ return DragDropManager.LastIDLifted < m_Id && !DragDropManager.Empty;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Gfx, m_Amount);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( EditAmount ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void EditAmount(object[] args)
+ {
+ if (InputBox.Show(Engine.MainWindow, Language.GetString(LocString.EnterAmount), Language.GetString(LocString.InputReq), m_Amount.ToString()))
+ {
+ m_Amount = (ushort)InputBox.GetInt(m_Amount);
+
+ if (m_Parent != null)
+ m_Parent.Update();
+ }
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.LiftA10, m_Amount, (ItemID)m_Gfx);
+ }
+ }
+
+ public class DropAction : MacroAction
+ {
+ private Serial m_To;
+ private Point3D m_At;
+ private Layer m_Layer;
+
+ public DropAction(string[] args)
+ {
+ m_To = Serial.Parse(args[1]);
+ m_At = Point3D.Parse(args[2]);
+ try
+ {
+ m_Layer = (Layer)Byte.Parse(args[3]);
+ }
+ catch
+ {
+ m_Layer = Layer.Invalid;
+ }
+ }
+
+ public DropAction(Serial to, Point3D at) : this(to, at, 0)
+ {
+ }
+
+ public DropAction(Serial to, Point3D at, Layer layer)
+ {
+ m_To = to;
+ m_At = at;
+ m_Layer = layer;
+ }
+
+ public override bool Perform()
+ {
+ if (DragDropManager.Holding != null)
+ {
+ if (m_Layer > Layer.Invalid && m_Layer <= Layer.LastUserValid)
+ {
+ Mobile m = World.FindMobile(m_To);
+ if (m != null)
+ DragDropManager.Drop(DragDropManager.Holding, m, m_Layer);
+ }
+ else
+ {
+ DragDropManager.Drop(DragDropManager.Holding, m_To, m_At);
+ }
+ }
+ else
+ {
+ World.Player.SendMessage(MsgLevel.Warning, LocString.MacroNoHold);
+ }
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_To, m_At, (byte)m_Layer);
+ }
+
+ public override string ToString()
+ {
+ if (m_Layer != Layer.Invalid)
+ return Language.Format(LocString.EquipTo, m_To, m_Layer);
+ else
+ return Language.Format(LocString.DropA2, m_To.IsValid ? m_To.ToString() : "Ground", m_At);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_To.IsValid)
+ {
+ return null; // Dont allow conversion(s)
+ }
+ else
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.ConvRelLoc, new MacroMenuCallback( ConvertToRelLoc ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+ }
+
+ private void ConvertToRelLoc(object[] args)
+ {
+ if (!m_To.IsValid && m_Parent != null)
+ m_Parent.Convert(this, new DropRelLocAction((sbyte)(m_At.X - World.Player.Position.X), (sbyte)(m_At.Y - World.Player.Position.Y), (sbyte)(m_At.Z - World.Player.Position.Z)));
+ }
+ }
+
+ public class DropRelLocAction : MacroAction
+ {
+ private sbyte[] m_Loc;
+
+ public DropRelLocAction(string[] args)
+ {
+ m_Loc = new sbyte[3]
+ {
+ Convert.ToSByte( args[1] ),
+ Convert.ToSByte( args[2] ),
+ Convert.ToSByte( args[3] )
+ };
+ }
+
+ public DropRelLocAction(sbyte x, sbyte y, sbyte z)
+ {
+ m_Loc = new sbyte[3] { x, y, z };
+ }
+
+ public override bool Perform()
+ {
+ if (DragDropManager.Holding != null)
+ DragDropManager.Drop(DragDropManager.Holding, null, new Point3D((ushort)(World.Player.Position.X + m_Loc[0]), (ushort)(World.Player.Position.Y + m_Loc[1]), (short)(World.Player.Position.Z + m_Loc[2])));
+ else
+ World.Player.SendMessage(LocString.MacroNoHold);
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Loc[0], m_Loc[1], m_Loc[2]);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.DropRelA3, m_Loc[0], m_Loc[1], m_Loc[2]);
+ }
+ }
+
+ public class GumpResponseAction : MacroAction
+ {
+ private int m_ButtonID;
+ private int[] m_Switches;
+ private GumpTextEntry[] m_TextEntries;
+
+ public GumpResponseAction(string[] args)
+ {
+ m_ButtonID = Convert.ToInt32(args[1]);
+ m_Switches = new int[Convert.ToInt32(args[2])];
+ for (int i = 0; i < m_Switches.Length; i++)
+ m_Switches[i] = Convert.ToInt32(args[3 + i]);
+ m_TextEntries = new GumpTextEntry[Convert.ToInt32(args[3 + m_Switches.Length])];
+ for (int i = 0; i < m_TextEntries.Length; i++)
+ {
+ string[] split = args[4 + m_Switches.Length + i].Split('&');
+ m_TextEntries[i].EntryID = Convert.ToUInt16(split[0]);
+ m_TextEntries[i].Text = split[1];
+ }
+ }
+
+ public GumpResponseAction(int button, int[] switches, GumpTextEntry[] entries)
+ {
+ m_ButtonID = button;
+ m_Switches = switches;
+ m_TextEntries = entries;
+ }
+
+ public override bool Perform()
+ {
+ ClientCommunication.SendToClient(new CloseGump(World.Player.CurrentGumpI));
+ ClientCommunication.SendToServer(new GumpResponse(World.Player.CurrentGumpS, World.Player.CurrentGumpI, m_ButtonID, m_Switches, m_TextEntries));
+ World.Player.HasGump = false;
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ ArrayList list = new ArrayList(3 + m_Switches.Length + m_TextEntries.Length);
+ list.Add(m_ButtonID);
+ list.Add(m_Switches.Length);
+ list.AddRange(m_Switches);
+ list.Add(m_TextEntries.Length);
+ for (int i = 0; i < m_TextEntries.Length; i++)
+ list.Add(String.Format("{0}&{1}", m_TextEntries[i].EntryID, m_TextEntries[i].Text));
+ return DoSerialize((object[])list.ToArray(typeof(object)));
+ }
+
+ public override string ToString()
+ {
+ if (m_ButtonID != 0)
+ return Language.Format(LocString.GumpRespB, m_ButtonID);
+ else
+ return Language.Format(LocString.CloseGump);
+ }
+
+ private MenuItem[] m_MenuItems;
+
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (this.m_MenuItems == null)
+ this.m_MenuItems = (MenuItem[])new MacroMenuItem[]
+ {
+ new MacroMenuItem(LocString.UseLastGumpResponse, new MacroMenuCallback(this.UseLastResponse), new object[0]),
+ new MacroMenuItem(LocString.Edit, new MacroMenuCallback(this.Edit), new object[0])
+ };
+ return this.m_MenuItems;
+ }
+
+ private void Edit(object[] args)
+ {
+ if (InputBox.Show(Language.GetString(LocString.EnterNewText), "Input Box", this.m_ButtonID.ToString()))
+ this.m_ButtonID = InputBox.GetInt();
+
+ Parent?.Update();
+ }
+
+ private void UseLastResponse(object[] args)
+ {
+ m_ButtonID = World.Player.LastGumpResponseAction.m_ButtonID;
+ m_Switches = World.Player.LastGumpResponseAction.m_Switches;
+ m_TextEntries = World.Player.LastGumpResponseAction.m_TextEntries;
+
+ World.Player.SendMessage(MsgLevel.Force, "Set GumpResponse to last response");
+
+ Parent?.Update();
+ }
+ }
+
+ public class MenuResponseAction : MacroAction
+ {
+ private ushort m_Index, m_ItemID, m_Hue;
+
+ public MenuResponseAction(string[] args)
+ {
+ m_Index = Convert.ToUInt16(args[1]);
+ m_ItemID = Convert.ToUInt16(args[2]);
+ m_Hue = Convert.ToUInt16(args[3]);
+ }
+
+ public MenuResponseAction(ushort idx, ushort iid, ushort hue)
+ {
+ m_Index = idx;
+ m_ItemID = iid;
+ m_Hue = hue;
+ }
+
+ public override bool Perform()
+ {
+ ClientCommunication.SendToServer(new MenuResponse(World.Player.CurrentMenuS, World.Player.CurrentMenuI, m_Index, m_ItemID, m_Hue));
+ World.Player.HasMenu = false;
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Index, m_ItemID, m_Hue);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.MenuRespA1, m_Index);
+ }
+ }
+
+ public class AbsoluteTargetAction : MacroAction
+ {
+ private TargetInfo m_Info;
+
+ public AbsoluteTargetAction(string[] args)
+ {
+ m_Info = new TargetInfo();
+
+ m_Info.Type = Convert.ToByte(args[1]);
+ m_Info.Flags = Convert.ToByte(args[2]);
+ m_Info.Serial = Convert.ToUInt32(args[3]);
+ m_Info.X = Convert.ToUInt16(args[4]);
+ m_Info.Y = Convert.ToUInt16(args[5]);
+ m_Info.Z = Convert.ToInt16(args[6]);
+ m_Info.Gfx = Convert.ToUInt16(args[7]);
+ }
+
+ public AbsoluteTargetAction(TargetInfo info)
+ {
+ m_Info = new TargetInfo();
+ m_Info.Type = info.Type;
+ m_Info.Flags = info.Flags;
+ m_Info.Serial = info.Serial;
+ m_Info.X = info.X;
+ m_Info.Y = info.Y;
+ m_Info.Z = info.Z;
+ m_Info.Gfx = info.Gfx;
+ }
+
+ public override bool Perform()
+ {
+ Targeting.Target(m_Info);
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Info.Type, m_Info.Flags, m_Info.Serial.Value, m_Info.X, m_Info.Y, m_Info.Z, m_Info.Gfx);
+ }
+
+ public override string ToString()
+ {
+ return Language.GetString(LocString.AbsTarg);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.ReTarget, new MacroMenuCallback( ReTarget ) ),
+ new MacroMenuItem( LocString.ConvLT, new MacroMenuCallback( ConvertToLastTarget ) ),
+ new MacroMenuItem( LocString.ConvTargType, new MacroMenuCallback( ConvertToByType ) ),
+ new MacroMenuItem( LocString.ConvRelLoc, new MacroMenuCallback( ConvertToRelLoc ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void ReTarget(object[] args)
+ {
+ Targeting.OneTimeTarget(!m_Info.Serial.IsValid, new Targeting.TargetResponseCallback(ReTargetResponse));
+ World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);
+ }
+
+ private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)
+ {
+ m_Info.Gfx = gfx;
+ m_Info.Serial = serial;
+ m_Info.Type = (byte)(ground ? 1 : 0);
+ m_Info.X = pt.X;
+ m_Info.Y = pt.Y;
+ m_Info.Z = pt.Z;
+
+ Engine.MainWindow.SafeAction(s => s.ShowMe());
+ if (m_Parent != null)
+ m_Parent.Update();
+ }
+
+ private void ConvertToLastTarget(object[] args)
+ {
+ if (m_Parent != null)
+ m_Parent.Convert(this, new LastTargetAction());
+ }
+
+ private void ConvertToByType(object[] args)
+ {
+ if (m_Parent != null)
+ m_Parent.Convert(this, new TargetTypeAction(m_Info.Serial.IsMobile, m_Info.Gfx));
+ }
+
+ private void ConvertToRelLoc(object[] args)
+ {
+ if (m_Parent != null)
+ m_Parent.Convert(this, new TargetRelLocAction((sbyte)(m_Info.X - World.Player.Position.X), (sbyte)(m_Info.Y - World.Player.Position.Y)));//, (sbyte)(m_Info.Z - World.Player.Position.Z) ) );
+ }
+ }
+
+ ///
+ /// Action to handle variable macros to alleviate the headache of having multiple macros for the same thing
+ ///
+ /// This Action does break the pattern that you see in every other action because the data that is stored for this
+ /// action exists not in the Macro file, but in a different file that has all the variables
+ ///
+ /// TODO: Re-eval this concept and instead store all data
+ ///
+ public class AbsoluteTargetVariableAction : MacroAction
+ {
+ private TargetInfo _target;
+ private readonly string _variableName;
+
+ public AbsoluteTargetVariableAction(string[] args)
+ {
+ _variableName = args[1];
+ }
+
+ public override bool Perform()
+ {
+ _target = null;
+
+ foreach (AbsoluteTargets.AbsoluteTarget at in AbsoluteTargets.AbsoluteTargetList)
+ {
+ if (at.TargetVariableName.Equals(_variableName))
+ {
+ _target = at.TargetInfo;
+ break;
+ }
+ }
+
+ if (_target != null)
+ {
+ Targeting.Target(_target);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(_variableName);
+ }
+
+ public override string ToString()
+ {
+ return $"{Language.GetString(LocString.AbsTarg)} (${_variableName})";
+ }
+
+ /*private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.ReTarget, ReTarget )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void ReTarget(object[] args)
+ {
+ Targeting.OneTimeTarget(!_target.Serial.IsValid, new Targeting.TargetResponseCallback(ReTargetResponse));
+ World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);
+ }
+
+ private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)
+ {
+ _target.Gfx = gfx;
+ _target.Serial = serial;
+ _target.Type = (byte)(ground ? 1 : 0);
+ _target.X = pt.X;
+ _target.Y = pt.Y;
+ _target.Z = pt.Z;
+
+ Engine.MainWindow.SafeAction(s => s.ShowMe());
+
+ m_Parent?.Update();
+ }*/
+ }
+
+ public class TargetTypeAction : MacroAction
+ {
+ private bool m_Mobile;
+ private ushort m_Gfx;
+ private object _previousObject;
+
+ public TargetTypeAction(string[] args)
+ {
+ m_Mobile = Convert.ToBoolean(args[1]);
+ m_Gfx = Convert.ToUInt16(args[2]);
+ }
+
+ public TargetTypeAction(bool mobile, ushort gfx)
+ {
+ m_Mobile = mobile;
+ m_Gfx = gfx;
+ }
+
+ public override bool Perform()
+ {
+ ArrayList list = new ArrayList();
+ if (m_Mobile)
+ {
+ foreach (Mobile find in World.MobilesInRange())
+ {
+ if (find.Body == m_Gfx)
+ {
+ if (Config.GetBool("RangeCheckTargetByType"))
+ {
+ if (Utility.InRange(World.Player.Position, find.Position, 2))
+ {
+ list.Add(find);
+ }
+ }
+ else
+ {
+ list.Add(find);
+ }
+ }
+ }
+ }
+ else
+ {
+ foreach (Item i in World.Items.Values)
+ {
+ if (i.ItemID == m_Gfx && !i.IsInBank)
+ {
+ if (Config.GetBool("RangeCheckTargetByType"))
+ {
+ if (Utility.InRange(World.Player.Position, i.Position, 2))
+ {
+ list.Add(i);
+ }
+ }
+ else
+ {
+ list.Add(i);
+ }
+ }
+
+ }
+ }
+
+ if (list.Count > 0)
+ {
+ if (Config.GetBool("DiffTargetByType") && list.Count > 1)
+ {
+ object currentObject = list[Utility.Random(list.Count)];
+
+ while (_previousObject != null && _previousObject == currentObject)
+ {
+ currentObject = list[Utility.Random(list.Count)];
+ }
+
+ Targeting.Target(currentObject);
+
+ _previousObject = currentObject;
+ }
+ else
+ {
+ Targeting.Target(list[Utility.Random(list.Count)]);
+ }
+
+ }
+ else
+ {
+ World.Player.SendMessage(MsgLevel.Warning, LocString.NoItemOfType,
+ m_Mobile ? String.Format("Character [{0}]", m_Gfx) : ((ItemID)m_Gfx).ToString());
+ }
+
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Mobile, m_Gfx);
+ }
+
+ public override string ToString()
+ {
+ if (m_Mobile)
+ return Language.Format(LocString.TargByType, m_Gfx);
+ else
+ return Language.Format(LocString.TargByType, (ItemID)m_Gfx);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.ReTarget, new MacroMenuCallback( ReTarget ) ),
+ new MacroMenuItem( LocString.ConvLT, new MacroMenuCallback( ConvertToLastTarget ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void ReTarget(object[] args)
+ {
+ Targeting.OneTimeTarget(false, new Targeting.TargetResponseCallback(ReTargetResponse));
+ World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);
+ }
+
+ private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)
+ {
+ if (!ground && serial.IsValid)
+ {
+ m_Mobile = serial.IsMobile;
+ m_Gfx = gfx;
+ }
+ Engine.MainWindow.SafeAction(s => s.ShowMe());
+ if (m_Parent != null)
+ m_Parent.Update();
+ }
+
+ private void ConvertToLastTarget(object[] args)
+ {
+ if (m_Parent != null)
+ m_Parent.Convert(this, new LastTargetAction());
+ }
+ }
+
+ public class TargetRelLocAction : MacroAction
+ {
+ private sbyte m_X, m_Y;
+
+ public TargetRelLocAction(string[] args)
+ {
+ m_X = Convert.ToSByte(args[1]);
+ m_Y = Convert.ToSByte(args[2]);
+ }
+
+ public TargetRelLocAction(sbyte x, sbyte y)
+ {
+ m_X = x;
+ m_Y = y;
+ }
+
+ public override bool Perform()
+ {
+ ushort x = (ushort)(World.Player.Position.X + m_X);
+ ushort y = (ushort)(World.Player.Position.Y + m_Y);
+ short z = (short)World.Player.Position.Z;
+ try
+ {
+ Ultima.HuedTile tile = Map.GetTileNear(World.Player.Map, x, y, z);
+ Targeting.Target(new Point3D(x, y, tile.Z), (ushort)tile.ID);
+ }
+ catch (Exception e)
+ {
+ World.Player.SendMessage(MsgLevel.Debug, "Error Executing TargetRelLoc: {0}", e.Message);
+ }
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_X, m_Y);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.TargRelLocA3, m_X, m_Y, 0);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.ReTarget, new MacroMenuCallback( ReTarget ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void ReTarget(object[] args)
+ {
+ Engine.MainWindow.SafeAction(s => s.ShowMe());
+
+ Targeting.OneTimeTarget(true, new Targeting.TargetResponseCallback(ReTargetResponse));
+ World.Player.SendMessage(LocString.SelTargAct);
+ }
+
+ private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)
+ {
+ m_X = (sbyte)(pt.X - World.Player.Position.X);
+ m_Y = (sbyte)(pt.Y - World.Player.Position.Y);
+ // m_Z = (sbyte)(pt.Z - World.Player.Position.Z);
+ if (m_Parent != null)
+ m_Parent.Update();
+ }
+ }
+
+ public class LastTargetAction : MacroAction
+ {
+ public LastTargetAction()
+ {
+ }
+
+ public override bool Perform()
+ {
+ if (!Targeting.DoLastTarget())//Targeting.LastTarget( true );
+ Targeting.ResendTarget();
+ return true;
+ }
+
+ public override string ToString()
+ {
+ return String.Format("Exec: {0}", Language.GetString(LocString.LastTarget));
+ }
+ }
+
+ public class SetLastTargetAction : MacroWaitAction
+ {
+ public SetLastTargetAction()
+ {
+ }
+
+ public override bool Perform()
+ {
+ Targeting.TargetSetLastTarget();
+ return !PerformWait();
+ }
+
+ public override bool PerformWait()
+ {
+ return !Targeting.LTWasSet;
+ }
+
+ public override string ToString()
+ {
+ return Language.GetString(LocString.SetLT);
+ }
+ }
+
+ public class SpeechAction : MacroAction
+ {
+ private MessageType m_Type;
+ private ushort m_Font;
+ private ushort m_Hue;
+ private string m_Lang;
+ private ArrayList m_Keywords;
+ private string m_Speech;
+
+ public SpeechAction(string[] args)
+ {
+ m_Type = ((MessageType)Convert.ToInt32(args[1])) & ~MessageType.Encoded;
+ m_Hue = Convert.ToUInt16(args[2]);
+ m_Font = Convert.ToUInt16(args[3]);
+ m_Lang = args[4];
+
+ int count = Convert.ToInt32(args[5]);
+ if (count > 0)
+ {
+ m_Keywords = new ArrayList(count);
+ m_Keywords.Add(Convert.ToUInt16(args[6]));
+
+ for (int i = 1; i < count; i++)
+ m_Keywords.Add(Convert.ToByte(args[6 + i]));
+ }
+
+ m_Speech = args[6 + count];
+ }
+
+ public SpeechAction(MessageType type, ushort hue, ushort font, string lang, ArrayList kw, string speech)
+ {
+ m_Type = type;
+ m_Hue = hue;
+ m_Font = font;
+ m_Lang = lang;
+ m_Keywords = kw;
+ m_Speech = speech;
+ }
+
+ public override bool Perform()
+ {
+ if (m_Speech.Length > 1 && m_Speech[0] == '-')
+ {
+ string text = m_Speech.Substring(1);
+ string[] split = text.Split(' ', '\t');
+ CommandCallback call = (CommandCallback)Command.List[split[0]];
+ if (call == null && text[0] == '-')
+ {
+ call = (CommandCallback)Command.List["-"];
+ if (call != null && split.Length > 1 && split[1] != null && split[1].Length > 1)
+ split[1] = split[1].Substring(1);
+ }
+
+ if (call != null)
+ {
+ ArrayList list = new ArrayList();
+ for (int i = 1; i < split.Length; i++)
+ {
+ if (split[i] != null && split[i].Length > 0)
+ list.Add(split[i]);
+ }
+ call((string[])list.ToArray(typeof(string)));
+ return true;
+ }
+ }
+
+ int hue = m_Hue;
+
+ if (m_Type != MessageType.Emote)
+ {
+ if (World.Player.SpeechHue == 0)
+ World.Player.SpeechHue = m_Hue;
+ hue = World.Player.SpeechHue;
+ }
+
+ ClientCommunication.SendToServer(new ClientUniMessage(m_Type, hue, m_Font, m_Lang, m_Keywords, m_Speech));
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ ArrayList list = new ArrayList(6);
+ list.Add((int)m_Type);
+ list.Add(m_Hue);
+ list.Add(m_Font);
+ list.Add(m_Lang);
+ if (m_Keywords != null && m_Keywords.Count > 1)
+ {
+ list.Add((int)m_Keywords.Count);
+ for (int i = 0; i < m_Keywords.Count; i++)
+ list.Add(m_Keywords[i]);
+ }
+ else
+ {
+ list.Add("0");
+ }
+ list.Add(m_Speech);
+
+ return DoSerialize((object[])list.ToArray(typeof(object)));
+ }
+
+ public override string ToString()
+ {
+ //return Language.Format( LocString.SayQA1, m_Speech );
+ StringBuilder sb = new StringBuilder();
+ switch (m_Type)
+ {
+ case MessageType.Emote:
+ sb.Append("Emote: ");
+ break;
+ case MessageType.Whisper:
+ sb.Append("Whisper: ");
+ break;
+ case MessageType.Yell:
+ sb.Append("Yell: ");
+ break;
+ case MessageType.Regular:
+ default:
+ sb.Append("Say: ");
+ break;
+ }
+ sb.Append(m_Speech);
+ return sb.ToString();
+ }
+
+ private MenuItem[] m_MenuItems;
+
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (this.m_MenuItems == null)
+ this.m_MenuItems = (MenuItem[])new MacroMenuItem[1]
+ {
+ new MacroMenuItem(LocString.Edit, new MacroMenuCallback(this.Edit), new object[0])
+ };
+ return this.m_MenuItems;
+ }
+
+ private void Edit(object[] args)
+ {
+ if (InputBox.Show(Language.GetString(LocString.EnterNewText), "Input Box", this.m_Speech))
+ this.m_Speech = InputBox.GetString();
+ if (this.Parent == null)
+ return;
+ this.Parent.Update();
+ }
+ }
+
+ public class UseSkillAction : MacroAction
+ {
+ private int m_Skill;
+
+ public UseSkillAction(string[] args)
+ {
+ m_Skill = Convert.ToInt32(args[1]);
+ }
+
+ public UseSkillAction(int sk)
+ {
+ m_Skill = sk;
+ }
+
+ public override bool Perform()
+ {
+ ClientCommunication.SendToServer(new UseSkill(m_Skill));
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Skill);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.UseSkillA1, Language.Skill2Str(m_Skill));
+ }
+ }
+
+ public class ExtCastSpellAction : MacroAction
+ {
+ private Spell m_Spell;
+ private Serial m_Book;
+
+ public ExtCastSpellAction(string[] args)
+ {
+ m_Spell = Spell.Get(Convert.ToInt32(args[1]));
+ m_Book = Serial.Parse(args[2]);
+ }
+
+ public ExtCastSpellAction(int s, Serial book)
+ {
+ m_Spell = Spell.Get(s);
+ m_Book = book;
+ }
+
+ public ExtCastSpellAction(Spell s, Serial book)
+ {
+ m_Spell = s;
+ m_Book = book;
+ }
+
+ public override bool Perform()
+ {
+ m_Spell.OnCast(new ExtCastSpell(m_Book, (ushort)m_Spell.GetID()));
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Spell.GetID(), m_Book.Value);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.CastSpellA1, m_Spell);
+ }
+ }
+
+ public class BookCastSpellAction : MacroAction
+ {
+ private Spell m_Spell;
+ private Serial m_Book;
+
+ public BookCastSpellAction(string[] args)
+ {
+ m_Spell = Spell.Get(Convert.ToInt32(args[1]));
+ m_Book = Serial.Parse(args[2]);
+ }
+
+ public BookCastSpellAction(int s, Serial book)
+ {
+ m_Spell = Spell.Get(s);
+ m_Book = book;
+ }
+
+ public BookCastSpellAction(Spell s, Serial book)
+ {
+ m_Spell = s;
+ m_Book = book;
+ }
+
+ public override bool Perform()
+ {
+ m_Spell.OnCast(new CastSpellFromBook(m_Book, (ushort)m_Spell.GetID()));
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Spell.GetID(), m_Book.Value);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.CastSpellA1, m_Spell);
+ }
+ }
+
+ public class MacroCastSpellAction : MacroAction
+ {
+ private Spell m_Spell;
+
+ public MacroCastSpellAction(string[] args)
+ {
+ m_Spell = Spell.Get(Convert.ToInt32(args[1]));
+ }
+
+ public MacroCastSpellAction(int s)
+ {
+ m_Spell = Spell.Get(s);
+ }
+
+ public MacroCastSpellAction(Spell s)
+ {
+ m_Spell = s;
+ }
+
+ public override bool Perform()
+ {
+ m_Spell.OnCast(new CastSpellFromMacro((ushort)m_Spell.GetID()));
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Spell.GetID());
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.CastSpellA1, m_Spell);
+ }
+ }
+
+ public class SetAbilityAction : MacroAction
+ {
+ private AOSAbility m_Ability;
+
+ public SetAbilityAction(string[] args)
+ {
+ m_Ability = (AOSAbility)Convert.ToInt32(args[1]);
+ }
+
+ public SetAbilityAction(AOSAbility a)
+ {
+ m_Ability = a;
+ }
+
+ public override bool Perform()
+ {
+ ClientCommunication.SendToServer(new UseAbility(m_Ability));
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize((int)m_Ability);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.SetAbilityA1, m_Ability);
+ }
+ }
+
+ public class DressAction : MacroWaitAction
+ {
+ private string m_Name;
+
+ public DressAction(string[] args)
+ {
+ m_Name = args[1];
+ }
+
+ public DressAction(string name)
+ {
+ m_Name = name;
+ }
+
+ public override bool Perform()
+ {
+ DressList list = DressList.Find(m_Name);
+ if (list != null)
+ {
+ list.Dress();
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ public override bool PerformWait()
+ {
+ return !ActionQueue.Empty;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Name);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.DressA1, m_Name);
+ }
+ }
+
+ public class UnDressAction : MacroWaitAction
+ {
+ private string m_Name;
+ private byte m_Layer;
+
+ public UnDressAction(string[] args)
+ {
+ try
+ {
+ m_Layer = Convert.ToByte(args[2]);
+ }
+ catch
+ {
+ m_Layer = 255;
+ }
+
+ if (m_Layer == 255)
+ m_Name = args[1];
+ else
+ m_Name = "";
+ }
+
+ public UnDressAction(string name)
+ {
+ m_Name = name;
+ m_Layer = 255;
+ }
+
+ public UnDressAction(byte layer)
+ {
+ m_Layer = layer;
+ m_Name = "";
+ }
+
+ public override bool Perform()
+ {
+ if (m_Layer == 255)
+ {
+ DressList list = DressList.Find(m_Name);
+ if (list != null)
+ {
+ list.Undress();
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else if (m_Layer == 0)
+ {
+ HotKeys.UndressHotKeys.OnUndressAll();
+ return false;
+ }
+ else
+ {
+ return !HotKeys.UndressHotKeys.Unequip((Layer)m_Layer);
+ }
+ }
+
+ public override bool PerformWait()
+ {
+ return !ActionQueue.Empty;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Name, m_Layer);
+ }
+
+ public override string ToString()
+ {
+ if (m_Layer == 255)
+ return Language.Format(LocString.UndressA1, m_Name);
+ else if (m_Layer == 0)
+ return Language.GetString(LocString.UndressAll);
+ else
+ return Language.Format(LocString.UndressLayerA1, (Layer)m_Layer);
+ }
+ }
+
+ public class WalkAction : MacroWaitAction
+ {
+ private Direction m_Dir;
+ private static DateTime m_LastWalk = DateTime.MinValue;
+
+ private enum KeyboardDir {
+ North = 0x21, //page up
+ Right = 0x27, // right
+ East = 0x22, // page down
+ Down = 0x28, // down
+ South = 0x23, // end
+ Left = 0x25, // left
+ West = 0x24, // home
+ Up = 0x26, // up
+ }
+
+ private static uint WM_KEYDOWN = 0x100, WM_KEYUP = 0x101;
+
+ [DllImport("user32.dll")]
+ private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
+
+ public static DateTime LastWalkTime { get { return m_LastWalk; } set { m_LastWalk = value; } }
+
+ public WalkAction(string[] args)
+ {
+ m_Dir = (Direction)(Convert.ToByte(args[1])) & Direction.Mask;
+ }
+
+ public WalkAction(Direction dir)
+ {
+ m_Dir = dir & Direction.Mask;
+ }
+
+ //private static int m_LastSeq = -1;
+ public override bool Perform()
+ {
+ return !PerformWait();
+ }
+
+ //public static bool IsMacroWalk(byte seq)
+ //{
+ // return m_LastSeq != -1 && m_LastSeq == (int)seq && World.Player.HasWalkEntry((byte)m_LastSeq);
+ //}
+
+ public override bool PerformWait()
+ {
+ if (m_LastWalk + TimeSpan.FromSeconds(0.4) >= DateTime.UtcNow)
+ {
+ return true;
+ }
+ else
+ {
+ m_LastSeq = World.Player.WalkSequence;
+ m_LastWalk = DateTime.UtcNow;
+
+ //ClientCommunication.SendToClient(new ForceWalk(m_Dir));
+ ClientCommunication.SendToServer(new WalkRequest(m_Dir, World.Player.WalkSequence++));
+
+
+
+ return false;
+ }
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize((byte)m_Dir);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.WalkA1, m_Dir != Direction.Mask ? m_Dir.ToString() : "Up");
+ }
+ }
+
+ public class WaitForMenuAction : MacroWaitAction
+ {
+ private uint m_MenuID;
+
+ public WaitForMenuAction(uint gid)
+ {
+ m_MenuID = gid;
+ }
+
+ public WaitForMenuAction(string[] args)
+ {
+ if (args.Length > 1)
+ m_MenuID = Convert.ToUInt32(args[1]);
+
+ try
+ {
+ m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[2]));
+ }
+ catch
+ {
+ }
+ }
+
+ public override bool Perform()
+ {
+ return !PerformWait();
+ }
+
+ public override bool PerformWait()
+ {
+ return !(World.Player.HasMenu && (World.Player.CurrentGumpI == m_MenuID || m_MenuID == 0));
+ }
+
+ public override string ToString()
+ {
+ if (m_MenuID == 0)
+ return Language.GetString(LocString.WaitAnyMenu);
+ else
+ return Language.Format(LocString.WaitMenuA1, m_MenuID);
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_MenuID, m_Timeout.TotalSeconds);
+ }
+
+ public override bool CheckMatch(MacroAction a)
+ {
+ if (a is WaitForMenuAction)
+ {
+ if (m_MenuID == 0 || ((WaitForMenuAction)a).m_MenuID == m_MenuID)
+ return true;
+ }
+
+ return false;
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( Edit ) ),
+ this.EditTimeoutMenuItem
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void Edit(object[] args)
+ {
+ new MacroInsertWait(this).ShowDialog(Engine.MainWindow);
+ }
+ }
+
+ public class WaitForGumpAction : MacroWaitAction
+ {
+ private uint m_GumpID;
+ private bool m_Strict;
+
+ public WaitForGumpAction()
+ {
+ m_GumpID = 0;
+ m_Strict = false;
+ }
+
+ public WaitForGumpAction(uint gid)
+ {
+ m_GumpID = gid;
+ m_Strict = false;
+ }
+
+ public WaitForGumpAction(string[] args)
+ {
+ m_GumpID = Convert.ToUInt32(args[1]);
+ try
+ {
+ m_Strict = Convert.ToBoolean(args[2]);
+ }
+ catch
+ {
+ m_Strict = false;
+ }
+
+ try
+ {
+ m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[3]));
+ }
+ catch
+ {
+ }
+ }
+
+ public override bool Perform()
+ {
+ return !PerformWait();
+ }
+
+ public override bool PerformWait()
+ {
+ return !(World.Player.HasGump && (World.Player.CurrentGumpI == m_GumpID || !m_Strict || m_GumpID == 0));
+
+ //if (!World.Player.HasGump) // Does the player even have a gump?
+ // return true;
+
+ //if ((int)World.Player.CurrentGumpI != (int)m_GumpID && m_Strict)
+ // return m_GumpID > 0;
+
+ //return false;
+ }
+
+ public override string ToString()
+ {
+ if (m_GumpID == 0 || !m_Strict)
+ return Language.GetString(LocString.WaitAnyGump);
+ else
+ return Language.Format(LocString.WaitGumpA1, m_GumpID);
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_GumpID, m_Strict, m_Timeout.TotalSeconds);
+ }
+
+ public override bool CheckMatch(MacroAction a)
+ {
+ if (a is WaitForGumpAction)
+ {
+ if (m_GumpID == 0 || ((WaitForGumpAction)a).m_GumpID == m_GumpID)
+ return true;
+ }
+
+ return false;
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( Edit ) ),
+ new MacroMenuItem( LocString.Null, new MacroMenuCallback( ToggleStrict ) ),
+ this.EditTimeoutMenuItem
+ };
+ }
+
+ if (!m_Strict)
+ m_MenuItems[1].Text = String.Format("Change to \"{0}\"", Language.Format(LocString.WaitGumpA1, m_GumpID));
+ else
+ m_MenuItems[1].Text = String.Format("Change to \"{0}\"", Language.GetString(LocString.WaitAnyGump));
+ m_MenuItems[1].Enabled = m_GumpID != 0 || m_Strict;
+
+ return m_MenuItems;
+ }
+
+ private void Edit(object[] args)
+ {
+ new MacroInsertWait(this).ShowDialog(Engine.MainWindow);
+ }
+
+ private void ToggleStrict(object[] args)
+ {
+ m_Strict = !m_Strict;
+ if (m_Parent != null)
+ m_Parent.Update();
+ }
+ }
+
+ public class WaitForTargetAction : MacroWaitAction
+ {
+ public WaitForTargetAction()
+ {
+ m_Timeout = TimeSpan.FromSeconds(30.0);
+ }
+
+ public WaitForTargetAction(string[] args)
+ {
+ try
+ {
+ m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[1]));
+ }
+ catch
+ {
+ m_Timeout = TimeSpan.FromSeconds(30.0);
+ }
+ }
+
+ public override bool Perform()
+ {
+ return !PerformWait();
+ }
+
+ public override bool PerformWait()
+ {
+ return !Targeting.HasTarget;
+ }
+
+ public override string ToString()
+ {
+ return Language.GetString(LocString.WaitTarg);
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Timeout.TotalSeconds);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( Edit ) ),
+ this.EditTimeoutMenuItem
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ public override bool CheckMatch(MacroAction a)
+ {
+ return (a is WaitForTargetAction);
+ }
+
+ private void Edit(object[] args)
+ {
+ new MacroInsertWait(this).ShowDialog(Engine.MainWindow);
+ }
+ }
+
+ public class PauseAction : MacroWaitAction
+ {
+ public PauseAction(string[] args)
+ {
+ m_Timeout = TimeSpan.Parse(args[1]);
+ }
+
+ public PauseAction(int ms)
+ {
+ m_Timeout = TimeSpan.FromMilliseconds(ms);
+ }
+
+ public PauseAction(TimeSpan time)
+ {
+ m_Timeout = time;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Timeout);
+ }
+
+ public override bool Perform()
+ {
+ this.StartTime = DateTime.UtcNow;
+ return !PerformWait();
+ }
+
+ public override bool PerformWait()
+ {
+ return (StartTime + m_Timeout >= DateTime.UtcNow);
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.PauseA1, m_Timeout.TotalSeconds);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( Edit ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void Edit(object[] args)
+ {
+ new MacroInsertWait(this).ShowDialog(Engine.MainWindow);
+ }
+ }
+
+ public class WaitForStatAction : MacroWaitAction
+ {
+ private byte m_Direction;
+ private int m_Value;
+ private IfAction.IfVarType m_Stat;
+
+ public byte Op { get { return m_Direction; } }
+ public int Amount { get { return m_Value; } }
+ public IfAction.IfVarType Stat { get { return m_Stat; } }
+
+ public WaitForStatAction(string[] args)
+ {
+ m_Stat = (IfAction.IfVarType)Convert.ToInt32(args[1]);
+ m_Direction = Convert.ToByte(args[2]);
+ m_Value = Convert.ToInt32(args[3]);
+
+ try
+ {
+ m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[4]));
+ }
+ catch
+ {
+ m_Timeout = TimeSpan.FromMinutes(60.0);
+ }
+ }
+
+ public WaitForStatAction(IfAction.IfVarType stat, byte dir, int val)
+ {
+ m_Stat = stat;
+ m_Direction = dir;
+ m_Value = val;
+
+ m_Timeout = TimeSpan.FromMinutes(60.0);
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize((int)m_Stat, m_Direction, m_Value, m_Timeout.TotalSeconds);
+ }
+
+ public override bool Perform()
+ {
+ return !PerformWait();
+ }
+
+ public override bool PerformWait()
+ {
+ if (m_Direction > 0)
+ {
+ // wait for m_Stat >= m_Value
+ switch (m_Stat)
+ {
+ case IfAction.IfVarType.Hits:
+ return World.Player.Hits < m_Value;
+ case IfAction.IfVarType.Mana:
+ return World.Player.Mana < m_Value;
+ case IfAction.IfVarType.Stamina:
+ return World.Player.Stam < m_Value;
+ }
+ }
+ else
+ {
+ // wait for m_Stat <= m_Value
+ switch (m_Stat)
+ {
+ case IfAction.IfVarType.Hits:
+ return World.Player.Hits > m_Value;
+ case IfAction.IfVarType.Mana:
+ return World.Player.Mana > m_Value;
+ case IfAction.IfVarType.Stamina:
+ return World.Player.Stam > m_Value;
+ }
+ }
+
+ return false;
+ }
+
+ public override string ToString()
+ {
+ return Language.Format(LocString.WaitA3, m_Stat, m_Direction > 0 ? ">=" : "<=", m_Value);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( Edit ) ),
+ this.EditTimeoutMenuItem
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void Edit(object[] args)
+ {
+ new MacroInsertWait(this).ShowDialog(Engine.MainWindow);
+ }
+ }
+
+ public class IfAction : MacroAction
+ {
+ public enum IfVarType : int
+ {
+ Hits = 0,
+ Mana,
+ Stamina,
+ Poisoned,
+ SysMessage,
+ Weight,
+ Mounted,
+ RHandEmpty,
+ LHandEmpty,
+
+ BeginCountersMarker,
+
+ Counter = 50
+ }
+
+ private sbyte m_Direction;
+ private object m_Value;
+ private IfVarType m_Var;
+ private string m_Counter;
+ private Assistant.Counter m_CountObj;
+
+ public sbyte Op { get { return m_Direction; } }
+ public object Value { get { return m_Value; } }
+ public IfVarType Variable { get { return m_Var; } }
+ public string Counter { get { return m_Counter; } }
+
+ public IfAction(string[] args)
+ {
+ m_Var = (IfVarType)Convert.ToInt32(args[1]);
+ try
+ {
+ m_Direction = Convert.ToSByte(args[2]);
+ if (m_Direction > 1)
+ m_Direction = 0;
+ }
+ catch
+ {
+ m_Direction = -1;
+ }
+
+ if (m_Var != IfVarType.SysMessage)
+ m_Value = Convert.ToInt32(args[3]);
+ else
+ m_Value = args[3].ToLower();
+
+ if (m_Var == IfVarType.Counter)
+ m_Counter = args[4];
+ }
+
+ public IfAction(IfVarType var, sbyte dir, int val)
+ {
+ m_Var = var;
+ m_Direction = dir;
+ m_Value = val;
+ }
+
+ public IfAction(IfVarType var, sbyte dir, int val, string counter)
+ {
+ m_Var = var;
+ m_Direction = dir;
+ m_Value = val;
+ m_Counter = counter;
+ }
+
+ public IfAction(IfVarType var, string text)
+ {
+ m_Var = var;
+ m_Value = text.ToLower();
+ }
+
+ public override string Serialize()
+ {
+ if (m_Var == IfVarType.Counter && m_Counter != null)
+ return DoSerialize((int)m_Var, m_Direction, m_Value, m_Counter);
+ else
+ return DoSerialize((int)m_Var, m_Direction, m_Value);
+ }
+
+ public override bool Perform()
+ {
+ return true;
+ }
+
+ public bool Evaluate()
+ {
+ switch (m_Var)
+ {
+ case IfVarType.Hits:
+ case IfVarType.Mana:
+ case IfVarType.Stamina:
+ case IfVarType.Weight:
+ {
+ int val = (int)m_Value;
+ if (m_Direction > 0)
+ {
+ // if stat >= m_Value
+ switch (m_Var)
+ {
+ case IfVarType.Hits:
+ return World.Player.Hits >= val;
+ case IfVarType.Mana:
+ return World.Player.Mana >= val;
+ case IfVarType.Stamina:
+ return World.Player.Stam >= val;
+ case IfVarType.Weight:
+ return World.Player.Weight >= val;
+ }
+ }
+ else
+ {
+ // if stat <= m_Value
+ switch (m_Var)
+ {
+ case IfVarType.Hits:
+ return World.Player.Hits <= val;
+ case IfVarType.Mana:
+ return World.Player.Mana <= val;
+ case IfVarType.Stamina:
+ return World.Player.Stam <= val;
+ case IfVarType.Weight:
+ return World.Player.Weight <= val;
+ }
+ }
+
+ return false;
+ }
+
+ case IfVarType.Poisoned:
+ {
+ if (Windows.AllowBit(FeatureBit.BlockHealPoisoned))
+ return World.Player.Poisoned;
+ else
+ return false;
+ }
+
+ case IfVarType.SysMessage:
+ {
+ string text = (string)m_Value;
+ for (int i = PacketHandlers.SysMessages.Count - 1; i >= 0; i--)
+ {
+ string sys = PacketHandlers.SysMessages[i];
+ if (sys.IndexOf(text, StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ PacketHandlers.SysMessages.RemoveRange(0, i + 1);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ case IfVarType.Mounted:
+ {
+ return World.Player.GetItemOnLayer(Layer.Mount) != null;
+ }
+
+ case IfVarType.RHandEmpty:
+ {
+ return World.Player.GetItemOnLayer(Layer.RightHand) == null;
+ }
+
+ case IfVarType.LHandEmpty:
+ {
+ return World.Player.GetItemOnLayer(Layer.LeftHand) == null;
+ }
+
+ case IfVarType.Counter:
+ {
+ if (m_CountObj == null)
+ {
+ foreach (Assistant.Counter c in Assistant.Counter.List)
+ {
+ if (c.Name == m_Counter)
+ {
+ m_CountObj = c;
+ break;
+ }
+ }
+ }
+
+ if (m_CountObj == null || !m_CountObj.Enabled)
+ return false;
+
+ if (m_Direction > 0)
+ return m_CountObj.Amount >= (int)m_Value;
+ else
+ return m_CountObj.Amount <= (int)m_Value;
+ }
+
+ default:
+ return false;
+ }
+ }
+
+ public override string ToString()
+ {
+ switch (m_Var)
+ {
+ case IfVarType.Hits:
+ case IfVarType.Mana:
+ case IfVarType.Stamina:
+ case IfVarType.Weight:
+ return String.Format("If ( {0} {1} {2} )", m_Var, m_Direction > 0 ? ">=" : "<=", m_Value);
+ case IfVarType.Poisoned:
+ return "If ( Poisoned )";
+ case IfVarType.SysMessage:
+ {
+ string str = (string)m_Value;
+ if (str.Length > 10)
+ str = str.Substring(0, 7) + "...";
+ return String.Format("If ( SysMessage \"{0}\" )", str);
+ }
+ case IfVarType.Mounted:
+ return "If ( Mounted )";
+ case IfVarType.RHandEmpty:
+ return "If ( R-Hand Empty )";
+ case IfVarType.LHandEmpty:
+ return "If ( L-Hand Empty )";
+ case IfVarType.Counter:
+ return String.Format("If ( \"{0} count\" {1} {2} )", m_Counter, m_Direction > 0 ? ">=" : "<=", m_Value);
+ default:
+ return "If ( ??? )";
+ }
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( Edit ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void Edit(object[] args)
+ {
+ new MacroInsertIf(this).ShowDialog(Engine.MainWindow);
+ }
+ }
+
+ public class ElseAction : MacroAction
+ {
+ public ElseAction()
+ {
+ }
+
+ public override bool Perform()
+ {
+ return true;
+ }
+
+ public override string ToString()
+ {
+ return "Else";
+ }
+ }
+
+ public class EndIfAction : MacroAction
+ {
+ public EndIfAction()
+ {
+ }
+
+ public override bool Perform()
+ {
+ return true;
+ }
+
+ public override string ToString()
+ {
+ return "End If";
+ }
+ }
+
+ public class HotKeyAction : MacroAction
+ {
+ private KeyData m_Key;
+
+ public HotKeyAction(KeyData hk)
+ {
+ m_Key = hk;
+ }
+
+ public HotKeyAction(string[] args)
+ {
+ try
+ {
+ int loc = Convert.ToInt32(args[1]);
+ if (loc != 0)
+ m_Key = HotKey.Get(loc);
+ }
+ catch
+ {
+ }
+
+ if (m_Key == null)
+ m_Key = HotKey.Get(args[2]);
+
+ if (m_Key == null)
+ throw new Exception("HotKey not found.");
+ }
+
+ public override bool Perform()
+ {
+ if (Windows.AllowBit(FeatureBit.LoopingMacros) || m_Key.DispName.IndexOf(Language.GetString(LocString.PlayA1).Replace(@"{0}", "")) == -1)
+ m_Key.Callback();
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Key.LocName, m_Key.StrName == null ? "" : m_Key.StrName);
+ }
+
+ public override string ToString()
+ {
+ return String.Format("Exec: {0}", m_Key.DispName);
+ }
+ }
+
+ public class ForAction : MacroAction
+ {
+ private int m_Max, m_Count;
+
+ public int Count { get { return m_Count; } set { m_Count = value; } }
+ public int Max { get { return m_Max; } }
+
+ public ForAction(string[] args)
+ {
+ m_Max = Convert.ToInt32(args[1]);
+ }
+
+ public ForAction(int max)
+ {
+ m_Max = max;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Max);
+ }
+
+ public override bool Perform()
+ {
+ return true;
+ }
+
+ public override string ToString()
+ {
+ return String.Format("For ( 1 to {0} )", m_Max);
+ }
+
+ private MenuItem[] m_MenuItems;
+ public override MenuItem[] GetContextMenuItems()
+ {
+ if (m_MenuItems == null)
+ {
+ m_MenuItems = new MacroMenuItem[]
+ {
+ new MacroMenuItem( LocString.Edit, new MacroMenuCallback( Edit ) )
+ };
+ }
+
+ return m_MenuItems;
+ }
+
+ private void Edit(object[] args)
+ {
+ if (InputBox.Show(Language.GetString(LocString.NumIter), "Input Box", m_Max.ToString()))
+ m_Max = InputBox.GetInt(m_Max);
+ if (Parent != null)
+ Parent.Update();
+ }
+ }
+
+ public class EndForAction : MacroAction
+ {
+ public EndForAction()
+ {
+ }
+
+ public override bool Perform()
+ {
+ return true;
+ }
+
+ public override string ToString()
+ {
+ return "End For";
+ }
+ }
+
+ public class ContextMenuAction : MacroAction
+ {
+ private ushort m_CtxName;
+ private ushort m_Idx;
+ private Serial m_Entity;
+
+ public ContextMenuAction(UOEntity ent, ushort idx, ushort ctxName)
+ {
+ m_Entity = ent != null ? ent.Serial : Serial.MinusOne;
+
+ if (World.Player != null && World.Player.Serial == m_Entity)
+ m_Entity = Serial.Zero;
+
+ m_Idx = idx;
+ m_CtxName = ctxName;
+ }
+
+ public ContextMenuAction(string[] args)
+ {
+ m_Entity = Serial.Parse(args[1]);
+ m_Idx = Convert.ToUInt16(args[2]);
+ try
+ {
+ m_CtxName = Convert.ToUInt16(args[3]);
+ }
+ catch
+ {
+ }
+ }
+
+ public override bool Perform()
+ {
+ Serial s = m_Entity;
+
+ if (s == Serial.Zero && World.Player != null)
+ s = World.Player.Serial;
+
+ ClientCommunication.SendToServer(new ContextMenuRequest(s));
+ ClientCommunication.SendToServer(new ContextMenuResponse(s, m_Idx));
+ return true;
+ }
+
+ public override string Serialize()
+ {
+ return DoSerialize(m_Entity, m_Idx, m_CtxName);
+ }
+
+ public override string ToString()
+ {
+ string ent;
+
+ if (m_Entity == Serial.Zero)
+ ent = "(self)";
+ else
+ ent = m_Entity.ToString();
+ return String.Format("ContextMenu: {1} ({0})", ent, m_Idx);
+ }
+ }
+}
+
diff --git a/Core/Actions.resx b/Core/Actions.resx
new file mode 100644
index 0000000..dd0ea4d
--- /dev/null
+++ b/Core/Actions.resx
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.0.0.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
diff --git a/Core/BuffsDebuffs.cs b/Core/BuffsDebuffs.cs
new file mode 100644
index 0000000..1c099e4
--- /dev/null
+++ b/Core/BuffsDebuffs.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Assistant.Core
+{
+ public enum BuffIcon : ushort
+ {
+ DismountPrevention = 0x3E9,
+ NoRearm = 0x3EA,
+
+ //Currently, no 0x3EB or 0x3EC
+ NightSight = 0x3ED,
+
+ DeathStrike,
+ EvilOmen,
+ UnknownStandingSwirl,
+ UnknownKneelingSword,
+ DivineFury,
+ EnemyOfOne,
+ HidingAndOrStealth,
+ ActiveMeditation,
+ BloodOathCaster,
+ BloodOathCurse,
+ CorpseSkin,
+ Mindrot,
+ PainSpike,
+ Strangle,
+ GiftOfRenewal,
+ AttuneWeapon,
+ Thunderstorm,
+ EssenceOfWind,
+ EtherealVoyage,
+ GiftOfLife,
+ ArcaneEmpowerment,
+ MortalStrike,
+ ReactiveArmor,
+ Protection,
+ ArchProtection,
+ MagicReflection,
+ Incognito,
+ Disguised, //*
+ AnimalForm,
+ Polymorph,
+ Invisibility,
+ Paralyze,
+ Poison,
+ Bleed,
+ Clumsy,
+ FeebleMind,
+ Weaken,
+ Curse,
+ MassCurse,
+ Agility,
+ Cunning,
+ Strength,
+ Bless,
+ Sleep = 1049,
+ StoneForm = 1050,
+ SpellPlague = 1051,
+ GargoyleBerserk = 1052,
+ GargoyleFly = 1054,
+ Inspire = 1055,
+ Invigorate = 1056,
+ Resilience = 1057,
+ Perseverance = 1058,
+ TribulationTarget = 1059,
+ DespairTarget = 1060,
+ ArcaneEmpowermentNew = 1061,
+ MagicFish = 1062,
+ HitLowerAttack = 1063,
+ HitLowerDefense = 1064,
+ HitDualwield = 1065,
+ Block = 1066,
+ DefenseMastery = 1067,
+ Despair = 1068,
+ HealingSkill = 1069,
+ SpellFocusing = 1070,
+ SpellFocusingTarget = 1071,
+ RageFocusingTarget = 1072,
+ RageFocusing = 1073,
+ Warding = 1074,
+ Tribulation = 1075,
+ ForceArrow = 1076,
+ DisarmNew = 1077,
+ Surge = 1078,
+ Feint = 1079,
+ TalonStrike = 1080,
+ PsychicAttack = 1081,
+ ConsecrateWeapon = 1082,
+ EnemyOfOneNew = 1084,
+ HorrificBeast = 1085,
+ LichForm = 1086,
+ VampiricEmbrace = 1087,
+ CurseWeapon = 1088,
+ ReaperForm = 1089,
+ ImmolatingWeapon = 1090,
+ Enchant = 1091,
+ HonorableExecution = 1092,
+ Confidence = 1093,
+ Evasion = 1094,
+ CounterAttack = 1095,
+ LightningStrike = 1096,
+ MomentumStrike = 1097,
+ OrangePetals = 1098,
+ RoseOfTrinsic = 1099,
+ PoisonResistanceImmunity = 1100,
+ Veterinary = 1101,
+ Perfection = 1102,
+ Honored = 1103,
+ ManaPhase = 1104,
+ FanDancerFanFire = 1105,
+ Rage = 1106,
+ Webbing = 1107,
+ MedusaStone = 1108,
+ DragonSlasherFear = 1109,
+ AuraOfNausea = 1110,
+ HowlOfCacophony = 1111,
+ GazeDespair = 1112,
+ HiryuPhysicalResistance = 1113,
+ RuneBeetleCorruption = 1114,
+ BloodwormAnemia = 1115,
+ RotwormBloodDisease = 1116,
+ SkillUseDelay = 1117,
+ FactionLoss = 1118,
+ HeatOfBattleStatus = 1119,
+ CriminalStatus = 1120,
+ ArmorPierce = 1121,
+ SplinteringEffect = 1122,
+ SwingSpeed = 1123,
+ WraithForm = 1124,
+ CityTradeDeal = 1126
+ }
+
+ public class BuffsDebuffs
+ {
+ public int IconNumber { get; set; }
+ public int Duration { get; set; }
+ public string ClilocMessage1 { get; set; }
+ public string ClilocMessage2 { get; set; }
+ public BuffIcon BuffIcon { get; set; }
+ public DateTime Timestamp { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Core/BuffsTimer.cs b/Core/BuffsTimer.cs
new file mode 100644
index 0000000..a6feffd
--- /dev/null
+++ b/Core/BuffsTimer.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Assistant
+{
+ public class BuffsTimer
+ {
+ //private static int m_Count;
+ private static Timer m_Timer;
+
+
+ static BuffsTimer()
+ {
+ }
+
+ /*public static int Count
+ {
+ get
+ {
+ return m_Count;
+ }
+ }*/
+
+ public static bool Running
+ {
+ get
+ {
+ return m_Timer.Running;
+ }
+ }
+
+ public static void Start()
+ {
+
+
+ }
+
+ public static void Stop()
+ {
+
+ }
+
+
+ }
+}
diff --git a/Core/Config.cs b/Core/Config.cs
new file mode 100644
index 0000000..91f1df6
--- /dev/null
+++ b/Core/Config.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Assistant
+{
+ internal class Config
+ {
+ internal static bool GetBool( string v )
+ {
+ switch ( v )
+ {
+ default:
+ return true;
+ case "QueueActions":
+ return false;
+ }
+ }
+
+ internal static int GetInt( string v )
+ {
+ return 0;
+ }
+
+ internal static string GetString( string v )
+ {
+ return "DEBUG";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/ContainerLabels.cs b/Core/ContainerLabels.cs
new file mode 100644
index 0000000..3ceeeb4
--- /dev/null
+++ b/Core/ContainerLabels.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml;
+
+namespace Assistant.Core
+{
+ public class ContainerLabels
+ {
+ public class ContainerLabel
+ {
+ public string Id { get; set; }
+ public string Type { get; set; }
+ public string Label { get; set; }
+ public int Hue { get; set; }
+ public string Alias { get; set; }
+ }
+
+ public static Serial LastContainerLabelDisplayed;
+
+ public static List ContainerLabelList = new List();
+
+ public static void Save(XmlTextWriter xml)
+ {
+ foreach (var label in ContainerLabelList)
+ {
+ xml.WriteStartElement("containerlabel");
+ xml.WriteAttributeString("id", label.Id);
+ xml.WriteAttributeString("type", label.Type);
+ xml.WriteAttributeString("label", label.Label);
+ xml.WriteAttributeString("hue", label.Hue.ToString());
+ xml.WriteAttributeString("alias", label.Alias);
+ xml.WriteEndElement();
+ }
+ }
+
+ public static void Load(XmlElement node)
+ {
+ ClearAll();
+
+ try
+ {
+
+ foreach (XmlElement el in node.GetElementsByTagName("containerlabel"))
+ {
+ ContainerLabel label = new ContainerLabel
+ {
+ Id = el.GetAttribute("id"),
+ Type = el.GetAttribute("type"),
+ Label = el.GetAttribute("label"),
+ Hue = Convert.ToInt32(el.GetAttribute("hue")),
+ Alias = el.GetAttribute("alias")
+ };
+
+ ContainerLabelList.Add(label);
+ }
+ }
+ catch
+ {
+ }
+ }
+
+ public static void ClearAll()
+ {
+ ContainerLabelList.Clear();
+ }
+ }
+}
diff --git a/Core/Geometry.cs b/Core/Geometry.cs
new file mode 100644
index 0000000..24f952d
--- /dev/null
+++ b/Core/Geometry.cs
@@ -0,0 +1,570 @@
+using System;
+
+namespace Assistant
+{
+ public interface IPoint2D
+ {
+ int X{ get; }
+ int Y{ get; }
+ }
+
+ public interface IPoint3D : IPoint2D
+ {
+ int Z{ get; }
+ }
+
+ public struct Point2D : IPoint2D
+ {
+ internal int m_X;
+ internal int m_Y;
+
+ public static readonly Point2D Zero = new Point2D( 0, 0 );
+ public static readonly Point2D MinusOne = new Point2D( -1, -1 );
+
+ public Point2D( int x, int y )
+ {
+ m_X = x;
+ m_Y = y;
+ }
+
+ public Point2D( IPoint2D p ) : this( p.X, p.Y )
+ {
+ }
+
+ public int X
+ {
+ get
+ {
+ return m_X;
+ }
+ set
+ {
+ m_X = value;
+ }
+ }
+
+ public int Y
+ {
+ get
+ {
+ return m_Y;
+ }
+ set
+ {
+ m_Y = value;
+ }
+ }
+
+ public override string ToString()
+ {
+ return String.Format( "({0}, {1})", m_X, m_Y );
+ }
+
+ public override bool Equals( object o )
+ {
+ if ( o == null || !(o is IPoint2D) ) return false;
+
+ IPoint2D p = (IPoint2D)o;
+
+ return m_X == p.X && m_Y == p.Y;
+ }
+
+ public override int GetHashCode()
+ {
+ return m_X ^ m_Y;
+ }
+
+ public static bool operator == ( Point2D l, Point2D r )
+ {
+ return l.m_X == r.m_X && l.m_Y == r.m_Y;
+ }
+
+ public static bool operator != ( Point2D l, Point2D r )
+ {
+ return l.m_X != r.m_X || l.m_Y != r.m_Y;
+ }
+
+ public static bool operator == ( Point2D l, IPoint2D r )
+ {
+ return l.m_X == r.X && l.m_Y == r.Y;
+ }
+
+ public static bool operator != ( Point2D l, IPoint2D r )
+ {
+ return l.m_X !=r.X || l.m_Y != r.Y;
+ }
+
+ public static bool operator > ( Point2D l, Point2D r )
+ {
+ return l.m_X > r.m_X && l.m_Y > r.m_Y;
+ }
+
+ public static bool operator > ( Point2D l, Point3D r )
+ {
+ return l.m_X > r.m_X && l.m_Y > r.m_Y;
+ }
+
+ public static bool operator > ( Point2D l, IPoint2D r )
+ {
+ return l.m_X > r.X && l.m_Y > r.Y;
+ }
+
+ public static bool operator < ( Point2D l, Point2D r )
+ {
+ return l.m_X < r.m_X && l.m_Y < r.m_Y;
+ }
+
+ public static bool operator < ( Point2D l, Point3D r )
+ {
+ return l.m_X < r.m_X && l.m_Y < r.m_Y;
+ }
+
+ public static bool operator < ( Point2D l, IPoint2D r )
+ {
+ return l.m_X < r.X && l.m_Y < r.Y;
+ }
+
+ public static bool operator >= ( Point2D l, Point2D r )
+ {
+ return l.m_X >= r.m_X && l.m_Y >= r.m_Y;
+ }
+
+ public static bool operator >= ( Point2D l, Point3D r )
+ {
+ return l.m_X >= r.m_X && l.m_Y >= r.m_Y;
+ }
+
+ public static bool operator >= ( Point2D l, IPoint2D r )
+ {
+ return l.m_X >= r.X && l.m_Y >= r.Y;
+ }
+
+ public static bool operator <= ( Point2D l, Point2D r )
+ {
+ return l.m_X <= r.m_X && l.m_Y <= r.m_Y;
+ }
+
+ public static bool operator <= ( Point2D l, Point3D r )
+ {
+ return l.m_X <= r.m_X && l.m_Y <= r.m_Y;
+ }
+
+ public static bool operator <= ( Point2D l, IPoint2D r )
+ {
+ return l.m_X <= r.X && l.m_Y <= r.Y;
+ }
+ }
+
+ public struct Point3D : IPoint3D
+ {
+ internal int m_X;
+ internal int m_Y;
+ internal int m_Z;
+
+ public static readonly Point3D Zero = new Point3D( 0, 0, 0 );
+ public static readonly Point3D MinusOne = new Point3D( -1, -1, 0 );
+
+ public Point3D( int x, int y, int z )
+ {
+ m_X = x;
+ m_Y = y;
+ m_Z = z;
+ }
+
+ public Point3D( IPoint3D p ) : this( p.X, p.Y, p.Z )
+ {
+ }
+
+ public Point3D( IPoint2D p, int z ) : this( p.X, p.Y, z )
+ {
+ }
+
+ public int X
+ {
+ get
+ {
+ return m_X;
+ }
+ set
+ {
+ m_X = value;
+ }
+ }
+
+ public int Y
+ {
+ get
+ {
+ return m_Y;
+ }
+ set
+ {
+ m_Y = value;
+ }
+ }
+
+ public int Z
+ {
+ get
+ {
+ return m_Z;
+ }
+ set
+ {
+ m_Z = value;
+ }
+ }
+
+ public override string ToString()
+ {
+ return String.Format( "({0}, {1}, {2})", m_X, m_Y, m_Z );
+ }
+
+ public override bool Equals( object o )
+ {
+ if ( o == null || !(o is IPoint3D) ) return false;
+
+ IPoint3D p = (IPoint3D)o;
+
+ return m_X == p.X && m_Y == p.Y && m_Z == p.Z;
+ }
+
+ public override int GetHashCode()
+ {
+ return m_X ^ m_Y ^ m_Z;
+ }
+
+ public static Point3D Parse( string value )
+ {
+ int start = value.IndexOf( '(' );
+ int end = value.IndexOf( ',', start + 1 );
+
+ string param1 = value.Substring( start + 1, end - (start + 1) ).Trim();
+
+ start = end;
+ end = value.IndexOf( ',', start + 1 );
+
+ string param2 = value.Substring( start + 1, end - (start + 1) ).Trim();
+
+ start = end;
+ end = value.IndexOf( ')', start + 1 );
+
+ string param3 = value.Substring( start + 1, end - (start + 1) ).Trim();
+
+ return new Point3D( Convert.ToInt32( param1 ), Convert.ToInt32( param2 ), Convert.ToInt16( param3 ) );
+ }
+
+ public static bool operator == ( Point3D l, Point3D r )
+ {
+ return l.m_X == r.m_X && l.m_Y == r.m_Y && l.m_Z == r.m_Z;
+ }
+
+ public static bool operator != ( Point3D l, Point3D r )
+ {
+ return l.m_X != r.m_X || l.m_Y != r.m_Y || l.m_Z != r.m_Z;
+ }
+
+ public static bool operator == ( Point3D l, IPoint3D r )
+ {
+ return l.m_X == r.X && l.m_Y == r.Y && l.m_Z == r.Z;
+ }
+
+ public static bool operator != ( Point3D l, IPoint3D r )
+ {
+ return l.m_X != r.X || l.m_Y != r.Y || l.m_Z != r.Z;
+ }
+
+ public static Point3D operator + ( Point3D l, Point3D r )
+ {
+ return new Point3D( l.m_X+r.m_X, l.m_Y+r.m_Y, l.m_Z+r.m_Z );
+ }
+
+ public static Point3D operator - ( Point3D l, Point3D r )
+ {
+ return new Point3D( l.m_X-r.m_X, l.m_Y-r.m_Y, l.m_Z-r.m_Z );
+ }
+ }
+
+ public struct Line2D
+ {
+ private Point2D m_Start, m_End;
+
+ public Line2D( IPoint2D start, IPoint2D end )
+ {
+ m_Start = new Point2D( start );
+ m_End = new Point2D( end );
+ Fix();
+ }
+
+ public void Fix()
+ {
+ if ( m_Start > m_End )
+ {
+ Point2D temp = m_Start;
+ m_Start = m_End;
+ m_End = temp;
+ }
+ }
+
+ public Point2D Start
+ {
+ get
+ {
+ return m_Start;
+ }
+ set
+ {
+ m_Start = value;
+ Fix();
+ }
+ }
+
+ public Point2D End
+ {
+ get
+ {
+ return m_End;
+ }
+ set
+ {
+ m_End = value;
+ Fix();
+ }
+ }
+
+ public double Length
+ {
+ get
+ {
+ int run = m_End.X - m_Start.X;
+ int rise = m_End.Y - m_Start.Y;
+
+ return Math.Sqrt( run * run + rise * rise );
+ }
+ }
+
+ public override string ToString()
+ {
+ return String.Format( "--{0}->{1}--", m_Start, m_End );
+ }
+
+ public override bool Equals( object o )
+ {
+ if ( o == null || !(o is Line2D) ) return false;
+
+ Line2D ln = (Line2D)o;
+
+ return m_Start == ln.m_Start && m_End == ln.m_End;
+ }
+
+ public override int GetHashCode()
+ {
+ return m_Start.GetHashCode() ^ (~m_End.GetHashCode());
+ }
+
+ public static bool operator == ( Line2D l, Line2D r )
+ {
+ return l.m_Start == r.m_Start && l.m_End == r.m_End;
+ }
+
+ public static bool operator != ( Line2D l, Line2D r )
+ {
+ return l.m_Start != r.m_Start || l.m_End != r.m_End;
+ }
+
+ public static bool operator > ( Line2D l, Line2D r )
+ {
+ return l.m_Start > r.m_Start && l.m_End > r.m_End;
+ }
+
+ public static bool operator < ( Line2D l, Line2D r )
+ {
+ return l.m_Start < r.m_Start && l.m_End < r.m_End;
+ }
+
+ public static bool operator >= ( Line2D l, Line2D r )
+ {
+ return l.m_Start >= r.m_Start && l.m_End >= r.m_End;
+ }
+
+ public static bool operator <= ( Line2D l, Line2D r )
+ {
+ return l.m_Start <= r.m_Start && l.m_End <= r.m_End;
+ }
+ }
+
+ public struct Rectangle2D
+ {
+ private Point2D m_Start;
+ private Point2D m_End;
+
+ public Rectangle2D( IPoint2D start, IPoint2D end )
+ {
+ m_Start = new Point2D( start );
+ m_End = new Point2D( end );
+ }
+
+ public Rectangle2D( int x, int y, int width, int height )
+ {
+ m_Start = new Point2D( x, y );
+ m_End = new Point2D( x + width, y + height );
+ }
+
+ public void Set( int x, int y, int width, int height )
+ {
+ m_Start = new Point2D( x, y );
+ m_End = new Point2D( x + width, y + height );
+ }
+
+ public static Rectangle2D Parse( string value )
+ {
+ int start = value.IndexOf( '(' );
+ int end = value.IndexOf( ',', start + 1 );
+
+ string param1 = value.Substring( start + 1, end - (start + 1) ).Trim();
+
+ start = end;
+ end = value.IndexOf( ',', start + 1 );
+
+ string param2 = value.Substring( start + 1, end - (start + 1) ).Trim();
+
+ start = end;
+ end = value.IndexOf( ',', start + 1 );
+
+ string param3 = value.Substring( start + 1, end - (start + 1) ).Trim();
+
+ start = end;
+ end = value.IndexOf( ')', start + 1 );
+
+ string param4 = value.Substring( start + 1, end - (start + 1) ).Trim();
+
+ return new Rectangle2D( Convert.ToInt32( param1 ), Convert.ToInt32( param2 ), Convert.ToInt32( param3 ), Convert.ToInt32( param4 ) );
+ }
+
+ public Point2D Start
+ {
+ get
+ {
+ return m_Start;
+ }
+ set
+ {
+ m_Start = value;
+ }
+ }
+
+ public Point2D End
+ {
+ get
+ {
+ return m_End;
+ }
+ set
+ {
+ m_End = value;
+ }
+ }
+
+ public int X
+ {
+ get
+ {
+ return m_Start.m_X;
+ }
+ set
+ {
+ m_Start.m_X = value;
+ }
+ }
+
+ public int Y
+ {
+ get
+ {
+ return m_Start.m_Y;
+ }
+ set
+ {
+ m_Start.m_Y = value;
+ }
+ }
+
+ public int Width
+ {
+ get
+ {
+ return m_End.m_X - m_Start.m_X;
+ }
+ set
+ {
+ m_End.m_X = m_Start.m_X + value;
+ }
+ }
+
+ public int Height
+ {
+ get
+ {
+ return m_End.m_Y - m_Start.m_Y;
+ }
+ set
+ {
+ m_End.m_Y = m_Start.m_Y + value;
+ }
+ }
+
+ public void MakeHold( Rectangle2D r )
+ {
+ if ( r.m_Start.m_X < m_Start.m_X )
+ m_Start.m_X = r.m_Start.m_X;
+
+ if ( r.m_Start.m_Y < m_Start.m_Y )
+ m_Start.m_Y = r.m_Start.m_Y;
+
+ if ( r.m_End.m_X > m_End.m_X )
+ m_End.m_X = r.m_End.m_X;
+
+ if ( r.m_End.m_Y > m_End.m_Y )
+ m_End.m_Y = r.m_End.m_Y;
+ }
+
+ // "test" must be smaller than this rectangle!
+ public bool Insersects( Rectangle2D test )
+ {
+ Point2D e1 = new Point2D( test.Start.X + test.Width, test.Start.Y );
+ Point2D e2 = new Point2D( test.Start.X, test.Start.Y + test.Width );
+
+ return Contains( test.Start ) || Contains( test.End ) || Contains( e1 ) || Contains( e2 );
+ }
+
+ public bool Contains( Rectangle2D test )
+ {
+ Point2D e1 = new Point2D( test.Start.X + test.Width, test.Start.Y );
+ Point2D e2 = new Point2D( test.Start.X, test.Start.Y + test.Width );
+
+ return Contains( test.Start ) && Contains( test.End ) && Contains( e1 ) && Contains( e2 );
+ }
+
+ public bool Contains( Point3D p )
+ {
+ return ( m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y );
+ //return ( m_Start <= p && m_End > p );
+ }
+
+ public bool Contains( Point2D p )
+ {
+ return ( m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y );
+ //return ( m_Start <= p && m_End > p );
+ }
+
+ public bool Contains( IPoint2D p )
+ {
+ return ( m_Start <= p && m_End > p );
+ }
+
+ public override string ToString()
+ {
+ return String.Format( "({0}, {1})+({2}, {3})", X, Y, Width, Height );
+ }
+ }
+}
diff --git a/Core/Item.cs b/Core/Item.cs
new file mode 100644
index 0000000..5d95bb4
--- /dev/null
+++ b/Core/Item.cs
@@ -0,0 +1,817 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Assistant
+{
+ public enum Layer : byte
+ {
+ Invalid = 0x00,
+
+ FirstValid = 0x01,
+
+ RightHand = 0x01,
+ LeftHand = 0x02,
+ Shoes = 0x03,
+ Pants = 0x04,
+ Shirt = 0x05,
+ Head = 0x06,
+ Gloves = 0x07,
+ Ring = 0x08,
+ Unused_x9 = 0x09,
+ Neck = 0x0A,
+ Hair = 0x0B,
+ Waist = 0x0C,
+ InnerTorso = 0x0D,
+ Bracelet = 0x0E,
+ Unused_xF = 0x0F,
+ FacialHair = 0x10,
+ MiddleTorso = 0x11,
+ Earrings = 0x12,
+ Arms = 0x13,
+ Cloak = 0x14,
+ Backpack = 0x15,
+ OuterTorso = 0x16,
+ OuterLegs = 0x17,
+ InnerLegs = 0x18,
+
+ LastUserValid= 0x18,
+
+ Mount = 0x19,
+ ShopBuy = 0x1A,
+ ShopResale = 0x1B,
+ ShopSell = 0x1C,
+ Bank = 0x1D,
+
+ LastValid = 0x1D
+ }
+
+ public class Item : UOEntity, IUOEntity
+ {
+
+ private ItemID m_ItemID;
+ private ushort m_Amount;
+ private byte m_Direction;
+
+ private bool m_Visible;
+ private bool m_Movable;
+
+ private Layer m_Layer;
+ private string m_Name;
+ private object m_Parent;
+
+ public IUOEntity Parent { get { return ( IUOEntity)m_Parent; } set { m_Parent = value; } }
+
+ private int m_Price;
+ private string m_BuyDesc;
+ private List- m_Items;
+
+ private bool m_IsNew;
+ private bool m_AutoStack;
+
+ private byte[] m_HousePacket;
+ private int m_HouseRev;
+
+ 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 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
- ();
+
+ m_Visible = true;
+ m_Movable = true;
+
+ }
+
+ public ItemID ItemID
+ {
+ get{ return m_ItemID; }
+ set{ m_ItemID = value; }
+ }
+
+ public ushort Amount
+ {
+ get{ return m_Amount; }
+ set{ m_Amount = value; }
+ }
+
+ public byte Direction
+ {
+ get{ return m_Direction; }
+ set{ m_Direction = value; }
+ }
+
+ public bool Visible
+ {
+ get{ return m_Visible; }
+ set{ m_Visible = value; }
+ }
+
+ public bool Movable
+ {
+ get{ return m_Movable; }
+ set{ m_Movable = value; }
+ }
+
+ public string Name
+ {
+ get
+ {
+ if ( !string.IsNullOrEmpty(m_Name) )
+ {
+ return m_Name;
+ }
+ else
+ {
+ return m_ItemID.ToString();
+ }
+ }
+ set
+ {
+ if ( value != null )
+ m_Name = value.Trim();
+ else
+ m_Name = null;
+ }
+ }
+
+ public string DisplayName
+ {
+ get
+ {
+ return Ultima.TileData.ItemTable[m_ItemID.Value].Name;
+ }
+ }
+
+ public Layer Layer
+ {
+ get
+ {
+ if ( ( m_Layer < Layer.FirstValid || m_Layer > Layer.LastValid ) &&
+ ( (this.ItemID.ItemData.Flags&Ultima.TileFlag.Wearable) != 0 ||
+ (this.ItemID.ItemData.Flags&Ultima.TileFlag.Armor) != 0 ||
+ (this.ItemID.ItemData.Flags&Ultima.TileFlag.Weapon) != 0
+ ) )
+ {
+ m_Layer = (Layer)this.ItemID.ItemData.Quality;
+ }
+ return m_Layer;
+ }
+ set
+ {
+ m_Layer = value;
+ }
+ }
+
+ public Item FindItemByID( ItemID id )
+ {
+ return FindItemByID( id, true );
+ }
+
+ public Item FindItemByID( ItemID id, bool recurse )
+ {
+ for (int i=0;i ( Container as UOEntity )?.Serial.Value ?? 0;
+
+ public object Container
+ {
+ get
+ {
+ if ( m_Parent is Serial && UpdateContainer() )
+ m_NeedContUpdate.Remove( this );
+ return m_Parent;
+ }
+ set
+ {
+ if ( ( m_Parent != null && m_Parent.Equals( value ) )
+ || ( value is Serial && m_Parent is UOEntity && ((UOEntity)m_Parent).Serial == (Serial)value )
+ || ( m_Parent is Serial && value is UOEntity && ((UOEntity)value).Serial == (Serial)m_Parent ) )
+ {
+ return;
+ }
+
+ if ( m_Parent is Mobile )
+ ((Mobile)m_Parent).RemoveItem( this );
+ else if ( m_Parent is Item )
+ ((Item)m_Parent).RemoveItem( this );
+
+
+
+ if ( value is Mobile )
+ m_Parent = ((Mobile)value).Serial;
+ else if ( value is Item )
+ m_Parent = ((Item)value).Serial;
+ else
+ m_Parent = value;
+
+ if ( !UpdateContainer() && m_NeedContUpdate != null )
+ m_NeedContUpdate.Add( this );
+ }
+ }
+
+ public bool UpdateContainer()
+ {
+ if ( !(m_Parent is Serial) || Deleted )
+ return true;
+
+ object o = null;
+ Serial contSer = (Serial)m_Parent;
+ if ( contSer.IsItem )
+ o = World.FindItem( contSer );
+ else if ( contSer.IsMobile )
+ o = World.FindMobile( contSer );
+
+ if ( o == null )
+ return false;
+
+ m_Parent = o;
+
+ if ( m_Parent is Item )
+ ((Item)m_Parent).AddItem( this );
+ else if ( m_Parent is Mobile )
+ ((Mobile)m_Parent).AddItem( this );
+
+ if (World.Player != null && (IsChildOf(World.Player.Backpack) || IsChildOf(World.Player.Quiver)))
+ {
+
+
+ if ( m_IsNew )
+ {
+ if ( m_AutoStack )
+ AutoStackResource();
+
+ if ( IsContainer && ( !IsPouch || !Config.GetBool( "NoSearchPouches" ) ) && Config.GetBool( "AutoSearch" ) )
+ {
+ PacketHandlers.IgnoreGumps.Add( this );
+ PlayerData.DoubleClick( this );
+
+ for (int c=0;c m_NeedContUpdate = new List
- ();
+ public static void UpdateContainers()
+ {
+ int i = 0;
+ while ( i < m_NeedContUpdate.Count )
+ {
+ if ( ((Item)m_NeedContUpdate[i]).UpdateContainer() )
+ m_NeedContUpdate.RemoveAt( i );
+ else
+ i++;
+ }
+ }
+
+ private static List m_AutoStackCache = new List();
+ public void AutoStackResource()
+ {
+ if ( !IsResource || !Config.GetBool( "AutoStack" ) || m_AutoStackCache.Contains( Serial ) )
+ return;
+
+ foreach ( Item check in World.Items.Values )
+ {
+ if ( check.Container == null && check.ItemID == ItemID && check.Hue == Hue && Utility.InRange( World.Player.Position, check.Position, 2 ) )
+ {
+ DragDropManager.DragDrop( this, check );
+ m_AutoStackCache.Add( Serial );
+ return;
+ }
+ }
+
+ DragDropManager.DragDrop( this, World.Player.Position );
+ m_AutoStackCache.Add( Serial );
+ }
+
+ public object RootContainer
+ {
+ get
+ {
+ int die = 100;
+ object cont = this.Container;
+ while ( cont != null && cont is Item && die-- > 0 )
+ cont = ((Item)cont).Container;
+
+ return cont;
+ }
+ }
+
+ public bool IsChildOf( object parent )
+ {
+ Serial parentSerial = 0;
+ if ( parent is Mobile )
+ return parent == RootContainer;
+ else if ( parent is Item )
+ parentSerial = ((Item)parent).Serial;
+ else
+ return false;
+
+ object check = this;
+ int die = 100;
+ while ( check != null && check is Item && die-- > 0 )
+ {
+ if ( ((Item)check).Serial == parentSerial )
+ return true;
+ else
+ check = ((Item)check).Container;
+ }
+
+ return false;
+ }
+
+ public Point3D GetWorldPosition()
+ {
+ int die = 100;
+ object root = this.Container;
+ while ( root != null && root is Item && ((Item)root).Container != null && die-- > 0 )
+ root = ((Item)root).Container;
+
+ if ( root is Item )
+ return ((Item)root).Position;
+ else if ( root is Mobile )
+ return ((Mobile)root).Position;
+ else
+ return this.Position;
+ }
+
+ private void AddItem( Item item )
+ {
+ for (int i=0;i y ? x : y;
+ }
+
+ public void ProcessPacketFlags( byte flags )
+ {
+ m_Visible = ( (flags&0x80) == 0 );
+ m_Movable = ( (flags&0x20) != 0 );
+ }
+
+ private Timer m_RemoveTimer = null;
+
+ public void RemoveRequest()
+ {
+ if ( m_RemoveTimer == null )
+ m_RemoveTimer = Timer.DelayedCallback( TimeSpan.FromSeconds( 0.25 ), new TimerCallback( Remove ) );
+ else if ( m_RemoveTimer.Running )
+ m_RemoveTimer.Stop();
+
+ m_RemoveTimer.Start();
+ }
+
+ public bool CancelRemove()
+ {
+ if ( m_RemoveTimer != null && m_RemoveTimer.Running )
+ {
+ m_RemoveTimer.Stop();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ public void ClearContents()
+ {
+ List
- rem = new List
- ( m_Items );
+ m_Items.Clear();
+ for ( int i = 0; i < rem.Count; i++ )
+ ( rem[i] ).Remove();
+ }
+
+ public override void Remove()
+ {
+ /*if ( IsMulti )
+ UOAssist.PostRemoveMulti( this );*/
+
+ List
- rem = new List
- ( m_Items );
+ m_Items.Clear();
+ for (int i=0;i Contains{ get{ return m_Items; } }
+
+ // possibly 4 bit x/y - 16x16?
+ public byte GridNum
+ {
+ get { return m_GridNum; }
+ set { m_GridNum = value; }
+ }
+
+ public bool OnGround{ get{ return Container == null; } }
+ public bool IsContainer
+ {
+ get
+ {
+ ushort iid = m_ItemID.Value;
+ return ( m_Items.Count > 0 && !IsCorpse ) || ( iid >= 0x9A8 && iid <= 0x9AC ) || ( iid >= 0x9B0 && iid <= 0x9B2 ) ||
+ ( iid >= 0xA2C && iid <= 0xA53 ) || ( iid >= 0xA97 && iid <= 0xA9E ) || ( iid >= 0xE3C && iid <= 0xE43 ) ||
+ ( iid >= 0xE75 && iid <= 0xE80 && iid != 0xE7B ) || iid == 0x1E80 || iid == 0x1E81 || iid == 0x232A || iid == 0x232B ||
+ iid == 0x2B02 || iid == 0x2B03 || iid == 0x2FB7 || iid == 0x3171 ;
+ }
+ }
+
+ public bool IsBagOfSending
+ {
+ get
+ {
+ return Hue >= 0x0400 && m_ItemID.Value == 0xE76;
+ }
+ }
+
+ public bool IsInBank
+ {
+ get
+ {
+ if ( m_Parent is Item )
+ return ((Item)m_Parent).IsInBank;
+ else if ( m_Parent is Mobile )
+ return this.Layer == Layer.Bank;
+ else
+ return false;
+ }
+ }
+
+ public bool IsNew
+ {
+ get{ return m_IsNew; }
+ set{ m_IsNew = value; }
+ }
+
+ public bool AutoStack
+ {
+ get{ return m_AutoStack; }
+ set{ m_AutoStack = value; }
+ }
+
+ public bool IsMulti
+ {
+ get { return m_ItemID.Value >= 0x4000; }
+ }
+
+ public bool IsPouch
+ {
+ get { return m_ItemID.Value == 0x0E79; }
+ }
+
+ public bool IsCorpse
+ {
+ get { return m_ItemID.Value == 0x2006 || ( m_ItemID.Value >= 0x0ECA && m_ItemID.Value <= 0x0ED2 ); }
+ }
+
+ public bool IsDoor
+ {
+ get
+ {
+ ushort iid = m_ItemID.Value;
+ return( iid >= 0x0675 && iid <= 0x06F6 ) || ( iid >= 0x0821 && iid <= 0x0875 ) || ( iid >= 0x1FED && iid <= 0x1FFC ) ||
+ ( iid >= 0x241F && iid <= 0x2424 ) || ( iid >= 0x2A05 && iid <= 0x2A1C );
+ }
+ }
+
+ public bool IsResource
+ {
+ get
+ {
+ ushort iid = m_ItemID.Value;
+ return ( iid >= 0x19B7 && iid <= 0x19BA ) || // ore
+ ( iid >= 0x09CC && iid <= 0x09CF ) || // fishes
+ ( iid >= 0x1BDD && iid <= 0x1BE2 ) || // logs
+ iid == 0x1779 || // granite / stone
+ iid == 0x11EA || iid == 0x11EB // sand
+ ;
+ }
+ }
+
+ public bool IsPotion
+ {
+ get
+ {
+ return ( m_ItemID.Value >= 0x0F06 && m_ItemID.Value <= 0x0F0D ) ||
+ m_ItemID.Value == 0x2790 || m_ItemID.Value == 0x27DB; // Ninja belt (works like a potion)
+ }
+ }
+
+ public bool IsVirtueShield
+ {
+ get
+ {
+ ushort iid = m_ItemID.Value;
+ return ( iid >= 0x1bc3 && iid <= 0x1bc5 ) ; // virtue shields
+ }
+ }
+
+ public bool IsTwoHanded
+ {
+ get
+ {
+ ushort iid = m_ItemID.Value;
+ return (
+ // everything in layer 2 except shields is 2handed
+ Layer == Layer.LeftHand &&
+ !( ( iid >= 0x1b72 && iid <= 0x1b7b ) || IsVirtueShield ) // shields
+ ) ||
+
+ // and all of these layer 1 weapons:
+ ( iid == 0x13fc || iid == 0x13fd ) || // hxbow
+ ( iid == 0x13AF || iid == 0x13b2 ) || // war axe & bow
+ ( iid >= 0x0F43 && iid <= 0x0F50 ) || // axes & xbow
+ ( iid == 0x1438 || iid == 0x1439 ) || // war hammer
+ ( iid == 0x1442 || iid == 0x1443 ) || // 2handed axe
+ ( iid == 0x1402 || iid == 0x1403 ) || // short spear
+ ( iid == 0x26c1 || iid == 0x26cb ) || // aos gay blade
+ ( iid == 0x26c2 || iid == 0x26cc ) || // aos gay bow
+ ( iid == 0x26c3 || iid == 0x26cd ) // aos gay xbow
+ ;
+ }
+ }
+
+ public override string ToString()
+ {
+ return String.Format( "{0} ({1})", this.Name, this.Serial );
+ }
+
+ public int Price
+ {
+ get { return m_Price; }
+ set { m_Price = value; }
+ }
+
+ public string BuyDesc
+ {
+ get { return m_BuyDesc; }
+ set { m_BuyDesc = value; }
+ }
+
+ public int HouseRevision
+ {
+ get { return m_HouseRev; }
+ set { m_HouseRev = value; }
+ }
+
+ public byte[] HousePacket
+ {
+ get { return m_HousePacket; }
+ set { m_HousePacket = value; }
+ }
+
+ public ushort GraphicID => ItemID;
+
+ 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(String.Format("Desktop/{0}/{1}/{2}/Multicache.dat", World.AccountName, World.ShardName, World.OrigPlayerName));
+ 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 );
+ }
+ }
+ }
+}
diff --git a/Core/ItemID.cs b/Core/ItemID.cs
new file mode 100644
index 0000000..9b855bf
--- /dev/null
+++ b/Core/ItemID.cs
@@ -0,0 +1,100 @@
+using System;
+
+namespace Assistant
+{
+ public struct ItemID
+ {
+ private ushort m_ID;
+
+ public ItemID( ushort id )
+ {
+ m_ID = id;
+ }
+
+ public ushort Value
+ {
+ get
+ {
+ return m_ID;
+ }
+ }
+ public static implicit operator ushort( ItemID a )
+ {
+ return a.m_ID;
+ }
+
+ public static implicit operator ItemID( ushort a )
+ {
+ return new ItemID( a );
+ }
+
+ public override string ToString()
+ {
+ try
+ {
+ return string.Format( "{0} ({1:X4})", Ultima.TileData.ItemTable[m_ID].Name, m_ID );
+ }
+ catch
+ {
+ return String.Format( " ({0:X4})", m_ID );
+ }
+ }
+
+ public Ultima.ItemData ItemData
+ {
+ get
+ {
+ try
+ {
+ return Ultima.TileData.ItemTable[m_ID];
+ }
+ catch
+ {
+ return new Ultima.ItemData("", Ultima.TileFlag.None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return m_ID;
+ }
+
+ public override bool Equals( object o )
+ {
+ if ( o == null || !(o is ItemID) ) return false;
+
+ return ((ItemID)o).m_ID == m_ID;
+ }
+
+ public static bool operator == ( ItemID l, ItemID r )
+ {
+ return l.m_ID == r.m_ID;
+ }
+
+ public static bool operator != ( ItemID l, ItemID r )
+ {
+ return l.m_ID != r.m_ID;
+ }
+
+ public static bool operator > ( ItemID l, ItemID r )
+ {
+ return l.m_ID > r.m_ID;
+ }
+
+ public static bool operator >= ( ItemID l, ItemID r )
+ {
+ return l.m_ID >= r.m_ID;
+ }
+
+ public static bool operator < ( ItemID l, ItemID r )
+ {
+ return l.m_ID < r.m_ID;
+ }
+
+ public static bool operator <= ( ItemID l, ItemID r )
+ {
+ return l.m_ID <= r.m_ID;
+ }
+ }
+}
diff --git a/Core/Language.cs b/Core/Language.cs
new file mode 100644
index 0000000..a3f811f
--- /dev/null
+++ b/Core/Language.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Assistant
+{
+ internal class Language
+ {
+ public static string CliLocName { get; internal set; }
+
+ internal static string GetString( LocString loc )
+ {
+ throw new NotImplementedException();
+ }
+
+ internal static LocString Format( LocString loc, object[] args )
+ {
+ throw new NotImplementedException();
+ }
+
+ internal static string GetString( int name )
+ {
+ throw new NotImplementedException();
+ }
+
+ internal static string ClilocFormat( int num, string ext_str )
+ {
+ throw new NotImplementedException();
+ }
+
+ internal static string GetCliloc( int v )
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/LocString.cs b/Core/LocString.cs
new file mode 100644
index 0000000..40c3d71
--- /dev/null
+++ b/Core/LocString.cs
@@ -0,0 +1,7 @@
+namespace Assistant
+{
+ internal class LocString
+ {
+ public static LocString UseOnce { get; internal set; }
+ }
+}
\ No newline at end of file
diff --git a/Core/Map.cs b/Core/Map.cs
new file mode 100644
index 0000000..67bdee2
--- /dev/null
+++ b/Core/Map.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Collections;
+using Ultima;
+
+namespace Assistant
+{
+ public class MultiTileEntry
+ {
+ public ushort m_ItemID;
+ public short m_OffsetX;
+ public short m_OffsetY;
+ public short m_OffsetZ;
+ }
+
+ public class Map
+ {
+ public static Ultima.Map GetMap( int mapNum )
+ {
+ switch ( mapNum )
+ {
+ case 1: return Ultima.Map.Trammel;
+ case 2: return Ultima.Map.Ilshenar;
+ case 3: return Ultima.Map.Malas;
+ case 4: return Ultima.Map.Tokuno;
+ case 0:
+ default:return Ultima.Map.Felucca;
+ }
+ }
+
+ public static int Parse( string name )
+ {
+ if ( string.IsNullOrEmpty(name) )
+ return 0;
+
+ name = name.ToLower();
+
+ if ( name == "felucca" )
+ return 0;
+ else if ( name == "trammel" )
+ return 1;
+ else if ( name == "ilshenar" )
+ return 2;
+ else if ( name == "malas" )
+ return 3;
+ else if ( name == "samurai" || name == "tokuno" )
+ return 4;
+ else
+ return 0;
+ }
+
+ public static HuedTile GetTileNear( int mapNum, int x, int y, int z )
+ {
+ try
+ {
+ Ultima.Map map = GetMap( mapNum );
+
+ HuedTile[] tiles = map.Tiles.GetStaticTiles( x, y );
+ if ( tiles != null && tiles.Length > 0 )
+ {
+ for ( int i=0;i= z-5 && tiles[i].Z <= z+5 )
+ return tiles[i];
+ }
+ }
+ }
+ catch
+ {
+ }
+
+ return new HuedTile( 0, 0, (sbyte)z );
+ }
+
+ private static void GetAverageZ( Ultima.Map map, int x, int y, ref int z, ref int avg, ref int top )
+ {
+ try
+ {
+ int zTop = map.Tiles.GetLandTile( x, y ).Z;
+ int zLeft = map.Tiles.GetLandTile( x, y + 1 ).Z;
+ int zRight = map.Tiles.GetLandTile( x + 1, y ).Z;
+ int zBottom = map.Tiles.GetLandTile( x + 1, y + 1 ).Z;
+
+ z = zTop;
+ if ( zLeft < z )
+ z = zLeft;
+ if ( zRight < z )
+ z = zRight;
+ if ( zBottom < z )
+ z = zBottom;
+
+ top = zTop;
+ if ( zLeft > top )
+ top = zLeft;
+ if ( zRight > top )
+ top = zRight;
+ if ( zBottom > top )
+ top = zBottom;
+
+ if ( Math.Abs( zTop - zBottom ) > Math.Abs( zLeft - zRight) )
+ avg = (int)Math.Floor( (zLeft + zRight) / 2.0 );
+ else
+ avg = (int)Math.Floor( (zTop + zBottom) / 2.0 );
+ }
+ catch
+ {
+ }
+ }
+
+ public static sbyte ZTop( int mapNum, int xCheck, int yCheck, int oldZ )
+ {
+ try
+ {
+ Ultima.Map map = GetMap( mapNum );
+
+ Tile landTile = map.Tiles.GetLandTile( xCheck, yCheck );
+ int landZ = 0, landCenter = 0, zTop = 0;
+
+ GetAverageZ( map, xCheck, yCheck, ref landZ, ref landCenter, ref zTop );
+
+ if ( zTop > oldZ )
+ oldZ = zTop;
+
+ bool isSet = false;
+ HuedTile[] staticTiles = map.Tiles.GetStaticTiles( xCheck, yCheck );
+ for ( int i = 0; i < staticTiles.Length; ++i )
+ {
+ HuedTile tile = staticTiles[i];
+ ItemData id = TileData.ItemTable[tile.ID & 0x3FFF];
+
+ int calcTop = (tile.Z + id.CalcHeight);
+
+ if ( calcTop <= oldZ+5 && ( !isSet || calcTop > zTop ) && ( (id.Flags & TileFlag.Surface) != 0 || (id.Flags&TileFlag.Wet) != 0 ) )
+ {
+ zTop = calcTop;
+ isSet = true;
+ }
+ }
+
+ return (sbyte)zTop;
+ }
+ catch
+ {
+ return (sbyte)oldZ;
+ }
+ }
+ }
+}
+
diff --git a/Core/Mobile.cs b/Core/Mobile.cs
new file mode 100644
index 0000000..0b5f64c
--- /dev/null
+++ b/Core/Mobile.cs
@@ -0,0 +1,602 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+
+namespace Assistant
+{
+ [Flags]
+ public enum Direction : byte
+ {
+ North = 0x0,
+ Right = 0x1,
+ East = 0x2,
+ Down = 0x3,
+ South = 0x4,
+ Left = 0x5,
+ West = 0x6,
+ Up = 0x7,
+ Mask = 0x7,
+ Running = 0x80,
+ ValueMask = 0x87
+ }
+
+ //public enum BodyType : byte
+ //{
+ // Empty,
+ // Monster,
+ // Sea_Monster,
+ // Animal,
+ // Human,
+ // Equipment
+ //}
+
+ public class Mobile : UOEntity, IUOEntity
+ {
+ private ushort m_Body;
+ private Direction m_Direction;
+ private string m_Name;
+
+ public IUOEntity Parent { get { return null; } set { } }
+
+ private byte m_Notoriety;
+
+ private bool m_Visible;
+ private bool m_Female;
+ private bool m_Poisoned;
+ private bool m_Blessed;
+ private bool m_Warmode;
+
+ //new
+ private bool m_Unknown;
+ private bool m_Unknown2;
+ private bool m_Unknown3;
+
+ private bool m_CanRename;
+ //end new
+
+ private ushort m_HitsMax, m_Hits;
+ protected ushort m_StamMax, m_Stam, m_ManaMax, m_Mana;
+
+ private List m_LoadSerials;
+ private List
- m_Items = new List
- ();
+
+ 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());
+ }
+
+ public override void AfterLoad()
+ {
+ 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
+ }
+
+ public Mobile(Serial serial) : base(serial)
+ {
+ m_Map = World.Player == null ? (byte)0 : World.Player.Map;
+ m_Visible = true;
+
+ }
+
+ public string Name
+ {
+ get
+ {
+ if (m_Name == null)
+ return "";
+ else
+ return m_Name;
+ }
+ set
+ {
+ if (value != null)
+ {
+ string trim = value.Trim();
+ if (trim.Length > 0)
+ m_Name = trim;
+ }
+ }
+ }
+
+ public ushort Body
+ {
+ get { return m_Body; }
+ set { m_Body = value; }
+ }
+
+ public Direction Direction
+ {
+ get { return m_Direction; }
+ set
+ {
+ if (value != m_Direction)
+ {
+ var oldDir = m_Direction;
+ m_Direction = value;
+ OnDirectionChanging(oldDir);
+ }
+ }
+ }
+
+ public bool Visible
+ {
+ get { return m_Visible; }
+ set { m_Visible = value; }
+ }
+
+ public bool Poisoned
+ {
+ get { return m_Poisoned; }
+ set { m_Poisoned = value; }
+ }
+
+ public bool Blessed
+ {
+ get { return m_Blessed; }
+ set { m_Blessed = value; }
+ }
+
+ public bool IsGhost
+ {
+ get
+ {
+ return m_Body == 402
+ || m_Body == 403
+ || m_Body == 607
+ || m_Body == 608
+ || m_Body == 970;
+ }
+ }
+
+ public bool IsHuman
+ {
+ get
+ {
+ return m_Body >= 0
+ && (m_Body == 400
+ || m_Body == 401
+ || m_Body == 402
+ || m_Body == 403
+ || m_Body == 605
+ || m_Body == 606
+ || m_Body == 607
+ || m_Body == 608
+ || m_Body == 970); //player ghost
+ }
+ }
+
+ public bool IsMonster
+ {
+ get
+ {
+ return !IsHuman;
+ }
+ }
+
+ //new
+ public bool Unknown
+ {
+ get { return m_Unknown; }
+ set { m_Unknown = 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...
+ {
+ get { return m_CanRename; }
+ set { m_CanRename = value; }
+ }
+ //end new
+
+ public bool Warmode
+ {
+ get { return m_Warmode; }
+ set { m_Warmode = value; }
+ }
+
+ public bool Female
+ {
+ get { return m_Female; }
+ set { m_Female = value; }
+ }
+
+ public byte Notoriety
+ {
+ get { return m_Notoriety; }
+ set
+ {
+ if (value != Notoriety)
+ {
+ OnNotoChange(m_Notoriety, value);
+ m_Notoriety = value;
+ }
+ }
+ }
+
+ protected virtual void OnNotoChange(byte old, byte cur)
+ {
+ }
+
+ // grey, blue, green, 'canbeattacked'
+ private static uint[] m_NotoHues = new uint[8]
+ {
+ // hue color #30
+ 0x000000, // black unused 0
+ 0x30d0e0, // blue 0x0059 1
+ 0x60e000, // green 0x003F 2
+ 0x9090b2, // greyish 0x03b2 3
+ 0x909090, // grey " 4
+ 0xd88038, // orange 0x0090 5
+ 0xb01000, // red 0x0022 6
+ 0xe0e000 // yellow 0x0035 7
+ };
+
+ private static int[] m_NotoHuesInt = new int[8]
+ {
+ 1, // black unused 0
+ 0x059, // blue 0x0059 1
+ 0x03F, // green 0x003F 2
+ 0x3B2, // greyish 0x03b2 3
+ 0x3B2, // grey " 4
+ 0x090, // orange 0x0090 5
+ 0x022, // red 0x0022 6
+ 0x035, // yellow 0x0035 7
+ };
+
+ public uint GetNotorietyColor()
+ {
+ if (m_Notoriety < 0 || m_Notoriety >= m_NotoHues.Length)
+ return m_NotoHues[0];
+ else
+ return m_NotoHues[m_Notoriety];
+ }
+
+ public int GetNotorietyColorInt()
+ {
+ if (m_Notoriety < 0 || m_Notoriety >= m_NotoHues.Length)
+ return m_NotoHuesInt[0];
+ else
+ return m_NotoHuesInt[m_Notoriety];
+ }
+
+ public byte GetStatusCode()
+ {
+ if (m_Poisoned)
+ return 1;
+ else
+ return 0;
+ }
+
+ public ushort HitsMax
+ {
+ get { return m_HitsMax; }
+ set { m_HitsMax = value; }
+ }
+
+ public ushort Hits
+ {
+ get { return m_Hits; }
+ set { m_Hits = value; }
+ }
+
+ public ushort Stam
+ {
+ get { return m_Stam; }
+ set { m_Stam = value; }
+ }
+
+ public ushort StamMax
+ {
+ get { return m_StamMax; }
+ set { m_StamMax = value; }
+ }
+
+ public ushort Mana
+ {
+ get { return m_Mana; }
+ set { m_Mana = value; }
+ }
+
+ public ushort ManaMax
+ {
+ get { return m_ManaMax; }
+ set { m_ManaMax = value; }
+ }
+
+
+ public byte Map
+ {
+ get { return m_Map; }
+ set
+ {
+ if (m_Map != value)
+ {
+ OnMapChange(m_Map, value);
+ m_Map = value;
+ }
+ }
+ }
+
+ public virtual void OnMapChange(byte old, byte cur)
+ {
+ }
+
+ public void AddItem(Item item)
+ {
+ m_Items.Add(item);
+ }
+
+ public void RemoveItem(Item item)
+ {
+ m_Items.Remove(item);
+ }
+
+ public override void Remove()
+ {
+ List
- rem = new List
- (m_Items);
+ m_Items.Clear();
+
+ for (int i = 0; i < rem.Count; i++)
+ rem[i].Remove();
+
+ if (!InParty)
+ {
+ base.Remove();
+ World.RemoveMobile(this);
+ }
+ else
+ {
+ Visible = false;
+ }
+ }
+
+ public bool InParty
+ {
+ get
+ {
+ return PacketHandlers.Party.Contains(this.Serial);
+ }
+ }
+
+ public Item GetItemOnLayer(Layer layer)
+ {
+ for (int i = 0; i < m_Items.Count; i++)
+ {
+ Item item = (Item)m_Items[i];
+ if (item.Layer == layer)
+ return item;
+ }
+ return null;
+ }
+
+ public Item Backpack
+ {
+ get
+ {
+ return GetItemOnLayer(Layer.Backpack);
+ }
+ }
+
+ public Item Quiver
+ {
+ get
+ {
+ Item item = GetItemOnLayer(Layer.Cloak);
+
+ if (item != null && item.IsContainer)
+ return item;
+ else
+ return null;
+ }
+ }
+
+ public Item FindItemByID(ItemID id)
+ {
+ for (int i = 0; i < Contains.Count; i++)
+ {
+ Item item = (Item)Contains[i];
+ if (item.ItemID == id)
+ return item;
+ }
+ return null;
+ }
+
+ public override void OnPositionChanging(Point3D oldPos)
+ {
+
+ base.OnPositionChanging(oldPos);
+ }
+
+ public virtual void OnDirectionChanging(Direction oldDir)
+ {
+ }
+
+ public int GetPacketFlags()
+ {
+ int flags = 0x0;
+
+ if (m_Female)
+ flags |= 0x02;
+
+ if (m_Poisoned)
+ flags |= 0x04;
+
+ if (m_Blessed)
+ flags |= 0x08;
+
+ if (m_Warmode)
+ flags |= 0x40;
+
+ if (!m_Visible)
+ flags |= 0x80;
+
+ if (m_Unknown)
+ flags |= 0x01;
+
+ if (m_Unknown2)
+ flags |= 0x10;
+
+ if (m_Unknown3)
+ flags |= 0x20;
+
+ return flags;
+ }
+
+ public void ProcessPacketFlags(byte flags)
+ {
+ if (!PacketHandlers.UseNewStatus)
+ m_Poisoned = (flags & 0x04) != 0;
+
+ m_Unknown = (flags & 0x01) != 0; //new
+ m_Female = (flags & 0x02) != 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;
+
+
+ }
+
+ public List
- Contains { get { return m_Items; } }
+
+ internal void OverheadMessageFrom(int hue, string from, string format, params object[] args)
+ {
+ OverheadMessageFrom(hue, from, String.Format(format, args));
+ }
+
+ internal void OverheadMessageFrom(int hue, string from, string text)
+ {
+ if (Config.GetInt("OverheadStyle") == 0)
+ {
+ ClientCommunication.SendToClient(new AsciiMessage(Serial, m_Body, MessageType.Regular, hue, 3, Language.CliLocName, text));
+ }
+ else
+ {
+ ClientCommunication.SendToClient(new UnicodeMessage(Serial, m_Body, MessageType.Regular, hue, 3, Language.CliLocName, from, text));
+ }
+ }
+
+ internal void OverheadMessage(string text)
+ {
+ OverheadMessage(Config.GetInt("SysColor"), text);
+ }
+
+ internal void OverheadMessage(string format, params object[] args)
+ {
+ OverheadMessage(Config.GetInt("SysColor"), String.Format(format, args));
+ }
+
+ internal void OverheadMessage(int hue, string format, params object[] args)
+ {
+ OverheadMessage(hue, String.Format(format, args));
+ }
+
+ internal void OverheadMessage(int hue, string text)
+ {
+ OverheadMessageFrom(hue, "Razor", text);
+ }
+
+ internal void OverheadMessage(LocString str)
+ {
+ OverheadMessage(Language.GetString(str));
+ }
+
+ 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; }
+ }
+
+ public ushort GraphicID { get => Body; }
+ }
+}
+
+
diff --git a/Core/ObjectPropertyList.cs b/Core/ObjectPropertyList.cs
new file mode 100644
index 0000000..0a2c98e
--- /dev/null
+++ b/Core/ObjectPropertyList.cs
@@ -0,0 +1,403 @@
+using System;
+using System.Text;
+using System.Collections;
+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> 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_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 );
+ }
+ }
+}
diff --git a/Core/OverheadMessages.cs b/Core/OverheadMessages.cs
new file mode 100644
index 0000000..61141dc
--- /dev/null
+++ b/Core/OverheadMessages.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml;
+
+namespace Assistant.Core
+{
+ public class OverheadMessages
+ {
+ public class OverheadMessage
+ {
+ public string SearchMessage { get; set; }
+ public string MessageOverhead { get; set; }
+ }
+
+ public static List OverheadMessageList = new List();
+
+ public static void Save(XmlTextWriter xml)
+ {
+ foreach (var message in OverheadMessageList)
+ {
+ xml.WriteStartElement("overheadmessage");
+ xml.WriteAttributeString("searchtext", message.SearchMessage);
+ xml.WriteAttributeString("message", (message.MessageOverhead));
+ xml.WriteEndElement();
+ }
+ }
+
+ public static void Load(XmlElement node)
+ {
+ ClearAll();
+
+ try
+ {
+
+ foreach (XmlElement el in node.GetElementsByTagName("overheadmessage"))
+ {
+ OverheadMessage overheadMessage = new OverheadMessage
+ {
+ MessageOverhead = el.GetAttribute("message"),
+ SearchMessage = el.GetAttribute("searchtext")
+ };
+
+ OverheadMessageList.Add(overheadMessage);
+ }
+ }
+ catch
+ {
+ }
+ }
+
+ public static void ClearAll()
+ {
+ OverheadMessageList.Clear();
+ }
+ }
+}
diff --git a/Core/Player.cs b/Core/Player.cs
new file mode 100644
index 0000000..a9fca27
--- /dev/null
+++ b/Core/Player.cs
@@ -0,0 +1,955 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Collections;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using Assistant.Core;
+
+using Ultima;
+
+namespace Assistant
+{
+ public class GumpResponseAction
+ {
+ private int m_ButtonID;
+ public int Button => m_ButtonID;
+ private int[] m_Switches;
+ private GumpTextEntry[] m_TextEntries;
+
+ public GumpResponseAction( string[] args )
+ {
+ m_ButtonID = Convert.ToInt32( args[1] );
+ m_Switches = new int[Convert.ToInt32( args[2] )];
+ for ( int i = 0; i < m_Switches.Length; i++ )
+ m_Switches[i] = Convert.ToInt32( args[3 + i] );
+ m_TextEntries = new GumpTextEntry[Convert.ToInt32( args[3 + m_Switches.Length] )];
+ for ( int i = 0; i < m_TextEntries.Length; i++ )
+ {
+ string[] split = args[4 + m_Switches.Length + i].Split( '&' );
+ m_TextEntries[i].EntryID = Convert.ToUInt16( split[0] );
+ m_TextEntries[i].Text = split[1];
+ }
+ }
+
+ public GumpResponseAction( int button, int[] switches, GumpTextEntry[] entries )
+ {
+ m_ButtonID = button;
+ m_Switches = switches;
+ m_TextEntries = entries;
+ }
+
+ public bool Perform()
+ {
+ ClientCommunication.SendToClient( new CloseGump( World.Player.CurrentGumpI ) );
+ ClientCommunication.SendToServer( new GumpResponse( World.Player.CurrentGumpS, World.Player.CurrentGumpI, m_ButtonID, m_Switches, m_TextEntries ) );
+ World.Player.HasGump = false;
+ return true;
+ }
+
+
+ private void UseLastResponse( object[] args )
+ {
+ m_ButtonID = World.Player.LastGumpResponseAction.m_ButtonID;
+ m_Switches = World.Player.LastGumpResponseAction.m_Switches;
+ m_TextEntries = World.Player.LastGumpResponseAction.m_TextEntries;
+
+ World.Player.SendMessage( MsgLevel.Force, "Set GumpResponse to last response" );
+
+ }
+ }
+
+ public enum LockType : byte
+ {
+ Up = 0,
+ Down = 1,
+ Locked = 2
+ }
+
+ public enum MsgLevel
+ {
+ Debug = 0,
+ Info = 0,
+ Warning = 1,
+ Error = 2,
+ Force = 3
+ }
+
+ public class Skill
+ {
+ public static int Count = 55;
+
+ private LockType m_Lock;
+ private ushort m_Value;
+ private ushort m_Base;
+ private ushort m_Cap;
+ private short m_Delta;
+ private int m_Idx;
+
+ public Skill(int idx)
+ {
+ m_Idx = idx;
+ }
+
+ public int Index { get { return m_Idx; } }
+
+ public LockType Lock
+ {
+ get { return m_Lock; }
+ set { m_Lock = value; }
+ }
+
+ public ushort FixedValue
+ {
+ get { return m_Value; }
+ set { m_Value = value; }
+ }
+
+ public ushort FixedBase
+ {
+ get { return m_Base; }
+ set
+ {
+ m_Delta += (short)(value - m_Base);
+ m_Base = value;
+ }
+ }
+
+ public ushort FixedCap
+ {
+ get { return m_Cap; }
+ set { m_Cap = value; }
+ }
+
+ public double Value
+ {
+ get { return m_Value / 10.0; }
+ set { m_Value = (ushort)(value * 10.0); }
+ }
+
+ public double Base
+ {
+ get { return m_Base / 10.0; }
+ set { m_Base = (ushort)(value * 10.0); }
+ }
+
+ public double Cap
+ {
+ get { return m_Cap / 10.0; }
+ set { m_Cap = (ushort)(value * 10.0); }
+ }
+
+ public double Delta
+ {
+ get { return m_Delta / 10.0; }
+ set { m_Delta = (short)(value * 10); }
+ }
+ }
+
+ public enum SkillName
+ {
+ Alchemy = 0,
+ Anatomy = 1,
+ AnimalLore = 2,
+ ItemID = 3,
+ ArmsLore = 4,
+ Parry = 5,
+ Begging = 6,
+ Blacksmith = 7,
+ Fletching = 8,
+ Peacemaking = 9,
+ Camping = 10,
+ Carpentry = 11,
+ Cartography = 12,
+ Cooking = 13,
+ DetectHidden = 14,
+ Discordance = 15,
+ EvalInt = 16,
+ Healing = 17,
+ Fishing = 18,
+ Forensics = 19,
+ Herding = 20,
+ Hiding = 21,
+ Provocation = 22,
+ Inscribe = 23,
+ Lockpicking = 24,
+ Magery = 25,
+ MagicResist = 26,
+ Tactics = 27,
+ Snooping = 28,
+ Musicianship = 29,
+ Poisoning = 30,
+ Archery = 31,
+ SpiritSpeak = 32,
+ Stealing = 33,
+ Tailoring = 34,
+ AnimalTaming = 35,
+ TasteID = 36,
+ Tinkering = 37,
+ Tracking = 38,
+ Veterinary = 39,
+ Swords = 40,
+ Macing = 41,
+ Fencing = 42,
+ Wrestling = 43,
+ Lumberjacking = 44,
+ Mining = 45,
+ Meditation = 46,
+ Stealth = 47,
+ RemoveTrap = 48,
+ Necromancy = 49,
+ Focus = 50,
+ Chivalry = 51,
+ Bushido = 52,
+ Ninjitsu = 53,
+ SpellWeaving = 54
+ }
+
+ public enum MaleSounds
+ {
+ Ah = 0x41A,
+ Ahha = 0x41B,
+ Applaud = 0x41C,
+ BlowNose = 0x41D,
+ Burp = 0x41E,
+ Cheer = 0x41F,
+ ClearThroat = 0x420,
+ Cough = 0x421,
+ CoughBS = 0x422,
+ Cry = 0x423,
+ Fart = 0x429,
+ Gasp = 0x42A,
+ Giggle = 0x42B,
+ Groan = 0x42C,
+ Growl = 0x42D,
+ Hey = 0x42E,
+ Hiccup = 0x42F,
+ Huh = 0x430,
+ Kiss = 0x431,
+ Laugh = 0x432,
+ No = 0x433,
+ Oh = 0x434,
+ Oomph1 = 0x435,
+ Oomph2 = 0x436,
+ Oomph3 = 0x437,
+ Oomph4 = 0x438,
+ Oomph5 = 0x439,
+ Oomph6 = 0x43A,
+ Oomph7 = 0x43B,
+ Oomph8 = 0x43C,
+ Oomph9 = 0x43D,
+ Oooh = 0x43E,
+ Oops = 0x43F,
+ Puke = 0x440,
+ Scream = 0x441,
+ Shush = 0x442,
+ Sigh = 0x443,
+ Sneeze = 0x444,
+ Sniff = 0x445,
+ Snore = 0x446,
+ Spit = 0x447,
+ Whistle = 0x448,
+ Yawn = 0x449,
+ Yea = 0x44A,
+ Yell = 0x44B,
+ }
+
+ public enum FemaleSounds
+ {
+ Ah = 0x30B,
+ Ahha = 0x30C,
+ Applaud = 0x30D,
+ BlowNose = 0x30E,
+ Burp = 0x30F,
+ Cheer = 0x310,
+ ClearThroat = 0x311,
+ Cough = 0x312,
+ CoughBS = 0x313,
+ Cry = 0x314,
+ Fart = 0x319,
+ Gasp = 0x31A,
+ Giggle = 0x31B,
+ Groan = 0x31C,
+ Growl = 0x31D,
+ Hey = 0x31E,
+ Hiccup = 0x31F,
+ Huh = 0x320,
+ Kiss = 0x321,
+ Laugh = 0x322,
+ No = 0x323,
+ Oh = 0x324,
+ Oomph1 = 0x325,
+ Oomph2 = 0x326,
+ Oomph3 = 0x327,
+ Oomph4 = 0x328,
+ Oomph5 = 0x329,
+ Oomph6 = 0x32A,
+ Oomph7 = 0x32B,
+ Oooh = 0x32C,
+ Oops = 0x32D,
+ Puke = 0x32E,
+ Scream = 0x32F,
+ Shush = 0x330,
+ Sigh = 0x331,
+ Sneeze = 0x332,
+ Sniff = 0x333,
+ Snore = 0x334,
+ Spit = 0x335,
+ Whistle = 0x336,
+ Yawn = 0x337,
+ Yea = 0x338,
+ Yell = 0x339,
+ }
+
+ public class PlayerData : Mobile
+ {
+ public int VisRange = 18;
+ public int MultiVisRange { get { return VisRange + 5; } }
+
+ private int m_MaxWeight = -1;
+
+ private short m_FireResist, m_ColdResist, m_PoisonResist, m_EnergyResist, m_Luck;
+ private ushort m_DamageMin, m_DamageMax;
+
+ private ushort m_Str, m_Dex, m_Int;
+ private LockType m_StrLock, m_DexLock, m_IntLock;
+ private uint m_Gold;
+ private ushort m_Weight;
+ private Skill[] m_Skills;
+ private ushort m_AR;
+ private ushort m_StatCap;
+ private byte m_Followers;
+ private byte m_FollowersMax;
+ private int m_Tithe;
+ private sbyte m_LocalLight;
+ private byte m_GlobalLight;
+ private ushort m_Features;
+ private byte m_Season;
+ private byte m_DefaultSeason;
+ private int[] m_MapPatches = new int[10];
+
+
+ private bool m_SkillsSent;
+ private DateTime m_CriminalStart = DateTime.MinValue;
+
+ internal List m_BuffsDebuffs = new List();
+ internal List BuffsDebuffs { get { return m_BuffsDebuffs; } }
+
+ private List m_OpenedCorpses = new List();
+ public List OpenedCorpses { get { return m_OpenedCorpses; } }
+
+ public Direction GetDirectionTo( int x, int y )
+ {
+ int dx = Position.m_X - x;
+ int dy = Position.m_Y - y;
+
+ int rx = ( dx - dy ) * 44;
+ int ry = ( dx + dy ) * 44;
+
+ int ax = Math.Abs( rx );
+ int ay = Math.Abs( ry );
+
+ Direction ret;
+
+ if ( ( ( ay >> 1 ) - ax ) >= 0 )
+ ret = ( ry > 0 ) ? Direction.Up : Direction.Down;
+ else if ( ( ( ax >> 1 ) - ay ) >= 0 )
+ ret = ( rx > 0 ) ? Direction.Left : Direction.Right;
+ else if ( rx >= 0 && ry >= 0 )
+ ret = Direction.West;
+ else if ( rx >= 0 && ry < 0 )
+ ret = Direction.South;
+ else if ( rx < 0 && ry < 0 )
+ ret = Direction.East;
+ else
+ ret = Direction.North;
+
+ return ret;
+ }
+
+ public Direction GetDirectionTo( Point2D p )
+ {
+ return GetDirectionTo( p.m_X, p.m_Y );
+ }
+
+ public Direction GetDirectionTo( Point3D p )
+ {
+ return GetDirectionTo( p.m_X, p.m_Y );
+ }
+
+ public Direction GetDirectionTo( IPoint2D p )
+ {
+ if ( p == null )
+ return Direction.North;
+
+ return GetDirectionTo( p.X, p.Y );
+ }
+ 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];
+ for (int i = 0; i < m_Skills.Length; i++)
+ m_Skills[i] = new Skill(i);
+ }
+
+ public ushort Str
+ {
+ get { return m_Str; }
+ set { m_Str = value; }
+ }
+
+ public ushort Dex
+ {
+ get { return m_Dex; }
+ set { m_Dex = value; }
+ }
+
+ public ushort Int
+ {
+ get { return m_Int; }
+ set { m_Int = value; }
+ }
+
+ public uint Gold
+ {
+ get { return m_Gold; }
+ set { m_Gold = value; }
+ }
+
+ public ushort Weight
+ {
+ get { return m_Weight; }
+ set { m_Weight = value; }
+ }
+
+ public ushort MaxWeight
+ {
+ get
+ {
+ if (m_MaxWeight == -1)
+ return (ushort)((m_Str * 3.5) + 40);
+ else
+ return (ushort)m_MaxWeight;
+ }
+ set
+ {
+ m_MaxWeight = value;
+ }
+ }
+
+ public short FireResistance
+ {
+ get { return m_FireResist; }
+ set { m_FireResist = value; }
+ }
+
+ public short ColdResistance
+ {
+ get { return m_ColdResist; }
+ set { m_ColdResist = value; }
+ }
+
+ public short PoisonResistance
+ {
+ get { return m_PoisonResist; }
+ set { m_PoisonResist = value; }
+ }
+
+ public short EnergyResistance
+ {
+ get { return m_EnergyResist; }
+ set { m_EnergyResist = value; }
+ }
+
+ public short Luck
+ {
+ get { return m_Luck; }
+ set { m_Luck = value; }
+ }
+
+ public ushort DamageMin
+ {
+ get { return m_DamageMin; }
+ set { m_DamageMin = value; }
+ }
+
+ public ushort DamageMax
+ {
+ get { return m_DamageMax; }
+ set { m_DamageMax = value; }
+ }
+
+ public LockType StrLock
+ {
+ get { return m_StrLock; }
+ set { m_StrLock = value; }
+ }
+
+ public LockType DexLock
+ {
+ get { return m_DexLock; }
+ set { m_DexLock = value; }
+ }
+
+ public LockType IntLock
+ {
+ get { return m_IntLock; }
+ set { m_IntLock = value; }
+ }
+
+ public ushort StatCap
+ {
+ get { return m_StatCap; }
+ set { m_StatCap = value; }
+ }
+
+ public ushort AR
+ {
+ get { return m_AR; }
+ set { m_AR = value; }
+ }
+
+ public byte Followers
+ {
+ get { return m_Followers; }
+ set { m_Followers = value; }
+ }
+
+ public byte FollowersMax
+ {
+ get { return m_FollowersMax; }
+ set { m_FollowersMax = value; }
+ }
+
+ public int Tithe
+ {
+ get { return m_Tithe; }
+ set { m_Tithe = value; }
+ }
+
+ public Skill[] Skills { get { return m_Skills; } }
+
+ public bool SkillsSent
+ {
+ get { return m_SkillsSent; }
+ set { m_SkillsSent = value; }
+ }
+
+
+ private void AutoOpenDoors()
+ {
+ if (Body != 0x03DB &&
+ !IsGhost &&
+ ((int)(Direction & Direction.Mask)) % 2 == 0 &&
+ Config.GetBool("AutoOpenDoors"))
+ {
+ int x = Position.X, y = Position.Y, z = Position.Z;
+
+ /* Check if one more tile in the direction we just moved is a door */
+ Utility.Offset(Direction, ref x, ref y);
+
+ foreach (Item i in World.Items.Values)
+ {
+ if (i.IsDoor && i.Position.X == x && i.Position.Y == y && i.Position.Z - 15 <= z && i.Position.Z + 15 >= z)
+ {
+ ClientCommunication.SendToServer(new OpenDoorMacro());
+ break;
+ }
+ }
+ }
+ }
+
+
+ public override void OnPositionChanging(Point3D oldPos)
+ {
+
+ AutoOpenDoors();
+
+ List mlist = new List(World.Mobiles.Values);
+ for (int i = 0; i < mlist.Count; i++)
+ {
+ Mobile m = mlist[i];
+ if (m != this)
+ {
+ if (!Utility.InRange(m.Position, Position, VisRange))
+ m.Remove();
+ else
+ Targeting.CheckLastTargetRange(m);
+ }
+ }
+
+ mlist = null;
+
+
+ List
- ilist = new List
- (World.Items.Values);
+ for (int i = 0; i < ilist.Count; i++)
+ {
+ Item item = ilist[i];
+ if (item.Deleted || item.Container != null)
+ continue;
+
+ int dist = Utility.Distance(item.GetWorldPosition(), Position);
+ if (item != DragDropManager.Holding && (dist > MultiVisRange || (!item.IsMulti && dist > VisRange)))
+ item.Remove();
+ }
+
+ ilist = null;
+
+ base.OnPositionChanging(oldPos);
+ }
+
+ public override void OnDirectionChanging(Direction oldDir)
+ {
+ AutoOpenDoors();
+ }
+
+ public override void OnMapChange(byte old, byte cur)
+ {
+ List list = new List(World.Mobiles.Values);
+ for (int i = 0; i < list.Count; i++)
+ {
+ Mobile m = list[i];
+ if (m != this && m.Map != cur)
+ m.Remove();
+ }
+
+ list = null;
+
+ World.Items.Clear();
+ for (int i = 0; i < Contains.Count; i++)
+ {
+ Item item = (Item)Contains[i];
+ World.AddItem(item);
+ item.Contains.Clear();
+ }
+
+ if (Config.GetBool("AutoSearch") && Backpack != null)
+ PlayerData.DoubleClick(Backpack);
+ }
+
+ /*public override void OnMapChange( byte old, byte cur )
+ {
+ World.Mobiles.Clear();
+ World.Items.Clear();
+ Counter.Reset();
+
+ Contains.Clear();
+
+ World.AddMobile( this );
+
+ UOAssist.PostMapChange( cur );
+ }*/
+
+ protected override void OnNotoChange(byte old, byte cur)
+ {
+
+ }
+
+
+
+
+
+ internal void SendMessage(MsgLevel lvl, LocString loc, params object[] args)
+ {
+ SendMessage(lvl, Language.Format(loc, args));
+ }
+
+ internal void SendMessage(MsgLevel lvl, LocString loc)
+ {
+ SendMessage(lvl, Language.GetString(loc));
+ }
+
+ internal void SendMessage(LocString loc, params object[] args)
+ {
+ SendMessage(MsgLevel.Info, Language.Format(loc, args));
+ }
+
+ internal void SendMessage(LocString loc)
+ {
+ SendMessage(MsgLevel.Info, Language.GetString(loc));
+ }
+
+ /*internal void SendMessage( int hue, LocString loc, params object[] args )
+ {
+ SendMessage( hue, Language.Format( loc, args ) );
+ }*/
+
+ internal void SendMessage(MsgLevel lvl, string format, params object[] args)
+ {
+ SendMessage(lvl, String.Format(format, args));
+ }
+
+ internal void SendMessage(string format, params object[] args)
+ {
+ SendMessage(MsgLevel.Info, String.Format(format, args));
+ }
+
+ internal void SendMessage(string text)
+ {
+ SendMessage(MsgLevel.Info, text);
+ }
+
+ internal void SendMessage(MsgLevel lvl, string text)
+ {
+ if (lvl >= (MsgLevel)Config.GetInt("MessageLevel") && text.Length > 0)
+ {
+ int hue;
+ switch (lvl)
+ {
+ case MsgLevel.Error:
+ case MsgLevel.Warning:
+ hue = Config.GetInt("WarningColor");
+ break;
+
+ default:
+ hue = Config.GetInt("SysColor");
+ break;
+ }
+
+ ClientCommunication.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, hue, 3, Language.CliLocName, "System", text));
+
+ PacketHandlers.SysMessages.Add(text);
+
+ if (PacketHandlers.SysMessages.Count >= 25)
+ PacketHandlers.SysMessages.RemoveRange(0, 10);
+ }
+ }
+
+ public uint CurrentGumpS, CurrentGumpI;
+ public GumpResponseAction LastGumpResponseAction;
+ public bool HasGump;
+ public List CurrentGumpStrings = new List();
+ public string CurrentGumpRawData;
+ public uint CurrentMenuS;
+ public ushort CurrentMenuI;
+ public bool HasMenu;
+
+ private ushort m_SpeechHue;
+ public ushort SpeechHue { get { return m_SpeechHue; } set { m_SpeechHue = value; } }
+
+ public sbyte LocalLightLevel { get { return m_LocalLight; } set { m_LocalLight = value; } }
+ public byte GlobalLightLevel { get { return m_GlobalLight; } set { m_GlobalLight = value; } }
+
+ public enum SeasonFlag
+ {
+ Spring,
+ Summer,
+ Fall,
+ Winter,
+ Desolation
+ }
+
+
+ public ushort Features { get { return m_Features; } set { m_Features = value; } }
+ public int[] MapPatches { get { return m_MapPatches; } set { m_MapPatches = value; } }
+
+ private int m_LastSkill = -1;
+ public int LastSkill { get { return m_LastSkill; } set { m_LastSkill = value; } }
+
+ private Serial m_LastObj = Serial.Zero;
+ public Serial LastObject { get { return m_LastObj; } set { m_LastObj = value; } }
+
+ public IUOEntity LastObjectAsEntity => World.FindEntity( LastObject );
+
+
+ private int m_LastSpell = -1;
+ public int LastSpell { get { return m_LastSpell; } set { m_LastSpell = value; } }
+
+ public byte WalkSequence { get; internal set; }
+ public Item LastContainer { get; internal set; }
+ public DateTime LastContainerOpenedAt { get; internal set; } = DateTime.UtcNow;
+ public DateTime LastGumpOpenedAt { get; internal set; } = DateTime.UtcNow;
+ public uint LastGumpX { get; internal set; }
+ public uint LastGumpY { get; internal set; }
+ public int LastGumpWidth { get; internal set; }
+ public int LastGumpHeight { get; internal set; }
+ public string LastSystemMessage { get; internal set; }
+ public uint LastContainerGumpGraphic { get; internal set; }
+
+ //private UOEntity m_LastCtxM = null;
+ //public UOEntity LastContextMenu { get { return m_LastCtxM; } set { m_LastCtxM = value; } }
+
+ public static bool DoubleClick(object clicked)
+ {
+ return DoubleClick(clicked, true);
+ }
+
+ public static bool DoubleClick(object clicked, bool silent)
+ {
+ Serial s;
+ if (clicked is Mobile)
+ s = ((Mobile)clicked).Serial.Value;
+ else if (clicked is Item)
+ s = ((Item)clicked).Serial.Value;
+ else if (clicked is Serial)
+ s = ((Serial)clicked).Value;
+ else
+ s = Serial.Zero;
+
+ if (s != Serial.Zero)
+ {
+ Item free = null, pack = World.Player.Backpack;
+ if (s.IsItem && pack != null && Config.GetBool("PotionEquip"))
+ {
+ Item i = World.FindItem(s);
+ if (i != null && i.IsPotion && i.ItemID != 3853) // dont unequip for exploison potions
+ {
+ // dont worry about uneqipping RuneBooks or SpellBooks
+ Item left = World.Player.GetItemOnLayer(Layer.LeftHand);
+ Item right = World.Player.GetItemOnLayer(Layer.RightHand);
+
+ if (left != null && (right != null || left.IsTwoHanded))
+ free = left;
+ else if (right != null && right.IsTwoHanded)
+ free = right;
+
+ if (free != null)
+ {
+ if (DragDropManager.HasDragFor(free.Serial))
+ free = null;
+ else
+ DragDropManager.DragDrop(free, pack);
+ }
+ }
+ }
+
+ ActionQueue.DoubleClick(silent, s);
+
+ if (free != null)
+ DragDropManager.DragDrop(free, World.Player, free.Layer, true);
+
+ if (s.IsItem)
+ World.Player.m_LastObj = s;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Core/Serial.cs b/Core/Serial.cs
new file mode 100644
index 0000000..a9e5bdb
--- /dev/null
+++ b/Core/Serial.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+
+namespace Assistant
+{
+ public struct Serial : IComparable
+ {
+ private uint m_Serial;
+ public static List Serials { get; set; }
+
+ public static readonly Serial MinusOne = new Serial( 0xFFFFFFFF );
+ public static readonly Serial Zero = new Serial( 0 );
+
+ private Serial( uint serial )
+ {
+ m_Serial = serial;
+ }
+
+ public uint Value
+ {
+ get
+ {
+ return m_Serial;
+ }
+ }
+
+ public bool IsMobile
+ {
+ get
+ {
+ return ( m_Serial > 0 && m_Serial < 0x40000000 );
+ }
+ }
+
+ public bool IsItem
+ {
+ get
+ {
+ return ( m_Serial >= 0x40000000 && m_Serial <= 0x7FFFFF00 );
+ }
+ }
+
+ public bool IsValid
+ {
+ get
+ {
+ return ( m_Serial > 0 && m_Serial <= 0x7FFFFF00 );
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)m_Serial;
+ }
+
+ public int CompareTo( object o )
+ {
+ if ( o == null ) return 1;
+ else if ( !(o is Serial) ) throw new ArgumentException();
+
+ uint ser = ((Serial)o).m_Serial;
+
+ if ( m_Serial > ser ) return 1;
+ else if ( m_Serial < ser ) return -1;
+ else return 0;
+ }
+
+ public override bool Equals( object o )
+ {
+ if ( o == null || !(o is Serial) ) return false;
+
+ return ((Serial)o).m_Serial == m_Serial;
+ }
+
+ public static bool operator == ( Serial l, Serial r )
+ {
+ return l.m_Serial == r.m_Serial;
+ }
+
+ public static bool operator != ( Serial l, Serial r )
+ {
+ return l.m_Serial != r.m_Serial;
+ }
+
+ public static bool operator > ( Serial l, Serial r )
+ {
+ return l.m_Serial > r.m_Serial;
+ }
+
+ public static bool operator < ( Serial l, Serial r )
+ {
+ return l.m_Serial < r.m_Serial;
+ }
+
+ public static bool operator >= ( Serial l, Serial r )
+ {
+ return l.m_Serial >= r.m_Serial;
+ }
+
+ public static bool operator <= ( Serial l, Serial r )
+ {
+ return l.m_Serial <= r.m_Serial;
+ }
+
+ public override string ToString()
+ {
+ return String.Format( "0x{0:X}", m_Serial );
+ }
+
+ public static Serial Parse( string s )
+ {
+ if ( s.StartsWith( "0x" ) )
+ return (Serial)Convert.ToUInt32( s.Substring( 2 ), 16 );
+ else
+ return (Serial)Convert.ToUInt32( s );
+ }
+
+ public static implicit operator uint( Serial a )
+ {
+ return a.m_Serial;
+ }
+
+ public static implicit operator int( Serial a )
+ {
+ return (int)a.m_Serial;
+ }
+
+ public static implicit operator Serial( uint a )
+ {
+ return new Serial( a );
+ }
+ }
+}
+
diff --git a/Core/SkillTimer.cs b/Core/SkillTimer.cs
new file mode 100644
index 0000000..2b12ed3
--- /dev/null
+++ b/Core/SkillTimer.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace Assistant
+{
+ public class SkillTimer
+ {
+ private static int m_Count;
+ private static Timer m_Timer;
+
+ static SkillTimer()
+ {
+ m_Timer = new InternalTimer();
+ }
+
+ public static int Count
+ {
+ get { return m_Count; }
+ }
+
+ public static bool Running
+ {
+ get { return m_Timer.Running; }
+ }
+
+ public static void Start()
+ {
+ m_Count = 0;
+
+ if (m_Timer.Running)
+ {
+ m_Timer.Stop();
+ }
+
+ m_Timer.Start();
+ }
+
+ public static void Stop()
+ {
+ m_Timer.Stop();
+ }
+
+ private class InternalTimer : Timer
+ {
+ public InternalTimer() : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
+ {
+ }
+
+ protected override void OnTick()
+ {
+ m_Count++;
+ if (m_Count > 10)
+ {
+ Stop();
+ }
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/Spells.cs b/Core/Spells.cs
new file mode 100644
index 0000000..3f7a508
--- /dev/null
+++ b/Core/Spells.cs
@@ -0,0 +1,393 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace Assistant
+{
+ public class Spell
+ {
+ public enum SpellFlag
+ {
+ None = '?',
+ Beneficial = 'B',
+ Harmful = 'H',
+ Neutral = 'N'
+ }
+
+ readonly public SpellFlag Flag;
+ readonly public int Circle;
+ readonly public int Number;
+ readonly public string WordsOfPower;
+ readonly public string[] Reagents;
+
+ private static Timer m_UnflagTimer;
+
+ public Spell(char flag, int n, int c, string power, string[] reags)
+ {
+ Flag = (SpellFlag) flag;
+ Number = n;
+ Circle = c;
+ WordsOfPower = power;
+ Reagents = reags;
+ }
+
+ public int Name
+ {
+ get
+ {
+ if (Circle <= 8) // Mage
+ return 3002011 + ((Circle - 1) * 8) + (Number - 1);
+ else if (Circle == 10) // Necr
+ return 1060509 + Number - 1;
+ else if (Circle == 20) // Chiv
+ return 1060585 + Number - 1;
+ else if (Circle == 40) // Bush
+ return 1060595 + Number - 1;
+ else if (Circle == 50) // Ninj
+ return 1060610 + Number - 1;
+ else if (Circle == 60) // Elfs
+ return 1071026 + Number - 1;
+ else
+ return -1;
+ }
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0} (#{1})", Language.GetString(this.Name), GetID());
+ }
+
+ public int GetID()
+ {
+ return ToID(Circle, Number);
+ }
+
+ public int GetHue(int def)
+ {
+ if (Config.GetBool("ForceSpellHue"))
+ {
+ switch (Flag)
+ {
+ case SpellFlag.Beneficial:
+ return Config.GetInt("BeneficialSpellHue");
+ case SpellFlag.Harmful:
+ return Config.GetInt("HarmfulSpellHue");
+ case SpellFlag.Neutral:
+ return Config.GetInt("NeutralSpellHue");
+ default:
+ return def;
+ }
+ }
+ else
+ {
+ return def;
+ }
+ }
+
+ public void OnCast(Packet p)
+ {
+ Cast();
+ ClientCommunication.SendToServer(p);
+ }
+
+ public void OnCast(int idx)
+ {
+ Cast();
+ ClientCommunication.CastSpell(idx);
+ }
+
+ private void Cast()
+ {
+ if (Config.GetBool("SpellUnequip"))
+ {
+ Item pack = World.Player.Backpack;
+ if (pack != null)
+ {
+ // dont worry about uneqipping RuneBooks or SpellBooks
+ Item item = World.Player.GetItemOnLayer(Layer.RightHand);
+#if DEBUG
+ if (item != null && item.ItemID != 0x22C5 && item.ItemID != 0xE3B && item.ItemID != 0xEFA &&
+ !item.IsVirtueShield)
+#else
+ if ( item != null && item.ItemID != 0x22C5 && item.ItemID != 0xE3B && item.ItemID != 0xEFA )
+#endif
+ {
+ DragDropManager.Drag(item, item.Amount);
+ DragDropManager.Drop(item, pack);
+ }
+
+ item = World.Player.GetItemOnLayer(Layer.LeftHand);
+#if DEBUG
+ if (item != null && item.ItemID != 0x22C5 && item.ItemID != 0xE3B && item.ItemID != 0xEFA &&
+ !item.IsVirtueShield)
+#else
+ if ( item != null && item.ItemID != 0x22C5 && item.ItemID != 0xE3B && item.ItemID != 0xEFA )
+#endif
+ {
+ DragDropManager.Drag(item, item.Amount);
+ DragDropManager.Drop(item, pack);
+ }
+ }
+ }
+
+
+
+ if (World.Player != null)
+ {
+ World.Player.LastSpell = GetID();
+ LastCastTime = DateTime.UtcNow;
+ Targeting.SpellTargetID = 0;
+ }
+ }
+
+ public static DateTime LastCastTime = DateTime.MinValue;
+
+
+
+ private static Dictionary m_SpellsByPower;
+ private static Dictionary m_SpellsByID;
+
+ static Spell()
+ {
+
+
+
+ }
+
+ public static void HealOrCureSelf()
+ {
+ Spell s = null;
+
+
+ {
+ if (World.Player.Poisoned)
+ {
+ s = Get(2, 3); // cure
+ }
+ else if (World.Player.Hits + 2 < World.Player.HitsMax)
+ {
+ if (World.Player.Hits + 30 < World.Player.HitsMax && World.Player.Mana >= 12)
+ s = Get(4, 5); // greater heal
+ else
+ s = Get(1, 4); // mini heal
+ }
+ else
+ {
+ if (World.Player.Mana >= 12)
+ s = Get(4, 5); // greater heal
+ else
+ s = Get(1, 4); // mini heal
+ }
+ }
+
+ if (s != null)
+ {
+ if (World.Player.Poisoned || World.Player.Hits < World.Player.HitsMax)
+ Targeting.TargetSelf(true);
+ ClientCommunication.SendToServer(new CastSpellFromMacro((ushort) s.GetID()));
+ s.Cast();
+ }
+ }
+
+ public static void MiniHealOrCureSelf()
+ {
+ Spell s = null;
+
+
+ {
+ if (World.Player.Poisoned)
+ s = Get(2, 3); // cure
+ else
+ s = Get(1, 4); // mini heal
+ }
+
+ if (s != null)
+ {
+ if (World.Player.Poisoned || World.Player.Hits < World.Player.HitsMax)
+ Targeting.TargetSelf(true);
+ ClientCommunication.SendToServer(new CastSpellFromMacro((ushort) s.GetID()));
+ s.Cast();
+ }
+ }
+
+ public static void Interrupt()
+ {
+ Item item = FindUsedLayer();
+
+ if (item != null)
+ {
+ ClientCommunication.SendToServer(new LiftRequest(item, 1)); // unequip
+ ClientCommunication.SendToServer(new EquipRequest(item.Serial, World.Player, item.Layer)); // Equip
+ }
+ }
+
+ internal static Item FindUsedLayer()
+ {
+ Item layeredItem = World.Player.GetItemOnLayer(Layer.Shoes);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Pants);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Shirt);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Head);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Gloves);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Ring);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Neck);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Waist);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.InnerTorso);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Bracelet);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.MiddleTorso);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Earrings);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Arms);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.Cloak);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.OuterTorso);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.OuterLegs);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.InnerLegs);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.RightHand);
+ if (layeredItem != null)
+ return layeredItem;
+
+ layeredItem = World.Player.GetItemOnLayer(Layer.LeftHand);
+ if (layeredItem != null)
+ return layeredItem;
+
+ return null;
+ }
+
+ public static void Initialize()
+ {
+ string filename = Path.Combine( Engine.RootPath, "spells.def" );
+ m_SpellsByPower = new Dictionary( 64 + 10 + 16 );
+ m_SpellsByID = new Dictionary( 64 + 10 + 16 );
+
+ if ( !File.Exists( filename ) )
+ {
+ MessageBox.Show( "CEUO", "No spells.def",
+ MessageBoxButtons.OK, MessageBoxIcon.Warning );
+ return;
+ }
+
+ using ( StreamReader reader = new StreamReader( filename ) )
+ {
+ string line;
+ while ( ( line = reader.ReadLine() ) != null )
+ {
+ line = line.Trim();
+ if ( line.Length <= 0 || line[0] == '#' )
+ continue;
+ string[] split = line.Split( '|' );
+
+ try
+ {
+ if ( split.Length >= 5 )
+ {
+ string[] reags = new string[split.Length - 5];
+ for ( int i = 5; i < split.Length; i++ )
+ reags[i - 5] = split[i].ToLower().Trim();
+ Spell s = new Spell( split[0].Trim()[0], Convert.ToInt32( split[1].Trim() ),
+ Convert.ToInt32( split[2].Trim() ), /*split[3].Trim(),*/ split[4].Trim(), reags );
+
+ m_SpellsByID[s.GetID()] = s;
+
+ if ( s.WordsOfPower != null && s.WordsOfPower.Trim().Length > 0 )
+ m_SpellsByPower[s.WordsOfPower] = s;
+ }
+ }
+ catch
+ {
+ }
+ }
+ }
+ }
+
+ public static void OnHotKey(ref object state)
+ {
+ ushort id = (ushort) state;
+ Spell s = Spell.Get(id);
+ if (s != null)
+ {
+ s.OnCast(new CastSpellFromMacro(id));
+ //if ( Macros.MacroManager.AcceptActions )
+ // Macros.MacroManager.Action( new Macros.MacroCastSpellAction( s ) );
+ }
+ }
+
+ public static int ToID(int circle, int num)
+ {
+ if (circle < 10)
+ return ((circle - 1) * 8) + num;
+ else
+ return (circle * 10) + num;
+ }
+
+ public static Spell Get(string power)
+ {
+ Spell s;
+ m_SpellsByPower.TryGetValue(power, out s);
+ return s;
+ }
+
+ public static Spell Get(int num)
+ {
+ Spell s;
+ m_SpellsByID.TryGetValue(num, out s);
+ return s;
+ }
+
+ public static Spell Get(int circle, int num)
+ {
+ return Get(Spell.ToID(circle, num));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/Targeting.cs b/Core/Targeting.cs
new file mode 100644
index 0000000..8a6d14d
--- /dev/null
+++ b/Core/Targeting.cs
@@ -0,0 +1,1705 @@
+using CEasyUO;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Assistant
+{
+ public class TargetInfo
+ {
+ public byte Type;
+ public uint TargID;
+ public byte Flags;
+ public Serial Serial;
+ public int X, Y;
+ public int Z;
+ public ushort Gfx;
+ }
+
+ public class Targeting
+ {
+ public const uint LocalTargID = 0x7FFFFFFF; // uid for target sent from razor
+
+ public delegate void TargetResponseCallback(bool location, Serial serial, Point3D p, ushort gfxid);
+ public delegate void CancelTargetCallback();
+
+ private static CancelTargetCallback m_OnCancel;
+ private static TargetResponseCallback m_OnTarget;
+
+ private static bool m_Intercept;
+ private static bool m_HasTarget;
+ private static bool m_ClientTarget;
+ private static TargetInfo m_LastTarget;
+ public static TargetInfo LastTarget => m_LastTarget != null ? m_LastTarget : m_LastGroundTarg;
+ private static TargetInfo m_LastGroundTarg;
+ private static TargetInfo m_LastBeneTarg;
+ private static TargetInfo m_LastHarmTarg;
+
+ private static bool m_AllowGround;
+ private static uint m_CurrentID;
+ private static byte m_CurFlags;
+
+ private static uint m_PreviousID;
+ private static bool m_PreviousGround;
+ private static byte m_PrevFlags;
+
+ private static Serial m_LastCombatant;
+
+ private delegate bool QueueTarget();
+ private static QueueTarget TargetSelfAction = new QueueTarget(DoTargetSelf);
+ private static QueueTarget LastTargetAction = new QueueTarget(DoLastTarget);
+ private static QueueTarget m_QueueTarget;
+
+
+ private static uint m_SpellTargID = 0;
+ public static uint SpellTargetID { get { return m_SpellTargID; } set { m_SpellTargID = value; } }
+
+ private static List m_FilterCancel = new List();
+
+ public static bool HasTarget { get { return m_HasTarget; } }
+
+
+ private static List m_MonsterIds = new List()
+ {
+ 0x1, 0x2, 0x3, 0x4, 0x7, 0x8, 0x9, 0xC, 0xD, 0xE, 0xF,
+ 0x10, 0x11, 0x12, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
+ 0x1E, 0x1F, 0x21, 0x23, 0x24, 0x25, 0x27, 0x29, 0x2A, 0x2C,
+ 0x2D, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3B, 0x3C, 0x3D, 0x42, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4B, 0x4F, 0x50, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x59, 0x5A,
+ 0x5B, 0x5C, 0x5D, 0x5E, 0x60, 0x61, 0x62, 0x69, 0x6A, 0x6B, 0x6C,
+ 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x87, 0x88, 0x89,
+ 0x8A, 0x8B, 0x8C, 0x8E, 0x8F, 0x91, 0x93, 0x96, 0x99, 0x9B, 0x9E,
+ 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xB4, 0x4C, 0x4D, 0x3D
+ };
+
+ public static void Initialize()
+ {
+ PacketHandler.RegisterClientToServerViewer(0x6C, new PacketViewerCallback(TargetResponse));
+ PacketHandler.RegisterServerToClientViewer(0x6C, new PacketViewerCallback(NewTarget));
+ PacketHandler.RegisterServerToClientViewer(0xAA, new PacketViewerCallback(CombatantChange));
+
+
+ }
+
+ private static void CombatantChange(PacketReader p, PacketHandlerEventArgs e)
+ {
+ Serial ser = p.ReadUInt32();
+ if (ser.IsMobile && ser != World.Player.Serial && ser != Serial.Zero && ser != Serial.MinusOne)
+ m_LastCombatant = ser;
+ }
+
+ private static void AttackLastComb()
+ {
+ if (m_LastCombatant.IsMobile)
+ ClientCommunication.SendToServer(new AttackReq(m_LastCombatant));
+ }
+
+ private static void AttackLastTarg()
+ {
+ if (m_LastTarget != null && m_LastTarget.Serial.IsMobile)
+ ClientCommunication.SendToServer(new AttackReq(m_LastTarget.Serial));
+ }
+
+ private static void OnClearQueue()
+ {
+ ClearQueue();
+
+
+ }
+
+ internal static void OneTimeTarget(TargetResponseCallback onTarget)
+ {
+ OneTimeTarget(false, onTarget, null);
+ }
+
+ internal static void OneTimeTarget(bool ground, TargetResponseCallback onTarget)
+ {
+ OneTimeTarget(ground, onTarget, null);
+ }
+
+ internal static void OneTimeTarget(TargetResponseCallback onTarget, CancelTargetCallback onCancel)
+ {
+ OneTimeTarget(false, onTarget, onCancel);
+ }
+
+ internal static void OneTimeTarget(bool ground, TargetResponseCallback onTarget, CancelTargetCallback onCancel)
+ {
+ if (m_Intercept && m_OnCancel != null)
+ {
+ m_OnCancel();
+ CancelOneTimeTarget();
+ }
+
+ if (m_HasTarget && m_CurrentID != 0 && m_CurrentID != LocalTargID)
+ {
+ m_PreviousID = m_CurrentID;
+ m_PreviousGround = m_AllowGround;
+ m_PrevFlags = m_CurFlags;
+
+ m_FilterCancel.Add(m_PreviousID);
+ }
+
+ m_Intercept = true;
+ m_CurrentID = LocalTargID;
+ m_OnTarget = onTarget;
+ m_OnCancel = onCancel;
+
+ m_ClientTarget = m_HasTarget = true;
+ ClientCommunication.SendToClient(new Target(LocalTargID, ground));
+ ClearQueue();
+ }
+
+ internal static void CancelOneTimeTarget()
+ {
+ m_ClientTarget = m_HasTarget = false;
+
+ ClientCommunication.SendToClient(new CancelTarget(LocalTargID));
+ EndIntercept();
+ }
+
+ private static bool m_LTWasSet;
+ public static void TargetSetLastTarget()
+ {
+ if (World.Player != null)
+ {
+ m_LTWasSet = false;
+ OneTimeTarget(false, new TargetResponseCallback(OnSetLastTarget), new CancelTargetCallback(OnSLTCancel));
+ }
+ }
+
+ private static void OnSLTCancel()
+ {
+ if (m_LastTarget != null)
+ m_LTWasSet = true;
+ }
+
+ private static void OnSetLastTarget(bool location, Serial serial, Point3D p, ushort gfxid)
+ {
+ if (serial == World.Player.Serial)
+ {
+ OnSLTCancel();
+ return;
+ }
+
+ m_LastBeneTarg = m_LastHarmTarg = m_LastGroundTarg = m_LastTarget = new TargetInfo();
+ m_LastTarget.Flags = 0;
+ m_LastTarget.Gfx = gfxid;
+ m_LastTarget.Serial = serial;
+ m_LastTarget.Type = (byte)(location ? 1 : 0);
+ m_LastTarget.X = p.X;
+ m_LastTarget.Y = p.Y;
+ m_LastTarget.Z = p.Z;
+
+ m_LTWasSet = true;
+
+ if (serial.IsMobile)
+ {
+ LastTargetChanged();
+ ClientCommunication.SendToClient(new ChangeCombatant(serial));
+ m_LastCombatant = serial;
+ }
+ }
+
+ private static Serial m_OldLT = Serial.Zero;
+
+ private static void RemoveTextFlags(UOEntity m)
+ {
+ if (m != null)
+ {
+ bool oplchanged = false;
+
+ if (oplchanged)
+ m.OPLChanged();
+ }
+ }
+
+ private static void AddTextFlags(UOEntity m)
+ {
+
+ }
+
+ private static void LastTargetChanged()
+ {
+ if (m_LastTarget != null)
+ {
+ bool lth = Config.GetInt("LTHilight") != 0;
+
+ if (m_OldLT.IsItem)
+ {
+ RemoveTextFlags(World.FindItem(m_OldLT));
+ }
+ else
+ {
+ Mobile m = World.FindMobile(m_OldLT);
+ if (m != null)
+ {
+ if (lth)
+ ClientCommunication.SendToClient(new MobileIncoming(m));
+
+ RemoveTextFlags(m);
+ }
+ }
+
+ if (m_LastTarget.Serial.IsItem)
+ {
+ AddTextFlags(World.FindItem(m_LastTarget.Serial));
+ }
+ else
+ {
+ Mobile m = World.FindMobile(m_LastTarget.Serial);
+ if (m != null)
+ {
+ if (IsLastTarget(m) && lth)
+ ClientCommunication.SendToClient(new MobileIncoming(m));
+
+ CheckLastTargetRange(m);
+
+ AddTextFlags(m);
+ }
+ }
+
+ m_OldLT = m_LastTarget.Serial;
+ }
+ }
+
+ public static bool LTWasSet { get { return m_LTWasSet; } }
+
+ public static void TargetRandNonFriendly()
+ {
+ RandomTarget(3, 4, 5, 6);
+ }
+
+ public static void TargetRandFriendly()
+ {
+ RandomTarget(0, 1, 2);
+ }
+
+ public static void TargetRandEnemy()
+ {
+ RandomTarget(5);
+ }
+
+ public static void TargetRandEnemyMonster()
+ {
+ RandomMonsterTarget(5);
+ }
+
+ public static void TargetRandEnemyHumanoid()
+ {
+ RandomHumanoidTarget(5);
+ }
+
+ public static void TargetRandRed()
+ {
+ RandomTarget(6);
+ }
+
+ public static void TargetRandGrey()
+ {
+ RandomTarget(3, 4);
+ }
+
+ public static void TargetRandGreyMonster()
+ {
+ RandomMonsterTarget(3, 4);
+ }
+
+ public static void TargetRandGreyHumanoid()
+ {
+ RandomHumanoidTarget(3, 4);
+ }
+
+ public static void TargetRandCriminal()
+ {
+ RandomTarget(4);
+ }
+
+ public static void TargetRandCriminalHumanoid()
+ {
+ RandomHumanoidTarget(4);
+ }
+
+ public static void TargetRandInnocent()
+ {
+ RandomTarget(1);
+ }
+
+ public static void TargetRandInnocentHumanoid()
+ {
+ RandomHumanoidTarget(1);
+ }
+
+ public static void TargetRandAnyone()
+ {
+ RandomTarget();
+ }
+
+ public static void RandomTarget(params int[] noto)
+ {
+
+
+ List list = new List();
+ foreach (Mobile m in World.MobilesInRange(12))
+ {
+ if ((noto.Length > 0 && noto[0] == 0) &&
+ !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&
+ Utility.InRange(World.Player.Position, m.Position, Config.GetInt("LTRange")))
+ {
+ for (int i = 0; i < noto.Length; i++)
+ {
+ if (noto[i] == m.Notoriety)
+ {
+ list.Add(m);
+ break;
+ }
+ }
+
+ if (noto.Length == 0)
+ list.Add(m);
+ }
+ }
+
+ if (list.Count > 0)
+ SetLastTargetTo((Mobile)list[Utility.Random(list.Count)]);
+
+ }
+
+ public static void RandomHumanoidTarget(params int[] noto)
+ {
+
+
+ List list = new List();
+ foreach (Mobile m in World.MobilesInRange(12))
+ {
+ if (m.Body != 0x0190 && m.Body != 0x0191 && m.Body != 0x025D && m.Body != 0x025E)
+ continue;
+
+ if ((noto.Length > 0 && noto[0] == 0) &&
+ !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&
+ Utility.InRange(World.Player.Position, m.Position, Config.GetInt("LTRange")))
+ {
+ for (int i = 0; i < noto.Length; i++)
+ {
+ if (noto[i] == m.Notoriety)
+ {
+ list.Add(m);
+ break;
+ }
+ }
+
+ if (noto.Length == 0)
+ list.Add(m);
+ }
+ }
+
+ if (list.Count > 0)
+ SetLastTargetTo(list[Utility.Random(list.Count)]);
+
+ }
+
+ public static void RandomMonsterTarget(params int[] noto)
+ {
+
+
+ List list = new List();
+ foreach (Mobile m in World.MobilesInRange(12))
+ {
+ if (!m.IsMonster)
+ continue;
+
+ if ((noto.Length > 0 && noto[0] == 0) &&
+ !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&
+ Utility.InRange(World.Player.Position, m.Position, Config.GetInt("LTRange")))
+ {
+ for (int i = 0; i < noto.Length; i++)
+ {
+ if (noto[i] == m.Notoriety)
+ {
+ list.Add(m);
+ break;
+ }
+ }
+
+ if (noto.Length == 0)
+ list.Add(m);
+ }
+ }
+
+ if (list.Count > 0)
+ SetLastTargetTo(list[Utility.Random(list.Count)]);
+
+ }
+
+
+ public static void TargetCloseNonFriendly()
+ {
+ ClosestTarget(3, 4, 5, 6);
+ }
+
+ public static void TargetCloseFriendly()
+ {
+ ClosestTarget(0, 1, 2);
+ }
+
+ public static void TargetCloseEnemy()
+ {
+ ClosestTarget(5);
+ }
+
+ public static void TargetCloseEnemyHumanoid()
+ {
+ ClosestHumanoidTarget(5);
+ }
+
+ public static void TargetCloseEnemyMonster()
+ {
+ ClosestMonsterTarget(5);
+ }
+
+ public static void TargetCloseRed()
+ {
+ ClosestTarget(6);
+ }
+
+ public static void TargetCloseGrey()
+ {
+ ClosestTarget(3, 4);
+ }
+
+ public static void TargetCloseGreyMonster()
+ {
+ ClosestMonsterTarget(3, 4);
+ }
+
+ public static void TargetCloseGreyHumanoid()
+ {
+ ClosestHumanoidTarget(3, 4);
+ }
+
+ public static void TargetCloseCriminal()
+ {
+ ClosestTarget(4);
+ }
+
+ public static void TargetCloseCriminalHumanoid()
+ {
+ ClosestHumanoidTarget(4);
+ }
+
+ public static void TargetCloseInnocent()
+ {
+ ClosestTarget(1);
+ }
+
+ public static void TargetCloseInnocentHumanoid()
+ {
+ ClosestHumanoidTarget(1);
+ }
+
+ public static void TargetClosest()
+ {
+ ClosestTarget();
+ }
+
+ public static void ClosestTarget(params int[] noto)
+ {
+
+
+ List list = new List();
+ foreach (Mobile m in World.MobilesInRange(12))
+ {
+ if ((noto.Length > 0 && noto[0] == 0) &&
+ !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&
+ Utility.InRange(World.Player.Position, m.Position, Config.GetInt("LTRange")))
+ {
+ for (int i = 0; i < noto.Length; i++)
+ {
+ if (noto[i] == m.Notoriety)
+ {
+ list.Add(m);
+ break;
+ }
+ }
+
+ if (noto.Length == 0)
+ list.Add(m);
+ }
+ }
+
+ Mobile closest = null;
+ double closestDist = double.MaxValue;
+
+ foreach (Mobile m in list)
+ {
+ double dist = Utility.DistanceSqrt(m.Position, World.Player.Position);
+
+ if (dist < closestDist || closest == null)
+ {
+ closestDist = dist;
+ closest = m;
+ }
+ }
+
+ if (closest != null)
+ SetLastTargetTo(closest);
+;
+ }
+
+ public static void ClosestHumanoidTarget(params int[] noto)
+ {
+
+
+ List list = new List();
+ foreach (Mobile m in World.MobilesInRange(12))
+ {
+ if (m.Body != 0x0190 && m.Body != 0x0191 && m.Body != 0x025D && m.Body != 0x025E)
+ continue;
+
+ if (((noto.Length > 0 && noto[0] == 0)) &&
+ !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&
+ Utility.InRange(World.Player.Position, m.Position, Config.GetInt("LTRange")))
+ {
+ for (int i = 0; i < noto.Length; i++)
+ {
+ if (noto[i] == m.Notoriety)
+ {
+ list.Add(m);
+ break;
+ }
+ }
+
+ if (noto.Length == 0)
+ list.Add(m);
+ }
+ }
+
+ Mobile closest = null;
+ double closestDist = double.MaxValue;
+
+ foreach (Mobile m in list)
+ {
+ double dist = Utility.DistanceSqrt(m.Position, World.Player.Position);
+
+ if (dist < closestDist || closest == null)
+ {
+ closestDist = dist;
+ closest = m;
+ }
+ }
+
+ if (closest != null)
+ SetLastTargetTo(closest);
+
+ }
+
+ public static void ClosestMonsterTarget(params int[] noto)
+ {
+
+
+ List list = new List();
+ foreach (Mobile m in World.MobilesInRange(12))
+ {
+ if (!m.IsMonster)
+ continue;
+
+ if (((noto.Length > 0 && noto[0] == 0)) &&
+ !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&
+ Utility.InRange(World.Player.Position, m.Position, Config.GetInt("LTRange")))
+ {
+ for (int i = 0; i < noto.Length; i++)
+ {
+ if (noto[i] == m.Notoriety)
+ {
+ list.Add(m);
+ break;
+ }
+ }
+
+ if (noto.Length == 0)
+ list.Add(m);
+ }
+ }
+
+ Mobile closest = null;
+ double closestDist = double.MaxValue;
+
+ foreach (Mobile m in list)
+ {
+ double dist = Utility.DistanceSqrt(m.Position, World.Player.Position);
+
+ if (dist < closestDist || closest == null)
+ {
+ closestDist = dist;
+ closest = m;
+ }
+ }
+
+ if (closest != null)
+ SetLastTargetTo(closest);
+
+ }
+ public static void SetLastTargetTo( uint serial )
+ {
+ TargetInfo targ = new TargetInfo();
+ m_LastGroundTarg = m_LastTarget = targ;
+
+ var m = World.FindEntity( serial );
+
+ targ.Type = 0;
+ if ( m_HasTarget )
+ targ.Flags = m_CurFlags;
+
+
+ targ.Gfx = m.GraphicID;
+ targ.Serial = m.Serial;
+ targ.X = m.Position.X;
+ targ.Y = m.Position.Y;
+ targ.Z = m.Position.Z;
+ }
+ public static void SetLastTargetTo(Mobile m)
+ {
+ SetLastTargetTo(m, 0);
+ }
+
+ public static void SetLastTargetTo(Mobile m, byte flagType)
+ {
+ TargetInfo targ = new TargetInfo();
+ m_LastGroundTarg = m_LastTarget = targ;
+
+ if ((m_HasTarget && m_CurFlags == 1) || flagType == 1)
+ m_LastHarmTarg = targ;
+ else if ((m_HasTarget && m_CurFlags == 2) || flagType == 2)
+ m_LastBeneTarg = targ;
+ else if (flagType == 0)
+ m_LastHarmTarg = m_LastBeneTarg = targ;
+
+ targ.Type = 0;
+ if (m_HasTarget)
+ targ.Flags = m_CurFlags;
+ else
+ targ.Flags = flagType;
+
+ targ.Gfx = m.Body;
+ targ.Serial = m.Serial;
+ targ.X = m.Position.X;
+ targ.Y = m.Position.Y;
+ targ.Z = m.Position.Z;
+
+ ClientCommunication.SendToClient(new ChangeCombatant(m));
+ m_LastCombatant = m.Serial;
+
+
+ TargetLast();
+ LastTargetChanged();
+ }
+
+ private static void EndIntercept()
+ {
+ m_Intercept = false;
+ m_OnTarget = null;
+ m_OnCancel = null;
+ }
+
+ public static void TargetSelf()
+ {
+ TargetSelf(false);
+ }
+
+ public static void TargetSelf(bool forceQ)
+ {
+ if (World.Player == null)
+ return;
+
+ //if ( Macros.MacroManager.AcceptActions )
+ // MacroManager.Action( new TargetSelfAction() );
+
+ if (m_HasTarget)
+ {
+ if (!DoTargetSelf())
+ ResendTarget();
+ }
+ else if (forceQ || Config.GetBool("QueueTargets"))
+ {
+
+ m_QueueTarget = TargetSelfAction;
+ }
+ }
+
+ public static bool DoTargetSelf()
+ {
+ if (World.Player == null)
+ return false;
+
+ if (CheckHealPoisonTarg(m_CurrentID, World.Player.Serial))
+ return false;
+
+ CancelClientTarget();
+ m_HasTarget = false;
+
+ if (m_Intercept)
+ {
+ TargetInfo targ = new TargetInfo();
+ targ.Serial = World.Player.Serial;
+ targ.Gfx = World.Player.Body;
+ targ.Type = 0;
+ targ.X = World.Player.Position.X;
+ targ.Y = World.Player.Position.Y;
+ targ.Z = World.Player.Position.Z;
+ targ.TargID = LocalTargID;
+ targ.Flags = 0;
+
+ OneTimeResponse(targ);
+ }
+ else
+ {
+ ClientCommunication.SendToServer(new TargetResponse(m_CurrentID, World.Player));
+ }
+
+ return true;
+ }
+
+ public static void TargetLast()
+ {
+ TargetLast( false);
+ }
+
+ public static void TargetLast( bool forceQ)
+ {
+ //if ( Macros.MacroManager.AcceptActions )
+ // MacroManager.Action( new LastTargetAction() );
+
+ if (m_HasTarget)
+ {
+ if (!DoLastTarget())
+ ResendTarget();
+ }
+ else if (forceQ || Config.GetBool("QueueTargets"))
+ {
+
+
+ m_QueueTarget = LastTargetAction;
+ }
+ }
+
+ public static bool DoLastTarget()
+ {
+ TargetInfo targ;
+ if (Config.GetBool("SmartLastTarget"))
+ {
+ if (m_AllowGround && m_LastGroundTarg != null)
+ targ = m_LastGroundTarg;
+ else if (m_CurFlags == 1)
+ targ = m_LastHarmTarg;
+ else if (m_CurFlags == 2)
+ targ = m_LastBeneTarg;
+ else
+ targ = m_LastTarget;
+
+ if (targ == null)
+ targ = m_LastTarget;
+ }
+ else
+ {
+ if (m_AllowGround && m_LastGroundTarg != null)
+ targ = m_LastGroundTarg;
+ else
+ targ = m_LastTarget;
+ }
+
+ if (targ == null)
+ return false;
+
+ Point3D pos = Point3D.Zero;
+ if (targ.Serial.IsMobile)
+ {
+ Mobile m = World.FindMobile(targ.Serial);
+ if (m != null)
+ {
+ pos = m.Position;
+
+ targ.X = pos.X;
+ targ.Y = pos.Y;
+ targ.Z = pos.Z;
+ }
+ else
+ {
+ pos = Point3D.Zero;
+ }
+ }
+ else if (targ.Serial.IsItem)
+ {
+ Item i = World.FindItem(targ.Serial);
+ if (i != null)
+ {
+ pos = i.GetWorldPosition();
+
+ targ.X = i.Position.X;
+ targ.Y = i.Position.Y;
+ targ.Z = i.Position.Z;
+ }
+ else
+ {
+ pos = Point3D.Zero;
+ targ.X = targ.Y = targ.Z = 0;
+ }
+ }
+ else
+ {
+ if (!m_AllowGround && (targ.Serial == Serial.Zero || targ.Serial >= 0x80000000))
+ {
+ return false;
+ }
+ else
+ {
+ pos = new Point3D(targ.X, targ.Y, targ.Z);
+ }
+ }
+
+ if (Config.GetBool("RangeCheckLT") && (pos == Point3D.Zero || !Utility.InRange(World.Player.Position, pos, Config.GetInt("LTRange"))))
+ {
+ if (Config.GetBool("QueueTargets"))
+ m_QueueTarget = LastTargetAction;
+ return false;
+ }
+
+ if (CheckHealPoisonTarg(m_CurrentID, targ.Serial))
+ return false;
+
+ CancelClientTarget();
+ m_HasTarget = false;
+
+ targ.TargID = m_CurrentID;
+
+ if (m_Intercept)
+ OneTimeResponse(targ);
+ else
+ ClientCommunication.SendToServer(new TargetResponse(targ));
+ return true;
+ }
+
+ public static void ClearQueue()
+ {
+ m_QueueTarget = null;
+ }
+
+ private static TimerCallbackState m_OneTimeRespCallback = new TimerCallbackState(OneTimeResponse);
+
+ private static void OneTimeResponse(object state)
+ {
+ TargetInfo info = state as TargetInfo;
+
+ if (info != null)
+ {
+ if ((info.X == 0xFFFF && info.X == 0xFFFF) && (info.Serial == 0 || info.Serial >= 0x80000000))
+ {
+ if (m_OnCancel != null)
+ m_OnCancel();
+ }
+ else
+ {
+
+ if (m_OnTarget != null)
+ m_OnTarget(info.Type == 1 ? true : false, info.Serial, new Point3D(info.X, info.Y, info.Z), info.Gfx);
+ }
+ }
+
+ EndIntercept();
+ }
+
+ private static void CancelTarget()
+ {
+ OnClearQueue();
+ CancelClientTarget();
+
+ if (m_HasTarget)
+ {
+ ClientCommunication.SendToServer(new TargetCancelResponse(m_CurrentID));
+ m_HasTarget = false;
+ }
+ }
+
+ private static void CancelClientTarget()
+ {
+ if (m_ClientTarget)
+ {
+ m_FilterCancel.Add((uint)m_CurrentID);
+ ClientCommunication.SendToClient(new CancelTarget(m_CurrentID));
+ m_ClientTarget = false;
+ }
+ }
+
+ public static void Target(TargetInfo info)
+ {
+ if (m_Intercept)
+ {
+ OneTimeResponse(info);
+ }
+ else if (m_HasTarget)
+ {
+ info.TargID = m_CurrentID;
+ m_LastGroundTarg = m_LastTarget = info;
+ ClientCommunication.SendToServer(new TargetResponse(info));
+ }
+
+ CancelClientTarget();
+ m_HasTarget = false;
+ }
+
+ public static void Target(Point3D pt)
+ {
+ TargetInfo info = new TargetInfo();
+ info.Type = 1;
+ info.Flags = 0;
+ info.Serial = 0;
+ info.X = pt.X;
+ info.Y = pt.Y;
+ info.Z = pt.Z;
+ info.Gfx = 0;
+
+ Target(info);
+ }
+
+ public static void Target(Point3D pt, int gfx)
+ {
+ TargetInfo info = new TargetInfo();
+ info.Type = 1;
+ info.Flags = 0;
+ info.Serial = 0;
+ info.X = pt.X;
+ info.Y = pt.Y;
+ info.Z = pt.Z;
+ info.Gfx = (ushort)(gfx & 0x3FFF);
+
+ Target(info);
+ }
+
+ public static void Target(Serial s)
+ {
+ TargetInfo info = new TargetInfo();
+ info.Type = 0;
+ info.Flags = 0;
+ info.Serial = s;
+
+ if (s.IsItem)
+ {
+ Item item = World.FindItem(s);
+ if (item != null)
+ {
+ info.X = item.Position.X;
+ info.Y = item.Position.Y;
+ info.Z = item.Position.Z;
+ info.Gfx = item.ItemID;
+ }
+ }
+ else if (s.IsMobile)
+ {
+ Mobile m = World.FindMobile(s);
+ if (m != null)
+ {
+ info.X = m.Position.X;
+ info.Y = m.Position.Y;
+ info.Z = m.Position.Z;
+ info.Gfx = m.Body;
+ }
+ }
+
+ Target(info);
+ }
+
+ public static void Target(object o)
+ {
+ if (o is Item)
+ {
+ Item item = (Item)o;
+ TargetInfo info = new TargetInfo();
+ info.Type = 0;
+ info.Flags = 0;
+ info.Serial = item.Serial;
+ info.X = item.Position.X;
+ info.Y = item.Position.Y;
+ info.Z = item.Position.Z;
+ info.Gfx = item.ItemID;
+ Target(info);
+ }
+ else if (o is Mobile)
+ {
+ Mobile m = (Mobile)o;
+ TargetInfo info = new TargetInfo();
+ info.Type = 0;
+ info.Flags = 0;
+ info.Serial = m.Serial;
+ info.X = m.Position.X;
+ info.Y = m.Position.Y;
+ info.Z = m.Position.Z;
+ info.Gfx = m.Body;
+ Target(info);
+ }
+ else if (o is Serial)
+ {
+ Target((Serial)o);
+ }
+ else if (o is TargetInfo)
+ {
+ Target((TargetInfo)o);
+ }
+ }
+
+ public static void CheckTextFlags(Mobile m)
+ {
+
+
+ }
+
+ public static bool IsLastTarget(Mobile m)
+ {
+ if (m != null)
+ {
+ if (Config.GetBool("SmartLastTarget"))
+ {
+ if (m_LastHarmTarg != null && m_LastHarmTarg.Serial == m.Serial)
+ return true;
+ }
+ else
+ {
+ if (m_LastTarget != null && m_LastTarget.Serial == m.Serial)
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static int m_NextPrevTargIdx = 0;
+ public static void NextTarget()
+ {
+ List list = World.MobilesInRange(12);
+ TargetInfo targ = new TargetInfo();
+ Mobile m = null, old = World.FindMobile(m_LastTarget == null ? Serial.Zero : m_LastTarget.Serial);
+
+ if (list.Count <= 0)
+ {
+
+ return;
+ }
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_NextPrevTargIdx++;
+
+ if (m_NextPrevTargIdx >= list.Count)
+ m_NextPrevTargIdx = 0;
+
+ m = (Mobile)list[m_NextPrevTargIdx];
+
+ if (m != null && m != World.Player && m != old)
+ break;
+ else
+ m = null;
+ }
+
+ if (m == null)
+ m = old;
+
+ if (m == null)
+ {
+
+ return;
+ }
+
+ m_LastGroundTarg = m_LastTarget = targ;
+
+ m_LastHarmTarg = m_LastBeneTarg = targ;
+
+ if (m_HasTarget)
+ targ.Flags = m_CurFlags;
+ else
+ targ.Type = 0;
+
+ targ.Gfx = m.Body;
+ targ.Serial = m.Serial;
+ targ.X = m.Position.X;
+ targ.Y = m.Position.Y;
+ targ.Z = m.Position.Z;
+
+ ClientCommunication.SendToClient(new ChangeCombatant(m));
+ m_LastCombatant = m.Serial;
+
+ /*if ( m_HasTarget )
+ {
+ DoLastTarget();
+ ClearQueue();
+ }*/
+ }
+
+ private static int m_NextPrevTargHumanoidIdx = 0;
+ public static void NextTargetHumanoid()
+ {
+ List mobiles = World.MobilesInRange(12);
+ List list = new List();
+
+ foreach (Mobile mob in mobiles)
+ {
+ if (mob.Body == 0x0190 || mob.Body == 0x0191 || mob.Body == 0x025D || mob.Body == 0x025E)
+ list.Add(mob);
+ }
+
+ if (list.Count <= 0)
+ {
+ return;
+ }
+
+ TargetInfo targ = new TargetInfo();
+ Mobile m = null, old = World.FindMobile(m_LastTarget == null ? Serial.Zero : m_LastTarget.Serial);
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_NextPrevTargHumanoidIdx++;
+
+ if (m_NextPrevTargHumanoidIdx >= list.Count)
+ m_NextPrevTargHumanoidIdx = 0;
+
+ m = (Mobile)list[m_NextPrevTargHumanoidIdx];
+
+ if (m != null && m != World.Player && m != old)
+ break;
+ else
+ m = null;
+ }
+
+ if (m == null)
+ m = old;
+
+ if (m == null)
+ {
+ return;
+ }
+
+ m_LastGroundTarg = m_LastTarget = targ;
+
+ m_LastHarmTarg = m_LastBeneTarg = targ;
+
+ if (m_HasTarget)
+ targ.Flags = m_CurFlags;
+ else
+ targ.Type = 0;
+
+ targ.Gfx = m.Body;
+ targ.Serial = m.Serial;
+ targ.X = m.Position.X;
+ targ.Y = m.Position.Y;
+ targ.Z = m.Position.Z;
+
+ ClientCommunication.SendToClient(new ChangeCombatant(m));
+ m_LastCombatant = m.Serial;
+
+ /*if ( m_HasTarget )
+ {
+ DoLastTarget();
+ ClearQueue();
+ }*/
+ }
+
+ private static int m_NextPrevTargEnemyHumanoidIdx = 0;
+ public static void NextTargetEnemyHumanoid()
+ {
+ List mobiles = World.MobilesInRange(12);
+ List list = new List();
+
+ foreach (Mobile mob in mobiles)
+ {
+ if (mob.Body == 0x0190 || mob.Body == 0x0191 || mob.Body == 0x025D || mob.Body == 0x025E)
+ {
+ if (mob.Notoriety == 5) // Check if they are red
+ {
+ list.Add(mob);
+ }
+ }
+ }
+
+ if (list.Count <= 0)
+ {
+ return;
+ }
+
+ TargetInfo targ = new TargetInfo();
+ Mobile m = null, old = World.FindMobile(m_LastTarget == null ? Serial.Zero : m_LastTarget.Serial);
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_NextPrevTargEnemyHumanoidIdx++;
+
+ if (m_NextPrevTargEnemyHumanoidIdx >= list.Count)
+ m_NextPrevTargEnemyHumanoidIdx = 0;
+
+ m = list[m_NextPrevTargEnemyHumanoidIdx];
+
+ if (m != null && m != World.Player && m != old)
+ break;
+ else
+ m = null;
+ }
+
+ if (m == null)
+ m = old;
+
+ if (m == null)
+ {
+ return;
+ }
+
+ m_LastGroundTarg = m_LastTarget = targ;
+
+ m_LastHarmTarg = m_LastBeneTarg = targ;
+
+ if (m_HasTarget)
+ targ.Flags = m_CurFlags;
+ else
+ targ.Type = 0;
+
+ targ.Gfx = m.Body;
+ targ.Serial = m.Serial;
+ targ.X = m.Position.X;
+ targ.Y = m.Position.Y;
+ targ.Z = m.Position.Z;
+
+ ClientCommunication.SendToClient(new ChangeCombatant(m));
+ m_LastCombatant = m.Serial;
+
+ /*if ( m_HasTarget )
+ {
+ DoLastTarget();
+ ClearQueue();
+ }*/
+ }
+
+ public static void PrevTarget()
+ {
+ List list = World.MobilesInRange(12);
+ TargetInfo targ = new TargetInfo();
+ Mobile m = null, old = World.FindMobile(m_LastTarget == null ? Serial.Zero : m_LastTarget.Serial);
+
+ if (list.Count <= 0)
+ {
+ return;
+ }
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_NextPrevTargIdx--;
+
+ if (m_NextPrevTargIdx < 0)
+ m_NextPrevTargIdx = list.Count - 1;
+
+ m = (Mobile)list[m_NextPrevTargIdx];
+
+ if (m != null && m != World.Player && m != old)
+ break;
+ else
+ m = null;
+ }
+
+ if (m == null)
+ m = old;
+
+ if (m == null)
+ {
+ return;
+ }
+
+ m_LastGroundTarg = m_LastTarget = targ;
+
+ m_LastHarmTarg = m_LastBeneTarg = targ;
+
+ if (m_HasTarget)
+ targ.Flags = m_CurFlags;
+ else
+ targ.Type = 0;
+
+ targ.Gfx = m.Body;
+ targ.Serial = m.Serial;
+ targ.X = m.Position.X;
+ targ.Y = m.Position.Y;
+ targ.Z = m.Position.Z;
+
+ ClientCommunication.SendToClient(new ChangeCombatant(m));
+ m_LastCombatant = m.Serial;
+ }
+
+ public static void PrevTargetHumanoid()
+ {
+ List mobiles = World.MobilesInRange(12);
+ List list = new List();
+
+ foreach (Mobile mob in mobiles)
+ {
+ if (mob.Body == 0x0190 || mob.Body == 0x0191 || mob.Body == 0x025D || mob.Body == 0x025E)
+ list.Add(mob);
+ }
+
+ if (list.Count <= 0)
+ {
+ return;
+ }
+
+ TargetInfo targ = new TargetInfo();
+ Mobile m = null, old = World.FindMobile(m_LastTarget == null ? Serial.Zero : m_LastTarget.Serial);
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_NextPrevTargHumanoidIdx--;
+
+ if (m_NextPrevTargHumanoidIdx < 0)
+ m_NextPrevTargHumanoidIdx = list.Count - 1;
+
+ m = (Mobile)list[m_NextPrevTargHumanoidIdx];
+
+ if (m != null && m != World.Player && m != old)
+ break;
+ else
+ m = null;
+ }
+
+ if (m == null)
+ m = old;
+
+ if (m == null)
+ {
+ return;
+ }
+
+ m_LastGroundTarg = m_LastTarget = targ;
+
+ m_LastHarmTarg = m_LastBeneTarg = targ;
+
+ if (m_HasTarget)
+ targ.Flags = m_CurFlags;
+ else
+ targ.Type = 0;
+
+ targ.Gfx = m.Body;
+ targ.Serial = m.Serial;
+ targ.X = m.Position.X;
+ targ.Y = m.Position.Y;
+ targ.Z = m.Position.Z;
+
+ ClientCommunication.SendToClient(new ChangeCombatant(m));
+ m_LastCombatant = m.Serial;
+
+ /*if ( m_HasTarget )
+ {
+ DoLastTarget();
+ ClearQueue();
+ }*/
+ }
+
+ public static void PrevTargetEnemyHumanoid()
+ {
+ List mobiles = World.MobilesInRange(12);
+ List list = new List();
+
+ foreach (Mobile mob in mobiles)
+ {
+ if (mob.Body == 0x0190 || mob.Body == 0x0191 || mob.Body == 0x025D || mob.Body == 0x025E)
+ {
+ if (mob.Notoriety == 5) // Check if they are red
+ {
+ list.Add(mob);
+ }
+ }
+ }
+
+ if (list.Count <= 0)
+ {
+ return;
+ }
+
+ TargetInfo targ = new TargetInfo();
+ Mobile m = null, old = World.FindMobile(m_LastTarget == null ? Serial.Zero : m_LastTarget.Serial);
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_NextPrevTargEnemyHumanoidIdx--;
+
+ if (m_NextPrevTargEnemyHumanoidIdx < 0)
+ m_NextPrevTargEnemyHumanoidIdx = list.Count - 1;
+
+ m = list[m_NextPrevTargEnemyHumanoidIdx];
+
+ if (m != null && m != World.Player && m != old)
+ break;
+ else
+ m = null;
+ }
+
+ if (m == null)
+ m = old;
+
+ if (m == null)
+ {
+ return;
+ }
+
+ m_LastGroundTarg = m_LastTarget = targ;
+
+ m_LastHarmTarg = m_LastBeneTarg = targ;
+
+ if (m_HasTarget)
+ targ.Flags = m_CurFlags;
+ else
+ targ.Type = 0;
+
+ targ.Gfx = m.Body;
+ targ.Serial = m.Serial;
+ targ.X = m.Position.X;
+ targ.Y = m.Position.Y;
+ targ.Z = m.Position.Z;
+
+ ClientCommunication.SendToClient(new ChangeCombatant(m));
+ m_LastCombatant = m.Serial;
+ }
+
+ public static void CheckLastTargetRange(Mobile m)
+ {
+ if (World.Player == null)
+ return;
+
+ if (m_HasTarget && m != null && m_LastTarget != null && m.Serial == m_LastTarget.Serial && m_QueueTarget == LastTargetAction)
+ {
+ if (Config.GetBool("RangeCheckLT") )
+ {
+ if (Utility.InRange(World.Player.Position, m.Position, Config.GetInt("LTRange")))
+ {
+ if (m_QueueTarget())
+ ClearQueue();
+ }
+ }
+ }
+ }
+
+ private static bool CheckHealPoisonTarg(uint targID, Serial ser)
+ {
+ if (World.Player == null)
+ return false;
+
+ if (targID == m_SpellTargID && ser.IsMobile && (World.Player.LastSpell == Spell.ToID(1, 4) || World.Player.LastSpell == Spell.ToID(4, 5)) && Config.GetBool("BlockHealPoison"))
+ {
+ Mobile m = World.FindMobile(ser);
+
+ if (m != null && m.Poisoned)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static void TargetResponse(PacketReader p, PacketHandlerEventArgs args)
+ {
+ TargetInfo info = new TargetInfo();
+ info.Type = p.ReadByte();
+ info.TargID = p.ReadUInt32();
+ info.Flags = p.ReadByte();
+ info.Serial = p.ReadUInt32();
+ info.X = p.ReadUInt16();
+ info.Y = p.ReadUInt16();
+ info.Z = p.ReadInt16();
+ info.Gfx = p.ReadUInt16();
+
+ m_ClientTarget = false;
+
+ //if (Config.GetBool("ShowAttackTargetOverhead"))
+ //{
+ // Mobile m = World.FindMobile(info.Serial);
+
+ // if (m != null)
+ // {
+ // if (FriendsAgent.IsFriend(m))
+ // {
+ // World.Player.OverheadMessage(63, $"Target: {m.Name}");
+ // }
+ // else
+ // {
+ // World.Player.OverheadMessage(m.GetNotorietyColorInt(), $"Target: {m.Name}");
+ // }
+ // }
+ //}
+
+ // check for cancel
+ if (info.X == 0xFFFF && info.X == 0xFFFF && (info.Serial <= 0 || info.Serial >= 0x80000000))
+ {
+ m_HasTarget = false;
+
+ if (m_Intercept)
+ {
+ args.Block = true;
+ Timer.DelayedCallbackState(TimeSpan.Zero, m_OneTimeRespCallback, info).Start();
+ EndIntercept();
+
+ if (m_PreviousID != 0)
+ {
+ m_CurrentID = m_PreviousID;
+ m_AllowGround = m_PreviousGround;
+ m_CurFlags = m_PrevFlags;
+
+ m_PreviousID = 0;
+
+ ResendTarget();
+ }
+ }
+ else if (m_FilterCancel.Contains((uint)info.TargID) || info.TargID == LocalTargID)
+ {
+ args.Block = true;
+ }
+
+ m_FilterCancel.Clear();
+ return;
+ }
+
+ ClearQueue();
+
+ if (m_Intercept)
+ {
+ if (info.TargID == LocalTargID)
+ {
+ Timer.DelayedCallbackState(TimeSpan.Zero, m_OneTimeRespCallback, info).Start();
+
+ m_HasTarget = false;
+ args.Block = true;
+
+ if (m_PreviousID != 0)
+ {
+ m_CurrentID = m_PreviousID;
+ m_AllowGround = m_PreviousGround;
+ m_CurFlags = m_PrevFlags;
+
+ m_PreviousID = 0;
+
+ ResendTarget();
+ }
+
+ m_FilterCancel.Clear();
+
+ return;
+ }
+ else
+ {
+ EndIntercept();
+ }
+ }
+
+ m_HasTarget = false;
+
+ if (CheckHealPoisonTarg(m_CurrentID, info.Serial))
+ {
+ ResendTarget();
+ args.Block = true;
+ }
+
+ if (info.Serial != World.Player.Serial)
+ {
+ if (info.Serial.IsValid)
+ {
+ // only let lasttarget be a non-ground target
+
+ m_LastTarget = info;
+ if (info.Flags == 1)
+ m_LastHarmTarg = info;
+ else if (info.Flags == 2)
+ m_LastBeneTarg = info;
+
+ LastTargetChanged();
+ }
+
+ m_LastGroundTarg = info; // ground target is the true last target
+
+
+ }
+ else
+ {
+
+ }
+
+
+
+ m_FilterCancel.Clear();
+ }
+
+ private static void NewTarget(PacketReader p, PacketHandlerEventArgs args)
+ {
+ bool prevAllowGround = m_AllowGround;
+ uint prevID = m_CurrentID;
+ byte prevFlags = m_CurFlags;
+ bool prevClientTarget = m_ClientTarget;
+
+ m_AllowGround = p.ReadBoolean(); // allow ground
+ m_CurrentID = p.ReadUInt32(); // target uid
+ m_CurFlags = p.ReadByte(); // flags
+ // the rest of the packet is 0s
+ // if (m_CurrentID == LocalTargID)
+ // return;
+ // check for a server cancel command
+ if (!m_AllowGround && m_CurrentID == 0 && m_CurFlags == 3)
+ {
+ m_HasTarget = false;
+ m_ClientTarget = false;
+ if (m_Intercept)
+ {
+ EndIntercept();
+ }
+ return;
+ }
+
+ if (Spell.LastCastTime + TimeSpan.FromSeconds(3.0) > DateTime.UtcNow && Spell.LastCastTime + TimeSpan.FromSeconds(0.5) <= DateTime.UtcNow && m_SpellTargID == 0)
+ m_SpellTargID = m_CurrentID;
+
+ m_HasTarget = true;
+ m_ClientTarget = false;
+
+if (m_QueueTarget != null && m_QueueTarget())
+ {
+ ClearQueue();
+ args.Block = true;
+ }
+
+ if (args.Block)
+ {
+ if (prevClientTarget)
+ {
+ m_AllowGround = prevAllowGround;
+ m_CurrentID = prevID;
+ m_CurFlags = prevFlags;
+
+ m_ClientTarget = true;
+
+ if (!m_Intercept)
+ CancelClientTarget();
+ }
+ }
+ else
+ {
+ m_ClientTarget = true;
+
+ if (m_Intercept)
+ {
+ if (m_OnCancel != null)
+ m_OnCancel();
+ EndIntercept();
+
+ m_FilterCancel.Add((uint)prevID);
+ }
+ }
+ }
+
+ public static void ResendTarget()
+ {
+ if (!m_ClientTarget || !m_HasTarget)
+ {
+ CancelClientTarget();
+ m_ClientTarget = m_HasTarget = true;
+ ClientCommunication.SendToClient(new Target(m_CurrentID, m_AllowGround, m_CurFlags));
+ }
+ }
+ }
+}
diff --git a/Core/Timer.cs b/Core/Timer.cs
new file mode 100644
index 0000000..a27a928
--- /dev/null
+++ b/Core/Timer.cs
@@ -0,0 +1,352 @@
+using System;
+using System.Collections.Generic;
+
+namespace Assistant
+{
+ public class MinHeap
+ {
+ private List m_List;
+ private int m_Size;
+
+ public MinHeap()
+ : this(1)
+ {
+ }
+
+ public MinHeap(int capacity)
+ {
+ m_List = new List(capacity + 1);
+ m_Size = 0;
+ m_List.Add(null); // 0th index is never used, always null
+ }
+
+ public MinHeap(ICollection c)
+ : this(c.Count)
+ {
+ foreach (IComparable o in c)
+ m_List.Add(o);
+ m_Size = c.Count;
+ Heapify();
+ }
+
+ public void Heapify()
+ {
+ for (int i = m_Size / 2; i > 0; i--)
+ PercolateDown(i);
+ }
+
+ private void PercolateDown(int hole)
+ {
+ IComparable tmp = m_List[hole];
+ int child;
+
+ for (; hole * 2 <= m_Size; hole = child)
+ {
+ child = hole * 2;
+ if (child != m_Size && (m_List[child + 1]).CompareTo(m_List[child]) < 0)
+ child++;
+
+ if (tmp.CompareTo(m_List[child]) >= 0)
+ m_List[hole] = m_List[child];
+ else
+ break;
+ }
+
+ m_List[hole] = tmp;
+ }
+
+ public IComparable Peek()
+ {
+ return m_List[1] as IComparable;
+ }
+
+ public IComparable Pop()
+ {
+ IComparable top = Peek();
+
+ m_List[1] = m_List[m_Size--];
+ PercolateDown(1);
+
+ return top;
+ }
+
+ public void Remove(IComparable o)
+ {
+ for (int i = 1; i <= m_Size; i++)
+ {
+ if (m_List[i] == o)
+ {
+ m_List[i] = m_List[m_Size--];
+ PercolateDown(i);
+ // TODO: Do we ever need to shrink?
+ return;
+ }
+ }
+ }
+
+ public void Clear()
+ {
+ int capacity = m_List.Count / 2;
+ if (capacity < 2)
+ capacity = 2;
+ m_Size = 0;
+ m_List = new List(capacity) { null };
+ }
+
+ public void Add(IComparable o)
+ {
+ // PercolateUp
+ int hole = ++m_Size;
+
+ // Grow the list if needed
+ while (m_List.Count <= m_Size)
+ m_List.Add(null);
+
+ for (; hole > 1 && o.CompareTo(m_List[hole / 2]) < 0; hole /= 2)
+ m_List[hole] = m_List[hole / 2];
+ m_List[hole] = o;
+ }
+
+ public void AddMultiple(ICollection col)
+ {
+ if (col == null || col.Count <= 0)
+ return;
+
+ foreach (IComparable o in col)
+ {
+ int hole = ++m_Size;
+
+ // Grow the list as needed
+ while (m_List.Count <= m_Size)
+ m_List.Add(null);
+
+ m_List[hole] = o;
+ }
+
+ Heapify();
+ }
+
+ public int Count { get { return m_Size; } }
+
+ public bool IsEmpty { get { return Count <= 0; } }
+
+ public List GetRawList()
+ {
+ List copy = new List(m_Size);
+ for (int i = 1; i <= m_Size; i++)
+ copy.Add(m_List[i]);
+ return copy;
+ }
+ }
+
+ public delegate void TimerCallback();
+
+ public delegate void TimerCallbackState(object state);
+
+ public abstract class Timer : IComparable
+ {
+ private DateTime m_Next;
+ private TimeSpan m_Delay;
+ private TimeSpan m_Interval;
+ private bool m_Running;
+ private int m_Index, m_Count;
+
+ protected abstract void OnTick();
+
+ public Timer(TimeSpan delay)
+ : this(delay, TimeSpan.Zero, 1)
+ {
+ }
+
+ public Timer(TimeSpan interval, int count)
+ : this(interval, interval, count)
+ {
+ }
+
+ public Timer(TimeSpan delay, TimeSpan interval)
+ : this(delay, interval, 0)
+ {
+ }
+
+ public Timer(TimeSpan delay, TimeSpan interval, int count)
+ {
+ m_Delay = delay;
+ m_Interval = interval;
+ m_Count = count;
+ }
+
+ public void Start()
+ {
+ if (!m_Running)
+ {
+ m_Index = 0;
+ m_Next = DateTime.Now + m_Delay;
+ m_Running = true;
+ m_Heap.Add(this);
+ ChangedNextTick(true);
+ }
+ }
+
+ public void Stop()
+ {
+ if (!m_Running)
+ return;
+
+ m_Running = false;
+ m_Heap.Remove(this);
+ //ChangedNextTick();
+ }
+
+ public int CompareTo(object obj)
+ {
+ if (obj is Timer)
+ return this.TimeUntilTick.CompareTo(((Timer)obj).TimeUntilTick);
+ else
+ return -1;
+ }
+
+ public TimeSpan TimeUntilTick
+ {
+ get { return m_Running ? m_Next - DateTime.Now : TimeSpan.MaxValue; }
+ }
+
+ public bool Running { get { return m_Running; } }
+
+ public TimeSpan Delay
+ {
+ get { return m_Delay; }
+ set { m_Delay = value; }
+ }
+
+ public TimeSpan Interval
+ {
+ get { return m_Interval; }
+ set { m_Interval = value; }
+ }
+
+ private static MinHeap m_Heap = new MinHeap();
+ private static System.Timers.Timer m_SystemTimer;
+
+ public static System.Timers.Timer SystemTimer
+ {
+ get { return m_SystemTimer; }
+ set
+ {
+ if (m_SystemTimer != value)
+ {
+ if (m_SystemTimer != null)
+ m_SystemTimer.Stop();
+ m_SystemTimer = value;
+ ChangedNextTick();
+ }
+ }
+ }
+
+ private static void ChangedNextTick()
+ {
+ ChangedNextTick(false);
+ }
+
+ private static void ChangedNextTick(bool allowImmediate)
+ {
+ if (m_SystemTimer == null)
+ return;
+
+ m_SystemTimer.Stop();
+
+ if (!m_Heap.IsEmpty)
+ {
+ int interval = (int)Math.Round(((Timer)m_Heap.Peek()).TimeUntilTick.TotalMilliseconds);
+ if (allowImmediate && interval <= 0)
+ {
+ Slice();
+ }
+ else
+ {
+ if (interval <= 0)
+ interval = 1;
+
+ m_SystemTimer.Interval = interval;
+ m_SystemTimer.Start();
+ }
+ }
+ }
+
+ public static void Slice()
+ {
+ int breakCount = 100;
+ List readd = new List();
+
+ while (!m_Heap.IsEmpty && ((Timer)m_Heap.Peek()).TimeUntilTick < TimeSpan.Zero)
+ {
+ if (breakCount-- <= 0)
+ break;
+
+ Timer t = (Timer)m_Heap.Pop();
+
+ if (t != null && t.Running)
+ {
+ t.OnTick();
+
+ if (t.Running && (t.m_Count == 0 || (++t.m_Index) < t.m_Count))
+ {
+ t.m_Next = DateTime.Now + t.m_Interval;
+ readd.Add(t);
+ }
+ else
+ {
+ t.Stop();
+ }
+ }
+ }
+
+ m_Heap.AddMultiple(readd);
+
+ ChangedNextTick();
+ }
+
+ private class OneTimeTimer : Timer
+ {
+ private TimerCallback m_Call;
+
+ public OneTimeTimer(TimeSpan d, TimerCallback call)
+ : base(d)
+ {
+ m_Call = call;
+ }
+
+ protected override void OnTick()
+ {
+ m_Call();
+ }
+ }
+
+ public static Timer DelayedCallback(TimeSpan delay, TimerCallback call)
+ {
+ return new OneTimeTimer(delay, call);
+ }
+
+ private class OneTimeTimerState : Timer
+ {
+ private TimerCallbackState m_Call;
+ private object m_State;
+
+ public OneTimeTimerState(TimeSpan d, TimerCallbackState call, object state)
+ : base(d)
+ {
+ m_Call = call;
+ m_State = state;
+ }
+
+ protected override void OnTick()
+ {
+ m_Call(m_State);
+ }
+ }
+
+ public static Timer DelayedCallbackState(TimeSpan delay, TimerCallbackState call, object state)
+ {
+ return new OneTimeTimerState(delay, call, state);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/UOEntity.cs b/Core/UOEntity.cs
new file mode 100644
index 0000000..2f7fba8
--- /dev/null
+++ b/Core/UOEntity.cs
@@ -0,0 +1,140 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Assistant
+{
+ public interface IUOEntity
+ {
+ Serial Serial { get; }
+ ushort GraphicID { get; }
+ Point3D Position { get; set; }
+ IUOEntity Parent { get; set; }
+ }
+ public class UOEntity
+ {
+ private Serial m_Serial;
+ private Point3D m_Pos;
+ private ushort m_Hue;
+ private bool m_Deleted;
+ private Dictionary m_ContextMenu = new Dictionary();
+ 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;
+ }
+
+ public Serial Serial{ get{ return m_Serial; } }
+
+ public virtual Point3D Position
+ {
+ get{ return m_Pos; }
+ set
+ {
+ if ( value != m_Pos )
+ {
+ var oldPos = m_Pos;
+ m_Pos = value;
+ OnPositionChanging( oldPos );
+ }
+ }
+ }
+
+ public bool Deleted
+ {
+ get
+ {
+ return m_Deleted;
+ }
+ }
+
+ public Dictionary ContextMenu
+ {
+ get { return m_ContextMenu; }
+ }
+
+ public virtual ushort Hue
+ {
+ get{ return m_Hue; }
+ set{ m_Hue = value; }
+ }
+
+ public virtual void Remove()
+ {
+ m_Deleted = true;
+ }
+
+ public virtual void OnPositionChanging( Point3D oldPos )
+ {
+ }
+
+ 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()
+ {
+ //ClientCommunication.SendToClient( m_ObjPropList.BuildPacket() );
+ ClientCommunication.SendToClient( new OPLInfo( Serial, OPLHash ) );
+ }
+ }
+}
diff --git a/Core/Utility.cs b/Core/Utility.cs
new file mode 100644
index 0000000..cf0e335
--- /dev/null
+++ b/Core/Utility.cs
@@ -0,0 +1,382 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+
+namespace Assistant
+{
+ public class Utility
+ {
+ public static string UintToEUO( uint Num )
+ {
+ uint bSys = 26;
+ uint bNum, cnt, cnt2;
+ string res = "";
+ char[] arr = new char[7];
+ bNum = ( Num ^ 69 ) + 7;
+ cnt = 0;
+ do
+ {
+ arr[cnt] = (char)( ( bNum % bSys ) + 65 );
+ if ( bNum < bSys ) break;
+ bNum = bNum / bSys;
+ cnt++;
+
+ } while ( true );
+
+ return new string( arr ).Trim( '\0' );
+ }
+
+ public static ushort EUO2StealthType( string EUO )
+ {
+ EUO = EUO.ToUpper();
+ uint a = 0;
+ uint i = 1;
+ foreach ( var c in EUO )
+ {
+ a += ( ( c - (uint)65 ) * i );
+ i *= 26;
+ }
+ a = ( a - 7 ) ^ 0x45;
+ if ( a > 0xFFFF )
+ return 0;
+
+ return (ushort)a;
+ }
+
+ public static uint EUO2StealthID( string EUO )
+ {
+ EUO = EUO.ToUpper();
+ uint ret = 0;
+ uint i = 1;
+ foreach ( var c in EUO )
+ {
+ ret += ( c - (uint)65 ) * i;
+ i *= 26;
+ }
+ return ( ret - 7 ) ^ 0x45;
+ }
+
+
+
+ private static Random m_Random = new Random();
+
+ public static int Random( int min, int max )
+ {
+ return m_Random.Next( max - min + 1 ) + min;
+ }
+
+ public static int Random( int num )
+ {
+ return m_Random.Next( num );
+ }
+
+ public static bool InRange( IPoint2D from, IPoint2D to, int range )
+ {
+ return ( to.X >= (from.X - range) )
+ && ( to.X <= (from.X + range) )
+ && ( to.Y >= (from.Y - range) )
+ && ( to.Y <= (from.Y + range) );
+ }
+
+ public static int Distance( int fx, int fy, int tx, int ty )
+ {
+ int xDelta = Math.Abs( fx - tx );
+ int yDelta = Math.Abs( fy - ty );
+
+ return ( xDelta > yDelta ? xDelta : yDelta );
+ }
+
+ public static int Distance( IPoint2D from, IPoint2D to )
+ {
+ int xDelta = Math.Abs( from.X - to.X );
+ int yDelta = Math.Abs( from.Y - to.Y );
+
+ return ( xDelta > yDelta ? xDelta : yDelta );
+ }
+
+ public static double DistanceSqrt( IPoint2D from, IPoint2D to )
+ {
+ float xDelta = Math.Abs( from.X - to.X );
+ float yDelta = Math.Abs( from.Y - to.Y );
+
+ return Math.Sqrt( xDelta*xDelta + yDelta*yDelta );
+ }
+
+ public static void Offset( Direction d, ref int x, ref int y )
+ {
+ switch ( d & Direction.Mask )
+ {
+ case Direction.North: --y; break;
+ case Direction.South: ++y; break;
+ case Direction.West: --x; break;
+ case Direction.East: ++x; break;
+ case Direction.Right: ++x; --y; break;
+ case Direction.Left: --x; ++y; break;
+ case Direction.Down: ++x; ++y; break;
+ case Direction.Up: --x; --y; break;
+ }
+ }
+
+ public static void FormatBuffer( TextWriter output, Stream input, int length )
+ {
+ output.WriteLine( " 0 1 2 3 4 5 6 7 8 9 A B C D E F" );
+ output.WriteLine( " -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" );
+
+ int byteIndex = 0;
+
+ int whole = length >> 4;
+ int rem = length & 0xF;
+
+ for ( int i = 0; i < whole; ++i, byteIndex += 16 )
+ {
+ StringBuilder bytes = new StringBuilder( 49 );
+ StringBuilder chars = new StringBuilder( 16 );
+
+ for ( int j = 0; j < 16; ++j )
+ {
+ int c = input.ReadByte();
+
+ bytes.Append( c.ToString( "X2" ) );
+
+ if ( j != 7 )
+ {
+ bytes.Append( ' ' );
+ }
+ else
+ {
+ bytes.Append( " " );
+ }
+
+ if ( c >= 0x20 && c < 0x80 )
+ {
+ chars.Append( (char)c );
+ }
+ else
+ {
+ chars.Append( '.' );
+ }
+ }
+
+ output.Write( byteIndex.ToString( "X4" ) );
+ output.Write( " " );
+ output.Write( bytes.ToString() );
+ output.Write( " " );
+ output.WriteLine( chars.ToString() );
+ }
+
+ if ( rem != 0 )
+ {
+ StringBuilder bytes = new StringBuilder( 49 );
+ StringBuilder chars = new StringBuilder( rem );
+
+ for ( int j = 0; j < 16; ++j )
+ {
+ if ( j < rem )
+ {
+ int c = input.ReadByte();
+
+ bytes.Append( c.ToString( "X2" ) );
+
+ if ( j != 7 )
+ {
+ bytes.Append( ' ' );
+ }
+ else
+ {
+ bytes.Append( " " );
+ }
+
+ if ( c >= 0x20 && c < 0x80 )
+ {
+ chars.Append( (char)c );
+ }
+ else
+ {
+ chars.Append( '.' );
+ }
+ }
+ else
+ {
+ bytes.Append( " " );
+ }
+ }
+
+ output.Write( byteIndex.ToString( "X4" ) );
+ output.Write( " " );
+ output.Write( bytes.ToString() );
+ if ( rem <= 8 )
+ output.Write( " " );
+ else
+ output.Write( " " );
+ output.WriteLine( chars.ToString() );
+ }
+ }
+
+ public static unsafe void FormatBuffer( TextWriter output, byte *buff, int length )
+ {
+ output.WriteLine( " 0 1 2 3 4 5 6 7 8 9 A B C D E F" );
+ output.WriteLine( " -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" );
+
+ int byteIndex = 0;
+
+ int whole = length >> 4;
+ int rem = length & 0xF;
+
+ for ( int i = 0; i < whole; ++i, byteIndex += 16 )
+ {
+ StringBuilder bytes = new StringBuilder( 49 );
+ StringBuilder chars = new StringBuilder( 16 );
+
+ for ( int j = 0; j < 16; ++j )
+ {
+ int c = *buff++;
+
+ bytes.Append( c.ToString( "X2" ) );
+
+ if ( j != 7 )
+ {
+ bytes.Append( ' ' );
+ }
+ else
+ {
+ bytes.Append( " " );
+ }
+
+ if ( c >= 0x20 && c < 0x80 )
+ {
+ chars.Append( (char)c );
+ }
+ else
+ {
+ chars.Append( '.' );
+ }
+ }
+
+ output.Write( byteIndex.ToString( "X4" ) );
+ output.Write( " " );
+ output.Write( bytes.ToString() );
+ output.Write( " " );
+ output.WriteLine( chars.ToString() );
+ }
+
+ if ( rem != 0 )
+ {
+ StringBuilder bytes = new StringBuilder( 49 );
+ StringBuilder chars = new StringBuilder( rem );
+
+ for ( int j = 0; j < 16; ++j )
+ {
+ if ( j < rem )
+ {
+ int c = *buff++;
+
+ bytes.Append( c.ToString( "X2" ) );
+
+ if ( j != 7 )
+ {
+ bytes.Append( ' ' );
+ }
+ else
+ {
+ bytes.Append( " " );
+ }
+
+ if ( c >= 0x20 && c < 0x80 )
+ {
+ chars.Append( (char)c );
+ }
+ else
+ {
+ chars.Append( '.' );
+ }
+ }
+ else
+ {
+ bytes.Append( " " );
+ }
+ }
+
+ output.Write( byteIndex.ToString( "X4" ) );
+ output.Write( " " );
+ output.Write( bytes.ToString() );
+ if ( rem <= 8 )
+ output.Write( " " );
+ else
+ output.Write( " " );
+ output.WriteLine( chars.ToString() );
+ }
+ }
+
+ private static char[] pathChars = new char[]{ '\\', '/' };
+ public static string PathDisplayStr( string path, int maxLen )
+ {
+ if ( path == null || path.Length <= maxLen || path.Length < 5 )
+ return path;
+
+ int first = (maxLen - 3) / 2;
+ int last = path.LastIndexOfAny( pathChars );
+ if ( last == -1 || last < maxLen / 4 )
+ last = path.Length - first;
+ first = maxLen - last - 3;
+ if ( first < 0 )
+ first = 1;
+ if ( last < first )
+ last = first;
+
+ return String.Format( "{0}...{1}", path.Substring( 0, first ), path.Substring( last ) );
+ }
+
+ public static string FormatSize( long size )
+ {
+ if ( size < 1024 ) // 1 K
+ return String.Format( "{0:#,##0} B", size );
+ else if ( size < 1048576 ) // 1 M
+ return String.Format( "{0:#,###.0} KB", size / 1024.0 );
+ else
+ return String.Format( "{0:#,###.0} MB", size / 1048576.0 );
+ }
+
+ public static string FormatTime( int sec )
+ {
+ int m = sec/60;
+ int h = m/60;
+ m = m%60;
+ return String.Format( "{0:#0}:{1:00}:{2:00}", h, m, sec%60 );
+ }
+
+ public static string FormatTimeMS( int ms )
+ {
+ int s = ms/1000;
+ int m = s/60;
+ int h = m/60;
+
+ ms = ms%1000;
+ s = s%60;
+ m = m%60;
+
+ if ( h > 0 || m > 55 )
+ return String.Format( "{0:#0}:{1:00}:{2:00}.{3:000}", h, m, s, ms );
+ else
+ return String.Format( "{0:00}:{1:00}.{2:000}", m, s, ms );
+ }
+
+ public static int ToInt32( string str, int def )
+ {
+ if ( str == null )
+ return def;
+
+ try
+ {
+ if ( str.Length > 2 && str.Substring( 0, 2 ).ToLower() == "0x" )
+ return Convert.ToInt32( str.Substring( 2 ), 16 );
+ else
+ return Convert.ToInt32( str );
+ }
+ catch
+ {
+ return def;
+ }
+ }
+ }
+}
diff --git a/Core/World.cs b/Core/World.cs
new file mode 100644
index 0000000..1b8a3bf
--- /dev/null
+++ b/Core/World.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Assistant
+{
+ public class World
+ {
+ private static Dictionary m_Items;
+ private static Dictionary m_Mobiles;
+ private static PlayerData m_Player;
+ private static string m_ShardName, m_PlayerName, m_AccountName;
+ private static Dictionary m_Servers;
+
+ static World()
+ {
+ m_Servers = new Dictionary();
+ m_Items = new Dictionary();
+ m_Mobiles = new Dictionary();
+ m_ShardName = "[None]";
+ }
+
+ internal static Dictionary Servers { get { return m_Servers; } }
+ internal static Dictionary Items { get { return m_Items; } }
+ internal static Dictionary Mobiles { get { return m_Mobiles; } }
+
+ internal static IUOEntity FindEntity( Serial serial )
+ {
+ Item it;
+ m_Items.TryGetValue( serial, out it );
+ if(it != null)
+ return it;
+ Mobile m;
+ m_Mobiles.TryGetValue( serial, out m );
+ return m;
+ }
+
+ internal static Item FindItem( Serial serial )
+ {
+ Item it;
+ m_Items.TryGetValue(serial, out it);
+ return it;
+ }
+
+ internal static Mobile FindMobile( Serial serial )
+ {
+ Mobile m;
+ m_Mobiles.TryGetValue(serial, out m);
+ return m;
+ }
+
+ internal static List MobilesInRange( int range )
+ {
+ List list = new List();
+
+ if ( World.Player == null )
+ return list;
+
+ foreach ( Mobile m in World.Mobiles.Values )
+ {
+ if ( Utility.InRange( World.Player.Position, m.Position, World.Player.VisRange ) )
+ list.Add( m );
+ }
+
+ return list;
+ }
+
+ internal static List MobilesInRange()
+ {
+ if ( Player == null )
+ return MobilesInRange( 18 );
+ else
+ return MobilesInRange( Player.VisRange );
+ }
+
+ internal static void AddItem( Item item )
+ {
+ m_Items[item.Serial] = item;
+ }
+
+ internal static void AddMobile( Mobile mob )
+ {
+ m_Mobiles[mob.Serial] = mob;
+ }
+
+ internal static void RemoveMobile( Mobile mob )
+ {
+ m_Mobiles.Remove( mob.Serial );
+ }
+
+ internal static void RemoveItem( Item item )
+ {
+ m_Items.Remove( item.Serial );
+ }
+
+ internal static PlayerData Player
+ {
+ get{ return m_Player; }
+ set{ m_Player = value; }
+ }
+
+ internal static string ShardName
+ {
+ get{ return m_ShardName; }
+ set{ m_ShardName = value; }
+ }
+
+ internal static string OrigPlayerName
+ {
+ get { return m_PlayerName; }
+ set { m_PlayerName = value; }
+ }
+
+ internal static string AccountName
+ {
+ get { return m_AccountName; }
+ set { m_AccountName = value; }
+ }
+ }
+}
+
diff --git a/Engine.cs b/Engine.cs
new file mode 100644
index 0000000..31a57a2
--- /dev/null
+++ b/Engine.cs
@@ -0,0 +1,83 @@
+using CEasyUO;
+using CUO_API;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Assistant
+{
+ public class Engine
+ {
+
+ public Engine()
+ {
+
+ }
+ public static ClientVersions ClientVersion { get; private set; }
+
+ public static bool UseNewMobileIncoming => ClientVersion >= ClientVersions.CV_70331;
+
+ public static bool UsePostHSChanges => ClientVersion >= ClientVersions.CV_7090;
+
+ public static bool UsePostSAChanges => ClientVersion >= ClientVersions.CV_7000;
+
+ public static bool UsePostKRPackets => ClientVersion >= ClientVersions.CV_6017;
+ private static string _rootPath = null;
+ public static string RootPath => _rootPath ?? ( _rootPath = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location ) );
+ public static string UOFilePath { get; internal set; }
+ public static bool IsInstalled { get; internal set; }
+
+ public static unsafe void Install( PluginHeader* header )
+ {
+ Console.WriteLine( "Install Invoked CEasyUO" );
+ try
+ {
+ ClientVersion = (ClientVersions)header->ClientVersion;
+ if ( !ClientCommunication.InstallHooks( header ) )
+ {
+ System.Diagnostics.Process.GetCurrentProcess().Kill();
+ return;
+ }
+ UOFilePath = Marshal.GetDelegateForFunctionPointer( header->GetUOFilePath )();
+ Ultima.Files.SetMulPath( UOFilePath );
+ Ultima.Multis.PostHSFormat = UsePostHSChanges;
+ Thread t = new Thread( () =>
+ {
+ Thread.CurrentThread.Name = "EasyUO Main Thread";
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault( false );
+ Application.Run( new CEasyUOMainForm() );
+ } );
+ t.SetApartmentState( ApartmentState.STA );
+ PacketHandlers.Initialize();
+ // Targeting.Initialize();
+ Spell.Initialize(); EUOVars.Initialize();
+ t.IsBackground = true;
+
+ t.Start();
+ IsInstalled = true;
+ }
+ catch (Exception e)
+ {
+ Debugger.Break();
+ Console.WriteLine( e.Message );
+ }
+
+
+
+ }
+
+
+ internal static void LogCrash( Exception e )
+ {
+ }
+ }
+}
diff --git a/Network/ClientCommunication.cs b/Network/ClientCommunication.cs
new file mode 100644
index 0000000..18badf8
--- /dev/null
+++ b/Network/ClientCommunication.cs
@@ -0,0 +1,196 @@
+using CUO_API;
+using System;
+using System.Diagnostics;
+using System.Net;
+using System.Runtime.InteropServices;
+
+namespace Assistant
+{
+ public unsafe sealed class ClientCommunication
+ {
+ public static DateTime ConnectionStart { get; private set; }
+ public static IPAddress LastConnection { get; }
+
+ public static IntPtr ClientWindow { get; private set; } = IntPtr.Zero;
+
+ private static OnPacketSendRecv _sendToClient, _sendToServer, _recv, _send;
+ private static OnGetPacketLength _getPacketLength;
+ private static OnGetPlayerPosition _getPlayerPosition;
+ private static OnCastSpell _castSpell;
+ private static OnGetStaticImage _getStaticImage;
+
+ private static OnHotkey _onHotkeyPressed;
+ private static OnMouse _onMouse;
+ private static OnUpdatePlayerPosition _onUpdatePlayerPosition;
+ private static OnClientClose _onClientClose;
+ private static OnInitialize _onInitialize;
+ private static OnConnected _onConnected;
+ private static OnDisconnected _onDisconnected;
+ private static OnFocusGained _onFocusGained;
+ private static OnFocusLost _onFocusLost;
+
+ internal static bool InstallHooks( PluginHeader* header )
+ {
+ _sendToClient = Marshal.GetDelegateForFunctionPointer( header->Recv );
+ _sendToServer = Marshal.GetDelegateForFunctionPointer( header->Send );
+ _getPacketLength = Marshal.GetDelegateForFunctionPointer( header->GetPacketLength );
+ _getPlayerPosition = Marshal.GetDelegateForFunctionPointer( header->GetPlayerPosition );
+ _castSpell = Marshal.GetDelegateForFunctionPointer( header->CastSpell );
+ _getStaticImage = Marshal.GetDelegateForFunctionPointer( header->GetStaticImage );
+
+ ClientWindow = header->HWND;
+
+ _recv = OnRecv;
+ _send = OnSend;
+ _onHotkeyPressed = OnHotKeyHandler;
+ _onMouse = OnMouseHandler;
+ _onUpdatePlayerPosition = OnPlayerPositionChanged;
+ _onClientClose = OnClientClosing;
+ _onInitialize = OnInitialize;
+ _onConnected = OnConnected;
+ _onDisconnected = OnDisconnected;
+ // _onFocusGained = OnFocusGained;
+ // _onFocusLost = OnFocusLost;
+
+ header->OnRecv = Marshal.GetFunctionPointerForDelegate( _recv );
+ header->OnSend = Marshal.GetFunctionPointerForDelegate( _send );
+ header->OnHotkeyPressed = Marshal.GetFunctionPointerForDelegate( _onHotkeyPressed );
+ header->OnMouse = Marshal.GetFunctionPointerForDelegate( _onMouse );
+ header->OnPlayerPositionChanged = Marshal.GetFunctionPointerForDelegate( _onUpdatePlayerPosition );
+ header->OnClientClosing = Marshal.GetFunctionPointerForDelegate( _onClientClose );
+ header->OnInitialize = Marshal.GetFunctionPointerForDelegate( _onInitialize );
+ header->OnConnected = Marshal.GetFunctionPointerForDelegate( _onConnected );
+ header->OnDisconnected = Marshal.GetFunctionPointerForDelegate( _onDisconnected );
+ // header->OnFocusGained = Marshal.GetFunctionPointerForDelegate( _onFocusGained );
+ // header->OnFocusLost = Marshal.GetFunctionPointerForDelegate( _onFocusLost );
+
+ return true;
+ }
+
+ private static void OnClientClosing()
+ {
+ var last = Console.BackgroundColor;
+ var lastFore = Console.ForegroundColor;
+ Console.BackgroundColor = ConsoleColor.Red;
+ Console.ForegroundColor = ConsoleColor.Black;
+ Console.WriteLine( "Closing EasyUO instance" );
+ Console.BackgroundColor = last;
+ Console.ForegroundColor = lastFore;
+
+ }
+
+ private static void OnInitialize()
+ {
+ var last = Console.BackgroundColor;
+ var lastFore = Console.ForegroundColor;
+ Console.BackgroundColor = ConsoleColor.Green;
+ Console.ForegroundColor = ConsoleColor.Black;
+ Console.WriteLine( "Initialized EasyUO instance" );
+ Console.BackgroundColor = last;
+ Console.ForegroundColor = lastFore;
+ }
+
+ private static void OnConnected()
+ {
+ ConnectionStart = DateTime.Now;
+ try
+ {
+ }
+ catch
+ {
+ }
+ }
+
+ private static void OnDisconnected()
+ {
+ PacketHandlers.Party.Clear();
+
+
+
+ World.Player = null;
+ World.Items.Clear();
+ World.Mobiles.Clear();
+ ActionQueue.Stop();
+
+ BuffsTimer.Stop();
+
+ PacketHandlers.Party.Clear();
+ PacketHandlers.IgnoreGumps.Clear();
+ }
+
+
+
+
+ private static bool OnHotKeyHandler( int key, int mod, bool ispressed )
+ {
+ if ( ispressed )
+ {
+ // bool code = HotKey.OnKeyDown( (int)( key | mod ) );
+
+ return true;// code;
+ }
+
+ return true;
+ }
+
+ private static void OnMouseHandler( int button, int wheel )
+ {
+ if ( button > 4 )
+ button = 3;
+ else if ( button > 3 )
+ button = 2;
+ else if ( button > 2 )
+ button = 2;
+ else if ( button > 1 )
+ button = 1;
+
+ //HotKey.OnMouse( button, wheel );
+ }
+
+ private static void OnPlayerPositionChanged( int x, int y, int z )
+ {
+ if(World.Player != null)
+ World.Player.Position = new Point3D( x, y, z );
+ }
+
+ private static bool OnRecv( byte[] data, int length )
+ {
+ fixed ( byte* ptr = data )
+ {
+ PacketReader p = new PacketReader( ptr, length, PacketsTable.GetPacketLength( data[0] ) < 0 );
+ Packet packet = new Packet( data, length, p.DynamicLength );
+
+ return !PacketHandler.OnServerPacket( p.PacketID, p, packet );
+ }
+ }
+
+ private static bool OnSend( byte[] data, int length )
+ {
+ fixed ( byte* ptr = data )
+ {
+ PacketReader p = new PacketReader( ptr, length, PacketsTable.GetPacketLength( data[0] ) < 0 );
+ Packet packet = new Packet( data, length, p.DynamicLength );
+
+ return !PacketHandler.OnClientPacket( p.PacketID, p, packet );
+ }
+ }
+
+ public static void CastSpell( int idx ) => _castSpell?.Invoke( idx );
+
+ public static bool GetPlayerPosition( out int x, out int y, out int z )
+ => _getPlayerPosition( out x, out y, out z );
+
+ internal static void SendToServer( Packet p )
+ {
+ var len = p.Length;
+ _sendToServer?.Invoke( p.Compile(), (int)len );
+ }
+
+ internal static void SendToClient( Packet p )
+ {
+ var len = p.Length;
+ _sendToClient?.Invoke( p.Compile(), (int)len );
+ }
+ }
+
+}
diff --git a/Network/Handlers.cs b/Network/Handlers.cs
new file mode 100644
index 0000000..fedbe69
--- /dev/null
+++ b/Network/Handlers.cs
@@ -0,0 +1,2458 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+using ContainerLabels = Assistant.Core.ContainerLabels;
+using OverheadMessages = Assistant.Core.OverheadMessages;
+using Assistant.Core;
+
+namespace Assistant
+{
+ public class PacketHandlers
+ {
+ private static List
- m_IgnoreGumps = new List
- ();
+ public static List
- IgnoreGumps { get { return m_IgnoreGumps; } }
+
+ 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));
+ PacketHandler.RegisterClientToServerViewer(0x07, new PacketViewerCallback(LiftRequest));
+ PacketHandler.RegisterClientToServerViewer(0x08, new PacketViewerCallback(DropRequest));
+ 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));
+ PacketHandler.RegisterClientToServerFilter(0x91, new PacketFilterCallback(GameLogin));
+ PacketHandler.RegisterClientToServerViewer(0x95, new PacketViewerCallback(HueResponse));
+ 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.RegisterClientToServerViewer(0xD7, new PacketViewerCallback(ClientEncodedPacket));
+ PacketHandler.RegisterClientToServerViewer(0xF8, new PacketViewerCallback(CreateCharacter));
+
+ //Server -> Client handlers
+ //PacketHandler.RegisterServerToClientViewer(0x0B, new PacketViewerCallback(Damage));
+ PacketHandler.RegisterServerToClientViewer(0x11, new PacketViewerCallback(MobileStatus));
+ PacketHandler.RegisterServerToClientViewer(0x17, new PacketViewerCallback(NewMobileStatus));
+ PacketHandler.RegisterServerToClientViewer(0x1A, new PacketViewerCallback(WorldItem));
+ PacketHandler.RegisterServerToClientViewer(0x1B, new PacketViewerCallback(LoginConfirm));
+ 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(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.RegisterServerToClientViewer(0x6F, new PacketViewerCallback(TradeRequest));
+ PacketHandler.RegisterServerToClientViewer(0x72, new PacketViewerCallback(ServerSetWarMode));
+ PacketHandler.RegisterServerToClientViewer(0x73, new PacketViewerCallback(PingResponse));
+ PacketHandler.RegisterServerToClientViewer(0x76, new PacketViewerCallback(ServerChange));
+ PacketHandler.RegisterServerToClientFilter(0x77, new PacketFilterCallback(MobileMoving));
+ PacketHandler.RegisterServerToClientFilter(0x78, new PacketFilterCallback(MobileIncoming));
+ PacketHandler.RegisterServerToClientViewer(0x7C, new PacketViewerCallback(SendMenu));
+ PacketHandler.RegisterServerToClientFilter(0x8C, new PacketFilterCallback(ServerAddress));
+ PacketHandler.RegisterServerToClientViewer(0xA1, new PacketViewerCallback(HitsUpdate));
+ 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));
+ PacketHandler.RegisterServerToClientViewer(0xB9, new PacketViewerCallback(Features));
+ PacketHandler.RegisterServerToClientViewer(0xBC, new PacketViewerCallback(ChangeSeason));
+ PacketHandler.RegisterServerToClientViewer(0xBF, new PacketViewerCallback(ExtendedPacket));
+ PacketHandler.RegisterServerToClientFilter(0xC1, new PacketFilterCallback(OnLocalizedMessage));
+ 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));
+ }
+
+ 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 ) );
+ }*/
+ }
+
+ private static void SetUpdateRange(Packet p, PacketHandlerEventArgs args)
+ {
+ if (World.Player != null)
+ 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;
+ ClientCommunication.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;
+ ClientCommunication.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();
+
+ // if you modify this, don't forget to modify the allnames hotkey
+ if (Config.GetBool("LastTargTextFlags"))
+ {
+ Mobile m = World.FindMobile(ser);
+ if (m != null)
+ Targeting.CheckTextFlags(m);
+ }
+
+ }
+
+ private static void ClientDoubleClick(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial ser = p.ReadUInt32();
+ if (Config.GetBool("BlockDismount") && World.Player != null && ser == World.Player.Serial && World.Player.Warmode && World.Player.GetItemOnLayer(Layer.Mount) != null)
+ { // mount layer = 0x19
+ args.Block = true;
+ return;
+ }
+PlayerData.DoubleClick(ser, false);
+
+
+ }
+
+ private static void DeathAnimation(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial killed = p.ReadUInt32();
+
+ }
+
+ private static void ExtendedClientCommand(Packet p, PacketHandlerEventArgs args)
+ {
+ ushort ext = p.ReadUInt16();
+ switch (ext)
+ {
+ case 0x10: // query object properties
+ {
+ break;
+ }
+ case 0x15: // context menu response
+ {
+ UOEntity ent = null;
+ Serial ser = p.ReadUInt32();
+ ushort idx = p.ReadUInt16();
+
+ if (ser.IsMobile)
+ ent = World.FindMobile(ser);
+ else if (ser.IsItem)
+ ent = World.FindItem(ser);
+
+ if (ent != null && ent.ContextMenu != null)
+ {
+ ushort menu;// = (ushort)ent.ContextMenu[idx];
+ // if (ent.ContextMenu.TryGetValue(idx, out menu) && menu != 0 && MacroManager.AcceptActions)
+ // MacroManager.Action(new ContextMenuAction(ent, idx, menu));
+ }
+
+ break;
+ }
+ case 0x1C:// cast spell
+ {
+ Serial ser = Serial.MinusOne;
+ if (p.ReadUInt16() == 1)
+ ser = p.ReadUInt32();
+ ushort sid = p.ReadUInt16();
+ Spell s = Spell.Get(sid);
+ if (s != null)
+ {
+ if(World.Player != null)
+ World.Player.LastSpell = sid;
+ s.OnCast(p);
+ args.Block = true;
+
+ // if (Macros.MacroManager.AcceptActions)
+ // MacroManager.Action(new ExtCastSpellAction(s, ser));
+ }
+ break;
+ }
+ case 0x24:
+ {
+ // for the cheatx0r part 2... anything outside this range indicates some haxing, just hide it with 0x30s
+ byte b = p.ReadByte();
+ if (b < 0x25 || b >= 0x5E + 0x25)
+ {
+ p.Seek(-1, SeekOrigin.Current);
+ 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;
+ }
+ }
+ }
+
+ private static void ClientTextCommand(PacketReader p, PacketHandlerEventArgs args)
+ {
+ int type = p.ReadByte();
+ string command = p.ReadString();
+
+ switch (type)
+ {
+ case 0x24: // Use skill
+ {
+ int skillIndex;
+
+ try { skillIndex = Convert.ToInt32(command.Split(' ')[0]); }
+ catch { break; }
+
+ if (World.Player != null)
+ World.Player.LastSkill = skillIndex;
+
+ // if (Macros.MacroManager.AcceptActions)
+ // MacroManager.Action(new UseSkillAction(skillIndex));
+
+ // if (skillIndex == (int)SkillName.Stealth && !World.Player.Visible)
+ // StealthSteps.Hide();
+
+ SkillTimer.Start();
+ break;
+ }
+ case 0x27: // Cast spell from book
+ {
+ try
+ {
+ string[] split = command.Split(' ');
+
+ if (split.Length > 0)
+ {
+ ushort spellID = Convert.ToUInt16(split[0]);
+ Serial serial = Convert.ToUInt32(split.Length > 1 ? Utility.ToInt32(split[1], -1) : -1);
+ Spell s = Spell.Get(spellID);
+ if (s != null)
+ {
+ s.OnCast(spellID);
+ args.Block = true;
+ // if (Macros.MacroManager.AcceptActions)
+ // MacroManager.Action(new BookCastSpellAction(s, serial));
+ }
+ }
+ }
+ catch
+ {
+ }
+ break;
+ }
+ case 0x56: // Cast spell from macro
+ {
+ try
+ {
+ ushort spellID = Convert.ToUInt16(command);
+ Spell s = Spell.Get(spellID);
+ if (s != null)
+ {
+ s.OnCast(spellID);
+ args.Block = true;
+ // if (Macros.MacroManager.AcceptActions)
+ // MacroManager.Action(new MacroCastSpellAction(s));
+ }
+ }
+ catch
+ {
+ }
+ break;
+ }
+ }
+ }
+
+ public static DateTime PlayCharTime = DateTime.MinValue;
+
+ private static void CreateCharacter(PacketReader p, PacketHandlerEventArgs args)
+ {
+ p.Seek(1 + 4 + 4 + 1, SeekOrigin.Begin); // skip begining crap
+ World.OrigPlayerName = p.ReadStringSafe(30);
+
+ PlayCharTime = DateTime.UtcNow;
+
+
+ }
+
+ private static void PlayCharacter(PacketReader p, PacketHandlerEventArgs args)
+ {
+ p.ReadUInt32(); //0xedededed
+ World.OrigPlayerName = p.ReadStringSafe(30);
+
+ PlayCharTime = DateTime.UtcNow;
+
+
+ //ClientCommunication.TranslateLogin( World.OrigPlayerName, World.ShardName );
+ }
+
+ private static void ServerList(PacketReader p, PacketHandlerEventArgs args)
+ {
+ p.ReadByte(); //unknown
+ ushort numServers = p.ReadUInt16();
+
+ for (int i = 0; i < numServers; ++i)
+ {
+ ushort num = p.ReadUInt16();
+ World.Servers[num] = p.ReadString(32);
+ p.ReadByte(); // full %
+ p.ReadSByte(); // time zone
+ p.ReadUInt32(); // ip
+ }
+ }
+
+ private static void PlayServer(PacketReader p, PacketHandlerEventArgs args)
+ {
+ ushort index = p.ReadUInt16();
+ string name;
+ if (World.Servers.TryGetValue(index, out name) && !string.IsNullOrEmpty(name))
+ World.ShardName = name;
+ else
+ World.ShardName = "[Unknown]";
+ }
+
+ private static void LiftRequest(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial serial = p.ReadUInt32();
+ ushort amount = p.ReadUInt16();
+
+ Item item = World.FindItem(serial);
+ ushort iid = 0;
+
+ if (item != null)
+ iid = item.ItemID.Value;
+
+ if (Config.GetBool("QueueActions"))
+ {
+ if (item == null)
+ {
+ World.AddItem(item = new Item(serial));
+ item.Amount = amount;
+ }
+
+ DragDropManager.Drag(item, amount, true);
+ //ClientCommunication.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" ) ) ) );
+ }
+ }
+
+ private static void LiftReject(PacketReader p, PacketHandlerEventArgs args)
+ {
+ /*
+ if ( ActionQueue.FilterLiftReject() )
+ args.Block = true;
+ */
+ int reason = p.ReadByte();
+
+ if (!DragDropManager.LiftReject())
+ args.Block = true;
+ //MacroManager.PlayError( MacroError.LiftRej );
+ }
+
+ private static void EquipRequest(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial iser = p.ReadUInt32(); // item being dropped serial
+ Layer layer = (Layer)p.ReadByte();
+ Serial mser = p.ReadUInt32();
+
+ Item item = World.FindItem(iser);
+
+ /* if (MacroManager.AcceptActions)
+ {
+ if (layer == Layer.Invalid || layer > Layer.LastValid)
+ {
+ if (item != null)
+ {
+ layer = item.Layer;
+ if (layer == Layer.Invalid || layer > Layer.LastValid)
+ layer = (Layer)item.ItemID.ItemData.Quality;
+ }
+ }
+
+ if (layer > Layer.Invalid && layer <= Layer.LastUserValid)
+ MacroManager.Action(new DropAction(mser, Point3D.Zero, layer));
+ }*/
+
+ if (item == null)
+ return;
+
+ Mobile m = World.FindMobile(mser);
+ if (m == null)
+ return;
+
+ if (Config.GetBool("QueueActions"))
+ args.Block = DragDropManager.Drop(item, m, layer);
+ }
+
+ private static void DropRequest(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial iser = p.ReadUInt32();
+ int x = p.ReadInt16();
+ int y = p.ReadInt16();
+ int z = p.ReadSByte();
+ if (Engine.UsePostKRPackets)
+ /* grid num */
+ p.ReadByte();
+ Point3D newPos = new Point3D(x, y, z);
+ Serial dser = p.ReadUInt32();
+
+ // if (Macros.MacroManager.AcceptActions)
+ // MacroManager.Action(new DropAction(dser, newPos));
+
+ Item i = World.FindItem(iser);
+ if (i == null)
+ return;
+
+ Item dest = World.FindItem(dser);
+ if (dest != null && dest.IsContainer && World.Player != null && (dest.IsChildOf(World.Player.Backpack) || dest.IsChildOf(World.Player.Quiver)))
+ i.IsNew = true;
+
+ if (Config.GetBool("QueueActions"))
+ args.Block = DragDropManager.Drop(i, dser, newPos);
+ }
+
+ private static void MovementRequest(Packet p, PacketHandlerEventArgs args)
+ {
+ if (World.Player != null)
+ {
+ Direction dir = (Direction)p.ReadByte();
+ byte seq = p.ReadByte();
+
+ World.Player.Direction = (dir & Direction.Mask);
+ World.Player.WalkSequence = seq;
+ //WalkAction.LastWalkTime = DateTime.UtcNow;
+ // if (MacroManager.AcceptActions)
+ // MacroManager.Action(new WalkAction(dir));
+ }
+ }
+
+ private static void ContainerContentUpdate(Packet p, PacketHandlerEventArgs args)
+ {
+ // This function will ignore the item if the container item has not been sent to the client yet.
+ // We can do this because we can't really count on getting all of the container info anyway.
+ // (So we'd need to request the container be updated, so why bother with the extra stuff required to find the container once its been sent?)
+ Serial serial = p.ReadUInt32();
+ ushort itemid = p.ReadUInt16();
+ itemid = (ushort)(itemid + p.ReadSByte()); // signed, itemID offset
+ ushort amount = p.ReadUInt16();
+ if (amount == 0)
+ amount = 1;
+ Point3D pos = new Point3D(p.ReadUInt16(), p.ReadUInt16(), 0);
+ byte gridPos = 0;
+ if (Engine.UsePostKRPackets)
+ gridPos = p.ReadByte();
+ Serial cser = p.ReadUInt32();
+ ushort hue = p.ReadUInt16();
+
+ Item i = World.FindItem(serial);
+ if (i == null)
+ {
+ if (!serial.IsItem)
+ return;
+
+ World.AddItem(i = new Item(serial));
+ i.IsNew = i.AutoStack = true;
+ }
+ else
+ {
+ i.CancelRemove();
+ }
+
+ if (serial != DragDropManager.Pending)
+ {
+ if (!DragDropManager.EndHolding(serial))
+ return;
+ }
+
+ i.ItemID = itemid;
+ i.Amount = amount;
+ i.Position = pos;
+ i.GridNum = gridPos;
+ i.Hue = hue;
+
+
+
+ i.Container = cser;
+ if (i.IsNew)
+ Item.UpdateContainers();
+
+ }
+
+ private static void BeginContainerContent(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial ser = p.ReadUInt32();
+ if (!ser.IsItem)
+ return;
+ Item item = World.FindItem(ser);
+ if (item != null)
+ {
+ if (m_IgnoreGumps.Contains(item))
+ {
+ m_IgnoreGumps.Remove(item);
+ args.Block = true;
+ }
+ World.Player.LastContainer = item;
+ }
+ else
+ {
+ World.AddItem(new Item(ser));
+ Item.UpdateContainers();
+ item = World.FindItem( ser );
+ World.Player.LastContainer = item;
+ }
+ World.Player.LastContainerOpenedAt = DateTime.UtcNow;
+ World.Player.LastContainerGumpGraphic = p.ReadUInt16();
+ }
+
+ private static void ContainerContent(Packet p, PacketHandlerEventArgs args)
+ {
+ int count = p.ReadUInt16();
+
+ for (int i = 0; i < count; i++)
+ {
+ Serial serial = p.ReadUInt32();
+ // serial is purposely not checked to be valid, sometimes buy lists dont have "valid" item serials (and we are okay with that).
+ Item item = World.FindItem(serial);
+ if (item == null)
+ {
+ World.AddItem(item = new Item(serial));
+ item.IsNew = true;
+ item.AutoStack = false;
+ }
+ else
+ {
+ item.CancelRemove();
+ }
+
+ if (!DragDropManager.EndHolding(serial))
+ continue;
+
+ item.ItemID = p.ReadUInt16();
+ item.ItemID = (ushort)(item.ItemID + p.ReadSByte());// signed, itemID offset
+ item.Amount = p.ReadUInt16();
+ if (item.Amount == 0)
+ item.Amount = 1;
+ item.Position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), 0);
+ if (Engine.UsePostKRPackets)
+ item.GridNum = p.ReadByte();
+ Serial cont = p.ReadUInt32();
+ var container = World.FindItem( cont );
+
+ if ( i == 0 )
+ {
+ if(container!= null)
+ {
+ container.ClearContents();
+
+
+ }
+
+ }
+ item.Hue = p.ReadUInt16();
+
+
+ item.Container = cont; // must be done after hue is set (for counters)
+
+ }
+ Item.UpdateContainers();
+ }
+
+ private static void EquipmentUpdate(Packet p, PacketHandlerEventArgs args)
+ {
+ Serial serial = p.ReadUInt32();
+
+ Item i = World.FindItem(serial);
+ bool isNew = false;
+ if (i == null)
+ {
+ World.AddItem(i = new Item(serial));
+ isNew = true;
+ Item.UpdateContainers();
+ }
+ else
+ {
+ i.CancelRemove();
+ }
+
+ if (!DragDropManager.EndHolding(serial))
+ return;
+
+ ushort iid = p.ReadUInt16();
+ i.ItemID = (ushort)(iid + p.ReadSByte()); // signed, itemID offset
+ i.Layer = (Layer)p.ReadByte();
+ Serial ser = p.ReadUInt32();// cont must be set after hue (for counters)
+ i.Hue = p.ReadUInt16();
+
+ i.Container = ser;
+
+ int ltHue = Config.GetInt("LTHilight");
+ if (ltHue != 0 && Targeting.IsLastTarget(i.Container as Mobile))
+ {
+ p.Seek(-2, SeekOrigin.Current);
+ p.Write((ushort)(ltHue & 0x3FFF));
+ }
+
+ if (i.Layer == Layer.Backpack && isNew && Config.GetBool("AutoSearch") && ser == World.Player.Serial)
+ {
+ m_IgnoreGumps.Add(i);
+ PlayerData.DoubleClick(i);
+ }
+ }
+
+ private static void SetSkillLock(PacketReader p, PacketHandlerEventArgs args)
+ {
+ int i = p.ReadUInt16();
+
+ if (i >= 0 && i < Skill.Count)
+ {
+ Skill skill = World.Player.Skills[i];
+
+ skill.Lock = (LockType)p.ReadByte();
+ }
+ }
+
+ private static void Skills(PacketReader p, PacketHandlerEventArgs args)
+ {
+ if (World.Player == null || World.Player.Skills == null)
+ return;
+
+ byte type = p.ReadByte();
+
+ switch (type)
+ {
+ case 0x02://list (with caps, 3.0.8 and up)
+ {
+ int i;
+ while ((i = p.ReadUInt16()) > 0)
+ {
+ if (i > 0 && i <= Skill.Count)
+ {
+ Skill skill = World.Player.Skills[i - 1];
+
+ if (skill == null)
+ continue;
+
+ skill.FixedValue = p.ReadUInt16();
+ skill.FixedBase = p.ReadUInt16();
+ skill.Lock = (LockType)p.ReadByte();
+ skill.FixedCap = p.ReadUInt16();
+ if (!World.Player.SkillsSent)
+ skill.Delta = 0;
+
+ }
+ else
+ {
+ p.Seek(7, SeekOrigin.Current);
+ }
+ }
+
+ World.Player.SkillsSent = true;
+ break;
+ }
+
+ case 0x00: // list (without caps, older clients)
+ {
+ int i;
+ while ((i = p.ReadUInt16()) > 0)
+ {
+ if (i > 0 && i <= Skill.Count)
+ {
+ Skill skill = World.Player.Skills[i - 1];
+
+ if (skill == null)
+ continue;
+
+ skill.FixedValue = p.ReadUInt16();
+ skill.FixedBase = p.ReadUInt16();
+ skill.Lock = (LockType)p.ReadByte();
+ skill.FixedCap = 100;//p.ReadUInt16();
+ if (!World.Player.SkillsSent)
+ skill.Delta = 0;
+
+ }
+ else
+ {
+ p.Seek(5, SeekOrigin.Current);
+ }
+ }
+
+ World.Player.SkillsSent = true;
+ break;
+ }
+
+ case 0xDF: //change (with cap, new clients)
+ {
+ int i = p.ReadUInt16();
+
+ if (i >= 0 && i < Skill.Count)
+ {
+ Skill skill = World.Player.Skills[i];
+
+ if (skill == null)
+ break;
+
+ ushort old = skill.FixedBase;
+ skill.FixedValue = p.ReadUInt16();
+ skill.FixedBase = p.ReadUInt16();
+ skill.Lock = (LockType)p.ReadByte();
+ skill.FixedCap = p.ReadUInt16();
+
+
+ }
+ break;
+ }
+
+ case 0xFF: //change (without cap, older clients)
+ {
+ int i = p.ReadUInt16();
+
+ if (i >= 0 && i < Skill.Count)
+ {
+ Skill skill = World.Player.Skills[i];
+
+ if (skill == null)
+ break;
+
+ ushort old = skill.FixedBase;
+ skill.FixedValue = p.ReadUInt16();
+ skill.FixedBase = p.ReadUInt16();
+ skill.Lock = (LockType)p.ReadByte();
+ skill.FixedCap = 100;
+
+ }
+ break;
+ }
+ }
+ }
+
+ private static void LoginConfirm(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Console.WriteLine( "Login Confirm" );
+ World.Items.Clear();
+ World.Mobiles.Clear();
+
+ UseNewStatus = false;
+
+ Serial serial = p.ReadUInt32();
+
+ PlayerData m = new PlayerData(serial);
+ m.Name = World.OrigPlayerName;
+
+ Mobile test = World.FindMobile(serial);
+ if (test != null)
+ test.Remove();
+
+ World.AddMobile(World.Player = m);
+
+ p.ReadUInt32(); // always 0?
+ m.Body = p.ReadUInt16();
+ m.Position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), p.ReadInt16());
+ m.Direction = (Direction)p.ReadByte();
+
+ }
+
+ private static void MobileMoving(Packet p, PacketHandlerEventArgs args)
+ {
+ Mobile m = World.FindMobile(p.ReadUInt32());
+
+ if (m != null)
+ {
+ m.Body = p.ReadUInt16();
+ m.Position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), p.ReadSByte());
+
+ if (World.Player != null && !Utility.InRange(World.Player.Position, m.Position, World.Player.VisRange))
+ {
+ m.Remove();
+ return;
+ }
+
+ Targeting.CheckLastTargetRange(m);
+
+ m.Direction = (Direction)p.ReadByte();
+ m.Hue = p.ReadUInt16();
+ int ltHue = Config.GetInt("LTHilight");
+ if (ltHue != 0 && Targeting.IsLastTarget(m))
+ {
+ p.Seek(-2, SeekOrigin.Current);
+ p.Write((short)(ltHue | 0x8000));
+ }
+
+ bool wasPoisoned = m.Poisoned;
+ m.ProcessPacketFlags(p.ReadByte());
+ byte oldNoto = m.Notoriety;
+ m.Notoriety = p.ReadByte();
+
+
+ }
+ }
+
+ private static readonly int[] HealthHues = new int[] { 428, 333, 37, 44, 49, 53, 158, 263, 368, 473, 578 };
+
+ private static void HitsUpdate(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Mobile m = World.FindMobile(p.ReadUInt32());
+
+ if (m != null)
+ {
+ int oldPercent = (int)(m.Hits * 100 / (m.HitsMax == 0 ? (ushort)1 : m.HitsMax));
+
+ m.HitsMax = p.ReadUInt16();
+ m.Hits = p.ReadUInt16();
+
+ }
+ }
+
+ private static void StamUpdate(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Mobile m = World.FindMobile(p.ReadUInt32());
+
+ if (m != null)
+ {
+ int oldPercent = (int)(m.Stam * 100 / (m.StamMax == 0 ? (ushort)1 : m.StamMax));
+
+ m.StamMax = p.ReadUInt16();
+ m.Stam = p.ReadUInt16();
+
+
+
+ }
+ }
+
+ private static void ManaUpdate(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Mobile m = World.FindMobile(p.ReadUInt32());
+
+ if (m != null)
+ {
+ int oldPercent = (int)(m.Mana * 100 / (m.ManaMax == 0 ? (ushort)1 : m.ManaMax));
+
+ m.ManaMax = p.ReadUInt16();
+ m.Mana = p.ReadUInt16();
+
+
+ }
+ }
+
+ private static void MobileStatInfo(PacketReader pvSrc, PacketHandlerEventArgs args)
+ {
+ Mobile m = World.FindMobile(pvSrc.ReadUInt32());
+ if (m == null)
+ return;
+ PlayerData p = World.Player;
+
+ m.HitsMax = pvSrc.ReadUInt16();
+ m.Hits = pvSrc.ReadUInt16();
+
+ m.ManaMax = pvSrc.ReadUInt16();
+ m.Mana = pvSrc.ReadUInt16();
+
+ m.StamMax = pvSrc.ReadUInt16();
+ m.Stam = pvSrc.ReadUInt16();
+
+
+ }
+
+ public static bool UseNewStatus = false;
+
+ private static void NewMobileStatus(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Mobile m = World.FindMobile((Serial)p.ReadUInt32());
+
+ if (m == null)
+ return;
+
+ UseNewStatus = true;
+
+ // 00 01
+ p.ReadUInt16();
+
+ // 00 01 Poison
+ // 00 02 Yellow Health Bar
+
+ ushort id = p.ReadUInt16();
+
+ // 00 Off
+ // 01 On
+ // For Poison: Poison Level + 1
+
+ byte flag = p.ReadByte();
+
+ if (id == 1)
+ {
+ bool wasPoisoned = m.Poisoned;
+ m.Poisoned = (flag != 0);
+
+
+ }
+ }
+
+ //private static void Damage(PacketReader p, PacketHandlerEventArgs args)
+ //{
+ // if (Config.GetBool("TrackDps"))
+ // {
+ // uint serial = p.ReadUInt32();
+ // ushort damage = p.ReadUInt16();
+
+ // if (serial != World.Player.Serial)
+ // return;
+
+ // World.Player.AddDamage(damage);
+ // }
+
+ //}
+
+ private static void MobileStatus(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial serial = p.ReadUInt32();
+ Mobile m = World.FindMobile(serial);
+ if (m == null)
+ World.AddMobile(m = new Mobile(serial));
+
+ m.Name = p.ReadString(30);
+
+ m.Hits = p.ReadUInt16();
+ m.HitsMax = p.ReadUInt16();
+
+ //p.ReadBoolean();//CanBeRenamed
+ if (p.ReadBoolean())
+ m.CanRename = true;
+
+ byte type = p.ReadByte();
+
+ if (m == World.Player && type != 0x00)
+ {
+ PlayerData player = (PlayerData)m;
+
+ player.Female = p.ReadBoolean();
+
+ int oStr = player.Str, oDex = player.Dex, oInt = player.Int;
+
+ player.Str = p.ReadUInt16();
+ player.Dex = p.ReadUInt16();
+ player.Int = p.ReadUInt16();
+
+
+
+ player.Stam = p.ReadUInt16();
+ player.StamMax = p.ReadUInt16();
+ player.Mana = p.ReadUInt16();
+ player.ManaMax = p.ReadUInt16();
+
+ player.Gold = p.ReadUInt32();
+ player.AR = p.ReadUInt16(); // ar / physical resist
+ player.Weight = p.ReadUInt16();
+
+ if (type >= 0x03)
+ {
+ if (type > 0x04)
+ {
+ player.MaxWeight = p.ReadUInt16();
+
+ p.ReadByte(); // race?
+ }
+
+ player.StatCap = p.ReadUInt16();
+
+ player.Followers = p.ReadByte();
+ player.FollowersMax = p.ReadByte();
+
+ if (type > 0x03)
+ {
+ player.FireResistance = p.ReadInt16();
+ player.ColdResistance = p.ReadInt16();
+ player.PoisonResistance = p.ReadInt16();
+ player.EnergyResistance = p.ReadInt16();
+
+ player.Luck = p.ReadInt16();
+
+ player.DamageMin = p.ReadUInt16();
+ player.DamageMax = p.ReadUInt16();
+
+ player.Tithe = p.ReadInt32();
+ }
+ }
+
+
+
+ }
+ }
+
+ private static void MobileUpdate(Packet p, PacketHandlerEventArgs args)
+ {
+ if (World.Player == null)
+ return;
+
+ Serial serial = p.ReadUInt32();
+ Mobile m = World.FindMobile(serial);
+ if (m == null)
+ World.AddMobile(m = new Mobile(serial));
+
+ bool wasHidden = !m.Visible;
+
+ m.Body = (ushort)(p.ReadUInt16() + p.ReadSByte());
+ m.Hue = p.ReadUInt16();
+ int ltHue = Config.GetInt("LTHilight");
+ if (ltHue != 0 && Targeting.IsLastTarget(m))
+ {
+ p.Seek(-2, SeekOrigin.Current);
+ p.Write((ushort)(ltHue | 0x8000));
+ }
+
+ bool wasPoisoned = m.Poisoned;
+ m.ProcessPacketFlags(p.ReadByte());
+
+ ushort x = p.ReadUInt16();
+ ushort y = p.ReadUInt16();
+ p.ReadUInt16(); //always 0?
+ m.Direction = (Direction)p.ReadByte();
+ m.Position = new Point3D(x, y, p.ReadSByte());
+
+
+
+ Item.UpdateContainers();
+ }
+
+ private static void MobileIncoming(Packet p, PacketHandlerEventArgs args)
+ {
+ if (World.Player == null)
+ return;
+
+ Serial serial = p.ReadUInt32();
+ ushort body = p.ReadUInt16();
+ Point3D position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), p.ReadSByte());
+
+ if (World.Player.Position != Point3D.Zero && !Utility.InRange(World.Player.Position, position, World.Player.VisRange))
+ return;
+
+ Mobile m = World.FindMobile(serial);
+ if (m == null)
+ World.AddMobile(m = new Mobile(serial));
+
+ bool wasHidden = !m.Visible;
+
+ if (m != World.Player && Config.GetBool("ShowMobNames"))
+ ClientCommunication.SendToServer(new SingleClick(m));
+ if (Config.GetBool("LastTargTextFlags"))
+ Targeting.CheckTextFlags(m);
+
+ int ltHue = Config.GetInt("LTHilight");
+ bool isLT;
+ if (ltHue != 0)
+ isLT = Targeting.IsLastTarget(m);
+ else
+ isLT = false;
+
+ m.Body = body;
+ if (m != World.Player)
+ m.Position = position;
+ m.Direction = (Direction)p.ReadByte();
+ m.Hue = p.ReadUInt16();
+ if (isLT)
+ {
+ p.Seek(-2, SeekOrigin.Current);
+ p.Write((short)(ltHue | 0x8000));
+ }
+
+ bool wasPoisoned = m.Poisoned;
+ m.ProcessPacketFlags(p.ReadByte());
+ byte oldNoto = m.Notoriety;
+ m.Notoriety = p.ReadByte();
+
+
+
+ while (true)
+ {
+ serial = p.ReadUInt32();
+ if (!serial.IsItem)
+ break;
+
+ Item item = World.FindItem(serial);
+ bool isNew = false;
+ if (item == null)
+ {
+ isNew = true;
+ World.AddItem(item = new Item(serial));
+ }
+
+ if (!DragDropManager.EndHolding(serial))
+ continue;
+
+ item.Container = m;
+
+ ushort id = p.ReadUInt16();
+
+ if (Engine.UseNewMobileIncoming)
+ item.ItemID = (ushort)(id & 0xFFFF);
+ else if (Engine.UsePostSAChanges)
+ item.ItemID = (ushort)(id & 0x7FFF);
+ else
+ item.ItemID = (ushort)(id & 0x3FFF);
+
+ item.Layer = (Layer)p.ReadByte();
+
+ if (Engine.UseNewMobileIncoming)
+ {
+ item.Hue = p.ReadUInt16();
+ if (isLT)
+ {
+ p.Seek(-2, SeekOrigin.Current);
+ p.Write((short)(ltHue & 0x3FFF));
+ }
+ }
+ else
+ {
+ if ((id & 0x8000) != 0)
+ {
+ item.Hue = p.ReadUInt16();
+ if (isLT)
+ {
+ p.Seek(-2, SeekOrigin.Current);
+ p.Write((short)(ltHue & 0x3FFF));
+ }
+ }
+ else
+ {
+ item.Hue = 0;
+ if (isLT)
+ ClientCommunication.SendToClient(new EquipmentItem(item, (ushort)(ltHue & 0x3FFF), m.Serial));
+ }
+ }
+
+ if (item.Layer == Layer.Backpack && isNew && Config.GetBool("AutoSearch") && m == World.Player && m != null)
+ {
+ m_IgnoreGumps.Add(item);
+ PlayerData.DoubleClick(item);
+ }
+ }
+
+ Item.UpdateContainers();
+ }
+
+ private static void RemoveObject(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial serial = p.ReadUInt32();
+
+ if (serial.IsMobile)
+ {
+ Mobile m = World.FindMobile(serial);
+ if (m != null && m != World.Player)
+ m.Remove();
+ }
+ else if (serial.IsItem)
+ {
+ Item i = World.FindItem(serial);
+ if (i != null)
+ {
+ if (DragDropManager.Holding == i)
+ {
+ i.Container = null;
+ }
+ else
+ {
+ i.RemoveRequest();
+ }
+ }
+ }
+ }
+
+ private static void ServerChange(PacketReader p, PacketHandlerEventArgs args)
+ {
+ if (World.Player != null)
+ World.Player.Position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), p.ReadInt16());
+ }
+
+ private static void WorldItem(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Item item;
+ uint serial = p.ReadUInt32();
+ item = World.FindItem(serial & 0x7FFFFFFF);
+ bool isNew = false;
+ if (item == null)
+ {
+ World.AddItem(item = new Item(serial & 0x7FFFFFFF));
+ isNew = true;
+ }
+ else
+ {
+ item.CancelRemove();
+ }
+
+ if (!DragDropManager.EndHolding(serial))
+ return;
+
+ item.Container = null;
+
+ ushort itemID = p.ReadUInt16();
+ item.ItemID = (ushort)(itemID & 0x7FFF);
+
+ if ((serial & 0x80000000) != 0)
+ item.Amount = p.ReadUInt16();
+ else
+ item.Amount = 1;
+
+ if ((itemID & 0x8000) != 0)
+ item.ItemID = (ushort)(item.ItemID + p.ReadSByte());
+
+ ushort x = p.ReadUInt16();
+ ushort y = p.ReadUInt16();
+
+ if ((x & 0x8000) != 0)
+ item.Direction = p.ReadByte();
+ else
+ item.Direction = 0;
+
+ short z = p.ReadSByte();
+
+ item.Position = new Point3D(x & 0x7FFF, y & 0x3FFF, z);
+
+ if ((y & 0x8000) != 0)
+ item.Hue = p.ReadUInt16();
+ else
+ item.Hue = 0;
+
+ byte flags = 0;
+ if ((y & 0x4000) != 0)
+ flags = p.ReadByte();
+
+ item.ProcessPacketFlags(flags);
+
+ if (isNew && World.Player != null)
+ {
+ if (item.ItemID == 0x2006)// corpse itemid = 0x2006
+ {
+ if (Config.GetBool("ShowCorpseNames"))
+ ClientCommunication.SendToServer(new SingleClick(item));
+
+ if (Config.GetBool("AutoOpenCorpses") && Utility.InRange(item.Position, World.Player.Position, Config.GetInt("CorpseRange")) && World.Player != null && World.Player.Visible)
+ {
+ if (Config.GetBool("BlockOpenCorpsesTwice"))
+ {
+ bool blockOpen = false;
+ foreach (uint openedCorse in World.Player.OpenedCorpses)
+ {
+ if (openedCorse == serial)
+ {
+ blockOpen = true;
+ break;
+ }
+ }
+
+ if (World.Player.OpenedCorpses.Count > 2000)
+ {
+ World.Player.OpenedCorpses.RemoveRange(0, 500);
+ }
+
+ if (!blockOpen)
+ {
+ PlayerData.DoubleClick(item);
+ }
+
+ if (!World.Player.OpenedCorpses.Contains(serial))
+ {
+ World.Player.OpenedCorpses.Add(serial);
+ }
+
+
+ }
+ else
+ {
+ PlayerData.DoubleClick(item);
+ }
+ }
+ }
+ else if (item.IsMulti)
+ {
+ }
+ else
+ {
+
+ }
+ }
+
+ Item.UpdateContainers();
+ }
+
+ 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();
+
+ Item item;
+ uint serial = p.ReadUInt32();
+ item = World.FindItem(serial);
+ bool isNew = false;
+ if (item == null)
+ {
+ World.AddItem(item = new Item(serial));
+ isNew = true;
+ }
+ else
+ {
+ item.CancelRemove();
+ }
+
+ if (!DragDropManager.EndHolding(serial))
+ return;
+
+ item.Container = null;
+
+ ushort itemID = p.ReadUInt16();
+ item.ItemID = (ushort)(_artDataID == 0x02 ? itemID | 0x4000 : itemID);
+
+ item.Direction = p.ReadByte();
+
+ ushort _amount = p.ReadUInt16();
+ item.Amount = _amount = p.ReadUInt16();
+
+ ushort x = p.ReadUInt16();
+ ushort y = p.ReadUInt16();
+ short z = p.ReadSByte();
+
+ item.Position = new Point3D(x, y, z);
+
+ byte _light = p.ReadByte();
+
+ item.Hue = p.ReadUInt16();
+
+ byte flags = p.ReadByte();
+
+ item.ProcessPacketFlags(flags);
+
+ if (Engine.UsePostHSChanges)
+ {
+ p.ReadUInt16();
+ }
+
+ if (isNew && World.Player != null)
+ {
+ if (item.ItemID == 0x2006)// corpse itemid = 0x2006
+ {
+ if (Config.GetBool("ShowCorpseNames"))
+ ClientCommunication.SendToServer(new SingleClick(item));
+ if (Config.GetBool("AutoOpenCorpses") && Utility.InRange(item.Position, World.Player.Position, Config.GetInt("CorpseRange")) && World.Player != null && World.Player.Visible)
+ PlayerData.DoubleClick(item);
+ }
+ else if (item.IsMulti)
+ {
+ }
+ else
+ {
+
+ }
+ }
+
+ Item.UpdateContainers();
+ }
+
+ public static List SysMessages = new List();
+
+ 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;
+ CEasyUO.EUOInterpreter.AddToJournal( text );
+ if (type == MessageType.Spell)
+ {
+ Spell s = Spell.Get(text.Trim());
+ bool replaced = false;
+ if (s != null)
+ {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder(Config.GetString("SpellFormat"));
+ 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)
+ {
+ ClientCommunication.SendToClient(new AsciiMessage(ser, body, MessageType.Spell, s.GetHue(hue), font, name, newText));
+ //ClientCommunication.SendToClient( new UnicodeMessage( ser, body, MessageType.Spell, s.GetHue( hue ), font, Language.CliLocName, 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"))
+ {
+ }
+
+ // Overhead message override
+ if (Config.GetBool("ShowOverheadMessages") && OverheadMessages.OverheadMessageList.Count > 0)
+ {
+ string overheadFormat = Config.GetString("OverheadFormat");
+
+ foreach (OverheadMessages.OverheadMessage message in OverheadMessages.OverheadMessageList)
+ {
+ if (text.IndexOf(message.SearchMessage, StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ World.Player.OverheadMessage(overheadFormat.Replace("{msg}", message.MessageOverhead));
+ break;
+ }
+ }
+ }
+ }
+
+ 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.DisplayName.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)
+ {
+ ClientCommunication.SendToClient(new AsciiMessage(ser, item.ItemID.Value, MessageType.Label, label.Hue, 3, Language.CliLocName, labelDisplay));
+
+ }
+ else
+ {
+ ClientCommunication.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 (Config.GetBool("ForceSpeechHue"))
+ {
+ p.Seek(10, SeekOrigin.Begin);
+ p.Write((ushort)Config.GetInt("SpeechHue"));
+ }
+ }
+
+ if (!ser.IsValid || ser == World.Player.Serial || ser.IsItem)
+ {
+ SysMessages.Add(text);
+
+ if (SysMessages.Count >= 25)
+ SysMessages.RemoveRange(0, 10);
+ }
+ }
+
+ }
+
+ 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
+ ushort font = p.ReadUInt16();
+ string name = 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;
+
+ p.Seek(3, SeekOrigin.Begin);
+ p.WriteAsciiFixed("", (int)p.Length - 3);
+ }
+ else
+ {
+ HandleSpeech(p, args, serial, body, type, hue, font, "A", name, 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
+ 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);
+ }
+
+ 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
+ ushort font = p.ReadUInt16();
+ int num = p.ReadInt32();
+ string name = p.ReadStringSafe(30);
+ string ext_str = 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
+ {
+ type = MessageType.Spell;
+ }
+
+
+ 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(String.Format("Exception in Ultima.dll cliloc: {0}, {1}", num, ext_str), e));
+ }
+ }
+
+ 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
+ ushort font = p.ReadUInt16();
+ int num = p.ReadInt32();
+ byte affixType = p.ReadByte();
+ string name = 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
+ )
+ {
+ type = MessageType.Spell;
+ }
+
+ string text;
+ if ((affixType & 1) != 0) // prepend
+ text = String.Format("{0}{1}", affix, Language.ClilocFormat(num, args));
+ else // 0 == append, 2 = system
+ text = String.Format("{0}{1}", Language.ClilocFormat(num, args), affix);
+ HandleSpeech(p, phea, serial, body, type, hue, font, Language.CliLocName.ToUpper(), name, text);
+ }
+
+ private static void SendGump(PacketReader p, PacketHandlerEventArgs args)
+ {
+ if (World.Player == null)
+ return;
+
+ World.Player.CurrentGumpS = p.ReadUInt32();
+ World.Player.CurrentGumpI = p.ReadUInt32();
+ World.Player.HasGump = true;
+ World.Player.LastGumpOpenedAt = DateTime.UtcNow;
+
+ //byte[] data = p.CopyBytes( 11, p.Length - 11 );
+
+ //if (Macros.MacroManager.AcceptActions && MacroManager.Action(new WaitForGumpAction(World.Player.CurrentGumpI)))
+ // args.Block = true;
+ }
+
+ private static void ClientGumpResponse(PacketReader p, PacketHandlerEventArgs args)
+ {
+ if (World.Player == null)
+ return;
+
+ Serial ser = p.ReadUInt32();
+ uint tid = p.ReadUInt32();
+ int bid = p.ReadInt32();
+
+ World.Player.HasGump = false;
+
+ int sc = p.ReadInt32();
+ if (sc < 0 || sc > 2000)
+ return;
+ int[] switches = new int[sc];
+ for (int i = 0; i < sc; i++)
+ switches[i] = p.ReadInt32();
+
+ int ec = p.ReadInt32();
+ if (ec < 0 || ec > 2000)
+ return;
+ GumpTextEntry[] entries = new GumpTextEntry[ec];
+ for (int i = 0; i < ec; i++)
+ {
+ ushort id = p.ReadUInt16();
+ ushort len = p.ReadUInt16();
+ if (len >= 240)
+ return;
+ string text = p.ReadUnicodeStringSafe(len);
+ entries[i] = new GumpTextEntry(id, text);
+ }
+
+ // if (Macros.MacroManager.AcceptActions)
+ // MacroManager.Action(new GumpResponseAction(bid, switches, entries));
+ if(bid != 0)
+ World.Player.LastGumpResponseAction = new GumpResponseAction(bid, switches, entries);
+ }
+
+ private static void ChangeSeason(PacketReader p, PacketHandlerEventArgs args)
+ {
+
+ }
+
+ private static void ExtendedPacket(PacketReader p, PacketHandlerEventArgs args)
+ {
+ ushort type = p.ReadUInt16();
+
+ switch (type)
+ {
+ case 0x04: // close gump
+ {
+ // int serial, int tid
+ if (World.Player != null)
+ World.Player.HasGump = false;
+ break;
+ }
+ case 0x06: // party messages
+ {
+ OnPartyMessage(p, args);
+ break;
+ }
+ case 0x08: // map change
+ {
+ if (World.Player != null)
+ World.Player.Map = p.ReadByte();
+ break;
+ }
+ case 0x14: // context menu
+ {
+ p.ReadInt16(); // 0x01
+ UOEntity ent = null;
+ Serial ser = p.ReadUInt32();
+ if (ser.IsMobile)
+ ent = World.FindMobile(ser);
+ else if (ser.IsItem)
+ ent = World.FindItem(ser);
+
+ if (ent != null)
+ {
+ byte count = p.ReadByte();
+
+ try
+ {
+ ent.ContextMenu.Clear();
+
+ for (int i = 0; i < count; i++)
+ {
+ ushort idx = p.ReadUInt16();
+ ushort num = p.ReadUInt16();
+ ushort flags = p.ReadUInt16();
+ ushort color = 0;
+
+ if ((flags & 0x02) != 0)
+ color = p.ReadUInt16();
+
+ ent.ContextMenu.Add(idx, num);
+ }
+ }
+ catch
+ {
+ }
+ }
+ break;
+ }
+ case 0x18: // map patches
+ {
+ if (World.Player != null)
+ {
+ int count = p.ReadInt32() * 2;
+ try
+ {
+ World.Player.MapPatches = new int[count];
+ for (int i = 0; i < count; i++)
+ World.Player.MapPatches[i] = p.ReadInt32();
+ }
+ catch
+ {
+ }
+ }
+ break;
+ }
+ case 0x19: // stat locks
+ {
+ if (p.ReadByte() == 0x02)
+ {
+ 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);
+ }
+ }
+ break;
+ }
+ case 0x1D: // Custom House "General Info"
+ {
+ Item i = World.FindItem(p.ReadUInt32());
+ if (i != null)
+ i.HouseRevision = p.ReadInt32();
+ break;
+ }
+ }
+ }
+
+ public static int SpecialPartySent = 0;
+ public static int SpecialPartyReceived = 0;
+
+ private static void RunUOProtocolExtention(PacketReader p, PacketHandlerEventArgs args)
+ {
+ args.Block = true;
+
+ switch (p.ReadByte())
+ {
+ case 1: // Custom Party information
+ {
+ Serial serial;
+
+ PacketHandlers.SpecialPartyReceived++;
+
+ while ((serial = p.ReadUInt32()) > 0)
+ {
+ Mobile mobile = World.FindMobile(serial);
+
+ short x = p.ReadInt16();
+ short y = p.ReadInt16();
+ byte map = p.ReadByte();
+
+ if (mobile == null)
+ {
+ World.AddMobile(mobile = new Mobile(serial));
+ mobile.Visible = false;
+ }
+
+ if (mobile.Name == null || mobile.Name.Length <= 0)
+ mobile.Name = "(Not Seen)";
+
+ if (!m_Party.Contains(serial))
+ m_Party.Add(serial);
+
+ if (map == World.Player.Map)
+ mobile.Position = new Point3D(x, y, mobile.Position.Z);
+ else
+ mobile.Position = Point3D.Zero;
+ }
+
+
+
+ break;
+ }
+ case 0xFE: // Begin Handshake/Features Negotiation
+ {
+ ulong features = p.ReadRawUInt64();
+
+
+ ClientCommunication.SendToServer(new RazorNegotiateResponse());
+
+ break;
+ }
+ }
+ }
+
+ private static List m_Party = new List();
+ public static List Party { get { return m_Party; } }
+ private static Timer m_PartyDeclineTimer = null;
+ public static Serial PartyLeader = Serial.Zero;
+
+ private static void OnPartyMessage(PacketReader p, PacketHandlerEventArgs args)
+ {
+ switch (p.ReadByte())
+ {
+ case 0x01: // List
+ {
+ m_Party.Clear();
+
+ int count = p.ReadByte();
+ for (int i = 0; i < count; i++)
+ {
+ Serial s = p.ReadUInt32();
+ if (World.Player == null || s != World.Player.Serial)
+ m_Party.Add(s);
+ }
+
+ break;
+ }
+ case 0x02: // Remove Member/Re-list
+ {
+ m_Party.Clear();
+ int count = p.ReadByte();
+ Serial remSerial = p.ReadUInt32(); // the serial of who was removed
+
+ if (World.Player != null)
+ {
+ Mobile rem = World.FindMobile(remSerial);
+ if (rem != null && !Utility.InRange(World.Player.Position, rem.Position, World.Player.VisRange))
+ rem.Remove();
+ }
+
+ for (int i = 0; i < count; i++)
+ {
+ Serial s = p.ReadUInt32();
+ if (World.Player == null || s != World.Player.Serial)
+ m_Party.Add(s);
+ }
+
+ break;
+ }
+ case 0x03: // text message
+
+ case 0x04: // 3 = private, 4 = public
+ {
+ Serial s = p.ReadUInt32();
+ string text = p.ReadUnicodeStringSafe();
+
+
+ var data = new List();
+
+ if (text.StartsWith("New marker: "))
+ {
+ string name = World.FindMobile(s).Name;
+ string trimmed = text.Substring(12);
+ string[] message = trimmed.Split(',');
+ data.Add(message);
+
+ foreach (string[] line in data)
+ {
+ float x = float.Parse(line[0]);
+ float y = float.Parse(line[1]);
+ string displayText = line[2];
+ string extraText = line[3];
+
+ string markerOwner = name;
+ }
+ }
+ break;
+ }
+ case 0x07: // party invite
+ {
+ //Serial leader = p.ReadUInt32();
+ PartyLeader = p.ReadUInt32();
+
+
+
+ break;
+ }
+ }
+
+;
+ }
+
+ private static void PartyAutoDecline()
+ {
+ PartyLeader = Serial.Zero;
+ }
+
+ private static void PingResponse(PacketReader p, PacketHandlerEventArgs args)
+ {
+
+ }
+
+ private static void ClientEncodedPacket(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial serial = p.ReadUInt32();
+ ushort packetID = p.ReadUInt16();
+ switch (packetID)
+ {
+ case 0x19: // set ability
+ {
+ int ability = 0;
+ if (p.ReadByte() == 0)
+ ability = p.ReadInt32();
+
+ // if (ability >= 0 && ability < (int)AOSAbility.Invalid && Macros.MacroManager.AcceptActions)
+ // MacroManager.Action(new SetAbilityAction((AOSAbility)ability));
+ break;
+ }
+ }
+ }
+
+ private static void GameLogin(Packet p, PacketHandlerEventArgs args)
+ {
+ int authID = p.ReadInt32();
+
+ World.AccountName = p.ReadString(30);
+
+ // TODO: Do we need to store account name?
+ }
+
+ private static void MenuResponse(PacketReader pvSrc, PacketHandlerEventArgs args)
+ {
+ if (World.Player == null)
+ return;
+
+ uint serial = pvSrc.ReadUInt32();
+ ushort menuID = pvSrc.ReadUInt16();
+ ushort index = pvSrc.ReadUInt16();
+ ushort itemID = pvSrc.ReadUInt16();
+ ushort hue = pvSrc.ReadUInt16();
+
+ World.Player.HasMenu = false;
+ // if (MacroManager.AcceptActions)
+ // MacroManager.Action(new MenuResponseAction(index, itemID, hue));
+ }
+
+ private static void SendMenu(PacketReader p, PacketHandlerEventArgs args)
+ {
+ if (World.Player == null)
+ return;
+
+ World.Player.CurrentMenuS = p.ReadUInt32();
+ World.Player.CurrentMenuI = p.ReadUInt16();
+ World.Player.HasMenu = true;
+ // if (MacroManager.AcceptActions && MacroManager.Action(new WaitForMenuAction(World.Player.CurrentMenuI)))
+ // args.Block = true;
+ }
+
+ private static void HueResponse(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial serial = p.ReadUInt32();
+ ushort iid = p.ReadUInt16();
+ ushort hue = p.ReadUInt16();
+
+ if (serial == Serial.MinusOne)
+ {
+
+ args.Block = true;
+ }
+ }
+
+ private static void ServerAddress(Packet p, PacketHandlerEventArgs args)
+ {
+
+ }
+
+ private static void Features(PacketReader p, PacketHandlerEventArgs args)
+ {
+ if (World.Player != null)
+ World.Player.Features = p.ReadUInt16();
+ }
+
+ private static void PersonalLight(PacketReader p, PacketHandlerEventArgs args)
+ {
+ if (World.Player != null && !args.Block)
+ {
+ p.ReadUInt32(); // serial
+
+ World.Player.LocalLightLevel = p.ReadSByte();
+
+ if (EnforceLightLevels(World.Player.LocalLightLevel))
+ args.Block = true;
+ }
+ }
+
+ private static void GlobalLight(PacketReader p, PacketHandlerEventArgs args)
+ {
+ if (World.Player != null && !args.Block)
+ {
+ World.Player.GlobalLightLevel = p.ReadByte();
+
+ if (EnforceLightLevels(World.Player.GlobalLightLevel))
+ args.Block = true;
+ }
+ }
+
+ private static bool EnforceLightLevels(int lightLevel)
+ {
+ if (Config.GetBool("MinMaxLightLevelEnabled"))
+ {
+ // 0 bright, 30 is dark
+
+ if (lightLevel < Config.GetInt("MaxLightLevel"))
+ {
+ lightLevel = Convert.ToByte(Config.GetInt("MaxLightLevel")); // light level is too light
+ }
+ else if (lightLevel > Config.GetInt("MinLightLevel")) // light level is too dark
+ {
+ lightLevel = Convert.ToByte(Config.GetInt("MinLightLevel"));
+ }
+ else // No need to block or do anything special
+ {
+ return false;
+ }
+
+ World.Player.LocalLightLevel = 0;
+ World.Player.GlobalLightLevel = (byte) lightLevel;
+
+ ClientCommunication.SendToClient(new GlobalLightLevel(lightLevel));
+ ClientCommunication.SendToClient(new PersonalLightLevel(World.Player));
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void ServerSetWarMode(PacketReader p, PacketHandlerEventArgs args)
+ {
+ World.Player.Warmode = p.ReadBoolean();
+ }
+
+ private static void CustomHouseInfo(PacketReader p, PacketHandlerEventArgs args)
+ {
+ p.ReadByte(); // compression
+ p.ReadByte(); // Unknown
+
+ Item i = World.FindItem(p.ReadUInt32());
+ if (i != null)
+ {
+ i.HouseRevision = p.ReadInt32();
+ i.HousePacket = p.CopyBytes(0, p.Length);
+ }
+ }
+
+ /*
+ Packet Build
+ 1. BYTE[1] Cmd
+ 2. BYTE[2] len
+ 3. BYTE[4] Player Serial
+ 4. BYTE[4] Gump ID
+ 5. BYTE[4] x
+ 6. BYTE[4] y
+ 7. BYTE[4] Compressed Gump Layout Length (CLen)
+ 8. BYTE[4] Decompressed Gump Layout Length (DLen)
+ 9. BYTE[CLen-4] Gump Data, zlib compressed
+ 10. BYTE[4] Number of text lines
+ 11. BYTE[4] Compressed Text Line Length (CTxtLen)
+ 12. BYTE[4] Decompressed Text Line Length (DTxtLen)
+ 13. BYTE[CTxtLen-4] Gump's Compressed Text data, zlib compressed
+ */
+ private static void CompressedGump(PacketReader p, PacketHandlerEventArgs args)
+ {
+ World.Player.HasGump = true;
+ if (World.Player == null)
+ return;
+
+ World.Player.CurrentGumpS = p.ReadUInt32();
+ World.Player.CurrentGumpI = p.ReadUInt32();
+ World.Player.LastGumpX = p.ReadUInt32();
+ World.Player.LastGumpY = p.ReadUInt32();
+ World.Player.LastGumpWidth = 0;
+ World.Player.LastGumpHeight = 0;
+
+ World.Player.LastGumpOpenedAt = DateTime.UtcNow;
+
+ // if (Macros.MacroManager.AcceptActions && MacroManager.Action(new WaitForGumpAction(World.Player.CurrentGumpI)))
+ // args.Block = true;
+
+ List gumpStrings = new List();
+
+ try
+ {
+
+ string layout = p.GetCompressedReader().ReadString();
+
+ int numStrings = p.ReadInt32();
+ if (numStrings < 0 || numStrings > 256)
+ numStrings = 0;
+
+ // Split on one or more non-digit characters.
+ World.Player.CurrentGumpStrings.Clear();
+
+ string[] numbers = Regex.Split(layout, @"\D+");
+
+ foreach (string value in numbers)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ int i = int.Parse(value);
+ if ((i >= 500000 && i <= 503405) || (i >= 1000000 && i <= 1155584) || (i >= 3000000 && i <= 3011032))
+ gumpStrings.Add(Language.GetString(i));
+ }
+ }
+
+ PacketReader pComp = p.GetCompressedReader();
+ int len = 0;
+ int x1 = 0;
+ string[] stringlistparse = new string[numStrings];
+
+ while (!pComp.AtEnd && (len = pComp.ReadInt16()) > 0)
+ {
+ string tempString = pComp.ReadUnicodeString(len);
+ stringlistparse[x1] = tempString;
+ x1++;
+ }
+
+ if (TryParseGump(layout, out string[] gumpPieces))
+ {
+ gumpStrings.AddRange(ParseGumpString(gumpPieces, stringlistparse));
+ }
+
+ World.Player.CurrentGumpStrings.AddRange(gumpStrings);
+ World.Player.CurrentGumpRawData = layout; // Get raw data of current gump
+ }
+ catch { }
+ }
+
+ private static bool TryParseGump(string gumpData, out string[] pieces)
+ {
+ List i = new List();
+ int dataIndex = 0;
+ while (dataIndex < gumpData.Length)
+ {
+ if (gumpData.Substring(dataIndex) == "\0")
+ {
+ break;
+ }
+ else
+ {
+ int begin = gumpData.IndexOf("{", dataIndex);
+ int end = gumpData.IndexOf("}", dataIndex + 1);
+ if ((begin != -1) && (end != -1))
+ {
+ string sub = gumpData.Substring(begin + 1, end - begin - 1).Trim();
+ i.Add(sub);
+ dataIndex = end;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ pieces = i.ToArray();
+ return (pieces.Length > 0);
+ }
+
+ private static List ParseGumpString(string[] gumpPieces, string[] gumpLines)
+ {
+ List gumpText = new List();
+ for (int i = 0; i < gumpPieces.Length; i++)
+ {
+ string[] gumpParams = Regex.Split(gumpPieces[i], @"\s+");
+ switch (gumpParams[0].ToLower())
+ {
+
+ 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;
+ case "resizepic":
+ World.Player.LastGumpWidth = Math.Max( int.Parse( gumpParams[4] ), World.Player.LastGumpWidth );
+ World.Player.LastGumpHeight = Math.Max( int.Parse( gumpParams[5] ), World.Player.LastGumpHeight );
+ break;
+ }
+ }
+
+ return gumpText;
+ }
+
+ private static void ResurrectionGump(PacketReader p, PacketHandlerEventArgs args)
+ {
+
+ }
+
+ private static void BuffDebuff(PacketReader p, PacketHandlerEventArgs args)
+ {
+ Serial ser = p.ReadUInt32();
+ ushort icon = p.ReadUInt16();
+ ushort action = p.ReadUInt16();
+
+ if (Enum.IsDefined(typeof(BuffIcon), icon))
+ {
+ BuffIcon buff = (BuffIcon)icon;
+
+ string format = Config.GetString("BuffDebuffFormat");
+ if (string.IsNullOrEmpty(format))
+ {
+ format = "[{action}{name}]";
+ }
+
+ switch (action)
+ {
+ case 0x01: // show
+
+ p.ReadUInt32(); //0x000
+ p.ReadUInt16(); //icon # again..?
+ p.ReadUInt16(); //0x1 = show
+ p.ReadUInt32(); //0x000
+ ushort duration = p.ReadUInt16();
+ p.ReadUInt16(); //0x0000
+ p.ReadByte(); //0x0
+
+ BuffsDebuffs buffInfo = new BuffsDebuffs
+ {
+ IconNumber = icon,
+ BuffIcon = (BuffIcon)icon,
+ ClilocMessage1 = Language.GetCliloc((int)p.ReadUInt32()),
+ ClilocMessage2 = Language.GetCliloc((int)p.ReadUInt32()),
+ Duration = duration,
+ Timestamp = DateTime.UtcNow
+ };
+
+ if (World.Player != null && World.Player.BuffsDebuffs.All(b => b.BuffIcon != buff))
+ {
+ World.Player.BuffsDebuffs.Add(buffInfo);
+
+ if (Config.GetBool("ShowBuffDebuffOverhead"))
+ {
+ World.Player.OverheadMessage(88, format.Replace("{action}", "+").Replace("{name}", buffInfo.ClilocMessage1));
+ }
+ }
+
+ break;
+
+ case 0x0: // remove
+ if (World.Player != null)// && World.Player.BuffsDebuffs.Any(b => b.BuffIcon == buff))
+ {
+ if (Config.GetBool("ShowBuffDebuffOverhead"))
+ {
+ string buffRemoveInfo = World.Player.BuffsDebuffs.Where(b => b.BuffIcon == buff).Select(x => x.ClilocMessage1).FirstOrDefault();
+ World.Player.OverheadMessage(338, format.Replace("{action}", "-").Replace("{name}", buffRemoveInfo));
+ }
+
+ World.Player.BuffsDebuffs.RemoveAll(b => b.BuffIcon == buff);
+ }
+
+ break;
+ }
+
+ }
+
+ if (World.Player != null && World.Player.BuffsDebuffs.Count > 0)
+ {
+ BuffsTimer.Start();
+ }
+ else
+ {
+ BuffsTimer.Stop();
+ }
+ }
+
+ private static void AttackRequest(Packet p, PacketHandlerEventArgs args)
+ {
+
+ }
+
+ private static void TradeRequest(PacketReader p, PacketHandlerEventArgs args)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Network/Packet.cs b/Network/Packet.cs
new file mode 100644
index 0000000..e59c676
--- /dev/null
+++ b/Network/Packet.cs
@@ -0,0 +1,2428 @@
+using System;
+
+using System.IO;
+
+using System.Text;
+
+using System.Collections;
+
+
+
+namespace Assistant
+
+{
+
+ public enum PacketPath
+
+ {
+
+ ClientToServer,
+
+ RazorToServer,
+
+ ServerToClient,
+
+ RazorToClient,
+
+
+
+ PacketVideo
+
+ }
+
+
+
+ public class Packet
+
+ {
+
+ private static bool m_Logging = false;
+
+ public static bool Logging
+
+ {
+
+ get
+
+ {
+
+ return m_Logging;
+
+ }
+
+ set
+
+ {
+
+ if ( value != m_Logging )
+
+ {
+
+ m_Logging = value;
+
+ if ( m_Logging )
+
+ BeginLog();
+
+ }
+
+ }
+
+ }
+
+
+
+ public static string PacketsLogFile
+
+ {
+
+ get
+
+ {
+
+ return "";// return Path.Combine( Config.GetInstallDirectory(), "Razor_Packets.log" );
+
+ }
+
+ }
+
+
+
+ private static void BeginLog()
+
+ {
+
+ using ( StreamWriter sw = new StreamWriter( PacketsLogFile, true ) )
+
+ {
+
+ sw.AutoFlush = true;
+
+ sw.WriteLine();
+
+ sw.WriteLine();
+
+ sw.WriteLine();
+
+ sw.WriteLine( ">>>>>>>>>> Logging started {0} <<<<<<<<<<", DateTime.UtcNow );
+
+ sw.WriteLine();
+
+ sw.WriteLine();
+
+ }
+
+ }
+
+
+
+ private static byte[] m_Buffer = new byte[4]; // Internal format buffer.
+
+ private MemoryStream m_Stream;
+
+ private bool m_DynSize;
+
+ private byte m_PacketID;
+
+
+
+ public Packet()
+
+ {
+
+ m_Stream = new MemoryStream();
+
+ }
+
+
+
+ public Packet( byte packetID )
+
+ {
+
+ m_PacketID = packetID;
+
+ m_DynSize = true;
+
+ }
+
+
+
+ public Packet( byte packetID, int capacity )
+
+ {
+
+ m_Stream = new MemoryStream( capacity );
+
+
+
+ m_PacketID = packetID;
+
+ m_DynSize = false;
+
+
+
+ m_Stream.WriteByte( packetID );
+
+ }
+
+
+
+ public Packet( byte[] data, int len, bool dynLen )
+
+ {
+
+ m_Stream = new MemoryStream( len );
+
+ m_PacketID = data[0];
+
+ m_DynSize = dynLen;
+
+
+
+ m_Stream.Position = 0;
+
+ m_Stream.Write( data, 0, len );
+
+
+
+ MoveToData();
+
+ }
+
+
+
+ public void EnsureCapacity( int capacity )
+
+ {
+
+ m_Stream = new MemoryStream( capacity );
+
+ Write( (byte)m_PacketID );
+
+ if ( m_DynSize )
+
+ Write( (short)0 );
+
+ }
+
+
+
+ public byte[] Compile()
+
+ {
+
+ if ( m_DynSize )
+
+ {
+
+ m_Stream.Seek( 1, SeekOrigin.Begin );
+
+ Write( (ushort)m_Stream.Length );
+
+ }
+
+
+
+ return ToArray();
+
+ }
+
+
+
+ public void MoveToData()
+
+ {
+
+ m_Stream.Position = m_DynSize ? 3 : 1;
+
+ }
+
+
+
+ public void Copy( Packet p )
+
+ {
+
+ m_Stream = new MemoryStream( (int)p.Length );
+
+ byte[] data = p.ToArray();
+
+ m_Stream.Write( data, 0, data.Length );
+
+
+
+ m_DynSize = p.m_DynSize;
+
+ m_PacketID = p.m_PacketID;
+
+
+
+ MoveToData();
+
+ }
+
+
+
+ /*public override int GetHashCode()
+
+ {
+
+ long oldPos = m_Stream.Position;
+
+
+
+ int code = 0;
+
+
+
+ m_Stream.Position = 0;
+
+
+
+ while ( m_Stream.Length - m_Stream.Position >= 4 )
+
+ code ^= ReadInt32();
+
+
+
+ code ^= ReadByte() | (ReadByte() << 8) | (ReadByte() << 16) | (ReadByte() << 24);
+
+
+
+ m_Stream.Position = oldPos;
+
+
+
+ return code;
+
+ }*/
+
+
+
+ public static void Log( string line, params object[] args )
+
+ {
+
+ Log( String.Format( line, args ) );
+
+ }
+
+
+
+ public static void Log( string line )
+
+ {
+
+ if ( !m_Logging )
+
+ return;
+
+
+
+ try
+
+ {
+
+ using ( StreamWriter sw = new StreamWriter( PacketsLogFile, true ) )
+
+ {
+
+ sw.AutoFlush = true;
+
+ sw.WriteLine( line );
+
+ sw.WriteLine();
+
+ }
+
+ }
+
+ catch
+
+ {
+
+ }
+
+ }
+
+
+
+ public static unsafe void Log( PacketPath path, byte* buff, int len )
+
+ {
+
+ Log( path, buff, len, false );
+
+ }
+
+
+
+ public static unsafe void Log( PacketPath path, byte* buff, int len, bool blocked )
+
+ {
+
+ if ( !m_Logging )
+
+ return;
+
+
+
+ try
+
+ {
+
+ using ( StreamWriter sw = new StreamWriter( PacketsLogFile, true ) )
+
+ {
+
+ sw.AutoFlush = true;
+
+
+
+ string pathStr;
+
+ switch ( path )
+
+ {
+
+ case PacketPath.ClientToServer:
+
+ pathStr = "Client -> Server";
+
+ break;
+
+ case PacketPath.RazorToServer:
+
+ pathStr = "Razor -> Server";
+
+ break;
+
+ case PacketPath.ServerToClient:
+
+ pathStr = "Server -> Client";
+
+ break;
+
+ case PacketPath.RazorToClient:
+
+ pathStr = "Razor -> Client";
+
+ break;
+
+ case PacketPath.PacketVideo:
+
+ pathStr = "PacketVideo -> Client";
+
+ break;
+
+ default:
+
+ pathStr = "Unknown -> Unknown";
+
+ break;
+
+ }
+
+
+
+ //sw.WriteLine( "{0}: {1}{2}0x{3:X2} (Length: {4})", Engine.MistedDateTime.ToString( "HH:mm:ss.ffff" ), pathStr, blocked ? " [BLOCKED] " : " ", buff[0], len );
+
+ //if ( buff[0] != 0x80 && buff[0] != 0x91 )
+
+ // Utility.FormatBuffer( sw, buff, len );
+
+ //else
+
+ // sw.WriteLine( "[Censored for Security Reasons]" );
+
+
+
+ sw.WriteLine();
+
+ sw.WriteLine();
+
+ }
+
+ }
+
+ catch
+
+ {
+
+ }
+
+ }
+
+
+
+ public long Seek( int offset, SeekOrigin origin )
+
+ {
+
+ return m_Stream.Seek( offset, origin );
+
+ }
+
+
+
+ public int ReadInt32()
+
+ {
+
+ if ( m_Stream.Position + 4 > m_Stream.Length )
+
+ return 0;
+
+
+
+ return ( ReadByte() << 24 )
+
+ | ( ReadByte() << 16 )
+
+ | ( ReadByte() << 8 )
+
+ | ReadByte();
+
+ }
+
+
+
+ public short ReadInt16()
+
+ {
+
+ if ( m_Stream.Position + 2 > m_Stream.Length )
+
+ return 0;
+
+ return (short)( ( ReadByte() << 8 ) | ReadByte() );
+
+ }
+
+
+
+ public byte ReadByte()
+
+ {
+
+ if ( m_Stream.Position + 1 > m_Stream.Length )
+
+ return 0;
+
+ return (byte)m_Stream.ReadByte();
+
+ }
+
+
+
+ public uint ReadUInt32()
+
+ {
+
+ if ( m_Stream.Position + 4 > m_Stream.Length )
+
+ return 0;
+
+ return (uint)( ( ReadByte() << 24 )
+
+ | ( ReadByte() << 16 )
+
+ | ( ReadByte() << 8 )
+
+ | ReadByte() );
+
+ }
+
+
+
+ public ushort ReadUInt16()
+
+ {
+
+ if ( m_Stream.Position + 2 > m_Stream.Length )
+
+ return 0;
+
+ return (ushort)( ( ReadByte() << 8 ) | ReadByte() );
+
+ }
+
+
+
+ public sbyte ReadSByte()
+
+ {
+
+ if ( m_Stream.Position + 1 > m_Stream.Length )
+
+ return 0;
+
+ return (sbyte)m_Stream.ReadByte();
+
+ }
+
+
+
+ public bool ReadBoolean()
+
+ {
+
+ if ( m_Stream.Position + 1 > m_Stream.Length )
+
+ return false;
+
+ return ( m_Stream.ReadByte() != 0 );
+
+ }
+
+
+
+ public string ReadUnicodeStringLE()
+
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( m_Stream.Position + 1 < m_Stream.Length && ( c = ReadByte() | ( ReadByte() << 8 ) ) != 0 )
+
+ sb.Append( (char)c );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUnicodeStringLESafe()
+
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( m_Stream.Position + 1 < m_Stream.Length && ( c = ReadByte() | ( ReadByte() << 8 ) ) != 0 )
+
+ {
+
+ if ( IsSafeChar( c ) )
+
+ sb.Append( (char)c );
+
+ }
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUnicodeStringSafe()
+
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( m_Stream.Position + 1 < m_Stream.Length && ( c = ReadUInt16() ) != 0 )
+
+ {
+
+ if ( IsSafeChar( c ) )
+
+ sb.Append( (char)c );
+
+ }
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUnicodeString()
+
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( m_Stream.Position + 1 < m_Stream.Length && ( c = ReadUInt16() ) != 0 )
+
+ sb.Append( (char)c );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public bool IsSafeChar( int c )
+
+ {
+
+ return ( c >= 0x20 && c < 0xFFFE );
+
+ }
+
+
+
+ public string ReadUTF8StringSafe( int fixedLength )
+
+ {
+
+ if ( m_Stream.Position >= m_Stream.Length )
+
+ return String.Empty;
+
+
+
+ long bound = m_Stream.Position + fixedLength;
+
+ long end = bound;
+
+
+
+ if ( bound > m_Stream.Length )
+
+ bound = m_Stream.Length;
+
+
+
+ int count = 0;
+
+ long index = m_Stream.Position;
+
+ long start = m_Stream.Position;
+
+
+
+ while ( index < bound && ReadByte() != 0 )
+
+ ++count;
+
+
+
+ m_Stream.Seek( start, SeekOrigin.Begin );
+
+
+
+ index = 0;
+
+
+
+ byte[] buffer = new byte[count];
+
+ int value = 0;
+
+
+
+ while ( m_Stream.Position < bound && ( value = ReadByte() ) != 0 )
+
+ buffer[index++] = (byte)value;
+
+
+
+ string s = Encoding.UTF8.GetString( buffer );
+
+
+
+ bool isSafe = true;
+
+
+
+ for ( int i = 0; isSafe && i < s.Length; ++i )
+
+ isSafe = IsSafeChar( (int)s[i] );
+
+
+
+ m_Stream.Seek( start + fixedLength, SeekOrigin.Begin );
+
+
+
+ if ( isSafe )
+
+ return s;
+
+
+
+ StringBuilder sb = new StringBuilder( s.Length );
+
+
+
+ for ( int i = 0; i < s.Length; ++i )
+
+ {
+
+ if ( IsSafeChar( (int)s[i] ) )
+
+ sb.Append( s[i] );
+
+ }
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUTF8StringSafe()
+
+ {
+
+ if ( m_Stream.Position >= m_Stream.Length )
+
+ return String.Empty;
+
+
+
+ int count = 0;
+
+ long index = m_Stream.Position;
+
+ long start = index;
+
+
+
+ while ( index < m_Stream.Length && ReadByte() != 0 )
+
+ ++count;
+
+
+
+ m_Stream.Seek( start, SeekOrigin.Begin );
+
+
+
+ index = 0;
+
+
+
+ byte[] buffer = new byte[count];
+
+ int value = 0;
+
+
+
+ while ( m_Stream.Position < m_Stream.Length && ( value = ReadByte() ) != 0 )
+
+ buffer[index++] = (byte)value;
+
+
+
+ string s = Encoding.UTF8.GetString( buffer );
+
+
+
+ bool isSafe = true;
+
+
+
+ for ( int i = 0; isSafe && i < s.Length; ++i )
+
+ isSafe = IsSafeChar( (int)s[i] );
+
+
+
+ if ( isSafe )
+
+ return s;
+
+
+
+ StringBuilder sb = new StringBuilder( s.Length );
+
+
+
+ for ( int i = 0; i < s.Length; ++i )
+
+ {
+
+ if ( IsSafeChar( (int)s[i] ) )
+
+ sb.Append( s[i] );
+
+ }
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUTF8String()
+
+ {
+
+ if ( m_Stream.Position >= m_Stream.Length )
+
+ return String.Empty;
+
+
+
+ int count = 0;
+
+ long index = m_Stream.Position;
+
+ long start = index;
+
+
+
+ while ( index < m_Stream.Length && ReadByte() != 0 )
+
+ ++count;
+
+
+
+ m_Stream.Seek( start, SeekOrigin.Begin );
+
+
+
+ index = 0;
+
+
+
+ byte[] buffer = new byte[count];
+
+ int value = 0;
+
+
+
+ while ( m_Stream.Position < m_Stream.Length && ( value = ReadByte() ) != 0 )
+
+ buffer[index++] = (byte)value;
+
+
+
+ return Encoding.UTF8.GetString( buffer );
+
+ }
+
+
+
+ public string ReadString()
+
+ {
+
+ return ReadStringSafe();
+
+ }
+
+
+
+ public string ReadStringSafe()
+
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( m_Stream.Position < m_Stream.Length && ( c = ReadByte() ) != 0 )
+
+ sb.Append( (char)c );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUnicodeStringSafe( int fixedLength )
+
+ {
+
+ return ReadUnicodeString( fixedLength );
+
+ }
+
+
+
+ public string ReadUnicodeString( int fixedLength )
+
+ {
+
+ long bound = m_Stream.Position + ( fixedLength << 1 );
+
+ long end = bound;
+
+
+
+ if ( bound > m_Stream.Length )
+
+ bound = m_Stream.Length;
+
+
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( ( m_Stream.Position + 1 ) < bound && ( c = ReadUInt16() ) != 0 )
+
+ if ( IsSafeChar( c ) )
+
+ sb.Append( (char)c );
+
+
+
+ m_Stream.Seek( end, SeekOrigin.Begin );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadStringSafe( int fixedLength )
+
+ {
+
+ return ReadString( fixedLength );
+
+ }
+
+
+
+ public string ReadString( int fixedLength )
+
+ {
+
+ long bound = m_Stream.Position + fixedLength;
+
+
+
+ if ( bound > m_Stream.Length )
+
+ bound = m_Stream.Length;
+
+
+
+ long end = bound;
+
+
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( m_Stream.Position < bound && ( c = ReadByte() ) != 0 )
+
+ sb.Append( (char)c );
+
+
+
+ m_Stream.Seek( end, SeekOrigin.Begin );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+
+
+
+
+
+ /////////////////////////////////////////////
+
+ ///Packet Writer/////////////////////////////
+
+ /////////////////////////////////////////////
+
+ public void Write( bool value )
+
+ {
+
+ m_Stream.WriteByte( (byte)( value ? 1 : 0 ) );
+
+ }
+
+
+
+ public void Write( byte value )
+
+ {
+
+ m_Stream.WriteByte( value );
+
+ }
+
+
+
+ public void Write( sbyte value )
+
+ {
+
+ m_Stream.WriteByte( (byte)value );
+
+ }
+
+
+
+ public void Write( short value )
+
+ {
+
+ m_Buffer[0] = (byte)( value >> 8 );
+
+ m_Buffer[1] = (byte)value;
+
+
+
+ m_Stream.Write( m_Buffer, 0, 2 );
+
+ }
+
+
+
+ public void Write( ushort value )
+
+ {
+
+ m_Buffer[0] = (byte)( value >> 8 );
+
+ m_Buffer[1] = (byte)value;
+
+
+
+ m_Stream.Write( m_Buffer, 0, 2 );
+
+ }
+
+
+
+ public void Write( int value )
+
+ {
+
+ m_Buffer[0] = (byte)( value >> 24 );
+
+ m_Buffer[1] = (byte)( value >> 16 );
+
+ m_Buffer[2] = (byte)( value >> 8 );
+
+ m_Buffer[3] = (byte)value;
+
+
+
+ m_Stream.Write( m_Buffer, 0, 4 );
+
+ }
+
+
+
+ public void Write( uint value )
+
+ {
+
+ m_Buffer[0] = (byte)( value >> 24 );
+
+ m_Buffer[1] = (byte)( value >> 16 );
+
+ m_Buffer[2] = (byte)( value >> 8 );
+
+ m_Buffer[3] = (byte)value;
+
+
+
+ m_Stream.Write( m_Buffer, 0, 4 );
+
+ }
+
+
+
+ public void Write( byte[] buffer, int offset, int size )
+
+ {
+
+ m_Stream.Write( buffer, offset, size );
+
+ }
+
+
+
+ public void WriteAsciiFixed( string value, int size )
+
+ {
+
+ if ( value == null )
+
+ value = String.Empty;
+
+
+
+ byte[] buffer = Encoding.ASCII.GetBytes( value );
+
+
+
+ if ( buffer.Length >= size )
+
+ {
+
+ m_Stream.Write( buffer, 0, size );
+
+ }
+
+ else
+
+ {
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+
+
+ byte[] pad = new byte[size - buffer.Length];
+
+
+
+ m_Stream.Write( pad, 0, pad.Length );
+
+ }
+
+ }
+
+
+
+ public void WriteAsciiNull( string value )
+
+ {
+
+ if ( value == null )
+
+ value = String.Empty;
+
+
+
+ byte[] buffer = Encoding.ASCII.GetBytes( value );
+
+
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+ m_Stream.WriteByte( 0 );
+
+ }
+
+
+
+ public void WriteLittleUniNull( string value )
+
+ {
+
+ if ( value == null )
+
+ value = String.Empty;
+
+
+
+ byte[] buffer = Encoding.Unicode.GetBytes( value );
+
+
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+
+
+ m_Buffer[0] = 0;
+
+ m_Buffer[1] = 0;
+
+ m_Stream.Write( m_Buffer, 0, 2 );
+
+ }
+
+
+
+ public void WriteLittleUniFixed( string value, int size )
+
+ {
+
+ if ( value == null )
+
+ value = String.Empty;
+
+
+
+ size *= 2;
+
+
+
+ byte[] buffer = Encoding.Unicode.GetBytes( value );
+
+
+
+ if ( buffer.Length >= size )
+
+ {
+
+ m_Stream.Write( buffer, 0, size );
+
+ }
+
+ else
+
+ {
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+
+
+ byte[] pad = new byte[size - buffer.Length];
+
+
+
+ m_Stream.Write( pad, 0, pad.Length );
+
+ }
+
+ }
+
+
+
+ public void WriteBigUniNull( string value )
+
+ {
+
+ if ( value == null )
+
+ value = String.Empty;
+
+
+
+ byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
+
+
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+
+
+ m_Buffer[0] = 0;
+
+ m_Buffer[1] = 0;
+
+ m_Stream.Write( m_Buffer, 0, 2 );
+
+ }
+
+
+
+ public void WriteBigUniFixed( string value, int size )
+
+ {
+
+ if ( value == null )
+
+ value = String.Empty;
+
+
+
+ size *= 2;
+
+
+
+ byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
+
+
+
+ if ( buffer.Length >= size )
+
+ {
+
+ m_Stream.Write( buffer, 0, size );
+
+ }
+
+ else
+
+ {
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+
+
+ byte[] pad = new byte[size - buffer.Length];
+
+
+
+ m_Stream.Write( pad, 0, pad.Length );
+
+ }
+
+ }
+
+
+
+ public void WriteUTF8Fixed( string value, int size )
+
+ {
+
+ if ( value == null )
+
+ value = String.Empty;
+
+
+
+ size *= 2;
+
+
+
+ byte[] buffer = Encoding.UTF8.GetBytes( value );
+
+
+
+ if ( buffer.Length >= size )
+
+ {
+
+ m_Stream.Write( buffer, 0, size );
+
+ }
+
+ else
+
+ {
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+
+
+ byte[] pad = new byte[size - buffer.Length];
+
+
+
+ m_Stream.Write( pad, 0, pad.Length );
+
+ }
+
+ }
+
+
+
+ public void WriteUTF8Null( string value )
+
+ {
+
+ if ( value == null )
+
+ value = String.Empty;
+
+
+
+ byte[] buffer = Encoding.UTF8.GetBytes( value );
+
+
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+ m_Buffer[0] = 0;
+
+ m_Buffer[1] = 0;
+
+ m_Stream.Write( m_Buffer, 0, 2 );
+
+ }
+
+
+
+ public void Fill()
+
+ {
+
+ byte[] buffer = new byte[m_Stream.Capacity - Position];
+
+ m_Stream.Write( buffer, 0, buffer.Length );
+
+ }
+
+
+
+ public void Fill( int length )
+
+ {
+
+ m_Stream.Write( new byte[length], 0, length );
+
+ }
+
+
+
+ public int PacketID
+
+ {
+
+ get
+
+ {
+
+ return m_PacketID;
+
+ }
+
+ }
+
+
+
+ public long Length
+
+ {
+
+ get
+
+ {
+
+ return m_Stream.Length;
+
+ }
+
+ }
+
+
+
+ public long Position
+
+ {
+
+ get
+
+ {
+
+ return m_Stream.Position;
+
+ }
+
+ set
+
+ {
+
+ m_Stream.Position = value;
+
+ }
+
+ }
+
+
+
+ public MemoryStream UnderlyingStream
+
+ {
+
+ get
+
+ {
+
+ return m_Stream;
+
+ }
+
+ }
+
+
+
+ public long Seek( long offset, SeekOrigin origin )
+
+ {
+
+ return m_Stream.Seek( offset, origin );
+
+ }
+
+
+
+ public byte[] ToArray()
+
+ {
+
+ return m_Stream.ToArray();
+
+ }
+
+ }
+
+
+
+ public unsafe sealed class PacketReader
+
+ {
+
+ private byte* m_Data;
+
+ private int m_Pos;
+
+ private int m_Length;
+
+ private bool m_Dyn;
+
+
+
+ public PacketReader( byte* buff, int len, bool dyn )
+
+ {
+
+ m_Data = buff;
+
+ m_Length = len;
+
+ m_Pos = 0;
+
+ m_Dyn = dyn;
+
+ }
+
+
+
+ public PacketReader( byte[] buff, bool dyn )
+
+ {
+
+ fixed ( byte* p = buff )
+
+ m_Data = p;
+
+ m_Length = buff.Length;
+
+ m_Pos = 0;
+
+ m_Dyn = dyn;
+
+ }
+
+
+
+ public void MoveToData()
+
+ {
+
+ m_Pos = m_Dyn ? 3 : 1;
+
+ }
+
+
+
+ public int Seek( int offset, SeekOrigin origin )
+
+ {
+
+ switch ( origin )
+
+ {
+
+ case SeekOrigin.End:
+
+ m_Pos = m_Length - offset;
+
+ break;
+
+ case SeekOrigin.Current:
+
+ m_Pos += offset;
+
+ break;
+
+ case SeekOrigin.Begin:
+
+ m_Pos = offset;
+
+ break;
+
+ }
+
+ if ( m_Pos < 0 )
+
+ m_Pos = 0;
+
+ else if ( m_Pos > m_Length )
+
+ m_Pos = m_Length;
+
+ return m_Pos;
+
+ }
+
+
+
+ public int Length { get { return m_Length; } }
+
+ public bool DynamicLength { get { return m_Dyn; } }
+
+
+
+ public byte[] CopyBytes( int offset, int count )
+
+ {
+
+ byte[] read = new byte[count];
+
+ for ( m_Pos = offset; m_Pos < offset + count && m_Pos < m_Length; m_Pos++ )
+
+ read[m_Pos - offset] = m_Data[m_Pos];
+
+ return read;
+
+ }
+
+
+
+ public PacketReader GetCompressedReader()
+
+ {
+
+ int fullLen = ReadInt32();
+
+ int destLen = 0;
+
+ byte[] buff;
+
+
+
+ if ( fullLen >= 4 )
+
+ {
+
+ int packLen = ReadInt32();
+
+ destLen = packLen;
+
+
+
+ if ( destLen < 0 )
+
+ destLen = 0;
+
+
+
+ buff = new byte[destLen];
+
+
+
+ if ( fullLen > 4 && destLen > 0 )
+
+ {
+
+ if ( ZLib.uncompress( buff, ref destLen, CopyBytes( this.Position, fullLen - 4 ), fullLen - 4 ) != ZLibError.Z_OK )
+
+ {
+
+ destLen = 0;
+
+ buff = new byte[1];
+
+ }
+
+ }
+
+ else
+
+ {
+
+ destLen = 0;
+
+ buff = new byte[1];
+
+ }
+
+ }
+
+ else
+
+ {
+
+ buff = new byte[1];
+
+ }
+
+
+
+ return new PacketReader( buff, false );
+
+ }
+
+
+
+ public byte ReadByte()
+
+ {
+
+ if ( m_Pos + 1 > m_Length || m_Data == null )
+
+ return 0;
+
+ return m_Data[m_Pos++];
+
+ }
+
+
+
+ public int ReadInt32()
+
+ {
+
+ return ( ReadByte() << 24 )
+
+ | ( ReadByte() << 16 )
+
+ | ( ReadByte() << 8 )
+
+ | ReadByte();
+
+ }
+
+
+
+ public short ReadInt16()
+
+ {
+
+ return (short)( ( ReadByte() << 8 ) | ReadByte() );
+
+ }
+
+
+
+ public uint ReadUInt32()
+
+ {
+
+ return (uint)(
+
+ ( ReadByte() << 24 )
+
+ | ( ReadByte() << 16 )
+
+ | ( ReadByte() << 8 )
+
+ | ReadByte() );
+
+ }
+
+
+
+ public ulong ReadRawUInt64()
+
+ {
+
+ return (ulong)
+
+ ( ( (ulong)ReadByte() << 0 )
+
+ | ( (ulong)ReadByte() << 8 )
+
+ | ( (ulong)ReadByte() << 16 )
+
+ | ( (ulong)ReadByte() << 24 )
+
+ | ( (ulong)ReadByte() << 32 )
+
+ | ( (ulong)ReadByte() << 40 )
+
+ | ( (ulong)ReadByte() << 48 )
+
+ | ( (ulong)ReadByte() << 56 ) );
+
+ }
+
+
+
+ public ushort ReadUInt16()
+
+ {
+
+ return (ushort)( ( ReadByte() << 8 ) | ReadByte() );
+
+ }
+
+
+
+ public sbyte ReadSByte()
+
+ {
+
+ if ( m_Pos + 1 > m_Length )
+
+ return 0;
+
+ return (sbyte)m_Data[m_Pos++];
+
+ }
+
+
+
+ public bool ReadBoolean()
+
+ {
+
+ return ( ReadByte() != 0 );
+
+ }
+
+
+
+ public string ReadUnicodeStringLE()
+
+ {
+
+ return ReadUnicodeString();
+
+ }
+
+
+
+ public string ReadUnicodeStringLESafe()
+
+ {
+
+ return ReadUnicodeStringSafe();
+
+ }
+
+
+
+ public string ReadUnicodeStringSafe()
+
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( ( c = ReadUInt16() ) != 0 )
+
+ {
+
+ if ( IsSafeChar( c ) )
+
+ sb.Append( (char)c );
+
+ }
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUnicodeString()
+
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( ( c = ReadUInt16() ) != 0 )
+
+ sb.Append( (char)c );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public bool IsSafeChar( int c )
+
+ {
+
+ return ( c >= 0x20 && c < 0xFFFE );
+
+ }
+
+
+
+ public string ReadUTF8StringSafe( int fixedLength )
+
+ {
+
+ if ( m_Pos >= m_Length )
+
+ return String.Empty;
+
+
+
+ int bound = m_Pos + fixedLength;
+
+ int end = bound;
+
+
+
+ if ( bound > m_Length )
+
+ bound = m_Length;
+
+
+
+ int count = 0;
+
+ int index = m_Pos;
+
+ int start = m_Pos;
+
+
+
+ while ( index < bound && ReadByte() != 0 )
+
+ ++count;
+
+
+
+ Seek( start, SeekOrigin.Begin );
+
+
+
+ index = 0;
+
+
+
+ byte[] buffer = new byte[count];
+
+ int value = 0;
+
+
+
+ while ( m_Pos < bound && ( value = ReadByte() ) != 0 )
+
+ buffer[index++] = (byte)value;
+
+
+
+ string s = Encoding.UTF8.GetString( buffer );
+
+
+
+ bool isSafe = true;
+
+
+
+ for ( int i = 0; isSafe && i < s.Length; ++i )
+
+ isSafe = IsSafeChar( (int)s[i] );
+
+
+
+ Seek( start + fixedLength, SeekOrigin.Begin );
+
+
+
+ if ( isSafe )
+
+ return s;
+
+
+
+ StringBuilder sb = new StringBuilder( s.Length );
+
+
+
+ for ( int i = 0; i < s.Length; ++i )
+
+ {
+
+ if ( IsSafeChar( (int)s[i] ) )
+
+ sb.Append( s[i] );
+
+ }
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUTF8StringSafe()
+
+ {
+
+ if ( m_Pos >= m_Length )
+
+ return String.Empty;
+
+
+
+ int count = 0;
+
+ int index = m_Pos;
+
+ int start = index;
+
+
+
+ while ( index < m_Length && ReadByte() != 0 )
+
+ ++count;
+
+
+
+ Seek( start, SeekOrigin.Begin );
+
+
+
+ index = 0;
+
+
+
+ byte[] buffer = new byte[count];
+
+ int value = 0;
+
+
+
+ while ( m_Pos < m_Length && ( value = ReadByte() ) != 0 )
+
+ buffer[index++] = (byte)value;
+
+
+
+ string s = Encoding.UTF8.GetString( buffer );
+
+
+
+ bool isSafe = true;
+
+
+
+ for ( int i = 0; isSafe && i < s.Length; ++i )
+
+ isSafe = IsSafeChar( (int)s[i] );
+
+
+
+ if ( isSafe )
+
+ return s;
+
+
+
+ StringBuilder sb = new StringBuilder( s.Length );
+
+
+
+ for ( int i = 0; i < s.Length; ++i )
+
+ {
+
+ if ( IsSafeChar( (int)s[i] ) )
+
+ sb.Append( s[i] );
+
+ }
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUTF8String()
+
+ {
+
+ if ( m_Pos >= m_Length )
+
+ return String.Empty;
+
+
+
+ int count = 0;
+
+ int index = m_Pos;
+
+ int start = index;
+
+
+
+ while ( index < m_Length && ReadByte() != 0 )
+
+ ++count;
+
+
+
+ Seek( start, SeekOrigin.Begin );
+
+
+
+ index = 0;
+
+
+
+ byte[] buffer = new byte[count];
+
+ int value = 0;
+
+
+
+ while ( m_Pos < m_Length && ( value = ReadByte() ) != 0 )
+
+ buffer[index++] = (byte)value;
+
+
+
+ return Encoding.UTF8.GetString( buffer );
+
+ }
+
+
+
+ public string ReadString()
+
+ {
+
+ return ReadStringSafe();
+
+ }
+
+
+
+ public string ReadStringSafe()
+
+ {
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( m_Pos < m_Length && ( c = ReadByte() ) != 0 )
+
+ sb.Append( (char)c );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUnicodeStringSafe( int fixedLength )
+
+ {
+
+ return ReadUnicodeString( fixedLength );
+
+ }
+
+
+
+ public string ReadUnicodeString( int fixedLength )
+
+ {
+
+ int bound = m_Pos + ( fixedLength << 1 );
+
+ int end = bound;
+
+
+
+ if ( bound > m_Length )
+
+ bound = m_Length;
+
+
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( ( m_Pos + 1 ) < bound && ( c = ReadUInt16() ) != 0 )
+
+ if ( IsSafeChar( c ) )
+
+ sb.Append( (char)c );
+
+
+
+ Seek( end, SeekOrigin.Begin );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadUnicodeStringBE( int fixedLength )
+
+ {
+
+ int bound = m_Pos + ( fixedLength << 1 );
+
+ int end = bound;
+
+
+
+ if ( bound > m_Length )
+
+ bound = m_Length;
+
+
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( ( m_Pos + 1 ) < bound )
+
+ {
+
+ c = (ushort)( ReadByte() | ( ReadByte() << 8 ) );
+
+ sb.Append( (char)c );
+
+ }
+
+
+
+ Seek( end, SeekOrigin.Begin );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public string ReadStringSafe( int fixedLength )
+
+ {
+
+ return ReadString( fixedLength );
+
+ }
+
+
+
+ public string ReadString( int fixedLength )
+
+ {
+
+ int bound = m_Pos + fixedLength;
+
+ int end = bound;
+
+
+
+ if ( bound > m_Length )
+
+ bound = m_Length;
+
+
+
+ StringBuilder sb = new StringBuilder();
+
+
+
+ int c;
+
+
+
+ while ( m_Pos < bound && ( c = ReadByte() ) != 0 )
+
+ sb.Append( (char)c );
+
+
+
+ Seek( end, SeekOrigin.Begin );
+
+
+
+ return sb.ToString();
+
+ }
+
+
+
+ public byte PacketID { get { return *m_Data; } }
+
+ public int Position { get { return m_Pos; } set { m_Pos = value; } }
+
+
+
+ public bool AtEnd { get { return m_Pos >= m_Length; } }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Network/PacketHandler.cs b/Network/PacketHandler.cs
new file mode 100644
index 0000000..7d2e045
--- /dev/null
+++ b/Network/PacketHandler.cs
@@ -0,0 +1,220 @@
+using System;
+using System.Collections.Generic;
+
+namespace Assistant
+{
+ public delegate void PacketViewerCallback(PacketReader p, PacketHandlerEventArgs args);
+ public delegate void PacketFilterCallback(Packet p, PacketHandlerEventArgs args);
+
+ public class PacketHandlerEventArgs
+ {
+ private bool m_Block;
+ public bool Block
+ {
+ get { return m_Block; }
+ set { m_Block = value; }
+ }
+
+ public PacketHandlerEventArgs()
+ {
+ Reinit();
+ }
+
+ public void Reinit()
+ {
+ m_Block = false;
+ }
+ }
+
+ public class PacketHandler
+ {
+ private static Dictionary> m_ClientViewers;
+ private static Dictionary> m_ServerViewers;
+
+ private static Dictionary> m_ClientFilters;
+ private static Dictionary> m_ServerFilters;
+
+ static PacketHandler()
+ {
+ m_ClientViewers = new Dictionary>();
+ m_ServerViewers = new Dictionary>();
+
+ m_ClientFilters = new Dictionary>();
+ m_ServerFilters = new Dictionary>();
+ }
+
+ internal static void RegisterClientToServerViewer(int packetID, PacketViewerCallback callback)
+ {
+ List list;
+ if (!m_ClientViewers.TryGetValue(packetID, out list) || list == null)
+ m_ClientViewers[packetID] = list = new List();
+ list.Add(callback);
+ }
+
+ internal static void RegisterServerToClientViewer(int packetID, PacketViewerCallback callback)
+ {
+ List list;
+ if (!m_ServerViewers.TryGetValue(packetID, out list) || list == null)
+ m_ServerViewers[packetID] = list = new List();
+ list.Add(callback);
+ }
+
+ internal static void RemoveClientToServerViewer(int packetID, PacketViewerCallback callback)
+ {
+ List list;
+ if (m_ClientViewers.TryGetValue(packetID, out list) && list != null)
+ list.Remove(callback);
+ }
+
+ internal static void RemoveServerToClientViewer(int packetID, PacketViewerCallback callback)
+ {
+ List list;
+ if (m_ServerViewers.TryGetValue(packetID, out list) && list != null)
+ list.Remove(callback);
+ }
+
+ internal static void RegisterClientToServerFilter(int packetID, PacketFilterCallback callback)
+ {
+ List list;
+ if (!m_ClientFilters.TryGetValue(packetID, out list) || list == null)
+ m_ClientFilters[packetID] = list = new List();
+ list.Add(callback);
+ }
+
+ internal static void RegisterServerToClientFilter(int packetID, PacketFilterCallback callback)
+ {
+ List list;
+ if (!m_ServerFilters.TryGetValue(packetID, out list) || list == null)
+ m_ServerFilters[packetID] = list = new List();
+ list.Add(callback);
+ }
+
+ internal static void RemoveClientToServerFilter(int packetID, PacketFilterCallback callback)
+ {
+ List list;
+ if (m_ClientFilters.TryGetValue(packetID, out list) && list != null)
+ list.Remove(callback);
+ }
+
+ internal static void RemoveServerToClientFilter(int packetID, PacketFilterCallback callback)
+ {
+ List