96 lines
4.2 KiB
C#
96 lines
4.2 KiB
C#
using UnityEngine;
|
|
using BaseGames.Core;
|
|
using BaseGames.Core.Events;
|
|
using BaseGames.Core.Save;
|
|
using BaseGames.Player.States;
|
|
|
|
namespace BaseGames.Equipment
|
|
{
|
|
/// <summary>
|
|
/// 工具槽管理器(架构 09_ProgressionModule §7.5)。
|
|
/// 管理玩家的 2 个工具槽(装备、使用、冷却)。
|
|
/// 实现 ISaveable 以持久化槽位状态。
|
|
/// </summary>
|
|
public class ToolSlotManager : MonoBehaviour, ISaveable
|
|
{
|
|
private const int SlotCount = 2;
|
|
|
|
[SerializeField] private ToolCatalogSO _toolCatalog;
|
|
[SerializeField] private ToolSO[] _slots = new ToolSO[SlotCount];
|
|
[SerializeField] private int[] _remainingUses = new int[SlotCount]; // -1 = 无限
|
|
[SerializeField] private ToolUsedEventChannelSO _onToolUsed;
|
|
|
|
private readonly float[] _cooldowns = new float[SlotCount];
|
|
|
|
private void Awake()
|
|
{
|
|
Debug.Assert(_toolCatalog != null, "[ToolSlotManager] _toolCatalog 未赋值,请在 Inspector 中指定 ToolCatalogSO。", this);
|
|
}
|
|
|
|
private void OnEnable() => ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
|
|
private void OnDisable() => ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
|
|
|
|
// ── 装备 ─────────────────────────────────────────────────────────────
|
|
public void EquipTool(int slotIndex, ToolSO tool)
|
|
{
|
|
if (slotIndex < 0 || slotIndex >= SlotCount) return;
|
|
_slots[slotIndex] = tool;
|
|
_remainingUses[slotIndex] = tool != null ? tool.maxUses : 0;
|
|
_cooldowns[slotIndex] = 0f;
|
|
}
|
|
|
|
// ── 使用 ─────────────────────────────────────────────────────────────
|
|
public bool TryUseTool(int slotIndex, PlayerController player)
|
|
{
|
|
if (slotIndex < 0 || slotIndex >= SlotCount) return false;
|
|
var tool = _slots[slotIndex];
|
|
if (tool == null) return false;
|
|
if (_cooldowns[slotIndex] > 0f) return false;
|
|
if (_remainingUses[slotIndex] == 0) return false; // 已耗尽(-1 = 无限不触发)
|
|
|
|
tool.effect?.Use(player);
|
|
|
|
if (_remainingUses[slotIndex] > 0) _remainingUses[slotIndex]--;
|
|
_cooldowns[slotIndex] = tool is IToolCooldown tc ? tc.CooldownDuration : 0f;
|
|
|
|
_onToolUsed?.Raise(new ToolUsedPayload
|
|
{
|
|
SlotIndex = slotIndex,
|
|
ToolId = tool.toolId
|
|
});
|
|
return true;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
for (int i = 0; i < SlotCount; i++)
|
|
if (_cooldowns[i] > 0f) _cooldowns[i] -= Time.deltaTime;
|
|
}
|
|
|
|
// ── 查询 ─────────────────────────────────────────────────────────────
|
|
public ToolSO GetTool(int slotIndex) => _slots[slotIndex];
|
|
public int GetRemainingUses(int slotIndex) => _remainingUses[slotIndex];
|
|
public float GetCooldownRatio(int slotIndex)
|
|
{
|
|
if (_slots[slotIndex] is IToolCooldown tc && tc.CooldownDuration > 0f)
|
|
return _cooldowns[slotIndex] / tc.CooldownDuration;
|
|
return 0f;
|
|
}
|
|
|
|
// ── ISaveable ────────────────────────────────────────────────────────
|
|
public void OnSave(SaveData data)
|
|
{
|
|
data.Tools.ToolSlot0 = _slots[0]?.toolId;
|
|
data.Tools.ToolSlot1 = _slots[1]?.toolId;
|
|
}
|
|
|
|
public void OnLoad(SaveData data)
|
|
{
|
|
_cooldowns[0] = _cooldowns[1] = 0f;
|
|
|
|
EquipTool(0, _toolCatalog.Find(data.Tools.ToolSlot0));
|
|
EquipTool(1, _toolCatalog.Find(data.Tools.ToolSlot1));
|
|
}
|
|
}
|
|
}
|