v0.13.0.11
This commit is contained in:
@@ -39,6 +39,66 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
class AITrigger : ISerializableEntity
|
||||
{
|
||||
public string Name => "ai trigger";
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties { get; set; }
|
||||
|
||||
[Serialize(AIState.Idle, false)]
|
||||
public AIState State { get; private set; }
|
||||
|
||||
[Serialize(0f, false)]
|
||||
public float Duration { get; private set; }
|
||||
|
||||
[Serialize(1f, false)]
|
||||
public float Probability { get; private set; }
|
||||
|
||||
[Serialize(0f, false)]
|
||||
public float MinDamage { get; private set; }
|
||||
|
||||
[Serialize(true, false)]
|
||||
public bool AllowToOverride { get; private set; }
|
||||
|
||||
[Serialize(true, false)]
|
||||
public bool AllowToBeOverridden { get; private set; }
|
||||
|
||||
public bool IsTriggered { get; private set; }
|
||||
|
||||
public float Timer { get; private set; } = -1;
|
||||
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
public void Launch()
|
||||
{
|
||||
IsTriggered = true;
|
||||
IsActive = true;
|
||||
Timer = Duration;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
IsTriggered = false;
|
||||
IsActive = false;
|
||||
Timer = 0;
|
||||
}
|
||||
|
||||
public void UpdateTimer(float deltaTime)
|
||||
{
|
||||
Timer -= deltaTime;
|
||||
if (Timer < 0)
|
||||
{
|
||||
Timer = 0;
|
||||
IsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public AITrigger(XElement element)
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
}
|
||||
}
|
||||
|
||||
partial class StatusEffect
|
||||
{
|
||||
[Flags]
|
||||
@@ -53,7 +113,8 @@ namespace Barotrauma
|
||||
UseTarget = 64,
|
||||
Hull = 128,
|
||||
Limb = 256,
|
||||
AllLimbs = 512
|
||||
AllLimbs = 512,
|
||||
LastLimb = 1024
|
||||
}
|
||||
|
||||
class ItemSpawnInfo
|
||||
@@ -198,10 +259,11 @@ 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<AITrigger> aiTriggers;
|
||||
|
||||
private readonly List<EventPrefab> triggeredEvents;
|
||||
private readonly string triggeredEventTargetTag = "statuseffecttarget",
|
||||
@@ -219,12 +281,16 @@ namespace Barotrauma
|
||||
|
||||
public readonly bool OnlyInside;
|
||||
public readonly bool OnlyOutside;
|
||||
// Currently only used for OnDamaged. TODO: is there a better, more generic way to do this?
|
||||
public readonly bool OnlyPlayerTriggered;
|
||||
|
||||
public HashSet<string> TargetIdentifiers
|
||||
{
|
||||
get { return targetIdentifiers; }
|
||||
}
|
||||
|
||||
public HashSet<string> AllowedAfflictions { get; private set; }
|
||||
|
||||
public List<Affliction> Afflictions
|
||||
{
|
||||
get;
|
||||
@@ -236,7 +302,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
|
||||
@@ -279,13 +347,15 @@ namespace Barotrauma
|
||||
requiredItems = new List<RelatedItem>();
|
||||
spawnItems = new List<ItemSpawnInfo>();
|
||||
spawnCharacters = new List<CharacterSpawnInfo>();
|
||||
aiTriggers = new List<AITrigger>();
|
||||
Afflictions = new List<Affliction>();
|
||||
explosions = new List<Explosion>();
|
||||
Explosions = new List<Explosion>();
|
||||
triggeredEvents = new List<EventPrefab>();
|
||||
reduceAffliction = new List<Pair<string, float>>();
|
||||
ReduceAffliction = new List<Pair<string, float>>();
|
||||
tags = new HashSet<string>(element.GetAttributeString("tags", "").Split(','));
|
||||
OnlyInside = element.GetAttributeBool("onlyinside", false);
|
||||
OnlyOutside = element.GetAttributeBool("onlyoutside", false);
|
||||
OnlyPlayerTriggered = element.GetAttributeBool("onlyplayertriggered", false);
|
||||
|
||||
Range = element.GetAttributeFloat("range", 0.0f);
|
||||
Offset = element.GetAttributeVector2("offset", Vector2.Zero);
|
||||
@@ -295,7 +365,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(); }
|
||||
}
|
||||
@@ -353,6 +423,14 @@ namespace Barotrauma
|
||||
targetIdentifiers.Add(identifiers[i].Trim().ToLowerInvariant());
|
||||
}
|
||||
break;
|
||||
case "allowedafflictions":
|
||||
string[] types = attribute.Value.Split(',');
|
||||
AllowedAfflictions = new HashSet<string>();
|
||||
for (int i = 0; i < types.Length; i++)
|
||||
{
|
||||
AllowedAfflictions.Add(types[i].Trim().ToLowerInvariant());
|
||||
}
|
||||
break;
|
||||
case "duration":
|
||||
duration = attribute.GetAttributeFloat(0.0f);
|
||||
break;
|
||||
@@ -419,7 +497,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);
|
||||
@@ -494,7 +572,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")));
|
||||
}
|
||||
@@ -505,7 +583,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")));
|
||||
}
|
||||
@@ -529,7 +607,6 @@ namespace Barotrauma
|
||||
triggeredEvents.Add(prefab);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (XElement eventElement in subElement.Elements())
|
||||
{
|
||||
if (!eventElement.Name.ToString().Equals("ScriptedEvent", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
@@ -540,6 +617,9 @@ namespace Barotrauma
|
||||
var newSpawnCharacter = new CharacterSpawnInfo(subElement, parentDebugName);
|
||||
if (!string.IsNullOrWhiteSpace(newSpawnCharacter.SpeciesName)) { spawnCharacters.Add(newSpawnCharacter); }
|
||||
break;
|
||||
case "aitrigger":
|
||||
aiTriggers.Add(new AITrigger(subElement));
|
||||
break;
|
||||
}
|
||||
}
|
||||
InitProjSpecific(element, parentDebugName);
|
||||
@@ -977,7 +1057,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Explosion explosion in explosions)
|
||||
foreach (Explosion explosion in Explosions)
|
||||
{
|
||||
explosion.Explode(position, damageSource: entity, attacker: user);
|
||||
}
|
||||
@@ -990,12 +1070,11 @@ namespace Barotrauma
|
||||
foreach (Affliction affliction in Afflictions)
|
||||
{
|
||||
if (Rand.Value(Rand.RandSync.Unsynced) > affliction.Probability) { continue; }
|
||||
Affliction multipliedAffliction = affliction;
|
||||
if (!disableDeltaTime)
|
||||
Affliction newAffliction = affliction;
|
||||
if (!disableDeltaTime && !setValue)
|
||||
{
|
||||
multipliedAffliction = affliction.CreateMultiplied(deltaTime);
|
||||
newAffliction = affliction.CreateMultiplied(deltaTime);
|
||||
}
|
||||
|
||||
if (target is Character character)
|
||||
{
|
||||
if (character.Removed) { continue; }
|
||||
@@ -1005,7 +1084,7 @@ namespace Barotrauma
|
||||
if (limb.Removed) { continue; }
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (targetLimbs != null && !targetLimbs.Contains(limb.type)) { continue; }
|
||||
AttackResult result = limb.character.DamageLimb(position, limb, multipliedAffliction.ToEnumerable(), stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source);
|
||||
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);
|
||||
//only apply non-limb-specific afflictions to the first limb
|
||||
if (!affliction.Prefab.LimbSpecific) { break; }
|
||||
@@ -1015,21 +1094,21 @@ namespace Barotrauma
|
||||
{
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (limb.character.Removed || limb.Removed) { continue; }
|
||||
AttackResult result = limb.character.DamageLimb(position, limb, multipliedAffliction.ToEnumerable(), stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Pair<string, float> reduceAffliction in reduceAffliction)
|
||||
foreach (Pair<string, float> reduceAffliction in ReduceAffliction)
|
||||
{
|
||||
float reduceAmount = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime;
|
||||
float reduceAmount = disableDeltaTime || setValue ? reduceAffliction.Second : reduceAffliction.Second * deltaTime;
|
||||
Limb targetLimb = null;
|
||||
Character targetCharacter = null;
|
||||
if (target is Character character)
|
||||
{
|
||||
targetCharacter = character;
|
||||
}
|
||||
else if (target is Limb limb)
|
||||
else if (target is Limb limb && !limb.Removed)
|
||||
{
|
||||
targetLimb = limb;
|
||||
targetCharacter = limb.character;
|
||||
@@ -1050,6 +1129,32 @@ namespace Barotrauma
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (aiTriggers.Any())
|
||||
{
|
||||
Character targetCharacter = target as Character;
|
||||
if (targetCharacter == null)
|
||||
{
|
||||
if (target is Limb targetLimb && !targetLimb.Removed)
|
||||
{
|
||||
targetCharacter = targetLimb.character;
|
||||
}
|
||||
}
|
||||
if (targetCharacter != null && !targetCharacter.Removed && !targetCharacter.IsPlayer)
|
||||
{
|
||||
if (targetCharacter.AIController is EnemyAIController enemyAI)
|
||||
{
|
||||
foreach (AITrigger trigger in aiTriggers)
|
||||
{
|
||||
if (Rand.Value(Rand.RandSync.Unsynced) > trigger.Probability) { continue; }
|
||||
if (target is Limb targetLimb && targetCharacter.LastDamage.HitLimb != targetLimb) { continue; }
|
||||
if (targetCharacter.LastDamage.Damage < trigger.MinDamage) { continue; }
|
||||
enemyAI.LaunchTrigger(trigger);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FireSize > 0.0f && entity != null)
|
||||
@@ -1290,7 +1395,7 @@ namespace Barotrauma
|
||||
foreach (Affliction affliction in element.Parent.Afflictions)
|
||||
{
|
||||
Affliction multipliedAffliction = affliction;
|
||||
if (!element.Parent.disableDeltaTime) { multipliedAffliction = affliction.CreateMultiplied(deltaTime); }
|
||||
if (!element.Parent.disableDeltaTime && !element.Parent.setValue) { multipliedAffliction = affliction.CreateMultiplied(deltaTime); }
|
||||
|
||||
if (target is Character character)
|
||||
{
|
||||
@@ -1304,7 +1409,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