Files
2025-03-12 12:56:27 +00:00

211 lines
8.2 KiB
C#

#nullable enable
using System;
namespace Barotrauma
{
/// <summary>
/// Can be used to check arbitrary campaign metadata set using <see cref="SetDataAction"/>.
/// </summary>
class CheckDataAction : BinaryOptionAction
{
[Serialize("", IsPropertySaveable.Yes, description: "Identifier of the data to check.")]
public Identifier Identifier { get; set; } = Identifier.Empty;
[Serialize("", IsPropertySaveable.Yes, description: "The condition that must be met for the check to succeed. Uses the same formatting as conditionals (for example, \"gt 5.2\", \"true\", \"lt 10\".)")]
public string Condition { get; set; } = "";
[Serialize(false, IsPropertySaveable.Yes, "Forces the comparison to use string instead of attempting to parse it as a boolean or a float first. Use this if you know the value is a string.")]
public bool ForceString { get; set; }
[Serialize(false, IsPropertySaveable.Yes, "Performs the comparison against a metadata by identifier instead of a constant value. Meaning that you could for example check whether the value of \"progress_of_some_event\" is larger than \"progress_of_some_other_event\".")]
public bool CheckAgainstMetadata { get; set; }
protected object? value2;
protected object? value1;
protected PropertyConditional.ComparisonOperatorType Operator { get; set; }
public CheckDataAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
{
if (string.IsNullOrEmpty(Condition))
{
Condition = element.GetAttributeString("value", string.Empty)!;
if (string.IsNullOrEmpty(Condition))
{
DebugConsole.ThrowError($"Error in scripted event \"{parentEvent.Prefab.Identifier}\". CheckDataAction with no condition set ({element}).",
contentPackage: element?.ContentPackage);
}
}
}
public CheckDataAction(ContentXElement element, string parentDebugString) : base(null, element)
{
if (string.IsNullOrEmpty(Condition))
{
Condition = element.GetAttributeString("value", string.Empty)!;
if (string.IsNullOrEmpty(Condition))
{
DebugConsole.ThrowError($"Error in scripted event \"{parentDebugString}\". CheckDataAction with no condition set ({element}).",
contentPackage: element?.ContentPackage);
}
}
}
public bool GetSuccess()
{
return DetermineSuccess() ?? false;
}
protected override bool? DetermineSuccess()
{
if (GameMain.GameSession?.GameMode is not CampaignMode campaignMode) { return false; }
(Operator, string value) = PropertyConditional.ExtractComparisonOperatorFromConditionString(Condition);
if (Operator == PropertyConditional.ComparisonOperatorType.None)
{
DebugConsole.ThrowError($"{Condition} is invalid, it should start with an operator followed by a boolean or a floating point value.",
contentPackage: ParentEvent?.Prefab?.ContentPackage);
return false;
}
if (CheckAgainstMetadata)
{
object? metadata1 = campaignMode.CampaignMetadata.GetValue(Identifier);
object? metadata2 = campaignMode.CampaignMetadata.GetValue(value.ToIdentifier());
if (metadata1 == null || metadata2 == null)
{
return Operator switch
{
PropertyConditional.ComparisonOperatorType.Equals => metadata1 == metadata2,
PropertyConditional.ComparisonOperatorType.NotEquals => metadata1 != metadata2,
_ => false
};
}
if (!ForceString)
{
switch (metadata1)
{
case bool bool1 when metadata2 is bool bool2:
return CompareBool(bool1, bool2) ?? false;
case float float1 when metadata2 is float float2:
return PropertyConditional.CompareFloat(float1, float2, Operator);
}
}
if (metadata1 is string string1 && metadata2 is string string2)
{
return CompareString(string1, string2) ?? false;
}
return false;
}
if (!ForceString)
{
bool? tryBoolean = TryBoolean(campaignMode, value);
if (tryBoolean != null) { return tryBoolean; }
bool? tryFloat = TryFloat(campaignMode, value);
if (tryFloat != null) { return tryFloat; }
}
bool? tryString = TryString(campaignMode, value);
if (tryString != null) { return tryString; }
return false;
}
private bool? TryBoolean(CampaignMode campaignMode, string value)
{
if (bool.TryParse(value, out bool b))
{
return CompareBool(GetBool(campaignMode), b);
}
DebugConsole.Log($"{value} != bool");
return null;
}
private bool? CompareBool(bool val1, bool val2)
{
value1 = val1;
value2 = val2;
switch (Operator)
{
case PropertyConditional.ComparisonOperatorType.Equals:
return val1 == val2;
case PropertyConditional.ComparisonOperatorType.NotEquals:
return val1 != val2;
default:
DebugConsole.Log($"Only \"Equals\" and \"Not equals\" operators are allowed for a boolean (was {Operator} for {val2}).");
return false;
}
}
private bool? TryFloat(CampaignMode campaignMode, string value)
{
if (float.TryParse(value, out float f))
{
return PropertyConditional.CompareFloat(GetFloat(campaignMode), f, Operator);
}
DebugConsole.Log($"{value} != float");
return null;
}
private bool? TryString(CampaignMode campaignMode, string value)
{
return CompareString(GetString(campaignMode), value);
}
private bool? CompareString(string val1, string val2)
{
value1 = val1;
value2 = val2;
bool equals = string.Equals(val1, val2, StringComparison.OrdinalIgnoreCase);
switch (Operator)
{
case PropertyConditional.ComparisonOperatorType.Equals:
return equals;
case PropertyConditional.ComparisonOperatorType.NotEquals:
return !equals;
default:
DebugConsole.Log($"Only \"Equals\" and \"Not equals\" operators are allowed for a string (was {Operator} for {val2}).");
return null;
}
}
protected virtual bool GetBool(CampaignMode campaignMode)
{
return campaignMode.CampaignMetadata.GetBoolean(Identifier);
}
protected virtual float GetFloat(CampaignMode campaignMode)
{
return campaignMode.CampaignMetadata.GetFloat(Identifier);
}
private string GetString(CampaignMode campaignMode)
{
return campaignMode.CampaignMetadata.GetString(Identifier);
}
public override string ToDebugString()
{
string condition = "?";
if (value2 != null && value1 != null)
{
condition = $"{value1.ColorizeObject()} {Operator.ColorizeObject()} {value2.ColorizeObject()}";
}
else if (!Identifier.IsEmpty)
{
condition = $"{Identifier} {Condition}".ColorizeObject();
}
return $"{ToolBox.GetDebugSymbol(succeeded.HasValue)} {nameof(CheckDataAction)} -> (Data: {Identifier.ColorizeObject()}, Success: {succeeded.ColorizeObject()}, Expression: {condition})";
}
}
}