140 lines
4.8 KiB
C#
140 lines
4.8 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using Sirenix.OdinInspector;
|
||
using UnityEngine;
|
||
|
||
namespace Ichni.Story
|
||
{
|
||
/// <summary>
|
||
/// 解锁条件树的节点基类。通过多态组合出"与 / 或 / 非 + 叶子条件"的复合表达式。
|
||
/// 由 <see cref="UnlockCondition"/> 借助 <c>[SerializeReference]</c> 序列化持有,
|
||
/// Odin 会以类型下拉框展示可选的节点类型。
|
||
/// </summary>
|
||
[Serializable]
|
||
public abstract class StoryConditionNode
|
||
{
|
||
/// <summary>
|
||
/// 对该节点求值。
|
||
/// </summary>
|
||
/// <param name="getVariable">按变量名返回其整型值的委托。</param>
|
||
/// <param name="isBlockCompleted">按 blockId 判断该 block 是否已完成的委托。</param>
|
||
public abstract bool Evaluate(Func<string, int> getVariable, Func<string, bool> isBlockCompleted);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复合节点(逻辑与 AND):所有子条件均满足时才满足。子列表为空视为满足。
|
||
/// </summary>
|
||
[Serializable]
|
||
[LabelText("All Of (AND)")]
|
||
public class AllOfCondition : StoryConditionNode
|
||
{
|
||
[HideLabel]
|
||
[SerializeReference]
|
||
[ListDrawerSettings(ShowFoldout = true, DefaultExpandedState = true)]
|
||
public List<StoryConditionNode> conditions = new List<StoryConditionNode>();
|
||
|
||
public override bool Evaluate(Func<string, int> getVariable, Func<string, bool> isBlockCompleted)
|
||
{
|
||
foreach (StoryConditionNode child in conditions)
|
||
{
|
||
if (child != null && !child.Evaluate(getVariable, isBlockCompleted))
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复合节点(逻辑或 OR):任一子条件满足即满足。子列表为空视为不满足。
|
||
/// </summary>
|
||
[Serializable]
|
||
[LabelText("Any Of (OR)")]
|
||
public class AnyOfCondition : StoryConditionNode
|
||
{
|
||
[HideLabel]
|
||
[SerializeReference]
|
||
[ListDrawerSettings(ShowFoldout = true, DefaultExpandedState = true)]
|
||
public List<StoryConditionNode> conditions = new List<StoryConditionNode>();
|
||
|
||
public override bool Evaluate(Func<string, int> getVariable, Func<string, bool> isBlockCompleted)
|
||
{
|
||
if (conditions.Count == 0)
|
||
return false;
|
||
|
||
foreach (StoryConditionNode child in conditions)
|
||
{
|
||
if (child != null && child.Evaluate(getVariable, isBlockCompleted))
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复合节点(逻辑非 NOT):对子条件取反。子条件为空视为满足(等价于"非 假")。
|
||
/// </summary>
|
||
[Serializable]
|
||
[LabelText("Not")]
|
||
public class NotCondition : StoryConditionNode
|
||
{
|
||
[HideLabel]
|
||
[SerializeReference]
|
||
public StoryConditionNode condition;
|
||
|
||
public override bool Evaluate(Func<string, int> getVariable, Func<string, bool> isBlockCompleted)
|
||
{
|
||
return condition == null || !condition.Evaluate(getVariable, isBlockCompleted);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 叶子节点:指定 block 已完成时满足。
|
||
/// </summary>
|
||
[Serializable]
|
||
[LabelText("Block Completed")]
|
||
public class BlockCompletedCondition : StoryConditionNode
|
||
{
|
||
[LabelText("Block ID")]
|
||
public string blockId;
|
||
|
||
public override bool Evaluate(Func<string, int> getVariable, Func<string, bool> isBlockCompleted)
|
||
{
|
||
return !string.IsNullOrEmpty(blockId) && isBlockCompleted(blockId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 叶子节点:将指定变量的当前值与目标值按比较方式求值。
|
||
/// </summary>
|
||
[Serializable]
|
||
[LabelText("Variable Compare")]
|
||
public class VariableCondition : StoryConditionNode
|
||
{
|
||
[LabelText("Variable Name")]
|
||
public string variableName;
|
||
|
||
[LabelText("Comparison")]
|
||
public VariableComparison comparison;
|
||
|
||
[LabelText("Value")]
|
||
public int value;
|
||
|
||
public override bool Evaluate(Func<string, int> getVariable, Func<string, bool> isBlockCompleted)
|
||
{
|
||
int actual = getVariable(variableName);
|
||
return comparison switch
|
||
{
|
||
VariableComparison.Equal => actual == value,
|
||
VariableComparison.NotEqual => actual != value,
|
||
VariableComparison.Greater => actual > value,
|
||
VariableComparison.GreaterOrEqual => actual >= value,
|
||
VariableComparison.Less => actual < value,
|
||
VariableComparison.LessOrEqual => actual <= value,
|
||
_ => false
|
||
};
|
||
}
|
||
}
|
||
}
|