using System; using Cielonos.MainGame; using Cielonos.MainGame.Inventory; using Cielonos.MainGame.Narrative; using UnityEngine; using Yarn.Unity; namespace Cielonos.Narrative { public static partial class CustomFunctions { /// /// 提供给 Yarn Spinner 调用的自定义函数,用于在对话中给予玩家指定物品。 /// 物品在授予后,会自动写入 InfoTransistor 中的 StartInventory,以便跨场景保存。 /// /// 物品的类名(需存在于 Inventory.Collections 命名空间下) /// 物品的数量/层数,默认为 1 [YarnCommand("obtain_item")] public static void ObtainItem(string itemClass, int stackAmount = 1) { PlayerInventorySaveData startInventory = InfoTransistor.GetInfo("StartInventory"); if (startInventory == null) { // 如果当前不存在过渡存档数据,说明这是本次场景内的第一次额外物品获取。 // 此时建立一个空的 SaveData 作为起始收集器。 InfoTransistor.SetInfo("StartInventory", new PlayerInventorySaveData()); startInventory = InfoTransistor.GetInfo("StartInventory"); } Type type = Type.GetType($"Cielonos.MainGame.Inventory.Collections.{itemClass}"); if (type == null) { Debug.LogError($"[YarnCommand] Cannot find item class type for name '{itemClass}'. Make sure it is in namespace Cielonos.MainGame.Inventory.Collections"); return; } ItemBase item = MainGameManager.Player.inventorySc.backpackSm.ObtainItem(type, stackAmount); ItemSaveData itemSaveData = new ItemSaveData(itemClass); if (item is MainWeaponBase mainWeapon) { MainGameManager.Player.inventorySc.equipmentSm.PrepareMainWeapon(mainWeapon); MainGameManager.Player.inventorySc.equipmentSm.EquipMainWeapon(mainWeapon); startInventory.mainWeapons.Add(itemSaveData); startInventory.preparedMainWeapons.Add(itemSaveData); startInventory.currentMainWeapon = itemSaveData; } else if (item is SupportEquipmentBase supportEquipment) { MainGameManager.Player.inventorySc.equipmentSm.EquipSupportEquipment(supportEquipment, 0); startInventory.supportEquipments.Add(itemSaveData); startInventory.currentSupportEquipments.Add(itemSaveData); } else if (item is PassiveEquipmentBase passiveEquipment) { MainGameManager.Player.inventorySc.backpackSm.ObtainItem(passiveEquipment); startInventory.passiveEquipments.Add(itemSaveData); } else if (item is ConsumableBase consumable) { itemSaveData.stackAmount = stackAmount; startInventory.consumables.Add(itemSaveData); Debug.Log($"[obtain_item] Obtained consumable '{itemClass}' with stack amount {stackAmount}."); } } [YarnFunction("check_have_item")] public static bool CheckHaveItem(string itemClass) { return MainGameManager.Player.inventorySc.backpackSm.HaveItem(itemClass); } /// /// 结束当前的地图事件(Event)。 /// 调用后会通知 RunManager 将当前节点标记为已完成/已耗尽,并把系统状态恢复到 MapSelection 以便玩家继续前进。 /// [YarnCommand("finish_event")] public static void FinishEvent() { if (RunManager.Instance != null && RunManager.Instance.currentPhase == RunPhase.InEvent) { RunManager.Instance.CompleteCurrentNode(); Debug.Log("[CustomFunctions] finish_event: 当前地图事件已结束,系统状态已恢复到 MapSelection。"); } } /// /// 耗尽/禁用指定的 NPC 交互(在剧情结束后彻底移除它的对话选项)。 /// 适用于那些不能被反复对话的 NPC,或者需要等离开场景才重置交互逻辑的 NPC。 /// /// NPC 的标识ID(例如 "SupportPersonnel") [YarnCommand("exhaust_npc")] public static void ExhaustNpc(string npcID) { if (StoryDirector.ActiveNpcs.TryGetValue(npcID, out var npc)) { npc.SetExhausted(); Debug.Log($"[CustomFunctions] NPC '{npcID}' 交互已耗尽。"); } else { Debug.LogWarning($"[CustomFunctions] exhaust_npc 找不到处于激活状态的 NPC: '{npcID}'"); } } } }