IndieGame/client/Assets/ParadoxNotion/NodeCanvas/Modules/DialogueTrees/Nodes/ProbabilitySelector.cs

130 lines
4.5 KiB
C#
Raw Normal View History

2024-10-11 10:12:15 +08:00
using System.Collections.Generic;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace NodeCanvas.DialogueTrees
{
[Category("Branch")]
[Description("Select a child to execute based on it's chance to be selected. An optional pre-Condition Task can be assigned to filter the child in or out of the selection probability.\nThe actor selected will be used for the condition checks.")]
[ParadoxNotion.Design.Icon("ProbabilitySelector")]
[Color("b3ff7f")]
public class ProbabilitySelector : DTNode
{
public class Option
{
public BBParameter<float> weight;
public ConditionTask condition;
public Option(float weightValue, IBlackboard bbValue) {
weight = new BBParameter<float> { value = weightValue, bb = bbValue };
condition = null;
}
}
[SerializeField, AutoSortWithChildrenConnections]
private List<Option> childOptions = new List<Option>();
private List<int> successIndeces;
public override int maxOutConnections { get { return -1; } }
public override void OnChildConnected(int index) {
if ( childOptions.Count < outConnections.Count ) {
childOptions.Insert(index, new Option(1, graphBlackboard));
}
}
public override void OnChildDisconnected(int index) {
childOptions.RemoveAt(index);
}
protected override Status OnExecute(Component agent, IBlackboard blackboard) {
successIndeces = new List<int>();
for ( var i = 0; i < outConnections.Count; i++ ) {
var condition = childOptions[i].condition;
if ( condition == null || condition.CheckOnce(finalActor.transform, blackboard) ) {
successIndeces.Add(i);
}
}
var probability = Random.Range(0f, GetTotal());
for ( var i = 0; i < outConnections.Count; i++ ) {
if ( !successIndeces.Contains(i) ) {
continue;
}
if ( probability > childOptions[i].weight.value ) {
probability -= childOptions[i].weight.value;
continue;
}
DLGTree.Continue(i);
return Status.Success;
}
return Status.Failure;
}
float GetTotal() {
var total = 0f;
for ( var i = 0; i < childOptions.Count; i++ ) {
var option = childOptions[i];
if ( successIndeces == null || successIndeces.Contains(i) ) {
total += option.weight.value;
continue;
}
}
return total;
}
protected override void OnReset() {
successIndeces = null;
}
///----------------------------------------------------------------------------------------------
///---------------------------------------UNITY EDITOR-------------------------------------------
#if UNITY_EDITOR
public override string GetConnectionInfo(int i) {
var result = childOptions[i].condition != null ? childOptions[i].condition.summaryInfo + "\n" : string.Empty;
if ( successIndeces == null || successIndeces.Contains(i) ) {
return result + Mathf.Round(( childOptions[i].weight.value / GetTotal() ) * 100) + "%";
}
return result + "Condition Failed";
}
public override void OnConnectionInspectorGUI(int i) {
DrawOptionGUI(i, GetTotal());
}
protected override void OnNodeInspectorGUI() {
base.OnNodeInspectorGUI();
if ( outConnections.Count == 0 ) {
return;
}
var total = GetTotal();
for ( var i = 0; i < childOptions.Count; i++ ) {
EditorUtils.BoldSeparator();
DrawOptionGUI(i, total);
}
}
void DrawOptionGUI(int i, float total) {
NodeCanvas.Editor.TaskEditor.TaskFieldMulti<ConditionTask>(childOptions[i].condition, DLGTree, (c) => { childOptions[i].condition = c; });
EditorUtils.Separator();
GUILayout.BeginHorizontal();
NodeCanvas.Editor.BBParameterEditor.ParameterField("Weight", childOptions[i].weight);
GUILayout.Label(Mathf.Round(( childOptions[i].weight.value / total ) * 100) + "%", GUILayout.Width(38));
GUILayout.EndHorizontal();
}
#endif
}
}