247 lines
11 KiB
C#
247 lines
11 KiB
C#
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<MainGameManager>
|
||
{
|
||
private const string CombatSceneName = "GameScene";
|
||
private const string MenuSceneName = "MenuScene";
|
||
|
||
public readonly HashSet<string> elementTags = new HashSet<string>()
|
||
{
|
||
"Wind", "Fire", "Ice", "Earth", "Storm", "Light", "Darkness", "Physics"
|
||
};
|
||
|
||
public BasePrefabs basePrefabs;
|
||
}
|
||
|
||
// ── 游戏数据字段 ────────────────────────────────────────────────────────────
|
||
public partial class MainGameManager
|
||
{
|
||
/// <summary>全关键词合并表,由各 Mod 的 KeywordData 合并而来。</summary>
|
||
public KeywordData keywordData;
|
||
|
||
/// <summary>当前跑局的存档快照,既是运行时状态也是持久化来源。null 表示无进行中的跑局。</summary>
|
||
public RunSave currentRun;
|
||
|
||
/// <summary>当前战斗的玩家英雄 CharacterData 列表,由 PrepareCombat() 填充。</summary>
|
||
public List<CharacterData> playerHeroDataList = new List<CharacterData>();
|
||
|
||
/// <summary>当前战斗的敌方 CharacterData 列表,由 PrepareCombat() 填充。</summary>
|
||
public List<CharacterData> enemyDataList = new List<CharacterData>();
|
||
}
|
||
|
||
// ── 初始化 ──────────────────────────────────────────────────────────────────
|
||
public partial class MainGameManager
|
||
{
|
||
protected override void Awake()
|
||
{
|
||
base.Awake();
|
||
|
||
// 合并所有 Mod 的 KeywordData 到全局查询表
|
||
keywordData = ScriptableObject.CreateInstance<KeywordData>();
|
||
foreach (KeyValuePair<string, ScriptableObject> 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
|
||
{
|
||
/// <summary>
|
||
/// 开始一次新跑局:从 RunConfig 初始化英雄和关卡序列,写入开局存档,准备首场战斗数据。
|
||
/// RunConfig 仅在此处读取一次,结果完整拷贝到 RunSave,后续不再查询它。
|
||
/// 由 Awake 消费 StartNewRun 意图时调用。
|
||
/// </summary>
|
||
private void StartNewRun(RunConfig config)
|
||
{
|
||
currentRun = new RunSave(
|
||
Random.Range(int.MinValue, int.MaxValue),
|
||
config.startingGold,
|
||
new List<string>(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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从 SaveManager 缓存恢复跑局并准备当前节点的战斗数据。
|
||
/// 由 Awake 消费 ContinueRun 意图时调用。
|
||
/// </summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据节点索引填充玩家英雄和敌方角色列表。
|
||
/// 仅准备运行时数据供 CombatMainManager 使用,不涉及场景加载。
|
||
/// </summary>
|
||
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}'。");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 战斗结束回调,由 CombatMainManager 调用。
|
||
/// 胜利时回写 HP、推进节点并存档,然后通过 InfoTransistor 写入 ContinueRun 意图并重载场景。
|
||
/// 失败时清除跑局存档(保留 PlayerSave)并返回主菜单。
|
||
/// 注意:MainGameManager 是场景局部单例,重载场景后当前实例会被销毁,
|
||
/// 新实例的 Awake 会从 InfoTransistor 消费意图并重新初始化。
|
||
/// </summary>
|
||
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);
|
||
}
|
||
} |