Unstable 0.1500.8.0
This commit is contained in:
@@ -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;
|
||||
|
||||
+16
-7
@@ -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; }
|
||||
}
|
||||
|
||||
+35
-15
@@ -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); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-6
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+1
@@ -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)
|
||||
{
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user