Rework some code parts

This commit is contained in:
Liza 2024-04-26 19:53:44 +02:00
parent 79f8959852
commit 8cc11c9389
Signed by: liza
GPG Key ID: 7199F8D727D55F67
9 changed files with 300 additions and 184 deletions

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<Version>4.3</Version> <Version>4.4</Version>
<LangVersion>12</LangVersion> <LangVersion>12</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

View File

@ -46,7 +46,6 @@ partial class DeliverooPlugin
_pluginLog.Verbose($" Choice {i} → {text}"); _pluginLog.Verbose($" Choice {i} → {text}");
if (text == desiredText) if (text == desiredText)
{ {
_pluginLog.Information($"Selecting choice {i} ({text})"); _pluginLog.Information($"Selecting choice {i} ({text})");
addonSelectString->AtkUnitBase.FireCallbackInt(i); addonSelectString->AtkUnitBase.FireCallbackInt(i);
@ -60,13 +59,13 @@ partial class DeliverooPlugin
private void OpenGcSupplySelectStringFollowUp() private void OpenGcSupplySelectStringFollowUp()
{ {
ResetTurnInErrorHandling(); _supplyHandler.ResetTurnInErrorHandling();
CurrentStage = Stage.SelectExpertDeliveryTab; CurrentStage = Stage.SelectExpertDeliveryTab;
} }
private void CloseGcSupplySelectStringFollowUp() private void CloseGcSupplySelectStringFollowUp()
{ {
if (GetNextItemToPurchase() == null) if (_exchangeHandler.GetNextItemToPurchase() == null)
{ {
_turnInWindow.State = false; _turnInWindow.State = false;
CurrentStage = Stage.RequestStop; CurrentStage = Stage.RequestStop;
@ -74,26 +73,27 @@ partial class DeliverooPlugin
else else
{ {
// you can occasionally get a 'not enough seals' warning lol // you can occasionally get a 'not enough seals' warning lol
_continueAt = DateTime.Now.AddSeconds(1); ContinueAt = DateTime.Now.AddSeconds(1);
CurrentStage = Stage.TargetQuartermaster; CurrentStage = Stage.TargetQuartermaster;
} }
} }
private void CloseGcSupplySelectStringThenStopFollowUp() private void CloseGcSupplySelectStringThenStopFollowUp()
{ {
if (GetNextItemToPurchase() == null) if (_exchangeHandler.GetNextItemToPurchase() == null)
{ {
_turnInWindow.State = false; _turnInWindow.State = false;
CurrentStage = Stage.RequestStop; CurrentStage = Stage.RequestStop;
} }
else if (GetCurrentSealCount() <= EffectiveReservedSealCount + GetNextItemToPurchase()!.SealCost) else if (_gameFunctions.GetCurrentSealCount() <=
EffectiveReservedSealCount + _exchangeHandler.GetNextItemToPurchase()!.SealCost)
{ {
_turnInWindow.State = false; _turnInWindow.State = false;
CurrentStage = Stage.RequestStop; CurrentStage = Stage.RequestStop;
} }
else else
{ {
_continueAt = DateTime.Now.AddSeconds(1); ContinueAt = DateTime.Now.AddSeconds(1);
CurrentStage = Stage.TargetQuartermaster; CurrentStage = Stage.TargetQuartermaster;
} }
} }

View File

@ -19,7 +19,7 @@ partial class DeliverooPlugin
if (CurrentStage == Stage.ConfirmReward && if (CurrentStage == Stage.ConfirmReward &&
_gameStrings.ExchangeItems.IsMatch(text)) _gameStrings.ExchangeItems.IsMatch(text))
{ {
PurchaseItemRequest? item = GetNextItemToPurchase(); PurchaseItemRequest? item = _exchangeHandler.GetNextItemToPurchase();
if (item == null) if (item == null)
{ {
addonSelectYesNo->AtkUnitBase.FireCallbackInt(1); addonSelectYesNo->AtkUnitBase.FireCallbackInt(1);
@ -33,12 +33,12 @@ partial class DeliverooPlugin
item.OnPurchase?.Invoke((int)item.TemporaryPurchaseQuantity); item.OnPurchase?.Invoke((int)item.TemporaryPurchaseQuantity);
item.TemporaryPurchaseQuantity = 0; item.TemporaryPurchaseQuantity = 0;
var nextItem = GetNextItemToPurchase(item); var nextItem = _exchangeHandler.GetNextItemToPurchase(item);
if (nextItem != null && GetCurrentSealCount() >= EffectiveReservedSealCount + nextItem.SealCost) if (nextItem != null && _gameFunctions.GetCurrentSealCount() >= EffectiveReservedSealCount + nextItem.SealCost)
CurrentStage = Stage.SelectRewardTier; CurrentStage = Stage.SelectRewardTier;
else else
CurrentStage = Stage.CloseGcExchange; CurrentStage = Stage.CloseGcExchange;
_continueAt = DateTime.Now.AddSeconds(0.5); ContinueAt = DateTime.Now.AddSeconds(0.5);
} }
else if (CurrentStage == Stage.TurnInSelected && else if (CurrentStage == Stage.TurnInSelected &&
_gameStrings.TradeHighQualityItem == text) _gameStrings.TradeHighQualityItem == text)

View File

@ -14,13 +14,12 @@ using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Deliveroo.External; using Deliveroo.External;
using Deliveroo.GameData; using Deliveroo.GameData;
using Deliveroo.Handlers;
using Deliveroo.Windows; using Deliveroo.Windows;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using LLib; using LLib;
using LLib.GameUI; using LLib.GameUI;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace Deliveroo; namespace Deliveroo;
@ -33,8 +32,6 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
private readonly IGameGui _gameGui; private readonly IGameGui _gameGui;
private readonly IFramework _framework; private readonly IFramework _framework;
private readonly IClientState _clientState; private readonly IClientState _clientState;
private readonly IObjectTable _objectTable;
private readonly ITargetManager _targetManager;
private readonly ICondition _condition; private readonly ICondition _condition;
private readonly ICommandManager _commandManager; private readonly ICommandManager _commandManager;
private readonly IPluginLog _pluginLog; private readonly IPluginLog _pluginLog;
@ -44,23 +41,19 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly GameStrings _gameStrings; private readonly GameStrings _gameStrings;
private readonly GameFunctions _gameFunctions;
private readonly ExternalPluginHandler _externalPluginHandler; private readonly ExternalPluginHandler _externalPluginHandler;
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly GcRewardsCache _gcRewardsCache; private readonly GcRewardsCache _gcRewardsCache;
private readonly IconCache _iconCache; private readonly IconCache _iconCache;
private readonly ItemCache _itemCache; private readonly ExchangeHandler _exchangeHandler;
private readonly SupplyHandler _supplyHandler;
private readonly ConfigWindow _configWindow; private readonly ConfigWindow _configWindow;
private readonly TurnInWindow _turnInWindow; private readonly TurnInWindow _turnInWindow;
private readonly ReadOnlyDictionary<uint, GcRankInfo> _gcRankInfo;
private readonly Dictionary<uint, int> _retainerItemCache = new();
private Stage _currentStageInternal = Stage.Stopped; private Stage _currentStageInternal = Stage.Stopped;
private DateTime _continueAt = DateTime.MinValue;
private int _lastTurnInListSize = int.MaxValue;
private uint _turnInErrors;
private List<PurchaseItemRequest> _itemsToPurchaseNow = new();
public DeliverooPlugin(DalamudPluginInterface pluginInterface, IChatGui chatGui, IGameGui gameGui, public DeliverooPlugin(DalamudPluginInterface pluginInterface, IChatGui chatGui, IGameGui gameGui,
IFramework framework, IClientState clientState, IObjectTable objectTable, ITargetManager targetManager, IFramework framework, IClientState clientState, IObjectTable objectTable, ITargetManager targetManager,
@ -74,8 +67,7 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
_gameGui = gameGui; _gameGui = gameGui;
_framework = framework; _framework = framework;
_clientState = clientState; _clientState = clientState;
_objectTable = objectTable; ITargetManager targetManager1 = targetManager;
_targetManager = targetManager;
_condition = condition; _condition = condition;
_commandManager = commandManager; _commandManager = commandManager;
_pluginLog = pluginLog; _pluginLog = pluginLog;
@ -83,36 +75,29 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
_gameStrings = new GameStrings(dataManager, _pluginLog); _gameStrings = new GameStrings(dataManager, _pluginLog);
_externalPluginHandler = new ExternalPluginHandler(_pluginInterface, _pluginLog); _externalPluginHandler = new ExternalPluginHandler(_pluginInterface, _pluginLog);
_gameFunctions = new GameFunctions(objectTable, _clientState, targetManager, dataManager,
_externalPluginHandler, _pluginLog);
_configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration(); _configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration();
_gcRewardsCache = new GcRewardsCache(dataManager); _gcRewardsCache = new GcRewardsCache(dataManager);
_iconCache = new IconCache(textureProvider); _iconCache = new IconCache(textureProvider);
_itemCache = new ItemCache(dataManager); var itemCache = new ItemCache(dataManager);
_configWindow = new ConfigWindow(_pluginInterface, this, _configuration, _gcRewardsCache, _clientState, _pluginLog, _iconCache);
_windowSystem.AddWindow(_configWindow);
_turnInWindow = new TurnInWindow(this, _pluginInterface, _configuration, _condition, _clientState, _gcRewardsCache, _configWindow, _iconCache);
_windowSystem.AddWindow(_turnInWindow);
_gcRankInfo = dataManager.GetExcelSheet<GrandCompanyRank>()!.Where(x => x.RowId > 0) _exchangeHandler = new ExchangeHandler(this, _gameFunctions, targetManager1, _gameGui, _chatGui, _pluginLog);
.ToDictionary(x => x.RowId, x => new GcRankInfo _supplyHandler = new SupplyHandler(this, _gameFunctions, targetManager1, _gameGui, _chatGui, itemCache,
{ _pluginLog);
NameTwinAddersMale = ExtractRankName<GCRankGridaniaMaleText>(dataManager, x.RowId, r => r.Singular),
NameTwinAddersFemale = ExtractRankName<GCRankGridaniaFemaleText>(dataManager, x.RowId, r => r.Singular), _configWindow = new ConfigWindow(_pluginInterface, this, _configuration, _gcRewardsCache, _clientState,
NameMaelstromMale = ExtractRankName<GCRankLimsaMaleText>(dataManager, x.RowId, r => r.Singular), _pluginLog, _iconCache, _gameFunctions);
NameMaelstromFemale = ExtractRankName<GCRankLimsaFemaleText>(dataManager, x.RowId, r => r.Singular), _windowSystem.AddWindow(_configWindow);
NameImmortalFlamesMale = ExtractRankName<GCRankUldahMaleText>(dataManager, x.RowId, r => r.Singular), _turnInWindow = new TurnInWindow(this, _pluginInterface, _configuration, _condition, _clientState,
NameImmortalFlamesFemale = ExtractRankName<GCRankUldahFemaleText>(dataManager, x.RowId, r => r.Singular), _gcRewardsCache, _configWindow, _iconCache, _gameFunctions);
MaxSeals = x.MaxSeals, _windowSystem.AddWindow(_turnInWindow);
RequiredSeals = x.RequiredSeals,
RequiredHuntingLog = x.Unknown10,
})
.AsReadOnly();
_framework.Update += FrameworkUpdate; _framework.Update += FrameworkUpdate;
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw; _pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
_pluginInterface.UiBuilder.OpenConfigUi += _configWindow.Toggle; _pluginInterface.UiBuilder.OpenConfigUi += _configWindow.Toggle;
_clientState.Login += Login; _clientState.Login += Login;
_clientState.Logout += Logout; _clientState.Logout += Logout;
_clientState.TerritoryChanged += TerritoryChanged;
_chatGui.ChatMessage += ChatMessage; _chatGui.ChatMessage += ChatMessage;
_commandManager.AddHandler("/deliveroo", new CommandInfo(ProcessCommand) _commandManager.AddHandler("/deliveroo", new CommandInfo(ProcessCommand)
{ {
@ -129,13 +114,8 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup); _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup);
} }
private static string ExtractRankName<T>(IDataManager dataManager, uint rankId, Func<T, Lumina.Text.SeString> func) private void ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message,
where T : ExcelRow ref bool isHandled)
{
return func(dataManager.GetExcelSheet<T>()!.GetRow(rankId)!).ToString();
}
private void ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
{ {
if (_configuration.PauseAtRank <= 0) if (_configuration.PauseAtRank <= 0)
return; return;
@ -175,6 +155,20 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
} }
} }
internal DateTime ContinueAt { private get; set; } = DateTime.MinValue;
internal List<PurchaseItemRequest> ItemsToPurchaseNow { get; set; } = new();
internal int LastTurnInListSize { get; set; } = int.MaxValue;
internal bool TurnInState
{
set => _turnInWindow.State = value;
}
internal string TurnInError
{
set => _turnInWindow.Error = value;
}
public int EffectiveReservedSealCount public int EffectiveReservedSealCount
{ {
get get
@ -182,7 +176,8 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
if (CharacterConfiguration is { IgnoreMinimumSealsToKeep: true }) if (CharacterConfiguration is { IgnoreMinimumSealsToKeep: true })
return 0; return 0;
return _configuration.ReserveDifferentSealCountAtMaxRank && GetSealCap() == MaxSealCap return _configuration.ReserveDifferentSealCountAtMaxRank &&
_gameFunctions.GetSealCap() == _gameFunctions.MaxSealCap
? _configuration.ReservedSealCountAtMaxRank ? _configuration.ReservedSealCountAtMaxRank
: _configuration.ReservedSealCount; : _configuration.ReservedSealCount;
} }
@ -224,13 +219,6 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
private void Logout() private void Logout()
{ {
CharacterConfiguration = null; CharacterConfiguration = null;
_retainerItemCache.Clear();
}
private void TerritoryChanged(ushort territoryType)
{
// there is no GC area that is in the same zone as a retainer bell, so this should be often enough.
_retainerItemCache.Clear();
} }
private unsafe void FrameworkUpdate(IFramework f) private unsafe void FrameworkUpdate(IFramework f)
@ -239,8 +227,9 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
if (!_clientState.IsLoggedIn || if (!_clientState.IsLoggedIn ||
_clientState.TerritoryType is not 128 and not 130 and not 132 || _clientState.TerritoryType is not 128 and not 130 and not 132 ||
_condition[ConditionFlag.OccupiedInCutSceneEvent] || _condition[ConditionFlag.OccupiedInCutSceneEvent] ||
GetDistanceToNpc(GetQuartermasterId(), out GameObject? quartermaster) >= 7f || _gameFunctions.GetDistanceToNpc(_gameFunctions.GetQuartermasterId(), out GameObject? quartermaster) >= 7f ||
GetDistanceToNpc(GetPersonnelOfficerId(), out GameObject? personnelOfficer) >= 7f || _gameFunctions.GetDistanceToNpc(_gameFunctions.GetPersonnelOfficerId(), out GameObject? personnelOfficer) >=
7f ||
CharacterConfiguration is { DisableForCharacter: true } || CharacterConfiguration is { DisableForCharacter: true } ||
_configWindow.IsOpen) _configWindow.IsOpen)
{ {
@ -252,10 +241,10 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
CurrentStage = Stage.Stopped; CurrentStage = Stage.Stopped;
} }
} }
else if (DateTime.Now > _continueAt) else if (DateTime.Now > ContinueAt)
{ {
_turnInWindow.IsOpen = true; _turnInWindow.IsOpen = true;
_turnInWindow.Multiplier = GetSealMultiplier(); _turnInWindow.Multiplier = _gameFunctions.GetSealMultiplier();
if (!_turnInWindow.State) if (!_turnInWindow.State)
{ {
@ -270,23 +259,25 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
else if (_turnInWindow.State && CurrentStage == Stage.Stopped) else if (_turnInWindow.State && CurrentStage == Stage.Stopped)
{ {
CurrentStage = Stage.TargetPersonnelOfficer; CurrentStage = Stage.TargetPersonnelOfficer;
_itemsToPurchaseNow = _turnInWindow.SelectedItems; ItemsToPurchaseNow = _turnInWindow.SelectedItems;
ResetTurnInErrorHandling(); _supplyHandler.ResetTurnInErrorHandling();
if (_itemsToPurchaseNow.Count > 0) if (ItemsToPurchaseNow.Count > 0)
{ {
_pluginLog.Information("Items to purchase:"); _pluginLog.Information("Items to purchase:");
foreach (var item in _itemsToPurchaseNow) foreach (var item in ItemsToPurchaseNow)
_pluginLog.Information($" {item.Name} (limit = {item.EffectiveLimit})"); _pluginLog.Information($" {item.Name} (limit = {item.EffectiveLimit})");
} }
else else
_pluginLog.Information("No items to purchase configured or available"); _pluginLog.Information("No items to purchase configured or available");
var nextItem = GetNextItemToPurchase(); var nextItem = _exchangeHandler.GetNextItemToPurchase();
if (nextItem != null && GetCurrentSealCount() >= EffectiveReservedSealCount + nextItem.SealCost) if (nextItem != null && _gameFunctions.GetCurrentSealCount() >=
EffectiveReservedSealCount + nextItem.SealCost)
CurrentStage = Stage.TargetQuartermaster; CurrentStage = Stage.TargetQuartermaster;
if (_gameGui.TryGetAddonByName<AddonGrandCompanySupplyList>("GrandCompanySupplyList", out var gcSupplyList) && if (_gameGui.TryGetAddonByName<AddonGrandCompanySupplyList>("GrandCompanySupplyList",
out var gcSupplyList) &&
LAddon.IsAddonReady(&gcSupplyList->AtkUnitBase)) LAddon.IsAddonReady(&gcSupplyList->AtkUnitBase))
CurrentStage = Stage.SelectExpertDeliveryTab; CurrentStage = Stage.SelectExpertDeliveryTab;
@ -301,7 +292,7 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
switch (CurrentStage) switch (CurrentStage)
{ {
case Stage.TargetPersonnelOfficer: case Stage.TargetPersonnelOfficer:
InteractWithPersonnelOfficer(personnelOfficer!, quartermaster!); _supplyHandler.InteractWithPersonnelOfficer(personnelOfficer!, quartermaster!);
break; break;
case Stage.OpenGcSupply: case Stage.OpenGcSupply:
@ -309,19 +300,19 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
break; break;
case Stage.SelectExpertDeliveryTab: case Stage.SelectExpertDeliveryTab:
SelectExpertDeliveryTab(); _supplyHandler.SelectExpertDeliveryTab();
break; break;
case Stage.SelectItemToTurnIn: case Stage.SelectItemToTurnIn:
SelectItemToTurnIn(); _supplyHandler.SelectItemToTurnIn();
break; break;
case Stage.TurnInSelected: case Stage.TurnInSelected:
TurnInSelectedItem(); _supplyHandler.TurnInSelectedItem();
break; break;
case Stage.FinalizeTurnIn: case Stage.FinalizeTurnIn:
FinalizeTurnInItem(); _supplyHandler.FinalizeTurnInItem();
break; break;
case Stage.CloseGcSupplySelectString: case Stage.CloseGcSupplySelectString:
@ -333,23 +324,23 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
break; break;
case Stage.CloseGcSupplyWindowThenStop: case Stage.CloseGcSupplyWindowThenStop:
CloseGcSupplyWindow(); _supplyHandler.CloseGcSupplyWindow();
break; break;
case Stage.TargetQuartermaster: case Stage.TargetQuartermaster:
InteractWithQuartermaster(personnelOfficer!, quartermaster!); _exchangeHandler.InteractWithQuartermaster(personnelOfficer!, quartermaster!);
break; break;
case Stage.SelectRewardTier: case Stage.SelectRewardTier:
SelectRewardTier(); _exchangeHandler.SelectRewardTier();
break; break;
case Stage.SelectRewardSubCategory: case Stage.SelectRewardSubCategory:
SelectRewardSubCategory(); _exchangeHandler.SelectRewardSubCategory();
break; break;
case Stage.SelectReward: case Stage.SelectReward:
SelectReward(); _exchangeHandler.SelectReward();
break; break;
case Stage.ConfirmReward: case Stage.ConfirmReward:
@ -357,7 +348,7 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
break; break;
case Stage.CloseGcExchange: case Stage.CloseGcExchange:
CloseGcExchange(); _exchangeHandler.CloseGcExchange();
break; break;
case Stage.RequestStop: case Stage.RequestStop:
@ -383,15 +374,13 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin
_commandManager.RemoveHandler("/deliveroo"); _commandManager.RemoveHandler("/deliveroo");
_chatGui.ChatMessage -= ChatMessage; _chatGui.ChatMessage -= ChatMessage;
_clientState.TerritoryChanged -= TerritoryChanged;
_clientState.Logout -= Logout; _clientState.Logout -= Logout;
_clientState.Login -= Login; _clientState.Login -= Login;
_pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle; _pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
_framework.Update -= FrameworkUpdate; _framework.Update -= FrameworkUpdate;
_externalPluginHandler.Restore(); _gameFunctions.Dispose();
_externalPluginHandler.Dispose(); _externalPluginHandler.Dispose();
_iconCache.Dispose(); _iconCache.Dispose();
} }

View File

@ -1,22 +1,85 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Memory; using Dalamud.Memory;
using Dalamud.Plugin.Services;
using Deliveroo.External;
using Deliveroo.GameData; using Deliveroo.GameData;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Control; using FFXIVClientStructs.FFXIV.Client.Game.Control;
using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Common.Math; using FFXIVClientStructs.FFXIV.Common.Math;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
using GrandCompany = FFXIVClientStructs.FFXIV.Client.UI.Agent.GrandCompany;
namespace Deliveroo; namespace Deliveroo;
partial class DeliverooPlugin internal sealed class GameFunctions : IDisposable
{ {
private unsafe void InteractWithTarget(GameObject obj) private readonly IObjectTable _objectTable;
private readonly IClientState _clientState;
private readonly ITargetManager _targetManager;
private readonly ExternalPluginHandler _externalPluginHandler;
private readonly IPluginLog _pluginLog;
private readonly ReadOnlyDictionary<uint, GcRankInfo> _gcRankInfo;
private readonly Dictionary<uint, int> _retainerItemCache = new();
public GameFunctions(IObjectTable objectTable, IClientState clientState, ITargetManager targetManager,
IDataManager dataManager, ExternalPluginHandler externalPluginHandler, IPluginLog pluginLog)
{
_objectTable = objectTable;
_clientState = clientState;
_targetManager = targetManager;
_externalPluginHandler = externalPluginHandler;
_pluginLog = pluginLog;
_gcRankInfo = dataManager.GetExcelSheet<GrandCompanyRank>()!.Where(x => x.RowId > 0)
.ToDictionary(x => x.RowId, x => new GcRankInfo
{
NameTwinAddersMale = ExtractRankName<GCRankGridaniaMaleText>(dataManager, x.RowId, r => r.Singular),
NameTwinAddersFemale = ExtractRankName<GCRankGridaniaFemaleText>(dataManager, x.RowId, r => r.Singular),
NameMaelstromMale = ExtractRankName<GCRankLimsaMaleText>(dataManager, x.RowId, r => r.Singular),
NameMaelstromFemale = ExtractRankName<GCRankLimsaFemaleText>(dataManager, x.RowId, r => r.Singular),
NameImmortalFlamesMale = ExtractRankName<GCRankUldahMaleText>(dataManager, x.RowId, r => r.Singular),
NameImmortalFlamesFemale =
ExtractRankName<GCRankUldahFemaleText>(dataManager, x.RowId, r => r.Singular),
MaxSeals = x.MaxSeals,
RequiredSeals = x.RequiredSeals,
RequiredHuntingLog = x.Unknown10,
})
.AsReadOnly();
_clientState.Logout += Logout;
_clientState.TerritoryChanged += TerritoryChanged;
}
private static string ExtractRankName<T>(IDataManager dataManager, uint rankId, Func<T, Lumina.Text.SeString> func)
where T : ExcelRow
{
return func(dataManager.GetExcelSheet<T>()!.GetRow(rankId)!).ToString();
}
private void Logout()
{
_retainerItemCache.Clear();
}
private void TerritoryChanged(ushort territoryType)
{
// there is no GC area that is in the same zone as a retainer bell, so this should be often enough.
_retainerItemCache.Clear();
}
public unsafe void InteractWithTarget(GameObject obj)
{ {
_pluginLog.Information($"Setting target to {obj}"); _pluginLog.Information($"Setting target to {obj}");
if (_targetManager.Target == null || _targetManager.Target != obj) if (_targetManager.Target == null || _targetManager.Target != obj)
@ -28,7 +91,7 @@ partial class DeliverooPlugin
(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)obj.Address, false); (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)obj.Address, false);
} }
internal unsafe int GetCurrentSealCount() public unsafe int GetCurrentSealCount()
{ {
InventoryManager* inventoryManager = InventoryManager.Instance(); InventoryManager* inventoryManager = InventoryManager.Instance();
switch ((GrandCompany)PlayerState.Instance()->GrandCompany) switch ((GrandCompany)PlayerState.Instance()->GrandCompany)
@ -44,11 +107,11 @@ partial class DeliverooPlugin
} }
} }
internal unsafe GrandCompany GetGrandCompany() => (GrandCompany)PlayerState.Instance()->GrandCompany; public unsafe GrandCompany GetGrandCompany() => (GrandCompany)PlayerState.Instance()->GrandCompany;
internal unsafe byte GetGrandCompanyRank() => PlayerState.Instance()->GetGrandCompanyRank(); public unsafe byte GetGrandCompanyRank() => PlayerState.Instance()->GetGrandCompanyRank();
private float GetDistanceToNpc(int npcId, out GameObject? o) public float GetDistanceToNpc(int npcId, out GameObject? o)
{ {
foreach (var obj in _objectTable) foreach (var obj in _objectTable)
{ {
@ -66,12 +129,12 @@ partial class DeliverooPlugin
return float.MaxValue; return float.MaxValue;
} }
private static int GetNpcId(GameObject obj) public static int GetNpcId(GameObject obj)
{ {
return Marshal.ReadInt32(obj.Address + 128); return Marshal.ReadInt32(obj.Address + 128);
} }
private int GetPersonnelOfficerId() public int GetPersonnelOfficerId()
{ {
return GetGrandCompany() switch return GetGrandCompany() switch
{ {
@ -82,7 +145,7 @@ partial class DeliverooPlugin
}; };
} }
private int GetQuartermasterId() public int GetQuartermasterId()
{ {
return GetGrandCompany() switch return GetGrandCompany() switch
{ {
@ -93,17 +156,17 @@ partial class DeliverooPlugin
}; };
} }
private uint GetSealCap() => _gcRankInfo.TryGetValue(GetGrandCompanyRank(), out var rank) ? rank.MaxSeals : 0; public uint GetSealCap() => _gcRankInfo.TryGetValue(GetGrandCompanyRank(), out var rank) ? rank.MaxSeals : 0;
public uint MaxSealCap => _gcRankInfo[11].MaxSeals; public uint MaxSealCap => _gcRankInfo[11].MaxSeals;
internal uint GetSealsRequiredForNextRank() public uint GetSealsRequiredForNextRank()
=> _gcRankInfo.GetValueOrDefault(GetGrandCompanyRank())?.RequiredSeals ?? 0; => _gcRankInfo.GetValueOrDefault(GetGrandCompanyRank())?.RequiredSeals ?? 0;
internal byte GetRequiredHuntingLogForNextRank() public byte GetRequiredHuntingLogForNextRank()
=> _gcRankInfo.GetValueOrDefault(GetGrandCompanyRank() + 1u)?.RequiredHuntingLog ?? 0; => _gcRankInfo.GetValueOrDefault(GetGrandCompanyRank() + 1u)?.RequiredHuntingLog ?? 0;
internal string? GetNextGrandCompanyRankName() public string? GetNextGrandCompanyRankName()
{ {
bool female = _clientState.LocalPlayer!.Customize[(int)CustomizeIndex.Gender] == 1; bool female = _clientState.LocalPlayer!.Customize[(int)CustomizeIndex.Gender] == 1;
GrandCompany grandCompany = GetGrandCompany(); GrandCompany grandCompany = GetGrandCompany();
@ -128,7 +191,7 @@ partial class DeliverooPlugin
return count; return count;
} }
private decimal GetSealMultiplier() public decimal GetSealMultiplier()
{ {
// priority seal allowance // priority seal allowance
if (_clientState.LocalPlayer!.StatusList.Any(x => x.StatusId == 1078)) if (_clientState.LocalPlayer!.StatusList.Any(x => x.StatusId == 1078))
@ -147,7 +210,7 @@ partial class DeliverooPlugin
/// <summary> /// <summary>
/// This returns ALL items that can be turned in, regardless of filter settings. /// This returns ALL items that can be turned in, regardless of filter settings.
/// </summary> /// </summary>
private unsafe List<TurnInItem> BuildTurnInList(AgentGrandCompanySupply* agent) public unsafe List<TurnInItem> BuildTurnInList(AgentGrandCompanySupply* agent)
{ {
List<TurnInItem> list = new(); List<TurnInItem> list = new();
for (int i = 11 /* skip over provisioning items */; i < agent->NumItems; ++i) for (int i = 11 /* skip over provisioning items */; i < agent->NumItems; ++i)
@ -170,4 +233,10 @@ partial class DeliverooPlugin
.ThenBy(x => x.ItemId) .ThenBy(x => x.ItemId)
.ToList(); .ToList();
} }
public void Dispose()
{
_clientState.TerritoryChanged -= TerritoryChanged;
_clientState.Logout -= Logout;
}
} }

View File

@ -1,34 +1,54 @@
using System; using System;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Plugin.Services;
using Deliveroo.GameData; using Deliveroo.GameData;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using LLib.GameUI; using LLib.GameUI;
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
namespace Deliveroo; namespace Deliveroo.Handlers;
partial class DeliverooPlugin internal sealed class ExchangeHandler
{ {
private void InteractWithQuartermaster(GameObject personnelOfficer, GameObject quartermaster) private readonly DeliverooPlugin _plugin;
private readonly GameFunctions _gameFunctions;
private readonly ITargetManager _targetManager;
private readonly IGameGui _gameGui;
private readonly IChatGui _chatGui;
private readonly IPluginLog _pluginLog;
public ExchangeHandler(DeliverooPlugin plugin, GameFunctions gameFunctions, ITargetManager targetManager,
IGameGui gameGui, IChatGui chatGui, IPluginLog pluginLog)
{ {
if (GetCurrentSealCount() < EffectiveReservedSealCount) _plugin = plugin;
_gameFunctions = gameFunctions;
_targetManager = targetManager;
_gameGui = gameGui;
_chatGui = chatGui;
_pluginLog = pluginLog;
}
public void InteractWithQuartermaster(GameObject personnelOfficer, GameObject quartermaster)
{
if (_gameFunctions.GetCurrentSealCount() < _plugin.EffectiveReservedSealCount)
{ {
CurrentStage = Stage.RequestStop; _plugin.CurrentStage = Stage.RequestStop;
return; return;
} }
if (_targetManager.Target == personnelOfficer) if (_targetManager.Target == personnelOfficer)
return; return;
InteractWithTarget(quartermaster); _gameFunctions.InteractWithTarget(quartermaster);
CurrentStage = Stage.SelectRewardTier; _plugin.CurrentStage = Stage.SelectRewardTier;
} }
private PurchaseItemRequest? GetNextItemToPurchase(PurchaseItemRequest? previousRequest = null) public PurchaseItemRequest? GetNextItemToPurchase(PurchaseItemRequest? previousRequest = null)
{ {
foreach (PurchaseItemRequest request in _itemsToPurchaseNow) foreach (PurchaseItemRequest request in _plugin.ItemsToPurchaseNow)
{ {
int toBuy = 0; int toBuy = 0;
if (request == previousRequest) if (request == previousRequest)
@ -40,7 +60,8 @@ partial class DeliverooPlugin
if (request.Type == Configuration.PurchaseType.KeepStocked) if (request.Type == Configuration.PurchaseType.KeepStocked)
{ {
if (GetItemCount(request.ItemId, request.CheckRetainerInventory) + toBuy < request.EffectiveLimit) if (_gameFunctions.GetItemCount(request.ItemId, request.CheckRetainerInventory) + toBuy <
request.EffectiveLimit)
return request; return request;
} }
else else
@ -53,12 +74,12 @@ partial class DeliverooPlugin
return null; return null;
} }
private unsafe void SelectRewardTier() public unsafe void SelectRewardTier()
{ {
PurchaseItemRequest? item = GetNextItemToPurchase(); PurchaseItemRequest? item = GetNextItemToPurchase();
if (item == null) if (item == null)
{ {
CurrentStage = Stage.CloseGcExchange; _plugin.CurrentStage = Stage.CloseGcExchange;
return; return;
} }
@ -79,17 +100,17 @@ partial class DeliverooPlugin
new() { Type = 0, Int = 0 } new() { Type = 0, Int = 0 }
}; };
addonExchange->FireCallback(9, selectRank); addonExchange->FireCallback(9, selectRank);
_continueAt = DateTime.Now.AddSeconds(0.5); _plugin.ContinueAt = DateTime.Now.AddSeconds(0.5);
CurrentStage = Stage.SelectRewardSubCategory; _plugin.CurrentStage = Stage.SelectRewardSubCategory;
} }
} }
private unsafe void SelectRewardSubCategory() public unsafe void SelectRewardSubCategory()
{ {
PurchaseItemRequest? item = GetNextItemToPurchase(); PurchaseItemRequest? item = GetNextItemToPurchase();
if (item == null) if (item == null)
{ {
CurrentStage = Stage.CloseGcExchange; _plugin.CurrentStage = Stage.CloseGcExchange;
return; return;
} }
@ -110,25 +131,25 @@ partial class DeliverooPlugin
new() { Type = 0, Int = 0 } new() { Type = 0, Int = 0 }
}; };
addonExchange->FireCallback(9, selectType); addonExchange->FireCallback(9, selectType);
_continueAt = DateTime.Now.AddSeconds(0.5); _plugin.ContinueAt = DateTime.Now.AddSeconds(0.5);
CurrentStage = Stage.SelectReward; _plugin.CurrentStage = Stage.SelectReward;
} }
} }
private unsafe void SelectReward() public unsafe void SelectReward()
{ {
if (_gameGui.TryGetAddonByName<AtkUnitBase>("GrandCompanyExchange", out var addonExchange) && if (_gameGui.TryGetAddonByName<AtkUnitBase>("GrandCompanyExchange", out var addonExchange) &&
LAddon.IsAddonReady(addonExchange)) LAddon.IsAddonReady(addonExchange))
{ {
if (SelectRewardItem(addonExchange)) if (SelectRewardItem(addonExchange))
{ {
_continueAt = DateTime.Now.AddSeconds(0.2); _plugin.ContinueAt = DateTime.Now.AddSeconds(0.2);
CurrentStage = Stage.ConfirmReward; _plugin.CurrentStage = Stage.ConfirmReward;
} }
else else
{ {
_continueAt = DateTime.Now.AddSeconds(0.2); _plugin.ContinueAt = DateTime.Now.AddSeconds(0.2);
CurrentStage = Stage.CloseGcExchange; _plugin.CurrentStage = Stage.CloseGcExchange;
} }
} }
} }
@ -146,9 +167,11 @@ partial class DeliverooPlugin
if (itemId == item.ItemId) if (itemId == item.ItemId)
{ {
_pluginLog.Information($"Selecting item {itemId}, {i}"); _pluginLog.Information($"Selecting item {itemId}, {i}");
long toBuy = (GetCurrentSealCount() - EffectiveReservedSealCount) / item.SealCost; long toBuy = (_gameFunctions.GetCurrentSealCount() - _plugin.EffectiveReservedSealCount) /
item.SealCost;
if (item.Type == Configuration.PurchaseType.KeepStocked) if (item.Type == Configuration.PurchaseType.KeepStocked)
toBuy = Math.Min(toBuy, item.EffectiveLimit - GetItemCount(item.ItemId, item.CheckRetainerInventory)); toBuy = Math.Min(toBuy,
item.EffectiveLimit - _gameFunctions.GetItemCount(item.ItemId, item.CheckRetainerInventory));
else else
toBuy = Math.Min(toBuy, item.EffectiveLimit); toBuy = Math.Min(toBuy, item.EffectiveLimit);
@ -186,7 +209,7 @@ partial class DeliverooPlugin
return false; return false;
} }
private unsafe void CloseGcExchange() public unsafe void CloseGcExchange()
{ {
if (_gameGui.TryGetAddonByName<AtkUnitBase>("GrandCompanyExchange", out var addonExchange) && if (_gameGui.TryGetAddonByName<AtkUnitBase>("GrandCompanyExchange", out var addonExchange) &&
LAddon.IsAddonReady(addonExchange)) LAddon.IsAddonReady(addonExchange))
@ -194,15 +217,15 @@ partial class DeliverooPlugin
addonExchange->FireCallbackInt(-1); addonExchange->FireCallbackInt(-1);
// If we just turned in the final item, there's no need to talk to the personnel officer again // If we just turned in the final item, there's no need to talk to the personnel officer again
if (_lastTurnInListSize == 1) if (_plugin.LastTurnInListSize == 1)
{ {
_turnInWindow.State = false; _plugin.TurnInState = false;
CurrentStage = Stage.RequestStop; _plugin.CurrentStage = Stage.RequestStop;
} }
else else
{ {
_continueAt = DateTime.Now.AddSeconds(1); _plugin.ContinueAt = DateTime.Now.AddSeconds(1);
CurrentStage = Stage.TargetPersonnelOfficer; _plugin.CurrentStage = Stage.TargetPersonnelOfficer;
} }
} }
} }

View File

@ -1,29 +1,54 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services;
using Deliveroo.GameData; using Deliveroo.GameData;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using LLib;
using LLib.GameUI; using LLib.GameUI;
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
namespace Deliveroo; namespace Deliveroo;
partial class DeliverooPlugin internal sealed class SupplyHandler
{ {
private void InteractWithPersonnelOfficer(GameObject personnelOfficer, GameObject quartermaster) private readonly DeliverooPlugin _plugin;
private readonly GameFunctions _gameFunctions;
private readonly ITargetManager _targetManager;
private readonly IGameGui _gameGui;
private readonly IChatGui _chatGui;
private readonly ItemCache _itemCache;
private readonly IPluginLog _pluginLog;
private uint _turnInErrors;
public SupplyHandler(DeliverooPlugin plugin, GameFunctions gameFunctions, ITargetManager targetManager,
IGameGui gameGui, IChatGui chatGui, ItemCache itemCache, IPluginLog pluginLog)
{
_plugin = plugin;
_gameFunctions = gameFunctions;
_targetManager = targetManager;
_gameGui = gameGui;
_chatGui = chatGui;
_itemCache = itemCache;
_pluginLog = pluginLog;
}
public void InteractWithPersonnelOfficer(GameObject personnelOfficer, GameObject quartermaster)
{ {
if (_targetManager.Target == quartermaster) if (_targetManager.Target == quartermaster)
return; return;
InteractWithTarget(personnelOfficer); _gameFunctions.InteractWithTarget(personnelOfficer);
CurrentStage = Stage.OpenGcSupply; _plugin.CurrentStage = Stage.OpenGcSupply;
} }
private unsafe void SelectExpertDeliveryTab() public unsafe void SelectExpertDeliveryTab()
{ {
var agentInterface = AgentModule.Instance()->GetAgentByInternalId(AgentId.GrandCompanySupply); var agentInterface = AgentModule.Instance()->GetAgentByInternalId(AgentId.GrandCompanySupply);
if (agentInterface != null && agentInterface->IsAgentActive()) if (agentInterface != null && agentInterface->IsAgentActive())
@ -42,7 +67,7 @@ partial class DeliverooPlugin
{ {
_pluginLog.Information("Tab already selected, probably due to haseltweaks"); _pluginLog.Information("Tab already selected, probably due to haseltweaks");
ResetTurnInErrorHandling(); ResetTurnInErrorHandling();
CurrentStage = Stage.SelectItemToTurnIn; _plugin.CurrentStage = Stage.SelectItemToTurnIn;
return; return;
} }
@ -55,18 +80,18 @@ partial class DeliverooPlugin
}; };
addon->FireCallback(3, selectExpertDeliveryTab); addon->FireCallback(3, selectExpertDeliveryTab);
ResetTurnInErrorHandling(); ResetTurnInErrorHandling();
CurrentStage = Stage.SelectItemToTurnIn; _plugin.CurrentStage = Stage.SelectItemToTurnIn;
} }
} }
private void ResetTurnInErrorHandling(int listSize = int.MaxValue) public void ResetTurnInErrorHandling(int listSize = int.MaxValue)
{ {
_pluginLog.Verbose("Resetting error handling state"); _pluginLog.Verbose("Resetting error handling state");
_lastTurnInListSize = listSize; _plugin.LastTurnInListSize = listSize;
_turnInErrors = 0; _turnInErrors = 0;
} }
private unsafe void SelectItemToTurnIn() public unsafe void SelectItemToTurnIn()
{ {
var agentInterface = AgentModule.Instance()->GetAgentByInternalId(AgentId.GrandCompanySupply); var agentInterface = AgentModule.Instance()->GetAgentByInternalId(AgentId.GrandCompanySupply);
if (agentInterface != null && agentInterface->IsAgentActive()) if (agentInterface != null && agentInterface->IsAgentActive())
@ -86,14 +111,14 @@ partial class DeliverooPlugin
if (addonGc->SelectedTab != 2) if (addonGc->SelectedTab != 2)
{ {
_turnInWindow.Error = "Wrong tab selected"; _plugin.TurnInError = "Wrong tab selected";
return; return;
} }
ItemFilterType configuredFilter = ResolveSelectedSupplyFilter(); ItemFilterType configuredFilter = ResolveSelectedSupplyFilter();
if (addonGc->SelectedFilter == 0 || addonGc->SelectedFilter != (int)configuredFilter) if (addonGc->SelectedFilter == 0 || addonGc->SelectedFilter != (int)configuredFilter)
{ {
_turnInWindow.Error = _plugin.TurnInError =
$"Wrong filter selected (expected {configuredFilter}, but is {(ItemFilterType)addonGc->SelectedFilter})"; $"Wrong filter selected (expected {configuredFilter}, but is {(ItemFilterType)addonGc->SelectedFilter})";
return; return;
} }
@ -103,7 +128,7 @@ partial class DeliverooPlugin
{ {
_pluginLog.Information( _pluginLog.Information(
$"No items to turn in ({addonGc->ListEmptyTextNode->AtkResNode.IsVisible}, {currentListSize})"); $"No items to turn in ({addonGc->ListEmptyTextNode->AtkResNode.IsVisible}, {currentListSize})");
CurrentStage = Stage.CloseGcSupplySelectStringThenStop; _plugin.CurrentStage = Stage.CloseGcSupplySelectStringThenStop;
addon->FireCallbackInt(-1); addon->FireCallbackInt(-1);
return; return;
} }
@ -112,29 +137,29 @@ partial class DeliverooPlugin
// something is wrong. // something is wrong.
if (_turnInErrors > 10) if (_turnInErrors > 10)
{ {
_turnInWindow.Error = "Unable to refresh item list"; _plugin.TurnInError = "Unable to refresh item list";
return; return;
} }
if (currentListSize >= _lastTurnInListSize) if (currentListSize >= _plugin.LastTurnInListSize)
{ {
_turnInErrors++; _turnInErrors++;
_pluginLog.Information( _pluginLog.Information(
$"Trying to refresh expert delivery list manually ({_turnInErrors}, old list size = {_lastTurnInListSize}, new list size = {currentListSize})..."); $"Trying to refresh expert delivery list manually ({_turnInErrors}, old list size = {_plugin.LastTurnInListSize}, new list size = {currentListSize})...");
addon->FireCallbackInt(2); addon->FireCallbackInt(2);
_continueAt = DateTime.Now.AddSeconds(0.1); _plugin.ContinueAt = DateTime.Now.AddSeconds(0.1);
return; return;
} }
ResetTurnInErrorHandling(currentListSize); ResetTurnInErrorHandling(currentListSize);
var agent = (AgentGrandCompanySupply*)agentInterface; var agent = (AgentGrandCompanySupply*)agentInterface;
List<TurnInItem> items = BuildTurnInList(agent); List<TurnInItem> items = _gameFunctions.BuildTurnInList(agent);
if (items.Count == 0) if (items.Count == 0)
{ {
// probably shouldn't happen with the previous node visibility check // probably shouldn't happen with the previous node visibility check
CurrentStage = Stage.CloseGcSupplySelectStringThenStop; _plugin.CurrentStage = Stage.CloseGcSupplySelectStringThenStop;
addon->FireCallbackInt(-1); addon->FireCallbackInt(-1);
return; return;
} }
@ -158,9 +183,9 @@ partial class DeliverooPlugin
// --------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------
// TODO If we ever manage to obtain a mapping name to itemId here, we can try and exclude e.g. Red Onion // TODO If we ever manage to obtain a mapping name to itemId here, we can try and exclude e.g. Red Onion
// Helms from being turned in. // Helms from being turned in.
if (GetCurrentSealCount() + items[0].SealsWithBonus > GetSealCap()) if (_gameFunctions.GetCurrentSealCount() + items[0].SealsWithBonus > _gameFunctions.GetSealCap())
{ {
CurrentStage = Stage.CloseGcSupplySelectString; _plugin.CurrentStage = Stage.CloseGcSupplySelectString;
addon->FireCallbackInt(-1); addon->FireCallbackInt(-1);
return; return;
} }
@ -172,11 +197,11 @@ partial class DeliverooPlugin
new() { Type = 0, Int = 0 } new() { Type = 0, Int = 0 }
}; };
addon->FireCallback(3, selectFirstItem); addon->FireCallback(3, selectFirstItem);
CurrentStage = Stage.TurnInSelected; _plugin.CurrentStage = Stage.TurnInSelected;
} }
} }
private unsafe void TurnInSelectedItem() public unsafe void TurnInSelectedItem()
{ {
if (_gameGui.TryGetAddonByName<AddonGrandCompanySupplyReward>("GrandCompanySupplyReward", if (_gameGui.TryGetAddonByName<AddonGrandCompanySupplyReward>("GrandCompanySupplyReward",
out var addonSupplyReward) && LAddon.IsAddonReady(&addonSupplyReward->AtkUnitBase)) out var addonSupplyReward) && LAddon.IsAddonReady(&addonSupplyReward->AtkUnitBase))
@ -191,19 +216,19 @@ partial class DeliverooPlugin
.Build()); .Build());
addonSupplyReward->AtkUnitBase.FireCallbackInt(1); addonSupplyReward->AtkUnitBase.FireCallbackInt(1);
CurrentStage = Stage.CloseGcSupplyWindowThenStop; _plugin.CurrentStage = Stage.CloseGcSupplyWindowThenStop;
return; return;
} }
_pluginLog.Information($"Turning in '{itemName}'"); _pluginLog.Information($"Turning in '{itemName}'");
addonSupplyReward->AtkUnitBase.FireCallbackInt(0); addonSupplyReward->AtkUnitBase.FireCallbackInt(0);
_continueAt = DateTime.Now.AddSeconds(0.58); _plugin.ContinueAt = DateTime.Now.AddSeconds(0.58);
CurrentStage = Stage.FinalizeTurnIn; _plugin.CurrentStage = Stage.FinalizeTurnIn;
} }
} }
private unsafe void FinalizeTurnInItem() public unsafe void FinalizeTurnInItem()
{ {
if (_gameGui.TryGetAddonByName<AddonGrandCompanySupplyList>("GrandCompanySupplyList", if (_gameGui.TryGetAddonByName<AddonGrandCompanySupplyList>("GrandCompanySupplyList",
out var addonSupplyList) && LAddon.IsAddonReady(&addonSupplyList->AtkUnitBase)) out var addonSupplyList) && LAddon.IsAddonReady(&addonSupplyList->AtkUnitBase))
@ -215,19 +240,19 @@ partial class DeliverooPlugin
new() { Type = 0, Int = 0 } new() { Type = 0, Int = 0 }
}; };
addonSupplyList->AtkUnitBase.FireCallback(3, updateFilter); addonSupplyList->AtkUnitBase.FireCallback(3, updateFilter);
CurrentStage = Stage.SelectItemToTurnIn; _plugin.CurrentStage = Stage.SelectItemToTurnIn;
} }
} }
private ItemFilterType ResolveSelectedSupplyFilter() private ItemFilterType ResolveSelectedSupplyFilter()
{ {
if (CharacterConfiguration is { UseHideArmouryChestItemsFilter: true }) if (_plugin.CharacterConfiguration is { UseHideArmouryChestItemsFilter: true })
return ItemFilterType.HideArmouryChestItems; return ItemFilterType.HideArmouryChestItems;
return ItemFilterType.HideGearSetItems; return ItemFilterType.HideGearSetItems;
} }
private unsafe void CloseGcSupplyWindow() public unsafe void CloseGcSupplyWindow()
{ {
var agentInterface = AgentModule.Instance()->GetAgentByInternalId(AgentId.GrandCompanySupply); var agentInterface = AgentModule.Instance()->GetAgentByInternalId(AgentId.GrandCompanySupply);
if (agentInterface != null && agentInterface->IsAgentActive()) if (agentInterface != null && agentInterface->IsAgentActive())
@ -240,7 +265,7 @@ partial class DeliverooPlugin
if (addon == null || !LAddon.IsAddonReady(addon)) if (addon == null || !LAddon.IsAddonReady(addon))
return; return;
CurrentStage = Stage.CloseGcSupplySelectStringThenStop; _plugin.CurrentStage = Stage.CloseGcSupplySelectStringThenStop;
addon->FireCallbackInt(-1); addon->FireCallbackInt(-1);
} }
} }

