//
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//
namespace MUnique.OpenMU.GameLogic.Offline;
using MUnique.OpenMU.GameLogic.MuHelper;
using MUnique.OpenMU.GameLogic.PlayerActions.Items;
///
/// Handles auto-repair of equipped items for the offline player.
///
internal sealed class RepairHandler
{
///
/// The durability health threshold (inclusive, in percent) below which a repair is triggered.
/// Mirrors the client's DEFAULT_DURABILITY_THRESHOLD constant in MuHelper.cpp.
///
private const int DurabilityRepairThresholdPercent = 50;
private readonly Player _player;
private readonly IMuHelperSettings? _config;
private readonly ItemRepairAction _repairAction = new();
private bool _loggedDisabled;
///
/// Initializes a new instance of the class.
///
/// The player.
/// The MU Helper configuration.
public RepairHandler(Player player, IMuHelperSettings? config)
{
this._player = player;
this._config = config;
}
///
/// Performs repairs on equipped items if the configuration allows it
/// and the item's durability is at or below %.
///
public async ValueTask PerformRepairsAsync()
{
if (this._config is not { RepairItem: true })
{
// Once per session: this states a configuration, not an event, and the tick runs twice a second.
if (!this._loggedDisabled)
{
this._loggedDisabled = true;
this._player.Logger.LogDebug("Auto-repair is disabled by MU Helper configuration for character {CharacterName}.", this._player.Name);
}
return;
}
for (byte i = InventoryConstants.FirstEquippableItemSlotIndex;
i <= InventoryConstants.LastEquippableItemSlotIndex;
i++)
{
if (i == InventoryConstants.PetSlot)
{
continue;
}
var item = this._player.Inventory?.GetItem(i);
if (item is null)
{
continue;
}
if (!NeedsDurabilityRepair(item))
{
continue;
}
await this._repairAction.RepairItemAsync(this._player, i).ConfigureAwait(false);
}
}
///
/// Returns when the item's durability health is at or below
/// %, using ceiling-integer arithmetic
/// to match the client formula: iHealth = (durability * 100 + max - 1) / max.
///
private static bool NeedsDurabilityRepair(Item item)
{
var max = item.GetMaximumDurabilityOfOnePiece();
if (max == 0)
{
return false;
}
var durabilityHealthPercent = ((int)item.Durability * 100 + max - 1) / max;
return durabilityHealthPercent <= DurabilityRepairThresholdPercent;
}
}