146 lines
5.9 KiB
C#
146 lines
5.9 KiB
C#
using Barotrauma.Extensions;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
|
|
/// <summary>
|
|
/// Checks whether an arbitrary condition is met. The conditionals work the same way as they do in StatusEffects.
|
|
/// </summary>
|
|
class CheckConditionalAction : BinaryOptionAction
|
|
{
|
|
[Serialize("", IsPropertySaveable.Yes, description: "Tag of the target to check.")]
|
|
public Identifier TargetTag { get; set; }
|
|
|
|
[Serialize(PropertyConditional.LogicalOperatorType.Or, IsPropertySaveable.Yes, description: "Do all of the conditions need to be met, or is it enough if at least one is? Only valid if there are multiple conditionals.")]
|
|
public PropertyConditional.LogicalOperatorType LogicalOperator { get; set; }
|
|
|
|
private ImmutableArray<PropertyConditional> Conditionals { get; }
|
|
|
|
[Serialize("", IsPropertySaveable.Yes, description: "A tag to apply to the hull the target is currently in when the check succeeds, as well as all the hulls linked to it.")]
|
|
public Identifier ApplyTagToLinkedHulls { get; set; }
|
|
|
|
[Serialize("", IsPropertySaveable.Yes, description: "A tag to apply to the hull the target is currently in when the check succeeds.")]
|
|
public Identifier ApplyTagToHull { get; set; }
|
|
|
|
[Serialize("", IsPropertySaveable.Yes, description: "Tag to apply to the target (or all targets if there's multiple) when the check succeeds.")]
|
|
public Identifier ApplyTagToTarget { get; set; }
|
|
|
|
[Serialize(true, IsPropertySaveable.Yes, description: "Should the check fail if no targets matching the specified tag are found?")]
|
|
public bool FailIfTargetNotFound { get; set; }
|
|
|
|
public CheckConditionalAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
|
|
{
|
|
if (TargetTag.IsEmpty)
|
|
{
|
|
DebugConsole.LogError($"CheckConditionalAction error: {GetEventDebugName()} uses a CheckConditionalAction with no target tag! This will cause the check to automatically succeed.",
|
|
contentPackage: parentEvent.Prefab.ContentPackage);
|
|
}
|
|
var conditionalElements = element.GetChildElements("Conditional");
|
|
if (conditionalElements.None())
|
|
{
|
|
//backwards compatibility
|
|
Conditionals = PropertyConditional.FromXElement(element, IsConditionalAttribute).ToImmutableArray();
|
|
}
|
|
else
|
|
{
|
|
var conditionalList = new List<PropertyConditional>();
|
|
foreach (ContentXElement subElement in conditionalElements)
|
|
{
|
|
conditionalList.AddRange(PropertyConditional.FromXElement(subElement));
|
|
}
|
|
Conditionals = conditionalList.ToImmutableArray();
|
|
}
|
|
|
|
if (Conditionals.None())
|
|
{
|
|
DebugConsole.LogError($"CheckConditionalAction error: {GetEventDebugName()} uses a CheckConditionalAction with no valid PropertyConditional! This will cause the check to automatically succeed.",
|
|
contentPackage: parentEvent.Prefab.ContentPackage);
|
|
}
|
|
|
|
static bool IsConditionalAttribute(XAttribute attribute)
|
|
{
|
|
var nameAsIdentifier = attribute.NameAsIdentifier();
|
|
return
|
|
nameAsIdentifier != nameof(TargetTag) &&
|
|
nameAsIdentifier != nameof(LogicalOperator) &&
|
|
nameAsIdentifier != nameof(ApplyTagToLinkedHulls) &&
|
|
nameAsIdentifier != nameof(ApplyTagToHull);
|
|
}
|
|
}
|
|
|
|
protected override bool? DetermineSuccess()
|
|
{
|
|
IEnumerable<ISerializableEntity> targets = null;
|
|
if (!TargetTag.IsEmpty)
|
|
{
|
|
targets = ParentEvent.GetTargets(TargetTag).OfType<ISerializableEntity>();
|
|
}
|
|
|
|
if (targets.None())
|
|
{
|
|
return !FailIfTargetNotFound;
|
|
}
|
|
|
|
if (Conditionals.None())
|
|
{
|
|
foreach (var target in targets)
|
|
{
|
|
ApplyTagsToTarget(target);
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
bool success = false;
|
|
foreach (var target in targets)
|
|
{
|
|
if (ConditionalsMatch(target))
|
|
{
|
|
ApplyTagsToTarget(target);
|
|
success = true;
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
void ApplyTagsToTarget(ISerializableEntity target)
|
|
{
|
|
if (!ApplyTagToTarget.IsEmpty)
|
|
{
|
|
ParentEvent.AddTarget(ApplyTagToTarget, target as Entity);
|
|
}
|
|
ApplyTagsToHulls(target as Entity, ApplyTagToHull, ApplyTagToLinkedHulls);
|
|
}
|
|
}
|
|
|
|
private bool ConditionalsMatch(ISerializableEntity target)
|
|
{
|
|
if (LogicalOperator == PropertyConditional.LogicalOperatorType.And)
|
|
{
|
|
return Conditionals.All(c => ConditionalMatches(target, c));
|
|
}
|
|
else
|
|
{
|
|
return Conditionals.Any(c => ConditionalMatches(target, c));
|
|
}
|
|
}
|
|
|
|
private static bool ConditionalMatches(ISerializableEntity target, PropertyConditional conditional)
|
|
{
|
|
if (target is Item item)
|
|
{
|
|
if (!conditional.TargetItemComponent.IsNullOrEmpty() &&
|
|
item.Components.None(ic => ic.Name == conditional.TargetItemComponent))
|
|
{
|
|
return false;
|
|
}
|
|
return item.ConditionalMatches(conditional);
|
|
}
|
|
return conditional.Matches(target);
|
|
}
|
|
}
|
|
} |