Unstable v0.1300.0.0 (February 19th 2021)
This commit is contained in:
@@ -56,7 +56,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (this.type != type || !HasRequiredItems(entity)) { return; }
|
||||
if (!Stackable && DelayList.Any(d => d.Parent == this && d.Targets.FirstOrDefault() == target)) { return; }
|
||||
if (targetIdentifiers != null && !IsValidTarget(target)) { return; }
|
||||
if (!IsValidTarget(target)) { return; }
|
||||
if (!HasRequiredConditions(target.ToEnumerable())) { return; }
|
||||
|
||||
switch (delayType)
|
||||
@@ -87,16 +87,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (this.type != type || !HasRequiredItems(entity)) { return; }
|
||||
if (!Stackable && DelayList.Any(d => d.Parent == this && d.Targets.SequenceEqual(targets))) { return; }
|
||||
if (delayType == DelayTypes.ReachCursor && Character.Controlled == null) return;
|
||||
if (delayType == DelayTypes.ReachCursor && Character.Controlled == null) { return; }
|
||||
|
||||
currentTargets.Clear();
|
||||
foreach (ISerializableEntity target in targets)
|
||||
{
|
||||
if (targetIdentifiers != null)
|
||||
{
|
||||
//ignore invalid targets
|
||||
if (!IsValidTarget(target)) { continue; }
|
||||
}
|
||||
if (!IsValidTarget(target)) { continue; }
|
||||
currentTargets.Add(target);
|
||||
}
|
||||
|
||||
@@ -148,7 +144,7 @@ namespace Barotrauma
|
||||
if (element.Delay > 0.0f) { continue; }
|
||||
break;
|
||||
case DelayTypes.ReachCursor:
|
||||
if (Vector2.Distance(element.Entity.WorldPosition, element.StartPosition.Value) < element.Delay) continue;
|
||||
if (Vector2.Distance(element.Entity.WorldPosition, element.StartPosition.Value) < element.Delay) { continue; }
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Barotrauma
|
||||
// - Use XElement instead of XAttribute in the constructor
|
||||
// - Simplify, remove unnecessary conversions
|
||||
// - Improve the flow so that the logic is undestandable.
|
||||
// - Maybe ass some test cases for the operators?
|
||||
// - Maybe add some test cases for the operators?
|
||||
class PropertyConditional
|
||||
{
|
||||
public enum ConditionType
|
||||
@@ -18,6 +18,7 @@ namespace Barotrauma
|
||||
PropertyValue,
|
||||
Name,
|
||||
SpeciesName,
|
||||
SpeciesGroup,
|
||||
HasTag,
|
||||
HasStatusTag,
|
||||
Affliction,
|
||||
@@ -46,6 +47,7 @@ namespace Barotrauma
|
||||
public readonly OperatorType Operator;
|
||||
public readonly string AttributeName;
|
||||
public readonly string AttributeValue;
|
||||
public readonly string[] SplitAttributeValue;
|
||||
public readonly float? FloatValue;
|
||||
|
||||
public readonly string TargetItemComponentName;
|
||||
@@ -55,8 +57,8 @@ namespace Barotrauma
|
||||
|
||||
// Only used by conditionals targeting an item (makes the conditional check the item/character whose inventory this item is inside)
|
||||
public readonly bool TargetContainer;
|
||||
|
||||
private readonly int cancelStatusEffect;
|
||||
// Only used by conditionals targeting an item. By default, containers check the parent item. This allows you to check the grandparent instead.
|
||||
public readonly bool TargetGrandParent;
|
||||
|
||||
// Remove this after refactoring
|
||||
public static bool IsValid(XAttribute attribute)
|
||||
@@ -109,20 +111,7 @@ namespace Barotrauma
|
||||
TargetItemComponentName = attribute.Parent.GetAttributeString("targetitemcomponent", "");
|
||||
TargetContainer = attribute.Parent.GetAttributeBool("targetcontainer", false);
|
||||
TargetSelf = attribute.Parent.GetAttributeBool("targetself", false);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
TargetGrandParent = attribute.Parent.GetAttributeBool("targetgrandparent", false);
|
||||
|
||||
if (!Enum.TryParse(AttributeName, true, out Type))
|
||||
{
|
||||
@@ -137,6 +126,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
AttributeValue = valueString;
|
||||
SplitAttributeValue = valueString.Split(',');
|
||||
if (float.TryParse(AttributeValue, NumberStyles.Float, CultureInfo.InvariantCulture, out float value))
|
||||
{
|
||||
FloatValue = value;
|
||||
@@ -180,8 +170,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public bool Matches(ISerializableEntity target)
|
||||
{
|
||||
string valStr = AttributeValue.ToString();
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case ConditionType.PropertyValue:
|
||||
@@ -194,13 +183,12 @@ namespace Barotrauma
|
||||
return false;
|
||||
case ConditionType.Name:
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
return (Operator == OperatorType.Equals) == (target.Name == valStr);
|
||||
return (Operator == OperatorType.Equals) == (target.Name == AttributeValue);
|
||||
case ConditionType.HasTag:
|
||||
{
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
string[] readTags = valStr.Split(',');
|
||||
int matches = 0;
|
||||
foreach (string tag in readTags)
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
{
|
||||
if (target is Item item && item.HasTag(tag))
|
||||
{
|
||||
@@ -208,58 +196,38 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
//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;
|
||||
return Operator == OperatorType.Equals ? matches >= SplitAttributeValue.Length : matches <= 0;
|
||||
}
|
||||
case ConditionType.HasStatusTag:
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
bool success = false;
|
||||
if (StatusEffect.DurationList.Any(d => d.Targets.Contains(target)) || DelayedEffect.DelayList.Any(d => d.Targets.Contains(target)))
|
||||
{
|
||||
string[] readTags = valStr.Split(',');
|
||||
foreach (DurationListElement duration in StatusEffect.DurationList)
|
||||
int matches = 0;
|
||||
foreach (DurationListElement durationEffect in StatusEffect.DurationList)
|
||||
{
|
||||
if (!duration.Targets.Contains(target)) { continue; }
|
||||
int matches = 0;
|
||||
foreach (string tag in readTags)
|
||||
if (!durationEffect.Targets.Contains(target)) { continue; }
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
{
|
||||
if (duration.Parent.HasTag(tag))
|
||||
if (durationEffect.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;
|
||||
}
|
||||
success = Operator == OperatorType.Equals ? matches >= SplitAttributeValue.Length : matches <= 0;
|
||||
}
|
||||
foreach (DelayedListElement delay in DelayedEffect.DelayList)
|
||||
foreach (DelayedListElement delayedEffect in DelayedEffect.DelayList)
|
||||
{
|
||||
if (!delay.Targets.Contains(target)) { continue; }
|
||||
int matches = 0;
|
||||
foreach (string tag in readTags)
|
||||
if (!delayedEffect.Targets.Contains(target)) { continue; }
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
{
|
||||
if (delay.Parent.HasTag(tag))
|
||||
if (delayedEffect.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 Operator == OperatorType.Equals ? matches >= SplitAttributeValue.Length : matches <= 0;
|
||||
}
|
||||
else if (Operator == OperatorType.NotEquals)
|
||||
{
|
||||
@@ -268,11 +236,19 @@ namespace Barotrauma
|
||||
}
|
||||
return success;
|
||||
case ConditionType.SpeciesName:
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
if (!(target is Character targetCharacter)) { return false; }
|
||||
return (Operator == OperatorType.Equals) == targetCharacter.SpeciesName.Equals(valStr, StringComparison.OrdinalIgnoreCase);
|
||||
{
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
if (!(target is Character targetCharacter)) { return false; }
|
||||
return Operator == OperatorType.Equals == targetCharacter.SpeciesName.Equals(AttributeValue, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
case ConditionType.SpeciesGroup:
|
||||
{
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
if (!(target is Character targetCharacter)) { return false; }
|
||||
return Operator == OperatorType.Equals == targetCharacter.Params.CompareGroup(AttributeValue);
|
||||
}
|
||||
case ConditionType.EntityType:
|
||||
switch (valStr)
|
||||
switch (AttributeValue)
|
||||
{
|
||||
case "character":
|
||||
case "Character":
|
||||
@@ -299,7 +275,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
return limb.type.ToString().Equals(valStr, StringComparison.OrdinalIgnoreCase);
|
||||
return limb.type.ToString().Equals(AttributeValue, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
case ConditionType.Affliction:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -52,7 +53,8 @@ namespace Barotrauma
|
||||
UseTarget = 64,
|
||||
Hull = 128,
|
||||
Limb = 256,
|
||||
AllLimbs = 512
|
||||
AllLimbs = 512,
|
||||
LastLimb = 1024
|
||||
}
|
||||
|
||||
class ItemSpawnInfo
|
||||
@@ -197,11 +199,15 @@ namespace Barotrauma
|
||||
|
||||
public readonly ActionType type = ActionType.OnActive;
|
||||
|
||||
private readonly List<Explosion> explosions;
|
||||
public readonly List<Explosion> Explosions;
|
||||
|
||||
private readonly List<ItemSpawnInfo> spawnItems;
|
||||
private readonly List<CharacterSpawnInfo> spawnCharacters;
|
||||
|
||||
private readonly List<EventPrefab> triggeredEvents;
|
||||
private readonly string triggeredEventTargetTag = "statuseffecttarget",
|
||||
triggeredEventEntityTag = "statuseffectentity";
|
||||
|
||||
private Character user;
|
||||
|
||||
public readonly float FireSize;
|
||||
@@ -212,6 +218,9 @@ namespace Barotrauma
|
||||
|
||||
public PhysicsBody sourceBody;
|
||||
|
||||
public readonly bool OnlyInside;
|
||||
public readonly bool OnlyOutside;
|
||||
|
||||
public HashSet<string> TargetIdentifiers
|
||||
{
|
||||
get { return targetIdentifiers; }
|
||||
@@ -228,7 +237,9 @@ namespace Barotrauma
|
||||
get { return spawnCharacters; }
|
||||
}
|
||||
|
||||
private readonly List<Pair<string, float>> reduceAffliction;
|
||||
public readonly List<Pair<string, float>> ReduceAffliction;
|
||||
|
||||
public float Duration => duration;
|
||||
|
||||
//only applicable if targeting NearbyCharacters or NearbyItems
|
||||
public float Range
|
||||
@@ -272,9 +283,12 @@ namespace Barotrauma
|
||||
spawnItems = new List<ItemSpawnInfo>();
|
||||
spawnCharacters = new List<CharacterSpawnInfo>();
|
||||
Afflictions = new List<Affliction>();
|
||||
explosions = new List<Explosion>();
|
||||
reduceAffliction = new List<Pair<string, float>>();
|
||||
Explosions = new List<Explosion>();
|
||||
triggeredEvents = new List<EventPrefab>();
|
||||
ReduceAffliction = new List<Pair<string, float>>();
|
||||
tags = new HashSet<string>(element.GetAttributeString("tags", "").Split(','));
|
||||
OnlyInside = element.GetAttributeBool("onlyinside", false);
|
||||
OnlyOutside = element.GetAttributeBool("onlyoutside", false);
|
||||
|
||||
Range = element.GetAttributeFloat("range", 0.0f);
|
||||
Offset = element.GetAttributeVector2("offset", Vector2.Zero);
|
||||
@@ -284,7 +298,7 @@ namespace Barotrauma
|
||||
List<LimbType> targetLimbs = new List<LimbType>();
|
||||
foreach (string targetLimbName in targetLimbNames)
|
||||
{
|
||||
if (Enum.TryParse(targetLimbName, out LimbType targetLimb)) { targetLimbs.Add(targetLimb); }
|
||||
if (Enum.TryParse(targetLimbName, ignoreCase: true, out LimbType targetLimb)) { targetLimbs.Add(targetLimb); }
|
||||
}
|
||||
if (targetLimbs.Count > 0) { this.targetLimbs = targetLimbs.ToArray(); }
|
||||
}
|
||||
@@ -310,7 +324,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (XAttribute attribute in attributes)
|
||||
{
|
||||
switch (attribute.Name.ToString())
|
||||
switch (attribute.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "type":
|
||||
if (!Enum.TryParse(attribute.Value, true, out type))
|
||||
@@ -352,6 +366,12 @@ namespace Barotrauma
|
||||
lifeTime = attribute.GetAttributeFloat(0);
|
||||
lifeTimer = lifeTime;
|
||||
break;
|
||||
case "eventtargettag":
|
||||
triggeredEventTargetTag = attribute.Value;
|
||||
break;
|
||||
case "evententitytag":
|
||||
triggeredEventEntityTag = attribute.Value;
|
||||
break;
|
||||
case "checkconditionalalways":
|
||||
CheckConditionalAlways = attribute.GetAttributeBool(false);
|
||||
break;
|
||||
@@ -402,7 +422,7 @@ namespace Barotrauma
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "explosion":
|
||||
explosions.Add(new Explosion(subElement, parentDebugName));
|
||||
Explosions.Add(new Explosion(subElement, parentDebugName));
|
||||
break;
|
||||
case "fire":
|
||||
FireSize = subElement.GetAttributeFloat("size", 10.0f);
|
||||
@@ -477,7 +497,7 @@ namespace Barotrauma
|
||||
if (subElement.Attribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in StatusEffect (" + parentDebugName + ") - define afflictions using identifiers or types instead of names.");
|
||||
reduceAffliction.Add(new Pair<string, float>(
|
||||
ReduceAffliction.Add(new Pair<string, float>(
|
||||
subElement.GetAttributeString("name", "").ToLowerInvariant(),
|
||||
subElement.GetAttributeFloat(1.0f, "amount", "strength", "reduceamount")));
|
||||
}
|
||||
@@ -488,7 +508,7 @@ namespace Barotrauma
|
||||
|
||||
if (AfflictionPrefab.List.Any(ap => ap.Identifier == name || ap.AfflictionType == name))
|
||||
{
|
||||
reduceAffliction.Add(new Pair<string, float>(
|
||||
ReduceAffliction.Add(new Pair<string, float>(
|
||||
name,
|
||||
subElement.GetAttributeFloat(1.0f, "amount", "strength", "reduceamount")));
|
||||
}
|
||||
@@ -502,6 +522,23 @@ namespace Barotrauma
|
||||
var newSpawnItem = new ItemSpawnInfo(subElement, parentDebugName);
|
||||
if (newSpawnItem.ItemPrefab != null) { spawnItems.Add(newSpawnItem); }
|
||||
break;
|
||||
case "triggerevent":
|
||||
string identifier = subElement.GetAttributeString("identifier", null);
|
||||
if (!string.IsNullOrWhiteSpace(identifier))
|
||||
{
|
||||
EventPrefab prefab = EventSet.GetEventPrefab(identifier);
|
||||
if (prefab != null)
|
||||
{
|
||||
triggeredEvents.Add(prefab);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (XElement eventElement in subElement.Elements())
|
||||
{
|
||||
if (!eventElement.Name.ToString().Equals("ScriptedEvent", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
triggeredEvents.Add(new EventPrefab(eventElement));
|
||||
}
|
||||
break;
|
||||
case "spawncharacter":
|
||||
var newSpawnCharacter = new CharacterSpawnInfo(subElement, parentDebugName);
|
||||
if (!string.IsNullOrWhiteSpace(newSpawnCharacter.SpeciesName)) { spawnCharacters.Add(newSpawnCharacter); }
|
||||
@@ -555,8 +592,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (!c.Enabled || c.Removed || !IsValidTarget(c)) { continue; }
|
||||
if (CheckDistance(c))
|
||||
if (c.Enabled && !c.Removed && CheckDistance(c) && IsValidTarget(c))
|
||||
{
|
||||
targets.Add(c);
|
||||
}
|
||||
@@ -564,12 +600,27 @@ namespace Barotrauma
|
||||
}
|
||||
if (HasTargetType(TargetType.NearbyItems))
|
||||
{
|
||||
foreach (Item item in Item.ItemList)
|
||||
//optimization for powered components that can be easily fetched from Powered.PoweredList
|
||||
if (targetIdentifiers.Count == 1 &&
|
||||
(targetIdentifiers.Contains("powered") || targetIdentifiers.Contains("junctionbox") || targetIdentifiers.Contains("relaycomponent")))
|
||||
{
|
||||
if (item.Removed || !IsValidTarget(item)) { continue; }
|
||||
if (CheckDistance(item))
|
||||
foreach (Powered powered in Powered.PoweredList)
|
||||
{
|
||||
targets.AddRange(item.AllPropertyObjects);
|
||||
Item item = powered.Item;
|
||||
if (!item.Removed && CheckDistance(item) && IsValidTarget(item))
|
||||
{
|
||||
targets.AddRange(item.AllPropertyObjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (!item.Removed && CheckDistance(item) && IsValidTarget(item))
|
||||
{
|
||||
targets.AddRange(item.AllPropertyObjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -590,25 +641,30 @@ namespace Barotrauma
|
||||
|
||||
public bool HasRequiredConditions(IEnumerable<ISerializableEntity> targets)
|
||||
{
|
||||
return HasRequiredConditions(targets, targetingContainer: false);
|
||||
return HasRequiredConditions(targets, propertyConditionals);
|
||||
}
|
||||
|
||||
private bool HasRequiredConditions(IEnumerable<ISerializableEntity> targets, bool targetingContainer)
|
||||
private bool HasRequiredConditions(IEnumerable<ISerializableEntity> targets, IEnumerable<PropertyConditional> conditionals, bool targetingContainer = false)
|
||||
{
|
||||
if (!propertyConditionals.Any()) { return true; }
|
||||
if (requiredItems.Any() && requiredItems.All(ri => ri.MatchOnEmpty) && !targets.Any()) { return true; }
|
||||
if (conditionals.None()) { return true; }
|
||||
if (requiredItems.Any() && requiredItems.All(ri => ri.MatchOnEmpty) && targets.None()) { return true; }
|
||||
switch (conditionalComparison)
|
||||
{
|
||||
case PropertyConditional.Comparison.Or:
|
||||
foreach (PropertyConditional pc in propertyConditionals)
|
||||
foreach (PropertyConditional pc in conditionals)
|
||||
{
|
||||
if (pc.TargetContainer && !targetingContainer)
|
||||
{
|
||||
var target = targets.FirstOrDefault(t => t is Item || t is ItemComponent);
|
||||
var targetItem = target as Item ?? (target as ItemComponent)?.Item;
|
||||
if (targetItem?.ParentInventory == null) { continue; }
|
||||
if (targetItem.ParentInventory.Owner is Item container && HasRequiredConditions(container.AllPropertyObjects, targetingContainer: true)) { return true; }
|
||||
if (targetItem.ParentInventory.Owner is Character character && HasRequiredConditions(character.ToEnumerable(), targetingContainer: true)) { return true; }
|
||||
var owner = targetItem.ParentInventory.Owner;
|
||||
if (pc.TargetGrandParent && owner is Item ownerItem)
|
||||
{
|
||||
owner = ownerItem.ParentInventory?.Owner;
|
||||
}
|
||||
if (owner is Item container && HasRequiredConditions(container.AllPropertyObjects, pc.ToEnumerable(), targetingContainer: true)) { return true; }
|
||||
if (owner is Character character && HasRequiredConditions(character.ToEnumerable(), pc.ToEnumerable(), targetingContainer: true)) { return true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -627,15 +683,20 @@ namespace Barotrauma
|
||||
}
|
||||
return false;
|
||||
case PropertyConditional.Comparison.And:
|
||||
foreach (PropertyConditional pc in propertyConditionals)
|
||||
foreach (PropertyConditional pc in conditionals)
|
||||
{
|
||||
if (pc.TargetContainer && !targetingContainer)
|
||||
{
|
||||
var target = targets.FirstOrDefault(t => t is Item || t is ItemComponent);
|
||||
var targetItem = target as Item ?? (target as ItemComponent)?.Item;
|
||||
if (targetItem?.ParentInventory == null) { return false; }
|
||||
if (targetItem.ParentInventory.Owner is Item container && !HasRequiredConditions(container.AllPropertyObjects, targetingContainer: true)) { return false; }
|
||||
if (targetItem.ParentInventory.Owner is Character character && !HasRequiredConditions(character.ToEnumerable(), targetingContainer: true)) { return false; }
|
||||
var owner = targetItem.ParentInventory.Owner;
|
||||
if (pc.TargetGrandParent && owner is Item ownerItem)
|
||||
{
|
||||
owner = ownerItem.ParentInventory?.Owner;
|
||||
}
|
||||
if (owner is Item container && !HasRequiredConditions(container.AllPropertyObjects, pc.ToEnumerable(), targetingContainer: true)) { return false; }
|
||||
if (owner is Character character && !HasRequiredConditions(character.ToEnumerable(), pc.ToEnumerable(), targetingContainer: true)) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -648,8 +709,8 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!pc.Matches(target)) { return false; }
|
||||
}
|
||||
if (targets.None(t => pc.Matches(t))) { return false; }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -660,34 +721,57 @@ namespace Barotrauma
|
||||
|
||||
protected bool IsValidTarget(ISerializableEntity entity)
|
||||
{
|
||||
if (targetIdentifiers == null) { return true; }
|
||||
|
||||
if (entity is Item item)
|
||||
{
|
||||
if (targetIdentifiers.Contains("item")) { return true; }
|
||||
if (item.HasTag(targetIdentifiers)) { return true; }
|
||||
if (targetIdentifiers.Any(id => id.Equals(item.Prefab.Identifier, StringComparison.OrdinalIgnoreCase))) { return true; }
|
||||
return IsValidTarget(item);
|
||||
}
|
||||
else if (entity is ItemComponent itemComponent)
|
||||
{
|
||||
if (targetIdentifiers.Contains("itemcomponent")) { return true; }
|
||||
if (itemComponent.Item.HasTag(targetIdentifiers)) { return true; }
|
||||
if (targetIdentifiers.Any(id => id.Equals(itemComponent.Item.Prefab.Identifier, StringComparison.OrdinalIgnoreCase))) { return true; }
|
||||
return IsValidTarget(itemComponent);
|
||||
}
|
||||
else if (entity is Structure structure)
|
||||
{
|
||||
if (targetIdentifiers == null) { return true; }
|
||||
if (targetIdentifiers.Contains("structure")) { return true; }
|
||||
if (targetIdentifiers.Any(id => id.Equals(structure.Prefab.Identifier, StringComparison.OrdinalIgnoreCase))) { return true; }
|
||||
}
|
||||
else if (entity is Character character)
|
||||
{
|
||||
if (targetIdentifiers.Contains("character")) { return true; }
|
||||
if (targetIdentifiers.Any(id => id.Equals(character.SpeciesName, StringComparison.OrdinalIgnoreCase))) { return true; }
|
||||
return IsValidTarget(character);
|
||||
}
|
||||
|
||||
if (targetIdentifiers == null) { return true; }
|
||||
return targetIdentifiers.Any(id => id.Equals(entity.Name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
protected bool IsValidTarget(ItemComponent itemComponent)
|
||||
{
|
||||
if (OnlyInside && itemComponent.Item.CurrentHull == null) { return false; }
|
||||
if (OnlyOutside && itemComponent.Item.CurrentHull != null) { return false; }
|
||||
if (targetIdentifiers == null) { return true; }
|
||||
if (targetIdentifiers.Contains("itemcomponent")) { return true; }
|
||||
if (itemComponent.Item.HasTag(targetIdentifiers)) { return true; }
|
||||
return targetIdentifiers.Any(id => id.Equals(itemComponent.Item.Prefab.Identifier, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
protected bool IsValidTarget(Item item)
|
||||
{
|
||||
if (OnlyInside && item.CurrentHull == null) { return false; }
|
||||
if (OnlyOutside && item.CurrentHull != null) { return false; }
|
||||
if (targetIdentifiers == null) { return true; }
|
||||
if (targetIdentifiers.Contains("item")) { return true; }
|
||||
if (item.HasTag(targetIdentifiers)) { return true; }
|
||||
return targetIdentifiers.Any(id => id.Equals(item.Prefab.Identifier, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
protected bool IsValidTarget(Character character)
|
||||
{
|
||||
if (OnlyInside && character.CurrentHull == null) { return false; }
|
||||
if (OnlyOutside && character.CurrentHull != null) { return false; }
|
||||
if (targetIdentifiers == null) { return true; }
|
||||
if (targetIdentifiers.Contains("character")) { return true; }
|
||||
return targetIdentifiers.Any(id => id.Equals(character.SpeciesName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public void SetUser(Character user)
|
||||
{
|
||||
this.user = user;
|
||||
@@ -701,7 +785,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (this.type != type || !HasRequiredItems(entity)) { return; }
|
||||
|
||||
if (targetIdentifiers != null && !IsValidTarget(target)) { return; }
|
||||
if (!IsValidTarget(target)) { return; }
|
||||
|
||||
if (duration > 0.0f && !Stackable)
|
||||
{
|
||||
@@ -726,11 +810,7 @@ namespace Barotrauma
|
||||
currentTargets.Clear();
|
||||
foreach (ISerializableEntity target in targets)
|
||||
{
|
||||
if (targetIdentifiers != null)
|
||||
{
|
||||
//ignore invalid targets
|
||||
if (!IsValidTarget(target)) { continue; }
|
||||
}
|
||||
if (!IsValidTarget(target)) { continue; }
|
||||
currentTargets.Add(target);
|
||||
}
|
||||
|
||||
@@ -781,9 +861,9 @@ namespace Barotrauma
|
||||
Vector2 position = worldPosition ?? (entity == null || entity.Removed ? Vector2.Zero : entity.WorldPosition);
|
||||
if (worldPosition == null)
|
||||
{
|
||||
if (entity is Character c && targetLimbs?.FirstOrDefault(l => l != LimbType.None) is LimbType l)
|
||||
if (entity is Character character && !character.Removed && targetLimbs?.FirstOrDefault(l => l != LimbType.None) is LimbType limbType)
|
||||
{
|
||||
Limb limb = c.AnimController.GetLimb(l);
|
||||
Limb limb = character.AnimController.GetLimb(limbType);
|
||||
if (limb != null && !limb.Removed)
|
||||
{
|
||||
position = limb.WorldPosition;
|
||||
@@ -791,8 +871,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetLimb = targets.FirstOrDefault(t => t is Limb) as Limb;
|
||||
if (targetLimb != null && !targetLimb.Removed)
|
||||
if (targets.FirstOrDefault(t => t is Limb) is Limb targetLimb && !targetLimb.Removed)
|
||||
{
|
||||
position = targetLimb.WorldPosition;
|
||||
}
|
||||
@@ -884,9 +963,9 @@ namespace Barotrauma
|
||||
{
|
||||
if (targetEntity.Removed) { continue; }
|
||||
}
|
||||
|
||||
if (target is Limb limb)
|
||||
else if (target is Limb limb)
|
||||
{
|
||||
if (limb.Removed) { continue; }
|
||||
position = limb.WorldPosition + Offset;
|
||||
}
|
||||
|
||||
@@ -901,13 +980,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Explosion explosion in explosions)
|
||||
foreach (Explosion explosion in Explosions)
|
||||
{
|
||||
explosion.Explode(position, damageSource: entity, attacker: user);
|
||||
}
|
||||
|
||||
foreach (ISerializableEntity target in targets)
|
||||
{
|
||||
//if the effect has a duration, these will be done in the UpdateAll method
|
||||
if (duration > 0) { break; }
|
||||
if (target == null) { continue; }
|
||||
foreach (Affliction affliction in Afflictions)
|
||||
{
|
||||
@@ -942,7 +1023,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Pair<string, float> reduceAffliction in reduceAffliction)
|
||||
foreach (Pair<string, float> reduceAffliction in ReduceAffliction)
|
||||
{
|
||||
float reduceAmount = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime;
|
||||
Limb targetLimb = null;
|
||||
@@ -981,6 +1062,34 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
bool isNotClient = GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient;
|
||||
if (isNotClient && GameMain.GameSession?.EventManager is { } eventManager)
|
||||
{
|
||||
foreach (EventPrefab eventPrefab in triggeredEvents)
|
||||
{
|
||||
Event ev = eventPrefab.CreateInstance();
|
||||
if (ev == null) { continue; }
|
||||
eventManager.QueuedEvents.Enqueue(ev);
|
||||
|
||||
if (ev is ScriptedEvent scriptedEvent)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(triggeredEventTargetTag))
|
||||
{
|
||||
List<Entity> eventTargets = targets.Where(t => t is Entity).Cast<Entity>().ToList();
|
||||
|
||||
if (eventTargets.Any())
|
||||
{
|
||||
scriptedEvent.Targets.Add(triggeredEventTargetTag, eventTargets);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(triggeredEventEntityTag) && entity != null)
|
||||
{
|
||||
scriptedEvent.Targets.Add(triggeredEventEntityTag, new List<Entity> { entity });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotClient && entity != null && Entity.Spawner != null) //clients are not allowed to spawn entities
|
||||
{
|
||||
foreach (CharacterSpawnInfo characterSpawnInfo in spawnCharacters)
|
||||
@@ -1042,11 +1151,11 @@ namespace Barotrauma
|
||||
case ItemSpawnInfo.SpawnRotationType.MainLimb:
|
||||
rotation = user.AnimController.MainLimb.body.TransformedRotation;
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
throw new NotImplementedException("Not implemented: " + itemSpawnInfo.RotationType);
|
||||
}
|
||||
rotation += MathHelper.ToRadians(itemSpawnInfo.Rotation * user.AnimController.Dir);
|
||||
projectile.Shoot(user, sourceBody.SimPosition, sourceBody.SimPosition, rotation + spread, ignoredBodies: user.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: true);
|
||||
projectile.Shoot(user, ConvertUnits.ToSimUnits(worldPos), ConvertUnits.ToSimUnits(worldPos), rotation + spread, ignoredBodies: user.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1057,25 +1166,18 @@ namespace Barotrauma
|
||||
break;
|
||||
case ItemSpawnInfo.SpawnPositionType.ThisInventory:
|
||||
{
|
||||
Inventory inventory = null;
|
||||
if (entity is Character character && character.Inventory != null)
|
||||
{
|
||||
int emptyCount = character.Inventory.Items.Count(it => it == null);
|
||||
if (emptyCount - Entity.Spawner.CountSpawnQueue(spawnInfo => spawnInfo is EntitySpawner.ItemSpawnInfo itemSpawnInfo && itemSpawnInfo.Inventory == character.Inventory) > 0)
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, character.Inventory);
|
||||
}
|
||||
inventory = character.Inventory;
|
||||
}
|
||||
else if (entity is Item item)
|
||||
{
|
||||
var inventory = item?.GetComponent<ItemContainer>()?.Inventory;
|
||||
if (inventory != null)
|
||||
{
|
||||
int emptyCount = inventory.Items.Count(it => it == null);
|
||||
if (emptyCount - Entity.Spawner.CountSpawnQueue(spawnInfo => spawnInfo is EntitySpawner.ItemSpawnInfo itemSpawnInfo && itemSpawnInfo.Inventory == inventory) > 0)
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, inventory);
|
||||
}
|
||||
}
|
||||
inventory = item?.GetComponent<ItemContainer>()?.Inventory;
|
||||
}
|
||||
if (inventory != null && inventory.CanBePut(itemSpawnInfo.ItemPrefab))
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, inventory, spawnIfInventoryFull: false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1092,12 +1194,13 @@ namespace Barotrauma
|
||||
}
|
||||
if (thisInventory != null)
|
||||
{
|
||||
foreach (Item item in thisInventory.Items)
|
||||
foreach (Item item in thisInventory.AllItems)
|
||||
{
|
||||
if (item == null) continue;
|
||||
Inventory containedInventory = item.GetComponent<ItemContainer>()?.Inventory;
|
||||
if (containedInventory == null || !containedInventory.Items.Any(i => i == null)) continue;
|
||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, containedInventory);
|
||||
if (containedInventory != null && containedInventory.CanBePut(itemSpawnInfo.ItemPrefab))
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, containedInventory, spawnIfInventoryFull: false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1204,7 +1307,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Pair<string, float> reduceAffliction in element.Parent.reduceAffliction)
|
||||
foreach (Pair<string, float> reduceAffliction in element.Parent.ReduceAffliction)
|
||||
{
|
||||
Limb targetLimb = null;
|
||||
Character targetCharacter = null;
|
||||
|
||||
Reference in New Issue
Block a user