Unstable 0.1500.7.0 (No edition)

This commit is contained in:
Markus Isberg
2021-10-14 00:42:06 +09:00
parent c8943ef9c4
commit de917c5d74
105 changed files with 871 additions and 443 deletions
@@ -103,6 +103,9 @@ namespace Barotrauma
!pathSteering.CurrentPath.Unreachable &&
(!requireNonDirty || !pathSteering.IsPathDirty);
public bool IsCurrentPathUnreachable => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Unreachable;
public bool IsCurrentPathFinished => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Finished;
protected readonly float colliderWidth;
protected readonly float minGapSize;
protected readonly float colliderLength;
@@ -412,7 +415,7 @@ namespace Barotrauma
}
else if (EscapeTarget != null && EscapeTarget.FlowTargetHull != Character.CurrentHull)
{
if (pathSteering.CurrentPath != null && !pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
if (IsCurrentPathUnreachable)
{
unreachableGaps.Add(EscapeTarget);
EscapeTarget = null;
@@ -453,7 +453,7 @@ namespace Barotrauma
if (SelectedAiTarget?.Entity != null || EscapeTarget != null)
{
Entity t = SelectedAiTarget?.Entity ?? EscapeTarget;
float referencePos = Vector2.DistanceSquared(Character.WorldPosition, t.WorldPosition) > 100 * 100 && HasValidPath(true) ? PathSteering.CurrentPath.CurrentNode.WorldPosition.X : t.WorldPosition.X;
float referencePos = Vector2.DistanceSquared(Character.WorldPosition, t.WorldPosition) > 100 * 100 && HasValidPath(requireNonDirty: true) ? PathSteering.CurrentPath.CurrentNode.WorldPosition.X : t.WorldPosition.X;
Character.AnimController.TargetDir = Character.WorldPosition.X < referencePos ? Direction.Right : Direction.Left;
}
else
@@ -916,9 +916,7 @@ namespace Barotrauma
{
if (SteeringManager is IndoorsSteeringManager pathSteering)
{
if (patrolTarget == null ||
pathSteering.CurrentPath == null ||
!pathSteering.IsPathDirty && (pathSteering.CurrentPath.Finished || pathSteering.CurrentPath.Unreachable))
if (patrolTarget == null || IsCurrentPathUnreachable || IsCurrentPathFinished)
{
newPatrolTargetTimer = Math.Min(newPatrolTargetTimer, newPatrolTargetIntervalMin);
}
@@ -936,8 +934,7 @@ namespace Barotrauma
else if (targetHulls.Any())
{
patrolTarget = ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced);
var path = PathSteering.PathFinder.FindPath(Character.SimPosition, patrolTarget.SimPosition, minGapSize: minGapSize * 1.5f, nodeFilter: n => PatrolNodeFilter(n));
var path = PathSteering.PathFinder.FindPath(Character.SimPosition, patrolTarget.SimPosition, Character.Submarine, minGapSize: minGapSize * 1.5f, nodeFilter: n => PatrolNodeFilter(n));
if (path.Unreachable)
{
//can't go to this room, remove it from the list and try another room
@@ -2331,34 +2328,32 @@ namespace Barotrauma
SelectedAiTarget.Entity is Character c && VisibleHulls.Contains(c.CurrentHull))
{
// Steer towards the target if in the same room and swimming
Vector2 dir = Vector2.Normalize(SelectedAiTarget.Entity.WorldPosition - Character.WorldPosition);
if (MathUtils.IsValid(dir))
{
SteeringManager.SteeringManual(deltaTime, dir);
}
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SelectedAiTarget.Entity.WorldPosition - Character.WorldPosition));
}
else
{
// Use path finding
PathSteering.SteeringSeek(Character.GetRelativeSimPosition(SelectedAiTarget.Entity), weight: 2, minGapWidth: minGapSize);
if (!PathSteering.IsPathDirty && PathSteering.CurrentPath.Unreachable)
{
// Can't reach
State = AIState.Idle;
IgnoreTarget(SelectedAiTarget);
return;
}
}
}
else
{
// Outside
SteeringManager.SteeringSeek(Character.GetRelativeSimPosition(SelectedAiTarget.Entity), 5);
if (Character.AnimController.InWater)
}
if (steeringManager is IndoorsSteeringManager pathSteering)
{
if (!pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
{
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15);
// Can't reach
State = AIState.Idle;
IgnoreTarget(SelectedAiTarget);
}
}
else if (Character.AnimController.InWater)
{
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15);
}
}
#region Targeting
@@ -2510,6 +2505,11 @@ namespace Barotrauma
else if (targetingFromOutsideToInside)
{
targetingTag = "room";
if (item.Submarine?.Info.IsRuin != null)
{
// Ignore ruin items when the creature is outside.
continue;
}
}
}
else if (targetingTag == "nasonov")
@@ -115,6 +115,11 @@ namespace Barotrauma
IsPathDirty = true;
}
public void SteeringSeekSimple(Vector2 targetSimPos, float weight = 1)
{
steering += base.DoSteeringSeek(targetSimPos, weight);
}
public void SteeringSeek(Vector2 target, float weight, float minGapWidth = 0, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisiblity = true)
{
steering += CalculateSteeringSeek(target, weight, minGapWidth, startNodeFilter, endNodeFilter, nodeFilter, checkVisiblity);
@@ -164,7 +169,7 @@ namespace Barotrauma
private Vector2 CalculateSteeringSeek(Vector2 target, float weight, float minGapSize = 0, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisibility = true)
{
bool needsNewPath = currentPath == null || currentPath.Unreachable;
bool needsNewPath = currentPath == null || currentPath.Unreachable || currentPath.Finished;
if (!needsNewPath && character.Submarine != null && character.Params.PathFinderPriority > 0.5f)
{
Vector2 targetDiff = target - currentTarget;
@@ -194,16 +199,8 @@ namespace Barotrauma
SkipCurrentPathNodes();
currentTarget = target;
Vector2 currentPos = host.SimPosition;
if (character != null && character.Submarine == null)
{
var targetHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(target), null, false);
if (targetHull != null && targetHull.Submarine != null)
{
currentPos -= targetHull.Submarine.SimPosition;
}
}
pathFinder.InsideSubmarine = character.Submarine != null;
pathFinder.ApplyPenaltyToOutsideNodes = character.PressureProtection <= 0;
pathFinder.InsideSubmarine = character.Submarine != null && !character.Submarine.Info.IsRuin;
pathFinder.ApplyPenaltyToOutsideNodes = character.Submarine != null && character.PressureProtection <= 0;
var newPath = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", minGapSize, startNodeFilter, endNodeFilter, nodeFilter, checkVisibility: checkVisibility);
bool useNewPath = needsNewPath || currentPath == null || currentPath.CurrentNode == null || character.Submarine != null && findPathTimer < -1 && Math.Abs(character.AnimController.TargetMovement.X) <= 0;
if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
@@ -218,7 +215,7 @@ namespace Barotrauma
// Use the new path if it has significantly lower cost (don't change the path if it has marginally smaller cost. This reduces navigating backwards due to new path that is calculated from the node just behind us).
float t = (float)currentPath.CurrentIndex / (currentPath.Nodes.Count - 1);
useNewPath = newPath.Cost < currentPath.Cost * MathHelper.Lerp(0.95f, 0, t);
if (!useNewPath && character.Submarine != null)
if (!useNewPath)
{
// It's possible that the current path was calculated from a start point that is no longer valid.
// Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
@@ -322,15 +319,26 @@ namespace Barotrauma
doorsChecked = true;
}
Vector2 pos = host.SimPosition;
if (character != null && CurrentPath.CurrentNode?.Submarine != null)
if (character != null && CurrentPath.CurrentNode != null)
{
if (character.Submarine == null)
var nodeSub = CurrentPath.CurrentNode.Submarine;
if (nodeSub != null)
{
pos -= CurrentPath.CurrentNode.Submarine.SimPosition;
if (character.Submarine == null)
{
// Going inside
pos -= ConvertUnits.ToSimUnits(nodeSub.Position);
}
else if (character.Submarine != nodeSub)
{
// Different subs
pos -= ConvertUnits.ToSimUnits(nodeSub.Position - character.Submarine.Position);
}
}
else if (character.Submarine != currentPath.CurrentNode.Submarine)
else if (character.Submarine != null)
{
pos -= ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position);
// Going outside
pos += ConvertUnits.ToSimUnits(character.Submarine.Position);
}
}
bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater;
@@ -724,7 +724,10 @@ namespace Barotrauma
}
if (retreatTarget != null && character.CurrentHull != retreatTarget)
{
TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true),
TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true)
{
UsePathingOutside = false
},
onAbandon: () =>
{
if (Enemy != null && HumanAIController.VisibleHulls.Contains(Enemy.CurrentHull))
@@ -783,6 +786,7 @@ namespace Barotrauma
TryAddSubObjective(ref followTargetObjective,
constructor: () => new AIObjectiveGoTo(Enemy, character, objectiveManager, repeat: true, getDivingGearIfNeeded: true, closeEnough: 50)
{
UsePathingOutside = false,
IgnoreIfTargetDead = true,
DialogueIdentifier = "dialogcannotreachtarget",
TargetName = Enemy.DisplayName,
@@ -334,7 +334,7 @@ namespace Barotrauma
continue;
}
// Don't allow to go outside if not already outside.
var path = PathSteering.PathFinder.FindPath(character.SimPosition, hull.SimPosition, nodeFilter: node => node.Waypoint.CurrentHull != null);
var path = PathSteering.PathFinder.FindPath(character.SimPosition, hull.SimPosition, character.Submarine, nodeFilter: node => node.Waypoint.CurrentHull != null);
if (path.Unreachable)
{
HumanAIController.UnreachableHulls.Add(hull);
@@ -323,7 +323,7 @@ namespace Barotrauma
// This is relatively expensive, so let's do this only when it significantly improves the behavior.
// Only allow one path find call per frame.
hasCalledPathFinder = true;
var path = PathSteering.PathFinder.FindPath(character.SimPosition, item.SimPosition, errorMsgStr: $"AIObjectiveGetItem {character.DisplayName}", nodeFilter: node => node.Waypoint.CurrentHull != null);
var path = PathSteering.PathFinder.FindPath(character.SimPosition, item.SimPosition, character.Submarine, errorMsgStr: $"AIObjectiveGetItem {character.DisplayName}", nodeFilter: node => node.Waypoint.CurrentHull != null);
if (path.Unreachable) { continue; }
}
currItemPriority = itemPriority;
@@ -27,6 +27,7 @@ namespace Barotrauma
public bool followControlledCharacter;
public bool mimic;
public bool SpeakIfFails { get; set; } = true;
public bool UsePathingOutside { get; set; } = true;
public float extraDistanceWhileSwimming;
public float extraDistanceOutsideSub;
@@ -121,13 +122,14 @@ namespace Barotrauma
}
private readonly float avoidLookAheadDistance = 5;
private readonly float pathWaitingTime = 3;
public AIObjectiveGoTo(ISpatialEntity target, Character character, AIObjectiveManager objectiveManager, bool repeat = false, bool getDivingGearIfNeeded = true, float priorityModifier = 1, float closeEnough = 0)
: base(character, objectiveManager, priorityModifier)
{
Target = target;
this.repeat = repeat;
waitUntilPathUnreachable = 3.0f;
waitUntilPathUnreachable = pathWaitingTime;
this.getDivingGearIfNeeded = getDivingGearIfNeeded;
if (Target is Item i)
{
@@ -186,7 +188,6 @@ namespace Barotrauma
// Wait
character.AIController.SteeringManager.Reset();
}
waitUntilPathUnreachable -= deltaTime;
if (!character.IsClimbing)
{
character.SelectedConstruction = null;
@@ -222,11 +223,13 @@ namespace Barotrauma
{
Abandon = true;
}
else if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable && !PathSteering.IsPathDirty)
else if (HumanAIController.IsCurrentPathUnreachable)
{
waitUntilPathUnreachable -= deltaTime;
SteeringManager.Reset();
if (waitUntilPathUnreachable < 0)
{
waitUntilPathUnreachable = pathWaitingTime;
if (repeat)
{
SpeakCannotReach();
@@ -325,25 +328,29 @@ namespace Barotrauma
}
else
{
SeekGaps(maxGapDistance);
seekGapsTimer = seekGapsInterval * Rand.Range(0.1f, 1.1f);
if (TargetGap != null)
bool isRuins = character.Submarine?.Info.IsRuin != null || Target.Submarine?.Info.IsRuin != null;
if (!isRuins || !HumanAIController.HasValidPath(requireNonDirty: true, requireUnfinished: true))
{
// Check that nothing is blocking the way
Vector2 rayStart = character.SimPosition;
Vector2 rayEnd = TargetGap.SimPosition;
if (TargetGap.Submarine != null && character.Submarine == null)
SeekGaps(maxGapDistance);
seekGapsTimer = seekGapsInterval * Rand.Range(0.1f, 1.1f);
if (TargetGap != null)
{
rayStart -= TargetGap.Submarine.SimPosition;
}
else if (TargetGap.Submarine == null && character.Submarine != null)
{
rayEnd -= character.Submarine.SimPosition;
}
var closestBody = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true);
if (closestBody != null)
{
TargetGap = null;
// Check that nothing is blocking the way
Vector2 rayStart = character.SimPosition;
Vector2 rayEnd = TargetGap.SimPosition;
if (TargetGap.Submarine != null && character.Submarine == null)
{
rayStart -= TargetGap.Submarine.SimPosition;
}
else if (TargetGap.Submarine == null && character.Submarine != null)
{
rayEnd -= character.Submarine.SimPosition;
}
var closestBody = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true);
if (closestBody != null)
{
TargetGap = null;
}
}
}
}
@@ -454,19 +461,25 @@ namespace Barotrauma
}
else if (!isInside && HumanAIController.UseIndoorSteeringOutside)
{
if (character.Submarine == null && Target.Submarine != null)
{
targetPos += Target.Submarine.SimPosition;
}
nodeFilter = n => n.Waypoint.Tunnel != null;
nodeFilter = n => n.Waypoint.Submarine == null;
}
PathSteering.SteeringSeek(targetPos, weight: 1,
startNodeFilter: n => (n.Waypoint.CurrentHull == null) == (character.CurrentHull == null),
endNodeFilter: endNodeFilter,
nodeFilter: nodeFilter,
checkVisiblity: CheckVisibility);
if (!isInside && !UsePathingOutside)
{
PathSteering.SteeringSeekSimple(character.GetRelativeSimPosition(Target), 10);
if (character.AnimController.InWater)
{
SteeringManager.SteeringAvoid(deltaTime, avoidLookAheadDistance, weight: 15);
}
}
else
{
PathSteering.SteeringSeek(targetPos, weight: 1,
startNodeFilter: n => (n.Waypoint.CurrentHull == null) == (character.CurrentHull == null),
endNodeFilter: endNodeFilter,
nodeFilter: nodeFilter,
checkVisiblity: CheckVisibility);
}
if (!isInside && (PathSteering.CurrentPath == null || PathSteering.IsPathDirty || PathSteering.CurrentPath.Unreachable))
{
if (useScooter)
@@ -251,7 +251,7 @@ namespace Barotrauma
currentTarget = ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced);
bool isInWrongSub = (character.TeamID == CharacterTeamType.FriendlyNPC && !character.IsEscorted) && character.Submarine.TeamID != character.TeamID;
bool isCurrentHullAllowed = !isInWrongSub && !IsForbidden(character.CurrentHull);
var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsgStr: null, nodeFilter: node =>
var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, character.Submarine, nodeFilter: node =>
{
if (node.Waypoint.CurrentHull == null) { return false; }
// Check that there is no unsafe hulls on the way to the target
@@ -1,7 +1,6 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
@@ -69,7 +68,7 @@ namespace Barotrauma
HumanAIController.ResetEscape();
}
HumanAIController.Escape(deltaTime);
if (HumanAIController.EscapeTarget == null || !HumanAIController.HasValidPath(requireNonDirty: true, requireUnfinished: false))
if (HumanAIController.EscapeTarget == null || HumanAIController.IsCurrentPathUnreachable)
{
Abandon = true;
}
@@ -92,14 +91,16 @@ namespace Barotrauma
{
RemoveSubObjective(ref moveInCaveObjective);
RemoveSubObjective(ref moveOutsideObjective);
// TODO: Check 'repeat' and 'onAbandon' parameters
TryAddSubObjective(ref moveInsideObjective,
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager),
onCompleted: () => moveInsideObjective = null);
onCompleted: () => RemoveSubObjective(ref moveInsideObjective),
onAbandon: () => Abandon = true);
}
else
{
#if DEBUG
DebugConsole.ThrowError("Error with a Return objective: no suitable target for 'moveInsideObjective'");
#endif
}
}
}
@@ -117,8 +118,7 @@ namespace Barotrauma
float closestDistance = float.MaxValue;
foreach (var w in WayPoint.WayPointList)
{
if (w.Tunnel == null) { continue; }
if (w.Tunnel.Type == Level.TunnelType.Cave) { continue; }
if (w.Tunnel != null && w.Tunnel.Type == Level.TunnelType.Cave) { continue; }
if (w.linkedTo.None(l => l is WayPoint linkedWaypoint && linkedWaypoint.Tunnel?.Type == Level.TunnelType.Cave)) { continue; }
float distance = Vector2.DistanceSquared(character.WorldPosition, w.WorldPosition);
if (closestOutsideWaypoint == null || distance < closestDistance)
@@ -131,17 +131,19 @@ namespace Barotrauma
{
RemoveSubObjective(ref moveInsideObjective);
RemoveSubObjective(ref moveOutsideObjective);
// TODO: Check 'repeat' and 'onAbandon' parameters
TryAddSubObjective(ref moveInCaveObjective,
constructor: () => new AIObjectiveGoTo(closestOutsideWaypoint, character, objectiveManager)
{
endNodeFilter = n => n.Waypoint == closestOutsideWaypoint
},
onCompleted: () => moveInCaveObjective = null);
onCompleted: () => RemoveSubObjective(ref moveInCaveObjective),
onAbandon: () => Abandon = true);
}
else
{
#if DEBUG
DebugConsole.ThrowError("Error with a Return objective: no suitable main or side path node target found for 'moveOutsideObjective'");
#endif
}
}
else
@@ -167,14 +169,16 @@ namespace Barotrauma
{
RemoveSubObjective(ref moveInsideObjective);
RemoveSubObjective(ref moveInCaveObjective);
// TODO: Check 'repeat' and 'onAbandon' parameters
TryAddSubObjective(ref moveOutsideObjective,
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager),
onCompleted: () => moveOutsideObjective = null);
onCompleted: () => RemoveSubObjective(ref moveOutsideObjective),
onAbandon: () => Abandon = true);
}
else
{
#if DEBUG
DebugConsole.ThrowError("Error with a Return objective: no suitable target for 'moveOutsideObjective'");
#endif
}
}
}
@@ -182,19 +186,11 @@ namespace Barotrauma
{
if (HumanAIController.IsInsideCave)
{
if (moveOutsideObjective != null)
{
RemoveSubObjective(ref moveOutsideObjective);
moveOutsideObjective = null;
}
RemoveSubObjective(ref moveOutsideObjective);
}
else
{
if (moveInCaveObjective != null)
{
RemoveSubObjective(ref moveInCaveObjective);
moveInCaveObjective = null;
}
RemoveSubObjective(ref moveInCaveObjective);
}
}
usingEscapeBehavior = shouldUseEscapeBehavior;
@@ -119,7 +119,8 @@ namespace Barotrauma
public PathFinder(List<WayPoint> wayPoints, bool isCharacter)
{
nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => (w.Submarine != null == isCharacter) || (isCharacter && w.Tunnel != null)), removeOrphans: true);
var filtered = isCharacter ? wayPoints : wayPoints.FindAll(w => w.Submarine == null);
nodes = PathNode.GenerateNodes(filtered, removeOrphans: true);
foreach (WayPoint wp in wayPoints)
{
wp.OnLinksChanged += WaypointLinksChanged;
@@ -179,17 +180,37 @@ namespace Barotrauma
foreach (PathNode node in nodes)
{
node.TempPosition = node.Position;
if (hostSub != null)
var wpSub = node.Waypoint.Submarine;
if (hostSub != null && wpSub == null)
{
Vector2 diff = node.Waypoint.Submarine != null ?
hostSub.SimPosition - node.Waypoint.Submarine.SimPosition :
hostSub.SimPosition - node.Waypoint.SimPosition;
node.TempPosition -= diff;
// inside and targeting outside
node.TempPosition -= hostSub.SimPosition;
}
else if (wpSub != null && hostSub != null && wpSub != hostSub)
{
// different subs
node.TempPosition -= hostSub.SimPosition - wpSub.SimPosition;
}
else if (hostSub == null && wpSub != null)
{
// Outside and targeting inside
node.TempPosition += wpSub.SimPosition;
}
float xDiff = Math.Abs(start.X - node.TempPosition.X);
float yDiff = Math.Abs(start.Y - node.TempPosition.Y);
if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null) { yDiff += 10.0f; }
node.TempDistance = xDiff + (InsideSubmarine ? yDiff * 10.0f : yDiff); //higher cost for vertical movement when inside the sub
if (InsideSubmarine)
{
//higher cost for vertical movement when inside the sub
if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null)
{
yDiff += 10.0f;
}
node.TempDistance = xDiff + yDiff * 10.0f;
}
else
{
node.TempDistance = xDiff + yDiff;
}
//much higher cost to waypoints that are outside
if (node.Waypoint.CurrentHull == null && ApplyPenaltyToOutsideNodes) { node.TempDistance *= 10.0f; }
@@ -57,7 +57,10 @@ namespace Barotrauma
public void SteeringManual(float deltaTime, Vector2 velocity)
{
steering += velocity;
if (MathUtils.IsValid(velocity))
{
steering += velocity;
}
}
public void Reset()
@@ -374,7 +374,7 @@ namespace Barotrauma
{
//pull the character's mouth to the target character (again with a fluctuating force)
float pullStrength = (float)(Math.Sin(eatTimer) * Math.Max(Math.Sin(eatTimer * 0.5f), 0.0f));
mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength);
}
else
{
@@ -746,7 +746,7 @@ namespace Barotrauma
var arm = GetLimb(armType);
if (arm != null && Math.Abs(arm.body.AngularVelocity) < 10.0f)
{
arm.body.SmoothRotate(MathHelper.Clamp(-arm.body.AngularVelocity, -0.5f, 0.5f), arm.Mass * 50.0f);
arm.body.SmoothRotate(MathHelper.Clamp(-arm.body.AngularVelocity, -0.5f, 0.5f), arm.Mass * 50.0f * CurrentGroundedParams.ArmMoveStrength);
}
//get the elbow to a neutral rotation
@@ -757,7 +757,7 @@ namespace Barotrauma
if (elbow != null)
{
float diff = elbow.JointAngle - (Dir > 0 ? elbow.LowerLimit : elbow.UpperLimit);
forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f);
forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f * CurrentGroundedParams.ArmMoveStrength);
}
}
}
@@ -809,8 +809,8 @@ namespace Barotrauma
{
foreach (Gap gap in currentHull.ConnectedGaps)
{
if (gap.IsHorizontal || gap.Open <= 0.0f) continue;
if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) continue;
if (gap.IsHorizontal || gap.Open <= 0.0f) { continue; }
if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) { continue; }
//if the gap is above us and leads outside, there's no surface to limit the movement
if (!gap.IsRoomToRoom && gap.Position.Y > currentHull.Position.Y)
@@ -830,7 +830,7 @@ namespace Barotrauma
}
}
surfaceLimiter = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 0.4f) - surfacePos;
surfaceLimiter = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 1.0f) - surfacePos;
surfaceLimiter = Math.Max(1.0f, surfaceLimiter);
if (surfaceLimiter > 50.0f) { return; }
}
@@ -921,7 +921,7 @@ namespace Barotrauma
head.body.ApplyTorque(Dir);
}
movement.Y = movement.Y - (surfaceLimiter - 1.0f) * 0.01f;
movement.Y = movement.Y * (1.0f - ((surfaceLimiter - 1.0f) / 50.0f));
}
bool isNotRemote = true;
@@ -1003,7 +1003,10 @@ namespace Barotrauma
rightHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, rightHandPos.X) : Math.Min(-0.3f, rightHandPos.X);
rightHandPos = Vector2.Transform(rightHandPos, rotationMatrix);
float speedMultiplier = Math.Min(character.SpeedMultiplier * (1 - Character.GetRightHandPenalty()), 1.0f);
// Limb hand, Vector2 pos, float force = 1.0f
if (character.Inventory != null && character.Inventory.GetItemInLimbSlot(InvSlotType.RightHand) != null)
{
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
}
HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
}
@@ -1013,6 +1016,10 @@ namespace Barotrauma
leftHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, leftHandPos.X) : Math.Min(-0.3f, leftHandPos.X);
leftHandPos = Vector2.Transform(leftHandPos, rotationMatrix);
float speedMultiplier = Math.Min(character.SpeedMultiplier * (1 - Character.GetLeftHandPenalty()), 1.0f);
if (character.Inventory != null && character.Inventory.GetItemInLimbSlot(InvSlotType.LeftHand) != null)
{
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
}
HandIK(leftHand, handPos + leftHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
}
}
@@ -1154,7 +1161,7 @@ namespace Barotrauma
if (character.SimPosition.Y > ladderSimPos.Y) { climbForce.Y = Math.Min(0.0f, climbForce.Y); }
//apply forces to the collider to move the Character up/down
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
float movementMultiplier = targetMovement.Y < 0 ? 0 : 1;
head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, WalkParams.HeadTorque);
@@ -1383,7 +1390,7 @@ namespace Barotrauma
target.CharacterHealth.CalculateVitality();
if (wasCritical && target.Vitality > 0.0f && Timing.TotalTime > lastReviveTime + 10.0f)
{
character.Info?.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive, character.Position + Vector2.UnitY * 150.0f);
character.Info?.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive);
SteamAchievementManager.OnCharacterRevived(target, character);
lastReviveTime = (float)Timing.TotalTime;
#if SERVER
@@ -1348,19 +1348,19 @@ namespace Barotrauma
string errorMsg = null;
if (!MathUtils.IsValid(body.SimPosition) || Math.Abs(body.SimPosition.X) > 1e10f || Math.Abs(body.SimPosition.Y) > 1e10f)
{
errorMsg = GetBodyName() + " position invalid (" + body.SimPosition + ", character: " + character.Name + "), resetting the ragdoll.";
errorMsg = GetBodyName() + " position invalid (" + body.SimPosition + ", character: " + character.Name + ").";
}
else if (!MathUtils.IsValid(body.LinearVelocity) || Math.Abs(body.LinearVelocity.X) > 1000f || Math.Abs(body.LinearVelocity.Y) > 1000f)
{
errorMsg = GetBodyName() + " velocity invalid (" + body.LinearVelocity + ", character: " + character.Name + "), resetting the ragdoll.";
errorMsg = GetBodyName() + " velocity invalid (" + body.LinearVelocity + ", character: " + character.Name + ").";
}
else if (!MathUtils.IsValid(body.Rotation))
{
errorMsg = GetBodyName() + " rotation invalid (" + body.Rotation + ", character: " + character.Name + "), resetting the ragdoll.";
errorMsg = GetBodyName() + " rotation invalid (" + body.Rotation + ", character: " + character.Name + ").";
}
else if (!MathUtils.IsValid(body.AngularVelocity) || Math.Abs(body.AngularVelocity) > 1000f)
{
errorMsg = GetBodyName() + " angular velocity invalid (" + body.AngularVelocity + ", character: " + character.Name + "), resetting the ragdoll.";
errorMsg = GetBodyName() + " angular velocity invalid (" + body.AngularVelocity + ", character: " + character.Name + ").";
}
if (errorMsg != null)
{
@@ -1469,11 +1469,11 @@ namespace Barotrauma
if (flowForce.LengthSquared() > 0.001f)
{
Collider.ApplyForce(flowForce, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
Collider.ApplyForce(flowForce);
foreach (Limb limb in limbs)
{
if (!limb.InWater) { continue; }
limb.body.ApplyForce(flowForce, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
limb.body.ApplyForce(flowForce);
}
}
}
@@ -1506,7 +1506,6 @@ namespace Barotrauma
if (TorsoPosition.HasValue && MathUtils.IsValid(TorsoPosition.Value)) { height = Math.Max(height, TorsoPosition.Value); }
Vector2 rayEnd = rayStart - new Vector2(0.0f, height);
Vector2 onGroundRayEnd = rayStart - Vector2.UnitY * (Collider.height * 0.5f + Collider.radius + ColliderHeightFromFloor * 1.2f);
Vector2 colliderBottomDisplay = ConvertUnits.ToDisplayUnits(GetColliderBottom());
Fixture standOnFloorFixture = null;
@@ -1587,7 +1586,25 @@ namespace Barotrauma
if (closestFraction == 1) //raycast didn't hit anything
{
floorNormal = Vector2.UnitY;
return (currentHull == null) ? -1000.0f : ConvertUnits.ToSimUnits(currentHull.Rect.Y - currentHull.Rect.Height);
if (CurrentHull == null)
{
return -1000.0f;
}
else
{
float hullBottom = currentHull.Rect.Y - currentHull.Rect.Height;
//check if there's a connected hull below
foreach (var gap in currentHull.ConnectedGaps)
{
if (!gap.IsRoomToRoom || gap.Open < 1.0f || gap.ConnectedDoor != null || gap.IsHorizontal) { continue; }
if (WorldPosition.X > gap.WorldRect.X && WorldPosition.X < gap.WorldRect.Right && gap.WorldPosition.Y < WorldPosition.Y)
{
var lowerHull = gap.linkedTo[0] == currentHull ? gap.linkedTo[1] : gap.linkedTo[0];
hullBottom = Math.Min(hullBottom, lowerHull.Rect.Y - lowerHull.Rect.Height);
}
}
return ConvertUnits.ToSimUnits(hullBottom);
}
}
else
{
@@ -1745,8 +1745,12 @@ namespace Barotrauma
}
else if (IsKeyDown(InputType.Attack))
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && Controlled != this)
{
if ((currentAttackTarget.DamageTarget as Entity)?.Removed ?? false)
{
currentAttackTarget = default(AttackTargetData);
}
currentAttackTarget.AttackLimb?.UpdateAttack(deltaTime, currentAttackTarget.AttackPos, currentAttackTarget.DamageTarget, out _);
}
else if (IsPlayer)
@@ -3670,16 +3674,14 @@ namespace Barotrauma
{
float attackerSkillLevel = attacker.GetSkillLevel("weapons");
attacker.Info?.IncreaseSkillLevel("weapons",
-healthChange * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, 1.0f),
attacker.Position + Vector2.UnitY * 100.0f);
-healthChange * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, 1.0f));
}
}
else if (healthChange > 0.0f)
{
float attackerSkillLevel = attacker.GetSkillLevel("medical");
attacker.Info?.IncreaseSkillLevel("medical",
healthChange * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, 1.0f),
attacker.Position + Vector2.UnitY * 100.0f);
healthChange * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, 1.0f));
}
}
@@ -3927,7 +3929,7 @@ namespace Barotrauma
}
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log);
public void Revive()
public void Revive(bool removeAllAfflictions = true)
{
if (Removed)
{
@@ -3938,7 +3940,14 @@ namespace Barotrauma
aiTarget?.Remove();
aiTarget = new AITarget(this);
CharacterHealth.RemoveAllAfflictions();
if (removeAllAfflictions)
{
CharacterHealth.RemoveAllAfflictions();
}
else
{
CharacterHealth.RemoveNegativeAfflictions();
}
SetAllDamage(0.0f, 0.0f, 0.0f);
Oxygen = 100.0f;
Bloodloss = 0.0f;
@@ -4284,12 +4293,8 @@ namespace Barotrauma
}
if (Submarine == null && target.Submarine != null)
{
if (AIController == null || !(AIController.SteeringManager is IndoorsSteeringManager))
{
// outside and targeting inside
// doesn't work with inside steering
targetPos += target.Submarine.SimPosition;
}
// outside and targeting inside
targetPos += target.Submarine.SimPosition;
}
else if (Submarine != null && target.Submarine == null)
{
@@ -4376,14 +4381,14 @@ namespace Barotrauma
public bool GiveTalent(TalentPrefab talentPrefab, bool addingFirstTime = true)
{
if (addingFirstTime)
{
if (!info.UnlockedTalents.Add(talentPrefab.Identifier)) { return false; }
}
if (info == null) { return false; }
info.UnlockedTalents.Add(talentPrefab.Identifier);
if (characterTalents.Any(t => t.Prefab == talentPrefab)) { return false; }
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 });
@@ -1162,7 +1162,7 @@ namespace Barotrauma
return (int)(salary * Job.Prefab.PriceMultiplier);
}
public void IncreaseSkillLevel(string skillIdentifier, float increase, Vector2 pos, bool gainedFromApprenticeship = false)
public void IncreaseSkillLevel(string skillIdentifier, float increase, bool gainedFromApprenticeship = false)
{
if (Job == null || (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) || Character == null) { return; }
@@ -1190,10 +1190,10 @@ namespace Barotrauma
}
}
OnSkillChanged(skillIdentifier, prevLevel, newLevel, pos);
OnSkillChanged(skillIdentifier, prevLevel, newLevel);
}
public void SetSkillLevel(string skillIdentifier, float level, Vector2 pos)
public void SetSkillLevel(string skillIdentifier, float level)
{
if (Job == null) { return; }
@@ -1201,19 +1201,19 @@ namespace Barotrauma
if (skill == null)
{
Job.Skills.Add(new Skill(skillIdentifier, level));
OnSkillChanged(skillIdentifier, 0.0f, level, pos);
OnSkillChanged(skillIdentifier, 0.0f, level);
}
else
{
float prevLevel = skill.Level;
skill.Level = level;
OnSkillChanged(skillIdentifier, prevLevel, skill.Level, pos);
OnSkillChanged(skillIdentifier, prevLevel, skill.Level);
}
}
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos);
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel);
public void GiveExperience(int amount, float popupOffset = 0f, bool isMissionExperience = false)
public void GiveExperience(int amount, bool isMissionExperience = false)
{
int prevAmount = ExperiencePoints;
@@ -1229,7 +1229,7 @@ namespace Barotrauma
if (amount < 0) { return; }
ExperiencePoints += amount;
OnExperienceChanged(prevAmount, ExperiencePoints, Character.Position + Vector2.UnitY * (150.0f + popupOffset));
OnExperienceChanged(prevAmount, ExperiencePoints);
}
public void SetExperience(int newExperience)
@@ -1238,7 +1238,7 @@ namespace Barotrauma
int prevAmount = ExperiencePoints;
ExperiencePoints = newExperience;
OnExperienceChanged(prevAmount, ExperiencePoints, Character.Position + Vector2.UnitY * 150.0f);
OnExperienceChanged(prevAmount, ExperiencePoints);
}
const int BaseExperienceRequired = 50;
@@ -1295,7 +1295,7 @@ namespace Barotrauma
return BaseExperienceRequired + AddedExperienceRequiredPerLevel * level;
}
partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos);
partial void OnExperienceChanged(int prevAmount, int newAmount);
public void Rename(string newName)
{
@@ -206,7 +206,11 @@ namespace Barotrauma
public float Stun
{
get { return stunAffliction.Strength; }
set { stunAffliction.Strength = MathHelper.Clamp(value, 0.0f, stunAffliction.Prefab.MaxStrength); }
set
{
if (Character.GodMode) { return; }
stunAffliction.Strength = MathHelper.Clamp(value, 0.0f, stunAffliction.Prefab.MaxStrength);
}
}
public float StunTimer { get; private set; }
@@ -629,6 +633,22 @@ namespace Barotrauma
CalculateVitality();
}
public void RemoveNegativeAfflictions()
{
// also don't remove genetic effects, even if they're negative
foreach (LimbHealth limbHealth in limbHealths)
{
limbHealth.Afflictions.RemoveAll(a => !a.Prefab.IsBuff && a.Prefab.AfflictionType != "geneticmaterialbuff" && a.Prefab.AfflictionType != "geneticmaterialdebuff");
}
afflictions.RemoveAll(a => !irremovableAfflictions.Contains(a) && !a.Prefab.IsBuff && a.Prefab.AfflictionType != "geneticmaterialbuff" && a.Prefab.AfflictionType != "geneticmaterialdebuff");
foreach (Affliction affliction in irremovableAfflictions)
{
affliction.Strength = 0.0f;
}
CalculateVitality();
}
private void AddLimbAffliction(Limb limb, Affliction newAffliction, bool allowStacking = true)
{
if (!newAffliction.Prefab.LimbSpecific || limb == null) { return; }
@@ -68,9 +68,20 @@ namespace Barotrauma
}
}
public class PreviewItem
{
public readonly string ItemIdentifier;
public readonly bool ShowPreview;
public PreviewItem(string itemIdentifier, bool showPreview)
{
ItemIdentifier = itemIdentifier;
ShowPreview = showPreview;
}
}
public readonly Dictionary<int, XElement> ItemSets = new Dictionary<int, XElement>();
public readonly Dictionary<int, List<string>> ItemIdentifiers = new Dictionary<int, List<string>>();
public readonly Dictionary<int, Dictionary<string, bool>> ShowItemPreview = new Dictionary<int, Dictionary<string, bool>>();
public readonly Dictionary<int, List<PreviewItem>> PreviewItems = new Dictionary<int, List<PreviewItem>>();
public readonly List<SkillPrefab> Skills = new List<SkillPrefab>();
public readonly List<AutonomousObjective> AutonomousObjectives = new List<AutonomousObjective>();
public readonly List<string> AppropriateOrders = new List<string>();
@@ -220,8 +231,7 @@ namespace Barotrauma
{
case "itemset":
ItemSets.Add(variant, subElement);
ItemIdentifiers[variant] = new List<string>();
ShowItemPreview[variant] = new Dictionary<string, bool>();
PreviewItems[variant] = new List<PreviewItem>();
loadItemIdentifiers(subElement, variant);
variant++;
break;
@@ -264,8 +274,7 @@ namespace Barotrauma
}
else
{
ItemIdentifiers[variant].Add(itemIdentifier);
ShowItemPreview[variant][itemIdentifier] = itemElement.GetAttributeBool("showpreview", true);
PreviewItems[variant].Add(new PreviewItem(itemIdentifier, itemElement.GetAttributeBool("showpreview", true)));
}
loadItemIdentifiers(itemElement, variant);
}
@@ -759,6 +759,10 @@ namespace Barotrauma
appliedDamageModifiers.AddRange(tempModifiers);
}
var result = new AttackResult(afflictionsCopy, this, appliedDamageModifiers);
if (result.Afflictions.None())
{
playSound = false;
}
AddDamageProjSpecific(playSound, result);
float bleedingDamage = 0;
@@ -11,12 +11,12 @@ namespace Barotrauma
{
public enum AnimationType
{
NotDefined,
Walk,
Run,
SwimSlow,
SwimFast,
Crouch
NotDefined = 0,
Walk = 1,
Run = 2,
Crouch = 3,
SwimSlow = 4,
SwimFast = 5
}
abstract class GroundedMovementParams : AnimationParams
@@ -597,7 +597,7 @@ namespace Barotrauma
[Serialize(float.NaN, true, description: "The orientation of the sprite as drawn on the sprite sheet. Overrides the value defined in the Ragdoll settings."), Editable(-360, 360, ValueStep = 90, DecimalCount = 0)]
public float SpriteOrientation { get; set; }
[Serialize(LimbType.None, true, description: "If set, the limb sprite will use the same sprite depth as the specified limb. Generally only useful for limbs that get added on the ragdoll on the fly (e.g. extra limbs added via gene splicing).")]
[Serialize(LimbType.None, true, description: "If set, the limb sprite will use the same sprite depth as the specified limb. Generally only useful for limbs that get added on the ragdoll on the fly (e.g. extra limbs added via gene splicing).")]
public LimbType InheritLimbDepth { get; set; }
[Serialize(0f, true), Editable(MinValueFloat = 0, MaxValueFloat = 500)]
@@ -12,9 +12,12 @@ namespace Barotrauma.Abilities
Ranged = 2
};
private readonly bool hittingCountsAsAiming;
private readonly WeaponType weapontype;
public AbilityConditionIsAiming(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
{
hittingCountsAsAiming = conditionElement.GetAttributeBool("hittingcountsasaiming", false);
switch (conditionElement.GetAttributeString("weapontype", ""))
{
case "melee":
@@ -28,7 +31,6 @@ namespace Barotrauma.Abilities
protected override bool MatchesConditionSpecific()
{
bool aimingCorrectItem = false;
if (character.AnimController is HumanoidAnimController animController)
{
foreach (Item item in character.HeldItems)
@@ -36,19 +38,23 @@ namespace Barotrauma.Abilities
switch (weapontype)
{
case WeaponType.Melee:
aimingCorrectItem |= item.GetComponent<MeleeWeapon>() != null && animController.IsAimingMelee;
var meleeWeapon = item.GetComponent<MeleeWeapon>();
if (meleeWeapon != null)
{
if (animController.IsAimingMelee || (meleeWeapon.Hitting && hittingCountsAsAiming)) { return true; }
}
break;
case WeaponType.Ranged:
aimingCorrectItem |= item.GetComponent<RangedWeapon>() != null && animController.IsAiming;
if (animController.IsAiming && item.GetComponent<RangedWeapon>() != null) { return true; }
break;
default:
aimingCorrectItem |= animController.IsAiming || animController.IsAimingMelee;
if (animController.IsAiming || animController.IsAimingMelee) { return true; }
break;
}
}
}
return aimingCorrectItem;
return false;
}
}
}
@@ -16,7 +16,7 @@ namespace Barotrauma.Abilities
{
if ((abilityObject as IAbilityValue)?.Value is float skillIncrease)
{
Character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, Character.Position + Vector2.UnitY * 175.0f);
Character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease);
}
else
{
@@ -1,21 +0,0 @@
using System.Xml.Linq;
namespace Barotrauma.Abilities
{
class CharacterAbilityGiveMissionCount : CharacterAbility
{
private readonly int amount;
public CharacterAbilityGiveMissionCount(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
{
amount = abilityElement.GetAttributeInt("amount", 0);
}
public override void InitializeAbility(bool addingFirstTime)
{
if (!addingFirstTime) { return; }
if (!(GameMain.GameSession?.Campaign is CampaignMode campaign)) { return; }
campaign.Settings.AddedMissionCount += amount;
}
}
}
@@ -49,13 +49,12 @@ namespace Barotrauma.Abilities
{
var skill = character.Info?.Job?.Skills?.GetRandom();
if (skill == null) { return; }
character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease);
}
else
{
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease);
}
}
}
}
@@ -13,7 +13,7 @@ namespace Barotrauma.Abilities
private void ApplyEffectSpecific()
{
Character.Revive();
Character.Revive(removeAllAfflictions: false);
}
protected override void ApplyEffect()
@@ -21,6 +21,7 @@ namespace Barotrauma.Abilities
{
foreach (var talent in talentOption.Talents)
{
if (talent == CharacterTalent.Prefab) { continue; }
Character.GiveTalent(talent);
}
}
@@ -14,7 +14,7 @@ namespace Barotrauma.Abilities
{
if (abilityObject is AbilitySkillGain abilitySkillGain && !abilitySkillGain.GainedFromApprenticeship && abilitySkillGain.Character != Character)
{
Character.Info?.IncreaseSkillLevel(abilitySkillGain.String, 1.0f, Character.Position + Vector2.UnitY * 175.0f, gainedFromApprenticeship: true);
Character.Info?.IncreaseSkillLevel(abilitySkillGain.String, 1.0f, gainedFromApprenticeship: true);
}
}
}
@@ -18,7 +18,7 @@ namespace Barotrauma.Abilities
if (skillIdentifier != lastSkillIdentifier)
{
lastSkillIdentifier = skillIdentifier;
Character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f, Character.Position + Vector2.UnitY * 175.0f);
Character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f);
}
}
}
@@ -13,6 +13,8 @@ namespace Barotrauma
public readonly TalentPrefab Prefab;
public bool AddedThisRound = true;
private readonly Dictionary<AbilityEffectType, List<CharacterAbilityGroupEffect>> characterAbilityGroupEffectDictionary = new Dictionary<AbilityEffectType, List<CharacterAbilityGroupEffect>>();
private readonly List<CharacterAbilityGroupInterval> characterAbilityGroupIntervals = new List<CharacterAbilityGroupInterval>();