Unstable 0.1500.8.0

This commit is contained in:
Markus Isberg
2021-10-16 10:32:38 +09:00
parent de917c5d74
commit fc2f7b76da
57 changed files with 608 additions and 302 deletions
@@ -1,4 +1,5 @@
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using FarseerPhysics;
using Microsoft.Xna.Framework;
@@ -346,7 +347,7 @@ namespace Barotrauma
}
#region Escape
public abstract void Escape(float deltaTime);
public abstract bool Escape(float deltaTime);
public Gap EscapeTarget { get; private set; }
@@ -425,17 +426,38 @@ namespace Barotrauma
}
if (EscapeTarget != null)
{
SteeringManager.SteeringSeek(EscapeTarget.SimPosition, 10);
float sqrDist = Vector2.DistanceSquared(Character.SimPosition, EscapeTarget.SimPosition);
if (sqrDist < 0.5f || Character.CurrentHull == null || HasValidPath(requireNonDirty: true, requireUnfinished: false) && pathSteering.CurrentPath.Finished)
Vector2 diff = EscapeTarget.WorldPosition - Character.WorldPosition;
float sqrDist = diff.LengthSquared();
if (Character.CurrentHull == null || sqrDist < MathUtils.Pow2(50) || pathSteering == null || IsCurrentPathUnreachable || IsCurrentPathFinished)
{
// Very close to the target, outside, or at the end of the path -> just steer towards it manually without using the path
// Very close to the target, outside, or at the end of the path -> try to steer through the gap
SteeringManager.Reset();
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(EscapeTarget.WorldPosition - Character.WorldPosition));
if (sqrDist < 4)
pathSteering?.ResetPath();
if (sqrDist < MathUtils.Pow2(50))
{
return true;
// Very close -> just keep steering forward
var forward = VectorExtensions.Forward(Character.AnimController.Collider.Rotation + MathHelper.PiOver2);
SteeringManager.SteeringManual(deltaTime, forward);
}
else if (Character.CurrentHull == null)
{
// Outside -> steer away from the target
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(-diff));
}
else
{
// Still inside -> steer towards the target
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(diff));
}
return sqrDist < MathUtils.Pow2(200);
}
else if (pathSteering != null)
{
pathSteering.SteeringSeek(EscapeTarget.SimPosition, weight: 1, minGapSize);
}
else
{
SteeringManager.SteeringSeek(EscapeTarget.SimPosition, 10);
}
}
else
@@ -1903,7 +1903,7 @@ namespace Barotrauma
Character.AnimController.ReleaseStuckLimbs();
LatchOntoAI?.DeattachFromBody(reset: true, cooldown: 1);
if (attacker == null || attacker.AiTarget == null || attacker.Removed || attacker.IsDead) { return; }
if (Character.Params.CanInteract)
if (Character.Params.CanInteract && attackResult.Damage > 10)
{
ReleaseDragTargets();
}
@@ -3607,12 +3607,12 @@ namespace Barotrauma
public bool CanPassThroughHole(Structure wall, int sectionIndex) => CanPassThroughHole(wall, sectionIndex, requiredHoleCount);
public override void Escape(float deltaTime)
public override bool Escape(float deltaTime)
{
if (SelectedAiTarget != null && (SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed))
{
State = AIState.Idle;
return;
return false;
}
else if (SelectedTargetMemory is AITargetMemory targetMemory && SelectedAiTarget?.Entity is Character)
{
@@ -3653,6 +3653,7 @@ namespace Barotrauma
}
}
}
return isSteeringThroughGap;
void SteerAwayFromTheEnemy()
{
@@ -1364,10 +1364,7 @@ namespace Barotrauma
ObjectiveManager.WaitTimer = waitDuration;
}
public override void Escape(float deltaTime)
{
UpdateEscape(deltaTime, canAttackDoors: false);
}
public override bool Escape(float deltaTime) => UpdateEscape(deltaTime, canAttackDoors: false);
private void CheckCrouching(float deltaTime)
{
@@ -269,7 +269,7 @@ namespace Barotrauma
{
var waypoint = CurrentPath.Nodes[i];
float directDistance = Vector2.DistanceSquared(character.WorldPosition, waypoint.WorldPosition);
if (directDistance > (pathDistance * pathDistance) || Submarine.PickBody(host.SimPosition, waypoint.SimPosition, collisionCategory: Physics.CollisionLevel) != null)
if (directDistance > (pathDistance * pathDistance) || Submarine.PickBody(host.SimPosition, waypoint.SimPosition, collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) != null)
{
pathDistance -= CurrentPath.GetLength(startIndex: i - 1, endIndex: i);
continue;
@@ -9,6 +9,7 @@ namespace Barotrauma
public override string Identifier { get; set; } = "return";
private AIObjectiveGoTo moveInsideObjective, moveInCaveObjective, moveOutsideObjective;
private bool usingEscapeBehavior;
private bool isSteeringThroughGap;
public Submarine ReturnTarget { get; }
public AIObjectiveReturn(Character character, Character orderGiver, AIObjectiveManager objectiveManager, float priorityModifier = 1.0f) : base(character, objectiveManager, priorityModifier)
@@ -57,7 +58,7 @@ namespace Barotrauma
return;
}
bool shouldUseEscapeBehavior = false;
if (character.CurrentHull != null)
if (character.CurrentHull != null || isSteeringThroughGap)
{
if (character.Submarine == null || !character.Submarine.IsConnectedTo(ReturnTarget))
{
@@ -67,8 +68,8 @@ namespace Barotrauma
{
HumanAIController.ResetEscape();
}
HumanAIController.Escape(deltaTime);
if (HumanAIController.EscapeTarget == null || HumanAIController.IsCurrentPathUnreachable)
isSteeringThroughGap = HumanAIController.Escape(deltaTime);
if (!isSteeringThroughGap && (HumanAIController.EscapeTarget == null || HumanAIController.IsCurrentPathUnreachable))
{
Abandon = true;
}
@@ -92,7 +93,10 @@ namespace Barotrauma
RemoveSubObjective(ref moveInCaveObjective);
RemoveSubObjective(ref moveOutsideObjective);
TryAddSubObjective(ref moveInsideObjective,
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager),
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager)
{
AllowGoingOutside = true
},
onCompleted: () => RemoveSubObjective(ref moveInsideObjective),
onAbandon: () => Abandon = true);
}
@@ -110,7 +114,7 @@ namespace Barotrauma
IsCompleted = true;
}
}
else if (moveInCaveObjective == null && moveOutsideObjective == null)
else if (!isSteeringThroughGap && moveInCaveObjective == null && moveOutsideObjective == null)
{
if (HumanAIController.IsInsideCave)
{
@@ -134,7 +138,8 @@ namespace Barotrauma
TryAddSubObjective(ref moveInCaveObjective,
constructor: () => new AIObjectiveGoTo(closestOutsideWaypoint, character, objectiveManager)
{
endNodeFilter = n => n.Waypoint == closestOutsideWaypoint
endNodeFilter = n => n.Waypoint == closestOutsideWaypoint,
AllowGoingOutside = true
},
onCompleted: () => RemoveSubObjective(ref moveInCaveObjective),
onAbandon: () => Abandon = true);
@@ -170,7 +175,10 @@ namespace Barotrauma
RemoveSubObjective(ref moveInsideObjective);
RemoveSubObjective(ref moveInCaveObjective);
TryAddSubObjective(ref moveOutsideObjective,
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager),
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager)
{
AllowGoingOutside = true
},
onCompleted: () => RemoveSubObjective(ref moveOutsideObjective),
onAbandon: () => Abandon = true);
}
@@ -221,6 +229,7 @@ namespace Barotrauma
moveInCaveObjective = null;
moveOutsideObjective = null;
usingEscapeBehavior = false;
isSteeringThroughGap = false;
HumanAIController.ResetEscape();
}
@@ -236,6 +236,7 @@ namespace Barotrauma
collisionCategory: Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionStairs);
if (body != null)
{
if (body.UserData is Submarine) { return false; }
if (body.UserData is Structure s && !s.IsPlatform) { return false; }
if (body.UserData is Item && body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall)) { return false; }
}
@@ -684,18 +684,15 @@ namespace Barotrauma
if (rightHand != null && !rightHand.Disabled)
{
HandIK(rightHand, torso.SimPosition + posAddition +
new Vector2(
-handPos.X,
(Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY), CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
HandIK(rightHand,
torso.SimPosition + posAddition + new Vector2(-handPos.X, (Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY),
CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
}
if (leftHand != null && !leftHand.Disabled)
{
HandIK(leftHand, torso.SimPosition + posAddition +
new Vector2(
handPos.X,
(Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY), CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
HandIK(leftHand,
torso.SimPosition + posAddition + new Vector2(handPos.X, (Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY),
CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
}
}
else
@@ -705,9 +702,7 @@ namespace Barotrauma
Vector2 footPos = colliderPos;
if (Crouching)
{
footPos = new Vector2(
Math.Sign(stepSize.X * i) * Dir * 0.4f,
colliderPos.Y);
footPos = new Vector2(Math.Sign(stepSize.X * i) * Dir * 0.35f, colliderPos.Y);
if (Math.Sign(footPos.X) != Math.Sign(Dir))
{
//lift the foot at the back up a bit
@@ -728,9 +723,16 @@ namespace Barotrauma
{
foot.DebugRefPos = colliderPos;
foot.DebugTargetPos = footPos;
MoveLimb(foot, footPos, CurrentGroundedParams.FootMoveStrength);
FootIK(foot, footPos,
CurrentGroundedParams.LegBendTorque, CurrentGroundedParams.FootTorque, CurrentGroundedParams.FootAngleInRadians);
float footMoveForce = CurrentGroundedParams.FootMoveStrength;
float legBendTorque = CurrentGroundedParams.LegBendTorque;
if (Crouching)
{
// Keeps the pose
legBendTorque = 100;
footMoveForce *= 2;
}
MoveLimb(foot, footPos, footMoveForce);
FootIK(foot, footPos, legBendTorque, CurrentGroundedParams.FootTorque, CurrentGroundedParams.FootAngleInRadians);
}
}
@@ -760,6 +762,12 @@ namespace Barotrauma
forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f * CurrentGroundedParams.ArmMoveStrength);
}
}
// Try to keep the wrist straight
LimbJoint wrist = GetJointBetweenLimbs(foreArmType, hand.type);
if (wrist != null)
{
hand.body.ApplyTorque(MathHelper.Clamp(-wrist.JointAngle, -MathHelper.PiOver2, MathHelper.PiOver2) * hand.Mass * 100f * CurrentGroundedParams.HandMoveStrength);
}
}
}
}
@@ -1008,6 +1016,12 @@ namespace Barotrauma
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
}
HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
// Try to keep the wrist straight
LimbJoint wrist = GetJointBetweenLimbs(LimbType.RightForearm, LimbType.RightHand);
if (wrist != null)
{
rightHand.body.ApplyTorque(MathHelper.Clamp(-wrist.JointAngle, -MathHelper.PiOver2, MathHelper.PiOver2) * rightHand.Mass * 100f * CurrentSwimParams.HandMoveStrength);
}
}
if (leftHand != null && !leftHand.Disabled)
@@ -1021,6 +1035,12 @@ namespace Barotrauma
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
}
HandIK(leftHand, handPos + leftHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
// Try to keep the wrist straight
LimbJoint wrist = GetJointBetweenLimbs(LimbType.LeftForearm, LimbType.LeftHand);
if (wrist != null)
{
leftHand.body.ApplyTorque(MathHelper.Clamp(-wrist.JointAngle, -MathHelper.PiOver2, MathHelper.PiOver2) * leftHand.Mass * 100f * CurrentSwimParams.HandMoveStrength);
}
}
}
@@ -665,6 +665,7 @@ namespace Barotrauma
public float MaxVitality => CharacterHealth.MaxVitality;
public float MaxHealth => MaxVitality;
public AIState AIState => AIController is EnemyAIController enemyAI ? enemyAI.State : AIState.Idle;
public bool IsLatched => AIController is EnemyAIController enemyAI && enemyAI.LatchOntoAI != null && enemyAI.LatchOntoAI.IsAttached;
public float Bloodloss
{
@@ -2751,7 +2752,8 @@ namespace Barotrauma
}
else if (this != Controlled)
{
IsRagdolled = IsKeyDown(InputType.Ragdoll);
wasRagdolled = IsRagdolled;
IsRagdolled = selfRagdolled = IsKeyDown(InputType.Ragdoll);
}
//Keep us ragdolled if we were forced or we're too speedy to unragdoll
else if (allowRagdoll && (!IsRagdolled || !tooFastToUnragdoll))
@@ -2765,13 +2767,18 @@ namespace Barotrauma
{
wasRagdolled = IsRagdolled;
IsRagdolled = selfRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
if (wasRagdolled != IsRagdolled) { ragdollingLockTimer = 0.25f; }
if (wasRagdolled != IsRagdolled) { ragdollingLockTimer = 0.5f; }
}
}
if (!wasRagdolled && IsRagdolled && selfRagdolled)
if (!wasRagdolled && IsRagdolled)
{
CheckTalents(AbilityEffectType.OnSelfRagdoll);
if (selfRagdolled)
{
CheckTalents(AbilityEffectType.OnSelfRagdoll);
}
// currently does not work when you are stunned, like it should
CheckTalents(AbilityEffectType.OnRagdoll);
}
lowPassMultiplier = MathHelper.Lerp(lowPassMultiplier, 1.0f, 0.1f);
@@ -3535,11 +3542,6 @@ namespace Barotrauma
if (Removed) { return new AttackResult(); }
if (attacker != null && attacker != this && GameMain.NetworkMember != null && !GameMain.NetworkMember.ServerSettings.AllowFriendlyFire)
{
if (attacker.TeamID == TeamID) { return new AttackResult(); }
}
float closestDistance = 0.0f;
foreach (Limb limb in AnimController.Limbs)
{
@@ -3602,7 +3604,11 @@ namespace Barotrauma
if (attacker != null && attacker != this && GameMain.NetworkMember != null && !GameMain.NetworkMember.ServerSettings.AllowFriendlyFire)
{
if (attacker.TeamID == TeamID) { return new AttackResult(); }
if (attacker.TeamID == TeamID)
{
afflictions = afflictions.Where(a => !a.Prefab.IsBuff);
if (!afflictions.Any()) { return new AttackResult(); }
}
}
#if CLIENT
@@ -4385,14 +4391,14 @@ namespace Barotrauma
info.UnlockedTalents.Add(talentPrefab.Identifier);
if (characterTalents.Any(t => t.Prefab == talentPrefab)) { return false; }
#if SERVER
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateTalents });
#endif
CharacterTalent characterTalent = new CharacterTalent(talentPrefab, this);
characterTalent.ActivateTalent(addingFirstTime);
characterTalents.Add(characterTalent);
characterTalent.AddedThisRound = addingFirstTime;
#if SERVER
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateTalents });
#endif
if (addingFirstTime)
{
OnTalentGiven(talentPrefab.Identifier);
@@ -216,6 +216,17 @@ namespace Barotrauma
public HashSet<string> UnlockedTalents { get; private set; } = new HashSet<string>();
/// <summary>
/// Endocrine boosters can unlock talents outside the user's talent tree. This method is used to cull them from the selection
/// </summary>
public IEnumerable<string> GetUnlockedTalentsInTree()
{
if (!TalentTree.JobTalentTrees.TryGetValue(Job.Prefab.Identifier, out TalentTree talentTree)) { return Enumerable.Empty<string>(); }
return UnlockedTalents.Where(t => talentTree.TalentIsInTree(t));
}
public int AdditionalTalentPoints { get; set; }
private Sprite _headSprite;
@@ -1220,7 +1231,7 @@ namespace Barotrauma
var experienceGainMultiplier = new AbilityValue(1f);
if (isMissionExperience)
{
Character.CheckTalents(AbilityEffectType.OnGainMissionExperience, experienceGainMultiplier);
Character?.CheckTalents(AbilityEffectType.OnGainMissionExperience, experienceGainMultiplier);
}
experienceGainMultiplier.Value += Character.GetStatValue(StatTypes.ExperienceGainMultiplier);
@@ -1252,7 +1263,7 @@ namespace Barotrauma
public int GetAvailableTalentPoints()
{
// hashset always has at least 1
return Math.Max(GetTotalTalentPoints() - UnlockedTalents.Count, 0);
return Math.Max(GetTotalTalentPoints() - GetUnlockedTalentsInTree().Count(), 0);
}
public float GetProgressTowardsNextLevel()
@@ -1297,6 +1308,8 @@ namespace Barotrauma
partial void OnExperienceChanged(int prevAmount, int newAmount);
partial void OnPermanentStatChanged(StatTypes statType);
public void Rename(string newName)
{
if (string.IsNullOrEmpty(newName)) { return; }
@@ -1362,7 +1375,7 @@ namespace Barotrauma
Job.Save(charElement);
XElement savedStatElement = new XElement("savedstatvalues");
foreach (var statValuePair in savedStatValues)
foreach (var statValuePair in SavedStatValues)
{
foreach (var savedStat in statValuePair.Value)
{
@@ -1708,26 +1721,42 @@ namespace Barotrauma
}
// This could maybe be a LookUp instead?
private readonly Dictionary<StatTypes, List<SavedStatValue>> savedStatValues = new Dictionary<StatTypes, List<SavedStatValue>>();
public readonly Dictionary<StatTypes, List<SavedStatValue>> SavedStatValues = new Dictionary<StatTypes, List<SavedStatValue>>();
public void ResetSavedStatValues()
public void ClearSavedStatValues()
{
foreach (var savedStatValue in savedStatValues.SelectMany(s => s.Value))
foreach (StatTypes statType in SavedStatValues.Keys)
{
if (savedStatValue.RemoveOnDeath)
{
savedStatValue.StatValue = 0f;
}
OnPermanentStatChanged(statType);
}
SavedStatValues.Clear();
}
public void ClearSavedStatValues(StatTypes statType)
{
SavedStatValues.Remove(statType);
OnPermanentStatChanged(statType);
}
public void ResetSavedStatValue(string statIdentifier)
{
savedStatValues.SelectMany(s => s.Value).Where(s => s.StatIdentifier == statIdentifier).ForEach(v => v.StatValue = 0f);
foreach (StatTypes statType in SavedStatValues.Keys)
{
bool changed = false;
foreach (SavedStatValue savedStatValue in SavedStatValues[statType])
{
if (savedStatValue.StatIdentifier != statIdentifier) { continue; }
if (MathUtils.NearlyEqual(savedStatValue.StatValue, 0.0f)) { continue; }
savedStatValue.StatValue = 0.0f;
changed = true;
}
if (changed) { OnPermanentStatChanged(statType); }
}
}
public float GetSavedStatValue(StatTypes statType)
{
if (savedStatValues.TryGetValue(statType, out var statValues))
if (SavedStatValues.TryGetValue(statType, out var statValues))
{
return statValues.Sum(v => v.StatValue);
}
@@ -1738,7 +1767,7 @@ namespace Barotrauma
}
public float GetSavedStatValue(StatTypes statType, string statIdentifier)
{
if (savedStatValues.TryGetValue(statType, out var statValues))
if (SavedStatValues.TryGetValue(statType, out var statValues))
{
return statValues.Where(s => s.StatIdentifier.Equals(statIdentifier, StringComparison.OrdinalIgnoreCase)).Sum(v => v.StatValue);
}
@@ -1750,19 +1779,24 @@ namespace Barotrauma
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath, bool removeAfterRound = false, float maxValue = float.MaxValue, bool setValue = false)
{
if (!savedStatValues.ContainsKey(statType))
if (!SavedStatValues.ContainsKey(statType))
{
savedStatValues.Add(statType, new List<SavedStatValue>());
SavedStatValues.Add(statType, new List<SavedStatValue>());
}
if (savedStatValues[statType].FirstOrDefault(s => s.StatIdentifier == statIdentifier) is SavedStatValue savedStat)
bool changed = false;
if (SavedStatValues[statType].FirstOrDefault(s => s.StatIdentifier == statIdentifier) is SavedStatValue savedStat)
{
float prevValue = savedStat.StatValue;
savedStat.StatValue = setValue ? value : MathHelper.Min(savedStat.StatValue + value, maxValue);
changed = !MathUtils.NearlyEqual(savedStat.StatValue, prevValue);
}
else
{
savedStatValues[statType].Add(new SavedStatValue(statIdentifier, MathHelper.Min(value, maxValue), removeOnDeath, removeAfterRound));
SavedStatValues[statType].Add(new SavedStatValue(statIdentifier, MathHelper.Min(value, maxValue), removeOnDeath, removeAfterRound));
changed = true;
}
if (changed) { OnPermanentStatChanged(statType); }
}
}
@@ -11,6 +11,7 @@ namespace Barotrauma.Abilities
protected readonly List<StatusEffect> statusEffects;
private readonly bool nearbyCharactersAppliesToSelf;
private readonly bool nearbyCharactersAppliesToAllies;
private readonly bool applyToSelected;
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
@@ -20,6 +21,7 @@ namespace Barotrauma.Abilities
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
applyToSelected = abilityElement.GetAttributeBool("applytoselected", false);
nearbyCharactersAppliesToSelf = abilityElement.GetAttributeBool("nearbycharactersappliestoself", true);
nearbyCharactersAppliesToAllies = abilityElement.GetAttributeBool("nearbycharactersappliestoallies", true);
}
protected void ApplyEffectSpecific(Character targetCharacter)
@@ -40,6 +42,10 @@ namespace Barotrauma.Abilities
{
targets.RemoveAll(c => c == Character);
}
if (!nearbyCharactersAppliesToAllies)
{
targets.RemoveAll(c => c is Character otherCharacter && HumanAIController.IsFriendly(otherCharacter, Character));
}
statusEffect.SetUser(Character);
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targets);
}
@@ -56,17 +62,20 @@ namespace Barotrauma.Abilities
}
}
protected override void ApplyEffect()
{
ApplyEffectSpecific(Character);
}
protected override void ApplyEffect(AbilityObject abilityObject)
{
if (applyToSelected && Character.SelectedCharacter is Character selectedCharacter)
{
ApplyEffectSpecific(selectedCharacter);
}
else if ((abilityObject as IAbilityCharacter)?.Character is Character targetCharacter)
else
{
ApplyEffectSpecific(Character);
}
}
protected override void ApplyEffect(AbilityObject abilityObject)
{
if ((abilityObject as IAbilityCharacter)?.Character is Character targetCharacter)
{
ApplyEffectSpecific(targetCharacter);
}
@@ -15,7 +15,7 @@ namespace Barotrauma.Abilities
private readonly bool setValue;
//private readonly float maximumValue;
public override bool AllowClientSimulation => true;
public override bool AppliesEffectOnIntervalUpdate => true;
public CharacterAbilityGivePermanentStat(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
@@ -6,6 +6,7 @@ namespace Barotrauma.Abilities
{
private readonly string statIdentifier;
public override bool AppliesEffectOnIntervalUpdate => true;
public override bool AllowClientSimulation => true;
public CharacterAbilityResetPermanentStat(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
{
@@ -31,7 +31,7 @@ namespace Barotrauma.Abilities
}
}
if (closestCharacter.SelectedConstruction == null || !Character.SelectedConstruction.HasTag(tag)) { return; }
if (closestCharacter.SelectedConstruction == null || !closestCharacter.SelectedConstruction.HasTag(tag)) { return; }
if (closestDistance < squaredMaxDistance)
{
@@ -66,6 +66,11 @@ namespace Barotrauma
}
}
public bool TalentIsInTree(string talentIdentifier)
{
return TalentSubTrees.SelectMany(s => s.TalentOptionStages.SelectMany(o => o.Talents.Select(t => t.Identifier))).Any(c => c == talentIdentifier);
}
public static void LoadFromFile(ContentFile file)
{
DebugConsole.Log("Loading talent tree: " + file.Path);