using System.Collections.Generic; using Continentis.MainGame.Character; using Continentis.MainGame.Saving; using SLSUtilities.General; using SLSUtilities.UModAssistance; using UnityEngine; using UnityEngine.SceneManagement; namespace Continentis.MainGame { // ── 常量与核心字段 ────────────────────────────────────────────────────────── public partial class MainGameManager : Singleton { private const string CombatSceneName = "GameScene"; private const string MenuSceneName = "MenuScene"; public readonly HashSet elementTags = new HashSet() { "Wind", "Fire", "Ice", "Earth", "Storm", "Light", "Darkness", "Physics" }; public BasePrefabs basePrefabs; } // ── 游戏数据字段 ──────────────────────────────────────────────────────────── public partial class MainGameManager { /// 全关键词合并表,由各 Mod 的 KeywordData 合并而来。 public KeywordData keywordData; /// 当前跑局的存档快照,既是运行时状态也是持久化来源。null 表示无进行中的跑局。 public RunSave currentRun; /// 当前战斗的玩家英雄 CharacterData 列表,由 PrepareCombat() 填充。 public List playerHeroDataList = new List(); /// 当前战斗的敌方 CharacterData 列表,由 PrepareCombat() 填充。 public List enemyDataList = new List(); } // ── 初始化 ────────────────────────────────────────────────────────────────── public partial class MainGameManager { protected override void Awake() { base.Awake(); // 合并所有 Mod 的 KeywordData 到全局查询表 keywordData = ScriptableObject.CreateInstance(); foreach (KeyValuePair pair in ModManager.Database[typeof(KeywordData)]) { KeywordData data = pair.Value as KeywordData; foreach (var keyword in data!.interpretedKeywords) { keywordData.interpretedKeywords.TryAdd(keyword.Key, keyword.Value); } } // 消费 InformationTransistor 中的主菜单意图 InfoTransistor transistor = InfoTransistor.Instance; if (transistor == null) { Debug.LogError("[MainGame] InformationTransistor 未找到,无法确定跑局意图。"); return; } InfoTransistor.Menu.MenuIntent intent = transistor.menuToMainGame.menuIntent; RunConfig config = transistor.menuToMainGame.pendingRunConfig; Debug.Log($"[MainGame] Awake:收到主菜单意图 {intent},RunConfig {(config != null ? config.name : "null")}。"); // 消费后重置,避免场景重新加载时重复执行 transistor.menuToMainGame.menuIntent = InfoTransistor.Menu.MenuIntent.None; transistor.menuToMainGame.pendingRunConfig = null; switch (intent) { case InfoTransistor.Menu.MenuIntent.StartNewRun: StartNewRun(config); break; case InfoTransistor.Menu.MenuIntent.ContinueRun: ContinueRun(); break; default: Debug.LogWarning("[MainGame] Awake 时未收到有效的跑局意图,跳过初始化。"); break; } } } // ── 跑局流程 API ──────────────────────────────────────────────────────────── public partial class MainGameManager { /// /// 开始一次新跑局:从 RunConfig 初始化英雄和关卡序列,写入开局存档,准备首场战斗数据。 /// RunConfig 仅在此处读取一次,结果完整拷贝到 RunSave,后续不再查询它。 /// 由 Awake 消费 StartNewRun 意图时调用。 /// private void StartNewRun(RunConfig config) { currentRun = new RunSave( Random.Range(int.MinValue, int.MaxValue), config.startingGold, new List(config.encounterSequenceIDs) ); foreach (string heroID in config.initialHeroIDs) { CharacterData data = CharacterData.Get(heroID); if (data == null) { Debug.LogError($"[MainGame] StartNewRun:找不到角色数据 '{heroID}',已跳过。"); continue; } int maxHP = Mathf.RoundToInt(data.generalAttributes.TryGetValue("MaximumHealth", out float hp) ? hp : 0f); HeroSave hero = new HeroSave(heroID, maxHP, maxHP); foreach (string cardID in data.initialDeckRef) hero.deck.Add(new CardSave(cardID)); currentRun.heroes.Add(hero); } SaveManager.Instance.SaveRunSave(currentRun); Debug.Log($"[MainGame] 新跑局开始(配置:{config.name},节点数:{currentRun.combatNodeIDs.Count},种子:{currentRun.randomSeed})"); PrepareCombat(currentRun.currentNodeIndex); } /// /// 从 SaveManager 缓存恢复跑局并准备当前节点的战斗数据。 /// 由 Awake 消费 ContinueRun 意图时调用。 /// private void ContinueRun() { currentRun = SaveManager.Instance.GetRunSave(); if (currentRun == null) { Debug.LogError("[MainGame] ContinueRun:SaveManager 缓存中无进行中的跑局。"); return; } Debug.Log($"[MainGame] 继续跑局(节点 {currentRun.currentNodeIndex} / {currentRun.combatNodeIDs.Count})"); PrepareCombat(currentRun.currentNodeIndex); } /// /// 根据节点索引填充玩家英雄和敌方角色列表。 /// 仅准备运行时数据供 CombatMainManager 使用,不涉及场景加载。 /// private void PrepareCombat(int nodeIndex) { if (nodeIndex >= currentRun.combatNodeIDs.Count) { Debug.Log("[MainGame] 所有关卡已通关,跑局结束!"); // TODO: Phase 4 — 显示通关结算界面 return; } // 填充玩家英雄列表 playerHeroDataList.Clear(); foreach (HeroSave hero in currentRun.heroes) { CharacterData data = CharacterData.Get(hero.characterDataID); if (data != null) playerHeroDataList.Add(data); else Debug.LogError($"[MainGame] PrepareCombat:找不到角色数据 '{hero.characterDataID}'。"); } // 填充敌方列表 string nodeID = currentRun.combatNodeIDs[nodeIndex]; CombatNodeData nodeData = CombatNodeData.Get(nodeID); if (nodeData == null) { Debug.LogError($"[MainGame] PrepareCombat:找不到 CombatNodeData '{nodeID}'。"); return; } enemyDataList.Clear(); foreach (string enemyID in nodeData.enemyCharacterIDs) { CharacterData data = CharacterData.Get(enemyID); if (data != null) enemyDataList.Add(data); else Debug.LogError($"[MainGame] PrepareCombat:找不到敌方角色数据 '{enemyID}'。"); } } /// /// 战斗结束回调,由 CombatMainManager 调用。 /// 胜利时回写 HP、推进节点并存档,然后通过 InfoTransistor 写入 ContinueRun 意图并重载场景。 /// 失败时清除跑局存档(保留 PlayerSave)并返回主菜单。 /// 注意:MainGameManager 是场景局部单例,重载场景后当前实例会被销毁, /// 新实例的 Awake 会从 InfoTransistor 消费意图并重新初始化。 /// public void ExitCombat(bool isVictory, IReadOnlyList<(string heroID, int currentHP)> heroResults = null) { if (isVictory) { if (heroResults != null) { foreach (var (heroID, hp) in heroResults) { HeroSave hero = currentRun.heroes.Find(h => h.characterDataID == heroID); if (hero != null) hero.currentHP = hp; } } currentRun.currentNodeIndex++; SaveManager.Instance.SaveRunSave(currentRun); Debug.Log($"[MainGame] 战斗胜利,节点推进至 {currentRun.currentNodeIndex},存档已写入。"); // 检查是否所有节点已通关 if (currentRun.currentNodeIndex >= currentRun.combatNodeIDs.Count) { Debug.Log("[MainGame] 所有关卡已通关,跑局结束!"); // TODO: Phase 4 — 显示通关结算界面,之后返回主菜单 return; } // 写入 ContinueRun 意图,重载场景以启动下一场战斗 // TODO: Phase 4 — 先进入奖励选择界面,完成后再走此流程 InfoTransistor transistor = InfoTransistor.Instance; transistor.menuToMainGame.menuIntent = InfoTransistor.Menu.MenuIntent.ContinueRun; transistor.menuToMainGame.pendingRunConfig = null; SceneManager.LoadScene(CombatSceneName); } else { SaveManager.Instance.DeleteRunSave(); Debug.Log("[MainGame] 战斗失败,跑局存档已清除(PlayerSave 保留),返回主菜单。"); SceneManager.LoadScene(MenuSceneName); } } } // ── 静态工具方法 ──────────────────────────────────────────────────────────── public partial class MainGameManager { public static void GenerateInfoText(string content, CombatCharacterViewBase characterView, Color color = default, float size = 1) => Instance.basePrefabs.GenerateInfoText(content, characterView, color, size); } }