|
@@ -0,0 +1,369 @@
|
|
|
+// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
+
|
|
|
+
|
|
|
+#include "Condition/EzAbilityCommonConditions.h"
|
|
|
+
|
|
|
+#include "EzAbilityContext.h"
|
|
|
+#include "EzAbilityNodeDescriptionHelpers.h"
|
|
|
+
|
|
|
+#define LOCTEXT_NAMESPACE "Ability"
|
|
|
+
|
|
|
+namespace UE::EzAbility::Conditions
|
|
|
+{
|
|
|
+
|
|
|
+ template<typename T>
|
|
|
+ bool CompareNumbers(const T Left, const T Right, const EGenericCheck Operator)
|
|
|
+ {
|
|
|
+ switch (Operator)
|
|
|
+ {
|
|
|
+ case EGenericCheck::Equal:
|
|
|
+ return Left == Right;
|
|
|
+ break;
|
|
|
+ case EGenericCheck::NotEqual:
|
|
|
+ return Left != Right;
|
|
|
+ break;
|
|
|
+ case EGenericCheck::Less:
|
|
|
+ return Left < Right;
|
|
|
+ break;
|
|
|
+ case EGenericCheck::LessOrEqual:
|
|
|
+ return Left <= Right;
|
|
|
+ break;
|
|
|
+ case EGenericCheck::Greater:
|
|
|
+ return Left > Right;
|
|
|
+ break;
|
|
|
+ case EGenericCheck::GreaterOrEqual:
|
|
|
+ return Left >= Right;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ensureMsgf(false, TEXT("Unhandled operator %d"), Operator);
|
|
|
+ return false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+// FAbilityCompareIntCondition
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+
|
|
|
+bool FAbilityCompareIntCondition::TestCondition(FEzAbilityContext& Context) const
|
|
|
+{
|
|
|
+ const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
|
|
|
+
|
|
|
+ const bool bResult = UE::EzAbility::Conditions::CompareNumbers<int32>(InstanceData.Left, InstanceData.Right, Operator);
|
|
|
+ return bResult ^ bInvert;
|
|
|
+}
|
|
|
+
|
|
|
+#if WITH_EDITOR
|
|
|
+FText FAbilityCompareIntCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
|
|
|
+{
|
|
|
+ const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
|
|
|
+ check(InstanceData);
|
|
|
+
|
|
|
+ FText LeftValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Left)), Formatting);
|
|
|
+ if (LeftValue.IsEmpty())
|
|
|
+ {
|
|
|
+ LeftValue = FText::AsNumber(InstanceData->Left);
|
|
|
+ }
|
|
|
+
|
|
|
+ FText RightValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Right)), Formatting);
|
|
|
+ if (RightValue.IsEmpty())
|
|
|
+ {
|
|
|
+ RightValue = FText::AsNumber(InstanceData->Right);
|
|
|
+ }
|
|
|
+
|
|
|
+ const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
|
|
|
+ const FText OperatorText = UE::EzAbility::DescHelpers::GetOperatorText(Operator, Formatting);
|
|
|
+
|
|
|
+ return FText::FormatNamed(LOCTEXT("CompareInt", "{EmptyOrNot}{Left} {Op} {Right}"),
|
|
|
+ TEXT("EmptyOrNot"), InvertText,
|
|
|
+ TEXT("Left"),LeftValue,
|
|
|
+ TEXT("Op"), OperatorText,
|
|
|
+ TEXT("Right"),RightValue);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+// FAbilityCompareFloatCondition
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+
|
|
|
+bool FAbilityCompareFloatCondition::TestCondition(FEzAbilityContext& Context) const
|
|
|
+{
|
|
|
+ const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
|
|
|
+
|
|
|
+ const bool bResult = UE::EzAbility::Conditions::CompareNumbers<double>(InstanceData.Left, InstanceData.Right, Operator);
|
|
|
+ return bResult ^ bInvert;
|
|
|
+}
|
|
|
+
|
|
|
+#if WITH_EDITOR
|
|
|
+FText FAbilityCompareFloatCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
|
|
|
+{
|
|
|
+ const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
|
|
|
+ check(InstanceData);
|
|
|
+
|
|
|
+ FNumberFormattingOptions Options;
|
|
|
+ Options.MinimumFractionalDigits = 1;
|
|
|
+ Options.MaximumFractionalDigits = 3;
|
|
|
+
|
|
|
+ FText LeftValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Left)), Formatting);
|
|
|
+ if (LeftValue.IsEmpty())
|
|
|
+ {
|
|
|
+ LeftValue = FText::AsNumber(InstanceData->Left, &Options);
|
|
|
+ }
|
|
|
+
|
|
|
+ FText RightValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Right)), Formatting);
|
|
|
+ if (RightValue.IsEmpty())
|
|
|
+ {
|
|
|
+ RightValue = FText::AsNumber(InstanceData->Right, &Options);
|
|
|
+ }
|
|
|
+
|
|
|
+ const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
|
|
|
+ const FText OperatorText = UE::EzAbility::DescHelpers::GetOperatorText(Operator, Formatting);
|
|
|
+
|
|
|
+ return FText::FormatNamed(LOCTEXT("CompareFloat", "{EmptyOrNot}{Left} {Op} {Right}"),
|
|
|
+ TEXT("EmptyOrNot"), InvertText,
|
|
|
+ TEXT("Left"),LeftValue,
|
|
|
+ TEXT("Op"), OperatorText,
|
|
|
+ TEXT("Right"),RightValue);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+// FAbilityCompareBoolCondition
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+
|
|
|
+bool FAbilityCompareBoolCondition::TestCondition(FEzAbilityContext& Context) const
|
|
|
+{
|
|
|
+ const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
|
|
|
+
|
|
|
+ return (InstanceData.bLeft == InstanceData.bRight) ^ bInvert;
|
|
|
+}
|
|
|
+
|
|
|
+#if WITH_EDITOR
|
|
|
+FText FAbilityCompareBoolCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
|
|
|
+{
|
|
|
+ const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
|
|
|
+ check(InstanceData);
|
|
|
+
|
|
|
+ FText LeftValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, bLeft)), Formatting);
|
|
|
+ if (LeftValue.IsEmpty())
|
|
|
+ {
|
|
|
+ LeftValue = UE::EzAbility::DescHelpers::GetBoolText(InstanceData->bLeft, Formatting);
|
|
|
+ }
|
|
|
+
|
|
|
+ FText RightValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, bRight)), Formatting);
|
|
|
+ if (RightValue.IsEmpty())
|
|
|
+ {
|
|
|
+ RightValue = UE::EzAbility::DescHelpers::GetBoolText(InstanceData->bRight, Formatting);
|
|
|
+ }
|
|
|
+
|
|
|
+ const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
|
|
|
+
|
|
|
+ const FText Format = (Formatting == EEzAbilityNodeFormatting::RichText)
|
|
|
+ ? LOCTEXT("CompareBoolRich", "{EmptyOrNot}{Left} <s>is</> {Right}")
|
|
|
+ : LOCTEXT("CompareBool", "{EmptyOrNot}{Left} is {Right}");
|
|
|
+
|
|
|
+ return FText::FormatNamed(Format,
|
|
|
+ TEXT("EmptyOrNot"), InvertText,
|
|
|
+ TEXT("Left"),LeftValue,
|
|
|
+ TEXT("Right"),RightValue);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+// FAbilityCompareEnumCondition
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+
|
|
|
+bool FAbilityCompareEnumCondition::TestCondition(FEzAbilityContext& Context) const
|
|
|
+{
|
|
|
+ const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
|
|
|
+
|
|
|
+ return (InstanceData.Left == InstanceData.Right) ^ bInvert;
|
|
|
+}
|
|
|
+
|
|
|
+#if WITH_EDITOR
|
|
|
+FText FAbilityCompareEnumCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
|
|
|
+{
|
|
|
+ const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
|
|
|
+ check(InstanceData);
|
|
|
+
|
|
|
+ FText LeftValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Left)), Formatting);
|
|
|
+ if (LeftValue.IsEmpty())
|
|
|
+ {
|
|
|
+ if (InstanceData->Left.Enum)
|
|
|
+ {
|
|
|
+ LeftValue = InstanceData->Left.Enum->GetDisplayNameTextByValue(InstanceData->Left.Value);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LeftValue = LOCTEXT("None", "None");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ FText RightValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Right)), Formatting);
|
|
|
+ if (RightValue.IsEmpty())
|
|
|
+ {
|
|
|
+ if (InstanceData->Left.Enum)
|
|
|
+ {
|
|
|
+ RightValue = InstanceData->Right.Enum->GetDisplayNameTextByValue(InstanceData->Right.Value);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ RightValue = LOCTEXT("None", "None");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
|
|
|
+
|
|
|
+ const FText Format = (Formatting == EEzAbilityNodeFormatting::RichText)
|
|
|
+ ? LOCTEXT("CompareEnumRich", "{EmptyOrNot}{Left} <s>is</> {Right}")
|
|
|
+ : LOCTEXT("CompareEnum", "{EmptyOrNot}{Left} is {Right}");
|
|
|
+
|
|
|
+ return FText::FormatNamed(Format,
|
|
|
+ TEXT("EmptyOrNot"), InvertText,
|
|
|
+ TEXT("Left"),LeftValue,
|
|
|
+ TEXT("Right"),RightValue);
|
|
|
+}
|
|
|
+
|
|
|
+void FAbilityCompareEnumCondition::OnBindingChanged(const FGuid& ID, FEzAbilityDataView InstanceData, const FEzAbilityPropertyPath& SourcePath, const FEzAbilityPropertyPath& TargetPath, const IEzAbilityBindingLookup& BindingLookup)
|
|
|
+{
|
|
|
+ if (!TargetPath.GetStructID().IsValid())
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ FInstanceDataType& Instance = InstanceData.GetMutable<FInstanceDataType>();
|
|
|
+
|
|
|
+ // Left has changed, update enums from the leaf property.
|
|
|
+ if (!TargetPath.IsPathEmpty()
|
|
|
+ && TargetPath.GetSegments().Last().GetName() == GET_MEMBER_NAME_CHECKED(FInstanceDataType, Left))
|
|
|
+ {
|
|
|
+ if (const FProperty* LeafProperty = BindingLookup.GetPropertyPathLeafProperty(SourcePath))
|
|
|
+ {
|
|
|
+ // Handle both old stype namespace enums and new class enum properties.
|
|
|
+ UEnum* NewEnum = nullptr;
|
|
|
+ if (const FByteProperty* ByteProperty = CastField<FByteProperty>(LeafProperty))
|
|
|
+ {
|
|
|
+ NewEnum = ByteProperty->GetIntPropertyEnum();
|
|
|
+ }
|
|
|
+ else if (const FEnumProperty* EnumProperty = CastField<FEnumProperty>(LeafProperty))
|
|
|
+ {
|
|
|
+ NewEnum = EnumProperty->GetEnum();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Instance.Left.Enum != NewEnum)
|
|
|
+ {
|
|
|
+ Instance.Left.Initialize(NewEnum);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Instance.Left.Initialize(nullptr);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Instance.Right.Enum != Instance.Left.Enum)
|
|
|
+ {
|
|
|
+ Instance.Right.Initialize(Instance.Left.Enum);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+// FAbilityCompareDistanceCondition
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+
|
|
|
+bool FAbilityCompareDistanceCondition::TestCondition(FEzAbilityContext& Context) const
|
|
|
+{
|
|
|
+ const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
|
|
|
+
|
|
|
+ const FVector::FReal Left = FVector::DistSquared(InstanceData.Source, InstanceData.Target);
|
|
|
+ const FVector::FReal Right = FMath::Square(InstanceData.Distance);
|
|
|
+ const bool bResult = UE::EzAbility::Conditions::CompareNumbers<FVector::FReal>(Left, Right, Operator);
|
|
|
+ return bResult ^ bInvert;
|
|
|
+}
|
|
|
+
|
|
|
+#if WITH_EDITOR
|
|
|
+FText FAbilityCompareDistanceCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
|
|
|
+{
|
|
|
+ const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
|
|
|
+ check(InstanceData);
|
|
|
+
|
|
|
+ FNumberFormattingOptions Options;
|
|
|
+ Options.MinimumFractionalDigits = 1;
|
|
|
+ Options.MaximumFractionalDigits = 3;
|
|
|
+
|
|
|
+ FText SourceValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Source)), Formatting);
|
|
|
+ if (SourceValue.IsEmpty())
|
|
|
+ {
|
|
|
+ SourceValue = InstanceData->Source.ToText();
|
|
|
+ }
|
|
|
+
|
|
|
+ FText TargetValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Target)), Formatting);
|
|
|
+ if (TargetValue.IsEmpty())
|
|
|
+ {
|
|
|
+ TargetValue = InstanceData->Target.ToText();
|
|
|
+ }
|
|
|
+
|
|
|
+ FText DistanceValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Distance)), Formatting);
|
|
|
+ if (DistanceValue.IsEmpty())
|
|
|
+ {
|
|
|
+ DistanceValue = FText::AsNumber(InstanceData->Distance, &Options);
|
|
|
+ }
|
|
|
+
|
|
|
+ const FText OperatorText = UE::EzAbility::DescHelpers::GetOperatorText(Operator, Formatting);
|
|
|
+ const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
|
|
|
+
|
|
|
+ const FText Format = (Formatting == EEzAbilityNodeFormatting::RichText)
|
|
|
+ ? LOCTEXT("CompareDistanceRich", "{EmptyOrNot}<s>Distance from</> {Source} <s>to</> {Target} {Op} {Distance}")
|
|
|
+ : LOCTEXT("CompareDistance", "{EmptyOrNot}Distance from {Source} to {Target} {Op} {Distance}");
|
|
|
+
|
|
|
+ return FText::FormatNamed(Format,
|
|
|
+ TEXT("EmptyOrNot"), InvertText,
|
|
|
+ TEXT("Source"), SourceValue,
|
|
|
+ TEXT("Target"), TargetValue,
|
|
|
+ TEXT("Op"), OperatorText,
|
|
|
+ TEXT("Distance"), DistanceValue);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+// FAbilityRandomCondition
|
|
|
+//----------------------------------------------------------------------//
|
|
|
+
|
|
|
+bool FAbilityRandomCondition::TestCondition(FEzAbilityContext& Context) const
|
|
|
+{
|
|
|
+ const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
|
|
|
+
|
|
|
+ return FMath::FRandRange(0.0f, 1.0f) < InstanceData.Threshold;
|
|
|
+}
|
|
|
+
|
|
|
+#if WITH_EDITOR
|
|
|
+FText FAbilityRandomCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
|
|
|
+{
|
|
|
+ const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
|
|
|
+ check(InstanceData);
|
|
|
+
|
|
|
+ FNumberFormattingOptions Options;
|
|
|
+ Options.MinimumFractionalDigits = 1;
|
|
|
+ Options.MaximumFractionalDigits = 3;
|
|
|
+
|
|
|
+ FText ThresholdValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Threshold)), Formatting);
|
|
|
+ if (ThresholdValue.IsEmpty())
|
|
|
+ {
|
|
|
+ ThresholdValue = FText::AsNumber(InstanceData->Threshold, &Options);
|
|
|
+ }
|
|
|
+
|
|
|
+ const FText Format = (Formatting == EEzAbilityNodeFormatting::RichText)
|
|
|
+ ? LOCTEXT("RandomRich", "<s>Random [0..1] <</> {Threshold}")
|
|
|
+ : LOCTEXT("Random", "Random [0..1] < {Threshold}");
|
|
|
+
|
|
|
+ return FText::FormatNamed(Format,
|
|
|
+ TEXT("Threshold"), ThresholdValue);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#undef LOCTEXT_NAMESPACE
|