using System; using System.Runtime.InteropServices; using Decal.Interop.Core; namespace Decal.Core { [ComVisible(true)] [Guid("CB8875CD-ABC2-42AD-8175-8908706EED37")] [ClassInterface(ClassInterfaceType.None)] [ComSourceInterfaces("Decal.Interop.Core.IACHooksEvents\0\0")] [ProgId("Decal.ACHooks")] public class ACHooksImpl : IACHooks { // COM events public event IACHooksEvents_ObjectDestroyedEventHandler ObjectDestroyed; public event IACHooksEvents_ChatTextInterceptEventHandler ChatTextIntercept; public event IACHooksEvents_ChatParserInterceptEventHandler ChatParserIntercept; public event IACHooksEvents_StatusTextInterceptEventHandler StatusTextIntercept; public event IACHooksEvents_ObjectSelectedEventHandler ObjectSelected; public event IACHooksEvents_MessageProcessedEventHandler MessageProcessed; public event IACHooksEvents_AC3DRegionChangedEventHandler AC3DRegionChanged; public event IACHooksEvents_ContainerOpenedEventHandler ContainerOpened; public event IACHooksEvents_ChatClickInterceptEventHandler ChatClickIntercept; public event IACHooksEvents_RenderPreUIEventHandler RenderPreUI; private DecalCoreImpl _decal; private IIdentifyFilter _idFilter; // State private int _currentSelection; private int _previousSelection; private int _selectedStackCount; private int _maxSelectedStackCount; private int _combatMode; private int _vendorId; private int _busyState; private int _busyStateId; private int _pointerState; private int _commandInterpreter; private int _openedContainer; private bool _chatState; private double _headingDegrees; private double _headingRadians; private int _landcell; private double _locationX, _locationY, _locationZ; private tagRECT _ac3dRegionRect; private tagRECT _acWindowRect; public void SetIDFilter(IIdentifyFilter pIDFilter) => _idFilter = pIDFilter; public void SetDecal(object pDecal) { _decal = pDecal as DecalCoreImpl; } // Hook availability public int HooksAvail => (int)(eAvailableHooks.eCurrentSelect | eAvailableHooks.ePrevSelect | eAvailableHooks.eCastSpell | eAvailableHooks.eMoveItem | eAvailableHooks.eSelectItem | eAvailableHooks.eUseItem | eAvailableHooks.eCombatMode | eAvailableHooks.eChatState | eAvailableHooks.eStackCount | eAvailableHooks.eMaxStackCount | eAvailableHooks.eVendorID | eAvailableHooks.eBusyState | eAvailableHooks.eBusyStateID | eAvailableHooks.ePointerState | eAvailableHooks.eMoveItemEx | eAvailableHooks.ePosition | eAvailableHooks.eFaceHeading | eAvailableHooks.eAC3DRegion | eAvailableHooks.eObjectDestroyed | eAvailableHooks.eSendTell | eAvailableHooks.eSetAutorun | eAvailableHooks.eSetCombatMode | eAvailableHooks.eGetMiscInt | eAvailableHooks.eGetAttribute | eAvailableHooks.eGetSkill | eAvailableHooks.eGetVital | eAvailableHooks.eHooksAvailEx); public bool HooksAvailEx => true; // Chat methods public void AddChatText(string szText, int lColor, int lTarget) { // In the open-source version, we fire this through the chat event system bool eat = false; ChatTextIntercept?.Invoke(szText, lColor, lTarget, ref eat); } public void AddChatTextRaw(string szText, int lColor, int lTarget) { AddChatText(szText, lColor, lTarget); } public void AddStatusText(string Text) { bool eat = false; StatusTextIntercept?.Invoke(Text, ref eat); } public void InvokeChatParser(string Text) { bool eat = false; ChatParserIntercept?.Invoke(Text, ref eat); } public void SetIdleTime(double dIdleTimeout) { } public void Logout() { } // Selection public int CurrentSelection { get => _currentSelection; set => _currentSelection = value; } public int PreviousSelection { get => _previousSelection; set => _previousSelection = value; } public int SelectedStackCount { get => _selectedStackCount; set => _selectedStackCount = value; } public int MaxSelectedStackCount => _maxSelectedStackCount; public void SetCursorPosition(int lX, int lY) { } // Window/region info public tagRECT AC3DRegionRect => _ac3dRegionRect; public IntPtr AC3DRegionRectPtr => IntPtr.Zero; public tagRECT ACWindowRect => _acWindowRect; // State properties public bool ChatState => _chatState; public int BusyState => _busyState; public int BusyStateID => _busyStateId; public int PointerState => _pointerState; public int VendorID => _vendorId; // Vendor operations public void VendorBuyListAdd(int lID, int lAmount) { } public void VendorBuyListClear() { } public void VendorBuyAll() { } public void VendorSellListAdd(int lID) { } public void VendorSellListClear() { } public void VendorSellAll() { } // Combat public int CombatMode => _combatMode; public void SetCombatMode(int pVal) { _combatMode = pVal; } public void SetAutorun(bool bOnOff) { } public bool FaceHeading(float fHeading, bool bUnknown) { return true; } public int CommandInterpreter => _commandInterpreter; // Item operations public void SelectItem(int lObjectID) { _previousSelection = _currentSelection; _currentSelection = lObjectID; ObjectSelected?.Invoke(lObjectID); } public void GiveItem(int lObject, int lDestination) { } public void ApplyItem(int UseThis, int OnThis) { } public void UseItem(int lObjectID, int lUseState) { } public void UseItemRaw(int lObjectID, int lUseState, int lUseMethod) { } public void MoveItem(int lObjectID, int lPackID, int lSlot, bool bStack) { } public void MoveItemEx(int lObjectID, int lDestinationID) { } public void MoveItemExRaw(int lObject, int lDestination, int lMoveFlags) { } public void DropItem(int lObjectID) { } // Spell casting public void CastSpell(int lSpellID, int lObjectID) { } // Object queries public bool IsValidObject(int lGUID) => false; public int GetWeenieObjectPtr(int lObjectID) => 0; public int GetPhysicsObjectPtr(int lObjectID) => 0; // Position public double HeadingDegrees => _headingDegrees; public double HeadingRadians => _headingRadians; public int Landcell => _landcell; public double LocationX => _locationX; public double LocationY => _locationY; public double LocationZ => _locationZ; // Character stats (parameterized properties — index-based access) public eTrainLevel SkillTrainLevel => eTrainLevel.eUntrained; public int SkillTotalXP => 0; public int SkillFreePoints => 0; public int SkillClicks => 0; public int AttributeTotalXP => 0; public int AttributeClicks => 0; public int AttributeStart => 0; public int VitalTotalXP => 0; public int VitalClicks => 0; public int Vital => 0; public int Attribute => 0; public int Skill => 0; public int Misc => 0; // ID/object operations public void RequestID(int lObjectID) { _idFilter?.AddToQueue(lObjectID); } public void IDQueueAdd(int lObjectID) { _idFilter?.AddToQueue(lObjectID); } // Spell bar public void SpellTabAdd(int lTab, int lIndex, int lSpellID) { } public void SpellTabDelete(int lTab, int lSpellID) { } // Trade public void TradeAdd(int ItemID) { } public void TradeAccept() { } public void TradeDecline() { } public void TradeReset() { } public void TradeEnd() { } // Salvage public void SalvagePanelAdd(int lObjectID) { } public void SalvagePanelSalvage() { } public int OpenedContainer => _openedContainer; // Experience public void AddSkillExp(eSkill SkillID, int lExperience) { } public void AddAttributeExp(eAttribute AttribID, int lExperience) { } public void AddVitalExp(eVital VitalID, int lExperience) { } public int SmartboxPtr() => 0; public float ObjectHeight(int lObjectID) => 0f; public int CallerRefInstanceInternal { set { } } // Equipment public void AutoWieldRaw(int lObjectID, int SlotID, int Explicit, int NotExplicit, int zeroVal1, int zeroVal2) { } public void AutoWield(int lObjectID) { } public void AutoWieldEx(int lObjectID, int SlotID, int Explicit, int NotExplicit) { } // Fellowship public void FellowshipRecruit(int lObjectID) { } public void FellowshipGrantLeader(int lObjectID) { } public void FellowshipSetOpen(bool IsOpen) { } public void FellowshipQuit() { } public void FellowshipDisband() { } public void FellowshipDismiss(int lObjectID) { } // UI public void UIElementMove(int lUIElementType, int X, int Y) { } public void UIElementResize(int lUIElementType, int Width, int Height) { } public int UIElementLookup(int lUIElementType) => 0; public tagRECT UIElementRegionRect(int lUIElementType) => default; // Internal event firing methods internal void FireObjectDestroyed(int guid) => ObjectDestroyed?.Invoke(guid); internal void FireContainerOpened(int guid) => ContainerOpened?.Invoke(guid); internal void FireRenderPreUI() => RenderPreUI?.Invoke(); internal void FireChatText(string text, int color, int target, ref bool eat) { ChatTextIntercept?.Invoke(text, color, target, ref eat); } internal void FireChatParser(string text, ref bool eat) { ChatParserIntercept?.Invoke(text, ref eat); } internal void FireStatusText(string text, ref bool eat) { StatusTextIntercept?.Invoke(text, ref eat); } internal void FireObjectSelected(int guid) => ObjectSelected?.Invoke(guid); internal void FireAC3DRegionChanged(int left, int top, int right, int bottom) { _ac3dRegionRect = new tagRECT { left = left, top = top, right = right, bottom = bottom }; AC3DRegionChanged?.Invoke(left, top, right, bottom); } internal void FireChatClick(string text, int id, ref bool eat) { ChatClickIntercept?.Invoke(text, id, ref eat); } internal void UpdatePosition(double x, double y, double z, int landcell, double headDeg, double headRad) { _locationX = x; _locationY = y; _locationZ = z; _landcell = landcell; _headingDegrees = headDeg; _headingRadians = headRad; } } }