Unstable 0.16.0.0
This commit is contained in:
@@ -55,14 +55,23 @@ namespace Barotrauma
|
||||
public override void Apply(ActionType type, float deltaTime, Entity entity, ISerializableEntity target, Vector2? worldPosition = null)
|
||||
{
|
||||
if (this.type != type || !HasRequiredItems(entity)) { return; }
|
||||
if (!Stackable && DelayList.Any(d => d.Parent == this && d.Targets.FirstOrDefault() == target)) { return; }
|
||||
if (!Stackable)
|
||||
{
|
||||
foreach (var existingEffect in DelayList)
|
||||
{
|
||||
if (existingEffect.Parent == this && existingEffect.Targets.FirstOrDefault() == target) { return; }
|
||||
}
|
||||
}
|
||||
if (!IsValidTarget(target)) { return; }
|
||||
if (!HasRequiredConditions(target.ToEnumerable())) { return; }
|
||||
|
||||
currentTargets.Clear();
|
||||
currentTargets.Add(target);
|
||||
if (!HasRequiredConditions(currentTargets)) { return; }
|
||||
|
||||
switch (delayType)
|
||||
{
|
||||
case DelayTypes.Timer:
|
||||
DelayList.Add(new DelayedListElement(this, entity, target.ToEnumerable(), delay, worldPosition, null));
|
||||
DelayList.Add(new DelayedListElement(this, entity, currentTargets, delay, worldPosition, null));
|
||||
break;
|
||||
case DelayTypes.ReachCursor:
|
||||
Projectile projectile = (entity as Item)?.GetComponent<Projectile>();
|
||||
@@ -78,16 +87,22 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
DelayList.Add(new DelayedListElement(this, entity, target.ToEnumerable(), Vector2.Distance(entity.WorldPosition, projectile.User.CursorWorldPosition), worldPosition, entity.WorldPosition));
|
||||
DelayList.Add(new DelayedListElement(this, entity, currentTargets, Vector2.Distance(entity.WorldPosition, projectile.User.CursorWorldPosition), worldPosition, entity.WorldPosition));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Apply(ActionType type, float deltaTime, Entity entity, IEnumerable<ISerializableEntity> targets, Vector2? worldPosition = null)
|
||||
public override void Apply(ActionType type, float deltaTime, Entity entity, IReadOnlyList<ISerializableEntity> targets, Vector2? worldPosition = null)
|
||||
{
|
||||
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 (!Stackable)
|
||||
{
|
||||
foreach (var existingEffect in DelayList)
|
||||
{
|
||||
if (existingEffect.Parent == this && existingEffect.Targets.SequenceEqual(targets)) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
currentTargets.Clear();
|
||||
foreach (ISerializableEntity target in targets)
|
||||
|
||||
@@ -178,15 +178,28 @@ namespace Barotrauma
|
||||
{
|
||||
if (target is Item item)
|
||||
{
|
||||
return item.ContainedItems.Any(it => Matches(it));
|
||||
foreach (var containedItem in item.ContainedItems)
|
||||
{
|
||||
if (Matches(containedItem)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (target is Items.Components.ItemComponent ic)
|
||||
{
|
||||
return ic.Item.ContainedItems.Any(it => Matches(it));
|
||||
foreach (var containedItem in ic.Item.ContainedItems)
|
||||
{
|
||||
if (Matches(containedItem)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (target is Character character)
|
||||
{
|
||||
return character.Inventory != null && character.Inventory.AllItems.Any(it => Matches(it));
|
||||
if (character.Inventory == null) { return false; }
|
||||
foreach (var containedItem in character.Inventory.AllItems)
|
||||
{
|
||||
if (Matches(containedItem)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,56 +217,34 @@ namespace Barotrauma
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
return (Operator == OperatorType.Equals) == (target.Name == AttributeValue);
|
||||
case ConditionType.HasTag:
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
return MatchesTagCondition(target);
|
||||
case ConditionType.HasStatusTag:
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
int matches = 0;
|
||||
foreach (DurationListElement durationEffect in StatusEffect.DurationList)
|
||||
{
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
int matches = 0;
|
||||
if (!durationEffect.Targets.Contains(target)) { continue; }
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
{
|
||||
if (target is Item item && item.HasTag(tag))
|
||||
if (durationEffect.Parent.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 >= 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)))
|
||||
foreach (DelayedListElement delayedEffect in DelayedEffect.DelayList)
|
||||
{
|
||||
int matches = 0;
|
||||
foreach (DurationListElement durationEffect in StatusEffect.DurationList)
|
||||
if (!delayedEffect.Targets.Contains(target)) { continue; }
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
{
|
||||
if (!durationEffect.Targets.Contains(target)) { continue; }
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
if (delayedEffect.Parent.HasTag(tag))
|
||||
{
|
||||
if (durationEffect.Parent.HasTag(tag))
|
||||
{
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
success = Operator == OperatorType.Equals ? matches >= SplitAttributeValue.Length : matches <= 0;
|
||||
}
|
||||
foreach (DelayedListElement delayedEffect in DelayedEffect.DelayList)
|
||||
{
|
||||
if (!delayedEffect.Targets.Contains(target)) { continue; }
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
{
|
||||
if (delayedEffect.Parent.HasTag(tag))
|
||||
{
|
||||
matches++;
|
||||
}
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
return Operator == OperatorType.Equals ? matches >= SplitAttributeValue.Length : matches <= 0;
|
||||
}
|
||||
else if (Operator == OperatorType.NotEquals)
|
||||
{
|
||||
//no status effects, so the tags cannot be equal -> condition met
|
||||
return true;
|
||||
}
|
||||
return success;
|
||||
return Operator == OperatorType.Equals ? matches >= SplitAttributeValue.Length : matches <= 0;
|
||||
case ConditionType.SpeciesName:
|
||||
{
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
@@ -335,96 +326,87 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool MatchesTagCondition(ISerializableEntity target)
|
||||
{
|
||||
if (!(target is Item item)) { return false; }
|
||||
|
||||
int matches = 0;
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
{
|
||||
if (item.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 >= SplitAttributeValue.Length : matches <= 0;
|
||||
}
|
||||
|
||||
public bool MatchesTagCondition(string targetTag)
|
||||
{
|
||||
if (string.IsNullOrEmpty(targetTag) || Type != ConditionType.HasTag) { return false; }
|
||||
|
||||
int matches = 0;
|
||||
foreach (string tag in SplitAttributeValue)
|
||||
{
|
||||
if (targetTag.Equals(tag, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
//If operator is == then it needs to match everything, otherwise if its != there must be zero matches.
|
||||
return Operator == OperatorType.Equals ? matches >= SplitAttributeValue.Length : matches <= 0;
|
||||
}
|
||||
|
||||
// TODO: refactor and add tests
|
||||
private bool Matches(ISerializableEntity target, SerializableProperty property)
|
||||
{
|
||||
object propertyValue = property.GetValue(target);
|
||||
Type type = property.PropertyType;
|
||||
|
||||
if (propertyValue == null)
|
||||
if (type == typeof(float) || type == typeof(int))
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + AttributeValue.ToString() + " (" + AttributeValue.GetType() + ") to property \"" + property.Name + "\" - property.GetValue() returns null!");
|
||||
float floatValue = property.GetFloatValue(target);
|
||||
switch (Operator)
|
||||
{
|
||||
case OperatorType.Equals:
|
||||
return MathUtils.NearlyEqual(floatValue, FloatValue.Value);
|
||||
case OperatorType.NotEquals:
|
||||
return !MathUtils.NearlyEqual(floatValue, FloatValue.Value);
|
||||
case OperatorType.GreaterThan:
|
||||
return floatValue > FloatValue.Value;
|
||||
case OperatorType.LessThan:
|
||||
return floatValue < FloatValue.Value;
|
||||
case OperatorType.GreaterThanEquals:
|
||||
return floatValue >= FloatValue.Value;
|
||||
case OperatorType.LessThanEquals:
|
||||
return floatValue <= FloatValue.Value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Type type = propertyValue.GetType();
|
||||
float? floatProperty = null;
|
||||
if (type == typeof(float) || type == typeof(int))
|
||||
{
|
||||
floatProperty = (float)propertyValue;
|
||||
}
|
||||
|
||||
switch (Operator)
|
||||
{
|
||||
case OperatorType.Equals:
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
return ((bool)propertyValue) == (AttributeValue == "true" || AttributeValue == "True");
|
||||
}
|
||||
else if (FloatValue == null)
|
||||
{
|
||||
return propertyValue.ToString().Equals(AttributeValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return propertyValue.Equals(FloatValue);
|
||||
return property.GetBoolValue(target) == (AttributeValue == "true" || AttributeValue == "True");
|
||||
}
|
||||
return property.GetValue(target).ToString().Equals(AttributeValue);
|
||||
|
||||
case OperatorType.NotEquals:
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
return ((bool)propertyValue) != (AttributeValue == "true" || AttributeValue == "True");
|
||||
}
|
||||
else if (FloatValue == null)
|
||||
{
|
||||
return !propertyValue.ToString().Equals(AttributeValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return !propertyValue.Equals(FloatValue);
|
||||
return property.GetBoolValue(target) != (AttributeValue == "true" || AttributeValue == "True");
|
||||
}
|
||||
return !property.GetValue(target).ToString().Equals(AttributeValue);
|
||||
case OperatorType.GreaterThan:
|
||||
if (FloatValue == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + AttributeValue.ToString() + " (" + AttributeValue.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
}
|
||||
else if (floatProperty > FloatValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case OperatorType.LessThan:
|
||||
if (FloatValue == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + AttributeValue.ToString() + " (" + AttributeValue.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
}
|
||||
else if (floatProperty < FloatValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case OperatorType.GreaterThanEquals:
|
||||
if (FloatValue == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + AttributeValue.ToString() + " (" + AttributeValue.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
}
|
||||
else if (floatProperty >= FloatValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case OperatorType.LessThanEquals:
|
||||
if (FloatValue == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't compare " + AttributeValue.ToString() + " (" + AttributeValue.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
}
|
||||
else if (floatProperty <= FloatValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
case OperatorType.LessThan:
|
||||
case OperatorType.GreaterThanEquals:
|
||||
DebugConsole.ThrowError("Couldn't compare " + AttributeValue.ToString() + " (" + AttributeValue.GetType() + ") to property \"" + property.Name + "\" (" + type + ")! "
|
||||
+ "Make sure the type of the value set in the config files matches the type of the property.");
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -217,7 +217,7 @@ namespace Barotrauma
|
||||
public string[] TalentIdentifiers;
|
||||
public bool GiveRandom;
|
||||
|
||||
public GiveTalentInfo(XElement element, string parentDebugName)
|
||||
public GiveTalentInfo(XElement element, string _)
|
||||
{
|
||||
TalentIdentifiers = element.GetAttributeStringArray("talentidentifiers", new string[0], convertToLowerInvariant: true);
|
||||
GiveRandom = element.GetAttributeBool("giverandom", false);
|
||||
@@ -751,14 +751,41 @@ namespace Barotrauma
|
||||
for (int i = 0; i < propertyNames.Length; i++)
|
||||
{
|
||||
if (propertyNames[i] != "condition") { continue; }
|
||||
if (propertyEffects[i].GetType() == typeof(float))
|
||||
object propertyEffect = propertyEffects[i];
|
||||
if (propertyEffect.GetType() == typeof(float))
|
||||
{
|
||||
return (float)propertyEffects[i] < 0.0f || (setValue && (float)propertyEffects[i] <= 0.0f);
|
||||
return (float)propertyEffect < 0.0f || (setValue && (float)propertyEffect <= 0.0f);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IncreasesItemCondition()
|
||||
{
|
||||
for (int i = 0; i < propertyNames.Length; i++)
|
||||
{
|
||||
if (propertyNames[i] != "condition") { continue; }
|
||||
object propertyEffect = propertyEffects[i];
|
||||
if (propertyEffect.GetType() == typeof(float))
|
||||
{
|
||||
return (float)propertyEffect > 0.0f || (setValue && (float)propertyEffect > 0.0f);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool MatchesTagConditionals(ItemPrefab itemPrefab)
|
||||
{
|
||||
if (itemPrefab == null || !HasConditions)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return itemPrefab.Tags.Any(t => propertyConditionals.Any(pc => pc.MatchesTagCondition(t)));
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasRequiredAfflictions(AttackResult attackResult)
|
||||
{
|
||||
if (requiredAfflictions == null) { return true; }
|
||||
@@ -787,7 +814,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<ISerializableEntity> GetNearbyTargets(Vector2 worldPosition, List<ISerializableEntity> targets = null)
|
||||
public IReadOnlyList<ISerializableEntity> GetNearbyTargets(Vector2 worldPosition, List<ISerializableEntity> targets = null)
|
||||
{
|
||||
targets ??= new List<ISerializableEntity>();
|
||||
if (Range <= 0.0f) { return targets; }
|
||||
@@ -843,23 +870,24 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasRequiredConditions(IEnumerable<ISerializableEntity> targets)
|
||||
public bool HasRequiredConditions(IReadOnlyList<ISerializableEntity> targets)
|
||||
{
|
||||
return HasRequiredConditions(targets, propertyConditionals);
|
||||
}
|
||||
|
||||
private bool HasRequiredConditions(IEnumerable<ISerializableEntity> targets, IEnumerable<PropertyConditional> conditionals, bool targetingContainer = false)
|
||||
private bool HasRequiredConditions(IReadOnlyList<ISerializableEntity> targets, IReadOnlyList<PropertyConditional> conditionals, bool targetingContainer = false)
|
||||
{
|
||||
if (conditionals.None()) { return true; }
|
||||
if (requiredItems.Any() && requiredItems.All(ri => ri.MatchOnEmpty) && targets.None()) { return true; }
|
||||
if (conditionals.Count == 0) { return true; }
|
||||
if (targets.Count == 0 && requiredItems.Count > 0 && requiredItems.All(ri => ri.MatchOnEmpty)) { return true; }
|
||||
switch (conditionalComparison)
|
||||
{
|
||||
case PropertyConditional.Comparison.Or:
|
||||
foreach (PropertyConditional pc in conditionals)
|
||||
for (int i = 0; i < conditionals.Count; i++)
|
||||
{
|
||||
var pc = conditionals[i];
|
||||
if (pc.TargetContainer && !targetingContainer)
|
||||
{
|
||||
var target = targets.FirstOrDefault(t => t is Item || t is ItemComponent);
|
||||
var target = FindTargetItemOrComponent(targets);
|
||||
var targetItem = target as Item ?? (target as ItemComponent)?.Item;
|
||||
if (targetItem?.ParentInventory == null)
|
||||
{
|
||||
@@ -881,37 +909,28 @@ namespace Barotrauma
|
||||
if (pc.Type == PropertyConditional.ConditionType.HasTag)
|
||||
{
|
||||
//if we're checking for tags, just check the Item object, not the ItemComponents
|
||||
if (HasRequiredConditions((container as ISerializableEntity).ToEnumerable(), pc.ToEnumerable(), targetingContainer: true)) { return true; }
|
||||
if (pc.Matches(container)) { return true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HasRequiredConditions(container.AllPropertyObjects, pc.ToEnumerable(), targetingContainer: true)) { return true; }
|
||||
if (AnyTargetMatches(container.AllPropertyObjects, pc.TargetItemComponentName, pc)) { return true; }
|
||||
}
|
||||
}
|
||||
if (owner is Character character && HasRequiredConditions(character.ToEnumerable(), pc.ToEnumerable(), targetingContainer: true)) { return true; }
|
||||
if (owner is Character character && pc.Matches(character)) { return true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (ISerializableEntity target in targets)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(pc.TargetItemComponentName))
|
||||
{
|
||||
if (!(target is ItemComponent ic) || ic.Name != pc.TargetItemComponentName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (pc.Matches(target)) { return true; }
|
||||
}
|
||||
if (AnyTargetMatches(targets, pc.TargetItemComponentName, pc)) { return true; }
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case PropertyConditional.Comparison.And:
|
||||
foreach (PropertyConditional pc in conditionals)
|
||||
for (int i = 0; i < conditionals.Count; i++)
|
||||
{
|
||||
var pc = conditionals[i];
|
||||
if (pc.TargetContainer && !targetingContainer)
|
||||
{
|
||||
var target = targets.FirstOrDefault(t => t is Item || t is ItemComponent);
|
||||
var target = FindTargetItemOrComponent(targets);
|
||||
var targetItem = target as Item ?? (target as ItemComponent)?.Item;
|
||||
if (targetItem?.ParentInventory == null)
|
||||
{
|
||||
@@ -933,29 +952,49 @@ namespace Barotrauma
|
||||
if (pc.Type == PropertyConditional.ConditionType.HasTag)
|
||||
{
|
||||
//if we're checking for tags, just check the Item object, not the ItemComponents
|
||||
if (!HasRequiredConditions((container as ISerializableEntity).ToEnumerable(), pc.ToEnumerable(), targetingContainer: true)) { return false; }
|
||||
if (!pc.Matches(container)) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!HasRequiredConditions(container.AllPropertyObjects, pc.ToEnumerable(), targetingContainer: true)) { return false; }
|
||||
if (!AnyTargetMatches(container.AllPropertyObjects, pc.TargetItemComponentName, pc)) { return false; }
|
||||
}
|
||||
}
|
||||
if (owner is Character character && !HasRequiredConditions(character.ToEnumerable(), pc.ToEnumerable(), targetingContainer: true)) { return false; }
|
||||
if (owner is Character character && !pc.Matches(character)) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
var validTargets = targets;
|
||||
if (!string.IsNullOrEmpty(pc.TargetItemComponentName))
|
||||
{
|
||||
validTargets = targets.Where(t => t is ItemComponent ic && ic.Name == pc.TargetItemComponentName);
|
||||
}
|
||||
if (targets.None(t => pc.Matches(t))) { return false; }
|
||||
if (!AnyTargetMatches(targets, pc.TargetItemComponentName, pc)) { return false; }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
static bool AnyTargetMatches(IReadOnlyList<ISerializableEntity> targets, string targetItemComponentName, PropertyConditional conditional)
|
||||
{
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(targetItemComponentName))
|
||||
{
|
||||
if (!(targets[i] is ItemComponent ic) || ic.Name != targetItemComponentName) { continue; }
|
||||
}
|
||||
if (conditional.Matches(targets[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static ISerializableEntity FindTargetItemOrComponent(IReadOnlyList<ISerializableEntity> targets)
|
||||
{
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
if (targets[i] is Item || targets[i] is ItemComponent) { return targets[i]; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool IsValidTarget(ISerializableEntity entity)
|
||||
@@ -972,14 +1011,27 @@ namespace Barotrauma
|
||||
{
|
||||
if (targetIdentifiers == null) { return true; }
|
||||
if (targetIdentifiers.Contains("structure")) { return true; }
|
||||
if (targetIdentifiers.Any(id => id.Equals(structure.Prefab.Identifier, StringComparison.OrdinalIgnoreCase))) { return true; }
|
||||
foreach (var id in targetIdentifiers)
|
||||
{
|
||||
if (id.Equals(structure.Prefab.Identifier, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (entity is Character character)
|
||||
{
|
||||
return IsValidTarget(character);
|
||||
}
|
||||
if (targetIdentifiers == null) { return true; }
|
||||
return targetIdentifiers.Any(id => id.Equals(entity.Name, StringComparison.OrdinalIgnoreCase));
|
||||
foreach (var id in targetIdentifiers)
|
||||
{
|
||||
if (id.Equals(entity.Name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected bool IsValidTarget(ItemComponent itemComponent)
|
||||
@@ -989,7 +1041,14 @@ namespace Barotrauma
|
||||
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));
|
||||
foreach (var id in targetIdentifiers)
|
||||
{
|
||||
if (id.Equals(itemComponent.Item.Prefab.Identifier, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected bool IsValidTarget(Item item)
|
||||
@@ -999,7 +1058,14 @@ namespace Barotrauma
|
||||
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));
|
||||
foreach (var id in targetIdentifiers)
|
||||
{
|
||||
if (id.Equals(item.Prefab.Identifier, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected bool IsValidTarget(Character character)
|
||||
@@ -1008,7 +1074,14 @@ namespace Barotrauma
|
||||
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));
|
||||
foreach (var id in targetIdentifiers)
|
||||
{
|
||||
if (id.Equals(character.SpeciesName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetUser(Character user)
|
||||
@@ -1037,12 +1110,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasRequiredConditions(target.ToEnumerable())) { return; }
|
||||
Apply(deltaTime, entity, target.ToEnumerable(), worldPosition);
|
||||
currentTargets.Clear();
|
||||
currentTargets.Add(target);
|
||||
if (!HasRequiredConditions(currentTargets)) { return; }
|
||||
Apply(deltaTime, entity, currentTargets, worldPosition);
|
||||
}
|
||||
|
||||
protected readonly List<ISerializableEntity> currentTargets = new List<ISerializableEntity>();
|
||||
public virtual void Apply(ActionType type, float deltaTime, Entity entity, IEnumerable<ISerializableEntity> targets, Vector2? worldPosition = null)
|
||||
public virtual void Apply(ActionType type, float deltaTime, Entity entity, IReadOnlyList<ISerializableEntity> targets, Vector2? worldPosition = null)
|
||||
{
|
||||
if (this.type != type) { return; }
|
||||
|
||||
@@ -1095,39 +1170,52 @@ namespace Barotrauma
|
||||
return hull;
|
||||
}
|
||||
|
||||
private Vector2 GetPosition(Entity entity, IEnumerable<ISerializableEntity> targets, Vector2? worldPosition = null)
|
||||
private Vector2 GetPosition(Entity entity, IReadOnlyList<ISerializableEntity> targets, Vector2? worldPosition = null)
|
||||
{
|
||||
Vector2 position = worldPosition ?? (entity == null || entity.Removed ? Vector2.Zero : entity.WorldPosition);
|
||||
if (worldPosition == null)
|
||||
{
|
||||
if (entity is Character character && !character.Removed && targetLimbs?.FirstOrDefault(l => l != LimbType.None) is LimbType limbType)
|
||||
if (entity is Character character && !character.Removed && targetLimbs != null)
|
||||
{
|
||||
Limb limb = character.AnimController.GetLimb(limbType);
|
||||
if (limb != null && !limb.Removed)
|
||||
foreach (var targetLimbType in targetLimbs)
|
||||
{
|
||||
position = limb.WorldPosition;
|
||||
Limb limb = character.AnimController.GetLimb(targetLimbType);
|
||||
if (limb != null && !limb.Removed)
|
||||
{
|
||||
position = limb.WorldPosition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (HasTargetType(TargetType.Contained))
|
||||
{
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
if (targets[i] is Item targetItem)
|
||||
{
|
||||
position = targetItem.WorldPosition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targets.FirstOrDefault(t => t is Limb) is Limb targetLimb && !targetLimb.Removed)
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
position = targetLimb.WorldPosition;
|
||||
}
|
||||
else if (HasTargetType(TargetType.Contained))
|
||||
{
|
||||
if (targets.FirstOrDefault(t => t is Item) is Item targetItem)
|
||||
if (targets[i] is Limb targetLimb && !targetLimb.Removed)
|
||||
{
|
||||
position = targetItem.WorldPosition;
|
||||
position = targetLimb.WorldPosition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
position += Offset;
|
||||
return position;
|
||||
}
|
||||
|
||||
protected void Apply(float deltaTime, Entity entity, IEnumerable<ISerializableEntity> targets, Vector2? worldPosition = null)
|
||||
protected void Apply(float deltaTime, Entity entity, IReadOnlyList<ISerializableEntity> targets, Vector2? worldPosition = null)
|
||||
{
|
||||
if (lifeTime > 0)
|
||||
{
|
||||
@@ -1137,58 +1225,68 @@ namespace Barotrauma
|
||||
|
||||
Hull hull = GetHull(entity);
|
||||
Vector2 position = GetPosition(entity, targets, worldPosition);
|
||||
foreach (ISerializableEntity serializableEntity in targets)
|
||||
if (useItemCount > 0)
|
||||
{
|
||||
if (!(serializableEntity is Item item)) { continue; }
|
||||
|
||||
Character targetCharacter = targets.FirstOrDefault(t => t is Character character && !character.Removed) as Character;
|
||||
if (targetCharacter == null)
|
||||
Character useTargetCharacter = null;
|
||||
Limb useTargetLimb = null;
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
foreach (var target in targets)
|
||||
if (targets[i] is Character character && !character.Removed)
|
||||
{
|
||||
if (target is Limb limb && limb.character != null && !limb.character.Removed)
|
||||
{
|
||||
targetCharacter = ((Limb)target).character;
|
||||
}
|
||||
useTargetCharacter = character;
|
||||
break;
|
||||
}
|
||||
else if (targets[i] is Limb limb && limb.character != null && !limb.character.Removed)
|
||||
{
|
||||
useTargetLimb = limb;
|
||||
useTargetCharacter ??= limb.character;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < useItemCount; i++)
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
if (item.Removed) { continue; }
|
||||
item.Use(deltaTime, targetCharacter, targets.FirstOrDefault(t => t is Limb) as Limb);
|
||||
if (!(targets[i] is Item item)) { continue; }
|
||||
for (int j = 0; j < useItemCount; j++)
|
||||
{
|
||||
if (item.Removed) { continue; }
|
||||
item.Use(deltaTime, useTargetCharacter, useTargetLimb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removeItem)
|
||||
{
|
||||
foreach (var target in targets)
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
if (target is Item item) { Entity.Spawner?.AddToRemoveQueue(item); }
|
||||
if (targets[i] is Item item) { Entity.Spawner?.AddToRemoveQueue(item); }
|
||||
}
|
||||
}
|
||||
if (removeCharacter)
|
||||
{
|
||||
foreach (var target in targets)
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
if (target is Character character) { Entity.Spawner?.AddToRemoveQueue(character); }
|
||||
if (targets[i] is Character character) { Entity.Spawner?.AddToRemoveQueue(character); }
|
||||
}
|
||||
}
|
||||
if (breakLimb || hideLimb)
|
||||
{
|
||||
foreach (var target in targets)
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
if (target is Character character)
|
||||
if (targets[i] is Character character)
|
||||
{
|
||||
var matchingLimb = character.AnimController.Limbs.FirstOrDefault(l => l.body == sourceBody);
|
||||
if (matchingLimb != null)
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
{
|
||||
if (breakLimb)
|
||||
if (limb.body == sourceBody)
|
||||
{
|
||||
character.TrySeverLimbJoints(matchingLimb, severLimbsProbability: 100, damage: 100, allowBeheading: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchingLimb.HideAndDisable(hideLimbTimer);
|
||||
if (breakLimb)
|
||||
{
|
||||
character.TrySeverLimbJoints(limb, severLimbsProbability: 100, damage: 100, allowBeheading: true, attacker: user);
|
||||
}
|
||||
else
|
||||
{
|
||||
limb.HideAndDisable(hideLimbTimer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1201,10 +1299,10 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (ISerializableEntity target in targets)
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
var target = targets[i];
|
||||
if (target == null) { continue; }
|
||||
|
||||
if (target is Entity targetEntity)
|
||||
{
|
||||
if (targetEntity.Removed) { continue; }
|
||||
@@ -1215,13 +1313,13 @@ namespace Barotrauma
|
||||
position = limb.WorldPosition + Offset;
|
||||
}
|
||||
|
||||
for (int i = 0; i < propertyNames.Length; i++)
|
||||
for (int j = 0; j < propertyNames.Length; j++)
|
||||
{
|
||||
if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out SerializableProperty property))
|
||||
if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[j], out SerializableProperty property))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ApplyToProperty(target, property, propertyEffects[i], deltaTime);
|
||||
ApplyToProperty(target, property, j, deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1231,8 +1329,11 @@ namespace Barotrauma
|
||||
explosion.Explode(position, damageSource: entity, attacker: user);
|
||||
}
|
||||
|
||||
foreach (ISerializableEntity target in targets)
|
||||
bool isNotClient = GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient;
|
||||
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
var target = targets[i];
|
||||
//if the effect has a duration, these will be done in the UpdateAll method
|
||||
if (duration > 0) { break; }
|
||||
if (target == null) { continue; }
|
||||
@@ -1251,7 +1352,7 @@ namespace Barotrauma
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (targetLimbs != null && !targetLimbs.Contains(limb.type)) { continue; }
|
||||
AttackResult result = limb.character.DamageLimb(position, limb, newAffliction.ToEnumerable(), stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source, allowStacking: !setValue);
|
||||
limb.character.TrySeverLimbJoints(limb, SeverLimbsProbability, disableDeltaTime ? result.Damage : result.Damage / deltaTime, allowBeheading: true);
|
||||
limb.character.TrySeverLimbJoints(limb, SeverLimbsProbability, disableDeltaTime ? result.Damage : result.Damage / deltaTime, allowBeheading: true, attacker: affliction.Source);
|
||||
RegisterTreatmentResults(entity, limb, affliction, result);
|
||||
//only apply non-limb-specific afflictions to the first limb
|
||||
if (!affliction.Prefab.LimbSpecific) { break; }
|
||||
@@ -1263,7 +1364,7 @@ namespace Barotrauma
|
||||
if (limb.character.Removed || limb.Removed) { continue; }
|
||||
newAffliction = GetMultipliedAffliction(affliction, entity, limb.character, deltaTime, multiplyAfflictionsByMaxVitality);
|
||||
AttackResult result = limb.character.DamageLimb(position, limb, newAffliction.ToEnumerable(), stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source, allowStacking: !setValue);
|
||||
limb.character.TrySeverLimbJoints(limb, SeverLimbsProbability, disableDeltaTime ? result.Damage : result.Damage / deltaTime, allowBeheading: true);
|
||||
limb.character.TrySeverLimbJoints(limb, SeverLimbsProbability, disableDeltaTime ? result.Damage : result.Damage / deltaTime, allowBeheading: true, attacker: affliction.Source);
|
||||
RegisterTreatmentResults(entity, limb, affliction, result);
|
||||
}
|
||||
}
|
||||
@@ -1302,7 +1403,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (aiTriggers.Any())
|
||||
if (aiTriggers.Count > 0)
|
||||
{
|
||||
Character targetCharacter = target as Character;
|
||||
if (targetCharacter == null)
|
||||
@@ -1328,7 +1429,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (talentTriggers.Any())
|
||||
if (talentTriggers.Count > 0)
|
||||
{
|
||||
Character targetCharacter = CharacterFromTarget(target);
|
||||
if (targetCharacter != null && !targetCharacter.Removed)
|
||||
@@ -1337,14 +1438,12 @@ namespace Barotrauma
|
||||
{
|
||||
targetCharacter.CheckTalents(AbilityEffectType.OnStatusEffectIdentifier, new AbilityStatusEffectIdentifier(talentTrigger));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||
if (isNotClient)
|
||||
{
|
||||
// these effects do not need to be run clientside, as they are replicated from server to clients anyway
|
||||
|
||||
foreach (int giveExperience in giveExperiences)
|
||||
{
|
||||
Character targetCharacter = CharacterFromTarget(target);
|
||||
@@ -1354,7 +1453,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (giveSkills.Any())
|
||||
if (giveSkills.Count > 0)
|
||||
{
|
||||
foreach (GiveSkill giveSkill in giveSkills)
|
||||
{
|
||||
@@ -1373,7 +1472,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (giveTalentInfos.Any())
|
||||
if (giveTalentInfos.Count > 0)
|
||||
{
|
||||
Character targetCharacter = CharacterFromTarget(target);
|
||||
if (targetCharacter?.Info == null) { continue; }
|
||||
@@ -1408,7 +1507,6 @@ namespace Barotrauma
|
||||
fire.Size = new Vector2(FireSize, fire.Size.Y);
|
||||
}
|
||||
|
||||
bool isNotClient = GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient;
|
||||
if (isNotClient && GameMain.GameSession?.EventManager is { } eventManager)
|
||||
{
|
||||
foreach (EventPrefab eventPrefab in triggeredEvents)
|
||||
@@ -1423,7 +1521,7 @@ namespace Barotrauma
|
||||
{
|
||||
List<Entity> eventTargets = targets.Where(t => t is Entity).Cast<Entity>().ToList();
|
||||
|
||||
if (eventTargets.Any())
|
||||
if (eventTargets.Count > 0)
|
||||
{
|
||||
scriptedEvent.Targets.Add(triggeredEventTargetTag, eventTargets);
|
||||
}
|
||||
@@ -1616,17 +1714,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void ApplyProjSpecific(float deltaTime, Entity entity, IEnumerable<ISerializableEntity> targets, Hull currentHull, Vector2 worldPosition, bool playSound);
|
||||
partial void ApplyProjSpecific(float deltaTime, Entity entity, IReadOnlyList<ISerializableEntity> targets, Hull currentHull, Vector2 worldPosition, bool playSound);
|
||||
|
||||
private void ApplyToProperty(ISerializableEntity target, SerializableProperty property, object value, float deltaTime)
|
||||
private void ApplyToProperty(ISerializableEntity target, SerializableProperty property, int effectIndex, float deltaTime)
|
||||
{
|
||||
if (disableDeltaTime || setValue) { deltaTime = 1.0f; }
|
||||
if (value is int || value is float)
|
||||
object propertyEffect = propertyEffects[effectIndex];
|
||||
if (propertyEffect is int || propertyEffect is float)
|
||||
{
|
||||
var propertyValue = property.GetValue(target);
|
||||
if (propertyValue is float propertyValueF)
|
||||
float propertyValueF = property.GetFloatValue(target);
|
||||
if (property.PropertyType == typeof(float))
|
||||
{
|
||||
float floatValue = Convert.ToSingle(value) * deltaTime;
|
||||
float floatValue = propertyEffect is float single ? single : (int)propertyEffect;
|
||||
floatValue *= deltaTime;
|
||||
if (!setValue)
|
||||
{
|
||||
floatValue += propertyValueF;
|
||||
@@ -1634,18 +1734,23 @@ namespace Barotrauma
|
||||
property.TrySetValue(target, floatValue);
|
||||
return;
|
||||
}
|
||||
else if (propertyValue is int integer)
|
||||
else if (property.PropertyType == typeof(int))
|
||||
{
|
||||
int intValue = (int)(Convert.ToInt32(value) * deltaTime);
|
||||
int intValue = (int)(propertyEffect is float single ? single * deltaTime : (int)propertyEffect * deltaTime);
|
||||
if (!setValue)
|
||||
{
|
||||
intValue += integer;
|
||||
intValue += (int)propertyValueF;
|
||||
}
|
||||
property.TrySetValue(target, intValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
property.TrySetValue(target, value);
|
||||
else if (propertyEffect is bool propertyValueBool)
|
||||
{
|
||||
property.TrySetValue(target, propertyValueBool);
|
||||
return;
|
||||
}
|
||||
property.TrySetValue(target, propertyEffect);
|
||||
}
|
||||
|
||||
public static void UpdateAll(float deltaTime)
|
||||
@@ -1682,7 +1787,7 @@ namespace Barotrauma
|
||||
{
|
||||
continue;
|
||||
}
|
||||
element.Parent.ApplyToProperty(target, property, element.Parent.propertyEffects[n], CoroutineManager.UnscaledDeltaTime);
|
||||
element.Parent.ApplyToProperty(target, property, n, CoroutineManager.UnscaledDeltaTime);
|
||||
}
|
||||
|
||||
foreach (Affliction affliction in element.Parent.Afflictions)
|
||||
|
||||
Reference in New Issue
Block a user