diff --git a/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml b/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml index 8e1510ba5..029b6f86d 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Medical/medical.xml @@ -380,8 +380,9 @@ - - + + + diff --git a/Barotrauma/BarotraumaShared/Source/StatusEffects/PropertyConditional.cs b/Barotrauma/BarotraumaShared/Source/StatusEffects/PropertyConditional.cs index e910950f9..d8884abd7 100644 --- a/Barotrauma/BarotraumaShared/Source/StatusEffects/PropertyConditional.cs +++ b/Barotrauma/BarotraumaShared/Source/StatusEffects/PropertyConditional.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.Xml.Linq; @@ -30,6 +31,8 @@ namespace Barotrauma public readonly OperatorType Operator; public readonly string Value; + private readonly int cancelStatusEffect; + public PropertyConditional(XAttribute attribute) { string attributeString = attribute.Value.ToString(); @@ -81,12 +84,25 @@ namespace Barotrauma default: if (op != "==" && op != "!=" && op != ">" && op != "<" && op != ">=" && op != "<=") //Didn't use escape strings or anything { - atStr = attributeString; //We probably don't even have an operator - DebugConsole.ThrowError("Error in property conditional - \"" + op + "\" is not a valid operator."); + atStr = attributeString; //We probably don't even have an operator } break; } + foreach (XElement subElement in attribute.Parent.Elements()) + { + switch (subElement.Name.ToString().ToLowerInvariant()) + { + case "cancel": + case "canceleffect": + case "cancelstatuseffect": + //This only works if there's a conditional checking for status effect tags. There is no way to cancel *all* status effects atm. + cancelStatusEffect = 1; + if (subElement.GetAttributeBool("all", false)) cancelStatusEffect = 2; + break; + } + } + if (!Enum.TryParse(attribute.Name.ToString(), true, out Type)) { PropertyName = attribute.Name.ToString(); @@ -95,8 +111,75 @@ namespace Barotrauma Value = atStr; } + + public bool Matches(ISerializableEntity target) + { + string valStr = Value.ToString(); + + switch (Type) + { + case ConditionType.PropertyValue: + if (target.SerializableProperties.TryGetValue(PropertyName.ToLowerInvariant(), out SerializableProperty property)) + { + return Matches(property); + } + return false; + case ConditionType.Name: + return (Operator == OperatorType.Equals) == (target.Name == valStr); + case ConditionType.HasTag: + { + string[] readTags = valStr.Split(','); + int matches = 0; + foreach (string tag in readTags) + if (((Item)target).HasTag(tag)) matches++; + + //If operator is == then it needs to match everything, otherwise if its != there must be zero matches. + return Operator == OperatorType.Equals ? matches >= readTags.Length : matches <= 0; + } + case ConditionType.HasStatusTag: + List durations = StatusEffect.DurationList.FindAll(d => d.Targets.Contains(target)); + List delays = DelayedEffect.DelayList.FindAll(d => d.Targets.Contains(target)); + + bool success = false; + if (durations.Count > 0 || delays.Count > 0) + { + string[] readTags = valStr.Split(','); + foreach (DurationListElement duration in durations) + { + int matches = 0; + foreach (string tag in readTags) + if (duration.Parent.HasTag(tag)) matches++; + + success = Operator == OperatorType.Equals ? matches >= readTags.Length : matches <= 0; + if (cancelStatusEffect > 0 && success) + StatusEffect.DurationList.Remove(duration); + if (cancelStatusEffect != 2) //cancelStatusEffect 1 = only cancel once, cancelStatusEffect 2 = cancel all of matching tags + return success; + } + foreach (DelayedListElement delay in delays) + { + int matches = 0; + foreach (string tag in readTags) + if (delay.Parent.HasTag(tag)) matches++; + + success = Operator == OperatorType.Equals ? matches >= readTags.Length : matches <= 0; + if (cancelStatusEffect > 0 && success) + DelayedEffect.DelayList.Remove(delay); + if (cancelStatusEffect != 2) //ditto + return success; + } + } + return success; + case ConditionType.SpeciesName: + Character targetCharacter = target as Character; + if (targetCharacter == null) return false; + return (Operator == OperatorType.Equals) == (targetCharacter.SpeciesName == valStr); + default: + return false; + } + } - public bool Matches(SerializableProperty property) + private bool Matches(SerializableProperty property) { object propertyValue = property.GetValue(); diff --git a/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs index 291d343d3..48134bd76 100644 --- a/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs @@ -57,7 +57,6 @@ namespace Barotrauma public bool Stackable; //Can the same status effect be applied several times to the same targets? private readonly int useItemCount; - private readonly int cancelStatusEffect; public readonly ActionType type; @@ -212,12 +211,6 @@ namespace Barotrauma case "useitem": useItemCount++; break; - case "cancel": - case "cancelstatuseffect": - //This only works if there's a conditional checking for status effect tags. There is no way to cancel *all* status effects atm. - cancelStatusEffect = 1; - if (subElement.GetAttributeBool("all", false)) cancelStatusEffect = 2; - break; case "requireditem": case "requireditems": RelatedItem newRequiredItem = RelatedItem.Load(subElement); @@ -270,69 +263,10 @@ namespace Barotrauma if (!propertyConditionals.Any()) return true; foreach (ISerializableEntity target in targets) { + if (target == null || target.SerializableProperties == null) continue; foreach (PropertyConditional pc in propertyConditionals) - { - if (target == null || target.SerializableProperties == null) continue; - - string valStr = pc.Value.ToString(); - - switch (pc.Type) - { - case PropertyConditional.ConditionType.PropertyValue: - if (target.SerializableProperties.TryGetValue(pc.PropertyName.ToLowerInvariant(), out SerializableProperty property)) - { - return pc.Matches(property); - } - return false; - case PropertyConditional.ConditionType.Name: - return (pc.Operator == PropertyConditional.OperatorType.Equals) == (target.Name == valStr); - case PropertyConditional.ConditionType.HasTag: - { - string[] readTags = valStr.Split(','); - int matches = 0; - foreach (string tag in readTags) - if (((Item)target).HasTag(tag)) matches++; - - //If operator is == then it needs to match everything, otherwise if its != there must be zero matches. - return pc.Operator == PropertyConditional.OperatorType.Equals ? matches >= readTags.Length : matches <= 0; - } - case PropertyConditional.ConditionType.HasStatusTag: - List durations = DurationList.FindAll(d => d.Targets.Contains(target)); - List delays = DelayedEffect.DelayList.FindAll(d => d.Targets.Contains(target)); - - bool success = false; - if (durations.Any() || delays.Any()) - { - string[] readTags = valStr.Split(','); - foreach (DurationListElement duration in durations) - { - int matches = 0; - foreach (string tag in readTags) - if (duration.Parent.HasTag(tag)) matches++; - - success = pc.Operator == PropertyConditional.OperatorType.Equals ? matches >= readTags.Length : matches <= 0; - if (cancelStatusEffect > 0 && success) - DurationList.Remove(duration); - if (cancelStatusEffect != 2) //cancelStatusEffect 1 = only cancel once, cancelStatusEffect 2 = cancel all of matching tags - return success; - } - foreach (DelayedListElement delay in delays) - { - int matches = 0; - foreach (string tag in readTags) - if (delay.Parent.HasTag(tag)) matches++; - - success = pc.Operator == PropertyConditional.OperatorType.Equals ? matches >= readTags.Length : matches <= 0; - if (cancelStatusEffect > 0 && success) - DelayedEffect.DelayList.Remove(delay); - if (cancelStatusEffect != 2) //ditto - return success; - } - } - return success; - case PropertyConditional.ConditionType.SpeciesName: - return (pc.Operator == PropertyConditional.OperatorType.Equals) == (((Character)target).SpeciesName == valStr); - } + { + if (!pc.Matches(target)) return false; } } return true;