View File

@ -25,13 +25,15 @@ internal sealed class ConfigWindow : LWindow
private readonly IClientState _clientState; private readonly IClientState _clientState;
private readonly IPluginLog _pluginLog; private readonly IPluginLog _pluginLog;
private readonly IconCache _iconCache; private readonly IconCache _iconCache;
private readonly GameFunctions _gameFunctions;
private readonly IReadOnlyDictionary<uint, GcRewardItem> _itemLookup; private readonly IReadOnlyDictionary<uint, GcRewardItem> _itemLookup;
private string _searchString = string.Empty; private string _searchString = string.Empty;
private uint _dragDropSource; private uint _dragDropSource;
public ConfigWindow(DalamudPluginInterface pluginInterface, DeliverooPlugin plugin, Configuration configuration, public ConfigWindow(DalamudPluginInterface pluginInterface, DeliverooPlugin plugin, Configuration configuration,
GcRewardsCache gcRewardsCache, IClientState clientState, IPluginLog pluginLog, IconCache iconCache) GcRewardsCache gcRewardsCache, IClientState clientState, IPluginLog pluginLog, IconCache iconCache,
GameFunctions gameFunctions)
: base("Deliveroo - Configuration###DeliverooConfig") : base("Deliveroo - Configuration###DeliverooConfig")
{ {
_pluginInterface = pluginInterface; _pluginInterface = pluginInterface;
@ -41,6 +43,7 @@ internal sealed class ConfigWindow : LWindow
_clientState = clientState; _clientState = clientState;
_pluginLog = pluginLog; _pluginLog = pluginLog;
_iconCache = iconCache; _iconCache = iconCache;
_gameFunctions = gameFunctions;
_itemLookup = _gcRewardsCache.RewardLookup; _itemLookup = _gcRewardsCache.RewardLookup;
@ -76,7 +79,8 @@ internal sealed class ConfigWindow : LWindow
uint? itemToRemove = null; uint? itemToRemove = null;
uint? itemToAdd = null; uint? itemToAdd = null;
int indexToAdd = 0; int indexToAdd = 0;
if (ImGui.BeginChild("Items", new Vector2(-1, -ImGui.GetFrameHeightWithSpacing()), true, ImGuiWindowFlags.NoSavedSettings)) if (ImGui.BeginChild("Items", new Vector2(-1, -ImGui.GetFrameHeightWithSpacing()), true,
ImGuiWindowFlags.NoSavedSettings))
{ {
for (int i = 0; i < _configuration.ItemsAvailableForPurchase.Count; ++i) for (int i = 0; i < _configuration.ItemsAvailableForPurchase.Count; ++i)
{ {
@ -91,10 +95,12 @@ internal sealed class ConfigWindow : LWindow
Vector2 iconSize = new Vector2(ImGui.GetTextLineHeight() + ImGui.GetStyle().ItemSpacing.Y); Vector2 iconSize = new Vector2(ImGui.GetTextLineHeight() + ImGui.GetStyle().ItemSpacing.Y);
if (icon != null) if (icon != null)
{ {
ImGui.SetCursorPos(pos + new Vector2(iconSize.X + ImGui.GetStyle().FramePadding.X, ImGui.GetStyle().ItemSpacing.Y / 2)); ImGui.SetCursorPos(pos + new Vector2(iconSize.X + ImGui.GetStyle().FramePadding.X,
ImGui.GetStyle().ItemSpacing.Y / 2));
} }
ImGui.Selectable($"{item.Name}{(item.Limited ? $" {SeIconChar.Hyadelyn.ToIconString()}" : "")}", false, ImGuiSelectableFlags.SpanAllColumns); ImGui.Selectable($"{item.Name}{(item.Limited ? $" {SeIconChar.Hyadelyn.ToIconString()}" : "")}",
false, ImGuiSelectableFlags.SpanAllColumns);
if (icon != null) if (icon != null)
{ {
@ -168,7 +174,8 @@ internal sealed class ConfigWindow : LWindow
bool addFirst = ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256, bool addFirst = ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256,
ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue); ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue);
foreach (var item in comboValues.Where(x => x.Name.Contains(_searchString, StringComparison.OrdinalIgnoreCase))) foreach (var item in comboValues.Where(x =>
x.Name.Contains(_searchString, StringComparison.OrdinalIgnoreCase)))
{ {
IDalamudTextureWrap? icon = _iconCache.GetIcon(item.IconId); IDalamudTextureWrap? icon = _iconCache.GetIcon(item.IconId);
if (icon != null) if (icon != null)
@ -322,7 +329,7 @@ internal sealed class ConfigWindow : LWindow
if (ImGui.InputInt("Minimum Seals to keep (e.g. for Squadron Missions)", ref reservedSealCount, 1000)) if (ImGui.InputInt("Minimum Seals to keep (e.g. for Squadron Missions)", ref reservedSealCount, 1000))
{ {
_configuration.ReservedSealCount = _configuration.ReservedSealCount =
Math.Max(0, Math.Min((int)_plugin.MaxSealCap, reservedSealCount)); Math.Max(0, Math.Min((int)_gameFunctions.MaxSealCap, reservedSealCount));
Save(); Save();
} }
@ -343,7 +350,7 @@ internal sealed class ConfigWindow : LWindow
if (ImGui.InputInt("Minimum seals to keep at max rank", ref reservedSealCountAtMaxRank)) if (ImGui.InputInt("Minimum seals to keep at max rank", ref reservedSealCountAtMaxRank))
{ {
_configuration.ReservedSealCountAtMaxRank = Math.Max(0, _configuration.ReservedSealCountAtMaxRank = Math.Max(0,
Math.Min((int)_plugin.MaxSealCap, reservedSealCountAtMaxRank)); Math.Min((int)_gameFunctions.MaxSealCap, reservedSealCountAtMaxRank));
Save(); Save();
} }

View File

@ -52,12 +52,13 @@ internal sealed class TurnInWindow : LWindow
private readonly GcRewardsCache _gcRewardsCache; private readonly GcRewardsCache _gcRewardsCache;
private readonly ConfigWindow _configWindow; private readonly ConfigWindow _configWindow;
private readonly IconCache _iconCache; private readonly IconCache _iconCache;
private readonly GameFunctions _gameFunctions;
private bool _state; private bool _state;
public TurnInWindow(DeliverooPlugin plugin, DalamudPluginInterface pluginInterface, Configuration configuration, public TurnInWindow(DeliverooPlugin plugin, DalamudPluginInterface pluginInterface, Configuration configuration,
ICondition condition, IClientState clientState, GcRewardsCache gcRewardsCache, ConfigWindow configWindow, ICondition condition, IClientState clientState, GcRewardsCache gcRewardsCache, ConfigWindow configWindow,
IconCache iconCache) IconCache iconCache, GameFunctions gameFunctions)
: base("GC Delivery###DeliverooTurnIn") : base("GC Delivery###DeliverooTurnIn")
{ {
_plugin = plugin; _plugin = plugin;
@ -68,6 +69,7 @@ internal sealed class TurnInWindow : LWindow
_gcRewardsCache = gcRewardsCache; _gcRewardsCache = gcRewardsCache;
_configWindow = configWindow; _configWindow = configWindow;
_iconCache = iconCache; _iconCache = iconCache;
_gameFunctions = gameFunctions;
Position = new Vector2(100, 100); Position = new Vector2(100, 100);
PositionCondition = ImGuiCond.FirstUseEver; PositionCondition = ImGuiCond.FirstUseEver;
@ -128,11 +130,11 @@ internal sealed class TurnInWindow : LWindow
{ {
get get
{ {
GrandCompany grandCompany = _plugin.GetGrandCompany(); GrandCompany grandCompany = _gameFunctions.GetGrandCompany();
if (grandCompany == GrandCompany.None) if (grandCompany == GrandCompany.None)
return new List<PurchaseItemRequest>(); return new List<PurchaseItemRequest>();
var rank = _plugin.GetGrandCompanyRank(); var rank = _gameFunctions.GetGrandCompanyRank();
return ItemsWrapper.GetItemsToPurchase() return ItemsWrapper.GetItemsToPurchase()
.Where(x => x.ItemId != GcRewardItem.None.ItemId) .Where(x => x.ItemId != GcRewardItem.None.ItemId)
.Where(x => x.Enabled) .Where(x => x.Enabled)
@ -176,7 +178,7 @@ internal sealed class TurnInWindow : LWindow
public override unsafe void Draw() public override unsafe void Draw()
{ {
GrandCompany grandCompany = _plugin.GetGrandCompany(); GrandCompany grandCompany = _gameFunctions.GetGrandCompany();
if (grandCompany == GrandCompany.None) if (grandCompany == GrandCompany.None)
{ {
// not sure we should ever get here // not sure we should ever get here
@ -184,7 +186,7 @@ internal sealed class TurnInWindow : LWindow
return; return;
} }
if (_plugin.GetGrandCompanyRank() < 6) if (_gameFunctions.GetGrandCompanyRank() < 6)
{ {
State = false; State = false;
ImGui.TextColored(ImGuiColors.DalamudRed, "You do not have the required rank for Expert Delivery."); ImGui.TextColored(ImGuiColors.DalamudRed, "You do not have the required rank for Expert Delivery.");
@ -262,18 +264,19 @@ internal sealed class TurnInWindow : LWindow
private unsafe void DrawNextRankPrequesites() private unsafe void DrawNextRankPrequesites()
{ {
string? rankName = _plugin.GetNextGrandCompanyRankName(); string? rankName = _gameFunctions.GetNextGrandCompanyRankName();
if (rankName != null) if (rankName != null)
{ {
int currentSeals = _plugin.GetCurrentSealCount(); int currentSeals = _gameFunctions.GetCurrentSealCount();
uint requiredSeals = _plugin.GetSealsRequiredForNextRank(); uint requiredSeals = _gameFunctions.GetSealsRequiredForNextRank();
int currentHuntingLog = MonsterNoteManager.Instance()->RankDataArraySpan[(int)_plugin.GetGrandCompany() + 7] int currentHuntingLog =
.Rank; MonsterNoteManager.Instance()->RankDataArraySpan[(int)_gameFunctions.GetGrandCompany() + 7]
byte requiredHuntingLog = _plugin.GetRequiredHuntingLogForNextRank(); .Rank;
byte requiredHuntingLog = _gameFunctions.GetRequiredHuntingLogForNextRank();
bool enoughSeals = currentSeals >= requiredSeals; bool enoughSeals = currentSeals >= requiredSeals;
bool enoughHuntingLog = requiredHuntingLog >= currentHuntingLog; bool enoughHuntingLog = currentHuntingLog >= requiredHuntingLog;
if (enoughSeals && enoughHuntingLog) if (enoughSeals && enoughHuntingLog)
ImGui.TextColored(ImGuiColors.HealerGreen, $"You meet all requirements to rank up to {rankName}."); ImGui.TextColored(ImGuiColors.HealerGreen, $"You meet all requirements to rank up to {rankName}.");
@ -318,8 +321,8 @@ internal sealed class TurnInWindow : LWindow
foreach (uint itemId in _configuration.ItemsAvailableForPurchase) foreach (uint itemId in _configuration.ItemsAvailableForPurchase)
{ {
var gcReward = _gcRewardsCache.GetReward(itemId); var gcReward = _gcRewardsCache.GetReward(itemId);
int itemCountWithoutRetainers = _plugin.GetItemCount(itemId, false); int itemCountWithoutRetainers = _gameFunctions.GetItemCount(itemId, false);
int itemCountWithRetainers = _plugin.GetItemCount(itemId, true); int itemCountWithRetainers = _gameFunctions.GetItemCount(itemId, true);
string itemNameWithoutRetainers = gcReward.Name; string itemNameWithoutRetainers = gcReward.Name;
string itemNameWithRetainers = gcReward.Name; string itemNameWithRetainers = gcReward.Name;
if (itemCountWithoutRetainers > 0) if (itemCountWithoutRetainers > 0)
@ -479,7 +482,7 @@ internal sealed class TurnInWindow : LWindow
ImGui.TextColored(ImGuiColors.DalamudRed, ImGui.TextColored(ImGuiColors.DalamudRed,
"This item will be skipped, as you are in the wrong Grand Company."); "This item will be skipped, as you are in the wrong Grand Company.");
} }
else if (comboItem.Item.RequiredRank > _plugin.GetGrandCompanyRank()) else if (comboItem.Item.RequiredRank > _gameFunctions.GetGrandCompanyRank())
{ {
ImGui.TextColored(ImGuiColors.DalamudRed, ImGui.TextColored(ImGuiColors.DalamudRed,
"This item will be skipped, your rank isn't high enough to buy it."); "This item will be skipped, your rank isn't high enough to buy it.");