Files
ichni_Official/Assets/Scripts/NewStorySystem/Data/StoryBlockDefinition.cs
2026-07-05 16:08:23 -04:00

141 lines
4.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Ichni.Story
{
/// <summary>
/// Block 在故事树中的状态:已锁定、当前可交互、已完成。
/// </summary>
public enum StoryBlockState
{
Locked,
Current,
Completed
}
/// <summary>
/// Block 的类型,决定点击后触发的行为。
/// </summary>
public enum StoryBlockType
{
Text,
Song,
Tutorial
}
/// <summary>
/// 变量条件的比较方式。
/// </summary>
public enum VariableComparison
{
Equal,
NotEqual,
Greater,
GreaterOrEqual,
Less,
LessOrEqual
}
/// <summary>
/// 故事树中单个 block 的完整数据定义,由 <see cref="StoryData"/> 持有。
/// </summary>
[InlineProperty]
[Serializable]
public class StoryBlockDefinition
{
[FoldoutGroup("$blockId", false)]
[LabelText("Block ID")]
public string blockId;
[FoldoutGroup("$blockId")]
[LabelText("Type")]
public StoryBlockType blockType;
[FoldoutGroup("$blockId")]
[LabelText("Grid Column")]
[Tooltip("故事树网格中的列:向右为正,(0,0) 位于容器左侧中部。可为负数与小数(用于微调)。")]
public float gridColumn;
[FoldoutGroup("$blockId")]
[LabelText("Grid Row")]
[Tooltip("故事树网格中的行向下为正、向上为负0 对应垂直中线。可为小数(用于微调)。")]
public float gridRow;
[FoldoutGroup("$blockId")]
[LabelText("Next Block IDs")]
public List<string> nextBlockIds = new List<string>();
[FoldoutGroup("$blockId")]
[LabelText("Unlock Condition")]
public UnlockCondition unlockCondition = new UnlockCondition();
// ── Text Block ──────────────────────────────────────────────────────────
[FoldoutGroup("$blockId")]
[ShowIf("blockType", StoryBlockType.Text)]
[LabelText("Yarn Node Name")]
public string yarnNodeName;
[FoldoutGroup("$blockId")]
[ShowIf("blockType", StoryBlockType.Text)]
[LabelText("Title Key (Localization)")]
public string titleKey;
// ── Song Block ──────────────────────────────────────────────────────────
[FoldoutGroup("$blockId")]
[ShowIf("blockType", StoryBlockType.Song)]
[LabelText("Song Name")]
public string songName;
// ── Tutorial Block ──────────────────────────────────────────────────────
[FoldoutGroup("$blockId")]
[ShowIf("blockType", StoryBlockType.Tutorial)]
[LabelText("Tutorial Name")]
public string tutorialName;
/// <summary>
/// 预览 / 调试用的显示标题:按类型取对应字段,缺省时回退到 blockId。
/// </summary>
public string GetDisplayTitle()
{
string title = blockType switch
{
StoryBlockType.Text => titleKey,
StoryBlockType.Song => songName,
StoryBlockType.Tutorial => tutorialName,
_ => null
};
return string.IsNullOrEmpty(title) ? blockId : title;
}
}
/// <summary>
/// Block 的解锁条件。以一棵可组合的条件树(<see cref="StoryConditionNode"/>)表达,
/// 支持"与 / 或 / 非 + 叶子条件"的任意嵌套。根节点为空时视为无条件解锁(始终满足)。
/// </summary>
[InlineProperty]
[Serializable]
public class UnlockCondition
{
[HideLabel]
[SerializeReference]
[InfoBox("留空表示无条件解锁(章节起始即可用)。可选择 All Of(AND) / Any Of(OR) / Not 复合节点进行任意嵌套。")]
public StoryConditionNode root;
/// <summary>
/// 检查解锁条件是否满足。根节点为空视为满足。
/// </summary>
/// <param name="getVariable">按变量名返回其整型值的委托。</param>
/// <param name="isBlockCompleted">按 blockId 判断该 block 是否已完成的委托。</param>
public bool IsSatisfied(Func<string, int> getVariable, Func<string, bool> isBlockCompleted)
{
return root == null || root.Evaluate(getVariable, isBlockCompleted);
}
}
}