EzAbilityCommonConditions.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Fill out your copyright notice in the Description page of Project Settings.
  2. #include "Condition/EzAbilityCommonConditions.h"
  3. #include "EzAbilityContext.h"
  4. #include "EzAbilityNodeDescriptionHelpers.h"
  5. #define LOCTEXT_NAMESPACE "Ability"
  6. namespace UE::EzAbility::Conditions
  7. {
  8. template<typename T>
  9. bool CompareNumbers(const T Left, const T Right, const EGenericCheck Operator)
  10. {
  11. switch (Operator)
  12. {
  13. case EGenericCheck::Equal:
  14. return Left == Right;
  15. break;
  16. case EGenericCheck::NotEqual:
  17. return Left != Right;
  18. break;
  19. case EGenericCheck::Less:
  20. return Left < Right;
  21. break;
  22. case EGenericCheck::LessOrEqual:
  23. return Left <= Right;
  24. break;
  25. case EGenericCheck::Greater:
  26. return Left > Right;
  27. break;
  28. case EGenericCheck::GreaterOrEqual:
  29. return Left >= Right;
  30. break;
  31. default:
  32. ensureMsgf(false, TEXT("Unhandled operator %d"), Operator);
  33. return false;
  34. break;
  35. }
  36. }
  37. }
  38. //----------------------------------------------------------------------//
  39. // FAbilityCompareIntCondition
  40. //----------------------------------------------------------------------//
  41. bool FAbilityCompareIntCondition::TestCondition(FEzAbilityContext& Context) const
  42. {
  43. const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
  44. const bool bResult = UE::EzAbility::Conditions::CompareNumbers<int32>(InstanceData.Left, InstanceData.Right, Operator);
  45. return bResult ^ bInvert;
  46. }
  47. #if WITH_EDITOR
  48. FText FAbilityCompareIntCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
  49. {
  50. const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
  51. check(InstanceData);
  52. FText LeftValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Left)), Formatting);
  53. if (LeftValue.IsEmpty())
  54. {
  55. LeftValue = FText::AsNumber(InstanceData->Left);
  56. }
  57. FText RightValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Right)), Formatting);
  58. if (RightValue.IsEmpty())
  59. {
  60. RightValue = FText::AsNumber(InstanceData->Right);
  61. }
  62. const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
  63. const FText OperatorText = UE::EzAbility::DescHelpers::GetOperatorText(Operator, Formatting);
  64. return FText::FormatNamed(LOCTEXT("CompareInt", "{EmptyOrNot}{Left} {Op} {Right}"),
  65. TEXT("EmptyOrNot"), InvertText,
  66. TEXT("Left"),LeftValue,
  67. TEXT("Op"), OperatorText,
  68. TEXT("Right"),RightValue);
  69. }
  70. #endif
  71. //----------------------------------------------------------------------//
  72. // FAbilityCompareFloatCondition
  73. //----------------------------------------------------------------------//
  74. bool FAbilityCompareFloatCondition::TestCondition(FEzAbilityContext& Context) const
  75. {
  76. const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
  77. const bool bResult = UE::EzAbility::Conditions::CompareNumbers<double>(InstanceData.Left, InstanceData.Right, Operator);
  78. return bResult ^ bInvert;
  79. }
  80. #if WITH_EDITOR
  81. FText FAbilityCompareFloatCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
  82. {
  83. const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
  84. check(InstanceData);
  85. FNumberFormattingOptions Options;
  86. Options.MinimumFractionalDigits = 1;
  87. Options.MaximumFractionalDigits = 3;
  88. FText LeftValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Left)), Formatting);
  89. if (LeftValue.IsEmpty())
  90. {
  91. LeftValue = FText::AsNumber(InstanceData->Left, &Options);
  92. }
  93. FText RightValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Right)), Formatting);
  94. if (RightValue.IsEmpty())
  95. {
  96. RightValue = FText::AsNumber(InstanceData->Right, &Options);
  97. }
  98. const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
  99. const FText OperatorText = UE::EzAbility::DescHelpers::GetOperatorText(Operator, Formatting);
  100. return FText::FormatNamed(LOCTEXT("CompareFloat", "{EmptyOrNot}{Left} {Op} {Right}"),
  101. TEXT("EmptyOrNot"), InvertText,
  102. TEXT("Left"),LeftValue,
  103. TEXT("Op"), OperatorText,
  104. TEXT("Right"),RightValue);
  105. }
  106. #endif
  107. //----------------------------------------------------------------------//
  108. // FAbilityCompareBoolCondition
  109. //----------------------------------------------------------------------//
  110. bool FAbilityCompareBoolCondition::TestCondition(FEzAbilityContext& Context) const
  111. {
  112. const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
  113. return (InstanceData.bLeft == InstanceData.bRight) ^ bInvert;
  114. }
  115. #if WITH_EDITOR
  116. FText FAbilityCompareBoolCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
  117. {
  118. const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
  119. check(InstanceData);
  120. FText LeftValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, bLeft)), Formatting);
  121. if (LeftValue.IsEmpty())
  122. {
  123. LeftValue = UE::EzAbility::DescHelpers::GetBoolText(InstanceData->bLeft, Formatting);
  124. }
  125. FText RightValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, bRight)), Formatting);
  126. if (RightValue.IsEmpty())
  127. {
  128. RightValue = UE::EzAbility::DescHelpers::GetBoolText(InstanceData->bRight, Formatting);
  129. }
  130. const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
  131. const FText Format = (Formatting == EEzAbilityNodeFormatting::RichText)
  132. ? LOCTEXT("CompareBoolRich", "{EmptyOrNot}{Left} <s>is</> {Right}")
  133. : LOCTEXT("CompareBool", "{EmptyOrNot}{Left} is {Right}");
  134. return FText::FormatNamed(Format,
  135. TEXT("EmptyOrNot"), InvertText,
  136. TEXT("Left"),LeftValue,
  137. TEXT("Right"),RightValue);
  138. }
  139. #endif
  140. //----------------------------------------------------------------------//
  141. // FAbilityCompareEnumCondition
  142. //----------------------------------------------------------------------//
  143. bool FAbilityCompareEnumCondition::TestCondition(FEzAbilityContext& Context) const
  144. {
  145. const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
  146. return (InstanceData.Left == InstanceData.Right) ^ bInvert;
  147. }
  148. #if WITH_EDITOR
  149. FText FAbilityCompareEnumCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
  150. {
  151. const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
  152. check(InstanceData);
  153. FText LeftValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Left)), Formatting);
  154. if (LeftValue.IsEmpty())
  155. {
  156. if (InstanceData->Left.Enum)
  157. {
  158. LeftValue = InstanceData->Left.Enum->GetDisplayNameTextByValue(InstanceData->Left.Value);
  159. }
  160. else
  161. {
  162. LeftValue = LOCTEXT("None", "None");
  163. }
  164. }
  165. FText RightValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Right)), Formatting);
  166. if (RightValue.IsEmpty())
  167. {
  168. if (InstanceData->Left.Enum)
  169. {
  170. RightValue = InstanceData->Right.Enum->GetDisplayNameTextByValue(InstanceData->Right.Value);
  171. }
  172. else
  173. {
  174. RightValue = LOCTEXT("None", "None");
  175. }
  176. }
  177. const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
  178. const FText Format = (Formatting == EEzAbilityNodeFormatting::RichText)
  179. ? LOCTEXT("CompareEnumRich", "{EmptyOrNot}{Left} <s>is</> {Right}")
  180. : LOCTEXT("CompareEnum", "{EmptyOrNot}{Left} is {Right}");
  181. return FText::FormatNamed(Format,
  182. TEXT("EmptyOrNot"), InvertText,
  183. TEXT("Left"),LeftValue,
  184. TEXT("Right"),RightValue);
  185. }
  186. void FAbilityCompareEnumCondition::OnBindingChanged(const FGuid& ID, FEzAbilityDataView InstanceData, const FEzAbilityPropertyPath& SourcePath, const FEzAbilityPropertyPath& TargetPath, const IEzAbilityBindingLookup& BindingLookup)
  187. {
  188. if (!TargetPath.GetStructID().IsValid())
  189. {
  190. return;
  191. }
  192. FInstanceDataType& Instance = InstanceData.GetMutable<FInstanceDataType>();
  193. // Left has changed, update enums from the leaf property.
  194. if (!TargetPath.IsPathEmpty()
  195. && TargetPath.GetSegments().Last().GetName() == GET_MEMBER_NAME_CHECKED(FInstanceDataType, Left))
  196. {
  197. if (const FProperty* LeafProperty = BindingLookup.GetPropertyPathLeafProperty(SourcePath))
  198. {
  199. // Handle both old stype namespace enums and new class enum properties.
  200. UEnum* NewEnum = nullptr;
  201. if (const FByteProperty* ByteProperty = CastField<FByteProperty>(LeafProperty))
  202. {
  203. NewEnum = ByteProperty->GetIntPropertyEnum();
  204. }
  205. else if (const FEnumProperty* EnumProperty = CastField<FEnumProperty>(LeafProperty))
  206. {
  207. NewEnum = EnumProperty->GetEnum();
  208. }
  209. if (Instance.Left.Enum != NewEnum)
  210. {
  211. Instance.Left.Initialize(NewEnum);
  212. }
  213. }
  214. else
  215. {
  216. Instance.Left.Initialize(nullptr);
  217. }
  218. if (Instance.Right.Enum != Instance.Left.Enum)
  219. {
  220. Instance.Right.Initialize(Instance.Left.Enum);
  221. }
  222. }
  223. }
  224. #endif
  225. //----------------------------------------------------------------------//
  226. // FAbilityCompareDistanceCondition
  227. //----------------------------------------------------------------------//
  228. bool FAbilityCompareDistanceCondition::TestCondition(FEzAbilityContext& Context) const
  229. {
  230. const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
  231. const FVector::FReal Left = FVector::DistSquared(InstanceData.Source, InstanceData.Target);
  232. const FVector::FReal Right = FMath::Square(InstanceData.Distance);
  233. const bool bResult = UE::EzAbility::Conditions::CompareNumbers<FVector::FReal>(Left, Right, Operator);
  234. return bResult ^ bInvert;
  235. }
  236. #if WITH_EDITOR
  237. FText FAbilityCompareDistanceCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
  238. {
  239. const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
  240. check(InstanceData);
  241. FNumberFormattingOptions Options;
  242. Options.MinimumFractionalDigits = 1;
  243. Options.MaximumFractionalDigits = 3;
  244. FText SourceValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Source)), Formatting);
  245. if (SourceValue.IsEmpty())
  246. {
  247. SourceValue = InstanceData->Source.ToText();
  248. }
  249. FText TargetValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Target)), Formatting);
  250. if (TargetValue.IsEmpty())
  251. {
  252. TargetValue = InstanceData->Target.ToText();
  253. }
  254. FText DistanceValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Distance)), Formatting);
  255. if (DistanceValue.IsEmpty())
  256. {
  257. DistanceValue = FText::AsNumber(InstanceData->Distance, &Options);
  258. }
  259. const FText OperatorText = UE::EzAbility::DescHelpers::GetOperatorText(Operator, Formatting);
  260. const FText InvertText = UE::EzAbility::DescHelpers::GetInvertText(bInvert, Formatting);
  261. const FText Format = (Formatting == EEzAbilityNodeFormatting::RichText)
  262. ? LOCTEXT("CompareDistanceRich", "{EmptyOrNot}<s>Distance from</> {Source} <s>to</> {Target} {Op} {Distance}")
  263. : LOCTEXT("CompareDistance", "{EmptyOrNot}Distance from {Source} to {Target} {Op} {Distance}");
  264. return FText::FormatNamed(Format,
  265. TEXT("EmptyOrNot"), InvertText,
  266. TEXT("Source"), SourceValue,
  267. TEXT("Target"), TargetValue,
  268. TEXT("Op"), OperatorText,
  269. TEXT("Distance"), DistanceValue);
  270. }
  271. #endif
  272. //----------------------------------------------------------------------//
  273. // FAbilityRandomCondition
  274. //----------------------------------------------------------------------//
  275. bool FAbilityRandomCondition::TestCondition(FEzAbilityContext& Context) const
  276. {
  277. const FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
  278. return FMath::FRandRange(0.0f, 1.0f) < InstanceData.Threshold;
  279. }
  280. #if WITH_EDITOR
  281. FText FAbilityRandomCondition::GetDescription(const FGuid& ID, FEzAbilityDataView InstanceDataView, const IEzAbilityBindingLookup& BindingLookup, EEzAbilityNodeFormatting Formatting) const
  282. {
  283. const FInstanceDataType* InstanceData = InstanceDataView.GetPtr<FInstanceDataType>();
  284. check(InstanceData);
  285. FNumberFormattingOptions Options;
  286. Options.MinimumFractionalDigits = 1;
  287. Options.MaximumFractionalDigits = 3;
  288. FText ThresholdValue = BindingLookup.GetBindingSourceDisplayName(FEzAbilityPropertyPath(ID, GET_MEMBER_NAME_CHECKED(FInstanceDataType, Threshold)), Formatting);
  289. if (ThresholdValue.IsEmpty())
  290. {
  291. ThresholdValue = FText::AsNumber(InstanceData->Threshold, &Options);
  292. }
  293. const FText Format = (Formatting == EEzAbilityNodeFormatting::RichText)
  294. ? LOCTEXT("RandomRich", "<s>Random [0..1] &lt;</> {Threshold}")
  295. : LOCTEXT("Random", "Random [0..1] &lt; {Threshold}");
  296. return FText::FormatNamed(Format,
  297. TEXT("Threshold"), ThresholdValue);
  298. }
  299. #endif
  300. #undef LOCTEXT_NAMESPACE