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
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|