Inventory logger
This commit is contained in:
parent
29fba4b7cb
commit
de2057789a
41 changed files with 12834 additions and 171 deletions
|
|
@ -1,157 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Decal.Adapter;
|
||||
using Decal.Adapter.Wrappers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MosswartMassacre
|
||||
{
|
||||
public sealed class InventoryMonitor : IDisposable
|
||||
{
|
||||
private const string Schema = "mm-inv/1.1";
|
||||
private readonly string _filePath;
|
||||
private Dictionary<int, ItemRecord> _cache = new Dictionary<int, ItemRecord>();
|
||||
private readonly WorldFilter _wf;
|
||||
private readonly CharacterFilter _cf;
|
||||
private bool _suppress;
|
||||
|
||||
public InventoryMonitor()
|
||||
{
|
||||
_cf = CoreManager.Current.CharacterFilter;
|
||||
_wf = CoreManager.Current.WorldFilter;
|
||||
_filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{_cf.Name}-inventory.json");
|
||||
|
||||
_cf.LoginComplete += (_, __) => SnapshotAndSaveAll();
|
||||
_wf.CreateObject += OnWorldFilterEvent;
|
||||
_wf.ChangeObject += OnWorldFilterEvent;
|
||||
_wf.MoveObject += OnWorldFilterEvent;
|
||||
_wf.ReleaseObject += OnWorldFilterEvent;
|
||||
|
||||
if (_cf.LoginStatus == 3)
|
||||
SnapshotAndSaveAll();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cf.LoginComplete -= (_, __) => SnapshotAndSaveAll();
|
||||
_wf.CreateObject -= OnWorldFilterEvent;
|
||||
_wf.ChangeObject -= OnWorldFilterEvent;
|
||||
_wf.MoveObject -= OnWorldFilterEvent;
|
||||
_wf.ReleaseObject -= OnWorldFilterEvent;
|
||||
}
|
||||
|
||||
private void SnapshotAndSaveAll()
|
||||
{
|
||||
var snapshot = _wf.GetInventory()
|
||||
.Select(o => new ItemRecord(o))
|
||||
.ToDictionary(r => r.Id, r => r);
|
||||
|
||||
SaveToDisk(new SnapshotFile
|
||||
{
|
||||
schema = Schema,
|
||||
items = snapshot.Values.ToList()
|
||||
});
|
||||
|
||||
_cache = snapshot;
|
||||
}
|
||||
|
||||
private void OnWorldFilterEvent(object s, EventArgs e)
|
||||
{
|
||||
if (_suppress) return;
|
||||
_suppress = true;
|
||||
try { DiffAndSave(); }
|
||||
finally { _suppress = false; }
|
||||
}
|
||||
|
||||
private void DiffAndSave()
|
||||
{
|
||||
var latest = _wf.GetInventory()
|
||||
.Select(o => new ItemRecord(o))
|
||||
.ToDictionary(r => r.Id, r => r);
|
||||
|
||||
var adds = latest.Keys.Except(_cache.Keys)
|
||||
.Select(id => latest[id]);
|
||||
var removes = _cache.Keys.Except(latest.Keys);
|
||||
var updates = latest.Values
|
||||
.Where(r => _cache.TryGetValue(r.Id, out var old) && !r.Equals(old));
|
||||
|
||||
if (!adds.Any() && !removes.Any() && !updates.Any())
|
||||
return;
|
||||
|
||||
var patch = new PatchFile
|
||||
{
|
||||
schema = Schema,
|
||||
type = "events",
|
||||
adds = adds.ToList(),
|
||||
removes = removes.ToList(),
|
||||
updates = updates.ToList()
|
||||
};
|
||||
SaveToDisk(patch);
|
||||
|
||||
_cache = latest;
|
||||
}
|
||||
|
||||
private void SaveToDisk(object doc)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(doc, Formatting.Indented);
|
||||
File.WriteAllText(_filePath, json, Encoding.UTF8);
|
||||
}
|
||||
|
||||
// Data classes
|
||||
private class SnapshotFile
|
||||
{
|
||||
public string Schema => schema;
|
||||
public string schema;
|
||||
public List<ItemRecord> items;
|
||||
}
|
||||
|
||||
private class PatchFile
|
||||
{
|
||||
public string schema;
|
||||
public string type;
|
||||
public List<ItemRecord> adds;
|
||||
public List<int> removes;
|
||||
public List<ItemRecord> updates;
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemRecord : IEquatable<ItemRecord>
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Container { get; set; }
|
||||
public int Icon { get; set; }
|
||||
public int Count { get; set; }
|
||||
public bool Equipped { get; set; }
|
||||
public bool HasIdData { get; set; }
|
||||
public int ObjectClass { get; set; }
|
||||
|
||||
public ItemRecord() { }
|
||||
|
||||
public ItemRecord(WorldObject wo)
|
||||
{
|
||||
Id = wo.Id;
|
||||
Name = wo.Name;
|
||||
Container = wo.Container;
|
||||
Icon = wo.Icon;
|
||||
Count = (int)wo.Values(LongValueKey.StackCount, 1);
|
||||
Equipped = wo.Values(LongValueKey.EquippedSlots, 0) > 0;
|
||||
HasIdData = wo.HasIdData;
|
||||
ObjectClass = (int)wo.ObjectClass;
|
||||
}
|
||||
|
||||
public bool Equals(ItemRecord other)
|
||||
{
|
||||
if (other == null) return false;
|
||||
return Container == other.Container
|
||||
&& Count == other.Count
|
||||
&& Equipped == other.Equipped
|
||||
&& HasIdData == other.HasIdData;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => Id;
|
||||
}
|
||||
}
|
||||
|
|
@ -38,10 +38,8 @@
|
|||
<HintPath>lib\Decal.Adapter.dll</HintPath>
|
||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<Reference Include="Decal.Interop.Core, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||
<HintPath>lib\Decal.Interop.Core.DLL</HintPath>
|
||||
<Reference Include="Decal.FileService">
|
||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Decal 3.0\Decal.FileService.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Decal.Interop.Inject, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
|
|
@ -66,6 +64,9 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>bin\Debug\utank2-i.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="VCS5">
|
||||
<HintPath>..\..\..\..\..\..\Games\Decal Plugins\Virindi\VirindiChatSystem5\VCS5.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="VirindiViewService">
|
||||
<HintPath>lib\VirindiViewService.dll</HintPath>
|
||||
</Reference>
|
||||
|
|
@ -74,7 +75,67 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Inventory.cs" />
|
||||
<Compile Include="..\Shared\Constants\BoolValueKey.cs">
|
||||
<Link>Shared\Constants\BoolValueKey.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Constants\Dictionaries.cs">
|
||||
<Link>Shared\Constants\Dictionaries.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Constants\DoubleValueKey.cs">
|
||||
<Link>Shared\Constants\DoubleValueKey.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Constants\EphemeralAttribute.cs">
|
||||
<Link>Shared\Constants\EphemeralAttribute.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Constants\IntValueKey.cs">
|
||||
<Link>Shared\Constants\IntValueKey.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Constants\SendOnLoginAttribute.cs">
|
||||
<Link>Shared\Constants\SendOnLoginAttribute.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Constants\ServerOnlyAttribute.cs">
|
||||
<Link>Shared\Constants\ServerOnlyAttribute.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Constants\StringValueKey.cs">
|
||||
<Link>Shared\Constants\StringValueKey.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Debug.cs">
|
||||
<Link>Shared\Debug.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\DecalProxy.cs">
|
||||
<Link>Shared\DecalProxy.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MyWorldObject.cs">
|
||||
<Link>Shared\MyWorldObject.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MyWorldObjectCreator.cs">
|
||||
<Link>Shared\MyWorldObjectCreator.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\PostMessageTools.cs">
|
||||
<Link>Shared\PostMessageTools.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\RateLimiter.cs">
|
||||
<Link>Shared\RateLimiter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\SerializableDictionary.cs">
|
||||
<Link>Shared\SerializableDictionary.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Settings\Setting.cs">
|
||||
<Link>Shared\Settings\Setting.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Settings\SettingsFile.cs">
|
||||
<Link>Shared\Settings\SettingsFile.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\User32.cs">
|
||||
<Link>Shared\User32.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Util.cs">
|
||||
<Link>Shared\Util.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\VCS_Connector.cs">
|
||||
<Link>Shared\VCS_Connector.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="MossyInventory.cs" />
|
||||
<Compile Include="vTank.cs" />
|
||||
<Compile Include="VtankControl.cs" />
|
||||
<Compile Include="Telemetry.cs" />
|
||||
|
|
@ -112,5 +173,25 @@
|
|||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="Decal">
|
||||
<Guid>{FF7F5F6D-34E0-4B6F-B3BB-8141DE2EF732}</Guid>
|
||||
<VersionMajor>2</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>primary</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="DecalNet">
|
||||
<Guid>{572B87C4-93BD-46B3-A291-CD58181D25DC}</Guid>
|
||||
<VersionMajor>2</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>primary</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
239
MosswartMassacre/MossyInventory.cs
Normal file
239
MosswartMassacre/MossyInventory.cs
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using Mag.Shared;
|
||||
|
||||
using Decal.Adapter;
|
||||
using Decal.Adapter.Wrappers;
|
||||
using System.Diagnostics;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace MosswartMassacre
|
||||
{
|
||||
class MossyInventory : IDisposable
|
||||
{
|
||||
|
||||
private string InventoryFileName
|
||||
{
|
||||
get
|
||||
{
|
||||
// 1) grab your character name
|
||||
var characterName = CoreManager.Current.CharacterFilter.Name;
|
||||
|
||||
// 2) grab the folder where your plugin dll is running
|
||||
var pluginFolder = Path.GetDirectoryName(
|
||||
System.Reflection.Assembly
|
||||
.GetExecutingAssembly()
|
||||
.Location
|
||||
);
|
||||
|
||||
// 3) combine into a full path with .json
|
||||
return Path.Combine(
|
||||
pluginFolder,
|
||||
$"{characterName}.json"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public MossyInventory()
|
||||
{
|
||||
try
|
||||
{
|
||||
CoreManager.Current.CharacterFilter.LoginComplete += CharacterFilter_LoginComplete;
|
||||
CoreManager.Current.WorldFilter.CreateObject += WorldFilter_CreateObject;
|
||||
CoreManager.Current.WorldFilter.ChangeObject += WorldFilter_ChangeObject;
|
||||
CoreManager.Current.CharacterFilter.Logoff += CharacterFilter_Logoff;
|
||||
PluginCore.WriteToChat($"[INV] {InventoryFileName}");
|
||||
PluginCore.WriteToChat("Started MOSSY!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[INV] {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private bool disposed;
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed) return;
|
||||
if (disposing)
|
||||
{
|
||||
CoreManager.Current.CharacterFilter.LoginComplete -= CharacterFilter_LoginComplete;
|
||||
CoreManager.Current.WorldFilter.CreateObject -= WorldFilter_CreateObject;
|
||||
CoreManager.Current.WorldFilter.ChangeObject -= WorldFilter_ChangeObject;
|
||||
CoreManager.Current.CharacterFilter.Logoff -= CharacterFilter_Logoff;
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
private bool loginComplete;
|
||||
private bool loggedInAndWaitingForIdData;
|
||||
private readonly List<int> requestedIds = new List<int>();
|
||||
|
||||
private void CharacterFilter_LoginComplete(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
loginComplete = true;
|
||||
if (!PluginSettings.Instance.InventoryLog)
|
||||
return;
|
||||
|
||||
if (!File.Exists(InventoryFileName))
|
||||
{
|
||||
PluginCore.WriteToChat("Requesting id information for all armor/weapon inventory. This will take a few minutes...");
|
||||
foreach (WorldObject wo in CoreManager.Current.WorldFilter.GetInventory())
|
||||
{
|
||||
if (!wo.HasIdData && ObjectClassNeedsIdent(wo.ObjectClass, wo.Name))
|
||||
CoreManager.Current.Actions.RequestId(wo.Id);
|
||||
}
|
||||
loggedInAndWaitingForIdData = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DumpInventoryToFile(true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[INV] {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void WorldFilter_CreateObject(object sender, CreateObjectEventArgs e)
|
||||
{
|
||||
if (!loginComplete || !PluginSettings.Instance.InventoryLog) return;
|
||||
|
||||
if (!e.New.HasIdData && ObjectClassNeedsIdent(e.New.ObjectClass, e.New.Name)
|
||||
&& !requestedIds.Contains(e.New.Id)
|
||||
&& e.New.Container == CoreManager.Current.CharacterFilter.Id)
|
||||
{
|
||||
requestedIds.Add(e.New.Id);
|
||||
CoreManager.Current.Actions.RequestId(e.New.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private void WorldFilter_ChangeObject(object sender, ChangeObjectEventArgs e)
|
||||
{
|
||||
if (!loginComplete || !PluginSettings.Instance.InventoryLog) return;
|
||||
|
||||
if (loggedInAndWaitingForIdData)
|
||||
{
|
||||
bool allHaveId = true;
|
||||
foreach (WorldObject wo in CoreManager.Current.WorldFilter.GetInventory())
|
||||
{
|
||||
if (!wo.HasIdData && ObjectClassNeedsIdent(wo.ObjectClass, wo.Name))
|
||||
{
|
||||
allHaveId = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allHaveId)
|
||||
{
|
||||
loggedInAndWaitingForIdData = false;
|
||||
DumpInventoryToFile();
|
||||
PluginCore.WriteToChat("Requesting id information for all armor/weapon inventory completed. Log file written.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!e.Changed.HasIdData && ObjectClassNeedsIdent(e.Changed.ObjectClass, e.Changed.Name)
|
||||
&& !requestedIds.Contains(e.Changed.Id)
|
||||
&& e.Changed.Container == CoreManager.Current.CharacterFilter.Id)
|
||||
{
|
||||
requestedIds.Add(e.Changed.Id);
|
||||
CoreManager.Current.Actions.RequestId(e.Changed.Id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void CharacterFilter_Logoff(object sender, Decal.Adapter.Wrappers.LogoffEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!PluginSettings.Instance.InventoryLog) return;
|
||||
DumpInventoryToFile();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[INV] {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void DumpInventoryToFile(bool requestIdsIfMissing = false)
|
||||
{
|
||||
var previouslySaved = new List<MyWorldObject>();
|
||||
|
||||
if (File.Exists(InventoryFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
string oldJson = File.ReadAllText(InventoryFileName);
|
||||
previouslySaved = JsonConvert.DeserializeObject<List<MyWorldObject>>(oldJson)
|
||||
?? new List<MyWorldObject>();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
PluginCore.WriteToChat("Inventory file is corrupt.");
|
||||
}
|
||||
}
|
||||
|
||||
var currentList = new List<MyWorldObject>();
|
||||
foreach (WorldObject wo in CoreManager.Current.WorldFilter.GetInventory())
|
||||
{
|
||||
bool merged = false;
|
||||
foreach (var prev in previouslySaved)
|
||||
{
|
||||
if (prev.Id == wo.Id && prev.ObjectClass == (int)wo.ObjectClass)
|
||||
{
|
||||
if (requestIdsIfMissing && !prev.HasIdData && !wo.HasIdData && ObjectClassNeedsIdent(wo.ObjectClass, wo.Name))
|
||||
{
|
||||
CoreManager.Current.Actions.RequestId(wo.Id);
|
||||
currentList.Add(MyWorldObjectCreator.Create(wo));
|
||||
}
|
||||
else
|
||||
{
|
||||
currentList.Add(MyWorldObjectCreator.Combine(prev, wo));
|
||||
}
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!merged)
|
||||
{
|
||||
if (requestIdsIfMissing && !wo.HasIdData && ObjectClassNeedsIdent(wo.ObjectClass, wo.Name))
|
||||
CoreManager.Current.Actions.RequestId(wo.Id);
|
||||
|
||||
currentList.Add(MyWorldObjectCreator.Create(wo));
|
||||
}
|
||||
}
|
||||
|
||||
var fi = new FileInfo(InventoryFileName);
|
||||
if (fi.Directory != null && !fi.Directory.Exists)
|
||||
fi.Directory.Create();
|
||||
|
||||
string json = JsonConvert.SerializeObject(currentList, Formatting.Indented);
|
||||
File.WriteAllText(InventoryFileName, json);
|
||||
}
|
||||
|
||||
private bool ObjectClassNeedsIdent(ObjectClass oc, string name)
|
||||
{
|
||||
return oc == ObjectClass.Armor
|
||||
|| oc == ObjectClass.Clothing
|
||||
|| oc == ObjectClass.MeleeWeapon
|
||||
|| oc == ObjectClass.MissileWeapon
|
||||
|| oc == ObjectClass.WandStaffOrb
|
||||
|| oc == ObjectClass.Jewelry
|
||||
|| (oc == ObjectClass.Gem && !string.IsNullOrEmpty(name) && name.Contains("Aetheria"))
|
||||
|| (oc == ObjectClass.Misc && !string.IsNullOrEmpty(name) && name.Contains("Essence"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,10 +29,13 @@ namespace MosswartMassacre
|
|||
public static string CharTag { get; set; } = "";
|
||||
public static bool TelemetryEnabled { get; set; } = false;
|
||||
public bool WebSocketEnabled { get; set; } = false;
|
||||
public bool InventoryLogEnabled { get; set; } = false;
|
||||
|
||||
private MossyInventory _inventoryLogger;
|
||||
|
||||
private static Queue<string> rareMessageQueue = new Queue<string>();
|
||||
private static DateTime _lastSent = DateTime.MinValue;
|
||||
private static readonly Queue<string> _chatQueue = new Queue<string>();
|
||||
private InventoryMonitor _inv;
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
|
|
@ -64,7 +67,11 @@ namespace MosswartMassacre
|
|||
vTank.Enable();
|
||||
//lyssna på commands
|
||||
WebSocket.OnServerCommand += HandleServerCommand;
|
||||
_inv = new InventoryMonitor();
|
||||
//starta inventory. Hanterar subscriptions i den med
|
||||
|
||||
_inventoryLogger = new MossyInventory();
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -103,7 +110,8 @@ namespace MosswartMassacre
|
|||
// sluta lyssna på commands
|
||||
WebSocket.OnServerCommand -= HandleServerCommand;
|
||||
WebSocket.Stop();
|
||||
_inv?.Dispose();
|
||||
//shutdown inv
|
||||
_inventoryLogger.Dispose();
|
||||
|
||||
MyHost = null;
|
||||
}
|
||||
|
|
@ -132,6 +140,7 @@ namespace MosswartMassacre
|
|||
WebSocket.Start();
|
||||
|
||||
|
||||
|
||||
}
|
||||
private async void OnSpawn(object sender, CreateObjectEventArgs e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ namespace MosswartMassacre
|
|||
private bool _httpServerEnabled = false;
|
||||
private bool _telemetryEnabled = false;
|
||||
private bool _webSocketEnabled = false;
|
||||
private bool _inventorylog = true;
|
||||
private string _charTag = "default";
|
||||
|
||||
public static PluginSettings Instance => _instance
|
||||
|
|
@ -134,5 +135,10 @@ namespace MosswartMassacre
|
|||
get => _charTag;
|
||||
set { _charTag = value; Save(); }
|
||||
}
|
||||
public bool InventoryLog
|
||||
{
|
||||
get => _inventorylog;
|
||||
set { _inventorylog = value; Save(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
187
Shared/Constants/BoolValueKey.cs
Normal file
187
Shared/Constants/BoolValueKey.cs
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
// https://github.com/ACEmulator/ACE/blob/master/Source/ACE.Entity/Enum/Properties/PropertyBool.cs
|
||||
public enum BoolValueKey
|
||||
{
|
||||
// properties marked as ServerOnly are properties we never saw in PCAPs, from here:
|
||||
// http://ac.yotesfan.com/ace_object/not_used_enums.php
|
||||
// source: @OptimShi
|
||||
// description attributes are used by the weenie editor for a cleaner display name
|
||||
|
||||
Undef = 0,
|
||||
[Ephemeral][ServerOnly]
|
||||
Stuck = 1,
|
||||
[Ephemeral]
|
||||
Open = 2,
|
||||
Locked = 3,
|
||||
RotProof = 4,
|
||||
AllegianceUpdateRequest = 5,
|
||||
AiUsesMana = 6,
|
||||
AiUseHumanMagicAnimations = 7,
|
||||
AllowGive = 8,
|
||||
CurrentlyAttacking = 9,
|
||||
AttackerAi = 10,
|
||||
[ServerOnly]
|
||||
IgnoreCollisions = 11,
|
||||
[ServerOnly]
|
||||
ReportCollisions = 12,
|
||||
[ServerOnly]
|
||||
Ethereal = 13,
|
||||
[ServerOnly]
|
||||
GravityStatus = 14,
|
||||
[ServerOnly]
|
||||
LightsStatus = 15,
|
||||
[ServerOnly]
|
||||
ScriptedCollision = 16,
|
||||
[ServerOnly]
|
||||
Inelastic = 17,
|
||||
[ServerOnly][Ephemeral]
|
||||
Visibility = 18,
|
||||
[ServerOnly]
|
||||
Attackable = 19,
|
||||
SafeSpellComponents = 20,
|
||||
AdvocateState = 21,
|
||||
Inscribable = 22,
|
||||
DestroyOnSell = 23,
|
||||
UiHidden = 24,
|
||||
IgnoreHouseBarriers = 25,
|
||||
HiddenAdmin = 26,
|
||||
PkWounder = 27,
|
||||
PkKiller = 28,
|
||||
NoCorpse = 29,
|
||||
UnderLifestoneProtection = 30,
|
||||
ItemManaUpdatePending = 31,
|
||||
[Ephemeral]
|
||||
GeneratorStatus = 32,
|
||||
[Ephemeral]
|
||||
ResetMessagePending = 33,
|
||||
DefaultOpen = 34,
|
||||
DefaultLocked = 35,
|
||||
DefaultOn = 36,
|
||||
OpenForBusiness = 37,
|
||||
IsFrozen = 38,
|
||||
DealMagicalItems = 39,
|
||||
LogoffImDead = 40,
|
||||
ReportCollisionsAsEnvironment = 41,
|
||||
AllowEdgeSlide = 42,
|
||||
AdvocateQuest = 43,
|
||||
[Ephemeral][SendOnLogin]
|
||||
IsAdmin = 44,
|
||||
[Ephemeral][SendOnLogin]
|
||||
IsArch = 45,
|
||||
[Ephemeral][SendOnLogin]
|
||||
IsSentinel = 46,
|
||||
[SendOnLogin]
|
||||
IsAdvocate = 47,
|
||||
CurrentlyPoweringUp = 48,
|
||||
[Ephemeral]
|
||||
GeneratorEnteredWorld = 49,
|
||||
NeverFailCasting = 50,
|
||||
VendorService = 51,
|
||||
AiImmobile = 52,
|
||||
DamagedByCollisions = 53,
|
||||
IsDynamic = 54,
|
||||
IsHot = 55,
|
||||
IsAffecting = 56,
|
||||
AffectsAis = 57,
|
||||
SpellQueueActive = 58,
|
||||
[Ephemeral]
|
||||
GeneratorDisabled = 59,
|
||||
IsAcceptingTells = 60,
|
||||
LoggingChannel = 61,
|
||||
OpensAnyLock = 62,
|
||||
UnlimitedUse = 63,
|
||||
GeneratedTreasureItem = 64,
|
||||
IgnoreMagicResist = 65,
|
||||
IgnoreMagicArmor = 66,
|
||||
AiAllowTrade = 67,
|
||||
[SendOnLogin]
|
||||
SpellComponentsRequired = 68,
|
||||
IsSellable = 69,
|
||||
IgnoreShieldsBySkill = 70,
|
||||
NoDraw = 71,
|
||||
ActivationUntargeted = 72,
|
||||
HouseHasGottenPriorityBootPos = 73,
|
||||
[Ephemeral]
|
||||
GeneratorAutomaticDestruction = 74,
|
||||
HouseHooksVisible = 75,
|
||||
HouseRequiresMonarch = 76,
|
||||
HouseHooksEnabled = 77,
|
||||
HouseNotifiedHudOfHookCount = 78,
|
||||
AiAcceptEverything = 79,
|
||||
IgnorePortalRestrictions = 80,
|
||||
RequiresBackpackSlot = 81,
|
||||
DontTurnOrMoveWhenGiving = 82,
|
||||
[ServerOnly]
|
||||
NpcLooksLikeObject = 83,
|
||||
IgnoreCloIcons = 84,
|
||||
AppraisalHasAllowedWielder = 85,
|
||||
ChestRegenOnClose = 86,
|
||||
LogoffInMinigame = 87,
|
||||
PortalShowDestination = 88,
|
||||
PortalIgnoresPkAttackTimer = 89,
|
||||
NpcInteractsSilently = 90,
|
||||
Retained = 91,
|
||||
IgnoreAuthor = 92,
|
||||
Limbo = 93,
|
||||
AppraisalHasAllowedActivator = 94,
|
||||
ExistedBeforeAllegianceXpChanges = 95,
|
||||
IsDeaf = 96,
|
||||
[Ephemeral][SendOnLogin]
|
||||
IsPsr = 97,
|
||||
Invincible = 98,
|
||||
Ivoryable = 99,
|
||||
Dyable = 100,
|
||||
CanGenerateRare = 101,
|
||||
CorpseGeneratedRare = 102,
|
||||
NonProjectileMagicImmune = 103,
|
||||
[SendOnLogin]
|
||||
ActdReceivedItems = 104,
|
||||
Unknown105 = 105,
|
||||
[Ephemeral]
|
||||
FirstEnterWorldDone = 106,
|
||||
RecallsDisabled = 107,
|
||||
RareUsesTimer = 108,
|
||||
ActdPreorderReceivedItems = 109,
|
||||
Afk = 110,
|
||||
IsGagged = 111,
|
||||
ProcSpellSelfTargeted = 112,
|
||||
IsAllegianceGagged = 113,
|
||||
EquipmentSetTriggerPiece = 114,
|
||||
Uninscribe = 115,
|
||||
WieldOnUse = 116,
|
||||
ChestClearedWhenClosed = 117,
|
||||
NeverAttack = 118,
|
||||
SuppressGenerateEffect = 119,
|
||||
TreasureCorpse = 120,
|
||||
EquipmentSetAddLevel = 121,
|
||||
BarberActive = 122,
|
||||
TopLayerPriority = 123,
|
||||
NoHeldItemShown = 124,
|
||||
LoginAtLifestone = 125,
|
||||
OlthoiPk = 126,
|
||||
[SendOnLogin]
|
||||
Account15Days = 127,
|
||||
HadNoVitae = 128,
|
||||
NoOlthoiTalk = 129,
|
||||
AutowieldLeft = 130,
|
||||
|
||||
|
||||
// ACE Specific
|
||||
/* custom */
|
||||
[ServerOnly]
|
||||
LinkedPortalOneSummon = 9001,
|
||||
[ServerOnly]
|
||||
LinkedPortalTwoSummon = 9002,
|
||||
[ServerOnly]
|
||||
HouseEvicted = 9003,
|
||||
[ServerOnly]
|
||||
UntrainedSkills = 9004,
|
||||
|
||||
|
||||
// Decal Specific
|
||||
Lockable_Decal = 201326592,
|
||||
Inscribable_Decal = 201326593,
|
||||
}
|
||||
}
|
||||
129
Shared/Constants/CoverageMask.cs
Normal file
129
Shared/Constants/CoverageMask.cs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the mapping for LongValueKey.Coverage.
|
||||
/// It represents what body parts an armor piece covers when used in defensive/armor calculations.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CoverageMask
|
||||
{
|
||||
None = 0,
|
||||
|
||||
Unknown = 0x00000001, // Original pants abdomen?
|
||||
|
||||
UnderwearUpperLegs = 0x00000002, // I think... 0x13 = Abdomen/UpperLegs
|
||||
UnderwearLowerLegs = 0x00000004, // I think... 0x16 = Abdomen/UpperLegs/LowerLegs
|
||||
UnderwearChest = 0x00000008,
|
||||
UnderwearAbdomen = 0x00000010, // Original shirt abdomen?
|
||||
UnderwearUpperArms = 0x00000020,
|
||||
UnderwearLowerArms = 0x00000040,
|
||||
// = 0x00000080,
|
||||
|
||||
OuterwearUpperLegs = 0x00000100,
|
||||
OuterwearLowerLegs = 0x00000200,
|
||||
OuterwearChest = 0x00000400,
|
||||
OuterwearAbdomen = 0x00000800,
|
||||
OuterwearUpperArms = 0x00001000,
|
||||
OuterwearLowerArms = 0x00002000,
|
||||
|
||||
Head = 0x00004000,
|
||||
Hands = 0x00008000,
|
||||
Feet = 0x00010000,
|
||||
|
||||
Cloak = 0x00020000,
|
||||
}
|
||||
|
||||
public enum CoverageMaskHelper : uint
|
||||
{
|
||||
// for server comparison only
|
||||
Underwear = CoverageMask.UnderwearUpperLegs | CoverageMask.UnderwearLowerLegs | CoverageMask.UnderwearChest | CoverageMask.UnderwearAbdomen | CoverageMask.UnderwearUpperArms | CoverageMask.UnderwearLowerArms,
|
||||
Outerwear = CoverageMask.OuterwearUpperLegs | CoverageMask.OuterwearLowerLegs | CoverageMask.OuterwearChest | CoverageMask.OuterwearAbdomen | CoverageMask.OuterwearUpperArms | CoverageMask.OuterwearLowerArms | CoverageMask.Head | CoverageMask.Hands | CoverageMask.Feet,
|
||||
|
||||
UnderwearLegs = CoverageMask.UnderwearUpperLegs | CoverageMask.UnderwearLowerLegs,
|
||||
UnderwearArms = CoverageMask.UnderwearUpperArms | CoverageMask.UnderwearLowerArms,
|
||||
|
||||
OuterwearLegs = CoverageMask.OuterwearUpperLegs | CoverageMask.OuterwearLowerLegs,
|
||||
OuterwearArms = CoverageMask.OuterwearUpperArms | CoverageMask.OuterwearLowerArms,
|
||||
|
||||
// exclude abdomen for searching
|
||||
UnderwearShirt = CoverageMask.UnderwearChest | CoverageMask.UnderwearUpperArms | CoverageMask.UnderwearLowerArms,
|
||||
UnderwearPants = CoverageMask.UnderwearUpperLegs | CoverageMask.UnderwearLowerLegs
|
||||
}
|
||||
|
||||
public static class CoverageMaskExtensions
|
||||
{
|
||||
public static int GetTotalBitsSet(this CoverageMask value)
|
||||
{
|
||||
int slotFlags = (int)value;
|
||||
int bitsSet = 0;
|
||||
|
||||
while (slotFlags != 0)
|
||||
{
|
||||
if ((slotFlags & 1) == 1)
|
||||
bitsSet++;
|
||||
slotFlags >>= 1;
|
||||
}
|
||||
|
||||
return bitsSet;
|
||||
}
|
||||
|
||||
public static bool IsBodyArmor(this CoverageMask value) { return ((int)value & 0x0001FF00) != 0; }
|
||||
public static bool IsRobe(this CoverageMask value) { return ((int)value == 0x00013F00); }
|
||||
public static bool IsUnderwear(this CoverageMask value) { return ((int)value & 0x0000007F) != 0; }
|
||||
public static bool IsShirt(this CoverageMask value) { return ((int)value & 0x00000078) != 0; }
|
||||
public static bool IsPants(this CoverageMask value) { return ((int)value & 0x00000017) != 0; }
|
||||
|
||||
public static List<CoverageMask> ReductionOptions(this CoverageMask value)
|
||||
{
|
||||
List<CoverageMask> options = new List<CoverageMask>();
|
||||
|
||||
if (value.GetTotalBitsSet() <= 1 || !value.IsBodyArmor() || value.IsRobe())
|
||||
options.Add(value);
|
||||
else
|
||||
{
|
||||
if (value == (CoverageMask.OuterwearUpperArms | CoverageMask.OuterwearLowerArms))
|
||||
{
|
||||
options.Add(CoverageMask.OuterwearUpperArms);
|
||||
options.Add(CoverageMask.OuterwearLowerArms);
|
||||
}
|
||||
else if (value == (CoverageMask.OuterwearUpperLegs | CoverageMask.OuterwearLowerLegs))
|
||||
{
|
||||
options.Add(CoverageMask.OuterwearUpperLegs);
|
||||
options.Add(CoverageMask.OuterwearLowerLegs);
|
||||
}
|
||||
else if (value == (CoverageMask.OuterwearLowerLegs | CoverageMask.Feet))
|
||||
options.Add(CoverageMask.Feet);
|
||||
else if (value == (CoverageMask.OuterwearChest | CoverageMask.OuterwearAbdomen))
|
||||
options.Add(CoverageMask.OuterwearChest);
|
||||
else if (value == (CoverageMask.OuterwearChest | CoverageMask.OuterwearAbdomen | CoverageMask.OuterwearUpperArms))
|
||||
options.Add(CoverageMask.OuterwearChest);
|
||||
else if (value == (CoverageMask.OuterwearChest | CoverageMask.OuterwearUpperArms | CoverageMask.OuterwearLowerArms))
|
||||
options.Add(CoverageMask.OuterwearChest);
|
||||
else if (value == (CoverageMask.OuterwearChest | CoverageMask.OuterwearUpperArms))
|
||||
options.Add(CoverageMask.OuterwearChest);
|
||||
else if (value == (CoverageMask.OuterwearAbdomen | CoverageMask.OuterwearUpperLegs | CoverageMask.OuterwearLowerLegs))
|
||||
{
|
||||
options.Add(CoverageMask.OuterwearAbdomen);
|
||||
options.Add(CoverageMask.OuterwearUpperLegs);
|
||||
options.Add(CoverageMask.OuterwearLowerLegs);
|
||||
}
|
||||
else if (value == (CoverageMask.OuterwearChest | CoverageMask.OuterwearAbdomen | CoverageMask.OuterwearUpperArms | CoverageMask.OuterwearLowerArms))
|
||||
options.Add(CoverageMask.OuterwearChest);
|
||||
else if (value == (CoverageMask.OuterwearAbdomen | CoverageMask.OuterwearUpperLegs))
|
||||
{
|
||||
// This is a emu piece that follows the pre-2010 retail guidelines
|
||||
// https://asheron.fandom.com/wiki/Announcements_-_2010/04_-_Shedding_Skin
|
||||
// For now, we assume only abdomen reduction
|
||||
options.Add(CoverageMask.OuterwearAbdomen);
|
||||
}
|
||||
else
|
||||
throw new Exception("Unable to determine reduction paths for CoverageMask of " + value);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
||||
436
Shared/Constants/Dictionaries.cs
Normal file
436
Shared/Constants/Dictionaries.cs
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
public static class Dictionaries
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a dictionary of skill ids vs names
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static readonly Dictionary<int, string> SkillInfo = new Dictionary<int, string>
|
||||
{
|
||||
// This list was taken from the Alinco source
|
||||
{ 0x1, "Axe" },
|
||||
{ 0x2, "Bow" },
|
||||
{ 0x3, "Crossbow" },
|
||||
{ 0x4, "Dagger" },
|
||||
{ 0x5, "Mace" },
|
||||
{ 0x6, "Melee Defense" },
|
||||
{ 0x7, "Missile Defense" },
|
||||
{ 0x8, "Sling" },
|
||||
{ 0x9, "Spear" },
|
||||
{ 0xA, "Staff" },
|
||||
{ 0xB, "Sword" },
|
||||
{ 0xC, "Thrown Weapons" },
|
||||
{ 0xD, "Unarmed Combat" },
|
||||
{ 0xE, "Arcane Lore" },
|
||||
{ 0xF, "Magic Defense" },
|
||||
{ 0x10, "Mana Conversion" },
|
||||
{ 0x12, "Item Tinkering" },
|
||||
{ 0x13, "Assess Person" },
|
||||
{ 0x14, "Deception" },
|
||||
{ 0x15, "Healing" },
|
||||
{ 0x16, "Jump" },
|
||||
{ 0x17, "Lockpick" },
|
||||
{ 0x18, "Run" },
|
||||
{ 0x1B, "Assess Creature" },
|
||||
{ 0x1C, "Weapon Tinkering" },
|
||||
{ 0x1D, "Armor Tinkering" },
|
||||
{ 0x1E, "Magic Item Tinkering" },
|
||||
{ 0x1F, "Creature Enchantment" },
|
||||
{ 0x20, "Item Enchantment" },
|
||||
{ 0x21, "Life Magic" },
|
||||
{ 0x22, "War Magic" },
|
||||
{ 0x23, "Leadership" },
|
||||
{ 0x24, "Loyalty" },
|
||||
{ 0x25, "Fletching" },
|
||||
{ 0x26, "Alchemy" },
|
||||
{ 0x27, "Cooking" },
|
||||
{ 0x28, "Salvaging" },
|
||||
{ 0x29, "Two Handed Combat" },
|
||||
{ 0x2A, "Gearcraft"},
|
||||
{ 0x2B, "Void" },
|
||||
{ 0x2C, "Heavy Weapons" },
|
||||
{ 0x2D, "Light Weapons" },
|
||||
{ 0x2E, "Finesse Weapons" },
|
||||
{ 0x2F, "Missile Weapons" },
|
||||
{ 0x30, "Shield" },
|
||||
{ 0x31, "Dual Wield" },
|
||||
{ 0x32, "Recklessness" },
|
||||
{ 0x33, "Sneak Attack" },
|
||||
{ 0x34, "Dirty Fighting" },
|
||||
{ 0x35, "Challenge" },
|
||||
{ 0x36, "Summoning" },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary of mastery ids vs names
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<int, string> MasteryInfo = new Dictionary<int, string>
|
||||
{
|
||||
{ 1, "Unarmed Weapon" },
|
||||
{ 2, "Sword" },
|
||||
{ 3, "Axe" },
|
||||
{ 4, "Mace" },
|
||||
{ 5, "Spear" },
|
||||
{ 6, "Dagger" },
|
||||
{ 7, "Staff" },
|
||||
{ 8, "Bow" },
|
||||
{ 9, "Crossbow" },
|
||||
{ 10, "Thrown" },
|
||||
{ 11, "Two Handed Combat" },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary of attribute set ids vs names
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<int, string> AttributeSetInfo = new Dictionary<int, string>
|
||||
{
|
||||
// This list was taken from Virindi Tank Loot Editor
|
||||
// 01
|
||||
{ 02, "Test"},
|
||||
// 03
|
||||
{ 04, "Carraida's Benediction"},
|
||||
{ 05, "Noble Relic Set" },
|
||||
{ 06, "Ancient Relic Set" },
|
||||
{ 07, "Relic Alduressa Set" },
|
||||
{ 08, "Shou-jen Set" },
|
||||
{ 09, "Empyrean Rings Set" },
|
||||
{ 10, "Arm, Mind, Heart Set" },
|
||||
{ 11, "Coat of the Perfect Light Set" },
|
||||
{ 12, "Leggings of Perfect Light Set" },
|
||||
{ 13, "Soldier's Set" },
|
||||
{ 14, "Adept's Set" },
|
||||
{ 15, "Archer's Set" },
|
||||
{ 16, "Defender's Set" },
|
||||
{ 17, "Tinker's Set" },
|
||||
{ 18, "Crafter's Set" },
|
||||
{ 19, "Hearty Set" },
|
||||
{ 20, "Dexterous Set" },
|
||||
{ 21, "Wise Set" },
|
||||
{ 22, "Swift Set" },
|
||||
{ 23, "Hardenend Set" },
|
||||
{ 24, "Reinforced Set" },
|
||||
{ 25, "Interlocking Set" },
|
||||
{ 26, "Flame Proof Set" },
|
||||
{ 27, "Acid Proof Set" },
|
||||
{ 28, "Cold Proof Set" },
|
||||
{ 29, "Lightning Proof Set" },
|
||||
{ 30, "Dedication Set" },
|
||||
{ 31, "Gladiatorial Clothing Set" },
|
||||
{ 32, "Ceremonial Clothing" },
|
||||
{ 33, "Protective Clothing" },
|
||||
{ 34, "Noobie Armor" },
|
||||
{ 35, "Sigil of Defense" },
|
||||
{ 36, "Sigil of Destruction" },
|
||||
{ 37, "Sigil of Fury" },
|
||||
{ 38, "Sigil of Growth" },
|
||||
{ 39, "Sigil of Vigor" },
|
||||
{ 40, "Heroic Protector Set" },
|
||||
{ 41, "Heroic Destroyer Set" },
|
||||
{ 42, "Olthoi Armor D Red" },
|
||||
{ 43, "Olthoi Armor C Rat" },
|
||||
{ 44, "Olthoi Armor C Red" },
|
||||
{ 45, "Olthoi Armor D Rat" },
|
||||
{ 46, "Upgraded Relic Alduressa Set" },
|
||||
{ 47, "Upgraded Ancient Relic Set" },
|
||||
{ 48, "Upgraded Noble Relic Set" },
|
||||
{ 49, "Weave of Alchemy" },
|
||||
{ 50, "Weave of Arcane Lore" },
|
||||
{ 51, "Weave of Armor Tinkering" },
|
||||
{ 52, "Weave of Assess Person" },
|
||||
{ 53, "Weave of Light Weapons" },
|
||||
{ 54, "Weave of Missile Weapons" },
|
||||
{ 55, "Weave of Cooking" },
|
||||
{ 56, "Weave of Creature Enchantment" },
|
||||
{ 57, "Weave of Missile Weapons" },
|
||||
{ 58, "Weave of Finesse" },
|
||||
{ 59, "Weave of Deception" },
|
||||
{ 60, "Weave of Fletching" },
|
||||
{ 61, "Weave of Healing" },
|
||||
{ 62, "Weave of Item Enchantment" },
|
||||
{ 63, "Weave of Item Tinkering" },
|
||||
{ 64, "Weave of Leadership" },
|
||||
{ 65, "Weave of Life Magic" },
|
||||
{ 66, "Weave of Loyalty" },
|
||||
{ 67, "Weave of Light Weapons" },
|
||||
{ 68, "Weave of Magic Defense" },
|
||||
{ 69, "Weave of Magic Item Tinkering" },
|
||||
{ 70, "Weave of Mana Conversion" },
|
||||
{ 71, "Weave of Melee Defense" },
|
||||
{ 72, "Weave of Missile Defense" },
|
||||
{ 73, "Weave of Salvaging" },
|
||||
{ 74, "Weave of Light Weapons" },
|
||||
{ 75, "Weave of Light Weapons" },
|
||||
{ 76, "Weave of Heavy Weapons" },
|
||||
{ 77, "Weave of Missile Weapons" },
|
||||
{ 78, "Weave of Two Handed Combat" },
|
||||
{ 79, "Weave of Light Weapons" },
|
||||
{ 80, "Weave of Void Magic" },
|
||||
{ 81, "Weave of War Magic" },
|
||||
{ 82, "Weave of Weapon Tinkering" },
|
||||
{ 83, "Weave of Assess Creature " },
|
||||
{ 84, "Weave of Dirty Fighting" },
|
||||
{ 85, "Weave of Dual Wield" },
|
||||
{ 86, "Weave of Recklessness" },
|
||||
{ 87, "Weave of Shield" },
|
||||
{ 88, "Weave of Sneak Attack" },
|
||||
{ 89, "Ninja_New" },
|
||||
{ 90, "Weave of Summoning" },
|
||||
|
||||
{ 91, "Shrouded Soul" },
|
||||
{ 92, "Darkened Mind" },
|
||||
{ 93, "Clouded Spirit" },
|
||||
{ 94, "Minor Stinging Shrouded Soul" },
|
||||
{ 95, "Minor Sparking Shrouded Soul" },
|
||||
{ 96, "Minor Smoldering Shrouded Soul" },
|
||||
{ 97, "Minor Shivering Shrouded Soul" },
|
||||
{ 98, "Minor Stinging Darkened Mind" },
|
||||
{ 99, "Minor Sparking Darkened Mind" },
|
||||
|
||||
{ 100, "Minor Smoldering Darkened Mind" },
|
||||
{ 101, "Minor Shivering Darkened Mind" },
|
||||
{ 102, "Minor Stinging Clouded Spirit" },
|
||||
{ 103, "Minor Sparking Clouded Spirit" },
|
||||
{ 104, "Minor Smoldering Clouded Spirit" },
|
||||
{ 105, "Minor Shivering Clouded Spirit" },
|
||||
{ 106, "Major Stinging Shrouded Soul" },
|
||||
{ 107, "Major Sparking Shrouded Soul" },
|
||||
{ 108, "Major Smoldering Shrouded Soul" },
|
||||
{ 109, "Major Shivering Shrouded Soul" },
|
||||
|
||||
{ 110, "Major Stinging Darkened Mind" },
|
||||
{ 111, "Major Sparking Darkened Mind" },
|
||||
{ 112, "Major Smoldering Darkened Mind" },
|
||||
{ 113, "Major Shivering Darkened Mind" },
|
||||
{ 114, "Major Stinging Clouded Spirit" },
|
||||
{ 115, "Major Sparking Clouded Spirit" },
|
||||
{ 116, "Major Smoldering Clouded Spirit" },
|
||||
{ 117, "Major Shivering Clouded Spirit" },
|
||||
{ 118, "Blackfire Stinging Shrouded Soul" },
|
||||
{ 119, "Blackfire Sparking Shrouded Soul" },
|
||||
|
||||
{ 120, "Blackfire Smoldering Shrouded Soul" },
|
||||
{ 121, "Blackfire Shivering Shrouded Soul" },
|
||||
{ 122, "Blackfire Stinging Darkened Mind" },
|
||||
{ 123, "Blackfire Sparking Darkened Mind" },
|
||||
{ 124, "Blackfire Smoldering Darkened Mind" },
|
||||
{ 125, "Blackfire Shivering Darkened Mind" },
|
||||
{ 126, "Blackfire Stinging Clouded Spirit" },
|
||||
{ 127, "Blackfire Sparking Clouded Spirit" },
|
||||
{ 128, "Blackfire Smoldering Clouded Spirit" },
|
||||
{ 129, "Blackfire Shivering Clouded Spirit" },
|
||||
|
||||
{ 130, "Shimmering Shadows" },
|
||||
|
||||
{ 131, "Brown Society Locket" },
|
||||
{ 132, "Yellow Society Locket" },
|
||||
{ 133, "Red Society Band" },
|
||||
{ 134, "Green Society Band" },
|
||||
{ 135, "Purple Society Band" },
|
||||
{ 136, "Blue Society Band" },
|
||||
|
||||
{ 137, "Gauntlet Garb" },
|
||||
|
||||
{ 138, "UNKNOWN_138" }, // Possibly Paragon Missile Weapons
|
||||
{ 139, "UNKNOWN_139" }, // Possibly Paragon Casters
|
||||
{ 140, "UNKNOWN_140" }, // Possibly Paragon Melee Weapons
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary of material ids vs names
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<int, string> MaterialInfo = new Dictionary<int, string>
|
||||
{
|
||||
{ 1, "Ceramic" },
|
||||
{ 2, "Porcelain" },
|
||||
// 3
|
||||
{ 4, "Linen" },
|
||||
{ 5, "Satin" },
|
||||
{ 6, "Silk" },
|
||||
{ 7, "Velvet" },
|
||||
{ 8, "Wool" },
|
||||
// 9
|
||||
{ 10, "Agate" },
|
||||
{ 11, "Amber" },
|
||||
{ 12, "Amethyst" },
|
||||
{ 13, "Aquamarine" },
|
||||
{ 14, "Azurite" },
|
||||
{ 15, "Black Garnet" },
|
||||
{ 16, "Black Opal" },
|
||||
{ 17, "Bloodstone" },
|
||||
{ 18, "Carnelian" },
|
||||
{ 19, "Citrine" },
|
||||
{ 20, "Diamond" },
|
||||
{ 21, "Emerald" },
|
||||
{ 22, "Fire Opal" },
|
||||
{ 23, "Green Garnet" },
|
||||
{ 24, "Green Jade" },
|
||||
{ 25, "Hematite" },
|
||||
{ 26, "Imperial Topaz" },
|
||||
{ 27, "Jet" },
|
||||
{ 28, "Lapis Lazuli" },
|
||||
{ 29, "Lavender Jade" },
|
||||
{ 30, "Malachite" },
|
||||
{ 31, "Moonstone" },
|
||||
{ 32, "Onyx" },
|
||||
{ 33, "Opal" },
|
||||
{ 34, "Peridot" },
|
||||
{ 35, "Red Garnet" },
|
||||
{ 36, "Red Jade" },
|
||||
{ 37, "Rose Quartz" },
|
||||
{ 38, "Ruby" },
|
||||
{ 39, "Sapphire" },
|
||||
{ 40, "Smokey Quartz" },
|
||||
{ 41, "Sunstone" },
|
||||
{ 42, "Tiger Eye" },
|
||||
{ 43, "Tourmaline" },
|
||||
{ 44, "Turquoise" },
|
||||
{ 45, "White Jade" },
|
||||
{ 46, "White Quartz" },
|
||||
{ 47, "White Sapphire" },
|
||||
{ 48, "Yellow Garnet" },
|
||||
{ 49, "Yellow Topaz" },
|
||||
{ 50, "Zircon" },
|
||||
{ 51, "Ivory" },
|
||||
{ 52, "Leather" },
|
||||
{ 53, "Armoredillo Hide" },
|
||||
{ 54, "Gromnie Hide" },
|
||||
{ 55, "Reed Shark Hide" },
|
||||
// 56
|
||||
{ 57, "Brass" },
|
||||
{ 58, "Bronze" },
|
||||
{ 59, "Copper" },
|
||||
{ 60, "Gold" },
|
||||
{ 61, "Iron" },
|
||||
{ 62, "Pyreal" },
|
||||
{ 63, "Silver" },
|
||||
{ 64, "Steel" },
|
||||
// 65
|
||||
{ 66, "Alabaster" },
|
||||
{ 67, "Granite" },
|
||||
{ 68, "Marble" },
|
||||
{ 69, "Obsidian" },
|
||||
{ 70, "Sandstone" },
|
||||
{ 71, "Serpentine" },
|
||||
{ 73, "Ebony" },
|
||||
{ 74, "Mahogany" },
|
||||
{ 75, "Oak" },
|
||||
{ 76, "Pine" },
|
||||
{ 77, "Teak" },
|
||||
};
|
||||
|
||||
public struct SpellInfo<T>
|
||||
{
|
||||
public readonly int Key;
|
||||
public readonly T Change;
|
||||
public readonly T Bonus;
|
||||
|
||||
public SpellInfo(int key, T change, T bonus = default(T))
|
||||
{
|
||||
Key = key;
|
||||
Change = change;
|
||||
Bonus = bonus;
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from Decal.Adapter.Wrappers.LongValueKey
|
||||
const int LongValueKey_MaxDamage = 218103842;
|
||||
const int LongValueKey_ArmorLevel = 28;
|
||||
|
||||
public static readonly Dictionary<int, SpellInfo<int>> LongValueKeySpellEffects = new Dictionary<int, SpellInfo<int>>()
|
||||
{
|
||||
// In 2012 they removed these item spells and converted them to auras that are cast on the player, not on the item.
|
||||
{ 1616, new SpellInfo<int>(LongValueKey_MaxDamage, 20)}, // Blood Drinker VI
|
||||
{ 2096, new SpellInfo<int>(LongValueKey_MaxDamage, 22)}, // Infected Caress
|
||||
//{ 5183, new SpellInfo<LongValueKey>(LongValueKey_MaxDamage, 22)}, // Incantation of Blood Drinker Pre Feb-2013
|
||||
//{ 4395, new SpellInfo<LongValueKey>(LongValueKey_MaxDamage, 24, 2)}, // Incantation of Blood Drinker, this spell on the item adds 2 more points of damage over a user casted 8 Pre Feb-2013
|
||||
{ 5183, new SpellInfo<int>(LongValueKey_MaxDamage, 24)}, // Incantation of Blood Drinker Post Feb-2013
|
||||
{ 4395, new SpellInfo<int>(LongValueKey_MaxDamage, 24)}, // Incantation of Blood Drinker Post Feb-2013
|
||||
|
||||
{ 2598, new SpellInfo<int>(LongValueKey_MaxDamage, 2, 2)}, // Minor Blood Thirst
|
||||
{ 2586, new SpellInfo<int>(LongValueKey_MaxDamage, 4, 4)}, // Major Blood Thirst
|
||||
{ 4661, new SpellInfo<int>(LongValueKey_MaxDamage, 7, 7)}, // Epic Blood Thirst
|
||||
{ 6089, new SpellInfo<int>(LongValueKey_MaxDamage, 10, 10)}, // Legendary Blood Thirst
|
||||
|
||||
{ 3688, new SpellInfo<int>(LongValueKey_MaxDamage, 300)}, // Prodigal Blood Drinker
|
||||
|
||||
|
||||
{ 1486, new SpellInfo<int>(LongValueKey_ArmorLevel, 200)}, // Impenetrability VI
|
||||
{ 2108, new SpellInfo<int>(LongValueKey_ArmorLevel, 220)}, // Brogard's Defiance
|
||||
{ 4407, new SpellInfo<int>(LongValueKey_ArmorLevel, 240)}, // Incantation of Impenetrability
|
||||
|
||||
{ 2604, new SpellInfo<int>(LongValueKey_ArmorLevel, 20, 20)}, // Minor Impenetrability
|
||||
{ 2592, new SpellInfo<int>(LongValueKey_ArmorLevel, 40, 40)}, // Major Impenetrability
|
||||
{ 4667, new SpellInfo<int>(LongValueKey_ArmorLevel, 60, 60)}, // Epic Impenetrability
|
||||
{ 6095, new SpellInfo<int>(LongValueKey_ArmorLevel, 80, 80)}, // Legendary Impenetrability
|
||||
};
|
||||
|
||||
// Taken from Decal.Adapter.Wrappers.DoubleValueKey
|
||||
const int DoubleValueKey_ElementalDamageVersusMonsters = 152;
|
||||
const int DoubleValueKey_AttackBonus = 167772172;
|
||||
const int DoubleValueKey_MeleeDefenseBonus = 29;
|
||||
const int DoubleValueKey_ManaCBonus = 144;
|
||||
|
||||
public static readonly Dictionary<int, SpellInfo<double>> DoubleValueKeySpellEffects = new Dictionary<int, SpellInfo<double>>()
|
||||
{
|
||||
// In 2012 they removed these item spells and converted them to auras that are cast on the player, not on the item.
|
||||
{ 3258, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .06)}, // Spirit Drinker VI
|
||||
{ 3259, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .07)}, // Infected Spirit Caress
|
||||
//{ 5182, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .07)}, // Incantation of Spirit Drinker Pre Feb-2013
|
||||
//{ 4414, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .08, .01)}, // Incantation of Spirit Drinker, this spell on the item adds 1 more % of damage over a user casted 8 Pre Feb-2013
|
||||
{ 5182, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .08)}, // Incantation of Spirit Drinker Post Feb-2013
|
||||
{ 4414, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .08)}, // Incantation of Spirit Drinker, this spell on the item adds 1 more % of damage over a user casted 8 Post Feb-2013
|
||||
|
||||
{ 3251, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .01, .01)}, // Minor Spirit Thirst
|
||||
{ 3250, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .03, .03)}, // Major Spirit Thirst
|
||||
{ 4670, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .05, .05)}, // Epic Spirit Thirst
|
||||
{ 6098, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .07, .07)}, // Legendary Spirit Thirst
|
||||
|
||||
{ 3735, new SpellInfo<double>(DoubleValueKey_ElementalDamageVersusMonsters, .15)}, // Prodigal Spirit Drinker
|
||||
|
||||
|
||||
// In 2012 they removed these item spells and converted them to auras that are cast on the player, not on the item.
|
||||
{ 1592, new SpellInfo<double>(DoubleValueKey_AttackBonus, .15)}, // Heart Seeker VI
|
||||
{ 2106, new SpellInfo<double>(DoubleValueKey_AttackBonus, .17)}, // Elysa's Sight
|
||||
{ 4405, new SpellInfo<double>(DoubleValueKey_AttackBonus, .20)}, // Incantation of Heart Seeker
|
||||
|
||||
{ 2603, new SpellInfo<double>(DoubleValueKey_AttackBonus, .03, .03)}, // Minor Heart Thirst
|
||||
{ 2591, new SpellInfo<double>(DoubleValueKey_AttackBonus, .05, .05)}, // Major Heart Thirst
|
||||
{ 4666, new SpellInfo<double>(DoubleValueKey_AttackBonus, .07, .07)}, // Epic Heart Thirst
|
||||
{ 6094, new SpellInfo<double>(DoubleValueKey_AttackBonus, .09, .09)}, // Legendary Heart Thirst
|
||||
|
||||
|
||||
// In 2012 they removed these item spells and converted them to auras that are cast on the player, not on the item.
|
||||
{ 1605, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .15)}, // Defender VI
|
||||
{ 2101, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .17)}, // Cragstone's Will
|
||||
//{ 4400, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .17)}, // Incantation of Defender Pre Feb-2013
|
||||
{ 4400, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .20)}, // Incantation of Defender Post Feb-2013
|
||||
|
||||
{ 2600, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .03, .03)}, // Minor Defender
|
||||
{ 3985, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .04, .04)}, // Mukkir Sense
|
||||
{ 2588, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .05, .05)}, // Major Defender
|
||||
{ 4663, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .07, .07)}, // Epic Defender
|
||||
{ 6091, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .09, .09)}, // Legendary Defender
|
||||
|
||||
{ 3699, new SpellInfo<double>(DoubleValueKey_MeleeDefenseBonus, .25)}, // Prodigal Defender
|
||||
|
||||
|
||||
// In 2012 they removed these item spells and converted them to auras that are cast on the player, not on the item.
|
||||
{ 1480, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.60)}, // Hermetic Link VI
|
||||
{ 2117, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.70)}, // Mystic's Blessing
|
||||
{ 4418, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.80)}, // Incantation of Hermetic Link
|
||||
|
||||
{ 3201, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.05, 1.05)}, // Feeble Hermetic Link
|
||||
{ 3199, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.10, 1.10)}, // Minor Hermetic Link
|
||||
{ 3202, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.15, 1.15)}, // Moderate Hermetic Link
|
||||
{ 3200, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.20, 1.20)}, // Major Hermetic Link
|
||||
{ 6086, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.25, 1.25)}, // Epic Hermetic Link
|
||||
{ 6087, new SpellInfo<double>(DoubleValueKey_ManaCBonus, 1.30, 1.30)}, // Legendary Hermetic Link
|
||||
};
|
||||
}
|
||||
}
|
||||
266
Shared/Constants/DoubleValueKey.cs
Normal file
266
Shared/Constants/DoubleValueKey.cs
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
// https://github.com/ACEmulator/ACE/blob/master/Source/ACE.Entity/Enum/Properties/PropertyFloat.cs
|
||||
public enum DoubleValueKey
|
||||
{
|
||||
// properties marked as ServerOnly are properties we never saw in PCAPs, from here:
|
||||
// http://ac.yotesfan.com/ace_object/not_used_enums.php
|
||||
// source: @OptimShi
|
||||
// description attributes are used by the weenie editor for a cleaner display name
|
||||
|
||||
Undef = 0,
|
||||
HeartbeatInterval = 1,
|
||||
[Ephemeral]
|
||||
HeartbeatTimestamp = 2,
|
||||
HealthRate = 3,
|
||||
StaminaRate = 4,
|
||||
ManaRate = 5,
|
||||
HealthUponResurrection = 6,
|
||||
StaminaUponResurrection = 7,
|
||||
ManaUponResurrection = 8,
|
||||
StartTime = 9,
|
||||
StopTime = 10,
|
||||
ResetInterval = 11,
|
||||
Shade = 12,
|
||||
ArmorModVsSlash = 13,
|
||||
ArmorModVsPierce = 14,
|
||||
ArmorModVsBludgeon = 15,
|
||||
ArmorModVsCold = 16,
|
||||
ArmorModVsFire = 17,
|
||||
ArmorModVsAcid = 18,
|
||||
ArmorModVsElectric = 19,
|
||||
CombatSpeed = 20,
|
||||
WeaponLength = 21,
|
||||
DamageVariance = 22,
|
||||
CurrentPowerMod = 23,
|
||||
AccuracyMod = 24,
|
||||
StrengthMod = 25,
|
||||
MaximumVelocity = 26,
|
||||
RotationSpeed = 27,
|
||||
MotionTimestamp = 28,
|
||||
WeaponDefense = 29,
|
||||
WimpyLevel = 30,
|
||||
VisualAwarenessRange = 31,
|
||||
AuralAwarenessRange = 32,
|
||||
PerceptionLevel = 33,
|
||||
PowerupTime = 34,
|
||||
MaxChargeDistance = 35,
|
||||
ChargeSpeed = 36,
|
||||
BuyPrice = 37,
|
||||
SellPrice = 38,
|
||||
DefaultScale = 39,
|
||||
LockpickMod = 40,
|
||||
RegenerationInterval = 41,
|
||||
RegenerationTimestamp = 42,
|
||||
GeneratorRadius = 43,
|
||||
TimeToRot = 44,
|
||||
DeathTimestamp = 45,
|
||||
PkTimestamp = 46,
|
||||
VictimTimestamp = 47,
|
||||
LoginTimestamp = 48,
|
||||
CreationTimestamp = 49,
|
||||
MinimumTimeSincePk = 50,
|
||||
DeprecatedHousekeepingPriority = 51,
|
||||
AbuseLoggingTimestamp = 52,
|
||||
LastPortalTeleportTimestamp = 53,
|
||||
UseRadius = 54,
|
||||
HomeRadius = 55,
|
||||
ReleasedTimestamp = 56,
|
||||
MinHomeRadius = 57,
|
||||
Facing = 58,
|
||||
ResetTimestamp = 59,
|
||||
LogoffTimestamp = 60,
|
||||
EconRecoveryInterval = 61,
|
||||
WeaponOffense = 62,
|
||||
DamageMod = 63,
|
||||
ResistSlash = 64,
|
||||
ResistPierce = 65,
|
||||
ResistBludgeon = 66,
|
||||
ResistFire = 67,
|
||||
ResistCold = 68,
|
||||
ResistAcid = 69,
|
||||
ResistElectric = 70,
|
||||
ResistHealthBoost = 71,
|
||||
ResistStaminaDrain = 72,
|
||||
ResistStaminaBoost = 73,
|
||||
ResistManaDrain = 74,
|
||||
ResistManaBoost = 75,
|
||||
[Ephemeral]
|
||||
Translucency = 76,
|
||||
PhysicsScriptIntensity = 77,
|
||||
Friction = 78,
|
||||
Elasticity = 79,
|
||||
AiUseMagicDelay = 80,
|
||||
ItemMinSpellcraftMod = 81,
|
||||
ItemMaxSpellcraftMod = 82,
|
||||
ItemRankProbability = 83,
|
||||
Shade2 = 84,
|
||||
Shade3 = 85,
|
||||
Shade4 = 86,
|
||||
ItemEfficiency = 87,
|
||||
ItemManaUpdateTimestamp = 88,
|
||||
SpellGestureSpeedMod = 89,
|
||||
SpellStanceSpeedMod = 90,
|
||||
AllegianceAppraisalTimestamp = 91,
|
||||
PowerLevel = 92,
|
||||
AccuracyLevel = 93,
|
||||
AttackAngle = 94,
|
||||
AttackTimestamp = 95,
|
||||
CheckpointTimestamp = 96,
|
||||
SoldTimestamp = 97,
|
||||
UseTimestamp = 98,
|
||||
UseLockTimestamp = 99,
|
||||
HealkitMod = 100,
|
||||
FrozenTimestamp = 101,
|
||||
HealthRateMod = 102,
|
||||
AllegianceSwearTimestamp = 103,
|
||||
ObviousRadarRange = 104,
|
||||
HotspotCycleTime = 105,
|
||||
HotspotCycleTimeVariance = 106,
|
||||
SpamTimestamp = 107,
|
||||
SpamRate = 108,
|
||||
BondWieldedTreasure = 109,
|
||||
BulkMod = 110,
|
||||
SizeMod = 111,
|
||||
GagTimestamp = 112,
|
||||
GeneratorUpdateTimestamp = 113,
|
||||
DeathSpamTimestamp = 114,
|
||||
DeathSpamRate = 115,
|
||||
WildAttackProbability = 116,
|
||||
FocusedProbability = 117,
|
||||
CrashAndTurnProbability = 118,
|
||||
CrashAndTurnRadius = 119,
|
||||
CrashAndTurnBias = 120,
|
||||
GeneratorInitialDelay = 121,
|
||||
AiAcquireHealth = 122,
|
||||
AiAcquireStamina = 123,
|
||||
AiAcquireMana = 124,
|
||||
/// <summary>
|
||||
/// this had a default of "1" - leaving comment to investigate potential options for defaulting these things (125)
|
||||
/// </summary>
|
||||
[SendOnLogin]
|
||||
ResistHealthDrain = 125,
|
||||
LifestoneProtectionTimestamp = 126,
|
||||
AiCounteractEnchantment = 127,
|
||||
AiDispelEnchantment = 128,
|
||||
TradeTimestamp = 129,
|
||||
AiTargetedDetectionRadius = 130,
|
||||
EmotePriority = 131,
|
||||
[Ephemeral]
|
||||
LastTeleportStartTimestamp = 132,
|
||||
EventSpamTimestamp = 133,
|
||||
EventSpamRate = 134,
|
||||
InventoryOffset = 135,
|
||||
CriticalMultiplier = 136,
|
||||
ManaStoneDestroyChance = 137,
|
||||
SlayerDamageBonus = 138,
|
||||
AllegianceInfoSpamTimestamp = 139,
|
||||
AllegianceInfoSpamRate = 140,
|
||||
NextSpellcastTimestamp = 141,
|
||||
[Ephemeral]
|
||||
AppraisalRequestedTimestamp = 142,
|
||||
AppraisalHeartbeatDueTimestamp = 143,
|
||||
ManaConversionMod = 144,
|
||||
LastPkAttackTimestamp = 145,
|
||||
FellowshipUpdateTimestamp = 146,
|
||||
CriticalFrequency = 147,
|
||||
LimboStartTimestamp = 148,
|
||||
WeaponMissileDefense = 149,
|
||||
WeaponMagicDefense = 150,
|
||||
IgnoreShield = 151,
|
||||
ElementalDamageMod = 152,
|
||||
StartMissileAttackTimestamp = 153,
|
||||
LastRareUsedTimestamp = 154,
|
||||
IgnoreArmor = 155,
|
||||
ProcSpellRate = 156,
|
||||
ResistanceModifier = 157,
|
||||
AllegianceGagTimestamp = 158,
|
||||
AbsorbMagicDamage = 159,
|
||||
CachedMaxAbsorbMagicDamage = 160,
|
||||
GagDuration = 161,
|
||||
AllegianceGagDuration = 162,
|
||||
[SendOnLogin]
|
||||
GlobalXpMod = 163,
|
||||
HealingModifier = 164,
|
||||
ArmorModVsNether = 165,
|
||||
ResistNether = 166,
|
||||
CooldownDuration = 167,
|
||||
[SendOnLogin]
|
||||
WeaponAuraOffense = 168,
|
||||
[SendOnLogin]
|
||||
WeaponAuraDefense = 169,
|
||||
[SendOnLogin]
|
||||
WeaponAuraElemental = 170,
|
||||
[SendOnLogin]
|
||||
WeaponAuraManaConv = 171,
|
||||
|
||||
|
||||
// ACE Specific
|
||||
[ServerOnly]
|
||||
PCAPRecordedWorkmanship = 8004,
|
||||
[ServerOnly]
|
||||
PCAPRecordedVelocityX = 8010,
|
||||
[ServerOnly]
|
||||
PCAPRecordedVelocityY = 8011,
|
||||
[ServerOnly]
|
||||
PCAPRecordedVelocityZ = 8012,
|
||||
[ServerOnly]
|
||||
PCAPRecordedAccelerationX = 8013,
|
||||
[ServerOnly]
|
||||
PCAPRecordedAccelerationY = 8014,
|
||||
[ServerOnly]
|
||||
PCAPRecordedAccelerationZ = 8015,
|
||||
[ServerOnly]
|
||||
PCAPRecordeOmegaX = 8016,
|
||||
[ServerOnly]
|
||||
PCAPRecordeOmegaY = 8017,
|
||||
[ServerOnly]
|
||||
PCAPRecordeOmegaZ = 8018,
|
||||
|
||||
|
||||
// Decal Specific
|
||||
SlashProt_Decal = 167772160,
|
||||
PierceProt_Decal = 167772161,
|
||||
BludgeonProt_Decal = 167772162,
|
||||
AcidProt_Decal = 167772163,
|
||||
LightningProt_Decal = 167772164,
|
||||
FireProt_Decal = 167772165,
|
||||
ColdProt_Decal = 167772166,
|
||||
Heading_Decal = 167772167,
|
||||
ApproachDistance_Decal = 167772168,
|
||||
SalvageWorkmanship_Decal = 167772169,
|
||||
Scale_Decal = 167772170,
|
||||
Variance_Decal = 167772171,
|
||||
AttackBonus_Decal = 167772172,
|
||||
Range_Decal = 167772173,
|
||||
DamageBonus_Decal = 167772174,
|
||||
}
|
||||
|
||||
public static class DoubleValueKeyTools
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a decal specific IntValueKey to the actual IntValueKey.
|
||||
/// If this is not an IntValueKey, 0 will be returned.
|
||||
/// </summary>
|
||||
public static uint ConvertToDouble(DoubleValueKey input)
|
||||
{
|
||||
if (input == DoubleValueKey.SlashProt_Decal) return (int)DoubleValueKey.ArmorModVsSlash;
|
||||
if (input == DoubleValueKey.PierceProt_Decal) return (int)DoubleValueKey.ArmorModVsPierce;
|
||||
if (input == DoubleValueKey.BludgeonProt_Decal) return (int)DoubleValueKey.ArmorModVsBludgeon;
|
||||
if (input == DoubleValueKey.AcidProt_Decal) return (int)DoubleValueKey.ArmorModVsAcid;
|
||||
if (input == DoubleValueKey.LightningProt_Decal) return (int)DoubleValueKey.ArmorModVsElectric;
|
||||
if (input == DoubleValueKey.FireProt_Decal) return (int)DoubleValueKey.ArmorModVsFire;
|
||||
if (input == DoubleValueKey.ColdProt_Decal) return (int)DoubleValueKey.ArmorModVsCold;
|
||||
|
||||
if (input == DoubleValueKey.ApproachDistance_Decal) return (int)DoubleValueKey.UseRadius;
|
||||
if (input == DoubleValueKey.Scale_Decal) return (int)DoubleValueKey.DefaultScale;
|
||||
if (input == DoubleValueKey.Variance_Decal) return (int)DoubleValueKey.DamageVariance;
|
||||
if (input == DoubleValueKey.AttackBonus_Decal) return (int)DoubleValueKey.WeaponOffense;;
|
||||
if (input == DoubleValueKey.Range_Decal) return (int)DoubleValueKey.MaximumVelocity;
|
||||
if (input == DoubleValueKey.DamageBonus_Decal) return (int)DoubleValueKey.DamageMod;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Shared/Constants/EphemeralAttribute.cs
Normal file
11
Shared/Constants/EphemeralAttribute.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// These are properties that aren't saved to the shard.
|
||||
/// </summary>
|
||||
public class EphemeralAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
126
Shared/Constants/EquipMask.cs
Normal file
126
Shared/Constants/EquipMask.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the mapping for LongValueKey.EquippableSlots.
|
||||
/// It represents where you can drag items to on your paper doll.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum EquipMask : uint
|
||||
{
|
||||
None = 0x00000000,
|
||||
|
||||
HeadWear = 0x00000001,
|
||||
|
||||
ChestWear = 0x00000002,
|
||||
AbdomenWear = 0x00000004,
|
||||
UpperArmWear = 0x00000008,
|
||||
LowerArmWear = 0x00000010,
|
||||
|
||||
HandWear = 0x00000020,
|
||||
|
||||
UpperLegWear = 0x00000040,
|
||||
LowerLegWear = 0x00000080,
|
||||
|
||||
FootWear = 0x00000100,
|
||||
ChestArmor = 0x00000200,
|
||||
AbdomenArmor = 0x00000400,
|
||||
UpperArmArmor = 0x00000800,
|
||||
LowerArmArmor = 0x00001000,
|
||||
UpperLegArmor = 0x00002000,
|
||||
LowerLegArmor = 0x00004000,
|
||||
|
||||
NeckWear = 0x00008000,
|
||||
WristWearLeft = 0x00010000,
|
||||
WristWearRight = 0x00020000,
|
||||
FingerWearLeft = 0x00040000,
|
||||
FingerWearRight = 0x00080000,
|
||||
|
||||
MeleeWeapon = 0x00100000,
|
||||
Shield = 0x00200000,
|
||||
MissileWeapon = 0x00400000,
|
||||
MissileAmmo = 0x00800000,
|
||||
Held = 0x01000000,
|
||||
TwoHanded = 0x02000000,
|
||||
|
||||
TrinketOne = 0x04000000,
|
||||
Cloak = 0x08000000,
|
||||
|
||||
SigilOne = 0x10000000, // Blue
|
||||
SigilTwo = 0x20000000, // Yellow
|
||||
SigilThree = 0x40000000, // Red
|
||||
|
||||
Clothing = 0x80000000 | HeadWear | ChestWear | AbdomenWear | UpperArmWear | LowerArmWear | HandWear | UpperLegWear | LowerLegWear | FootWear,
|
||||
Armor = ChestArmor | AbdomenArmor | UpperArmArmor | LowerArmArmor | UpperLegArmor | LowerLegArmor | FootWear,
|
||||
ArmorExclusive = ChestArmor | AbdomenArmor | UpperArmArmor | LowerArmArmor | UpperLegArmor | LowerLegArmor,
|
||||
Extremity = HeadWear | HandWear | FootWear,
|
||||
Jewelry = NeckWear | WristWearLeft | WristWearRight | FingerWearLeft | FingerWearRight | TrinketOne | Cloak | SigilOne | SigilTwo | SigilThree,
|
||||
WristWear = WristWearLeft | WristWearRight,
|
||||
FingerWear = FingerWearLeft | FingerWearRight,
|
||||
Sigil = SigilOne | SigilTwo | SigilThree,
|
||||
ReadySlot = Held | TwoHanded | TrinketOne | Cloak | SigilOne | SigilTwo,
|
||||
Weapon = SigilTwo | TrinketOne | Held,
|
||||
WeaponReadySlot = SigilOne | SigilTwo | TrinketOne | Held,
|
||||
Selectable = MeleeWeapon | Shield | MissileWeapon | Held | TwoHanded,
|
||||
SelectablePlusAmmo = Selectable | MissileAmmo,
|
||||
All = 0x7FFFFFFF,
|
||||
CanGoInReadySlot = 0x7FFFFFFF
|
||||
}
|
||||
|
||||
public static class EquipMaskExtensions
|
||||
{
|
||||
public static int GetTotalBitsSet(this EquipMask value)
|
||||
{
|
||||
int slotFlags = (int)value;
|
||||
int bitsSet = 0;
|
||||
|
||||
while (slotFlags != 0)
|
||||
{
|
||||
if ((slotFlags & 1) == 1)
|
||||
bitsSet++;
|
||||
slotFlags >>= 1;
|
||||
}
|
||||
|
||||
return bitsSet;
|
||||
}
|
||||
|
||||
// Some feet armor have EquipMask.Feet | EquipMask.PantsLowerLegs
|
||||
|
||||
public static bool IsBodyArmor(this EquipMask value)
|
||||
{
|
||||
return ((int)value & 0x00007F21) != 0;
|
||||
}
|
||||
|
||||
public static bool IsCoreBodyArmor(this EquipMask value)
|
||||
{
|
||||
return (value & (EquipMask.ChestArmor | EquipMask.UpperArmArmor | EquipMask.LowerArmArmor | EquipMask.AbdomenArmor | EquipMask.UpperLegArmor | EquipMask.LowerLegArmor)) != 0;
|
||||
}
|
||||
|
||||
public static bool IsExtremityBodyArmor(this EquipMask value)
|
||||
{
|
||||
return (value & (EquipMask.FootWear | EquipMask.HandWear | EquipMask.HeadWear)) != 0;
|
||||
}
|
||||
|
||||
public static bool IsUnderwear(this EquipMask value)
|
||||
{
|
||||
if (value == (EquipMask.FootWear | EquipMask.LowerLegWear))
|
||||
return false;
|
||||
|
||||
return ((int)value & 0x000000DE) != 0;
|
||||
}
|
||||
|
||||
public static bool IsShirt(this EquipMask value)
|
||||
{
|
||||
return ((int)value & 0x0000001A) != 0;
|
||||
}
|
||||
|
||||
public static bool IsPants(this EquipMask value)
|
||||
{
|
||||
if (value == (EquipMask.FootWear | EquipMask.LowerLegWear))
|
||||
return false;
|
||||
|
||||
return ((int)value & 0x000000C4) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
722
Shared/Constants/IntValueKey.cs
Normal file
722
Shared/Constants/IntValueKey.cs
Normal file
|
|
@ -0,0 +1,722 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
// https://github.com/ACEmulator/ACE/blob/master/Source/ACE.Entity/Enum/Properties/PropertyInt.cs
|
||||
public enum IntValueKey
|
||||
{
|
||||
// properties marked as ServerOnly are properties we never saw in PCAPs, from here:
|
||||
// http://ac.yotesfan.com/ace_object/not_used_enums.php
|
||||
// source: @OptimShi
|
||||
// description attributes are used by the weenie editor for a cleaner display name
|
||||
|
||||
Undef = 0,
|
||||
[ServerOnly]
|
||||
ItemType = 1,
|
||||
CreatureType = 2,
|
||||
[ServerOnly]
|
||||
PaletteTemplate = 3,
|
||||
ClothingPriority = 4,
|
||||
[SendOnLogin]
|
||||
EncumbranceVal = 5, // ENCUMB_VAL_INT,
|
||||
[SendOnLogin]
|
||||
ItemsCapacity = 6,
|
||||
[SendOnLogin]
|
||||
ContainersCapacity = 7,
|
||||
[ServerOnly]
|
||||
Mass = 8,
|
||||
[ServerOnly]
|
||||
ValidLocations = 9, // LOCATIONS_INT
|
||||
[ServerOnly]
|
||||
CurrentWieldedLocation = 10,
|
||||
[ServerOnly]
|
||||
MaxStackSize = 11,
|
||||
[ServerOnly]
|
||||
StackSize = 12,
|
||||
[ServerOnly]
|
||||
StackUnitEncumbrance = 13,
|
||||
[ServerOnly]
|
||||
StackUnitMass = 14,
|
||||
[ServerOnly]
|
||||
StackUnitValue = 15,
|
||||
[ServerOnly]
|
||||
ItemUseable = 16,
|
||||
RareId = 17,
|
||||
[ServerOnly]
|
||||
UiEffects = 18,
|
||||
Value = 19,
|
||||
[Ephemeral][SendOnLogin]
|
||||
CoinValue = 20,
|
||||
TotalExperience = 21,
|
||||
AvailableCharacter = 22,
|
||||
TotalSkillCredits = 23,
|
||||
[SendOnLogin]
|
||||
AvailableSkillCredits = 24,
|
||||
[SendOnLogin]
|
||||
Level = 25,
|
||||
AccountRequirements = 26,
|
||||
ArmorType = 27,
|
||||
ArmorLevel = 28,
|
||||
AllegianceCpPool = 29,
|
||||
[SendOnLogin]
|
||||
AllegianceRank = 30,
|
||||
ChannelsAllowed = 31,
|
||||
ChannelsActive = 32,
|
||||
Bonded = 33,
|
||||
MonarchsRank = 34,
|
||||
AllegianceFollowers = 35,
|
||||
ResistMagic = 36,
|
||||
ResistItemAppraisal = 37,
|
||||
ResistLockpick = 38,
|
||||
DeprecatedResistRepair = 39,
|
||||
[SendOnLogin]
|
||||
CombatMode = 40,
|
||||
CurrentAttackHeight = 41,
|
||||
CombatCollisions = 42,
|
||||
[SendOnLogin]
|
||||
NumDeaths = 43,
|
||||
Damage = 44,
|
||||
DamageType = 45,
|
||||
[ServerOnly]
|
||||
DefaultCombatStyle = 46,
|
||||
[SendOnLogin]
|
||||
AttackType = 47,
|
||||
WeaponSkill = 48,
|
||||
WeaponTime = 49,
|
||||
AmmoType = 50,
|
||||
CombatUse = 51,
|
||||
[ServerOnly]
|
||||
ParentLocation = 52,
|
||||
/// <summary>
|
||||
/// TODO: Migrate inventory order away from this and instead use the new InventoryOrder property
|
||||
/// TODO: PlacementPosition is used (very sparingly) in cache.bin, so it has (or had) a meaning at one point before we hijacked it
|
||||
/// TODO: and used it for our own inventory order
|
||||
/// </summary>
|
||||
[ServerOnly]
|
||||
PlacementPosition = 53,
|
||||
WeaponEncumbrance = 54,
|
||||
WeaponMass = 55,
|
||||
ShieldValue = 56,
|
||||
ShieldEncumbrance = 57,
|
||||
MissileInventoryLocation = 58,
|
||||
FullDamageType = 59,
|
||||
WeaponRange = 60,
|
||||
AttackersSkill = 61,
|
||||
DefendersSkill = 62,
|
||||
AttackersSkillValue = 63,
|
||||
AttackersClass = 64,
|
||||
[ServerOnly]
|
||||
Placement = 65,
|
||||
CheckpointStatus = 66,
|
||||
Tolerance = 67,
|
||||
TargetingTactic = 68,
|
||||
CombatTactic = 69,
|
||||
HomesickTargetingTactic = 70,
|
||||
NumFollowFailures = 71,
|
||||
FriendType = 72,
|
||||
FoeType = 73,
|
||||
MerchandiseItemTypes = 74,
|
||||
MerchandiseMinValue = 75,
|
||||
MerchandiseMaxValue = 76,
|
||||
NumItemsSold = 77,
|
||||
NumItemsBought = 78,
|
||||
MoneyIncome = 79,
|
||||
MoneyOutflow = 80,
|
||||
[Ephemeral]
|
||||
MaxGeneratedObjects = 81,
|
||||
[Ephemeral]
|
||||
InitGeneratedObjects = 82,
|
||||
ActivationResponse = 83,
|
||||
OriginalValue = 84,
|
||||
NumMoveFailures = 85,
|
||||
MinLevel = 86,
|
||||
MaxLevel = 87,
|
||||
LockpickMod = 88,
|
||||
BoosterEnum = 89,
|
||||
BoostValue = 90,
|
||||
MaxStructure = 91,
|
||||
Structure = 92,
|
||||
[ServerOnly]
|
||||
PhysicsState = 93,
|
||||
[ServerOnly]
|
||||
TargetType = 94,
|
||||
RadarBlipColor = 95,
|
||||
EncumbranceCapacity = 96,
|
||||
LoginTimestamp = 97,
|
||||
[SendOnLogin]
|
||||
CreationTimestamp = 98,
|
||||
PkLevelModifier = 99,
|
||||
GeneratorType = 100,
|
||||
AiAllowedCombatStyle = 101,
|
||||
LogoffTimestamp = 102,
|
||||
GeneratorDestructionType = 103,
|
||||
ActivationCreateClass = 104,
|
||||
ItemWorkmanship = 105,
|
||||
ItemSpellcraft = 106,
|
||||
ItemCurMana = 107,
|
||||
ItemMaxMana = 108,
|
||||
ItemDifficulty = 109,
|
||||
ItemAllegianceRankLimit = 110,
|
||||
PortalBitmask = 111,
|
||||
AdvocateLevel = 112,
|
||||
[SendOnLogin]
|
||||
Gender = 113,
|
||||
Attuned = 114,
|
||||
ItemSkillLevelLimit = 115,
|
||||
GateLogic = 116,
|
||||
ItemManaCost = 117,
|
||||
Logoff = 118,
|
||||
Active = 119,
|
||||
AttackHeight = 120,
|
||||
NumAttackFailures = 121,
|
||||
AiCpThreshold = 122,
|
||||
AiAdvancementStrategy = 123,
|
||||
Version = 124,
|
||||
[SendOnLogin]
|
||||
Age = 125,
|
||||
VendorHappyMean = 126,
|
||||
VendorHappyVariance = 127,
|
||||
CloakStatus = 128,
|
||||
[SendOnLogin]
|
||||
VitaeCpPool = 129,
|
||||
NumServicesSold = 130,
|
||||
MaterialType = 131,
|
||||
[SendOnLogin]
|
||||
NumAllegianceBreaks = 132,
|
||||
[Ephemeral]
|
||||
ShowableOnRadar = 133,
|
||||
[SendOnLogin]
|
||||
PlayerKillerStatus = 134,
|
||||
VendorHappyMaxItems = 135,
|
||||
ScorePageNum = 136,
|
||||
ScoreConfigNum = 137,
|
||||
ScoreNumScores = 138,
|
||||
[SendOnLogin]
|
||||
DeathLevel = 139,
|
||||
AiOptions = 140,
|
||||
OpenToEveryone = 141,
|
||||
GeneratorTimeType = 142,
|
||||
GeneratorStartTime = 143,
|
||||
GeneratorEndTime = 144,
|
||||
GeneratorEndDestructionType = 145,
|
||||
XpOverride = 146,
|
||||
NumCrashAndTurns = 147,
|
||||
ComponentWarningThreshold = 148,
|
||||
HouseStatus = 149,
|
||||
[ServerOnly]
|
||||
HookPlacement = 150,
|
||||
[ServerOnly]
|
||||
HookType = 151,
|
||||
[ServerOnly]
|
||||
HookItemType = 152,
|
||||
AiPpThreshold = 153,
|
||||
GeneratorVersion = 154,
|
||||
HouseType = 155,
|
||||
PickupEmoteOffset = 156,
|
||||
WeenieIteration = 157,
|
||||
WieldRequirements = 158,
|
||||
WieldSkillType = 159,
|
||||
WieldDifficulty = 160,
|
||||
HouseMaxHooksUsable = 161,
|
||||
HouseCurrentHooksUsable = 162,
|
||||
AllegianceMinLevel = 163,
|
||||
AllegianceMaxLevel = 164,
|
||||
HouseRelinkHookCount = 165,
|
||||
SlayerCreatureType = 166,
|
||||
ConfirmationInProgress = 167,
|
||||
ConfirmationTypeInProgress = 168,
|
||||
TsysMutationData = 169,
|
||||
NumItemsInMaterial = 170,
|
||||
NumTimesTinkered = 171,
|
||||
AppraisalLongDescDecoration = 172,
|
||||
AppraisalLockpickSuccessPercent = 173,
|
||||
[Ephemeral]
|
||||
AppraisalPages = 174,
|
||||
[Ephemeral]
|
||||
AppraisalMaxPages = 175,
|
||||
AppraisalItemSkill = 176,
|
||||
GemCount = 177,
|
||||
GemType = 178,
|
||||
ImbuedEffect = 179,
|
||||
AttackersRawSkillValue = 180,
|
||||
[SendOnLogin]
|
||||
ChessRank = 181,
|
||||
ChessTotalGames = 182,
|
||||
ChessGamesWon = 183,
|
||||
ChessGamesLost = 184,
|
||||
TypeOfAlteration = 185,
|
||||
SkillToBeAltered = 186,
|
||||
SkillAlterationCount = 187,
|
||||
[SendOnLogin]
|
||||
HeritageGroup = 188,
|
||||
TransferFromAttribute = 189,
|
||||
TransferToAttribute = 190,
|
||||
AttributeTransferCount = 191,
|
||||
[SendOnLogin]
|
||||
FakeFishingSkill = 192,
|
||||
NumKeys = 193,
|
||||
DeathTimestamp = 194,
|
||||
PkTimestamp = 195,
|
||||
VictimTimestamp = 196,
|
||||
HookGroup = 197,
|
||||
AllegianceSwearTimestamp = 198,
|
||||
[SendOnLogin]
|
||||
HousePurchaseTimestamp = 199,
|
||||
RedirectableEquippedArmorCount = 200,
|
||||
MeleeDefenseImbuedEffectTypeCache = 201,
|
||||
MissileDefenseImbuedEffectTypeCache = 202,
|
||||
MagicDefenseImbuedEffectTypeCache = 203,
|
||||
ElementalDamageBonus = 204,
|
||||
ImbueAttempts = 205,
|
||||
ImbueSuccesses = 206,
|
||||
CreatureKills = 207,
|
||||
PlayerKillsPk = 208,
|
||||
PlayerKillsPkl = 209,
|
||||
RaresTierOne = 210,
|
||||
RaresTierTwo = 211,
|
||||
RaresTierThree = 212,
|
||||
RaresTierFour = 213,
|
||||
RaresTierFive = 214,
|
||||
[SendOnLogin]
|
||||
AugmentationStat = 215,
|
||||
[SendOnLogin]
|
||||
AugmentationFamilyStat = 216,
|
||||
[SendOnLogin]
|
||||
AugmentationInnateFamily = 217,
|
||||
[SendOnLogin]
|
||||
AugmentationInnateStrength = 218,
|
||||
[SendOnLogin]
|
||||
AugmentationInnateEndurance = 219,
|
||||
[SendOnLogin]
|
||||
AugmentationInnateCoordination = 220,
|
||||
[SendOnLogin]
|
||||
AugmentationInnateQuickness = 221,
|
||||
[SendOnLogin]
|
||||
AugmentationInnateFocus = 222,
|
||||
[SendOnLogin]
|
||||
AugmentationInnateSelf = 223,
|
||||
[SendOnLogin]
|
||||
AugmentationSpecializeSalvaging = 224,
|
||||
[SendOnLogin]
|
||||
AugmentationSpecializeItemTinkering = 225,
|
||||
[SendOnLogin]
|
||||
AugmentationSpecializeArmorTinkering = 226,
|
||||
[SendOnLogin]
|
||||
AugmentationSpecializeMagicItemTinkering = 227,
|
||||
[SendOnLogin]
|
||||
AugmentationSpecializeWeaponTinkering = 228,
|
||||
[SendOnLogin]
|
||||
AugmentationExtraPackSlot = 229,
|
||||
[SendOnLogin]
|
||||
AugmentationIncreasedCarryingCapacity = 230,
|
||||
[SendOnLogin]
|
||||
AugmentationLessDeathItemLoss = 231,
|
||||
[SendOnLogin]
|
||||
AugmentationSpellsRemainPastDeath = 232,
|
||||
[SendOnLogin]
|
||||
AugmentationCriticalDefense = 233,
|
||||
[SendOnLogin]
|
||||
AugmentationBonusXp = 234,
|
||||
[SendOnLogin]
|
||||
AugmentationBonusSalvage = 235,
|
||||
[SendOnLogin]
|
||||
AugmentationBonusImbueChance = 236,
|
||||
[SendOnLogin]
|
||||
AugmentationFasterRegen = 237,
|
||||
[SendOnLogin]
|
||||
AugmentationIncreasedSpellDuration = 238,
|
||||
[SendOnLogin]
|
||||
AugmentationResistanceFamily = 239,
|
||||
[SendOnLogin]
|
||||
AugmentationResistanceSlash = 240,
|
||||
[SendOnLogin]
|
||||
AugmentationResistancePierce = 241,
|
||||
[SendOnLogin]
|
||||
AugmentationResistanceBlunt = 242,
|
||||
[SendOnLogin]
|
||||
AugmentationResistanceAcid = 243,
|
||||
[SendOnLogin]
|
||||
AugmentationResistanceFire = 244,
|
||||
[SendOnLogin]
|
||||
AugmentationResistanceFrost = 245,
|
||||
[SendOnLogin]
|
||||
AugmentationResistanceLightning = 246,
|
||||
RaresTierOneLogin = 247,
|
||||
RaresTierTwoLogin = 248,
|
||||
RaresTierThreeLogin = 249,
|
||||
RaresTierFourLogin = 250,
|
||||
RaresTierFiveLogin = 251,
|
||||
RaresLoginTimestamp = 252,
|
||||
RaresTierSix = 253,
|
||||
RaresTierSeven = 254,
|
||||
RaresTierSixLogin = 255,
|
||||
RaresTierSevenLogin = 256,
|
||||
ItemAttributeLimit = 257,
|
||||
ItemAttributeLevelLimit = 258,
|
||||
ItemAttribute2ndLimit = 259,
|
||||
ItemAttribute2ndLevelLimit = 260,
|
||||
CharacterTitleId = 261,
|
||||
NumCharacterTitles = 262,
|
||||
ResistanceModifierType = 263,
|
||||
FreeTinkersBitfield = 264,
|
||||
EquipmentSetId = 265,
|
||||
PetClass = 266,
|
||||
Lifespan = 267,
|
||||
[Ephemeral]
|
||||
RemainingLifespan = 268,
|
||||
UseCreateQuantity = 269,
|
||||
WieldRequirements2 = 270,
|
||||
WieldSkillType2 = 271,
|
||||
WieldDifficulty2 = 272,
|
||||
WieldRequirements3 = 273,
|
||||
WieldSkillType3 = 274,
|
||||
WieldDifficulty3 = 275,
|
||||
WieldRequirements4 = 276,
|
||||
WieldSkillType4 = 277,
|
||||
WieldDifficulty4 = 278,
|
||||
Unique = 279,
|
||||
SharedCooldown = 280,
|
||||
Faction1Bits = 281,
|
||||
Faction2Bits = 282,
|
||||
Faction3Bits = 283,
|
||||
Hatred1Bits = 284,
|
||||
Hatred2Bits = 285,
|
||||
Hatred3Bits = 286,
|
||||
SocietyRankCelhan = 287,
|
||||
SocietyRankEldweb = 288,
|
||||
SocietyRankRadblo = 289,
|
||||
HearLocalSignals = 290,
|
||||
HearLocalSignalsRadius = 291,
|
||||
Cleaving = 292,
|
||||
[SendOnLogin]
|
||||
AugmentationSpecializeGearcraft = 293,
|
||||
[SendOnLogin]
|
||||
AugmentationInfusedCreatureMagic = 294,
|
||||
[SendOnLogin]
|
||||
AugmentationInfusedItemMagic = 295,
|
||||
[SendOnLogin]
|
||||
AugmentationInfusedLifeMagic = 296,
|
||||
[SendOnLogin]
|
||||
AugmentationInfusedWarMagic = 297,
|
||||
[SendOnLogin]
|
||||
AugmentationCriticalExpertise = 298,
|
||||
[SendOnLogin]
|
||||
AugmentationCriticalPower = 299,
|
||||
[SendOnLogin]
|
||||
AugmentationSkilledMelee = 300,
|
||||
[SendOnLogin]
|
||||
AugmentationSkilledMissile = 301,
|
||||
[SendOnLogin]
|
||||
AugmentationSkilledMagic = 302,
|
||||
ImbuedEffect2 = 303,
|
||||
ImbuedEffect3 = 304,
|
||||
ImbuedEffect4 = 305,
|
||||
ImbuedEffect5 = 306,
|
||||
[SendOnLogin]
|
||||
DamageRating = 307,
|
||||
[SendOnLogin]
|
||||
DamageResistRating = 308,
|
||||
[SendOnLogin]
|
||||
AugmentationDamageBonus = 309,
|
||||
[SendOnLogin]
|
||||
AugmentationDamageReduction = 310,
|
||||
ImbueStackingBits = 311,
|
||||
[SendOnLogin]
|
||||
HealOverTime = 312,
|
||||
[SendOnLogin]
|
||||
CritRating = 313,
|
||||
[SendOnLogin]
|
||||
CritDamageRating = 314,
|
||||
[SendOnLogin]
|
||||
CritResistRating = 315,
|
||||
[SendOnLogin]
|
||||
CritDamageResistRating = 316,
|
||||
[SendOnLogin]
|
||||
HealingResistRating = 317,
|
||||
[SendOnLogin]
|
||||
DamageOverTime = 318,
|
||||
ItemMaxLevel = 319,
|
||||
ItemXpStyle = 320,
|
||||
EquipmentSetExtra = 321,
|
||||
[SendOnLogin]
|
||||
AetheriaBitfield = 322,
|
||||
[SendOnLogin]
|
||||
HealingBoostRating = 323,
|
||||
HeritageSpecificArmor = 324,
|
||||
AlternateRacialSkills = 325,
|
||||
[SendOnLogin]
|
||||
AugmentationJackOfAllTrades = 326,
|
||||
[SendOnLogin]
|
||||
AugmentationResistanceNether = 327,
|
||||
[SendOnLogin]
|
||||
AugmentationInfusedVoidMagic = 328,
|
||||
[SendOnLogin]
|
||||
WeaknessRating = 329,
|
||||
[SendOnLogin]
|
||||
NetherOverTime = 330,
|
||||
[SendOnLogin]
|
||||
NetherResistRating = 331,
|
||||
LuminanceAward = 332,
|
||||
[SendOnLogin]
|
||||
LumAugDamageRating = 333,
|
||||
[SendOnLogin]
|
||||
LumAugDamageReductionRating = 334,
|
||||
[SendOnLogin]
|
||||
LumAugCritDamageRating = 335,
|
||||
[SendOnLogin]
|
||||
LumAugCritReductionRating = 336,
|
||||
[SendOnLogin]
|
||||
LumAugSurgeEffectRating = 337,
|
||||
[SendOnLogin]
|
||||
LumAugSurgeChanceRating = 338,
|
||||
[SendOnLogin]
|
||||
LumAugItemManaUsage = 339,
|
||||
[SendOnLogin]
|
||||
LumAugItemManaGain = 340,
|
||||
[SendOnLogin]
|
||||
LumAugVitality = 341,
|
||||
[SendOnLogin]
|
||||
LumAugHealingRating = 342,
|
||||
[SendOnLogin]
|
||||
LumAugSkilledCraft = 343,
|
||||
[SendOnLogin]
|
||||
LumAugSkilledSpec = 344,
|
||||
[SendOnLogin]
|
||||
LumAugNoDestroyCraft = 345,
|
||||
RestrictInteraction = 346,
|
||||
OlthoiLootTimestamp = 347,
|
||||
OlthoiLootStep = 348,
|
||||
UseCreatesContractId = 349,
|
||||
[SendOnLogin]
|
||||
DotResistRating = 350,
|
||||
[SendOnLogin]
|
||||
LifeResistRating = 351,
|
||||
CloakWeaveProc = 352,
|
||||
WeaponType = 353,
|
||||
[SendOnLogin]
|
||||
MeleeMastery = 354,
|
||||
[SendOnLogin]
|
||||
RangedMastery = 355,
|
||||
SneakAttackRating = 356,
|
||||
RecklessnessRating = 357,
|
||||
DeceptionRating = 358,
|
||||
CombatPetRange = 359,
|
||||
[SendOnLogin]
|
||||
WeaponAuraDamage = 360,
|
||||
[SendOnLogin]
|
||||
WeaponAuraSpeed = 361,
|
||||
[SendOnLogin]
|
||||
SummoningMastery = 362,
|
||||
HeartbeatLifespan = 363,
|
||||
UseLevelRequirement = 364,
|
||||
[SendOnLogin]
|
||||
LumAugAllSkills = 365,
|
||||
UseRequiresSkill = 366,
|
||||
UseRequiresSkillLevel = 367,
|
||||
UseRequiresSkillSpec = 368,
|
||||
UseRequiresLevel = 369,
|
||||
[SendOnLogin]
|
||||
GearDamage = 370,
|
||||
[SendOnLogin]
|
||||
GearDamageResist = 371,
|
||||
[SendOnLogin]
|
||||
GearCrit = 372,
|
||||
[SendOnLogin]
|
||||
GearCritResist = 373,
|
||||
[SendOnLogin]
|
||||
GearCritDamage = 374,
|
||||
[SendOnLogin]
|
||||
GearCritDamageResist = 375,
|
||||
[SendOnLogin]
|
||||
GearHealingBoost = 376,
|
||||
[SendOnLogin]
|
||||
GearNetherResist = 377,
|
||||
[SendOnLogin]
|
||||
GearLifeResist = 378,
|
||||
[SendOnLogin]
|
||||
GearMaxHealth = 379,
|
||||
Unknown380 = 380,
|
||||
[SendOnLogin]
|
||||
PKDamageRating = 381,
|
||||
[SendOnLogin]
|
||||
PKDamageResistRating = 382,
|
||||
[SendOnLogin]
|
||||
GearPKDamageRating = 383,
|
||||
[SendOnLogin]
|
||||
GearPKDamageResistRating = 384,
|
||||
Unknown385 = 385,
|
||||
/// <summary>
|
||||
/// Overpower chance % for endgame creatures.
|
||||
/// </summary>
|
||||
[SendOnLogin]
|
||||
Overpower = 386,
|
||||
[SendOnLogin]
|
||||
OverpowerResist = 387,
|
||||
// Client does not display accurately
|
||||
[SendOnLogin]
|
||||
GearOverpower = 388,
|
||||
// Client does not display accurately
|
||||
[SendOnLogin]
|
||||
GearOverpowerResist = 389,
|
||||
// Number of times a character has enlightened
|
||||
[SendOnLogin]
|
||||
Enlightenment = 390,
|
||||
|
||||
|
||||
// ACE Specific
|
||||
[ServerOnly]
|
||||
PCAPRecordedAutonomousMovement = 8007,
|
||||
[ServerOnly]
|
||||
PCAPRecordedMaxVelocityEstimated = 8030,
|
||||
[ServerOnly]
|
||||
PCAPRecordedPlacement = 8041,
|
||||
[ServerOnly]
|
||||
PCAPRecordedAppraisalPages = 8042,
|
||||
[ServerOnly]
|
||||
PCAPRecordedAppraisalMaxPages = 8043,
|
||||
|
||||
//[ServerOnly]
|
||||
//TotalLogins = 9001,
|
||||
//[ServerOnly]
|
||||
//DeletionTimestamp = 9002,
|
||||
//[ServerOnly]
|
||||
//CharacterOptions1 = 9003,
|
||||
//[ServerOnly]
|
||||
//CharacterOptions2 = 9004,
|
||||
//[ServerOnly]
|
||||
//LootTier = 9005,
|
||||
//[ServerOnly]
|
||||
//GeneratorProbability = 9006,
|
||||
//[ServerOnly]
|
||||
//WeenieType = 9007 // I don't think this property type is needed anymore. We don't store the weenie type in the property bags, we store it as a separate field in the base objects.
|
||||
[ServerOnly]
|
||||
CurrentLoyaltyAtLastLogoff = 9008,
|
||||
[ServerOnly]
|
||||
CurrentLeadershipAtLastLogoff = 9009,
|
||||
[ServerOnly]
|
||||
AllegianceOfficerRank = 9010,
|
||||
[ServerOnly]
|
||||
HouseRentTimestamp = 9011,
|
||||
/// <summary>
|
||||
/// Stores the player's selected hairstyle at creation or after a barber use. This is used only for Gear Knights and Olthoi characters who have more than a single part/texture for a "hairstyle" (BodyStyle)
|
||||
/// </summary>
|
||||
[ServerOnly]
|
||||
Hairstyle = 9012,
|
||||
/// <summary>
|
||||
/// Used to store the calculated Clothing Priority for use with armor reduced items and items like Over-Robes.
|
||||
/// </summary>
|
||||
[Ephemeral][ServerOnly]
|
||||
VisualClothingPriority = 9013,
|
||||
[ServerOnly]
|
||||
SquelchGlobal = 9014,
|
||||
|
||||
/// <summary>
|
||||
/// TODO: This is a place holder for future use. See PlacementPosition
|
||||
/// This is the sort order for items in a container
|
||||
/// </summary>
|
||||
[ServerOnly]
|
||||
InventoryOrder = 9015,
|
||||
|
||||
// Decal Specific
|
||||
WeenieClassId_Decal = 218103808,
|
||||
Icon_Decal_DID = 218103809,
|
||||
Container_Decal_IID = 218103810,
|
||||
Landblock_Decal = 218103811,
|
||||
ItemSlots_Decal = 218103812,
|
||||
PackSlots_Decal = 218103813,
|
||||
StackCount_Decal = 218103814,
|
||||
StackMax_Decal = 218103815,
|
||||
Spell_Decal_DID = 218103816,
|
||||
SlotLegacy_Decal = 218103817,
|
||||
Wielder_Decal_IID = 218103818,
|
||||
WieldingSlot_Decal = 218103819,
|
||||
Monarch_Decal_IID = 218103820,
|
||||
Coverage_Decal = 218103821,
|
||||
EquipableSlots_Decal = 218103822,
|
||||
EquipType_Decal = 218103823,
|
||||
IconOutline_Decal = 218103824,
|
||||
MissileType_Decal = 218103825,
|
||||
UsageMask_Decal = 218103826,
|
||||
HouseOwner_Decal_IID = 218103827,
|
||||
HookMask_Decal = 218103828,
|
||||
HookType_Decal = 218103829,
|
||||
Setup_Decal_DID = 218103830,
|
||||
ObjectDescriptionFlags_Decal = 218103831,
|
||||
CreateFlags1_Decal = 218103832,
|
||||
CreateFlags2_Decal = 218103833,
|
||||
Category_Decal = 218103834,
|
||||
Behavior_Decal = 218103835,
|
||||
MagicDef_Decal = 218103836,
|
||||
SpecialProps_Decal = 218103837,
|
||||
SpellCount_Decal = 218103838,
|
||||
WeapSpeed_Decal = 218103839,
|
||||
EquipSkill_Decal = 218103840,
|
||||
DamageType_Decal = 218103841,
|
||||
MaxDamage_Decal = 218103842,
|
||||
Unknown10_Decal = 218103843, // CurrentWieldLocation?
|
||||
Unknown100000_Decal = 218103844, // RadarBlipColor ???
|
||||
Unknown800000_Decal = 218103845,
|
||||
Unknown8000000_Decal = 218103846,
|
||||
PhysicsDataFlags_Decal = 218103847,
|
||||
ActiveSpellCount_Decal = 218103848,
|
||||
IconOverlay_Decal_DID = 218103849,
|
||||
IconUnderlay_Decal_DID = 218103850,
|
||||
Slot_Decal = 231735296,
|
||||
}
|
||||
|
||||
public static class IntValueKeyTools
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a decal specific IntValueKey to the actual IntValueKey.
|
||||
/// If this is not an IntValueKey, 0 will be returned.
|
||||
/// </summary>
|
||||
public static uint ConvertToInt(IntValueKey input)
|
||||
{
|
||||
if (input == IntValueKey.Category_Decal) return (int)IntValueKey.ItemType;
|
||||
if (input == IntValueKey.Coverage_Decal) return (int)IntValueKey.ClothingPriority;
|
||||
if (input == IntValueKey.ItemSlots_Decal) return (int)IntValueKey.ItemsCapacity;
|
||||
if (input == IntValueKey.PackSlots_Decal) return (int)IntValueKey.ContainersCapacity;
|
||||
if (input == IntValueKey.EquipableSlots_Decal) return (int)IntValueKey.ValidLocations;
|
||||
//if (input == IntValueKey.WieldingSlot_Decal) return (int)IntValueKey.CurrentWieldedLocation;
|
||||
if (input == IntValueKey.StackMax_Decal) return (int)IntValueKey.MaxStackSize;
|
||||
if (input == IntValueKey.StackCount_Decal) return (int)IntValueKey.StackSize;
|
||||
if (input == IntValueKey.IconOutline_Decal) return (int)IntValueKey.UiEffects;
|
||||
if (input == IntValueKey.MaxDamage_Decal) return (int)IntValueKey.Damage;
|
||||
if (input == IntValueKey.DamageType_Decal) return (int)IntValueKey.DamageType;
|
||||
if (input == IntValueKey.EquipSkill_Decal) return (int)IntValueKey.WeaponSkill;
|
||||
if (input == IntValueKey.WeapSpeed_Decal) return (int)IntValueKey.WeaponTime;
|
||||
if (input == IntValueKey.MissileType_Decal) return (int)IntValueKey.AmmoType;
|
||||
if (input == IntValueKey.EquipType_Decal) return (int)IntValueKey.CombatUse;
|
||||
if (input == IntValueKey.UsageMask_Decal) return (int)IntValueKey.TargetType;
|
||||
if (input == IntValueKey.HookMask_Decal) return (int)IntValueKey.HookType;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If input is not a IID, 0 will be returned
|
||||
/// </summary>
|
||||
public static uint ConvertToIID(IntValueKey input)
|
||||
{
|
||||
if (input == IntValueKey.Container_Decal_IID) return 2; // CONTAINER_IID
|
||||
if (input == IntValueKey.Wielder_Decal_IID) return 3; // WIELDER_IID
|
||||
if (input == IntValueKey.Monarch_Decal_IID) return 26; // MONARCH_IID
|
||||
if (input == IntValueKey.HouseOwner_Decal_IID) return 32; // HOUSE_OWNER_IID
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If input is not a DID, 0 will be returned
|
||||
/// </summary>
|
||||
public static uint ConvertToDID(IntValueKey input)
|
||||
{
|
||||
if (input == IntValueKey.Setup_Decal_DID) return 1; // SETUP_DID
|
||||
if (input == IntValueKey.Icon_Decal_DID) return 8; // ICON_DID
|
||||
if (input == IntValueKey.Spell_Decal_DID) return 28; // SPELL_DID
|
||||
if (input == IntValueKey.IconOverlay_Decal_DID) return 50; // ICON_OVERLAY_DID
|
||||
if (input == IntValueKey.IconUnderlay_Decal_DID) return 52; // ICON_UNDERLAY_DID
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Shared/Constants/ItemType.cs
Normal file
54
Shared/Constants/ItemType.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
[Flags]
|
||||
public enum ItemType : uint
|
||||
{
|
||||
None = 0x00000000,
|
||||
MeleeWeapon = 0x00000001,
|
||||
Armor = 0x00000002,
|
||||
Clothing = 0x00000004,
|
||||
Jewelry = 0x00000008,
|
||||
Creature = 0x00000010,
|
||||
Food = 0x00000020,
|
||||
Money = 0x00000040,
|
||||
Misc = 0x00000080,
|
||||
MissileWeapon = 0x00000100,
|
||||
Container = 0x00000200,
|
||||
Useless = 0x00000400,
|
||||
Gem = 0x00000800,
|
||||
SpellComponents = 0x00001000,
|
||||
Writable = 0x00002000,
|
||||
Key = 0x00004000,
|
||||
Caster = 0x00008000,
|
||||
Portal = 0x00010000,
|
||||
Lockable = 0x00020000,
|
||||
PromissoryNote = 0x00040000,
|
||||
ManaStone = 0x00080000,
|
||||
Service = 0x00100000,
|
||||
MagicWieldable = 0x00200000,
|
||||
CraftCookingBase = 0x00400000,
|
||||
CraftAlchemyBase = 0x00800000,
|
||||
CraftFletchingBase = 0x02000000,
|
||||
CraftAlchemyIntermediate = 0x04000000,
|
||||
CraftFletchingIntermediate = 0x08000000,
|
||||
LifeStone = 0x10000000,
|
||||
TinkeringTool = 0x20000000,
|
||||
TinkeringMaterial = 0x40000000,
|
||||
Gameboard = 0x80000000,
|
||||
|
||||
PortalMagicTarget = Portal | LifeStone,
|
||||
LockableMagicTarget = Misc | Container,
|
||||
Vestements = Armor | Clothing,
|
||||
Weapon = MeleeWeapon | MissileWeapon,
|
||||
WeaponOrCaster = MeleeWeapon | MissileWeapon | Caster,
|
||||
Item = MeleeWeapon | Armor | Clothing | Jewelry | Food | Money | Misc | MissileWeapon | Container |
|
||||
Gem | SpellComponents | Writable | Key | Caster | Portal | PromissoryNote | ManaStone | MagicWieldable,
|
||||
RedirectableItemEnchantmentTarget = MeleeWeapon | Armor | Clothing | MissileWeapon | Caster,
|
||||
ItemEnchantableTarget = MeleeWeapon | Armor | Clothing | Jewelry | Misc | MissileWeapon | Container | Gem | Caster | ManaStone,
|
||||
VendorShopKeep = MeleeWeapon | Armor | Clothing | Food | Misc | MissileWeapon | Container | Useless | Writable | Key |
|
||||
PromissoryNote | CraftFletchingIntermediate | TinkeringMaterial,
|
||||
VendorGrocer = Food | Container | Writable | Key | PromissoryNote | CraftCookingBase
|
||||
}
|
||||
}
|
||||
80
Shared/Constants/MaterialType.cs
Normal file
80
Shared/Constants/MaterialType.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
public enum MaterialType : uint
|
||||
{
|
||||
Unknown = 0x00000000,
|
||||
Ceramic = 0x00000001,
|
||||
Porcelain = 0x00000002,
|
||||
Linen = 0x00000004,
|
||||
Satin = 0x00000005,
|
||||
Silk = 0x00000006,
|
||||
Velvet = 0x00000007,
|
||||
Wool = 0x00000008,
|
||||
Agate = 0x0000000A,
|
||||
Amber = 0x0000000B,
|
||||
Amethyst = 0x0000000C,
|
||||
Aquamarine = 0x0000000D,
|
||||
Azurite = 0x0000000E,
|
||||
BlackGarnet = 0x0000000F,
|
||||
BlackOpal = 0x00000010,
|
||||
Bloodstone = 0x00000011,
|
||||
Carnelian = 0x00000012,
|
||||
Citrine = 0x00000013,
|
||||
Diamond = 0x00000014,
|
||||
Emerald = 0x00000015,
|
||||
FireOpal = 0x00000016,
|
||||
GreenGarnet = 0x00000017,
|
||||
GreenJade = 0x00000018,
|
||||
Hematite = 0x00000019,
|
||||
ImperialTopaz = 0x0000001A,
|
||||
Jet = 0x0000001B,
|
||||
LapisLazuli = 0x0000001C,
|
||||
LavenderJade = 0x0000001D,
|
||||
Malachite = 0x0000001E,
|
||||
Moonstone = 0x0000001F,
|
||||
Onyx = 0x00000020,
|
||||
Opal = 0x00000021,
|
||||
Peridot = 0x00000022,
|
||||
RedGarnet = 0x00000023,
|
||||
RedJade = 0x00000024,
|
||||
RoseQuartz = 0x00000025,
|
||||
Ruby = 0x00000026,
|
||||
Sapphire = 0x00000027,
|
||||
SmokeyQuartz = 0x00000028,
|
||||
Sunstone = 0x00000029,
|
||||
TigerEye = 0x0000002A,
|
||||
Tourmaline = 0x0000002B,
|
||||
Turquoise = 0x0000002C,
|
||||
WhiteJade = 0x0000002D,
|
||||
WhiteQuartz = 0x0000002E,
|
||||
WhiteSapphire = 0x0000002F,
|
||||
YellowGarnet = 0x00000030,
|
||||
YellowTopaz = 0x00000031,
|
||||
Zircon = 0x00000032,
|
||||
Ivory = 0x00000033,
|
||||
Leather = 0x00000034,
|
||||
ArmoredilloHide = 0x00000035,
|
||||
GromnieHide = 0x00000036,
|
||||
ReedSharkHide = 0x00000037,
|
||||
Brass = 0x00000039,
|
||||
Bronze = 0x0000003A,
|
||||
Copper = 0x0000003B,
|
||||
Gold = 0x0000003C,
|
||||
Iron = 0x0000003D,
|
||||
Pyreal = 0x0000003E,
|
||||
Silver = 0x0000003F,
|
||||
Steel = 0x00000040,
|
||||
Alabaster = 0x00000042,
|
||||
Granite = 0x00000043,
|
||||
Marble = 0x00000044,
|
||||
Obsidian = 0x00000045,
|
||||
Sandstone = 0x00000046,
|
||||
Serpentine = 0x00000047,
|
||||
Ebony = 0x00000049,
|
||||
Mahogany = 0x0000004A,
|
||||
Oak = 0x0000004B,
|
||||
Pine = 0x0000004C,
|
||||
Teak = 0x0000004D,
|
||||
}
|
||||
}
|
||||
33
Shared/Constants/QuadValueKey.cs
Normal file
33
Shared/Constants/QuadValueKey.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
// https://github.com/ACEmulator/ACE/blob/master/Source/ACE.Entity/Enum/Properties/PropertyInt64.cs
|
||||
public enum QuadValueKey
|
||||
{
|
||||
Undef = 0,
|
||||
[SendOnLogin]
|
||||
TotalExperience = 1,
|
||||
[SendOnLogin]
|
||||
AvailableExperience = 2,
|
||||
AugmentationCost = 3,
|
||||
ItemTotalXp = 4,
|
||||
ItemBaseXp = 5,
|
||||
[SendOnLogin]
|
||||
AvailableLuminance = 6,
|
||||
[SendOnLogin]
|
||||
MaximumLuminance = 7,
|
||||
InteractionReqs = 8,
|
||||
|
||||
|
||||
// ACE Specific
|
||||
/* custom */
|
||||
[ServerOnly]
|
||||
AllegianceXPCached = 9000,
|
||||
[ServerOnly]
|
||||
AllegianceXPGenerated = 9001,
|
||||
[ServerOnly]
|
||||
AllegianceXPReceived = 9002,
|
||||
[ServerOnly]
|
||||
VerifyXp = 9003
|
||||
}
|
||||
}
|
||||
11
Shared/Constants/SendOnLoginAttribute.cs
Normal file
11
Shared/Constants/SendOnLoginAttribute.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// These are properties that aren't saved to the shard.
|
||||
/// </summary>
|
||||
public class SendOnLoginAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
11
Shared/Constants/ServerOnlyAttribute.cs
Normal file
11
Shared/Constants/ServerOnlyAttribute.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// These are properties that aren't saved to the shard.
|
||||
/// </summary>
|
||||
public class ServerOnlyAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
67
Shared/Constants/Skill.cs
Normal file
67
Shared/Constants/Skill.cs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// note: even though these are unnumbered, order is very important. values of "none" or commented
|
||||
/// as retired or unused --ABSOLUTELY CANNOT-- be removed. Skills that are none, retired, or not
|
||||
/// implemented have been removed from the SkillHelper.ValidSkills hashset below.
|
||||
/// </summary>
|
||||
public enum Skill
|
||||
{
|
||||
None,
|
||||
Axe, /* Retired */
|
||||
Bow, /* Retired */
|
||||
Crossbow, /* Retired */
|
||||
Dagger, /* Retired */
|
||||
Mace, /* Retired */
|
||||
MeleeDefense,
|
||||
MissileDefense,
|
||||
Sling, /* Retired */
|
||||
Spear, /* Retired */
|
||||
Staff, /* Retired */
|
||||
Sword, /* Retired */
|
||||
ThrownWeapon, /* Retired */
|
||||
UnarmedCombat, /* Retired */
|
||||
ArcaneLore,
|
||||
MagicDefense,
|
||||
ManaConversion,
|
||||
Spellcraft, /* Unimplemented */
|
||||
ItemTinkering,
|
||||
AssessPerson,
|
||||
Deception,
|
||||
Healing,
|
||||
Jump,
|
||||
Lockpick,
|
||||
Run,
|
||||
Awareness, /* Unimplemented */
|
||||
ArmsAndArmorRepair, /* Unimplemented */
|
||||
AssessCreature,
|
||||
WeaponTinkering,
|
||||
ArmorTinkering,
|
||||
MagicItemTinkering,
|
||||
CreatureEnchantment,
|
||||
ItemEnchantment,
|
||||
LifeMagic,
|
||||
WarMagic,
|
||||
Leadership,
|
||||
Loyalty,
|
||||
Fletching,
|
||||
Alchemy,
|
||||
Cooking,
|
||||
Salvaging,
|
||||
TwoHandedCombat,
|
||||
Gearcraft, /* Retired */
|
||||
VoidMagic,
|
||||
HeavyWeapons,
|
||||
LightWeapons,
|
||||
FinesseWeapons,
|
||||
MissileWeapons,
|
||||
Shield,
|
||||
DualWield,
|
||||
Recklessness,
|
||||
SneakAttack,
|
||||
DirtyFighting,
|
||||
Challenge, /* Unimplemented */
|
||||
Summoning
|
||||
}
|
||||
}
|
||||
707
Shared/Constants/SpellCategory.cs
Normal file
707
Shared/Constants/SpellCategory.cs
Normal file
|
|
@ -0,0 +1,707 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
public enum SpellCategory
|
||||
{
|
||||
Undefined,
|
||||
Strength_Raising,
|
||||
Strength_Lowering,
|
||||
Endurance_Raising,
|
||||
Endurance_Lowering,
|
||||
Quickness_Raising,
|
||||
Quickness_Lowering,
|
||||
Coordination_Raising,
|
||||
Coordination_Lowering,
|
||||
Focus_Raising,
|
||||
Focus_Lowering,
|
||||
Self_Raising,
|
||||
Self_Lowering,
|
||||
Focus_Concentration,
|
||||
Focus_Disruption,
|
||||
Focus_Brilliance,
|
||||
Focus_Dullness,
|
||||
Axe_Raising,
|
||||
Axe_Lowering,
|
||||
Bow_Raising,
|
||||
Bow_Lowering,
|
||||
Crossbow_Raising,
|
||||
Crossbow_Lowering,
|
||||
Dagger_Raising,
|
||||
Dagger_Lowering,
|
||||
Mace_Raising,
|
||||
Mace_Lowering,
|
||||
Spear_Raising,
|
||||
Spear_Lowering,
|
||||
Staff_Raising,
|
||||
Staff_Lowering,
|
||||
Sword_Raising,
|
||||
Sword_Lowering,
|
||||
Thrown_Weapons_Raising,
|
||||
Thrown_Weapons_Lowering,
|
||||
Unarmed_Combat_Raising,
|
||||
Unarmed_Combat_Lowering,
|
||||
Melee_Defense_Raising,
|
||||
Melee_Defense_Lowering,
|
||||
Missile_Defense_Raising,
|
||||
Missile_Defense_Lowering,
|
||||
Magic_Defense_Raising,
|
||||
Magic_Defense_Lowering,
|
||||
Creature_Enchantment_Raising,
|
||||
Creature_Enchantment_Lowering,
|
||||
Item_Enchantment_Raising,
|
||||
Item_Enchantment_Lowering,
|
||||
Life_Magic_Raising,
|
||||
Life_Magic_Lowering,
|
||||
War_Magic_Raising,
|
||||
War_Magic_Lowering,
|
||||
Mana_Conversion_Raising,
|
||||
Mana_Conversion_Lowering,
|
||||
Arcane_Lore_Raising,
|
||||
Arcane_Lore_Lowering,
|
||||
Appraise_Armor_Raising,
|
||||
Appraise_Armor_Lowering,
|
||||
Appraise_Item_Raising,
|
||||
Appraise_Item_Lowering,
|
||||
Appraise_Magic_Item_Raising,
|
||||
Appraise_Magic_Item_Lowering,
|
||||
Appraise_Weapon_Raising,
|
||||
Appraise_Weapon_Lowering,
|
||||
Assess_Monster_Raising,
|
||||
Assess_Monster_Lowering,
|
||||
Deception_Raising,
|
||||
Deception_Lowering,
|
||||
Healing_Raising,
|
||||
Healing_Lowering,
|
||||
Jump_Raising,
|
||||
Jump_Lowering,
|
||||
Leadership_Raising,
|
||||
Leadership_Lowering,
|
||||
Lockpick_Raising,
|
||||
Lockpick_Lowering,
|
||||
Loyalty_Raising,
|
||||
Loyalty_Lowering,
|
||||
Run_Raising,
|
||||
Run_Lowering,
|
||||
Health_Raising,
|
||||
Health_Lowering,
|
||||
Stamina_Raising,
|
||||
Stamina_Lowering,
|
||||
Mana_Raising,
|
||||
Mana_Lowering,
|
||||
Mana_Remedy,
|
||||
Mana_Malediction,
|
||||
Health_Transfer_to_caster,
|
||||
Health_Transfer_from_caster,
|
||||
Stamina_Transfer_to_caster,
|
||||
Stamina_Transfer_from_caster,
|
||||
Mana_Transfer_to_caster,
|
||||
Mana_Transfer_from_caster,
|
||||
Health_Accelerating,
|
||||
Health_Decelerating,
|
||||
Stamina_Accelerating,
|
||||
Stamina_Decelerating,
|
||||
Mana_Accelerating,
|
||||
Mana_Decelerating,
|
||||
Vitae_Raising,
|
||||
Vitae_Lowering,
|
||||
Acid_Protection,
|
||||
Acid_Vulnerability,
|
||||
Bludgeon_Protection,
|
||||
Bludgeon_Vulnerability,
|
||||
Cold_Protection,
|
||||
Cold_Vulnerability,
|
||||
Electric_Protection,
|
||||
Electric_Vulnerability,
|
||||
Fire_Protection,
|
||||
Fire_Vulnerability,
|
||||
Pierce_Protection,
|
||||
Pierce_Vulnerability,
|
||||
Slash_Protection,
|
||||
Slash_Vulnerability,
|
||||
Armor_Raising,
|
||||
Armor_Lowering,
|
||||
Acid_Missile,
|
||||
Bludgeoning_Missile,
|
||||
Cold_Missile,
|
||||
Electric_Missile,
|
||||
Fire_Missile,
|
||||
Piercing_Missile,
|
||||
Slashing_Missile,
|
||||
Acid_Seeker,
|
||||
Bludgeoning_Seeker,
|
||||
Cold_Seeker,
|
||||
Electric_Seeker,
|
||||
Fire_Seeker,
|
||||
Piercing_Seeker,
|
||||
Slashing_Seeker,
|
||||
Acid_Burst,
|
||||
Bludgeoning_Burst,
|
||||
Cold_Burst,
|
||||
Electric_Burst,
|
||||
Fire_Burst,
|
||||
Piercing_Burst,
|
||||
Slashing_Burst,
|
||||
Acid_Blast,
|
||||
Bludgeoning_Blast,
|
||||
Cold_Blast,
|
||||
Electric_Blast,
|
||||
Fire_Blast,
|
||||
Piercing_Blast,
|
||||
Slashing_Blast,
|
||||
Acid_Scatter,
|
||||
Bludgeoning_Scatter,
|
||||
Cold_Scatter,
|
||||
Electric_Scatter,
|
||||
Fire_Scatter,
|
||||
Piercing_Scatter,
|
||||
Slashing_Scatter,
|
||||
Attack_Mod_Raising,
|
||||
Attack_Mod_Lowering,
|
||||
Damage_Raising,
|
||||
Damage_Lowering,
|
||||
Defense_Mod_Raising,
|
||||
Defense_Mod_Lowering,
|
||||
Weapon_Time_Raising,
|
||||
Weapon_Time_Lowering,
|
||||
Armor_Value_Raising,
|
||||
Armor_Value_Lowering,
|
||||
Acid_Resistance_Raising,
|
||||
Acid_Resistance_Lowering,
|
||||
Bludgeon_Resistance_Raising,
|
||||
Bludgeon_Resistance_Lowering,
|
||||
Cold_Resistance_Raising,
|
||||
Cold_Resistance_Lowering,
|
||||
Electric_Resistance_Raising,
|
||||
Electric_Resistance_Lowering,
|
||||
Fire_Resistance_Raising,
|
||||
Fire_Resistance_Lowering,
|
||||
Pierce_Resistance_Raising,
|
||||
Pierce_Resistance_Lowering,
|
||||
Slash_Resistance_Raising,
|
||||
Slash_Resistance_Lowering,
|
||||
Bludgeoning_Resistance_Raising,
|
||||
Bludgeoning_Resistance_Lowering,
|
||||
Slashing_Resistance_Raising,
|
||||
Slashing_Resistance_Lowering,
|
||||
Piercing_Resistance_Raising,
|
||||
Piercing_Resistance_Lowering,
|
||||
Electrical_Resistance_Raising,
|
||||
Electrical_Resistance_Lowering,
|
||||
Frost_Resistance_Raising,
|
||||
Frost_Resistance_Lowering,
|
||||
Flame_Resistance_Raising,
|
||||
Flame_Resistance_Lowering,
|
||||
Acidic_Resistance_Raising,
|
||||
Acidic_Resistance_Lowering,
|
||||
Armor_Level_Raising,
|
||||
Armor_Level_Lowering,
|
||||
Lockpick_Resistance_Raising,
|
||||
Lockpick_Resistance_Lowering,
|
||||
Appraisal_Resistance_Raising,
|
||||
Appraisal_Resistance_Lowering,
|
||||
Vision_Raising,
|
||||
Vision_Lowering,
|
||||
Transparency_Raising,
|
||||
Transparency_Lowering,
|
||||
Portal_Tie,
|
||||
Portal_Recall,
|
||||
Portal_Creation,
|
||||
Portal_Item_Creation,
|
||||
Vitae,
|
||||
Assess_Person_Raising,
|
||||
Assess_Person_Lowering,
|
||||
Acid_Volley,
|
||||
Bludgeoning_Volley,
|
||||
Frost_Volley,
|
||||
Lightning_Volley,
|
||||
Flame_Volley,
|
||||
Force_Volley,
|
||||
Blade_Volley,
|
||||
Portal_Sending,
|
||||
Lifestone_Sending,
|
||||
Cooking_Raising,
|
||||
Cooking_Lowering,
|
||||
Fletching_Raising,
|
||||
Fletching_Lowering,
|
||||
Alchemy_Lowering,
|
||||
Alchemy_Raising,
|
||||
Acid_Ring,
|
||||
Bludgeoning_Ring,
|
||||
Cold_Ring,
|
||||
Electric_Ring,
|
||||
Fire_Ring,
|
||||
Piercing_Ring,
|
||||
Slashing_Ring,
|
||||
Acid_Wall,
|
||||
Bludgeoning_Wall,
|
||||
Cold_Wall,
|
||||
Electric_Wall,
|
||||
Fire_Wall,
|
||||
Piercing_Wall,
|
||||
Slashing_Wall,
|
||||
Acid_Strike,
|
||||
Bludgeoning_Strike,
|
||||
Cold_Strike,
|
||||
Electric_Strike,
|
||||
Fire_Strike,
|
||||
Piercing_Strike,
|
||||
Slashing_Strike,
|
||||
Acid_Streak,
|
||||
Bludgeoning_Streak,
|
||||
Cold_Streak,
|
||||
Electric_Streak,
|
||||
Fire_Streak,
|
||||
Piercing_Streak,
|
||||
Slashing_Streak,
|
||||
Dispel,
|
||||
Creature_Mystic_Raising,
|
||||
Creature_Mystic_Lowering,
|
||||
Item_Mystic_Raising,
|
||||
Item_Mystic_Lowering,
|
||||
War_Mystic_Raising,
|
||||
War_Mystic_Lowering,
|
||||
Health_Restoring,
|
||||
Health_Depleting,
|
||||
Mana_Restoring,
|
||||
Mana_Depleting,
|
||||
Strength_Increase,
|
||||
Strength_Decrease,
|
||||
Endurance_Increase,
|
||||
Endurance_Decrease,
|
||||
Quickness_Increase,
|
||||
Quickness_Decrease,
|
||||
Coordination_Increase,
|
||||
Coordination_Decrease,
|
||||
Focus_Increase,
|
||||
Focus_Decrease,
|
||||
Self_Increase,
|
||||
Self_Decrease,
|
||||
GreatVitality_Raising,
|
||||
PoorVitality_Lowering,
|
||||
GreatVigor_Raising,
|
||||
PoorVigor_Lowering,
|
||||
GreaterIntellect_Raising,
|
||||
LessorIntellect_Lowering,
|
||||
LifeGiver_Raising,
|
||||
LifeTaker_Lowering,
|
||||
StaminaGiver_Raising,
|
||||
StaminaTaker_Lowering,
|
||||
ManaGiver_Raising,
|
||||
ManaTaker_Lowering,
|
||||
Acid_Ward_Protection,
|
||||
Acid_Ward_Vulnerability,
|
||||
Fire_Ward_Protection,
|
||||
Fire_Ward_Vulnerability,
|
||||
Cold_Ward_Protection,
|
||||
Cold_Ward_Vulnerability,
|
||||
Electric_Ward_Protection,
|
||||
Electric_Ward_Vulnerability,
|
||||
Leadership_Obedience_Raising,
|
||||
Leadership_Obedience_Lowering,
|
||||
Melee_Defense_Shelter_Raising,
|
||||
Melee_Defense_Shelter_Lowering,
|
||||
Missile_Defense_Shelter_Raising,
|
||||
Missile_Defense_Shelter_Lowering,
|
||||
Magic_Defense_Shelter_Raising,
|
||||
Magic_Defense_Shelter_Lowering,
|
||||
HuntersAcumen_Raising,
|
||||
HuntersAcumen_Lowering,
|
||||
StillWater_Raising,
|
||||
StillWater_Lowering,
|
||||
StrengthofEarth_Raising,
|
||||
StrengthofEarth_Lowering,
|
||||
Torrent_Raising,
|
||||
Torrent_Lowering,
|
||||
Growth_Raising,
|
||||
Growth_Lowering,
|
||||
CascadeAxe_Raising,
|
||||
CascadeAxe_Lowering,
|
||||
CascadeDagger_Raising,
|
||||
CascadeDagger_Lowering,
|
||||
CascadeMace_Raising,
|
||||
CascadeMace_Lowering,
|
||||
CascadeSpear_Raising,
|
||||
CascadeSpear_Lowering,
|
||||
CascadeStaff_Raising,
|
||||
CascadeStaff_Lowering,
|
||||
StoneCliffs_Raising,
|
||||
StoneCliffs_Lowering,
|
||||
MaxDamage_Raising,
|
||||
MaxDamage_Lowering,
|
||||
Bow_Damage_Raising,
|
||||
Bow_Damage_Lowering,
|
||||
Bow_Range_Raising,
|
||||
Bow_Range_Lowering,
|
||||
Extra_Defense_Mod_Raising,
|
||||
Extra_Defense_Mod_Lowering,
|
||||
Extra_Bow_Skill_Raising,
|
||||
Extra_Bow_Skill_Lowering,
|
||||
Extra_Alchemy_Skill_Raising,
|
||||
Extra_Alchemy_Skill_Lowering,
|
||||
Extra_Arcane_Lore_Skill_Raising,
|
||||
Extra_Arcane_Lore_Skill_Lowering,
|
||||
Extra_Appraise_Armor_Skill_Raising,
|
||||
Extra_Appraise_Armor_Skill_Lowering,
|
||||
Extra_Cooking_Skill_Raising,
|
||||
Extra_Cooking_Skill_Lowering,
|
||||
Extra_Crossbow_Skill_Raising,
|
||||
Extra_Crossbow_Skill_Lowering,
|
||||
Extra_Deception_Skill_Raising,
|
||||
Extra_Deception_Skill_Lowering,
|
||||
Extra_Loyalty_Skill_Raising,
|
||||
Extra_Loyalty_Skill_Lowering,
|
||||
Extra_Fletching_Skill_Raising,
|
||||
Extra_Fletching_Skill_Lowering,
|
||||
Extra_Healing_Skill_Raising,
|
||||
Extra_Healing_Skill_Lowering,
|
||||
Extra_Melee_Defense_Skill_Raising,
|
||||
Extra_Melee_Defense_Skill_Lowering,
|
||||
Extra_Appraise_Item_Skill_Raising,
|
||||
Extra_Appraise_Item_Skill_Lowering,
|
||||
Extra_Jumping_Skill_Raising,
|
||||
Extra_Jumping_Skill_Lowering,
|
||||
Extra_Life_Magic_Skill_Raising,
|
||||
Extra_Life_Magic_Skill_Lowering,
|
||||
Extra_Lockpick_Skill_Raising,
|
||||
Extra_Lockpick_Skill_Lowering,
|
||||
Extra_Appraise_Magic_Item_Skill_Raising,
|
||||
Extra_Appraise_Magic_Item_Skill_Lowering,
|
||||
Extra_Mana_Conversion_Skill_Raising,
|
||||
Extra_Mana_Conversion_Skill_Lowering,
|
||||
Extra_Assess_Creature_Skill_Raising,
|
||||
Extra_Assess_Creature_Skill_Lowering,
|
||||
Extra_Assess_Person_Skill_Raising,
|
||||
Extra_Assess_Person_Skill_Lowering,
|
||||
Extra_Run_Skill_Raising,
|
||||
Extra_Run_Skill_Lowering,
|
||||
Extra_Sword_Skill_Raising,
|
||||
Extra_Sword_Skill_Lowering,
|
||||
Extra_Thrown_Weapons_Skill_Raising,
|
||||
Extra_Thrown_Weapons_Skill_Lowering,
|
||||
Extra_Unarmed_Combat_Skill_Raising,
|
||||
Extra_Unarmed_Combat_Skill_Lowering,
|
||||
Extra_Appraise_Weapon_Skill_Raising,
|
||||
Extra_Appraise_Weapon_Skill_Lowering,
|
||||
Armor_Increase,
|
||||
Armor_Decrease,
|
||||
Extra_Acid_Resistance_Raising,
|
||||
Extra_Acid_Resistance_Lowering,
|
||||
Extra_Bludgeon_Resistance_Raising,
|
||||
Extra_Bludgeon_Resistance_Lowering,
|
||||
Extra_Fire_Resistance_Raising,
|
||||
Extra_Fire_Resistance_Lowering,
|
||||
Extra_Cold_Resistance_Raising,
|
||||
Extra_Cold_Resistance_Lowering,
|
||||
Extra_Attack_Mod_Raising,
|
||||
Extra_Attack_Mod_Lowering,
|
||||
Extra_Armor_Value_Raising,
|
||||
Extra_Armor_Value_Lowering,
|
||||
Extra_Pierce_Resistance_Raising,
|
||||
Extra_Pierce_Resistance_Lowering,
|
||||
Extra_Slash_Resistance_Raising,
|
||||
Extra_Slash_Resistance_Lowering,
|
||||
Extra_Electric_Resistance_Raising,
|
||||
Extra_Electric_Resistance_Lowering,
|
||||
Extra_Weapon_Time_Raising,
|
||||
Extra_Weapon_Time_Lowering,
|
||||
Bludgeon_Ward_Protection,
|
||||
Bludgeon_Ward_Vulnerability,
|
||||
Slash_Ward_Protection,
|
||||
Slash_Ward_Vulnerability,
|
||||
Pierce_Ward_Protection,
|
||||
Pierce_Ward_Vulnerability,
|
||||
Stamina_Restoring,
|
||||
Stamina_Depleting,
|
||||
Fireworks,
|
||||
Health_Divide,
|
||||
Stamina_Divide,
|
||||
Mana_Divide,
|
||||
Coordination_Increase2,
|
||||
Strength_Increase2,
|
||||
Focus_Increase2,
|
||||
Endurance_Increase2,
|
||||
Self_Increase2,
|
||||
Melee_Defense_Multiply,
|
||||
Missile_Defense_Multiply,
|
||||
Magic_Defense_Multiply,
|
||||
Attributes_Decrease,
|
||||
LifeGiver_Raising2,
|
||||
Item_Enchantment_Raising2,
|
||||
Skills_Decrease,
|
||||
Extra_Mana_Conversion_Bonus,
|
||||
War_Mystic_Raising2,
|
||||
War_Mystic_Lowering2,
|
||||
Magic_Defense_Shelter_Raising2,
|
||||
Extra_Life_Magic_Skill_Raising2,
|
||||
Creature_Mystic_Raising2,
|
||||
Item_Mystic_Raising2,
|
||||
Mana_Raising2,
|
||||
Self_Raising2,
|
||||
CreatureEnchantment_Raising2,
|
||||
Salvaging_Raising,
|
||||
Extra_Salvaging_Raising,
|
||||
Extra_Salvaging_Raising2,
|
||||
CascadeAxe_Raising2,
|
||||
Extra_Bow_Skill_Raising2,
|
||||
Extra_Thrown_Weapons_Skill_Raising2,
|
||||
Extra_Crossbow_Skill_Raising2,
|
||||
CascadeDagger_Raising2,
|
||||
CascadeMace_Raising2,
|
||||
Extra_Unarmed_Combat_Skill_Raising2,
|
||||
CascadeSpear_Raising2,
|
||||
CascadeStaff_Raising2,
|
||||
Extra_Sword_Skill_Raising2,
|
||||
Acid_Protection_Rare,
|
||||
Acid_Resistance_Raising_Rare,
|
||||
Alchemy_Raising_Rare,
|
||||
Appraisal_Resistance_Lowering_Rare,
|
||||
Appraise_Armor_Raising_Rare,
|
||||
Appraise_Item_Raising_Rare,
|
||||
Appraise_Magic_Item_Raising_Rare,
|
||||
Appraise_Weapon_Raising_Rare,
|
||||
Arcane_Lore_Raising_Rare,
|
||||
Armor_Raising_Rare,
|
||||
Armor_Value_Raising_Rare,
|
||||
Assess_Monster_Raising_Rare,
|
||||
Assess_Person_Raising_Rare,
|
||||
Attack_Mod_Raising_Rare,
|
||||
Axe_Raising_Rare,
|
||||
Bludgeon_Protection_Rare,
|
||||
Bludgeon_Resistance_Raising_Rare,
|
||||
Bow_Raising_Rare,
|
||||
Cold_Protection_Rare,
|
||||
Cold_Resistance_Raising_Rare,
|
||||
Cooking_Raising_Rare,
|
||||
Coordination_Raising_Rare,
|
||||
Creature_Enchantment_Raising_Rare,
|
||||
Crossbow_Raising_Rare,
|
||||
Dagger_Raising_Rare,
|
||||
Damage_Raising_Rare,
|
||||
Deception_Raising_Rare,
|
||||
Defense_Mod_Raising_Rare,
|
||||
Electric_Protection_Rare,
|
||||
Electric_Resistance_Raising_Rare,
|
||||
Endurance_Raising_Rare,
|
||||
Fire_Protection_Rare,
|
||||
Fire_Resistance_Raising_Rare,
|
||||
Fletching_Raising_Rare,
|
||||
Focus_Raising_Rare,
|
||||
Healing_Raising_Rare,
|
||||
Health_Accelerating_Rare,
|
||||
Item_Enchantment_Raising_Rare,
|
||||
Jump_Raising_Rare,
|
||||
Leadership_Raising_Rare,
|
||||
Life_Magic_Raising_Rare,
|
||||
Lockpick_Raising_Rare,
|
||||
Loyalty_Raising_Rare,
|
||||
Mace_Raising_Rare,
|
||||
Magic_Defense_Raising_Rare,
|
||||
Mana_Accelerating_Rare,
|
||||
Mana_Conversion_Raising_Rare,
|
||||
Melee_Defense_Raising_Rare,
|
||||
Missile_Defense_Raising_Rare,
|
||||
Pierce_Protection_Rare,
|
||||
Pierce_Resistance_Raising_Rare,
|
||||
Quickness_Raising_Rare,
|
||||
Run_Raising_Rare,
|
||||
Self_Raising_Rare,
|
||||
Slash_Protection_Rare,
|
||||
Slash_Resistance_Raising_Rare,
|
||||
Spear_Raising_Rare,
|
||||
Staff_Raising_Rare,
|
||||
Stamina_Accelerating_Rare,
|
||||
Strength_Raising_Rare,
|
||||
Sword_Raising_Rare,
|
||||
Thrown_Weapons_Raising_Rare,
|
||||
Unarmed_Combat_Raising_Rare,
|
||||
War_Magic_Raising_Rare,
|
||||
Weapon_Time_Raising_Rare,
|
||||
Armor_Increase_Inky_Armor,
|
||||
Magic_Defense_Shelter_Raising_Fiun,
|
||||
Extra_Run_Skill_Raising_Fiun,
|
||||
Extra_Mana_Conversion_Skill_Raising_Fiun,
|
||||
Attributes_Increase_Cantrip1,
|
||||
Extra_Melee_Defense_Skill_Raising2,
|
||||
ACTDPurchaseRewardSpell,
|
||||
ACTDPurchaseRewardSpellHealth,
|
||||
SaltAsh_Attack_Mod_Raising,
|
||||
Quickness_Increase2,
|
||||
Extra_Alchemy_Skill_Raising2,
|
||||
Extra_Cooking_Skill_Raising2,
|
||||
Extra_Fletching_Skill_Raising2,
|
||||
Extra_Lockpick_Skill_Raising2,
|
||||
MucorManaWell,
|
||||
Stamina_Restoring2,
|
||||
Allegiance_Raising,
|
||||
Health_DoT,
|
||||
Health_DoT_Secondary,
|
||||
Health_DoT_Tertiary,
|
||||
Health_HoT,
|
||||
Health_HoT_Secondary,
|
||||
Health_HoT_Tertiary,
|
||||
Health_Divide_Secondary,
|
||||
Health_Divide_Tertiary,
|
||||
SetSword_Raising,
|
||||
SetAxe_Raising,
|
||||
SetDagger_Raising,
|
||||
SetMace_Raising,
|
||||
SetSpear_Raising,
|
||||
SetStaff_Raising,
|
||||
SetUnarmed_Raising,
|
||||
SetBow_Raising,
|
||||
SetCrossbow_Raising,
|
||||
SetThrown_Raising,
|
||||
SetItemEnchantment_Raising,
|
||||
SetCreatureEnchantment_Raising,
|
||||
SetWarMagic_Raising,
|
||||
SetLifeMagic_Raising,
|
||||
SetMeleeDefense_Raising,
|
||||
SetMissileDefense_Raising,
|
||||
SetMagicDefense_Raising,
|
||||
SetStamina_Accelerating,
|
||||
SetCooking_Raising,
|
||||
SetFletching_Raising,
|
||||
SetLockpick_Raising,
|
||||
SetAlchemy_Raising,
|
||||
SetSalvaging_Raising,
|
||||
SetArmorExpertise_Raising,
|
||||
SetWeaponExpertise_Raising,
|
||||
SetItemTinkering_Raising,
|
||||
SetMagicItemExpertise_Raising,
|
||||
SetLoyalty_Raising,
|
||||
SetStrength_Raising,
|
||||
SetEndurance_Raising,
|
||||
SetCoordination_Raising,
|
||||
SetQuickness_Raising,
|
||||
SetFocus_Raising,
|
||||
SetWillpower_Raising,
|
||||
SetHealth_Raising,
|
||||
SetStamina_Raising,
|
||||
SetMana_Raising,
|
||||
SetSprint_Raising,
|
||||
SetJumping_Raising,
|
||||
SetSlashResistance_Raising,
|
||||
SetBludgeonResistance_Raising,
|
||||
SetPierceResistance_Raising,
|
||||
SetFlameResistance_Raising,
|
||||
SetAcidResistance_Raising,
|
||||
SetFrostResistance_Raising,
|
||||
SetLightningResistance_Raising,
|
||||
Crafting_LockPick_Raising,
|
||||
Crafting_Fletching_Raising,
|
||||
Crafting_Cooking_Raising,
|
||||
Crafting_Alchemy_Raising,
|
||||
Crafting_ArmorTinkering_Raising,
|
||||
Crafting_WeaponTinkering_Raising,
|
||||
Crafting_MagicTinkering_Raising,
|
||||
Crafting_ItemTinkering_Raising,
|
||||
SkillPercent_Alchemy_Raising,
|
||||
TwoHanded_Raising,
|
||||
TwoHanded_Lowering,
|
||||
Extra_TwoHanded_Skill_Raising,
|
||||
Extra_TwoHanded_Skill_Lowering,
|
||||
Extra_TwoHanded_Skill_Raising2,
|
||||
TwoHanded_Raising_Rare,
|
||||
SetTwoHanded_Raising,
|
||||
GearCraft_Raising,
|
||||
GearCraft_Lowering,
|
||||
Extra_GearCraft_Skill_Raising,
|
||||
Extra_GearCraft_Skill_Lowering,
|
||||
Extra_GearCraft_Skill_Raising2,
|
||||
GearCraft_Raising_Rare,
|
||||
SetGearCraft_Raising,
|
||||
LoyaltyMana_Raising,
|
||||
LoyaltyStamina_Raising,
|
||||
LeadershipHealth_Raising,
|
||||
TrinketDamage_Raising,
|
||||
TrinketDamage_Lowering,
|
||||
TrinketHealth_Raising,
|
||||
TrinketStamina_Raising,
|
||||
TrinketMana_Raising,
|
||||
TrinketXP_Raising,
|
||||
DeceptionArcaneLore_Raising,
|
||||
HealOverTime_Raising,
|
||||
DamageOverTime_Raising,
|
||||
HealingResistRating_Raising,
|
||||
AetheriaDamageRating_Raising,
|
||||
AetheriaDamageReduction_Raising,
|
||||
SKIPPED,
|
||||
AetheriaHealth_Raising,
|
||||
AetheriaStamina_Raising,
|
||||
AetheriaMana_Raising,
|
||||
AetheriaCriticalDamage_Raising,
|
||||
AetheriaHealingAmplification_Raising,
|
||||
AetheriaProcDamageRating_Raising,
|
||||
AetheriaProcDamageReduction_Raising,
|
||||
AetheriaProcHealthOverTime_Raising,
|
||||
AetheriaProcDamageOverTime_Raising,
|
||||
AetheriaProcHealingReduction_Raising,
|
||||
RareDamageRating_Raising,
|
||||
RareDamageReductionRating_Raising,
|
||||
AetheriaEndurance_Raising,
|
||||
NetherDamageOverTime_Raising,
|
||||
NetherDamageOverTime_Raising2,
|
||||
NetherDamageOverTime_Raising3,
|
||||
Nether_Streak,
|
||||
Nether_Missile,
|
||||
Nether_Ring,
|
||||
NetherDamageRating_Lowering,
|
||||
NetherDamageHealingReduction_Raising,
|
||||
Void_Magic_Lowering,
|
||||
Void_Magic_Raising,
|
||||
Void_Mystic_Raising,
|
||||
SetVoidMagic_Raising,
|
||||
Void_Magic_Raising_Rare,
|
||||
Void_Mystic_Raising2,
|
||||
LuminanceDamageRating_Raising,
|
||||
LuminanceDamageReduction_Raising,
|
||||
LuminanceHealth_Raising,
|
||||
AetheriaCriticalReduction_Raising,
|
||||
Extra_Missile_Defense_Skill_Raising,
|
||||
Extra_Missile_Defense_Skill_Lowering,
|
||||
Extra_Missile_Defense_Skill_Raising2,
|
||||
AetheriaHealthResistance_Raising,
|
||||
AetheriaDotResistance_Raising,
|
||||
Cloak_Skill_Raising,
|
||||
Cloak_All_Skill_Raising,
|
||||
Cloak_Magic_Defense_Lowering,
|
||||
Cloak_Melee_Defense_Lowering,
|
||||
Cloak_Missile_Defense_Lowering,
|
||||
DirtyFighting_Lowering,
|
||||
DirtyFighting_Raising,
|
||||
Extra_DirtyFighting_Raising,
|
||||
DualWield_Lowering,
|
||||
DualWield_Raising,
|
||||
Extra_DualWield_Raising,
|
||||
Recklessness_Lowering,
|
||||
Recklessness_Raising,
|
||||
Extra_Recklessness_Raising,
|
||||
Shield_Lowering,
|
||||
Shield_Raising,
|
||||
Extra_Shield_Raising,
|
||||
SneakAttack_Lowering,
|
||||
SneakAttack_Raising,
|
||||
Extra_SneakAttack_Raising,
|
||||
Rare_DirtyFighting_Raising,
|
||||
Rare_DualWield_Raising,
|
||||
Rare_Recklessness_Raising,
|
||||
Rare_Shield_Raising,
|
||||
Rare_SneakAttack_Raising,
|
||||
DF_Attack_Skill_Debuff,
|
||||
DF_Bleed_Damage,
|
||||
DF_Defense_Skill_Debuff,
|
||||
DF_Healing_Debuff,
|
||||
SetDirtyFighting_Raising,
|
||||
SetDualWield_Raising,
|
||||
SetRecklessness_Raising,
|
||||
SetShield_Raising,
|
||||
SetSneakAttack_Raising,
|
||||
LifeGiver_Mhoire,
|
||||
RareDamageRating_Raising2,
|
||||
Spell_Damage_Raising,
|
||||
Summoning_Raising,
|
||||
Summoning_Lowering,
|
||||
Extra_Summoning_Skill_Raising,
|
||||
SetSummoning_Raising
|
||||
}
|
||||
}
|
||||
106
Shared/Constants/StringValueKey.cs
Normal file
106
Shared/Constants/StringValueKey.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
// https://github.com/ACEmulator/ACE/blob/master/Source/ACE.Entity/Enum/Properties/PropertyString.cs
|
||||
public enum StringValueKey
|
||||
{
|
||||
// properties marked as ServerOnly are properties we never saw in PCAPs, from here:
|
||||
// http://ac.yotesfan.com/ace_object/not_used_enums.php
|
||||
// source: @OptimShi
|
||||
// description attributes are used by the weenie editor for a cleaner display name
|
||||
Undef = 0,
|
||||
[SendOnLogin]
|
||||
Name = 1,
|
||||
/// <summary>
|
||||
/// default "Adventurer"
|
||||
/// </summary>
|
||||
Title = 2,
|
||||
Sex = 3,
|
||||
HeritageGroup = 4,
|
||||
Template = 5,
|
||||
AttackersName = 6,
|
||||
Inscription = 7,
|
||||
[Description("Scribe Name")]
|
||||
ScribeName = 8,
|
||||
VendorsName = 9,
|
||||
Fellowship = 10,
|
||||
MonarchsName = 11,
|
||||
[ServerOnly]
|
||||
LockCode = 12,
|
||||
[ServerOnly]
|
||||
KeyCode = 13,
|
||||
Use = 14,
|
||||
ShortDesc = 15,
|
||||
LongDesc = 16,
|
||||
ActivationTalk = 17,
|
||||
[ServerOnly]
|
||||
UseMessage = 18,
|
||||
ItemHeritageGroupRestriction = 19,
|
||||
PluralName = 20,
|
||||
MonarchsTitle = 21,
|
||||
ActivationFailure = 22,
|
||||
ScribeAccount = 23,
|
||||
TownName = 24,
|
||||
CraftsmanName = 25,
|
||||
UsePkServerError = 26,
|
||||
ScoreCachedText = 27,
|
||||
ScoreDefaultEntryFormat = 28,
|
||||
ScoreFirstEntryFormat = 29,
|
||||
ScoreLastEntryFormat = 30,
|
||||
ScoreOnlyEntryFormat = 31,
|
||||
ScoreNoEntry = 32,
|
||||
[ServerOnly]
|
||||
Quest = 33,
|
||||
GeneratorEvent = 34,
|
||||
PatronsTitle = 35,
|
||||
HouseOwnerName = 36,
|
||||
QuestRestriction = 37,
|
||||
AppraisalPortalDestination = 38,
|
||||
TinkerName = 39,
|
||||
ImbuerName = 40,
|
||||
HouseOwnerAccount = 41,
|
||||
DisplayName = 42,
|
||||
DateOfBirth = 43,
|
||||
ThirdPartyApi = 44,
|
||||
KillQuest = 45,
|
||||
Afk = 46,
|
||||
AllegianceName = 47,
|
||||
AugmentationAddQuest = 48,
|
||||
KillQuest2 = 49,
|
||||
KillQuest3 = 50,
|
||||
UseSendsSignal = 51,
|
||||
|
||||
[Description("Gear Plating Name")]
|
||||
GearPlatingName = 52,
|
||||
|
||||
|
||||
// ACE Specific
|
||||
[ServerOnly]
|
||||
PCAPRecordedCurrentMotionState = 8006,
|
||||
[ServerOnly]
|
||||
PCAPRecordedServerName = 8031,
|
||||
[ServerOnly]
|
||||
PCAPRecordedCharacterName = 8032,
|
||||
|
||||
/* custom */
|
||||
[ServerOnly]
|
||||
AllegianceMotd = 9001,
|
||||
[ServerOnly]
|
||||
AllegianceMotdSetBy = 9002,
|
||||
[ServerOnly]
|
||||
AllegianceSpeakerTitle = 9003,
|
||||
[ServerOnly]
|
||||
AllegianceSeneschalTitle = 9004,
|
||||
[ServerOnly]
|
||||
AllegianceCastellanTitle = 9005,
|
||||
[ServerOnly]
|
||||
GodState = 9006,
|
||||
[ServerOnly]
|
||||
TinkerLog = 9007,
|
||||
|
||||
|
||||
// Decal Specific
|
||||
SecondaryName_Decal = 184549376,
|
||||
}
|
||||
}
|
||||
79
Shared/Constants/WeenieType.cs
Normal file
79
Shared/Constants/WeenieType.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
public enum WeenieType : uint
|
||||
{
|
||||
Undef,
|
||||
Generic,
|
||||
Clothing,
|
||||
MissileLauncher,
|
||||
Missile,
|
||||
Ammunition,
|
||||
MeleeWeapon,
|
||||
Portal,
|
||||
Book,
|
||||
Coin,
|
||||
Creature,
|
||||
Admin,
|
||||
Vendor,
|
||||
HotSpot,
|
||||
Corpse,
|
||||
Cow,
|
||||
AI,
|
||||
Machine,
|
||||
Food,
|
||||
Door,
|
||||
Chest,
|
||||
Container,
|
||||
Key,
|
||||
Lockpick,
|
||||
PressurePlate,
|
||||
LifeStone,
|
||||
Switch,
|
||||
PKModifier,
|
||||
Healer,
|
||||
LightSource,
|
||||
Allegiance,
|
||||
UNKNOWN__GUESSEDNAME32, // NOTE: Missing 1
|
||||
SpellComponent,
|
||||
ProjectileSpell,
|
||||
Scroll,
|
||||
Caster,
|
||||
Channel,
|
||||
ManaStone,
|
||||
Gem,
|
||||
AdvocateFane,
|
||||
AdvocateItem,
|
||||
Sentinel,
|
||||
GSpellEconomy,
|
||||
LSpellEconomy,
|
||||
CraftTool,
|
||||
LScoreKeeper,
|
||||
GScoreKeeper,
|
||||
GScoreGatherer,
|
||||
ScoreBook,
|
||||
EventCoordinator,
|
||||
Entity,
|
||||
Stackable,
|
||||
HUD,
|
||||
House,
|
||||
Deed,
|
||||
SlumLord,
|
||||
Hook,
|
||||
Storage,
|
||||
BootSpot,
|
||||
HousePortal,
|
||||
Game,
|
||||
GamePiece,
|
||||
SkillAlterationDevice,
|
||||
AttributeTransferDevice,
|
||||
Hooker,
|
||||
AllegianceBindstone,
|
||||
InGameStatKeeper,
|
||||
AugmentationDevice,
|
||||
SocialManager,
|
||||
Pet,
|
||||
PetDevice,
|
||||
CombatPet
|
||||
}
|
||||
}
|
||||
20
Shared/Constants/WieldRequirement.cs
Normal file
20
Shared/Constants/WieldRequirement.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
namespace Mag.Shared.Constants
|
||||
{
|
||||
public enum WieldRequirement
|
||||
{
|
||||
Invalid,
|
||||
Skill,
|
||||
RawSkill,
|
||||
Attrib,
|
||||
RawAttrib,
|
||||
SecondaryAttrib,
|
||||
RawSecondaryAttrib,
|
||||
Level,
|
||||
Training,
|
||||
IntStat,
|
||||
BoolStat,
|
||||
CreatureType,
|
||||
HeritageType
|
||||
}
|
||||
}
|
||||
139
Shared/Debug.cs
Normal file
139
Shared/Debug.cs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using Decal.Adapter;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
static class Debug
|
||||
{
|
||||
static string _debugLogPath;
|
||||
static string _errorLogPath;
|
||||
|
||||
static string _pluginName;
|
||||
|
||||
public static void Init(string debugLogPath, string errorLogPath, string pluginName)
|
||||
{
|
||||
_debugLogPath = debugLogPath;
|
||||
_errorLogPath = errorLogPath;
|
||||
|
||||
_pluginName = pluginName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will write to the debug.txt
|
||||
/// </summary>
|
||||
public static void LogDebug(string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (String.IsNullOrEmpty(_debugLogPath))
|
||||
return;
|
||||
|
||||
FileInfo fileInfo = new FileInfo(_debugLogPath);
|
||||
|
||||
// Limit the file to 1MB
|
||||
bool append = !(fileInfo.Exists && fileInfo.Length > 1048576);
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(fileInfo.FullName, append))
|
||||
{
|
||||
writer.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "," + message);
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Eat the exception, yumm.
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will only write the exception to the errors.txt file if DebugEnabled is true.
|
||||
/// </summary>
|
||||
public static void LogException(Exception ex, string note = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (!Settings.SettingsManager.Misc.DebuggingEnabled.Value)
|
||||
// return;
|
||||
|
||||
if (note != null)
|
||||
MyClasses.VCS_Connector.SendChatTextCategorized("Errors", "<{" + _pluginName + "}>: " + "Exception caught: " + ex.Message + Environment.NewLine + ex.Source + Environment.NewLine + ex.StackTrace + Environment.NewLine + "Note: " + note, 5);
|
||||
else
|
||||
MyClasses.VCS_Connector.SendChatTextCategorized("Errors", "<{" + _pluginName + "}>: " + "Exception caught: " + ex.Message + Environment.NewLine + ex.Source + Environment.NewLine + ex.StackTrace, 5);
|
||||
|
||||
if (String.IsNullOrEmpty(_errorLogPath))
|
||||
return;
|
||||
|
||||
FileInfo fileInfo = new FileInfo(_errorLogPath);
|
||||
|
||||
// Limit the file to 1MB
|
||||
bool append = !(fileInfo.Exists && fileInfo.Length > 1048576);
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(fileInfo.FullName, append))
|
||||
{
|
||||
writer.WriteLine("============================================================================");
|
||||
|
||||
writer.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture));
|
||||
writer.WriteLine(ex);
|
||||
|
||||
if (note != null)
|
||||
writer.WriteLine("Note: " + note);
|
||||
|
||||
writer.WriteLine("============================================================================");
|
||||
writer.WriteLine("");
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Eat the exception, yumm.
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogText(string text)
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (!Settings.SettingsManager.Misc.DebuggingEnabled.Value)
|
||||
// return;
|
||||
|
||||
MyClasses.VCS_Connector.SendChatTextCategorized("CommandLine", "<{" + _pluginName + "}>: " + "Log Text: " + text, 5);
|
||||
|
||||
if (String.IsNullOrEmpty(_errorLogPath))
|
||||
return;
|
||||
|
||||
FileInfo fileInfo = new FileInfo(_errorLogPath);
|
||||
|
||||
// Limit the file to 1MB
|
||||
bool append = !(fileInfo.Exists && fileInfo.Length > 1048576);
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(fileInfo.FullName, append))
|
||||
{
|
||||
writer.WriteLine(DateTime.Now + ": " + text);
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { LogException(ex); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will only write the message to the chat if DebugEnabled is true.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="color"></param>
|
||||
/// <param name="target"></param>
|
||||
public static void WriteToChat(string message, int color = 5, int target = 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (!Settings.SettingsManager.Misc.DebuggingEnabled.Value)
|
||||
// return;
|
||||
|
||||
MyClasses.VCS_Connector.SendChatTextCategorized("CommandLine", "<{" + _pluginName + "}>: " + message, color, target);
|
||||
}
|
||||
catch (Exception ex) { LogException(ex); }
|
||||
}
|
||||
}
|
||||
}
|
||||
178
Shared/DecalProxy.cs
Normal file
178
Shared/DecalProxy.cs
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
//File: DecalProxy.cs
|
||||
//
|
||||
//Description: Contains reflection-based calls of newer Decal methods, so that
|
||||
// they can be easily invoked only if the currently running version contains
|
||||
// the desired feature.
|
||||
//
|
||||
//
|
||||
//This file is Copyright (c) 2013 VirindiPlugins
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//Virindi: yes, or you could just directly resize the window
|
||||
//Virindi: note...
|
||||
//Virindi: right now you have to call move after you call resize
|
||||
//Virindi: so right now what you have to do if you use that resize is grab the location, resize, then move back to the original location
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
using System.Drawing;
|
||||
|
||||
using Decal.Adapter;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
internal static class DecalProxy
|
||||
{
|
||||
public enum UIElementType : int
|
||||
{
|
||||
Smartbox = 0x1000049A,
|
||||
Chat = 0x10000601,
|
||||
FloatChat1 = 0x10000505,
|
||||
FloatChat2 = 0x1000050E,
|
||||
FloatChat3 = 0x1000050F,
|
||||
FloatChat4 = 0x10000510,
|
||||
Examination = 0x100005F7,
|
||||
Vitals = 0x100005FA,
|
||||
EnvPack = 0x100005FD,
|
||||
Panels = 0x100005FF,
|
||||
TBar = 0x10000603,
|
||||
Indicators = 0x10000611,
|
||||
ProgressBar = 0x10000613,
|
||||
Combat = 0x100006B5,
|
||||
Radar = 0x100006D2,
|
||||
}
|
||||
|
||||
|
||||
static Version iCachedDecalVersion = null;
|
||||
static Assembly iCachedDecalAssembly = null;
|
||||
public static bool TestDecalVersion(Version v)
|
||||
{
|
||||
if (iCachedDecalVersion != null) return iCachedDecalVersion >= v;
|
||||
|
||||
System.Reflection.Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
foreach (System.Reflection.Assembly a in asms)
|
||||
{
|
||||
AssemblyName nmm = a.GetName();
|
||||
if (nmm.Name == "Decal.Adapter")
|
||||
{
|
||||
iCachedDecalVersion = nmm.Version;
|
||||
iCachedDecalAssembly = a;
|
||||
return (nmm.Version >= v);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Hooks_UIElementMove(Decal.Adapter.Wrappers.HooksWrapper hooks, UIElementType e, int x, int y)
|
||||
{
|
||||
//This will load the cached assembly. We don't actually care what the version is
|
||||
//since we just check below if the required members are present.
|
||||
TestDecalVersion(new Version());
|
||||
|
||||
int ee = (int)e;
|
||||
|
||||
Type DecalType_UIElementType = iCachedDecalAssembly.GetType("Decal.Adapter.Wrappers.UIElementType");
|
||||
if (DecalType_UIElementType == null) return;
|
||||
object e_decal = Enum.ToObject(DecalType_UIElementType, ee);
|
||||
|
||||
Type DecalType_HooksWrapper = iCachedDecalAssembly.GetType("Decal.Adapter.Wrappers.HooksWrapper");
|
||||
if (DecalType_HooksWrapper == null) return;
|
||||
MethodInfo call = DecalType_HooksWrapper.GetMethod("UIElementMove", new Type[] { DecalType_UIElementType, typeof(int), typeof(int) });
|
||||
if (call == null) return;
|
||||
|
||||
call.Invoke(hooks, new object[] { e_decal, x, y });
|
||||
}
|
||||
|
||||
public static void Hooks_UIElementResize(Decal.Adapter.Wrappers.HooksWrapper hooks, UIElementType e, int width, int height)
|
||||
{
|
||||
//This will load the cached assembly. We don't actually care what the version is
|
||||
//since we just check below if the required members are present.
|
||||
TestDecalVersion(new Version());
|
||||
|
||||
int ee = (int)e;
|
||||
|
||||
Type DecalType_UIElementType = iCachedDecalAssembly.GetType("Decal.Adapter.Wrappers.UIElementType");
|
||||
if (DecalType_UIElementType == null) return;
|
||||
object e_decal = Enum.ToObject(DecalType_UIElementType, ee);
|
||||
|
||||
Type DecalType_HooksWrapper = iCachedDecalAssembly.GetType("Decal.Adapter.Wrappers.HooksWrapper");
|
||||
if (DecalType_HooksWrapper == null) return;
|
||||
MethodInfo call = DecalType_HooksWrapper.GetMethod("UIElementResize", new Type[] { DecalType_UIElementType, typeof(int), typeof(int) });
|
||||
if (call == null) return;
|
||||
|
||||
call.Invoke(hooks, new object[] { e_decal, width, height });
|
||||
}
|
||||
|
||||
public static Rectangle Hooks_UIElementRegion(Decal.Adapter.Wrappers.HooksWrapper hooks, UIElementType e)
|
||||
{
|
||||
//This will load the cached assembly. We don't actually care what the version is
|
||||
//since we just check below if the required members are present.
|
||||
TestDecalVersion(new Version());
|
||||
|
||||
int ee = (int)e;
|
||||
|
||||
Type DecalType_UIElementType = iCachedDecalAssembly.GetType("Decal.Adapter.Wrappers.UIElementType");
|
||||
if (DecalType_UIElementType == null) return Rectangle.Empty;
|
||||
object e_decal = Enum.ToObject(DecalType_UIElementType, ee);
|
||||
|
||||
Type DecalType_HooksWrapper = iCachedDecalAssembly.GetType("Decal.Adapter.Wrappers.HooksWrapper");
|
||||
if (DecalType_HooksWrapper == null) return Rectangle.Empty;
|
||||
MethodInfo call = DecalType_HooksWrapper.GetMethod("UIElementRegion", new Type[] { DecalType_UIElementType });
|
||||
if (call == null) return Rectangle.Empty;
|
||||
|
||||
return (Rectangle)call.Invoke(hooks, new object[] { e_decal });
|
||||
}
|
||||
|
||||
|
||||
[DllImport("Decal.dll")]
|
||||
static extern int DispatchOnChatCommand(ref IntPtr str, [MarshalAs(UnmanagedType.U4)] int target);
|
||||
|
||||
static bool Decal_DispatchOnChatCommand(string cmd)
|
||||
{
|
||||
IntPtr bstr = Marshal.StringToBSTR(cmd);
|
||||
|
||||
try
|
||||
{
|
||||
bool eaten = (DispatchOnChatCommand(ref bstr, 1) & 0x1) > 0;
|
||||
|
||||
return eaten;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeBSTR(bstr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will first attempt to send the messages to all plugins. If no plugins set e.Eat to true on the message, it will then simply call InvokeChatParser.
|
||||
/// </summary>
|
||||
/// <param name="cmd"></param>
|
||||
public static void DispatchChatToBoxWithPluginIntercept(string cmd)
|
||||
{
|
||||
if (!Decal_DispatchOnChatCommand(cmd))
|
||||
CoreManager.Current.Actions.InvokeChatParser(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
355
Shared/ItemInfo.cs
Normal file
355
Shared/ItemInfo.cs
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Mag.Shared.Constants;
|
||||
using Mag.Shared.Spells;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiate this object with the item you want info for.
|
||||
/// ToString() this object for the info.
|
||||
/// </summary>
|
||||
public class ItemInfo
|
||||
{
|
||||
private readonly MyWorldObject mwo;
|
||||
|
||||
public ItemInfo(MyWorldObject myWorldObject)
|
||||
{
|
||||
mwo = myWorldObject;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ToString(true, true);
|
||||
}
|
||||
|
||||
public string ToString(bool showBuffedValues, bool showValueAndBurden)
|
||||
{
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
|
||||
if (mwo.Values(IntValueKey.MaterialType) > 0)
|
||||
{
|
||||
if (Dictionaries.MaterialInfo.ContainsKey(mwo.Values(IntValueKey.MaterialType)))
|
||||
sb.Append(Dictionaries.MaterialInfo[mwo.Values(IntValueKey.MaterialType)] + " ");
|
||||
else
|
||||
sb.Append("unknown material " + mwo.Values(IntValueKey.MaterialType) + " ");
|
||||
}
|
||||
|
||||
sb.Append(mwo.Name);
|
||||
|
||||
if (mwo.Values((IntValueKey)353) > 0)
|
||||
{
|
||||
if (Dictionaries.MasteryInfo.ContainsKey(mwo.Values((IntValueKey)353)))
|
||||
sb.Append(" (" + Dictionaries.MasteryInfo[mwo.Values((IntValueKey)353)] + ")");
|
||||
else
|
||||
sb.Append(" (Unknown mastery " + mwo.Values((IntValueKey)353) + ")");
|
||||
}
|
||||
|
||||
int set = mwo.Values((IntValueKey)265, 0);
|
||||
if (set != 0)
|
||||
{
|
||||
sb.Append(", ");
|
||||
if (Dictionaries.AttributeSetInfo.ContainsKey(set))
|
||||
sb.Append(Dictionaries.AttributeSetInfo[set]);
|
||||
else
|
||||
sb.Append("Unknown set " + set);
|
||||
}
|
||||
|
||||
if (mwo.Values(IntValueKey.ArmorLevel) > 0)
|
||||
sb.Append(", AL " + mwo.Values(IntValueKey.ArmorLevel));
|
||||
|
||||
if (mwo.Values(IntValueKey.ImbuedEffect) > 0)
|
||||
{
|
||||
sb.Append(",");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 1) == 1) sb.Append(" CS");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 2) == 2) sb.Append(" CB");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 4) == 4) sb.Append(" AR");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 8) == 8) sb.Append(" SlashRend");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 16) == 16) sb.Append(" PierceRend");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 32) == 32) sb.Append(" BludgeRend");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 64) == 64) sb.Append(" AcidRend");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 128) == 128) sb.Append(" FrostRend");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 256) == 256) sb.Append(" LightRend");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 512) == 512) sb.Append(" FireRend");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 1024) == 1024) sb.Append(" MeleeImbue");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 4096) == 4096) sb.Append(" MagicImbue");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 8192) == 8192) sb.Append(" Hematited");
|
||||
if ((mwo.Values(IntValueKey.ImbuedEffect) & 536870912) == 536870912) sb.Append(" MagicAbsorb");
|
||||
}
|
||||
|
||||
if (mwo.Values(IntValueKey.NumTimesTinkered) > 0)
|
||||
sb.Append(", Tinks " + mwo.Values(IntValueKey.NumTimesTinkered));
|
||||
|
||||
if (mwo.Values(IntValueKey.MaxDamage_Decal) != 0 && mwo.Values(DoubleValueKey.Variance_Decal) != 0)
|
||||
sb.Append(", " + (mwo.Values(IntValueKey.MaxDamage_Decal) - (mwo.Values(IntValueKey.MaxDamage_Decal) * mwo.Values(DoubleValueKey.Variance_Decal))).ToString("N2") + "-" + mwo.Values(IntValueKey.MaxDamage_Decal));
|
||||
else if (mwo.Values(IntValueKey.MaxDamage_Decal) != 0 && mwo.Values(DoubleValueKey.Variance_Decal) == 0)
|
||||
sb.Append(", " + mwo.Values(IntValueKey.MaxDamage_Decal));
|
||||
|
||||
if (mwo.Values(IntValueKey.ElementalDamageBonus, 0) != 0)
|
||||
sb.Append(", +" + mwo.Values(IntValueKey.ElementalDamageBonus));
|
||||
|
||||
if (mwo.Values(DoubleValueKey.DamageBonus_Decal, 1) != 1)
|
||||
sb.Append(", +" + Math.Round(((mwo.Values(DoubleValueKey.DamageBonus_Decal) - 1) * 100)) + "%");
|
||||
|
||||
if (mwo.Values(DoubleValueKey.ElementalDamageMod, 1) != 1)
|
||||
sb.Append(", +" + Math.Round(((mwo.Values(DoubleValueKey.ElementalDamageMod) - 1) * 100)) + "%vs. Monsters");
|
||||
|
||||
if (mwo.Values(DoubleValueKey.AttackBonus_Decal, 1) != 1)
|
||||
sb.Append(", +" + Math.Round(((mwo.Values(DoubleValueKey.AttackBonus_Decal) - 1) * 100)) + "%a");
|
||||
|
||||
if (mwo.Values(DoubleValueKey.WeaponDefense, 1) != 1)
|
||||
sb.Append(", " + Math.Round(((mwo.Values(DoubleValueKey.WeaponDefense) - 1) * 100)) + "%md");
|
||||
|
||||
if (mwo.Values(DoubleValueKey.WeaponMagicDefense, 1) != 1)
|
||||
sb.Append(", " + Math.Round(((mwo.Values(DoubleValueKey.WeaponMagicDefense) - 1) * 100), 1) + "%mgc.d");
|
||||
|
||||
if (mwo.Values(DoubleValueKey.WeaponMissileDefense, 1) != 1)
|
||||
sb.Append(", " + Math.Round(((mwo.Values(DoubleValueKey.WeaponMissileDefense) - 1) * 100), 1) + "%msl.d");
|
||||
|
||||
if (mwo.Values(DoubleValueKey.ManaConversionMod) != 0)
|
||||
sb.Append(", " + Math.Round((mwo.Values(DoubleValueKey.ManaConversionMod) * 100)) + "%mc");
|
||||
|
||||
if (showBuffedValues && (mwo.ObjectClass == (int)ObjectClass.MeleeWeapon || mwo.ObjectClass == (int)ObjectClass.MissileWeapon || mwo.ObjectClass == (int)ObjectClass.WandStaffOrb))
|
||||
{
|
||||
sb.Append(", (");
|
||||
|
||||
// (Damage)
|
||||
if (mwo.ObjectClass == (int)ObjectClass.MeleeWeapon)
|
||||
sb.Append(mwo.CalcedBuffedTinkedDoT.ToString("N1") + "/" + mwo.GetBuffedIntValueKey((int)IntValueKey.MaxDamage_Decal));
|
||||
|
||||
if (mwo.ObjectClass == (int)ObjectClass.MissileWeapon)
|
||||
sb.Append(mwo.CalcedBuffedMissileDamage.ToString("N1"));
|
||||
|
||||
if (mwo.ObjectClass == (int)ObjectClass.WandStaffOrb)
|
||||
sb.Append(((mwo.GetBuffedDoubleValueKey((int)DoubleValueKey.ElementalDamageMod) - 1) * 100).ToString("N1"));
|
||||
|
||||
// (AttackBonus/MeleeDefenseBonus/ManaCBonus)
|
||||
sb.Append(" ");
|
||||
|
||||
if (mwo.Values(DoubleValueKey.AttackBonus_Decal, 1) != 1)
|
||||
sb.Append(Math.Round(((mwo.GetBuffedDoubleValueKey((int)DoubleValueKey.AttackBonus_Decal) - 1) * 100)).ToString("N1") + "/");
|
||||
|
||||
if (mwo.Values(DoubleValueKey.WeaponDefense, 1) != 1)
|
||||
sb.Append(Math.Round(((mwo.GetBuffedDoubleValueKey((int)DoubleValueKey.WeaponDefense) - 1) * 100)).ToString("N1"));
|
||||
|
||||
if (mwo.Values(DoubleValueKey.ManaConversionMod) != 0)
|
||||
sb.Append("/" + Math.Round(mwo.GetBuffedDoubleValueKey((int)DoubleValueKey.ManaConversionMod) * 100));
|
||||
|
||||
sb.Append(")");
|
||||
}
|
||||
|
||||
if (mwo.Spells.Count > 0)
|
||||
{
|
||||
List<int> sortedSpellIds = new List<int>();
|
||||
|
||||
foreach (var spell in mwo.Spells)
|
||||
sortedSpellIds.Add(spell);
|
||||
|
||||
sortedSpellIds.Sort();
|
||||
sortedSpellIds.Reverse();
|
||||
|
||||
foreach (int spellId in sortedSpellIds)
|
||||
{
|
||||
Spell spell = SpellTools.GetSpell(spellId);
|
||||
|
||||
if (spell == null)
|
||||
continue;
|
||||
|
||||
// If the item is not loot generated, show all spells
|
||||
if (!mwo.IntValues.ContainsKey((int)IntValueKey.MaterialType))
|
||||
goto ShowSpell;
|
||||
|
||||
// Always show Minor/Major/Epic Impen
|
||||
if (spell.Name.Contains("Minor Impenetrability") || spell.Name.Contains("Major Impenetrability") || spell.Name.Contains("Epic Impenetrability") || spell.Name.Contains("Legendary Impenetrability"))
|
||||
goto ShowSpell;
|
||||
|
||||
// Always show trinket spells
|
||||
if (spell.Name.Contains("Augmented"))
|
||||
goto ShowSpell;
|
||||
|
||||
if (mwo.Values(IntValueKey.ResistMagic, 0) != 0)
|
||||
{
|
||||
// Show banes and impen on unenchantable equipment
|
||||
if (spell.Name.Contains(" Bane") || spell.Name.Contains("Impen") || spell.Name.StartsWith("Brogard"))
|
||||
goto ShowSpell;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide banes and impen on enchantable equipment
|
||||
if (spell.Name.Contains(" Bane") || spell.Name.Contains("Impen") || spell.Name.StartsWith("Brogard"))
|
||||
continue;
|
||||
}
|
||||
|
||||
//Debug.WriteToChat(spellById.Name + ", Difficulty: " + spellById.Difficulty + ", Family: " + spellById.Family + ", Generation: " + spellById.Generation + ", Type: " + spellById.Type + ", " + spellById.Unknown1 + " " + spellById.Unknown2 + " " + spellById.Unknown3 + " " + spellById.Unknown4 + " " + spellById.Unknown5 + " " + spellById.Unknown6 + " " + spellById.Unknown7 + " " + spellById.Unknown8 + " " + spellById.Unknown9 + " " + spellById.Unknown10);
|
||||
// <{Mag-Tools}>: Major Coordination, Difficulty: 15, Family: 267, Generation: 1, Type: 1, 0 1 1 2572 -2.07525870829232E+20 0 0 0 0 0
|
||||
// <{Mag-Tools}>: Epic Magic Resistance, Difficulty: 20, Family: 299, Generation: 1, Type: 1, 0 1 1 4704 -2.07525870829232E+20 0 0 0 0 0
|
||||
// <{Mag-Tools}>: Epic Life Magic Aptitude, Difficulty: 20, Family: 357, Generation: 1, Type: 1, 0 1 1 4700 -2.07525870829232E+20 0 0 0 0 0
|
||||
// <{Mag-Tools}>: Epic Endurance, Difficulty: 20, Family: 263, Generation: 1, Type: 1, 0 1 1 4226 -2.07525870829232E+20 0 0 0 0 0
|
||||
// <{Mag-Tools}>: Essence Glutton, Difficulty: 30, Family: 279, Generation: 1, Type: 1, 0 0 1 2666 -2.07525870829232E+20 0 0 0 0 0
|
||||
|
||||
// <{Mag-Tools}>: Might of the Lugians, Difficulty: 300, Family: 1, Generation: 1, Type: 1, 0 0 1 2087 -2.07525870829232E+20 0 0 0 0 0
|
||||
// <{Mag-Tools}>: Executor's Blessing, Difficulty: 300, Family: 115, Generation: 1, Type: 1, 0 0 1 2053 -2.07525870829232E+20 0 0 0 0 0
|
||||
// <{Mag-Tools}>: Regeneration Other Incantation, Difficulty: 400, Family: 93, Generation: 1, Type: 1, 5 0.25 1 3982 -2.07525870829232E+20 0 0 0 0 0
|
||||
|
||||
// Focusing stone
|
||||
// <{Mag-Tools}>: Brilliance, Difficulty: 250, Family: 15, Generation: 1, Type: 1, 5 0.25 1 2348 -2.07525870829232E+20 0 0 0 0 0
|
||||
// <{Mag-Tools}>: Concentration, Difficulty: 100, Family: 13, Generation: 1, Type: 1, 0 0 1 2347 -2.07525870829232E+20 0 0 0 0 0
|
||||
// <{Mag-Tools}>: Malediction, Difficulty: 50, Family: 284, Generation: 1, Type: 1, 0 0 1 2346 -2.07525870829232E+20 0 0 0 0 0
|
||||
|
||||
// Weapon buffs
|
||||
// <{Mag-Tools}>: Elysa's Sight, Difficulty: 300, Family: 152, Generation: 1, Type: 1, 25 0 1 2106 -2.07525870829232E+20 0 0 0 0 0 (Attack Skill)
|
||||
// <{Mag-Tools}>: Infected Caress, Difficulty: 300, Family: 154, Generation: 1, Type: 1, 25 0 1 2096 -2.07525870829232E+20 0 0 0 0 0 (Damage)
|
||||
// <{Mag-Tools}>: Infected Spirit Caress, Difficulty: 300, Family: 154, Generation: 1, Type: 1, 25 0 1 3259 -2.07525870829232E+20 0 0 0 0 0 (Damage)
|
||||
// <{Mag-Tools}>: Cragstone's Will, Difficulty: 300, Family: 156, Generation: 1, Type: 1, 25 0 1 2101 -2.07525870829232E+20 0 0 0 0 0 (Defense)
|
||||
// <{Mag-Tools}>: Atlan's Alacrity, Difficulty: 300, Family: 158, Generation: 1, Type: 1, 25 0 1 2116 -2.07525870829232E+20 0 0 0 0 0 (Speed)
|
||||
// <{Mag-Tools}>: Mystic's Blessing, Difficulty: 300, Family: 195, Generation: 1, Type: 1, 25 0 1 2117 -2.07525870829232E+20 0 0 0 0 0 (Mana C)
|
||||
// <{Mag-Tools}>: Vision of the Hunter, Difficulty: 500, Family: 325, Generation: 1, Type: 1, 25 0 1 2968 -2.07525870829232E+20 0 0 0 0 0 (Damage Mod)
|
||||
|
||||
if ((spell.Family >= 152 && spell.Family <= 158) || spell.Family == 195 || spell.Family == 325)
|
||||
{
|
||||
// This is a weapon buff
|
||||
|
||||
// Lvl 6
|
||||
if (spell.Difficulty == 250)
|
||||
continue;
|
||||
|
||||
// Lvl 7
|
||||
if (spell.Difficulty == 300)
|
||||
goto ShowSpell;
|
||||
|
||||
// Lvl 8+
|
||||
if (spell.Difficulty >= 400)
|
||||
goto ShowSpell;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is not a weapon buff.
|
||||
|
||||
// Filter all 1-5 spells
|
||||
if (spell.Name.EndsWith(" I") || spell.Name.EndsWith(" II") || spell.Name.EndsWith(" III") || spell.Name.EndsWith(" IV") || spell.Name.EndsWith(" V"))
|
||||
continue;
|
||||
|
||||
// Filter 6's
|
||||
if (spell.Name.EndsWith(" VI"))
|
||||
continue;
|
||||
|
||||
// Filter 7's
|
||||
if (spell.Difficulty == 300)
|
||||
continue;
|
||||
|
||||
// Filter 8's
|
||||
if (spell.Name.Contains("Incantation"))
|
||||
continue;
|
||||
|
||||
ShowSpell:
|
||||
|
||||
sb.Append(", " + spell.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Wield Lvl 180
|
||||
if (mwo.Values(IntValueKey.WieldDifficulty) > 0)
|
||||
{
|
||||
// I don't quite understand this.
|
||||
if (mwo.Values(IntValueKey.WieldRequirements) == 7 && mwo.Values(IntValueKey.WieldSkillType) == 1)
|
||||
sb.Append(", Wield Lvl " + mwo.Values(IntValueKey.WieldDifficulty));
|
||||
else
|
||||
{
|
||||
if (Dictionaries.SkillInfo.ContainsKey(mwo.Values(IntValueKey.WieldSkillType)))
|
||||
sb.Append(", " + Dictionaries.SkillInfo[mwo.Values(IntValueKey.WieldSkillType)] + " " + mwo.Values(IntValueKey.WieldDifficulty));
|
||||
else
|
||||
sb.Append(", Unknown skill: " + mwo.Values(IntValueKey.WieldSkillType) + " " + mwo.Values(IntValueKey.WieldDifficulty));
|
||||
}
|
||||
}
|
||||
|
||||
// Summoning Gem
|
||||
if (mwo.Values((IntValueKey)369) > 0)
|
||||
sb.Append(", Lvl " + mwo.Values((IntValueKey)369));
|
||||
|
||||
// Melee Defense 300 to Activate
|
||||
// If the activation is lower than the wield requirement, don't show it.
|
||||
if (mwo.Values(IntValueKey.ItemSkillLevelLimit) > 0 && (mwo.Values(IntValueKey.WieldSkillType) != mwo.Values(IntValueKey.AppraisalItemSkill) || mwo.Values(IntValueKey.WieldDifficulty) < mwo.Values(IntValueKey.ItemSkillLevelLimit)))
|
||||
{
|
||||
if (Dictionaries.SkillInfo.ContainsKey(mwo.Values(IntValueKey.AppraisalItemSkill)))
|
||||
sb.Append(", " + Dictionaries.SkillInfo[mwo.Values(IntValueKey.AppraisalItemSkill)] + " " + mwo.Values(IntValueKey.ItemSkillLevelLimit) + " to Activate");
|
||||
else
|
||||
sb.Append(", Unknown skill: " + mwo.Values(IntValueKey.AppraisalItemSkill) + " " + mwo.Values(IntValueKey.ItemSkillLevelLimit) + " to Activate");
|
||||
}
|
||||
|
||||
// Summoning Gem
|
||||
if (mwo.Values((IntValueKey)366) > 0 && mwo.Values((IntValueKey)367) > 0)
|
||||
{
|
||||
if (Dictionaries.SkillInfo.ContainsKey(mwo.Values((IntValueKey)366)))
|
||||
sb.Append(", " + Dictionaries.SkillInfo[mwo.Values((IntValueKey)366)] + " " + mwo.Values((IntValueKey)367));
|
||||
else
|
||||
sb.Append(", Unknown skill: " + mwo.Values((IntValueKey)366) + " " + mwo.Values((IntValueKey)367));
|
||||
}
|
||||
|
||||
// Summoning Gem
|
||||
if (mwo.Values((IntValueKey)368) > 0 && mwo.Values((IntValueKey)367) > 0)
|
||||
{
|
||||
if (Dictionaries.SkillInfo.ContainsKey(mwo.Values((IntValueKey)368)))
|
||||
sb.Append(", Spec " + Dictionaries.SkillInfo[mwo.Values((IntValueKey)368)] + " " + mwo.Values((IntValueKey)367));
|
||||
else
|
||||
sb.Append(", Unknown skill spec: " + mwo.Values((IntValueKey)368) + " " + mwo.Values((IntValueKey)367));
|
||||
}
|
||||
|
||||
if (mwo.Values(IntValueKey.ItemDifficulty) > 0)
|
||||
sb.Append(", Diff " + mwo.Values(IntValueKey.ItemDifficulty));
|
||||
|
||||
if (mwo.ObjectClass == (int)ObjectClass.Salvage)
|
||||
{
|
||||
if (mwo.Values(DoubleValueKey.SalvageWorkmanship_Decal) > 0)
|
||||
sb.Append(", Work " + mwo.Values(DoubleValueKey.SalvageWorkmanship_Decal).ToString("N2"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mwo.Values(IntValueKey.ItemWorkmanship) > 0 && mwo.Values(IntValueKey.NumTimesTinkered) != 10) // Don't show the work if its already 10 tinked.
|
||||
sb.Append(", Craft " + mwo.Values(IntValueKey.ItemWorkmanship));
|
||||
}
|
||||
|
||||
if (mwo.ObjectClass == (int)ObjectClass.Armor && mwo.Values(IntValueKey.ResistMagic, 0) != 0)
|
||||
{
|
||||
sb.Append(", [" +
|
||||
mwo.Values(DoubleValueKey.SlashProt_Decal).ToString("N1") + "/" +
|
||||
mwo.Values(DoubleValueKey.PierceProt_Decal).ToString("N1") + "/" +
|
||||
mwo.Values(DoubleValueKey.BludgeonProt_Decal).ToString("N1") + "/" +
|
||||
mwo.Values(DoubleValueKey.ColdProt_Decal).ToString("N1") + "/" +
|
||||
mwo.Values(DoubleValueKey.FireProt_Decal).ToString("N1") + "/" +
|
||||
mwo.Values(DoubleValueKey.AcidProt_Decal).ToString("N1") + "/" +
|
||||
mwo.Values(DoubleValueKey.LightningProt_Decal).ToString("N1") + "]");
|
||||
}
|
||||
|
||||
if (showValueAndBurden)
|
||||
{
|
||||
if (mwo.Values(IntValueKey.Value) > 0)
|
||||
sb.Append(", Value " + String.Format("{0:n0}", mwo.Values(IntValueKey.Value)));
|
||||
|
||||
if (mwo.Values(IntValueKey.EncumbranceVal) > 0)
|
||||
sb.Append(", BU " + mwo.Values(IntValueKey.EncumbranceVal));
|
||||
}
|
||||
|
||||
if (mwo.TotalRating > 0)
|
||||
{
|
||||
sb.Append(", [");
|
||||
bool first = true;
|
||||
if (mwo.DamRating > 0) { sb.Append("D " + mwo.DamRating); first = false; }
|
||||
if (mwo.DamResistRating > 0) { if (!first) sb.Append(", "); sb.Append("DR " + mwo.DamResistRating); first = false; }
|
||||
if (mwo.CritRating > 0) { if (!first) sb.Append(", "); sb.Append("C " + mwo.CritRating); first = false; }
|
||||
if (mwo.CritDamRating > 0) { if (!first) sb.Append(", "); sb.Append("CD " + mwo.CritDamRating); first = false; }
|
||||
if (mwo.CritResistRating > 0) { if (!first) sb.Append(", "); sb.Append("CR " + mwo.CritResistRating); first = false; }
|
||||
if (mwo.CritDamResistRating > 0) { if (!first) sb.Append(", "); sb.Append("CDR " + mwo.CritDamResistRating); first = false; }
|
||||
if (mwo.HealBoostRating > 0) { if (!first) sb.Append(", "); sb.Append("HB " + mwo.HealBoostRating); first = false; }
|
||||
if (mwo.VitalityRating > 0) { if (!first) sb.Append(", "); sb.Append("V " + mwo.VitalityRating); first = false; }
|
||||
sb.Append("]");
|
||||
}
|
||||
|
||||
if (mwo.ObjectClass == (int)ObjectClass.Misc && mwo.Name.Contains("Keyring"))
|
||||
sb.Append(", Keys: " + mwo.Values(IntValueKey.NumKeys) + ", Uses: " + mwo.Values(IntValueKey.Structure));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
386
Shared/MyWorldObject.cs
Normal file
386
Shared/MyWorldObject.cs
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
using Mag.Shared.Constants;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a user defiend object to represent a Decal.Adapter.WorldObject.
|
||||
/// All properties will return -1 if the property isn't supported.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MyWorldObject
|
||||
{
|
||||
public bool HasIdData;
|
||||
public int Id;
|
||||
public int LastIdTime;
|
||||
public int ObjectClass;
|
||||
|
||||
public SerializableDictionary<int, bool> BoolValues = new SerializableDictionary<int, bool>();
|
||||
public SerializableDictionary<int, double> DoubleValues = new SerializableDictionary<int, double>();
|
||||
public SerializableDictionary<int, int> IntValues = new SerializableDictionary<int, int>();
|
||||
public SerializableDictionary<int, string> StringValues = new SerializableDictionary<int, string>();
|
||||
|
||||
public List<int> ActiveSpells = new List<int>();
|
||||
public List<int> Spells = new List<int>();
|
||||
|
||||
public void Init(bool hasIdData, int id, int lastIdTime, int objectClass, IDictionary<int, bool> boolValues, IDictionary<int, double> doubleValues, IDictionary<int, int> intValues, IDictionary<int, string> stringValues, IList<int> activeSpells, IList<int> spells)
|
||||
{
|
||||
HasIdData = hasIdData;
|
||||
Id = id;
|
||||
LastIdTime = lastIdTime;
|
||||
ObjectClass = objectClass;
|
||||
|
||||
AddTo(boolValues, doubleValues, intValues, stringValues);
|
||||
|
||||
ActiveSpells.Clear();
|
||||
foreach (var i in activeSpells)
|
||||
ActiveSpells.Add(i);
|
||||
|
||||
Spells.Clear();
|
||||
foreach (var i in spells)
|
||||
Spells.Add(i);
|
||||
}
|
||||
|
||||
public void AddTo(IDictionary<int, bool> boolValues, IDictionary<int, double> doubleValues, IDictionary<int, int> intValues, IDictionary<int, string> stringValues)
|
||||
{
|
||||
foreach (var kvp in boolValues)
|
||||
{
|
||||
if (boolValues.ContainsKey(kvp.Key))
|
||||
BoolValues[kvp.Key] = kvp.Value;
|
||||
else
|
||||
BoolValues.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
foreach (var kvp in doubleValues)
|
||||
{
|
||||
if (doubleValues.ContainsKey(kvp.Key))
|
||||
DoubleValues[kvp.Key] = kvp.Value;
|
||||
else
|
||||
DoubleValues.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
foreach (var kvp in intValues)
|
||||
{
|
||||
if (intValues.ContainsKey(kvp.Key))
|
||||
IntValues[kvp.Key] = kvp.Value;
|
||||
else
|
||||
IntValues.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
foreach (var kvp in stringValues)
|
||||
{
|
||||
if (stringValues.ContainsKey(kvp.Key))
|
||||
StringValues[kvp.Key] = kvp.Value;
|
||||
else
|
||||
StringValues.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Values(BoolValueKey key, bool defaultValue = false)
|
||||
{
|
||||
if (BoolValues.ContainsKey((int)key))
|
||||
return BoolValues[(int)key];
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public double Values(DoubleValueKey key, double defaultValue = 0)
|
||||
{
|
||||
if (DoubleValues.ContainsKey((int)key))
|
||||
return DoubleValues[(int)key];
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public int Values(IntValueKey key, int defaultValue = 0)
|
||||
{
|
||||
if (IntValues.ContainsKey((int)key))
|
||||
return IntValues[(int)key];
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public string Values(StringValueKey key, string defaultValue = null)
|
||||
{
|
||||
if (StringValues.ContainsKey((int)key))
|
||||
return StringValues[(int)key];
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
public string Material { get { if (IntValues.ContainsKey(131)) return Dictionaries.MaterialInfo.ContainsKey(IntValues[131]) ? Dictionaries.MaterialInfo[IntValues[131]] : IntValues[131].ToString(CultureInfo.InvariantCulture); return null; } }
|
||||
|
||||
public string Name { get { return StringValues.ContainsKey(1) ? StringValues[1] : null; } }
|
||||
|
||||
|
||||
public string EquipSkill { get { if (IntValues.ContainsKey(218103840)) return Dictionaries.SkillInfo.ContainsKey(IntValues[218103840]) ? Dictionaries.SkillInfo[IntValues[218103840]] : IntValues[218103840].ToString(CultureInfo.InvariantCulture); return null; } }
|
||||
|
||||
public string Mastery { get { if (IntValues.ContainsKey(353)) return Dictionaries.MasteryInfo.ContainsKey(IntValues[353]) ? Dictionaries.MasteryInfo[IntValues[353]] : IntValues[353].ToString(CultureInfo.InvariantCulture); return null; } }
|
||||
|
||||
public string ItemSet { get { if (IntValues.ContainsKey(265)) return Dictionaries.AttributeSetInfo.ContainsKey(IntValues[265]) ? Dictionaries.AttributeSetInfo[IntValues[265]] : IntValues[265].ToString(CultureInfo.InvariantCulture); return null; } }
|
||||
|
||||
|
||||
public int ArmorLevel { get { return IntValues.ContainsKey(28) ? IntValues[28] : -1; } }
|
||||
|
||||
public string Imbue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IntValues.ContainsKey(179) || IntValues[179] == 0) return null;
|
||||
|
||||
string retVal = String.Empty;
|
||||
if ((IntValues[179] & 1) == 1) retVal += " CS";
|
||||
if ((IntValues[179] & 2) == 2) retVal += " CB";
|
||||
if ((IntValues[179] & 4) == 4) retVal += " AR";
|
||||
if ((IntValues[179] & 8) == 8) retVal += " SlashRend";
|
||||
if ((IntValues[179] & 16) == 16) retVal += " PierceRend";
|
||||
if ((IntValues[179] & 32) == 32) retVal += " BludgeRend";
|
||||
if ((IntValues[179] & 64) == 64) retVal += " AcidRend";
|
||||
if ((IntValues[179] & 128) == 128) retVal += " FrostRend";
|
||||
if ((IntValues[179] & 256) == 256) retVal += " LightRend";
|
||||
if ((IntValues[179] & 512) == 512) retVal += " FireRend";
|
||||
if ((IntValues[179] & 1024) == 1024) retVal += " MeleeImbue";
|
||||
if ((IntValues[179] & 4096) == 4096) retVal += " MagicImbue";
|
||||
if ((IntValues[179] & 8192) == 8192) retVal += " Hematited";
|
||||
if ((IntValues[179] & 536870912) == 536870912) retVal += " MagicAbsorb";
|
||||
retVal = retVal.Trim();
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
public int Tinks { get { return IntValues.ContainsKey(171) ? IntValues[171] : -1; } }
|
||||
|
||||
|
||||
public int MaxDamage { get { return IntValues.ContainsKey(218103842) ? IntValues[218103842] : -1; } }
|
||||
|
||||
public int ElementalDmgBonus { get { return IntValues.ContainsKey(204) ? IntValues[204] : -1; } }
|
||||
|
||||
public Double Variance { get { return DoubleValues.ContainsKey(167772171) ? DoubleValues[167772171] : -1; } }
|
||||
|
||||
public Double DamageBonus { get { return DoubleValues.ContainsKey(167772174) ? DoubleValues[167772174] : -1; } }
|
||||
|
||||
public Double ElementalDamageVersusMonsters { get { return DoubleValues.ContainsKey(152) ? DoubleValues[152] : -1; } }
|
||||
|
||||
public Double AttackBonus { get { return DoubleValues.ContainsKey(167772172) ? DoubleValues[167772172] : -1; } }
|
||||
|
||||
public Double MeleeDefenseBonus { get { return DoubleValues.ContainsKey(29) ? DoubleValues[29] : -1; } }
|
||||
|
||||
public Double MagicDBonus { get { return DoubleValues.ContainsKey(150) ? DoubleValues[150] : -1; } }
|
||||
|
||||
public Double MissileDBonus { get { return DoubleValues.ContainsKey(149) ? DoubleValues[149] : -1; } }
|
||||
|
||||
public Double ManaCBonus { get { return DoubleValues.ContainsKey(144) ? DoubleValues[144] : -1; } }
|
||||
|
||||
|
||||
public int WieldLevel { get { if (IntValues.ContainsKey(160) && IntValues[160] > 0 && IntValues.ContainsKey(158) && IntValues[158] == 7 && IntValues.ContainsKey(159) && IntValues[159] == 1) return IntValues[160]; return -1; } }
|
||||
|
||||
public int SkillLevel { get { if (IntValues.ContainsKey(160) && IntValues[160] > 0 && (!IntValues.ContainsKey(158) || IntValues[158] != 7) && IntValues.ContainsKey(159)) return IntValues[160]; return -1; } }
|
||||
|
||||
|
||||
public int LoreRequirement { get { return IntValues.ContainsKey(109) ? IntValues[109] : -1; } }
|
||||
|
||||
public Double SalvageWorkmanship { get { return DoubleValues.ContainsKey(167772169) ? DoubleValues[167772169] : -1; } }
|
||||
|
||||
public int Workmanship { get { return IntValues.ContainsKey(105) ? IntValues[105] : -1; } }
|
||||
|
||||
public int Value { get { return IntValues.ContainsKey(19) ? IntValues[19] : -1; } }
|
||||
|
||||
public int Burden { get { return IntValues.ContainsKey(5) ? IntValues[5] : -1; } }
|
||||
|
||||
|
||||
public int DamRating { get { return IntValues.ContainsKey(370) ? IntValues[370] : -1; } }
|
||||
|
||||
public int DamResistRating { get { return IntValues.ContainsKey(371) ? IntValues[371] : -1; } }
|
||||
|
||||
public int CritRating { get { return IntValues.ContainsKey(372) ? IntValues[372] : -1; } }
|
||||
|
||||
public int CritResistRating { get { return IntValues.ContainsKey(373) ? IntValues[373] : -1; } }
|
||||
|
||||
public int CritDamRating { get { return IntValues.ContainsKey(374) ? IntValues[374] : -1; } }
|
||||
|
||||
public int CritDamResistRating { get { return IntValues.ContainsKey(375) ? IntValues[375] : -1; } }
|
||||
|
||||
public int HealBoostRating { get { return IntValues.ContainsKey(376) ? IntValues[376] : -1; } }
|
||||
|
||||
public int VitalityRating { get { return IntValues.ContainsKey(379) ? IntValues[379] : -1; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the sum of all the ratings found on this item, or -1 if no ratings exist.
|
||||
/// </summary>
|
||||
public int TotalRating
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DamRating == -1 && DamResistRating == -1 && CritRating == -1 && CritResistRating == -1 && CritDamRating == -1 && CritDamResistRating == -1 && HealBoostRating == -1 && VitalityRating == -1)
|
||||
return -1;
|
||||
|
||||
return Math.Max(DamRating, 0) + Math.Max(DamResistRating, 0) + Math.Max(CritRating, 0) + Math.Max(CritResistRating, 0) + Math.Max(CritDamRating, 0) + Math.Max(CritDamResistRating, 0) + Math.Max(HealBoostRating, 0) + Math.Max(VitalityRating, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This will take the current AmorLevel of the item, subtract any buffs, subtract tinks as 20 AL each (not including imbue), and add any impen cantrips.
|
||||
/// </summary>
|
||||
public int CalcedStartingArmorLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
int armorFromTinks = 0;
|
||||
int armorFromBuffs = 0;
|
||||
|
||||
if (Tinks > 0 && ArmorLevel > 0)
|
||||
armorFromTinks = (Imbue != null) ? (Tinks - 1) * 20 : Tinks * 20; // This assumes each tink adds an amor level of 20
|
||||
|
||||
if ((!IntValues.ContainsKey(131) || IntValues[131] == 0) && ArmorLevel > 0) // If this item has no material, its not a loot gen, assume its a quest item and subtract 200 al
|
||||
armorFromTinks = 200;
|
||||
|
||||
foreach (int spell in ActiveSpells)
|
||||
{
|
||||
foreach (var effect in Dictionaries.LongValueKeySpellEffects)
|
||||
{
|
||||
if (spell == effect.Key && effect.Value.Key == 28)
|
||||
armorFromBuffs += effect.Value.Change;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (int spell in Spells)
|
||||
{
|
||||
foreach (var effect in Dictionaries.LongValueKeySpellEffects)
|
||||
{
|
||||
if (spell == effect.Key && effect.Value.Key == 28)
|
||||
armorFromBuffs -= effect.Value.Bonus;
|
||||
}
|
||||
}
|
||||
|
||||
return ArmorLevel - armorFromTinks - armorFromBuffs;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will take into account Variance, MaxDamage and Tinks of a melee weapon and determine what its optimal 10 tinked DamageOverTime is.
|
||||
/// </summary>
|
||||
public double CalcedBuffedTinkedDoT
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!DoubleValues.ContainsKey(167772171) || !IntValues.ContainsKey(218103842))
|
||||
return -1;
|
||||
|
||||
double variance = DoubleValues.ContainsKey(167772171) ? DoubleValues[167772171] : 0;
|
||||
int maxDamage = GetBuffedIntValueKey(218103842);
|
||||
|
||||
int numberOfTinksLeft = Math.Max(10 - Math.Max(Tinks, 0), 0);
|
||||
|
||||
if (!IntValues.ContainsKey(179) || IntValues[179] == 0)
|
||||
numberOfTinksLeft--; // Factor in an imbue tink
|
||||
|
||||
// If this is not a loot generated item, it can't be tinked
|
||||
if (!IntValues.ContainsKey(131) || IntValues[131] == 0)
|
||||
numberOfTinksLeft = 0;
|
||||
|
||||
for (int i = 1; i <= numberOfTinksLeft; i++)
|
||||
{
|
||||
double ironTinkDoT = CalculateDamageOverTime(maxDamage + 24 + 1, variance);
|
||||
double graniteTinkDoT = CalculateDamageOverTime(maxDamage + 24, variance * .8);
|
||||
|
||||
if (ironTinkDoT >= graniteTinkDoT)
|
||||
maxDamage++;
|
||||
else
|
||||
variance *= .8;
|
||||
}
|
||||
|
||||
return CalculateDamageOverTime(maxDamage + 24, variance);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetBuffedIntValueKey(LongValueKey.MaxDamage) + (((GetBuffedDoubleValueKey(DoubleValueKey.DamageBonus) - 1) * 100) / 3) + GetBuffedIntValueKey(LongValueKey.ElementalDmgBonus);
|
||||
/// </summary>
|
||||
public double CalcedBuffedMissileDamage { get { if (!IntValues.ContainsKey(218103842) || !DoubleValues.ContainsKey(167772174) || !IntValues.ContainsKey(204)) return -1; return GetBuffedIntValueKey(218103842) + (((GetBuffedDoubleValueKey(167772174) - 1) * 100) / 3) + GetBuffedIntValueKey(204); } }
|
||||
|
||||
public double BuffedElementalDamageVersusMonsters { get { return GetBuffedDoubleValueKey(152, -1); } }
|
||||
|
||||
public double BuffedAttackBonus { get { return GetBuffedDoubleValueKey(167772172, -1); } }
|
||||
|
||||
public double BuffedMeleeDefenseBonus { get { return GetBuffedDoubleValueKey(29, -1); } }
|
||||
|
||||
public double BuffedManaCBonus { get { return GetBuffedDoubleValueKey(144, -1); } }
|
||||
|
||||
public int GetBuffedIntValueKey(int key, int defaultValue = 0)
|
||||
{
|
||||
if (!IntValues.ContainsKey(key))
|
||||
return defaultValue;
|
||||
|
||||
int value = IntValues[key];
|
||||
|
||||
foreach (int spell in ActiveSpells)
|
||||
{
|
||||
if (Dictionaries.LongValueKeySpellEffects.ContainsKey(spell) && Dictionaries.LongValueKeySpellEffects[spell].Key == key)
|
||||
value -= Dictionaries.LongValueKeySpellEffects[spell].Change;
|
||||
}
|
||||
|
||||
foreach (int spell in Spells)
|
||||
{
|
||||
if (Dictionaries.LongValueKeySpellEffects.ContainsKey(spell) && Dictionaries.LongValueKeySpellEffects[spell].Key == key)
|
||||
value += Dictionaries.LongValueKeySpellEffects[spell].Bonus;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public double GetBuffedDoubleValueKey(int key, double defaultValue = 0)
|
||||
{
|
||||
if (!DoubleValues.ContainsKey(key))
|
||||
return defaultValue;
|
||||
|
||||
double value = DoubleValues[key];
|
||||
|
||||
foreach (int spell in ActiveSpells)
|
||||
{
|
||||
if (Dictionaries.DoubleValueKeySpellEffects.ContainsKey(spell) && Dictionaries.DoubleValueKeySpellEffects[spell].Key == key)
|
||||
{
|
||||
if (Math.Abs(Dictionaries.DoubleValueKeySpellEffects[spell].Change - 1) < Double.Epsilon)
|
||||
value /= Dictionaries.DoubleValueKeySpellEffects[spell].Change;
|
||||
else
|
||||
value -= Dictionaries.DoubleValueKeySpellEffects[spell].Change;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (int spell in Spells)
|
||||
{
|
||||
if (Dictionaries.DoubleValueKeySpellEffects.ContainsKey(spell) && Dictionaries.DoubleValueKeySpellEffects[spell].Key == key && Math.Abs(Dictionaries.DoubleValueKeySpellEffects[spell].Bonus - 0) > Double.Epsilon)
|
||||
{
|
||||
if (Math.Abs(Dictionaries.DoubleValueKeySpellEffects[spell].Change - 1) < Double.Epsilon)
|
||||
value *= Dictionaries.DoubleValueKeySpellEffects[spell].Bonus;
|
||||
else
|
||||
value += Dictionaries.DoubleValueKeySpellEffects[spell].Bonus;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// maxDamage * ((1 - critChance) * (2 - variance) / 2 + (critChance * critMultiplier));
|
||||
/// </summary>
|
||||
/// <param name="maxDamage"></param>
|
||||
/// <param name="variance"></param>
|
||||
/// <param name="critChance"></param>
|
||||
/// <param name="critMultiplier"></param>
|
||||
/// <returns></returns>
|
||||
public static double CalculateDamageOverTime(int maxDamage, double variance, double critChance = .1, double critMultiplier = 2)
|
||||
{
|
||||
return maxDamage * ((1 - critChance) * (2 - variance) / 2 + (critChance * critMultiplier));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Shared/MyWorldObjectCreator.cs
Normal file
55
Shared/MyWorldObjectCreator.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using Decal.Adapter.Wrappers;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
public static class MyWorldObjectCreator
|
||||
{
|
||||
public static MyWorldObject Create(WorldObject wo)
|
||||
{
|
||||
MyWorldObject mwo = new MyWorldObject();
|
||||
|
||||
Dictionary<int, bool> boolValues = new Dictionary<int,bool>();
|
||||
Dictionary<int, double> doubleValues = new Dictionary<int,double>();
|
||||
Dictionary<int, int> intValues = new Dictionary<int, int>();
|
||||
Dictionary<int, string> stringValues = new Dictionary<int,string>();
|
||||
List<int> activeSpells = new List<int>();
|
||||
List<int> spells = new List<int>();
|
||||
|
||||
foreach (var key in wo.BoolKeys)
|
||||
boolValues.Add(key, wo.Values((BoolValueKey)key));
|
||||
|
||||
foreach (var key in wo.DoubleKeys)
|
||||
doubleValues.Add(key, wo.Values((DoubleValueKey)key));
|
||||
|
||||
foreach (var key in wo.LongKeys)
|
||||
intValues.Add(key, wo.Values((LongValueKey)key));
|
||||
|
||||
foreach (var key in wo.StringKeys)
|
||||
stringValues.Add(key, wo.Values((StringValueKey)key));
|
||||
|
||||
for (int i = 0 ; i < wo.ActiveSpellCount ; i++)
|
||||
activeSpells.Add(wo.ActiveSpell(i));
|
||||
|
||||
for (int i = 0; i < wo.SpellCount; i++)
|
||||
spells.Add(wo.Spell(i));
|
||||
|
||||
mwo.Init(wo.HasIdData, wo.Id, wo.LastIdTime, (int)wo.ObjectClass, boolValues, doubleValues, intValues, stringValues, activeSpells, spells);
|
||||
|
||||
return mwo;
|
||||
}
|
||||
|
||||
public static MyWorldObject Combine(MyWorldObject older, WorldObject newer)
|
||||
{
|
||||
if (!older.HasIdData || newer.HasIdData)
|
||||
return Create(newer);
|
||||
|
||||
MyWorldObject mwo = Create(newer);
|
||||
|
||||
older.AddTo(mwo.BoolValues, mwo.DoubleValues, mwo.IntValues, mwo.StringValues);
|
||||
|
||||
return older;
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Shared/ObjectClass.cs
Normal file
165
Shared/ObjectClass.cs
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
|
||||
using Mag.Shared.Constants;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
public enum ObjectClass
|
||||
{
|
||||
Unknown = 0,
|
||||
MeleeWeapon = 1,
|
||||
Armor = 2,
|
||||
Clothing = 3,
|
||||
Jewelry = 4,
|
||||
Monster = 5,
|
||||
Food = 6,
|
||||
Money = 7,
|
||||
Misc = 8,
|
||||
MissileWeapon = 9,
|
||||
Container = 10,
|
||||
Gem = 11,
|
||||
SpellComponent = 12,
|
||||
Key = 13,
|
||||
Portal = 14,
|
||||
TradeNote = 15,
|
||||
ManaStone = 16,
|
||||
Plant = 17,
|
||||
BaseCooking = 18,
|
||||
BaseAlchemy = 19,
|
||||
BaseFletching = 20,
|
||||
CraftedCooking = 21,
|
||||
CraftedAlchemy = 22,
|
||||
CraftedFletching = 23,
|
||||
Player = 24,
|
||||
Vendor = 25,
|
||||
Door = 26,
|
||||
Corpse = 27,
|
||||
Lifestone = 28,
|
||||
HealingKit = 29,
|
||||
Lockpick = 30,
|
||||
WandStaffOrb = 31,
|
||||
Bundle = 32,
|
||||
Book = 33,
|
||||
Journal = 34,
|
||||
Sign = 35,
|
||||
Housing = 36,
|
||||
Npc = 37,
|
||||
Foci = 38,
|
||||
Salvage = 39,
|
||||
Ust = 40,
|
||||
Services = 41,
|
||||
Scroll = 42,
|
||||
NumObjectClasses = 43,
|
||||
}
|
||||
|
||||
public static class ObjectClassTools
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a decal specific IntValueKey to the actual IntValueKey.
|
||||
/// If this is not an IntValueKey, 0 will be returned.
|
||||
/// </summary>
|
||||
public static ObjectClass FromWeenieType(ItemType itemType, WeenieType weenieType)
|
||||
{
|
||||
var result = ObjectClass.Unknown;
|
||||
|
||||
if ((itemType & ItemType.MeleeWeapon) != 0)
|
||||
result = ObjectClass.MeleeWeapon;
|
||||
else if ((itemType & ItemType.Armor) != 0)
|
||||
result = ObjectClass.Armor;
|
||||
else if ((itemType & ItemType.Clothing) != 0)
|
||||
result = ObjectClass.Clothing;
|
||||
else if ((itemType & ItemType.Jewelry) != 0)
|
||||
result = ObjectClass.Jewelry;
|
||||
else if ((itemType & ItemType.Creature) != 0)
|
||||
result = ObjectClass.Monster;
|
||||
else if ((itemType & ItemType.Food) != 0)
|
||||
result = ObjectClass.Food;
|
||||
else if ((itemType & ItemType.Money) != 0)
|
||||
result = ObjectClass.Money;
|
||||
else if ((itemType & ItemType.Misc) != 0)
|
||||
result = ObjectClass.Misc;
|
||||
else if ((itemType & ItemType.MissileWeapon) != 0)
|
||||
result = ObjectClass.MissileWeapon;
|
||||
else if ((itemType & ItemType.Container) != 0)
|
||||
result = ObjectClass.Container;
|
||||
else if ((itemType & ItemType.Useless) != 0)
|
||||
result = ObjectClass.Bundle;
|
||||
else if ((itemType & ItemType.Gem) != 0)
|
||||
result = ObjectClass.Gem;
|
||||
else if ((itemType & ItemType.SpellComponents) != 0)
|
||||
result = ObjectClass.SpellComponent;
|
||||
else if ((itemType & ItemType.Key) != 0)
|
||||
result = ObjectClass.Key;
|
||||
else if ((itemType & ItemType.Caster) != 0)
|
||||
result = ObjectClass.WandStaffOrb;
|
||||
else if ((itemType & ItemType.Portal) != 0)
|
||||
result = ObjectClass.Portal;
|
||||
else if ((itemType & ItemType.PromissoryNote) != 0)
|
||||
result = ObjectClass.TradeNote;
|
||||
else if ((itemType & ItemType.ManaStone) != 0)
|
||||
result = ObjectClass.ManaStone;
|
||||
else if ((itemType & ItemType.Service) != 0)
|
||||
result = ObjectClass.Services;
|
||||
else if ((itemType & ItemType.MagicWieldable) != 0)
|
||||
result = ObjectClass.Plant;
|
||||
else if ((itemType & ItemType.CraftCookingBase) != 0)
|
||||
result = ObjectClass.BaseCooking;
|
||||
else if ((itemType & ItemType.CraftAlchemyBase) != 0)
|
||||
result = ObjectClass.BaseAlchemy;
|
||||
//else if ((itemType & ItemType.01000000)
|
||||
// result = ObjectClass.BaseFletching;
|
||||
else if ((itemType & ItemType.CraftFletchingBase) != 0)
|
||||
result = ObjectClass.CraftedCooking;
|
||||
else if ((itemType & ItemType.CraftAlchemyIntermediate) != 0)
|
||||
result = ObjectClass.CraftedAlchemy;
|
||||
else if ((itemType & ItemType.CraftFletchingIntermediate) != 0)
|
||||
result = ObjectClass.CraftedFletching;
|
||||
else if ((itemType & ItemType.TinkeringTool) != 0)
|
||||
result = ObjectClass.Ust;
|
||||
else if ((itemType & ItemType.TinkeringMaterial) != 0)
|
||||
result = ObjectClass.Salvage;
|
||||
|
||||
/*
|
||||
if (Behavior & 0x00000008)
|
||||
result = ObjectClass.Player;
|
||||
else if (Behavior & 0x00000200)
|
||||
result = ObjectClass.Vendor;
|
||||
else if (Behavior & 0x00001000)
|
||||
result = ObjectClass.Door;
|
||||
else if (Behavior & 0x00002000)
|
||||
result = ObjectClass.Corpse;
|
||||
else if (Behavior & 0x00004000)
|
||||
result = ObjectClass.Lifestone;
|
||||
else if (Behavior & 0x00008000)
|
||||
result = ObjectClass.Food;
|
||||
else if (Behavior & 0x00010000)
|
||||
result = ObjectClass.HealingKit;
|
||||
else if (Behavior & 0x00020000)
|
||||
result = ObjectClass.Lockpick;
|
||||
else if (Behavior & 0x00040000)
|
||||
result = ObjectClass.Portal;
|
||||
else if (Behavior & 0x00800000)
|
||||
result = ObjectClass.Foci;
|
||||
else if (Behavior & 0x00000001)
|
||||
result = ObjectClass.Container;
|
||||
*/
|
||||
|
||||
/*if (((itemType & ItemType.Writable) != 0) && (Behavior & 0x00000100) && result == ObjectClass.Unknown)
|
||||
{
|
||||
if (pCreate->m_Behavior & 0x00000002)
|
||||
result = ObjectClass.Journal;
|
||||
else if (pCreate->m_Behavior & 0x00000004)
|
||||
result = ObjectClass.Sign;
|
||||
else if (!(pCreate->m_Behavior & 0x0000000F))
|
||||
result = ObjectClass.Book;
|
||||
}*/
|
||||
|
||||
/*if (((itemType & ItemType.Writable) != 0) && ((GameDataFlags1 & 0x00400000) != 0))
|
||||
result = ObjectClass.Scroll;*/
|
||||
|
||||
//throw new Exception($"Unable to convert WeenieType {input} to an ObjectClass.");
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
293
Shared/PostMessageTools.cs
Normal file
293
Shared/PostMessageTools.cs
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Decal.Adapter;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
public static class PostMessageTools
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/dd375731%28v=vs.85%29.aspx
|
||||
|
||||
private const byte VK_RETURN = 0x0D;
|
||||
private const byte VK_SHIFT = 0x10;
|
||||
private const byte VK_CONTROL = 0x11;
|
||||
private const byte VK_PAUSE = 0x13;
|
||||
private const byte VK_SPACE = 0x20;
|
||||
|
||||
private static byte ScanCode(char Char)
|
||||
{
|
||||
switch (char.ToLower(Char))
|
||||
{
|
||||
case 'a': return 0x1E;
|
||||
case 'b': return 0x30;
|
||||
case 'c': return 0x2E;
|
||||
case 'd': return 0x20;
|
||||
case 'e': return 0x12;
|
||||
case 'f': return 0x21;
|
||||
case 'g': return 0x22;
|
||||
case 'h': return 0x23;
|
||||
case 'i': return 0x17;
|
||||
case 'j': return 0x24;
|
||||
case 'k': return 0x25;
|
||||
case 'l': return 0x26;
|
||||
case 'm': return 0x32;
|
||||
case 'n': return 0x31;
|
||||
case 'o': return 0x18;
|
||||
case 'p': return 0x19;
|
||||
case 'q': return 0x10;
|
||||
case 'r': return 0x13;
|
||||
case 's': return 0x1F;
|
||||
case 't': return 0x14;
|
||||
case 'u': return 0x16;
|
||||
case 'v': return 0x2F;
|
||||
case 'w': return 0x11;
|
||||
case 'x': return 0x2D;
|
||||
case 'y': return 0x15;
|
||||
case 'z': return 0x2C;
|
||||
case '/': return 0x35;
|
||||
case ' ': return 0x39;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static byte CharCode(char Char)
|
||||
{
|
||||
switch (char.ToLower(Char))
|
||||
{
|
||||
case 'a': return 0x41;
|
||||
case 'b': return 0x42;
|
||||
case 'c': return 0x43;
|
||||
case 'd': return 0x44;
|
||||
case 'e': return 0x45;
|
||||
case 'f': return 0x46;
|
||||
case 'g': return 0x47;
|
||||
case 'h': return 0x48;
|
||||
case 'i': return 0x49;
|
||||
case 'j': return 0x4A;
|
||||
case 'k': return 0x4B;
|
||||
case 'l': return 0x4C;
|
||||
case 'm': return 0x4D;
|
||||
case 'n': return 0x4E;
|
||||
case 'o': return 0x4F;
|
||||
case 'p': return 0x50;
|
||||
case 'q': return 0x51;
|
||||
case 'r': return 0x52;
|
||||
case 's': return 0x53;
|
||||
case 't': return 0x54;
|
||||
case 'u': return 0x55;
|
||||
case 'v': return 0x56;
|
||||
case 'w': return 0x57;
|
||||
case 'x': return 0x58;
|
||||
case 'y': return 0x59;
|
||||
case 'z': return 0x5A;
|
||||
case '/': return 0xBF;
|
||||
case ' ': return 0x20;
|
||||
}
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
public static void SendEnter()
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)VK_RETURN, (UIntPtr)0x001C0001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)VK_RETURN, (UIntPtr)0xC01C0001);
|
||||
}
|
||||
|
||||
public static void SendPause()
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)VK_PAUSE, (UIntPtr)0x00450001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)VK_PAUSE, (UIntPtr)0xC0450001);
|
||||
}
|
||||
|
||||
static Timer _spaceReleaseTimer;
|
||||
static DateTime _spaceSendTime;
|
||||
static int _spaceHoldTimeMilliseconds;
|
||||
static bool _spaceAddShift;
|
||||
static bool _spaceAddW;
|
||||
static bool _spaceAddZ;
|
||||
static bool _spaceAddX;
|
||||
static bool _spaceAddC;
|
||||
|
||||
public static void SendSpace(int msToHoldDown = 0, bool addShift = false, bool addW = false, bool addZ = false, bool addX = false, bool addC = false)
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)VK_SPACE, (UIntPtr)0x00390001);
|
||||
if (msToHoldDown == 0)
|
||||
{
|
||||
if (addShift) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)VK_SHIFT, (UIntPtr)0x002A0001);
|
||||
if (addW) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode('w'), (UIntPtr)0x00110001);
|
||||
if (addZ) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode('z'), (UIntPtr)0x002C0001);
|
||||
if (addX) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode('x'), (UIntPtr)0x002D0001);
|
||||
if (addC) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode('c'), (UIntPtr)0x002E0001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)VK_SPACE, (UIntPtr)0xC0390001);
|
||||
if (addW) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode('w'), (UIntPtr)0xC0110001);
|
||||
if (addZ) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode('z'), (UIntPtr)0xC02C0001);
|
||||
if (addX) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode('x'), (UIntPtr)0xC02D0001);
|
||||
if (addC) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode('c'), (UIntPtr)0xC02E0001);
|
||||
if (addShift) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)VK_SHIFT, (UIntPtr)0xC02A0001);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_spaceReleaseTimer == null)
|
||||
{
|
||||
_spaceReleaseTimer = new Timer();
|
||||
_spaceReleaseTimer.Tick += new EventHandler(SpaceReleaseTimer_Tick);
|
||||
_spaceReleaseTimer.Interval = 1;
|
||||
}
|
||||
|
||||
_spaceSendTime = DateTime.UtcNow;
|
||||
_spaceHoldTimeMilliseconds = msToHoldDown;
|
||||
_spaceAddShift = addShift;
|
||||
_spaceAddW = addW;
|
||||
_spaceAddZ = addZ;
|
||||
_spaceAddX = addX;
|
||||
_spaceAddC = addC;
|
||||
_spaceReleaseTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
static void SpaceReleaseTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (_spaceSendTime.AddMilliseconds(_spaceHoldTimeMilliseconds) <= DateTime.UtcNow)
|
||||
{
|
||||
_spaceReleaseTimer.Stop();
|
||||
if (_spaceAddShift) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)VK_SHIFT, (UIntPtr)0x002A0001);
|
||||
if (_spaceAddW) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode('w'), (UIntPtr)0x00110001);
|
||||
if (_spaceAddZ) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode('z'), (UIntPtr)0x002C0001);
|
||||
if (_spaceAddX) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode('x'), (UIntPtr)0x002D0001);
|
||||
if (_spaceAddC) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode('c'), (UIntPtr)0x002E0001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)VK_SPACE, (UIntPtr)0xC0390001);
|
||||
if (_spaceAddW) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode('w'), (UIntPtr)0xC0110001);
|
||||
if (_spaceAddZ) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode('z'), (UIntPtr)0xC02C0001);
|
||||
if (_spaceAddX) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode('x'), (UIntPtr)0xC02D0001);
|
||||
if (_spaceAddC) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode('c'), (UIntPtr)0xC02E0001);
|
||||
if (_spaceAddShift) User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)VK_SHIFT, (UIntPtr)0xC02A0001);
|
||||
}
|
||||
}
|
||||
|
||||
static Timer _movementReleaseTimer;
|
||||
static DateTime _movementSendTime;
|
||||
static int _movementHoldTimeMilliseconds;
|
||||
static char _movementKey;
|
||||
|
||||
public static void SendMovement(char ch, int msToHoldDown = 0)
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode(ch), (UIntPtr)(0x00000001 + ScanCode(ch) * 0x10000));
|
||||
if (msToHoldDown == 0)
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode(ch), (UIntPtr)(0xC0000001 + ScanCode(ch) * 0x10000));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_movementReleaseTimer == null)
|
||||
{
|
||||
_movementReleaseTimer = new Timer();
|
||||
_movementReleaseTimer.Tick += new EventHandler(MovementReleaseTimer_Tick);
|
||||
_movementReleaseTimer.Interval = 1;
|
||||
}
|
||||
|
||||
_movementSendTime = DateTime.Now;
|
||||
_movementHoldTimeMilliseconds = msToHoldDown;
|
||||
_movementKey = ch;
|
||||
_movementReleaseTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
static void MovementReleaseTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (_movementSendTime.AddMilliseconds(_movementHoldTimeMilliseconds) <= DateTime.Now)
|
||||
{
|
||||
_movementReleaseTimer.Stop();
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode(_movementKey), (UIntPtr)(0xC0000001 + ScanCode(_movementKey) * 0x10000));
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendCntrl(char ch)
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)VK_CONTROL, (UIntPtr)0x001D0001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)CharCode(ch), (UIntPtr)0x00100001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)CharCode(ch), (UIntPtr)0xC0100001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)VK_CONTROL, (UIntPtr)0xC01D0001);
|
||||
}
|
||||
|
||||
public static void SendAltF4()
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_DESTROY, new IntPtr(0), new UIntPtr(0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens/Closes fellowship view
|
||||
/// </summary>
|
||||
public static void SendF4()
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)0x00000073, (UIntPtr)0x003E0001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)0x00000073, (UIntPtr)0xC03E0001);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens/Closes main pack view
|
||||
/// </summary>
|
||||
public static void SendF12()
|
||||
{
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)0x0000007B, (UIntPtr)0x00580001);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)0x0000007B, (UIntPtr)0xC0580001);
|
||||
}
|
||||
|
||||
public static void SendMsg(string msg)
|
||||
{
|
||||
foreach (char ch in msg)
|
||||
{
|
||||
byte code = CharCode(ch);
|
||||
uint lparam = (uint)((ScanCode(ch) << 0x10) | 1);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYDOWN, (IntPtr)code, (UIntPtr)(lparam));
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_KEYUP, (IntPtr)code, (UIntPtr)(0xC0000000 | lparam));
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClickOK()
|
||||
{
|
||||
User32.RECT rect = new User32.RECT();
|
||||
|
||||
User32.GetWindowRect(CoreManager.Current.Decal.Hwnd, ref rect);
|
||||
|
||||
// The reason why we click at both of these positions is some clients will be running windowed, and some windowless. This will hit both locations
|
||||
SendMouseClick(rect.Width / 2, rect.Height / 2 + 18);
|
||||
SendMouseClick(rect.Width / 2, rect.Height / 2 + 25);
|
||||
SendMouseClick(rect.Width / 2, rect.Height / 2 + 31);
|
||||
}
|
||||
|
||||
public static void ClickYes()
|
||||
{
|
||||
User32.RECT rect = new User32.RECT();
|
||||
|
||||
User32.GetWindowRect(CoreManager.Current.Decal.Hwnd, ref rect);
|
||||
|
||||
// 800x600 +32 works, +33 does not work on single/double/tripple line boxes
|
||||
// 1600x1200 +31 works, +32 does not work on single/double/tripple line boxes
|
||||
// The reason why we click at both of these positions is some clients will be running windowed, and some windowless. This will hit both locations
|
||||
SendMouseClick(rect.Width / 2 - 80, rect.Height / 2 + 18);
|
||||
SendMouseClick(rect.Width / 2 - 80, rect.Height / 2 + 25);
|
||||
SendMouseClick(rect.Width / 2 - 80, rect.Height / 2 + 31);
|
||||
}
|
||||
|
||||
public static void ClickNo()
|
||||
{
|
||||
User32.RECT rect = new User32.RECT();
|
||||
|
||||
User32.GetWindowRect(CoreManager.Current.Decal.Hwnd, ref rect);
|
||||
|
||||
// The reason why we click at both of these positions is some clients will be running windowed, and some windowless. This will hit both locations
|
||||
SendMouseClick(rect.Width / 2 + 80, rect.Height / 2 + 18);
|
||||
SendMouseClick(rect.Width / 2 + 80, rect.Height / 2 + 25);
|
||||
SendMouseClick(rect.Width / 2 + 80, rect.Height / 2 + 31);
|
||||
}
|
||||
|
||||
public static void SendMouseClick(int x, int y)
|
||||
{
|
||||
int loc = (y * 0x10000) + x;
|
||||
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_MOUSEMOVE, (IntPtr)0x00000000, (UIntPtr)loc);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_LBUTTONDOWN, (IntPtr)0x00000001, (UIntPtr)loc);
|
||||
User32.PostMessage(CoreManager.Current.Decal.Hwnd, User32.WM_LBUTTONUP, (IntPtr)0x00000000, (UIntPtr)loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Shared/RateLimiter.cs
Normal file
59
Shared/RateLimiter.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
public class RateLimiter
|
||||
{
|
||||
public readonly int MaxNumberOfEvents;
|
||||
private readonly double overPeriodInSeconds;
|
||||
private readonly double targetEventSpacingInSeconds;
|
||||
|
||||
private readonly Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
|
||||
public RateLimiter(int maxNumberOfEvents, TimeSpan overPeriod)
|
||||
{
|
||||
if (maxNumberOfEvents <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(maxNumberOfEvents), $"{nameof(maxNumberOfEvents)} must be greater than 0");
|
||||
|
||||
if (overPeriod <= TimeSpan.Zero)
|
||||
throw new ArgumentOutOfRangeException(nameof(overPeriod), $"{nameof(overPeriod)} must be greater than TimeSpan.Zero");
|
||||
|
||||
MaxNumberOfEvents = maxNumberOfEvents;
|
||||
overPeriodInSeconds = overPeriod.TotalSeconds;
|
||||
|
||||
targetEventSpacingInSeconds = overPeriodInSeconds / maxNumberOfEvents;
|
||||
}
|
||||
|
||||
|
||||
private int numberOfEventsRegistered;
|
||||
|
||||
/// <summary>
|
||||
/// Result > 0 : We're able to meet our target rate and must pause between events.<para />
|
||||
/// Result = 0 : We're running right no time. A new event should be registered without delay.<para />
|
||||
/// Result < 0 : We're running behind. A new event should be registered without delay. We're failing to meet our target rate.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double GetSecondsToWaitBeforeNextEvent()
|
||||
{
|
||||
var elapsedSeconds = stopwatch.Elapsed.TotalSeconds;
|
||||
|
||||
return ((targetEventSpacingInSeconds * numberOfEventsRegistered) - elapsedSeconds);
|
||||
}
|
||||
|
||||
public void RegisterEvent()
|
||||
{
|
||||
numberOfEventsRegistered++;
|
||||
|
||||
var elapsedSeconds = stopwatch.Elapsed.TotalSeconds;
|
||||
|
||||
if (numberOfEventsRegistered > MaxNumberOfEvents || elapsedSeconds > overPeriodInSeconds)
|
||||
{
|
||||
numberOfEventsRegistered = 1;
|
||||
|
||||
stopwatch.Reset();
|
||||
stopwatch.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Shared/SerializableDictionary.cs
Normal file
81
Shared/SerializableDictionary.cs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
[XmlRoot("dictionary")]
|
||||
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
|
||||
{
|
||||
public System.Xml.Schema.XmlSchema GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ReadXml(System.Xml.XmlReader reader)
|
||||
{
|
||||
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
|
||||
|
||||
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
|
||||
|
||||
bool wasEmpty = reader.IsEmptyElement;
|
||||
|
||||
reader.Read();
|
||||
|
||||
if (wasEmpty)
|
||||
return;
|
||||
|
||||
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
|
||||
{
|
||||
reader.ReadStartElement("item");
|
||||
|
||||
reader.ReadStartElement("key");
|
||||
|
||||
TKey key = (TKey)keySerializer.Deserialize(reader);
|
||||
|
||||
reader.ReadEndElement();
|
||||
|
||||
reader.ReadStartElement("value");
|
||||
|
||||
TValue value = (TValue)valueSerializer.Deserialize(reader);
|
||||
|
||||
reader.ReadEndElement();
|
||||
|
||||
this.Add(key, value);
|
||||
|
||||
reader.ReadEndElement();
|
||||
|
||||
reader.MoveToContent();
|
||||
}
|
||||
|
||||
reader.ReadEndElement();
|
||||
}
|
||||
|
||||
public void WriteXml(System.Xml.XmlWriter writer)
|
||||
{
|
||||
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
|
||||
|
||||
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
|
||||
|
||||
foreach (TKey key in this.Keys)
|
||||
{
|
||||
writer.WriteStartElement("item");
|
||||
|
||||
writer.WriteStartElement("key");
|
||||
|
||||
keySerializer.Serialize(writer, key);
|
||||
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteStartElement("value");
|
||||
|
||||
TValue value = this[key];
|
||||
|
||||
valueSerializer.Serialize(writer, value);
|
||||
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Shared/Settings/Setting.cs
Normal file
59
Shared/Settings/Setting.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
|
||||
namespace Mag.Shared.Settings
|
||||
{
|
||||
class Setting<T>
|
||||
{
|
||||
public readonly string Xpath;
|
||||
|
||||
public readonly string Description;
|
||||
|
||||
public readonly T DefaultValue;
|
||||
|
||||
private T value;
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return value;
|
||||
}
|
||||
set
|
||||
{
|
||||
// If we're setting it to the value its already at, don't continue with the set.
|
||||
if (Object.Equals(this.value, value))
|
||||
return;
|
||||
|
||||
// The value differs, set it.
|
||||
this.value = value;
|
||||
|
||||
StoreValueInConfigFile();
|
||||
|
||||
if (Changed != null)
|
||||
Changed(this);
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<Setting<T>> Changed;
|
||||
|
||||
public Setting(string xpath, string description = null, T defaultValue = default(T))
|
||||
{
|
||||
Xpath = xpath;
|
||||
|
||||
Description = description;
|
||||
|
||||
DefaultValue = defaultValue;
|
||||
|
||||
LoadValueFromConfig(defaultValue);
|
||||
}
|
||||
|
||||
void LoadValueFromConfig(T defaultValue)
|
||||
{
|
||||
value = SettingsFile.GetSetting(Xpath, defaultValue);
|
||||
}
|
||||
|
||||
void StoreValueInConfigFile()
|
||||
{
|
||||
SettingsFile.PutSetting(Xpath, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
210
Shared/Settings/SettingsFile.cs
Normal file
210
Shared/Settings/SettingsFile.cs
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace Mag.Shared.Settings
|
||||
{
|
||||
static class SettingsFile
|
||||
{
|
||||
internal static readonly XmlDocument XmlDocument = new XmlDocument();
|
||||
|
||||
static string _documentPath;
|
||||
|
||||
static string _rootNodeName = "Settings";
|
||||
|
||||
static SettingsFile()
|
||||
{
|
||||
ReloadXmlDocument();
|
||||
}
|
||||
|
||||
public static void Init(string filePath, string rootNode = "Settings")
|
||||
{
|
||||
_documentPath = filePath;
|
||||
|
||||
_rootNodeName = rootNode;
|
||||
|
||||
ReloadXmlDocument();
|
||||
}
|
||||
|
||||
public static void ReloadXmlDocument()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!String.IsNullOrEmpty(_documentPath) && File.Exists(_documentPath))
|
||||
XmlDocument.Load(_documentPath);
|
||||
else
|
||||
XmlDocument.LoadXml("<" + _rootNodeName + "></" + _rootNodeName + ">");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
|
||||
XmlDocument.LoadXml("<" + _rootNodeName + "></" + _rootNodeName + ">");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveXmlDocument()
|
||||
{
|
||||
XmlDocument.Save(_documentPath);
|
||||
}
|
||||
|
||||
public static T GetSetting<T>(string xPath, T defaultValue = default(T))
|
||||
{
|
||||
XmlNode xmlNode = XmlDocument.SelectSingleNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
if (xmlNode != null)
|
||||
{
|
||||
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
|
||||
|
||||
if (converter.CanConvertFrom(typeof(string)))
|
||||
return (T)converter.ConvertFromString(xmlNode.InnerText);
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static void PutSetting<T>(string xPath, T value)
|
||||
{
|
||||
// Before we save a setting, we reload the document to make sure we don't overwrite settings saved from another session.
|
||||
ReloadXmlDocument();
|
||||
|
||||
XmlNode xmlNode = XmlDocument.SelectSingleNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
if (xmlNode == null)
|
||||
xmlNode = createMissingNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
|
||||
|
||||
if (converter.CanConvertTo(typeof(string)))
|
||||
{
|
||||
string result = converter.ConvertToString(value);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
xmlNode.InnerText = result;
|
||||
|
||||
XmlDocument.Save(_documentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static XmlNode createMissingNode(string xPath)
|
||||
{
|
||||
string[] xPathSections = xPath.Split('/');
|
||||
|
||||
string currentXPath = "";
|
||||
|
||||
XmlNode currentNode = XmlDocument.SelectSingleNode(_rootNodeName);
|
||||
|
||||
foreach (string xPathSection in xPathSections)
|
||||
{
|
||||
currentXPath += xPathSection;
|
||||
|
||||
XmlNode testNode = XmlDocument.SelectSingleNode(currentXPath);
|
||||
|
||||
if (testNode == null)
|
||||
{
|
||||
if (currentNode != null)
|
||||
currentNode.InnerXml += "<" + xPathSection + "></" + xPathSection + ">";
|
||||
}
|
||||
|
||||
currentNode = XmlDocument.SelectSingleNode(currentXPath);
|
||||
|
||||
currentXPath += "/";
|
||||
}
|
||||
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
public static IList<string> GetChilderenInnerTexts(string xPath)
|
||||
{
|
||||
XmlNode xmlNode = XmlDocument.SelectSingleNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
Collection<string> collection = new Collection<string>();
|
||||
|
||||
if (xmlNode != null)
|
||||
{
|
||||
foreach (XmlNode childNode in xmlNode.ChildNodes)
|
||||
collection.Add(childNode.InnerText);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static void SetNodeChilderen(string xPath, string childNodeName, IList<string> innerTexts)
|
||||
{
|
||||
// Before we save a setting, we reload the document to make sure we don't overwrite settings saved from another session.
|
||||
ReloadXmlDocument();
|
||||
|
||||
XmlNode parentNode = XmlDocument.SelectSingleNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
if (parentNode == null)
|
||||
{
|
||||
if (innerTexts.Count == 0)
|
||||
return;
|
||||
|
||||
parentNode = createMissingNode(_rootNodeName + "/" + xPath);
|
||||
}
|
||||
|
||||
parentNode.RemoveAll();
|
||||
|
||||
if (innerTexts.Count == 0)
|
||||
{
|
||||
XmlDocument.Save(_documentPath);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string innerText in innerTexts)
|
||||
{
|
||||
XmlNode childNode = parentNode.AppendChild(XmlDocument.CreateElement(childNodeName));
|
||||
|
||||
childNode.InnerText = innerText;
|
||||
}
|
||||
|
||||
XmlDocument.Save(_documentPath);
|
||||
}
|
||||
|
||||
public static XmlNode GetNode(string xPath, bool createIfNull = false)
|
||||
{
|
||||
var node = XmlDocument.SelectSingleNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
if (node == null && createIfNull)
|
||||
node = createMissingNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public static void SetNodeChilderen(string xPath, string childNodeName, Collection<Dictionary<string, string>> childNodeAttributes)
|
||||
{
|
||||
// Before we save a setting, we reload the document to make sure we don't overwrite settings saved from another session.
|
||||
ReloadXmlDocument();
|
||||
|
||||
XmlNode parentNode = XmlDocument.SelectSingleNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
if (parentNode == null)
|
||||
parentNode = createMissingNode(_rootNodeName + "/" + xPath);
|
||||
|
||||
if (parentNode.HasChildNodes)
|
||||
parentNode.RemoveAll();
|
||||
|
||||
foreach (Dictionary<string, string> dictionary in childNodeAttributes)
|
||||
{
|
||||
XmlNode childNode = parentNode.AppendChild(XmlDocument.CreateElement(childNodeName));
|
||||
|
||||
foreach (KeyValuePair<string, string> pair in dictionary)
|
||||
{
|
||||
XmlAttribute attribute = XmlDocument.CreateAttribute(pair.Key);
|
||||
attribute.Value = pair.Value;
|
||||
|
||||
if (childNode.Attributes != null)
|
||||
childNode.Attributes.Append(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
XmlDocument.Save(_documentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Shared/SortableBindingList.cs
Normal file
100
Shared/SortableBindingList.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
class SortableBindingList<T> : BindingList<T> where T : class
|
||||
{
|
||||
protected override bool SupportsSortingCore { get { return true; } }
|
||||
|
||||
private bool isSorted;
|
||||
private ListSortDirection sortDirection;
|
||||
private PropertyDescriptor sortProperty;
|
||||
|
||||
protected override bool IsSortedCore { get { return isSorted; } }
|
||||
|
||||
protected override ListSortDirection SortDirectionCore { get { return sortDirection; } }
|
||||
|
||||
protected override PropertyDescriptor SortPropertyCore { get { return sortProperty; } }
|
||||
|
||||
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
|
||||
{
|
||||
sortProperty = prop;
|
||||
sortDirection = direction;
|
||||
|
||||
List<T> items = (List<T>)Items;
|
||||
|
||||
items.Sort(delegate(T lhs, T rhs)
|
||||
{
|
||||
isSorted = true;
|
||||
object lhsValue = lhs == null ? null : prop.GetValue(lhs);
|
||||
object rhsValue = rhs == null ? null : prop.GetValue(rhs);
|
||||
int result = Comparer.Default.Compare(lhsValue, rhsValue);
|
||||
|
||||
if (direction == ListSortDirection.Descending)
|
||||
result = -result;
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void RemoveSortCore()
|
||||
{
|
||||
sortDirection = ListSortDirection.Ascending;
|
||||
sortProperty = null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sorts using the default IComparer of T
|
||||
/// </summary>
|
||||
public void Sort()
|
||||
{
|
||||
sort(null, null);
|
||||
}
|
||||
|
||||
public void Sort(IComparer<T> comparer)
|
||||
{
|
||||
sort(comparer, null);
|
||||
}
|
||||
|
||||
public void Sort(Comparison<T> comparison)
|
||||
{
|
||||
sort(null, comparison);
|
||||
}
|
||||
|
||||
private void sort(IComparer<T> comparer, Comparison<T> comparison)
|
||||
{
|
||||
sortProperty = null;
|
||||
sortDirection = ListSortDirection.Ascending;
|
||||
|
||||
//Extract items and sort separately
|
||||
List<T> sortList = new List<T>();
|
||||
foreach (var item in this)
|
||||
sortList.Add(item);
|
||||
|
||||
if (comparison == null)
|
||||
sortList.Sort(comparer);
|
||||
else
|
||||
sortList.Sort(comparison);
|
||||
|
||||
//Disable notifications, rebuild, and re-enable notifications
|
||||
bool oldRaise = RaiseListChangedEvents;
|
||||
RaiseListChangedEvents = false;
|
||||
|
||||
try
|
||||
{
|
||||
ClearItems();
|
||||
sortList.ForEach(item => Add(item));
|
||||
}
|
||||
finally
|
||||
{
|
||||
RaiseListChangedEvents = oldRaise;
|
||||
ResetBindings();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
188
Shared/Spells/Spell.cs
Normal file
188
Shared/Spells/Spell.cs
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
|
||||
namespace Mag.Shared.Spells
|
||||
{
|
||||
/// <summary>
|
||||
/// Use GetSpell() to intialize a Spell object
|
||||
/// </summary>
|
||||
public class Spell
|
||||
{
|
||||
public readonly int Id;
|
||||
public readonly string Name;
|
||||
public readonly int Difficulty;
|
||||
public readonly int Duration;
|
||||
public readonly int Family;
|
||||
|
||||
public enum BuffLevels
|
||||
{
|
||||
None,
|
||||
|
||||
I,
|
||||
II,
|
||||
III,
|
||||
IV,
|
||||
V,
|
||||
VI,
|
||||
VII,
|
||||
VIII,
|
||||
}
|
||||
public readonly BuffLevels BuffLevel;
|
||||
|
||||
public enum CantripLevels
|
||||
{
|
||||
None,
|
||||
|
||||
Feeble,
|
||||
Minor,
|
||||
Lesser,
|
||||
Moderate,
|
||||
Inner,
|
||||
Major,
|
||||
Epic,
|
||||
Legendary,
|
||||
}
|
||||
public readonly CantripLevels CantripLevel;
|
||||
|
||||
public Spell(int id, string name, int difficulty, int duration, int family)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Difficulty = difficulty;
|
||||
Duration = duration;
|
||||
Family = family;
|
||||
|
||||
if (name.EndsWith(" I"))
|
||||
BuffLevel = BuffLevels.I;
|
||||
else if (name.EndsWith(" II"))
|
||||
BuffLevel = BuffLevels.II;
|
||||
else if (name.EndsWith(" III"))
|
||||
BuffLevel = BuffLevels.III;
|
||||
else if (name.EndsWith(" IV"))
|
||||
BuffLevel = BuffLevels.IV;
|
||||
else if (name.EndsWith(" V"))
|
||||
BuffLevel = BuffLevels.V;
|
||||
else if (name.EndsWith(" VI"))
|
||||
BuffLevel = BuffLevels.VI;
|
||||
else if (name.EndsWith(" VII")) // This doesn't pick up every lvl 7
|
||||
BuffLevel = BuffLevels.VII;
|
||||
else if (name.StartsWith("Incantation ") || name.StartsWith("Aura of Incantation "))
|
||||
BuffLevel = BuffLevels.VIII;
|
||||
|
||||
if (name.StartsWith("Feeble "))
|
||||
CantripLevel = CantripLevels.Feeble;
|
||||
else if (name.StartsWith("Minor "))
|
||||
CantripLevel = CantripLevels.Minor;
|
||||
else if (name.StartsWith("Lesser "))
|
||||
CantripLevel = CantripLevels.Lesser;
|
||||
else if (name.StartsWith("Moderate "))
|
||||
CantripLevel = CantripLevels.Moderate;
|
||||
else if (name.StartsWith("Inner ") && name != "Inner Calm")
|
||||
CantripLevel = CantripLevels.Inner;
|
||||
else if (name.StartsWith("Major "))
|
||||
CantripLevel = CantripLevels.Major;
|
||||
else if (name.StartsWith("Epic "))
|
||||
CantripLevel = CantripLevels.Epic;
|
||||
else if (name.StartsWith("Legendary "))
|
||||
CantripLevel = CantripLevels.Legendary;
|
||||
|
||||
// Try to determine if this is a lvl x
|
||||
if (BuffLevel == BuffLevels.None && CantripLevel == CantripLevels.None)
|
||||
{
|
||||
// These spells don't have levels
|
||||
if (name.StartsWith("Prodigal ") || // Rares
|
||||
name.StartsWith("Cloaked in ") || name.StartsWith("Shroud of ")) // Cloaks
|
||||
return;
|
||||
|
||||
if (difficulty == 1 && duration == 1800)
|
||||
BuffLevel = BuffLevels.I;
|
||||
if (difficulty == 50 && duration == -1 && name.StartsWith("Evaporate "))
|
||||
BuffLevel = BuffLevels.II;
|
||||
|
||||
if (difficulty == 50 && duration == 1800)
|
||||
BuffLevel = BuffLevels.II;
|
||||
if (difficulty == 100 && duration == -1 && name.StartsWith("Extinguish "))
|
||||
BuffLevel = BuffLevels.II;
|
||||
|
||||
if (difficulty == 100 && duration == 1800)
|
||||
BuffLevel = BuffLevels.III;
|
||||
if (difficulty == 150 && duration == -1 && name.StartsWith("Cleanse "))
|
||||
BuffLevel = BuffLevels.III;
|
||||
|
||||
if (difficulty == 150 && duration == 1800)
|
||||
BuffLevel = BuffLevels.IV;
|
||||
if (difficulty == 200 && duration == -1 && name.StartsWith("Devour "))
|
||||
BuffLevel = BuffLevels.IV;
|
||||
|
||||
if (difficulty == 200 && duration == 1800)
|
||||
BuffLevel = BuffLevels.V;
|
||||
if (difficulty == 250 && duration == -1 && name.StartsWith("Purge "))
|
||||
BuffLevel = BuffLevels.V;
|
||||
|
||||
if (difficulty == 200 && duration == -1 && !name.StartsWith("Devour ")) // Ring spells
|
||||
BuffLevel = BuffLevels.VI;
|
||||
if (difficulty == 250 && duration == 2700)
|
||||
BuffLevel = BuffLevels.VI;
|
||||
if (difficulty == 300 && duration == -1 && name.StartsWith("Nullify "))
|
||||
BuffLevel = BuffLevels.VI;
|
||||
|
||||
if (difficulty == 300 && duration == -1 && !name.StartsWith("Nullify "))
|
||||
BuffLevel = BuffLevels.VII;
|
||||
if (difficulty == 300 && duration == 240)
|
||||
BuffLevel = BuffLevels.VII;
|
||||
if (difficulty == 300 && duration == 3600)
|
||||
BuffLevel = BuffLevels.VII;
|
||||
if (difficulty == 325 && duration == -1)
|
||||
BuffLevel = BuffLevels.VII;
|
||||
if (difficulty == 325 && duration == 240)
|
||||
BuffLevel = BuffLevels.VII;
|
||||
if (difficulty == 350 && duration == -1)
|
||||
BuffLevel = BuffLevels.VII;
|
||||
|
||||
if (difficulty == 400 && duration == 5400)
|
||||
BuffLevel = BuffLevels.VIII;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsOfSameFamilyAndGroup(Spell compareSpell)
|
||||
{
|
||||
if (Family != compareSpell.Family)
|
||||
return false;
|
||||
|
||||
if (BuffLevel != 0 && compareSpell.BuffLevel != 0)
|
||||
return true;
|
||||
|
||||
if (CantripLevel != 0 && compareSpell.CantripLevel != 0)
|
||||
return true;
|
||||
|
||||
// Are both spells are of an unkown group?
|
||||
if (BuffLevel == 0 && compareSpell.BuffLevel == 0 && CantripLevel == 0 && compareSpell.CantripLevel == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsSameOrSurpasses(Spell compareSpell)
|
||||
{
|
||||
return (this == compareSpell || Surpasses(compareSpell));
|
||||
}
|
||||
|
||||
public bool Surpasses(Spell compareSpell)
|
||||
{
|
||||
if (Family == 0 || Family != compareSpell.Family)
|
||||
return false;
|
||||
|
||||
if (BuffLevel > 0 && compareSpell.BuffLevel > 0 && BuffLevel > compareSpell.BuffLevel)
|
||||
return true;
|
||||
|
||||
if (CantripLevel > 0 && compareSpell.CantripLevel > 0 && CantripLevel > compareSpell.CantripLevel)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
149
Shared/Spells/SpellTools.cs
Normal file
149
Shared/Spells/SpellTools.cs
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Mag.Shared.Spells
|
||||
{
|
||||
public static class SpellTools
|
||||
{
|
||||
static readonly List<string> SpellTableHeader = new List<string>();
|
||||
static readonly Collection<string[]> SpellTable = new Collection<string[]>();
|
||||
|
||||
static readonly Dictionary<int, Spell> SpellsById = new Dictionary<int, Spell>();
|
||||
|
||||
static SpellTools()
|
||||
{
|
||||
var resourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||
|
||||
if (resourceNames.Length == 0)
|
||||
return;
|
||||
|
||||
var rootNameSpace = resourceNames[0].Substring(0, resourceNames[0].IndexOf('.'));
|
||||
|
||||
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(rootNameSpace + ".Shared.Spells.Spells.csv"))
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
SpellTableHeader = new List<string>(reader.ReadLine().Split(','));
|
||||
|
||||
while (!reader.EndOfStream)
|
||||
SpellTable.Add(reader.ReadLine().Split(','));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will return null if no spell was found.
|
||||
/// </summary>
|
||||
public static Spell GetSpell(int id)
|
||||
{
|
||||
if (SpellsById.TryGetValue(id, out var spell))
|
||||
return spell;
|
||||
|
||||
int idIndex = SpellTableHeader.IndexOf("Id");
|
||||
|
||||
foreach (string[] line in SpellTable)
|
||||
{
|
||||
if (line[idIndex] == id.ToString(CultureInfo.InvariantCulture))
|
||||
return GetSpell(line);
|
||||
}
|
||||
|
||||
//throw new ArgumentException("Spell of id: " + id + " not found in Spells.csv");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will return null if no spell was found.
|
||||
/// </summary>
|
||||
public static Spell GetSpell(string name)
|
||||
{
|
||||
foreach (var kvp in SpellsById)
|
||||
{
|
||||
if (String.Equals(kvp.Value.Name, name, StringComparison.OrdinalIgnoreCase))
|
||||
return kvp.Value;
|
||||
}
|
||||
|
||||
int nameIndex = SpellTableHeader.IndexOf("Name");
|
||||
|
||||
foreach (string[] line in SpellTable)
|
||||
{
|
||||
if (String.Equals(line[nameIndex], name, StringComparison.OrdinalIgnoreCase))
|
||||
return GetSpell(line);
|
||||
}
|
||||
|
||||
//throw new ArgumentException("Spell of name: " + name + " not found in Spells.csv");
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Spell GetSpell(string[] splitLine)
|
||||
{
|
||||
int idIndex = SpellTableHeader.IndexOf("Id");
|
||||
int nameIndex = SpellTableHeader.IndexOf("Name");
|
||||
int difficultyIndex = SpellTableHeader.IndexOf("Difficulty");
|
||||
int durationIndex = SpellTableHeader.IndexOf("Duration");
|
||||
int familyIndex = SpellTableHeader.IndexOf("Family");
|
||||
|
||||
int id;
|
||||
int.TryParse(splitLine[idIndex], out id);
|
||||
|
||||
string name = splitLine[nameIndex];
|
||||
|
||||
int difficulty;
|
||||
int.TryParse(splitLine[difficultyIndex], out difficulty);
|
||||
|
||||
int duration;
|
||||
int.TryParse(splitLine[durationIndex], out duration);
|
||||
|
||||
int family;
|
||||
int.TryParse(splitLine[familyIndex], out family);
|
||||
|
||||
var spell = new Spell(id, name, difficulty, duration, family);
|
||||
|
||||
if (!SpellsById.ContainsKey(spell.Id))
|
||||
SpellsById.Add(spell.Id, spell);
|
||||
|
||||
return spell;
|
||||
}
|
||||
|
||||
public static bool IsAKnownSpell(int id)
|
||||
{
|
||||
if (SpellsById.ContainsKey(id))
|
||||
return true;
|
||||
|
||||
int idIndex = SpellTableHeader.IndexOf("Id");
|
||||
|
||||
foreach (string[] line in SpellTable)
|
||||
{
|
||||
if (line[idIndex] == id.ToString(CultureInfo.InvariantCulture))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsAKnownSpell(string name)
|
||||
{
|
||||
foreach (var kvp in SpellsById)
|
||||
{
|
||||
if (String.Equals(kvp.Value.Name, name, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
|
||||
int nameIndex = SpellTableHeader.IndexOf("Name");
|
||||
|
||||
foreach (string[] line in SpellTable)
|
||||
{
|
||||
if (line[nameIndex] == name)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
6267
Shared/Spells/Spells.csv
Normal file
6267
Shared/Spells/Spells.csv
Normal file
File diff suppressed because it is too large
Load diff
81
Shared/User32.cs
Normal file
81
Shared/User32.cs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
public static class User32
|
||||
{
|
||||
public const int WM_ACTIVATE = 0x0006;
|
||||
public const int WM_SETFOCUS = 0x0007;
|
||||
public const int WM_KILLFOCUS = 0x0008;
|
||||
public const int WM_ACTIVATEAPP = 0x001C;
|
||||
public const int WM_DESTROY = 0x0002;
|
||||
public const int WM_KEYDOWN = 0x0100;
|
||||
public const int WM_KEYUP = 0x0101;
|
||||
public const int WM_CHAR = 0x0102;
|
||||
|
||||
public const int WM_MOUSEMOVE = 0x0200;
|
||||
public const int WM_LBUTTONDOWN = 0x0201;
|
||||
public const int WM_LBUTTONUP = 0x0202;
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool PostMessage(IntPtr hhwnd, uint msg, IntPtr wparam, UIntPtr lparam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetCursorPos(out System.Drawing.Point lpPoint);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
|
||||
public int Width { get { return Right - Left; } }
|
||||
public int Height { get { return Bottom - Top; } }
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
|
||||
|
||||
//Gets window attributes
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
|
||||
//Sets window attributes
|
||||
/// <summary>
|
||||
/// Changes an attribute of the specified window. The function also sets the 32-bit (long) value at the specified offset into the extra window memory.
|
||||
/// </summary>
|
||||
/// <param name="hWnd">A handle to the window and, indirectly, the class to which the window belongs..</param>
|
||||
/// <param name="nIndex">The zero-based offset to the value to be set. Valid values are in the range zero through the number of bytes of extra window memory, minus the size of an integer. To set any other value, specify one of the following values: GWL_EXSTYLE, GWL_HINSTANCE, GWL_ID, GWL_STYLE, GWL_USERDATA, GWL_WNDPROC </param>
|
||||
/// <param name="dwNewLong">The replacement value.</param>
|
||||
/// <returns>If the function succeeds, the return value is the previous value of the specified 32-bit integer.
|
||||
/// If the function fails, the return value is zero. To get extended error information, call GetLastError. </returns>
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||
|
||||
/// <summary>
|
||||
/// The MoveWindow function changes the position and dimensions of the specified window. For a top-level window, the position and dimensions are relative to the upper-left corner of the screen. For a child window, they are relative to the upper-left corner of the parent window's client area.
|
||||
/// </summary>
|
||||
/// <param name="hWnd">Handle to the window.</param>
|
||||
/// <param name="x">Specifies the new position of the left side of the window.</param>
|
||||
/// <param name="y">Specifies the new position of the top of the window.</param>
|
||||
/// <param name="nWidth">Specifies the new width of the window.</param>
|
||||
/// <param name="nHeight">Specifies the new height of the window.</param>
|
||||
/// <param name="bRepaint">Specifies whether the window is to be repainted. If this parameter is TRUE, the window receives a message. If the parameter is FALSE, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of moving a child window.</param>
|
||||
/// <returns>If the function succeeds, the return value is nonzero.
|
||||
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para></returns>
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint);
|
||||
|
||||
|
||||
public const int SW_MINIMIZE = 6;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
}
|
||||
}
|
||||
415
Shared/Util.cs
Normal file
415
Shared/Util.cs
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Decal.Adapter;
|
||||
using Decal.Adapter.Wrappers;
|
||||
|
||||
using Decal.Filters;
|
||||
|
||||
namespace Mag.Shared
|
||||
{
|
||||
public static class Util
|
||||
{
|
||||
public static CoordsObject GetCoords(int landBlock, double x, double y)
|
||||
{
|
||||
int ilbLng = (int)(Math.Floor(landBlock / (double)(0x1000000))) & 0xFF;
|
||||
int ilbLat = (int)(Math.Floor(landBlock / (double)(0x10000))) & 0xFF;
|
||||
|
||||
double latOut = ((double)(ilbLat - 0x7F) * 192 + y - 84) / 240;
|
||||
double lngOut = ((double)(ilbLng - 0x7F) * 192 + x - 84) / 240;
|
||||
|
||||
return new CoordsObject(latOut, lngOut);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function will return the distance in meters.
|
||||
/// The manual distance units are in map compass units, while the distance units used in the UI are meters.
|
||||
/// In AC there are 240 meters in a kilometer; thus if you set your attack range to 1 in the UI it
|
||||
/// will showas 0.00416666666666667in the manual options (0.00416666666666667 being 1/240).
|
||||
/// </summary>
|
||||
/// <param name="obj1"></param>
|
||||
/// <param name="obj2"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Object passed with an Id of 0</exception>
|
||||
public static double GetDistance(WorldObject obj1, WorldObject obj2)
|
||||
{
|
||||
if (obj1.Id == 0)
|
||||
throw new ArgumentOutOfRangeException("obj1", "Object passed with an Id of 0");
|
||||
|
||||
if (obj2.Id == 0)
|
||||
throw new ArgumentOutOfRangeException("obj2", "Object passed with an Id of 0");
|
||||
|
||||
return CoreManager.Current.WorldFilter.Distance(obj1.Id, obj2.Id) * 240;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function will return the distance in meters.
|
||||
/// The manual distance units are in map compass units, while the distance units used in the UI are meters.
|
||||
/// In AC there are 240 meters in a kilometer; thus if you set your attack range to 1 in the UI it
|
||||
/// will showas 0.00416666666666667in the manual options (0.00416666666666667 being 1/240).
|
||||
/// </summary>
|
||||
/// <param name="destObj"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">CharacterFilder.Id or Object passed with an Id of 0</exception>
|
||||
public static double GetDistanceFromPlayer(WorldObject destObj)
|
||||
{
|
||||
if (CoreManager.Current.CharacterFilter.Id == 0)
|
||||
throw new ArgumentOutOfRangeException("destObj", "CharacterFilter.Id of 0");
|
||||
|
||||
if (destObj.Id == 0)
|
||||
throw new ArgumentOutOfRangeException("destObj", "Object passed with an Id of 0");
|
||||
|
||||
return CoreManager.Current.WorldFilter.Distance(CoreManager.Current.CharacterFilter.Id, destObj.Id) * 240;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest object found of the specified object class. If no object is found, null is returned.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static WorldObject GetClosestObject(ObjectClass objectClass)
|
||||
{
|
||||
WorldObject closest = null;
|
||||
|
||||
foreach (WorldObject obj in CoreManager.Current.WorldFilter.GetLandscape())
|
||||
{
|
||||
if (obj.ObjectClass != objectClass)
|
||||
continue;
|
||||
|
||||
if (closest == null || GetDistanceFromPlayer(obj) < GetDistanceFromPlayer(closest))
|
||||
closest = obj;
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
public static WorldObject GetClosestObject(string objectName, bool partialMatch = false)
|
||||
{
|
||||
WorldObject closest = null;
|
||||
|
||||
foreach (WorldObject obj in CoreManager.Current.WorldFilter.GetLandscape())
|
||||
{
|
||||
if (!partialMatch && String.Compare(obj.Name, objectName, StringComparison.OrdinalIgnoreCase) != 0)
|
||||
continue;
|
||||
if (partialMatch && !obj.Name.ToLower().Contains(objectName.ToLower()))
|
||||
continue;
|
||||
|
||||
if (closest == null || GetDistanceFromPlayer(obj) < GetDistanceFromPlayer(closest))
|
||||
closest = obj;
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="container"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static int GetFreePackSlots(int container)
|
||||
{
|
||||
if (container == 0)
|
||||
throw new ArgumentOutOfRangeException("container", "Invalid container passed, id of 0.");
|
||||
|
||||
WorldObject target = CoreManager.Current.WorldFilter[container];
|
||||
|
||||
if (target == null || (target.ObjectClass != ObjectClass.Player && target.ObjectClass != ObjectClass.Container))
|
||||
throw new ArgumentOutOfRangeException("container", "Invalid container passed, null reference");
|
||||
|
||||
int slotsFilled = 0;
|
||||
|
||||
foreach (WorldObject obj in CoreManager.Current.WorldFilter.GetByContainer(container))
|
||||
{
|
||||
if (obj.ObjectClass == ObjectClass.Container || obj.ObjectClass == ObjectClass.Foci || obj.Values(LongValueKey.EquippedSlots) != 0)
|
||||
continue;
|
||||
|
||||
slotsFilled++;
|
||||
}
|
||||
|
||||
return CoreManager.Current.WorldFilter[container].Values(LongValueKey.ItemSlots) - slotsFilled;
|
||||
}
|
||||
|
||||
// http://www.regular-expressions.info/reference.html
|
||||
|
||||
// Local Chat
|
||||
// You say, "test"
|
||||
private static readonly Regex YouSay = new Regex("^You say, \"(?<msg>.*)\"$");
|
||||
// <Tell:IIDString:1343111160:PlayerName>PlayerName<\Tell> says, "asdf"
|
||||
private static readonly Regex PlayerSaysLocal = new Regex("^<Tell:IIDString:[0-9]+:(?<name>[\\w\\s'-]+)>[\\w\\s'-]+<\\\\Tell> says, \"(?<msg>.*)\"$");
|
||||
//
|
||||
// Master Arbitrator says, "Arena Three is now available for new warriors!"
|
||||
private static readonly Regex NpcSays = new Regex("^(?<name>[\\w\\s'-]+) says, \"(?<msg>.*)\"$");
|
||||
|
||||
// Channel Chat
|
||||
// [Allegiance] <Tell:IIDString:0:PlayerName>PlayerName<\Tell> says, "kk"
|
||||
// [General] <Tell:IIDString:0:PlayerName>PlayerName<\Tell> says, "asdfasdfasdf"
|
||||
// [Fellowship] <Tell:IIDString:0:PlayerName>PlayerName<\Tell> says, "test"
|
||||
private static readonly Regex PlayerSaysChannel = new Regex("^\\[(?<channel>.+)]+ <Tell:IIDString:[0-9]+:(?<name>[\\w\\s'-]+)>[\\w\\s'-]+<\\\\Tell> says, \"(?<msg>.*)\"$");
|
||||
//
|
||||
// [Fellowship] <Tell:IIDString:0:Master Arbitrator>Master Arbitrator<\Tell> says, "Good Luck!"
|
||||
|
||||
// Tells
|
||||
// You tell PlayerName, "test"
|
||||
private static readonly Regex YouTell = new Regex("^You tell .+, \"(?<msg>.*)\"$");
|
||||
// <Tell:IIDString:1343111160:PlayerName>PlayerName<\Tell> tells you, "test"
|
||||
private static readonly Regex PlayerTellsYou = new Regex("^<Tell:IIDString:[0-9]+:(?<name>[\\w\\s'-]+)>[\\w\\s'-]+<\\\\Tell> tells you, \"(?<msg>.*)\"$");
|
||||
//
|
||||
// Master Arbitrator tells you, "You fought in the Colosseum's Arenas too recently. I cannot reward you for 4s."
|
||||
private static readonly Regex NpcTellsYou = new Regex("^(?<name>[\\w\\s'-]+) tells you, \"(?<msg>.*)\"$");
|
||||
|
||||
[Flags]
|
||||
public enum ChatFlags : byte
|
||||
{
|
||||
None = 0x00,
|
||||
|
||||
PlayerSaysLocal = 0x01,
|
||||
PlayerSaysChannel = 0x02,
|
||||
YouSay = 0x04,
|
||||
|
||||
PlayerTellsYou = 0x08,
|
||||
YouTell = 0x10,
|
||||
|
||||
NpcSays = 0x20,
|
||||
NpcTellsYou = 0x40,
|
||||
|
||||
All = 0xFF,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the text was said by a person, envoy, npc, monster, etc..
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="chatFlags"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsChat(string text, ChatFlags chatFlags = ChatFlags.All)
|
||||
{
|
||||
if ((chatFlags & ChatFlags.PlayerSaysLocal) == ChatFlags.PlayerSaysLocal && PlayerSaysLocal.IsMatch(text))
|
||||
return true;
|
||||
|
||||
if ((chatFlags & ChatFlags.PlayerSaysChannel) == ChatFlags.PlayerSaysChannel && PlayerSaysChannel.IsMatch(text))
|
||||
return true;
|
||||
|
||||
if ((chatFlags & ChatFlags.YouSay) == ChatFlags.YouSay && YouSay.IsMatch(text))
|
||||
return true;
|
||||
|
||||
|
||||
if ((chatFlags & ChatFlags.PlayerTellsYou) == ChatFlags.PlayerTellsYou && PlayerTellsYou.IsMatch(text))
|
||||
return true;
|
||||
|
||||
if ((chatFlags & ChatFlags.YouTell) == ChatFlags.YouTell && YouTell.IsMatch(text))
|
||||
return true;
|
||||
|
||||
|
||||
if ((chatFlags & ChatFlags.NpcSays) == ChatFlags.NpcSays && NpcSays.IsMatch(text))
|
||||
return true;
|
||||
|
||||
if ((chatFlags & ChatFlags.NpcTellsYou) == ChatFlags.NpcTellsYou && NpcTellsYou.IsMatch(text))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will return the name of the person/monster/npc of a chat message or tell.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetSourceOfChat(string text)
|
||||
{
|
||||
bool isSays = IsChat(text, ChatFlags.NpcSays | ChatFlags.PlayerSaysChannel | ChatFlags.PlayerSaysLocal);
|
||||
bool isTell = IsChat(text, ChatFlags.NpcTellsYou | ChatFlags.PlayerTellsYou);
|
||||
|
||||
if (isSays && isTell)
|
||||
{
|
||||
int indexOfSays = text.IndexOf(" says, \"", StringComparison.Ordinal);
|
||||
int indexOfTell = text.IndexOf(" tells you", StringComparison.Ordinal);
|
||||
|
||||
if (indexOfSays <= indexOfTell)
|
||||
isTell = false;
|
||||
else
|
||||
isSays = false;
|
||||
}
|
||||
|
||||
string source = string.Empty;
|
||||
|
||||
if (isSays)
|
||||
source = text.Substring(0, text.IndexOf(" says, \"", StringComparison.Ordinal));
|
||||
else if (isTell)
|
||||
source = text.Substring(0, text.IndexOf(" tells you", StringComparison.Ordinal));
|
||||
else
|
||||
return source;
|
||||
|
||||
source = source.Trim();
|
||||
|
||||
if (source.Contains(">") && source.Contains("<"))
|
||||
{
|
||||
source = source.Remove(0, source.IndexOf('>') + 1);
|
||||
if (source.Contains("<"))
|
||||
source = source.Substring(0, source.IndexOf('<'));
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ChatChannels : ushort
|
||||
{
|
||||
None = 0x0000,
|
||||
|
||||
Area = 0x0001,
|
||||
Tells = 0x0002,
|
||||
|
||||
Fellowship = 0x0004,
|
||||
Allegiance = 0x0008,
|
||||
General = 0x0010,
|
||||
Trade = 0x0020,
|
||||
LFG = 0x0040,
|
||||
Roleplay = 0x0080,
|
||||
Society = 0x0100,
|
||||
|
||||
All = 0xFFFF,
|
||||
}
|
||||
|
||||
public static ChatChannels GetChatChannel(string text)
|
||||
{
|
||||
if (IsChat(text, ChatFlags.PlayerSaysLocal | ChatFlags.YouSay | ChatFlags.NpcSays))
|
||||
return ChatChannels.Area;
|
||||
|
||||
if (IsChat(text, ChatFlags.PlayerTellsYou | ChatFlags.YouTell | ChatFlags.NpcTellsYou))
|
||||
return ChatChannels.Tells;
|
||||
|
||||
if (IsChat(text, ChatFlags.PlayerSaysChannel))
|
||||
{
|
||||
Match match = PlayerSaysChannel.Match(text);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
string channel = match.Groups["channel"].Value;
|
||||
|
||||
if (channel == "Fellowship") return ChatChannels.Fellowship;
|
||||
if (channel == "Allegiance") return ChatChannels.Allegiance;
|
||||
if (channel == "General") return ChatChannels.General;
|
||||
if (channel == "Trade") return ChatChannels.Trade;
|
||||
if (channel == "LFG") return ChatChannels.LFG;
|
||||
if (channel == "Roleplay") return ChatChannels.Roleplay;
|
||||
if (channel == "Society") return ChatChannels.Society;
|
||||
}
|
||||
}
|
||||
|
||||
return ChatChannels.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a message of:
|
||||
/// [Allegiance] <Tell:IIDString:0:PlayerName>PlayerName<\Tell> says, "kk"
|
||||
/// to:
|
||||
/// [Allegiance] PlayerName says, "kk"
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static string CleanMessage(string text)
|
||||
{
|
||||
string output = text;
|
||||
|
||||
int ltIndex = output.IndexOf('<');
|
||||
int gtIndex = output.IndexOf('>');
|
||||
int cIndex = output.IndexOf(',');
|
||||
|
||||
if (ltIndex != -1 && ltIndex < gtIndex && gtIndex < cIndex)
|
||||
output = output.Substring(0, ltIndex) + output.Substring(gtIndex + 1, output.Length - gtIndex - 1);
|
||||
|
||||
ltIndex = output.IndexOf('<');
|
||||
gtIndex = output.IndexOf('>');
|
||||
cIndex = output.IndexOf(',');
|
||||
|
||||
if (ltIndex != -1 && ltIndex < gtIndex && gtIndex < cIndex)
|
||||
output = output.Substring(0, ltIndex) + output.Substring(gtIndex + 1, output.Length - gtIndex - 1);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// You say, "Zojak ...."
|
||||
private static readonly Regex YouSaySpellCast = new Regex("^You say, \"(Zojak|Malar|Puish|Cruath|Volae|Quavosh|Shurov|Boquar|Helkas|Equin|Roiga|Malar|Jevak|Tugak|Slavu|Drostu|Traku|Yanoi|Drosta|Feazh) .*\"$");
|
||||
// Player says, "Zojak ...."
|
||||
private static readonly Regex PlayerSaysSpellCast = new Regex("^<Tell:IIDString:[0-9]+:(?<name>[\\w\\s'-]+)>[\\w\\s'-]+<\\\\Tell> says, \"(Zojak|Malar|Puish|Cruath|Volae|Quavosh|Shurov|Boquar|Helkas|Equin|Roiga|Malar|Jevak|Tugak|Slavu|Drostu|Traku|Yanoi|Drosta|Feazh) .*\"$");
|
||||
|
||||
/// <summary>
|
||||
/// Returns true for messages that are like:
|
||||
/// You say, "Zojak....
|
||||
/// or
|
||||
/// Somebody says, "Zojak...
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="isMine"> </param>
|
||||
/// <param name="isPlayer"> </param>
|
||||
/// <returns></returns>
|
||||
public static bool IsSpellCastingMessage(string text, bool isMine = true, bool isPlayer = true)
|
||||
{
|
||||
if (isMine && YouSaySpellCast.IsMatch(text))
|
||||
return true;
|
||||
|
||||
if (isPlayer && PlayerSaysSpellCast.IsMatch(text))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void ExportSpells(string targetFileName)
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(targetFileName, true))
|
||||
{
|
||||
writer.WriteLine("Id,Name,Description,Difficulty,Duration,Family,Flags,Generation,IconId,IsDebuff,IsFastWindup,IsFellowship,IsIrresistible,IsOffensive,IsUntargetted,Mana,School,SortKey,Speed,TargetEffect,TargetMask,Type,Unknown1,Unknown2,Unknown3,Unknown4,Unknown5,Unknown6,Unknown7,Unknown8,Unknown9,Unknown10");
|
||||
|
||||
FileService service = CoreManager.Current.Filter<FileService>();
|
||||
|
||||
for (int i = 0 ; i < service.SpellTable.Length ; i++)
|
||||
{
|
||||
Spell spell = service.SpellTable[i];
|
||||
|
||||
string flags = "";
|
||||
flags += ((spell.Flags & 0x80000) == 0x80000) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x40000) == 0x40000) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x20000) == 0x20000) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x10000) == 0x10000) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x8000) == 0x8000) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x4000) == 0x4000) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x2000) == 0x2000) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x1000) == 0x1000) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x800) == 0x800) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x400) == 0x400) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x200) == 0x200) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x100) == 0x100) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x80) == 0x80) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x40) == 0x40) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x20) == 0x20) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x10) == 0x10) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x8) == 0x8) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x4) == 0x4) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x2) == 0x2) ? "1" : "0";
|
||||
flags += ((spell.Flags & 0x1) == 0x1) ? "1" : "0";
|
||||
|
||||
writer.WriteLine(spell.Id + "," + spell.Name.Replace(",", ".") + "," + spell.Description.Replace(",", ".") + "," + spell.Difficulty + "," + spell.Duration + "," + spell.Family + "," + flags + "," + spell.Generation + "," + spell.IconId + "," + spell.IsDebuff + "," + spell.IsFastWindup + "," + spell.IsFellowship + "," + spell.IsIrresistible + "," + spell.IsOffensive + "," + spell.IsUntargetted + "," + spell.Mana + "," + spell.School + "," + spell.SortKey + "," + spell.Speed + "," + spell.TargetEffect + "," + spell.TargetMask + "," + spell.Type + "," + spell.Unknown1 + "," + spell.Unknown2 + "," + spell.Unknown3 + "," + spell.Unknown4 + "," + spell.Unknown5 + "," + spell.Unknown6 + "," + spell.Unknown7 + "," + spell.Unknown8 + "," + spell.Unknown9 + "," + spell.Unknown10);
|
||||
}
|
||||
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static string NumberFormatter(long number, string format, int largestViewableNumber, string reducedFormat = "#,##0")
|
||||
{
|
||||
if (number <= largestViewableNumber)
|
||||
return number.ToString(format);
|
||||
|
||||
int spaces = largestViewableNumber.ToString(format).Length;
|
||||
|
||||
if (((float)number / 1000).ToString(reducedFormat).Length <= spaces)
|
||||
return ((float)number / 1000).ToString(reducedFormat) + "k"; // thousand
|
||||
|
||||
if (((float)number / 1000000).ToString(reducedFormat).Length <= spaces)
|
||||
return ((float)number / 1000000).ToString(reducedFormat) + "M"; // million
|
||||
|
||||
return ((float)number / 1000000000).ToString(reducedFormat) + "G"; // billion
|
||||
}
|
||||
}
|
||||
}
|
||||
266
Shared/VCS_Connector.cs
Normal file
266
Shared/VCS_Connector.cs
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
//File: VCS_Connector.cs
|
||||
//
|
||||
//Description: Connector class for Virindi Chat System 5.
|
||||
//
|
||||
//References required:
|
||||
// VCS5
|
||||
//
|
||||
//This file is Copyright (c) 2013 VirindiPlugins
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Decal.Adapter;
|
||||
using Decal.Adapter.Wrappers;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MyClasses
|
||||
{
|
||||
static class VCS_Connector
|
||||
{
|
||||
public enum eVVSConsoleColorClass
|
||||
{
|
||||
SystemMessage = 0,
|
||||
Magic = 1,
|
||||
MyMeleeAttack = 2,
|
||||
OtherMeleeAttack = 3,
|
||||
MyTell = 4,
|
||||
OtherTell = 5,
|
||||
GlobalChat = 6,
|
||||
AllegianceChat = 7,
|
||||
FellowChat = 8,
|
||||
OpenChat = 9,
|
||||
OpenEmote = 10,
|
||||
StatusError = 11,
|
||||
StatRaised = 12,
|
||||
RareFound = 13,
|
||||
|
||||
PluginMessage = 96,
|
||||
PluginError = 97,
|
||||
Link = 98,
|
||||
Unknown = 99,
|
||||
}
|
||||
|
||||
public static string ThisPluginName = "???";
|
||||
public static PluginHost Host = null;
|
||||
|
||||
/// <summary>
|
||||
/// A shortcut method to initialize plugin name and the PluginHost object.
|
||||
/// </summary>
|
||||
/// <param name="myhost">PluginCore.Host</param>
|
||||
/// <param name="mypluginname">The friendly name of this plugin. Used in the presets list.</param>
|
||||
public static void Initialize(PluginHost myhost, string mypluginname)
|
||||
{
|
||||
Host = myhost;
|
||||
ThisPluginName = mypluginname;
|
||||
}
|
||||
|
||||
#region SendChatText
|
||||
|
||||
/// <summary>
|
||||
/// Sends text as regular chat. Deprecated.
|
||||
/// </summary>
|
||||
/// <param name="host">PluginCore.Host</param>
|
||||
/// <param name="text">The chat message.</param>
|
||||
/// <param name="color">The default AC console color ID.</param>
|
||||
/// <param name="window">The default target window, 0=auto, 1=main, 2=float1</param>
|
||||
/// <param name="vvsfilteras">The VVS console control filter type.</param>
|
||||
[Obsolete]
|
||||
public static void SendChatText(PluginHost host, string text, int color, int window, eVVSConsoleColorClass vvsfilteras)
|
||||
{
|
||||
if (IsVCSPresent(host))
|
||||
{
|
||||
//Send using VCS
|
||||
Curtain_SendChatTextVCS(text, color, window);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Send the old way
|
||||
host.Actions.AddChatTextRaw(text, color, window);
|
||||
}
|
||||
|
||||
|
||||
if (IsVirindiViewsPresent(host))
|
||||
Curtain_SendChatTextVViews(text, color, (int)vvsfilteras);
|
||||
}
|
||||
|
||||
static void Curtain_SendChatTextVCS(string text, int color, int window)
|
||||
{
|
||||
VCS5.PluginCore.Instance.FilterOutputText(text, window, color);
|
||||
}
|
||||
|
||||
static void Curtain_SendChatTextVViews(string text, int color, int vvsfilteras)
|
||||
{
|
||||
VirindiViewService.Controls.HudChatbox.SendChatText(text, (VirindiViewService.Controls.HudConsole.eACTextColor)color, (VirindiViewService.eConsoleColorClass)vvsfilteras);
|
||||
}
|
||||
|
||||
#endregion SendChatText
|
||||
|
||||
#region Sending Categorized Text
|
||||
|
||||
/// <summary>
|
||||
/// Send a filtered chat message by VCS preset. Call Initialize() first, then call InitializeCategory() to
|
||||
/// create the preset, then finally call this to output text.
|
||||
/// </summary>
|
||||
/// <param name="categoryname">The preset name. Should already be initialized by InitializeCategory().</param>
|
||||
/// <param name="text">The output chat text.</param>
|
||||
/// <param name="color">The default AC console color ID.</param>
|
||||
/// <param name="windows">The default target windows, 0=auto, 1=main, 2=float1</param>
|
||||
public static void SendChatTextCategorized(string categoryname, string text, int color, params int[] windows)
|
||||
{
|
||||
if ((windows == null) || (windows.Length == 0)) windows = new int[] { 1 };
|
||||
|
||||
if (IsVCSPresent(Host))
|
||||
{
|
||||
Curtain_SendChatTextCategorized(categoryname, text, color, windows);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (int x in windows)
|
||||
{
|
||||
if (Host != null)
|
||||
Host.Actions.AddChatText(text, color, x);
|
||||
else
|
||||
CoreManager.Current.Actions.AddChatText(text, color, x);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsVirindiViewsPresent(Host))
|
||||
Curtain_SendChatTextVViews(text, color, (int)eVVSConsoleColorClass.PluginMessage);
|
||||
}
|
||||
|
||||
static void Curtain_SendChatTextCategorized(string categoryname, string text, int color, params int[] windows)
|
||||
{
|
||||
VCS5.Presets.FilterOutputPreset(ThisPluginName, categoryname, text, color, windows);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a VCS preset type which can later be used for chat. Will appear in the VCS presets list. Call Initialize() first.
|
||||
/// </summary>
|
||||
/// <param name="categoryname">The preset name.</param>
|
||||
/// <param name="description">The preset description.</param>
|
||||
public static void InitializeCategory(string categoryname, string description)
|
||||
{
|
||||
if (IsVCSPresent(Host))
|
||||
Curtain_InitializeCategory(categoryname, description);
|
||||
}
|
||||
|
||||
static void Curtain_InitializeCategory(string categoryname, string description)
|
||||
{
|
||||
VCS5.Presets.RegisterPreset(ThisPluginName, categoryname, description);
|
||||
}
|
||||
|
||||
#endregion Sending Categorized Text
|
||||
|
||||
#region VCS and VVS online checks
|
||||
|
||||
static bool seenvcsassembly = false;
|
||||
|
||||
public static bool IsVCSPresent(PluginHost pHost)
|
||||
{
|
||||
try
|
||||
{
|
||||
//See if VCS assembly is loaded
|
||||
if (!seenvcsassembly)
|
||||
{
|
||||
System.Reflection.Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
|
||||
foreach (System.Reflection.Assembly a in asms)
|
||||
{
|
||||
AssemblyName nmm = a.GetName();
|
||||
if ((nmm.Name == "VCS5") && (nmm.Version >= new System.Version("5.0.0.5")))
|
||||
{
|
||||
seenvcsassembly = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (seenvcsassembly)
|
||||
if (Curtain_VCSInstanceEnabled())
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool Curtain_VCSInstanceEnabled()
|
||||
{
|
||||
return VCS5.PluginCore.Running;
|
||||
}
|
||||
|
||||
static bool has_cachedvvsresult = false;
|
||||
static bool cachedvvsresult = false;
|
||||
|
||||
//Doh
|
||||
//Need to know about VVS to post to VVS "console" controls.
|
||||
//Since VVS is a service and can't be turned on and off at runtime, we only need to do this once.
|
||||
public static bool IsVirindiViewsPresent(PluginHost pHost)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (has_cachedvvsresult) return cachedvvsresult;
|
||||
|
||||
//See if VCS assembly is loaded
|
||||
System.Reflection.Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
|
||||
bool l = false;
|
||||
foreach (System.Reflection.Assembly a in asms)
|
||||
{
|
||||
AssemblyName nmm = a.GetName();
|
||||
if ((nmm.Name == "VirindiViewService") && (nmm.Version >= new System.Version("1.0.0.14")))
|
||||
{
|
||||
l = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (l)
|
||||
if (Curtain_VirindiViewsInstanceEnabled())
|
||||
{
|
||||
has_cachedvvsresult = true;
|
||||
cachedvvsresult = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
has_cachedvvsresult = true;
|
||||
cachedvvsresult = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool Curtain_VirindiViewsInstanceEnabled()
|
||||
{
|
||||
return VirindiViewService.Service.Running;
|
||||
}
|
||||
|
||||
#endregion VCS and VVS online checks
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MosswartMassacre", "Mosswar
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GearCycler", "GearCycler\GearCycler.csproj", "{1293560E-2A56-417F-8116-8CE0420DC97C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -19,10 +17,6 @@ Global
|
|||
{8C97E839-4D05-4A5F-B0C8-E8E778654322}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8C97E839-4D05-4A5F-B0C8-E8E778654322}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8C97E839-4D05-4A5F-B0C8-E8E778654322}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1293560E-2A56-417F-8116-8CE0420DC97C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1293560E-2A56-417F-8116-8CE0420DC97C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1293560E-2A56-417F-8116-8CE0420DC97C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1293560E-2A56-417F-8116-8CE0420DC97C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue