using UnityEngine; using BaseGames.Core.Events; using BaseGames.Core.Save; using BaseGames.Player.States; namespace BaseGames.Equipment { /// /// 工具槽管理器(架构 09_ProgressionModule §7.5)。 /// 管理玩家的 2 个工具槽(装备、使用、冷却)。 /// 实现 ISaveable 以持久化槽位状态。 /// 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); } // ── 装备 ───────────────────────────────────────────────────────────── 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)); } } }