qstbak/Questionable/Questionable.Controller/ContextMenuController.cs
2026-08-17 20:29:32 +10:00

198 lines
6.1 KiB
C#

using System;
using Dalamud.Game.Gui.ContextMenu;
using Dalamud.Game.Text;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using LLib.GameData;
using LLib.GameUI;
using LLib.Shop;
using Microsoft.Extensions.Logging;
using Questionable.Controller.CustomDelivery;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model.Gathering;
namespace Questionable.Controller;
internal sealed class ContextMenuController : IDisposable
{
private readonly IContextMenu _contextMenu;
private readonly QuestController _questController;
private readonly CustomDeliveryController _customDeliveryController;
private readonly FateController _fateController;
private readonly SeasonalDutyController _seasonalDutyController;
private readonly AttunementController _attunementController;
private readonly GatheringPointRegistry _gatheringPointRegistry;
private readonly GatheringData _gatheringData;
private readonly GameFunctions _gameFunctions;
private readonly QuestFunctions _questFunctions;
private readonly IGameGui _gameGui;
private readonly IChatGui _chatGui;
private readonly ILogger<ContextMenuController> _logger;
public ContextMenuController(IContextMenu contextMenu, QuestController questController, CustomDeliveryController customDeliveryController, FateController fateController, SeasonalDutyController seasonalDutyController, AttunementController attunementController, GatheringPointRegistry gatheringPointRegistry, GatheringData gatheringData, GameFunctions gameFunctions, QuestFunctions questFunctions, IGameGui gameGui, IChatGui chatGui, ILogger<ContextMenuController> logger)
{
_contextMenu = contextMenu;
_questController = questController;
_customDeliveryController = customDeliveryController;
_fateController = fateController;
_seasonalDutyController = seasonalDutyController;
_attunementController = attunementController;
_gatheringPointRegistry = gatheringPointRegistry;
_gatheringData = gatheringData;
_gameFunctions = gameFunctions;
_questFunctions = questFunctions;
_gameGui = gameGui;
_chatGui = chatGui;
_logger = logger;
_contextMenu.OnMenuOpened += MenuOpened;
}
private void MenuOpened(IMenuOpenedArgs args)
{
if (args.AddonName != null)
{
return;
}
uint num = GetHoveredSatisfactionSupplyItemId();
if (num == 0)
{
_logger.LogTrace("Ignoring context menu, no item hovered");
return;
}
if (num > 1000000)
{
num -= 1000000;
}
if (num >= 500000)
{
num -= 500000;
}
if (_gatheringData.TryGetCustomDeliveryNpc(num, out var _))
{
AddContextMenuEntry(args, num);
return;
}
_logger.LogDebug("No custom delivery NPC found for item {ItemId}.", num);
}
private unsafe uint GetHoveredSatisfactionSupplyItemId()
{
AgentSatisfactionSupply* ptr = AgentSatisfactionSupply.Instance();
if (ptr == null || !ptr->IsAgentActive())
{
return 0u;
}
if (_gameGui.TryGetAddonByName<AddonSatisfactionSupply>("SatisfactionSupply", out var addonPtr) && LAddon.IsAddonReady(&addonPtr->AtkUnitBase))
{
int hoveredElementIndex = addonPtr->HoveredElementIndex;
if (hoveredElementIndex >= 0 && hoveredElementIndex <= 2)
{
return ptr->Items[addonPtr->HoveredElementIndex].Id;
}
}
return 0u;
}
private unsafe void AddContextMenuEntry(IMenuOpenedArgs args, uint itemId)
{
GatheringPointId gatheringPointId;
bool flag = _gatheringPointRegistry.TryGetGatheringPointId(itemId, EClassJob.Miner, out gatheringPointId);
bool flag2 = _gatheringPointRegistry.TryGetGatheringPointId(itemId, EClassJob.Botanist, out gatheringPointId);
if (!flag && !flag2)
{
_logger.LogDebug("No gathering point found for item {ItemId}.", itemId);
}
else
{
if (_gatheringData.GetRecommendedCollectability(itemId) == 0)
{
return;
}
AgentSatisfactionSupply* ptr = AgentSatisfactionSupply.Instance();
if (ptr != null && ptr->IsAgentActive())
{
int npcIndex = (int)(ptr->NpcInfo.Id - 1);
SatisfactionSupplyActions.NpcState npcState = SatisfactionSupplyActions.GetNpcState(npcIndex);
int maxTurnIns = ((ptr->NpcInfo.SatisfactionRank == 1) ? 3 : 6);
int num = Math.Min(ptr->NpcData.RemainingAllowances, SatisfactionSupplyHelper.CalculateTurnInsToNextRank((ushort)npcState.SatisfactionCurrent, (ushort)npcState.SatisfactionMax, maxTurnIns));
bool num2 = (flag && _questFunctions.IsClassJobUnlocked(EClassJob.Miner)) || (flag2 && _questFunctions.IsClassJobUnlocked(EClassJob.Botanist));
string text = string.Empty;
if (!num2)
{
text = (flag ? "Miner not unlocked" : "Botanist not unlocked");
}
else if (num == 0)
{
text = "No allowances";
}
else if (num > _gameFunctions.GetFreeInventorySlots())
{
text = "Inventory full";
}
else if (_gameFunctions.IsOccupied())
{
text = "Can't be used while interacting";
}
else if (_customDeliveryController.IsRunning)
{
text = "Delivery already in progress";
}
else if (_questController.IsRunning || _fateController.IsRunning || _seasonalDutyController.IsRunning || _attunementController.IsRunning)
{
text = "Automation is running";
}
string text2 = "Deliver with Questionable";
if (!string.IsNullOrEmpty(text))
{
text2 = text2 + " (" + text + ")";
}
args.AddMenuItem(new MenuItem
{
Prefix = SeIconChar.Hyadelyn,
PrefixColor = 52,
Name = text2,
OnClicked = delegate
{
StartDelivery(npcIndex);
},
IsEnabled = string.IsNullOrEmpty(text)
});
}
}
}
private void StartDelivery(int npcIndex)
{
_questController.Stop("Custom delivery start");
_fateController.Stop("Custom delivery start");
_seasonalDutyController.Stop("Custom delivery start");
_attunementController.Stop("Custom delivery start");
if (_customDeliveryController.State != CustomDeliveryController.EDeliveryState.Idle)
{
_customDeliveryController.Stop("Custom delivery start");
}
if (!_customDeliveryController.Start(npcIndex, EDeliverySlot.Gather))
{
_chatGui.PrintError("Unable to start custom delivery.", "Questionable", 576);
}
}
public void Dispose()
{
_contextMenu.OnMenuOpened -= MenuOpened;
}
}