Questionable/Questionable/Controller/ContextMenuController.cs

167 lines
6.0 KiB
C#

using System;
using System.Linq;
using Dalamud.Game.Gui.ContextMenu;
using Dalamud.Game.Text;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using LLib.GameData;
using Microsoft.Extensions.Logging;
using Questionable.Data;
using Questionable.Functions;
using Questionable.GameStructs;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Controller;
internal sealed class ContextMenuController : IDisposable
{
private readonly IContextMenu _contextMenu;
private readonly QuestController _questController;
private readonly GatheringData _gatheringData;
private readonly QuestRegistry _questRegistry;
private readonly QuestData _questData;
private readonly GameFunctions _gameFunctions;
private readonly QuestFunctions _questFunctions;
private readonly IGameGui _gameGui;
private readonly IChatGui _chatGui;
private readonly IClientState _clientState;
private readonly ILogger<ContextMenuController> _logger;
public ContextMenuController(
IContextMenu contextMenu,
QuestController questController,
GatheringData gatheringData,
QuestRegistry questRegistry,
QuestData questData,
GameFunctions gameFunctions,
QuestFunctions questFunctions,
IGameGui gameGui,
IChatGui chatGui,
IClientState clientState,
ILogger<ContextMenuController> logger)
{
_contextMenu = contextMenu;
_questController = questController;
_gatheringData = gatheringData;
_questRegistry = questRegistry;
_questData = questData;
_gameFunctions = gameFunctions;
_questFunctions = questFunctions;
_gameGui = gameGui;
_chatGui = chatGui;
_clientState = clientState;
_logger = logger;
_contextMenu.OnMenuOpened += MenuOpened;
}
private void MenuOpened(IMenuOpenedArgs args)
{
uint itemId = (uint)_gameGui.HoveredItem;
if (itemId == 0)
return;
if (itemId > 1_000_000)
itemId -= 1_000_000;
if (itemId >= 500_000)
itemId -= 500_000;
if (_gatheringData.TryGetCustomDeliveryNpc(itemId, out uint npcId))
{
AddContextMenuEntry(args, itemId, npcId, EExtendedClassJob.Miner, "Mine");
AddContextMenuEntry(args, itemId, npcId, EExtendedClassJob.Botanist, "Harvest");
}
}
private void AddContextMenuEntry(IMenuOpenedArgs args, uint itemId, uint npcId, EExtendedClassJob extendedClassJob,
string verb)
{
EClassJob currentClassJob = (EClassJob)_clientState.LocalPlayer!.ClassJob.RowId;
EClassJob classJob = ClassJobUtils.AsIndividualJobs(extendedClassJob).Single();
if (classJob != currentClassJob && currentClassJob is EClassJob.Miner or EClassJob.Botanist)
return;
if (!_gatheringData.TryGetGatheringPointId(itemId, classJob, out _))
{
_logger.LogInformation("No gathering point found for current job.");
return;
}
ushort collectability = _gatheringData.GetRecommendedCollectability(itemId);
int quantityToGather = collectability > 0 ? 6 : int.MaxValue;
if (collectability == 0)
return;
unsafe
{
var agentSatisfactionSupply = AgentSatisfactionSupply.Instance();
if (agentSatisfactionSupply->IsAgentActive())
{
int maxTurnIns = agentSatisfactionSupply->NpcInfo.SatisfactionRank == 1 ? 3 : 6;
quantityToGather = Math.Min(agentSatisfactionSupply->NpcData.RemainingAllowances,
((AgentSatisfactionSupply2*)agentSatisfactionSupply)->CalculateTurnInsToNextRank(maxTurnIns));
}
}
string lockedReasonn = string.Empty;
if (!_questFunctions.IsClassJobUnlocked(classJob))
lockedReasonn = $"{classJob} not unlocked";
else if (quantityToGather == 0)
lockedReasonn = "No allowances";
else if (quantityToGather > _gameFunctions.GetFreeInventorySlots())
lockedReasonn = "Inventory full";
else if (_gameFunctions.IsOccupied())
lockedReasonn = "Can't be used while interacting";
string name = $"{verb} with Questionable";
if (!string.IsNullOrEmpty(lockedReasonn))
name += $" ({lockedReasonn})";
args.AddMenuItem(new MenuItem
{
Prefix = SeIconChar.Hyadelyn,
PrefixColor = 52,
Name = name,
OnClicked = _ => StartGathering(npcId, itemId, quantityToGather, collectability, extendedClassJob),
IsEnabled = string.IsNullOrEmpty(lockedReasonn),
});
}
private void StartGathering(uint npcId, uint itemId, int quantity, ushort collectability,
EExtendedClassJob extendedClassJob)
{
var info = (SatisfactionSupplyInfo)_questData.GetAllByIssuerDataId(npcId)
.Single(x => x is SatisfactionSupplyInfo);
if (_questRegistry.TryGetQuest(info.QuestId, out Quest? quest))
{
var sequence = quest.FindSequence(0)!;
var switchClassStep = sequence.Steps.Single(x => x.InteractionType == EInteractionType.SwitchClass);
switchClassStep.TargetClass = extendedClassJob;
var gatherStep = sequence.Steps.Single(x => x.InteractionType == EInteractionType.Gather);
gatherStep.ItemsToGather =
[
new GatheredItem
{
ItemId = itemId,
ItemCount = quantity,
Collectability = collectability,
}
];
_questController.SetGatheringQuest(quest);
_questController.StartSingleQuest("SatisfactionSupply prepare gathering");
}
else
_chatGui.PrintError($"No associated quest ({info.QuestId}).", "Questionable");
}
public void Dispose()
{
_contextMenu.OnMenuOpened -= MenuOpened;
}
}