This commit is contained in:
SoulliesOfficial
2026-04-01 12:23:27 -04:00
parent aff7ac0e03
commit c3b1561375
933 changed files with 114333 additions and 119360 deletions

View File

@@ -1,17 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Continentis.MainGame.Card;
using Continentis.MainGame.Character;
using Continentis.MainGame.Commands;
using Continentis.MainGame.Equipment;
using Continentis.MainGame.Saving;
using Continentis.MainGame.UI;
using SLSFramework.General;
using SLSFramework.UModAssistance;
using TMPro;
using UnityEngine;
namespace Continentis.MainGame.Combat
{
/// <summary>
/// 战斗进行状态枚举
/// </summary>
public enum CombatState
{
InProgress,
ConfirmingRound,
Victory,
Defeat
}
public partial class CombatMainManager : Singleton<CombatMainManager>
{
public CombatCharacterController characterController;
@@ -23,6 +33,7 @@ namespace Continentis.MainGame.Combat
public int currentRound;
public int currentActionIndex;
public CharacterBase currentCharacter;
public CombatState combatState;
}
public partial class CombatMainManager
@@ -54,6 +65,8 @@ namespace Continentis.MainGame.Combat
{
public void StartCombat()
{
combatState = CombatState.InProgress;
foreach (CharacterBase character in characterController.characters)
character.InitializeCards();
@@ -62,23 +75,19 @@ namespace Continentis.MainGame.Combat
eventCollection.onCombatStart.Invoke();
foreach (CharacterBase character in characterController.characters)
{
character.eventSubmodule.onCombatStart.Invoke();
foreach (EquipmentBase equipment in character.equipmentSubmodule.currentEquipments)
equipment.eventSubmodule.onCombatStart.Invoke();
}
character.DispatchCombatStart();
foreach (CardInstance card in characterController.characters
.SelectMany(character => character.deckSubmodule.GetAllCards()))
{
card.eventSubmodule.onCombatStart.Invoke();
}
// 1.2b — 初始化 CombatLogs 并订阅事件
CombatLogs.Instance.Initialize(this);
NextRound();
}
public void NextRound()
{
// 战斗已结束则不再推进
if (combatState != CombatState.InProgress) return;
currentRound++;
// UI 反馈:回合提示动画(同步,纯 UI 无逻辑影响)
@@ -108,45 +117,67 @@ namespace Continentis.MainGame.Combat
if (intendedCard.targets.Count > 0)
{
CardInstance card = intendedCard.cardInstance;
card.eventSubmodule.onTargeting(intendedCard.targets[0]);
card.Targeting(intendedCard.targets[0]);
card.contentSubmodule.dirtyMark = true;
}
}
}
}
// ── 以下所有事件入队,确保 Buff 触发的视觉效果顺序正确 ────────────
// ── 进入"回合前确认"阶段:等待玩家点击 Confirm ───────────────────
combatState = CombatState.ConfirmingRound;
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
{
CombatMainPage page = CombatUIManager.Instance.combatMainPage;
page.SetButtonAction(ConfirmRound, "Confirm", true);
}));
CommandBase waitSignal = Cmd.WaitForSignal(out confirmRoundSignal);
CommandQueueManager.Instance.AddCommand(waitSignal);
// ── 玩家确认后回合正式开始Buff 触发链入队 ────────────────────
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
{
combatState = CombatState.InProgress;
CombatUIManager.Instance.combatMainPage.SetButtonAction(
EndAction, "Waiting...", false);
}));
foreach (CharacterBase character in characterController.characters)
{
CharacterBase captured = character;
CommandQueueManager.Instance.AddCommand(Cmd.Do(
() => captured.eventSubmodule.onRoundStart.Invoke()));
CommandQueueManager.Instance.AddCommand(Cmd.Do(
() => captured.equipmentSubmodule.currentEquipments.ForEach(
equipment => equipment.eventSubmodule.onRoundStart.Invoke())));
CommandQueueManager.Instance.AddCommand(Cmd.Do(
() => captured.combatBuffSubmodule.RoundStart()));
CommandQueueManager.Instance.AddCommand(Cmd.Do(() => captured.DispatchRoundStart()));
}
// ── 所有回合开始事件处理完毕后,进入第一个行动 ────────────────────
CommandQueueManager.Instance.AddCommand(Cmd.Do(NextAction));
}
/// <summary>
/// 玩家在"回合前确认"阶段点击 Confirm 后调用,释放队列暂停信号。
/// </summary>
public void ConfirmRound()
{
if (combatState != CombatState.ConfirmingRound) return;
confirmRoundSignal?.Invoke();
confirmRoundSignal = null;
}
// 持有当前回合的信号委托ConfirmRound() 调用后置 null 防止重复触发
private Action confirmRoundSignal;
public void NextAction()
{
// 战斗已结束则不再推进
if (combatState != CombatState.InProgress) return;
if (characterController.actionOrderList.Count == 0)
{
// 回合结束:所有角色的 onRoundEnd 和 Buff 触发均入队
foreach (CharacterBase character in characterController.characters)
{
CharacterBase captured = character;
CommandQueueManager.Instance.AddCommand(Cmd.Do(
() => captured.eventSubmodule.onRoundEnd.Invoke()));
CommandQueueManager.Instance.AddCommand(Cmd.Do(
() => captured.equipmentSubmodule.currentEquipments.ForEach(
equipment => equipment.eventSubmodule.onRoundEnd.Invoke())));
CommandQueueManager.Instance.AddCommand(Cmd.Do(
() => captured.combatBuffSubmodule.RoundEnd()));
CommandQueueManager.Instance.AddCommand(Cmd.Do(() => captured.DispatchRoundEnd()));
}
CommandQueueManager.Instance.AddCommand(Cmd.Do(NextRound));
@@ -158,15 +189,14 @@ namespace Continentis.MainGame.Combat
CharacterBase actionCharacter = currentCharacter;
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
{
actionCharacter.eventSubmodule.onActionStart.Invoke();
actionCharacter.combatBuffSubmodule.ActionStart();
actionCharacter.DispatchActionStart();
actionCharacter.recordSubmodule.SetAction(currentRound, ++currentActionIndex);
}));
CombatMainPage combatMainPage = CombatUIManager.Instance.combatMainPage;
if (currentCharacter is PlayerHero playerHero)
{
CombatMainPage combatMainPage = CombatUIManager.Instance.combatMainPage;
playerHero.deckSubmodule.SetUpHandCardViews();
combatMainPage.handPile.isUpdatingLayout = false;
@@ -179,23 +209,24 @@ namespace Continentis.MainGame.Combat
}));
combatMainPage.combatResourcesDisplayer.SetCharacter(playerHero);
CombatUIManager.Instance.combatMainPage.endActionButton
.GetComponentInChildren<TMP_Text>().text = "End Action";
CombatUIManager.Instance.combatMainPage.endActionButton.interactable = true;
combatMainPage.SetButtonAction(EndAction, "End Action", true);
}
else if (currentCharacter is CombatNPC)
{
if (currentCharacter.fraction == Fraction.Enemy)
CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren<TMP_Text>().text = "Enemy Action";
else if (currentCharacter.fraction == Fraction.Ally)
CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren<TMP_Text>().text = "Ally Action";
else
CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren<TMP_Text>().text = "Others Action";
CombatUIManager.Instance.combatMainPage.endActionButton.interactable = false;
string npcLabel = currentCharacter.fraction switch
{
Fraction.Enemy => "Enemy Action",
Fraction.Ally => "Ally Action",
_ => "Others Action"
};
combatMainPage.SetButtonAction(null, npcLabel, false);
CommandQueueManager.Instance.AddCommand(Cmd.Wait(0.25f));
// 2.3e — PreAction 钩子NPC 出牌前
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
currentCharacter.intentionSubmodule.currentIntention.PreAction()));
foreach (IntendedCard intendedCard in currentCharacter.intentionSubmodule.intendedCards)
{
IntendedCard captured = intendedCard;
@@ -205,11 +236,15 @@ namespace Continentis.MainGame.Combat
Cmd.Do(() => {
captured.cardInstance.Play(captured.targets, currentCharacter);
captured.cardInstance.DestroyIntentionCardView();
}),
}),
Cmd.Wait(0.25f)
));
}
// 2.3e — PostAction 钩子NPC 出完全部卡牌后
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
currentCharacter.intentionSubmodule.currentIntention.PostAction()));
CommandQueueManager.Instance.AddCommand(Cmd.Do(EndAction));
}
@@ -221,23 +256,11 @@ namespace Continentis.MainGame.Combat
public void EndAction()
{
CombatUIManager.Instance.combatMainPage.endActionButton
.GetComponentInChildren<TMP_Text>().text = "Waiting...";
CombatUIManager.Instance.combatMainPage.endActionButton.interactable = false;
CommandQueueManager.Instance.AddCommand(
Cmd.Do(currentCharacter.eventSubmodule.onActionEnd.Invoke));
foreach (CardInstance card in currentCharacter.deckSubmodule.GetAllCards())
{
CardInstance captured = card;
CommandQueueManager.Instance.AddCommand(
Cmd.Do(captured.eventSubmodule.onActionEnd.Invoke));
}
CombatUIManager.Instance.combatMainPage.SetButtonAction(null, "Waiting...", false);
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
{
currentCharacter.combatBuffSubmodule.ActionEnd();
currentCharacter.DispatchActionEnd();
if (currentCharacter is PlayerHero playerHero)
{
@@ -259,4 +282,73 @@ namespace Continentis.MainGame.Combat
}));
}
}
public partial class CombatMainManager
{
/// <summary>
/// 结束战斗,触发胜负流程。由 CombatCharacterController.CheckCombatEnd() 调用。
/// </summary>
public void EndCombat(bool isVictory)
{
// 防止重复触发
if (combatState != CombatState.InProgress) return;
combatState = isVictory ? CombatState.Victory : CombatState.Defeat;
// 触发战斗结束全局事件
eventCollection.onCombatEnd.Invoke();
foreach (CharacterBase character in characterController.characters)
character.DispatchCombatEnd();
// 清理所有卡牌 Logic 的托管订阅
foreach (CharacterBase character in characterController.characters)
foreach (CardInstance card in character.deckSubmodule.GetAllCards())
card.cardLogic?.Dispose();
if (isVictory)
{
CombatVictory();
}
else
{
CombatDefeat();
}
}
/// <summary>
/// 战斗胜利处理:收集战后英雄 HP通知 MainGameManager 推进节点并存档。
/// </summary>
private void CombatVictory()
{
CombatUIManager.Instance.combatMainPage.SetButtonAction(null, "Victory!", false);
// 将玩家英雄的战后 HP 与 RunSave 中的 HeroSave 对应:按 currentRun.heroes 顺序匹配
var heroResults = new List<(string heroID, int currentHP)>();
List<HeroSave> runHeroes = MainGameManager.Instance.currentRun?.heroes;
if (runHeroes != null)
{
for (int i = 0; i < Mathf.Min(characterController.playerHeroes.Count, runHeroes.Count); i++)
{
int hp = Mathf.RoundToInt(characterController.playerHeroes[i].GetAttribute("Health"));
heroResults.Add((runHeroes[i].characterDataID, hp));
}
}
// CommandQueue 执行完毕后再切场景,避免队列中残余命令在新场景报错
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
MainGameManager.Instance.ExitCombat(isVictory: true, heroResults)));
}
/// <summary>
/// 战斗失败处理:通知 MainGameManager 删档并返回主菜单。
/// </summary>
private void CombatDefeat()
{
CombatUIManager.Instance.combatMainPage.SetButtonAction(null, "Defeat...", false);
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
MainGameManager.Instance.ExitCombat(isVictory: false)));
}
}
}