diff --git a/Assets/Prefabs/FixSystemPrefabs/Clinic System.prefab b/Assets/Prefabs/FixSystemPrefabs/Clinic System.prefab
index 891b751a1..8e80287e3 100644
--- a/Assets/Prefabs/FixSystemPrefabs/Clinic System.prefab
+++ b/Assets/Prefabs/FixSystemPrefabs/Clinic System.prefab
@@ -1406,11 +1406,64 @@ Transform:
m_Children:
- {fileID: 3619849418667778924}
- {fileID: 6121709156540084727}
+ - {fileID: 9102307160016725311}
- {fileID: 6249684167985838438}
- {fileID: 7931034805346183671}
- {fileID: 6274499368345295635}
m_Father: {fileID: 9073824794961298310}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &9102307160016725310
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 9102307160016725311}
+ - component: {fileID: 9102307160016725312}
+ m_Layer: 0
+ m_Name: Actor Entrance
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &9102307160016725311
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 9102307160016725310}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: -1.55, y: 0.15, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 9111904319609796187}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &9102307160016725312
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 9102307160016725310}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: bbc0dde0e8b8a9c498545e1b5b508241, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ data:
+ slotPosition: {x: 0, y: 0, z: 0}
+ actorRole: 2
+ idx: 1
+ maxWidth: 800
+ minWidth: 300
+ bubbleStyle: {fileID: 11400000, guid: e3f425b45fd35cc4caf1939eaea2f7bc, type: 2}
+ pivotType: 5
--- !u!1 &5345859371557614914
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/Prefabs/FixSystemPrefabs/维修面板.prefab b/Assets/Prefabs/FixSystemPrefabs/维修面板.prefab
index 6d9719f77..26f0b0989 100644
--- a/Assets/Prefabs/FixSystemPrefabs/维修面板.prefab
+++ b/Assets/Prefabs/FixSystemPrefabs/维修面板.prefab
@@ -8626,6 +8626,9 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
environmentLight: {fileID: 7098573010793440161}
+ deepEnvironmentLight: {fileID: 3788564698077470635}
+ deepEnvironmentNormalIntensity: 0.9
+ deepEnvironmentAlpha: 0.8509804
isEnvironmentLightFlickering: 0
normalEnvironmentIntensity: 2
warningEnvironmentIntensity: 1.25
@@ -8646,6 +8649,10 @@ MonoBehaviour:
warningAlarmLightColor: {r: 1, g: 0.42, b: 0.35, a: 1}
alarmBlinkSpeed: 0.5
alarmLightColor: {r: 1, g: 0, b: 0, a: 1}
+ emergencyIntroDipDuration: 0.08
+ emergencyIntroRiseDuration: 0.18
+ emergencyOutroDuration: 0.18
+ emergencyIntroDipIntensityScale: 0.55
--- !u!1 &7297538176355823427
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/Scripts/FixSystemNew/Open/OpenYarnCommand.cs b/Assets/Scripts/FixSystemNew/Open/OpenYarnCommand.cs
index 1b066d37a..2415b2017 100644
--- a/Assets/Scripts/FixSystemNew/Open/OpenYarnCommand.cs
+++ b/Assets/Scripts/FixSystemNew/Open/OpenYarnCommand.cs
@@ -16,6 +16,12 @@ namespace AibisDream.FixSystem
ShockSystem.StartCoroutine(ShockSystem.PlayFlashEffect());
}
+ [YarnCommand("play_shock_flash_and_wait")]
+ public static IEnumerator PlayShockFlashAndWait()
+ {
+ yield return ShockSystem.PlayFlashEffect();
+ }
+
[YarnCommand("play_shock_flashback")]
public static IEnumerator PlayShockFlashback(string imagePath)
{
@@ -69,4 +75,4 @@ namespace AibisDream.FixSystem
ShockSystem.SetAbnormalState(false);
}
}
-}
\ No newline at end of file
+}
diff --git a/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelLight.cs b/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelLight.cs
index 037235e1f..a5e8b1453 100644
--- a/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelLight.cs
+++ b/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelLight.cs
@@ -28,6 +28,8 @@ namespace AibisDream.FixSystem
private const float ALARM_LIGHT_MAX_INTENSITY = 4f;
private const float MIN_FLICKER_BLINK_COUNT = 2;
private const float MAX_FLICKER_BLINK_COUNT = 4;
+ private const string PANEL_LIGHT_ON_SFX = "event:/ActionFB/light_flicker_on";
+ private const string PANEL_LIGHT_OFF_SFX = "event:/ActionFB/light_flicker_off";
private const float MIN_FLICKER_INTERVAL = 3f;
private const float MAX_FLICKER_INTERVAL = 8f;
@@ -37,6 +39,9 @@ namespace AibisDream.FixSystem
[Header("环境灯设置")]
[SerializeField] private Light2D environmentLight;
+ [SerializeField] private Light2D deepEnvironmentLight;
+ [SerializeField, Min(0.01f)] private float deepEnvironmentNormalIntensity = 0.9f;
+ [SerializeField, Range(0f, 1f)] private float deepEnvironmentAlpha = 0.8509804f;
[SerializeField] private bool isEnvironmentLightFlickering = false;
[SerializeField] private float normalEnvironmentIntensity = 2f;
[SerializeField] private float warningEnvironmentIntensity = 1.25f;
@@ -62,15 +67,29 @@ namespace AibisDream.FixSystem
[SerializeField] private float alarmBlinkSpeed = 0.5f;
[SerializeField] private Color alarmLightColor = Color.red;
+ [Header("紧急状态转场")]
+ [SerializeField] private float emergencyIntroDipDuration = 0.08f;
+ [SerializeField] private float emergencyIntroRiseDuration = 0.18f;
+ [SerializeField] private float emergencyOutroDuration = 0.18f;
+ [SerializeField, Range(0f, 1f)] private float emergencyIntroDipIntensityScale = 0.55f;
+
private Tween alarmTween;
+ private Tween lightStateTransitionTween;
private LightState currentState = LightState.Normal;
#endregion
#region 生命周期
+ private void LateUpdate()
+ {
+ SyncDeepEnvironmentLight();
+ }
+
private void OnDisable()
{
+ lightStateTransitionTween?.Kill();
+ lightStateTransitionTween = null;
StopAlarmLight();
StopAllCoroutines();
}
@@ -79,9 +98,54 @@ namespace AibisDream.FixSystem
#region 光照系统 - 公共方法
- public void Initialize(bool isSystemOn)
+ public void Initialize(bool isSystemOn, LightState state = LightState.Normal)
{
- panelLight.intensity = isSystemOn ? panelLightIntensity : 0f;
+ lightStateTransitionTween?.Kill();
+ lightStateTransitionTween = null;
+ alarmTween?.Kill();
+ alarmTween = null;
+ StopAllCoroutines();
+
+ currentState = state;
+
+ if (!isSystemOn)
+ {
+ if (panelLight != null)
+ {
+ panelLight.color = panelLightColor;
+ panelLight.intensity = 0f;
+ }
+ if (environmentLight != null)
+ {
+ environmentLight.color = normalEnvironmentColor;
+ environmentLight.intensity = SYSTEM_OFF_ENVIRONMENT_INTENSITY;
+ }
+ if (alarmLight != null)
+ {
+ alarmLight.intensity = 0f;
+ }
+ SyncDeepEnvironmentLight();
+ return;
+ }
+
+ UpdateLightsState();
+ if (isEnvironmentLightFlickering)
+ {
+ StartCoroutine(EnvironmentLightFlickerRoutine());
+ }
+ SyncDeepEnvironmentLight();
+ }
+
+ private void SyncDeepEnvironmentLight()
+ {
+ if (deepEnvironmentLight == null || environmentLight == null) return;
+
+ Color deepColor = environmentLight.color;
+ deepColor.a = deepEnvironmentAlpha;
+ deepEnvironmentLight.color = deepColor;
+ float intensityRatio = Mathf.Max(0f,
+ environmentLight.intensity / Mathf.Max(0.01f, normalEnvironmentIntensity));
+ deepEnvironmentLight.intensity = deepEnvironmentNormalIntensity * intensityRatio;
}
///
@@ -91,8 +155,9 @@ namespace AibisDream.FixSystem
{
if (currentState != newState)
{
+ LightState previousState = currentState;
currentState = newState;
- UpdateLightsState();
+ TransitionLightsState(previousState, newState);
Debug.Log($"灯光状态已切换为: {newState}");
}
}
@@ -150,6 +215,8 @@ namespace AibisDream.FixSystem
// 如果当前正在闪烁,立即使用新速度重启。
if (currentState != LightState.Normal && alarmLight != null)
{
+ lightStateTransitionTween?.Kill();
+ lightStateTransitionTween = null;
StartAlarmLightBlink(GetStateConfig(currentState));
}
}
@@ -172,6 +239,151 @@ namespace AibisDream.FixSystem
#region 光照系统 - 状态更新方法
+ ///
+ /// 根据紧急状态的进入/退出选择短转场,其他状态保持即时切换。
+ ///
+ private void TransitionLightsState(LightState previousState, LightState newState)
+ {
+ lightStateTransitionTween?.Kill();
+ lightStateTransitionTween = null;
+
+ alarmTween?.Kill();
+ alarmTween = null;
+
+ var stateConfig = GetStateConfig(newState);
+ UpdatePanelLight();
+
+ if (newState == LightState.Emergency)
+ {
+ PlayEmergencyIntro(stateConfig);
+ }
+ else if (previousState == LightState.Emergency)
+ {
+ PlayEmergencyOutro(stateConfig);
+ }
+ else
+ {
+ UpdateAlarmLight(stateConfig);
+ UpdateEnvironmentLight(stateConfig);
+ }
+ }
+
+ ///
+ /// Emergency 进入:极短压暗后快速升起红光,再接循环警报。
+ ///
+ private void PlayEmergencyIntro((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity,
+ float alarmBlinkDuration, Color envColor, float envIntensity) config)
+ {
+ float dipDuration = Mathf.Max(0.01f, emergencyIntroDipDuration);
+ float riseDuration = Mathf.Max(0.01f, emergencyIntroRiseDuration);
+ DG.Tweening.Sequence sequence = DOTween.Sequence();
+
+ if (environmentLight != null)
+ {
+ float dipIntensity = environmentLight.intensity * emergencyIntroDipIntensityScale;
+ Color dipColor = Color.Lerp(environmentLight.color, config.envColor, 0.35f);
+
+ sequence.Append(DOTween.To(
+ () => environmentLight.intensity,
+ value => environmentLight.intensity = value,
+ dipIntensity,
+ dipDuration).SetEase(Ease.OutQuad));
+ sequence.Join(DOTween.To(
+ () => environmentLight.color,
+ value => environmentLight.color = value,
+ dipColor,
+ dipDuration).SetEase(Ease.OutQuad));
+ sequence.Append(DOTween.To(
+ () => environmentLight.intensity,
+ value => environmentLight.intensity = value,
+ config.envIntensity,
+ riseDuration).SetEase(Ease.OutCubic));
+ sequence.Join(DOTween.To(
+ () => environmentLight.color,
+ value => environmentLight.color = value,
+ config.envColor,
+ riseDuration).SetEase(Ease.OutCubic));
+ }
+ else
+ {
+ sequence.AppendInterval(dipDuration + riseDuration);
+ }
+
+ if (alarmLight != null)
+ {
+ alarmLight.color = config.alarmColor;
+ alarmLight.intensity = 0f;
+ sequence.Insert(dipDuration, DOTween.To(
+ () => alarmLight.intensity,
+ value => alarmLight.intensity = value,
+ config.alarmMaxIntensity,
+ riseDuration).SetEase(Ease.OutCubic));
+ }
+
+ lightStateTransitionTween = sequence.OnComplete(() =>
+ {
+ lightStateTransitionTween = null;
+ if (currentState == LightState.Emergency)
+ {
+ StartAlarmLightBlink(config, true);
+ }
+ });
+ }
+
+ ///
+ /// Emergency 退出:快速收起紧急红光,平滑落到目标状态。
+ ///
+ private void PlayEmergencyOutro((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity,
+ float alarmBlinkDuration, Color envColor, float envIntensity) config)
+ {
+ float duration = Mathf.Max(0.01f, emergencyOutroDuration);
+ DG.Tweening.Sequence sequence = DOTween.Sequence();
+
+ if (environmentLight != null)
+ {
+ sequence.Join(DOTween.To(
+ () => environmentLight.intensity,
+ value => environmentLight.intensity = value,
+ config.envIntensity,
+ duration).SetEase(Ease.OutQuad));
+ sequence.Join(DOTween.To(
+ () => environmentLight.color,
+ value => environmentLight.color = value,
+ config.envColor,
+ duration).SetEase(Ease.OutQuad));
+ }
+
+ if (alarmLight != null)
+ {
+ sequence.Join(DOTween.To(
+ () => alarmLight.intensity,
+ value => alarmLight.intensity = value,
+ 0f,
+ duration).SetEase(Ease.OutQuad));
+ }
+
+ if (environmentLight == null && alarmLight == null)
+ {
+ sequence.AppendInterval(duration);
+ }
+
+ LightState targetState = currentState;
+ lightStateTransitionTween = sequence.OnComplete(() =>
+ {
+ lightStateTransitionTween = null;
+ if (currentState != targetState) return;
+
+ if (config.alarmEnabled)
+ {
+ StartAlarmLightBlink(config);
+ }
+ else
+ {
+ StopAlarmLight();
+ }
+ });
+ }
+
///
/// 更新所有灯光状态
///
@@ -225,17 +437,17 @@ namespace AibisDream.FixSystem
/// 启动警报灯闪烁
///
private void StartAlarmLightBlink((bool alarmEnabled, Color alarmColor, float alarmMaxIntensity,
- float alarmBlinkDuration, Color envColor, float envIntensity) config)
+ float alarmBlinkDuration, Color envColor, float envIntensity) config, bool startLit = false)
{
if (alarmLight == null) return;
alarmTween?.Kill();
- alarmLight.intensity = 0f;
+ alarmLight.intensity = startLit ? config.alarmMaxIntensity : 0f;
alarmLight.color = config.alarmColor;
alarmTween = DOTween.To(
() => alarmLight.intensity,
x => alarmLight.intensity = x,
- config.alarmMaxIntensity,
+ startLit ? 0f : config.alarmMaxIntensity,
config.alarmBlinkDuration
)
.SetLoops(-1, LoopType.Yoyo)
@@ -349,6 +561,7 @@ namespace AibisDream.FixSystem
for (int i = 0; i < panelLightBlinkCount; i++)
{
// 渐亮
+ AudioManager.Instance?.PlaySfx(PANEL_LIGHT_ON_SFX);
DOTween.To(() => panelLight.intensity, x => panelLight.intensity = x, panelLightIntensity, panelLightBlinkDuration * 0.5f)
.SetEase(Ease.InOutQuad);
if (environmentLight != null)
@@ -359,6 +572,7 @@ namespace AibisDream.FixSystem
yield return new WaitForSeconds(panelLightBlinkDuration);
// 渐暗
+ AudioManager.Instance?.PlaySfx(PANEL_LIGHT_OFF_SFX);
DOTween.To(() => panelLight.intensity, x => panelLight.intensity = x, 0f, panelLightBlinkDuration * 0.5f)
.SetEase(Ease.InOutQuad);
if (environmentLight != null)
@@ -370,13 +584,19 @@ namespace AibisDream.FixSystem
}
// 最后渐亮到常亮状态
- DOTween.To(() => panelLight.intensity, x => panelLight.intensity = x, panelLightIntensity, panelLightBlinkDuration * 0.5f)
- .SetEase(Ease.InOutQuad);
+ AudioManager.Instance?.PlaySfx(PANEL_LIGHT_ON_SFX);
+ DG.Tweening.Sequence finalRise = DOTween.Sequence();
+ finalRise.Join(DOTween.To(() => panelLight.intensity, x => panelLight.intensity = x,
+ panelLightIntensity, panelLightBlinkDuration * 0.5f)
+ .SetEase(Ease.InOutQuad));
if (environmentLight != null)
{
- DOTween.To(() => environmentLight.intensity, x => environmentLight.intensity = x, normalEnvironmentIntensity, panelLightBlinkDuration * 0.5f)
- .SetEase(Ease.InOutQuad);
+ finalRise.Join(DOTween.To(() => environmentLight.intensity, x => environmentLight.intensity = x,
+ normalEnvironmentIntensity, panelLightBlinkDuration * 0.5f)
+ .SetEase(Ease.InOutQuad));
}
+
+ yield return finalRise.WaitForCompletion();
}
#endregion
diff --git a/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelSystem.cs b/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelSystem.cs
index c05fc6ace..8d320af29 100644
--- a/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelSystem.cs
+++ b/Assets/Scripts/FixSystemNew/Screen System/Core/FixPanelSystem.cs
@@ -7,6 +7,12 @@ using DG.Tweening;
namespace AibisDream.FixSystem
{
+ public enum SystemStartupMode
+ {
+ AutoOnHead,
+ Deferred
+ }
+
///
/// 维修面板系统 - 统一管理所有侧边栏面板
/// 包括常驻面板(对话、任务)和随状态切换的游戏面板
@@ -57,17 +63,24 @@ namespace AibisDream.FixSystem
[Header("光照系统")]
[SerializeField] private bool isSystemOn = false;
public bool IsSystemOn => isSystemOn;
+ public bool ShouldAutoStartOnHeadEntry =>
+ !isSystemOn && (!isStartupPrepared || startupMode == SystemStartupMode.AutoOnHead);
[SerializeField] private FixPanelLight panelLight;
public FixPanelLight PanelLight => panelLight;
+ private bool isStarting;
+ private bool isStartupPrepared;
+ private SystemStartupMode startupMode = SystemStartupMode.AutoOnHead;
+ private LightState targetLightState = LightState.Normal;
+
[Header("维修切换管理")]
[SerializeField] private RepairSystemManager repairSystemManager;
public RepairSystemManager RepairSystemManager => repairSystemManager;
private void InitLight()
{
- panelLight.Initialize(isSystemOn);
+ panelLight.Initialize(isSystemOn, targetLightState);
GetRepairPanel().InitLight(isSystemOn);
// 无光环境下屏幕也不能亮
if (!isSystemOn)
@@ -80,11 +93,36 @@ namespace AibisDream.FixSystem
#region 系统启动协调
+ ///
+ /// 为指定剧情准备一次系统启动。只有显式调用该接口的 YarnProject 会改变默认表现。
+ ///
+ public void PrepareSystemStartup(SystemStartupMode mode)
+ {
+ startupMode = mode;
+ isStartupPrepared = true;
+ targetLightState = LightState.Normal;
+ ApplySystemOnImmediate(false);
+ taskPanel?.HidePanelImmediate();
+ }
+
///
/// 启动所有系统(协调灯光系统和 CablePanel 的启动顺序)
///
public IEnumerator StartAllSystems()
{
+ if (isSystemOn) yield break;
+
+ if (isStarting)
+ {
+ while (isStarting)
+ {
+ yield return null;
+ }
+ yield break;
+ }
+
+ isStarting = true;
+
// 1. 先启动 CablePanel 的系统自检
var cablePanel = GetRepairPanel();
if (cablePanel != null)
@@ -102,12 +140,27 @@ namespace AibisDream.FixSystem
screenPanel.gameObject.SetActive(true);
isSystemOn = true;
+ isStarting = false;
+ isStartupPrepared = false;
+
+ // 开机动画使用 Normal 表现,完成后再进入 Yarn 在关机期间缓存的目标状态。
+ ApplyLightState(targetLightState);
}
///
/// 设置灯光状态,并同步更新相关面板的灯光效果
///
public void SetLightState(LightState newState)
+ {
+ targetLightState = newState;
+
+ // 关机时只缓存目标状态,避免序章的 Warning 提前点亮面板。
+ if (!isSystemOn) return;
+
+ ApplyLightState(newState);
+ }
+
+ private void ApplyLightState(LightState newState)
{
// 1. 更新主灯光系统
if (panelLight != null)
@@ -134,6 +187,7 @@ namespace AibisDream.FixSystem
var dto = new FixPanelSnapshotDto
{
isSystemOn = isSystemOn,
+ lightState = targetLightState.ToString(),
currentRepairSystemType = repairSystemManager?.GetCurrentSystemType()?.Name,
isCableRetracted = cablePanel != null && cablePanel.isCableRetracted
};
@@ -161,6 +215,17 @@ namespace AibisDream.FixSystem
{
if (dto == null) return;
+ // 读档恢复的是稳定终态,不继承可能仍留在场景中的待启动模式。
+ isStartupPrepared = false;
+ startupMode = SystemStartupMode.AutoOnHead;
+ targetLightState = LightState.Normal;
+ if (!string.IsNullOrEmpty(dto.lightState)
+ && !System.Enum.TryParse(dto.lightState, true, out targetLightState))
+ {
+ Debug.LogWarning($"[FixPanelSystem] Unknown saved light state '{dto.lightState}'; using Normal.");
+ targetLightState = LightState.Normal;
+ }
+
ApplySystemOnImmediate(dto.isSystemOn);
if (repairSystemManager != null)
@@ -177,10 +242,11 @@ namespace AibisDream.FixSystem
public void ApplySystemOnImmediate(bool isOn)
{
isSystemOn = isOn;
+ isStarting = false;
if (panelLight != null)
{
- panelLight.Initialize(isOn);
+ panelLight.Initialize(isOn, targetLightState);
}
var cablePanel = GetRepairPanel();
diff --git a/Assets/Scripts/FixSystemNew/Screen System/FixPanel/TaskPanel.cs b/Assets/Scripts/FixSystemNew/Screen System/FixPanel/TaskPanel.cs
index d81ebe74c..e56f304fc 100644
--- a/Assets/Scripts/FixSystemNew/Screen System/FixPanel/TaskPanel.cs
+++ b/Assets/Scripts/FixSystemNew/Screen System/FixPanel/TaskPanel.cs
@@ -33,6 +33,12 @@ namespace AibisDream.FixSystem
taskRoot.DOLocalMoveX(ShownLocalX, 1f);
}
+ public void HidePanelImmediate()
+ {
+ taskRoot.DOKill();
+ SetPanelVisibleImmediate(false);
+ }
+
public void CompleteTask(string lineId)
{
if (_taskDict.Remove(lineId, out var taskItem))
diff --git a/Assets/Scripts/FixSystemNew/Screen System/ScreenYarnCommand.cs b/Assets/Scripts/FixSystemNew/Screen System/ScreenYarnCommand.cs
index 8e5add39f..a7672371b 100644
--- a/Assets/Scripts/FixSystemNew/Screen System/ScreenYarnCommand.cs
+++ b/Assets/Scripts/FixSystemNew/Screen System/ScreenYarnCommand.cs
@@ -1,6 +1,7 @@
using AibisDream.FixSystem;
using Yarn.Unity;
using System.Collections;
+using UnityEngine;
namespace AibisDream
{
@@ -101,6 +102,19 @@ namespace AibisDream
yield return FixPanelSystem.Instance.StartAllSystems();
}
+ [YarnCommand("prepare_system_startup")]
+ public static void PrepareSystemStartup(string mode)
+ {
+ if (FixPanelSystem.Instance == null) return;
+ if (!System.Enum.TryParse(mode, true, out SystemStartupMode startupMode))
+ {
+ Debug.LogWarning($"[Yarn] Unknown system startup mode '{mode}'. Expected AutoOnHead or Deferred.");
+ return;
+ }
+
+ FixPanelSystem.Instance.PrepareSystemStartup(startupMode);
+ }
+
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs b/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs
index 5f506ab97..475c08bbb 100644
--- a/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs
+++ b/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs
@@ -63,19 +63,24 @@ namespace AibisDream.FixSystem
var cablePanel = FixPanelSystem.GetRepairPanel();
// 拔出插头
// 切换Body或Head
- if (Enum.TryParse(transition.Args, out var moduleState))
+ bool hasModuleState = Enum.TryParse(transition.Args, out ModuleState moduleState);
+ bool isHeadEntry = hasModuleState && moduleState == ModuleState.Head;
+ if (hasModuleState)
{
bodyModuleSystem.SwitchModuleGroup(moduleState);
}
- if (cablePanel != null && !FixPanelSystem.Instance.IsSystemOn)
+ if (!FixPanelSystem.Instance.IsSystemOn && isHeadEntry)
{
// 切换相机
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModuleCenter);
yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f);
yield return new WaitForSeconds(0.5f);
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule);
- yield return FixPanelSystem.Instance.StartAllSystems();
+ if (FixPanelSystem.Instance.ShouldAutoStartOnHeadEntry)
+ {
+ yield return FixPanelSystem.Instance.StartAllSystems();
+ }
}
else
{
diff --git a/Assets/Scripts/SaveSystem/SaveSnapshot.cs b/Assets/Scripts/SaveSystem/SaveSnapshot.cs
index c21ffa9af..4312b9195 100644
--- a/Assets/Scripts/SaveSystem/SaveSnapshot.cs
+++ b/Assets/Scripts/SaveSystem/SaveSnapshot.cs
@@ -222,6 +222,9 @@ namespace AibisDream.SaveSystem
{
public bool isSystemOn;
+ /// 当前目标灯态;旧存档缺失时按 Normal 处理。
+ public string lightState;
+
/// RepairSystemManager 当前激活系统类型名;空则默认 BodyModuleSystem。
public string currentRepairSystemType;
diff --git a/Assets/Yarn/FP/FP_Prologue/Center.yarn b/Assets/Yarn/FP/FP_Prologue/Center.yarn
index de94d58a2..e93bd976d 100644
--- a/Assets/Yarn/FP/FP_Prologue/Center.yarn
+++ b/Assets/Yarn/FP/FP_Prologue/Center.yarn
@@ -18,17 +18,13 @@ position: 205,199
///在这里决定这次诊疗的目标是什么,以及目标判断相关的数值
//【流程相关】
-//gamestage:1-引入对话;2-检查;3-检查后对话;4-调速;5-调速后对话(冷却液)
+//gamestage:1-开场;2-插线检查(镇静→溃解→隔离);3-切割记忆;6-螺旋;999-结束
<>
-<>
-<>
-<>
-<>
-<>
-<>
<>
<>
+<>
<>
+<>
///【流程逻辑】
@@ -62,10 +58,6 @@ colorID: 1
<>
<>
<>
-<>
- <>
-<>
- <>
<>
<>
<>
@@ -73,4 +65,4 @@ colorID: 1
<>
// 结束,进入下一个Yarn
<>
-===
\ No newline at end of file
+===
diff --git a/Assets/Yarn/FP/FP_Prologue/EventNode.yarn b/Assets/Yarn/FP/FP_Prologue/EventNode.yarn
index 34b4c922c..c0c43f7b5 100644
--- a/Assets/Yarn/FP/FP_Prologue/EventNode.yarn
+++ b/Assets/Yarn/FP/FP_Prologue/EventNode.yarn
@@ -3,7 +3,10 @@ tags: event
colorID: 8
position: -2,-3039
---
-// <>
+<>
+ // 找记忆阶段:情绪模块已关机
+ <>
+<>
<>
<>
<>
@@ -14,6 +17,10 @@ tags: event
colorID: 8
position: 240,-2640
---
+<>
+ // 找记忆阶段:表达模块非目标
+ <>
+<>
<>
===
@@ -22,7 +29,10 @@ tags: event
colorID: 8
position: 480,-3040
---
-// <>
+<>
+ // 找记忆阶段:逻辑模块已关机
+ <>
+<>
<>
<>
<>
@@ -33,7 +43,10 @@ tags: event
colorID: 8
position: 240,-3040
---
-// <>
+<>
+ // 找记忆阶段:插中记忆,直接进入切割
+ <>
+<>
<>
<>
<>
@@ -47,22 +60,6 @@ tags: event
===
-title: EmoCutDown
-tags: event
----
-<>
-===
-
-
-
-
-title: LogicCutDown
-tags: event
----
-<>
-===
-
-
title: 拿起插头
tags: event
@@ -74,6 +71,12 @@ tags: event
title: ShockEffect
tags: event
---
+<>
+ <>
+ <>
+ <>
+ <>
+<>
<>
//<>
===
diff --git a/Assets/Yarn/FP/FP_Prologue/Stage2-5_切割.yarn b/Assets/Yarn/FP/FP_Prologue/Stage2-5_切割.yarn
index fdd4e5da0..cd1dbcdc6 100644
--- a/Assets/Yarn/FP/FP_Prologue/Stage2-5_切割.yarn
+++ b/Assets/Yarn/FP/FP_Prologue/Stage2-5_切割.yarn
@@ -8,8 +8,13 @@ position: 569,-3402
////需要用两种跳字效果来区分两个人格
<>
<>
+<>
+ <>
+<>
<>
-<>
+<>
+<>
+<>
<>
<>
dn: 系统已就绪。#auto_next
@@ -73,7 +78,7 @@ group:插线检查
position: 1108,-2261
---
<>
-<>
+<>
<>
gotash?: 啊…啊! #line:037a594
// <>
@@ -110,63 +115,6 @@ me: 出现异常状况。现在重新通电。
-title: 第二次切除
-tags:
-colorID: 8
-group:插线检查
-position: 1111,-2544
----
-<>
-<>
-Task: 切除{$currentCheckModule}模块 #line:0b94b47
-me: 会有点疼。 #line:04b0c1b
-<>
-<>
-===
-
-
-
-
-title: 第二次切除后
-tags:
-colorID: 8
-group:插线检查
-position: 1115,-2127
----
-// <>
-<>
-gotash?: 呃…啊 #line:0e795e0
-<>
-<>
-<>
-<>
-// 【背景中更多蓝色液体流出】 #line:095103b
-<>
-<>
-<>
-<>
-gotash?: 它还…它还活着……
为什么!我还在这个身体里…… #line:0a0aea0
-<>
-<>
-gotash?: 这是梦…这是梦。我必须醒来,我必须醒来…… #line:0d70b5d
-<>
-<>
-<>
-<>
-<>
-gotash?:醒来吧…醒来… #line:067a91c
-<>
-me: 生命体征正在溃解,得先稳定下来。 #line:015ac4e
-
-<>
-<>
-<>
-
-===
-
-
-
-
title:电击后
tags:
colorID: 8
@@ -175,7 +123,6 @@ position: 788,-1825
---
<>
<>
- <>
<>
<>
dn: 电流过载#auto_next
@@ -265,48 +212,6 @@ position: 788,-1825
-title: 第三次切除
-tags:
-colorID: 8
-group:插线检查
-position: 1110,-2412
----
-<>
-<>
-Task: 切除{$currentCheckModule}模块 #line:014f73d
-me: 坚持住。 #line:0352590
-<>
-===
-
-
-
-title: 第三次切除后
-tags:
-colorID: 8
-group:插线检查
-position: 1100,-1980
----
-<>
-<>
-gotash?: 呃呃呃呃呃呃呃呃#auto_next #line:0cf6d36
-<>
-<>
-me:污染源全部排除了。现在应该… #line:0c23843
-<>
-<>
-<>
-gotash?:不……我…死……死……我要…#auto_next #line:060f2e3
-<>
-me:为什么…不起作用? #line:0b93ed1
-<>
-<>
-<>
-<>
-===
-
-
-
-
title: 第一次检查
tags:
colorID: 8
@@ -319,10 +224,9 @@ Linking: 正在建立连接… #line:08a3591
// <>
// <>
//gotash?: 啊!痛…痛! #line:0681cac
-EmoModule: 已与{$currentCheckModule}模块建立连接! #line:0e05aec
+EmoModule: 已与{$currentCheckModule}模块建立连接! #line:0e05aec
<>
-<>
-Error: 检测到排异性坏死!请尽快处理。 #line:06122b9
+Error: 检测到排异性坏死!请尽快处理。 #line:06122b9
Error: 模块完整度:44.9% #line:0862409
Error: 原型泄漏:27.8% 已污染 #line:0c259fd
gotash?: 医生…
@@ -343,7 +247,10 @@ me: 很快就好了。
EmoModule: 指令执行完成!正在刷新...
Error: 原型泄漏:35.2%
<>
-【模块闪火花】
+// 情绪/逻辑/记忆进入损坏状态:文字闪烁+间歇火花
+<>
+<>
+<>
<>
gotash?: 咳…咳咳…
Error: 警告!检测到溃解数据流! #auto_next
@@ -367,11 +274,13 @@ Linking: 已收到紧急隔离指令。
Linking: 正在隔离逻辑模块…
<>
<>
+<>
Linking: 逻辑模块已隔离。
Linking: 原型泄漏:43.1%
Linking: 正在隔离情绪模块…
<>
<>
+<>
Linking: 情绪模块已隔离。
Linking: 原型泄漏:61.2%
Linking: 正在隔离记忆模块…
@@ -404,7 +313,50 @@ gotash?: [[size]]不[[/size]]!医生!我不想死…
gotash?: 我必须[[size]]死[[/size]],回收必须被完成… #line:0ab8d02
gotash?: 我想回家…妈妈……
me: 很抱歉。没有什么妈妈。
-->执行切除术 #line:0cc9043
+<>
+ // 插着的就是记忆模块,直接切割
+ ->执行切除术 #line:0cc9043
+ <>
+ <>
+ <>
+ <>
+ <>
+<>
+ // 插着的不是记忆模块,需要重新插线连接记忆
+ me: 等等…刚才连接的是{$currentCheckModule}模块。
+ me: 得直接连接记忆模块,才能进行切除。
+ Task: 插线连接记忆模块
+ <>
+ <>
+ <>
+<>
+===
+
+
+
+
+title: 连接记忆切除
+tags:
+colorID: 8
+group:插线检查
+description: 找记忆阶段插中记忆模块,触发切割
+position: 1101,-2974
+---
+<>
+<>
+<>
+<>
+Linking: 正在建立连接…
+<>
+MemModule: 已与记忆模块建立连接!
+<>
+<>
+gotash?: 没用的…没用的。 #line:01f682e
+Error: 检测到模块发生递归性坏死!请尽快处理。 #line:0c297b0
+Error: 模块核心完整度:让我死吧 #line:0a13a1b
+Error: 这一定是个噩梦:让我死吧 #line:037d57d
+me: 我得再快些。 #line:048cfa4
+->执行切除术 #line:06dd480
<>
<>
<>
@@ -415,55 +367,19 @@ me: 很抱歉。没有什么妈妈。
-title: 第二次检查
-tags:
-colorID: 8
-group:插线检查
-position: 1101,-2974
----
-<>
-Linking: 正在建立连接… #line:0e63512
-<>
-LogicModule: 已与{$currentCheckModule}模块建立连接! #line:08d3946
-<>
-Error: 检测到非法字符串扰。 #line:05804d7
-<>
-Error: 检测到排异性坏死!请尽快处理。 #line:0740cff
-Error: 模块完整度:73.9% #line:00274a3
-Error: 原型泄漏:74.00%73这是个_6噩5梦/r #line:0489e3a
-me: 我得再快些。 #line:048cfa4
-->执行切除术 #line:06dd480
- <>
- <>
-<>
-<>
-===
-
-
-
-
-title: 第三次检查
-tags:
+title: 未检测到信号
+tags:
colorID: 8
group:插线检查
+description: 找记忆阶段误插已关机模块或表达模块
position: 1090,-2816
---
<>
-Linking: 正在建立连接… #line:0fd4c6f
+Linking: 正在建立连接… #line:0fd4c6f
<>
-MemModule: 已与{$currentCheckModule}模块建立连接! #line:008fd04
<>
-gotash?: 没用的…没用的。 #line:01f682e
-Error: 检测到模块发生递归性坏死!请尽快处理。 #line:0c297b0
-Error: 模块核心完整度:让我死吧 #line:0a13a1b
-Error: 这一定是个噩梦:让我死吧 #line:037d57d
-Error: 求求你让我死吧#line:0797a17
-Error: 求求你让我死吧#line:0d5406c
-->执行模块切除 #line:0a88566
- <>
- <>
-<>
-<>
+Error: 未检测到信号。
+<>
===
@@ -475,13 +391,7 @@ colorID: 8
group:插线检查
position: 758,-2965
---
-<>
- <>
-<>
- <>
-<>
- <>
-<>
+<>
===
@@ -495,14 +405,7 @@ position: 769,-2682
---
<>
<>
-<>
- <>
-<>
- <>
-<>
- <>
-<>
-
+<>
===
@@ -516,13 +419,7 @@ position: 774,-2287
---
<>
<>
-<>
- <>
-<>
- <>
-<>
- <>
-<>
+<>
===
@@ -545,4 +442,4 @@ Error: 请定位坏死模块以中止溃解。 #line:0668599
->结束检查 #line:0b1d611
<>
<>
-===
\ No newline at end of file
+===