private void NextNode(bool checkDoors) { if (checkDoors) { CheckDoorsInPath(); } currentPath.SkipToNextNode(); }
private Vector2 DiffToCurrentNode() { if (currentPath == null || currentPath.Unreachable) { return(Vector2.Zero); } if (currentPath.Finished) { Vector2 pos2 = host.SimPosition; if (character != null && character.Submarine == null && CurrentPath.Nodes.Count > 0 && CurrentPath.Nodes.Last().Submarine != null) { pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition; } return(currentTarget - pos2); } if (canOpenDoors && !character.LockHands && buttonPressCooldown <= 0.0f) { CheckDoorsInPath(); } Vector2 pos = host.SimPosition; if (character != null && currentPath.CurrentNode != null) { if (CurrentPath.CurrentNode.Submarine != null) { if (character.Submarine == null) { pos -= CurrentPath.CurrentNode.Submarine.SimPosition; } else if (character.Submarine != currentPath.CurrentNode.Submarine) { pos -= FarseerPhysics.ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position); } } } bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater; //only humanoids can climb ladders if (!isDiving && character.AnimController is HumanoidAnimController && IsNextLadderSameAsCurrent) { if (character.SelectedConstruction != currentPath.CurrentNode.Ladders.Item && currentPath.CurrentNode.Ladders.Item.IsInsideTrigger(character.WorldPosition)) { currentPath.CurrentNode.Ladders.Item.TryInteract(character, false, true); } } var collider = character.AnimController.Collider; if (character.IsClimbing && !isDiving) { Vector2 diff = currentPath.CurrentNode.SimPosition - pos; bool nextLadderSameAsCurrent = IsNextLadderSameAsCurrent; if (nextLadderSameAsCurrent) { //climbing ladders -> don't move horizontally diff.X = 0.0f; } //at the same height as the waypoint if (Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y) < (collider.height / 2 + collider.radius) * 1.25f) { float heightFromFloor = character.AnimController.GetColliderBottom().Y - character.AnimController.FloorY; if (heightFromFloor <= 0.0f) { diff.Y = Math.Max(diff.Y, 1.0f); } bool aboveFloor = heightFromFloor > 0 && heightFromFloor < collider.height * 1.5f; if (aboveFloor || IsNextNodeLadder) { if (!nextLadderSameAsCurrent) { character.AnimController.Anim = AnimController.Animation.None; } currentPath.SkipToNextNode(); } } else if (nextLadderSameAsCurrent) { //if the current node is below the character and the next one is above (or vice versa) //and both are on ladders, we can skip directly to the next one //e.g. no point in going down to reach the starting point of a path when we could go directly to the one above if (Math.Sign(currentPath.CurrentNode.WorldPosition.Y - character.WorldPosition.Y) != Math.Sign(currentPath.NextNode.WorldPosition.Y - character.WorldPosition.Y)) { currentPath.SkipToNextNode(); } } return(diff); } else if (character.AnimController.InWater) { // If the character is underwater, we don't need the ladders anymore if (character.IsClimbing && isDiving) { character.AnimController.Anim = AnimController.Animation.None; character.SelectedConstruction = null; } float multiplier = MathHelper.Lerp(1, 10, MathHelper.Clamp(collider.LinearVelocity.Length() / 10, 0, 1)); if (Vector2.DistanceSquared(pos, currentPath.CurrentNode.SimPosition) < MathUtils.Pow(collider.radius * 2 * multiplier, 2)) { currentPath.SkipToNextNode(); } } else { Vector2 colliderBottom = character.AnimController.GetColliderBottom(); Vector2 colliderSize = collider.GetSize(); Vector2 velocity = collider.LinearVelocity; // Cannot use the head position, because not all characters have head or it can be below the total height of the character float characterHeight = colliderSize.Y + character.AnimController.ColliderHeightFromFloor; float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X); bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y; bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight; float margin = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1)); float targetDistance = collider.radius * margin; if (horizontalDistance < targetDistance && isAboveFeet && isNotTooHigh) { currentPath.SkipToNextNode(); } } if (currentPath.CurrentNode == null) { return(Vector2.Zero); } return(currentPath.CurrentNode.SimPosition - pos); }
private Vector2 DiffToCurrentNode() { if (currentPath == null || currentPath.Finished || currentPath.Unreachable) { return(Vector2.Zero); } if (currentPath.Finished) { Vector2 pos2 = host.SimPosition; if (character != null && character.Submarine == null && CurrentPath.Nodes.Last().Submarine != null) { //todo: take multiple subs into account pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition; } return(currentTarget - pos2); } if (canOpenDoors && !character.LockHands) { CheckDoorsInPath(); } Vector2 pos = host.SimPosition; if (character != null && currentPath.CurrentNode != null) { if (CurrentPath.CurrentNode.Submarine != null) { if (character.Submarine == null) { pos -= CurrentPath.CurrentNode.Submarine.SimPosition; } else if (character.Submarine != currentPath.CurrentNode.Submarine) { pos -= FarseerPhysics.ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position); } } } if (currentPath.CurrentNode != null && currentPath.CurrentNode.Ladders != null) { if (character.SelectedConstruction != currentPath.CurrentNode.Ladders.Item && currentPath.CurrentNode.Ladders.Item.IsInsideTrigger(character.WorldPosition)) { currentPath.CurrentNode.Ladders.Item.TryInteract(character, false, true); } } var collider = character.AnimController.Collider; Vector2 colliderBottom = character.AnimController.GetColliderBottom(); if (Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X) < collider.radius * 2 && currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y && currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + 1.5f) { currentPath.SkipToNextNode(); } if (currentPath.CurrentNode == null) { return(Vector2.Zero); } if (character.AnimController.Anim == AnimController.Animation.Climbing) { Vector2 diff = currentPath.CurrentNode.SimPosition - pos; if (currentPath.CurrentNode.Ladders != null) { //climbing ladders -> don't move horizontally diff.X = 0.0f; //at the same height as the waypoint if (Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y) < collider.height / 2 + collider.radius) { float heightFromFloor = character.AnimController.GetColliderBottom().Y - character.AnimController.FloorY; //we can safely skip to the next waypoint if the character is at a safe height above the floor, //or if the next waypoint in the path is also on ladders if ((heightFromFloor > 0.0f && heightFromFloor < collider.height) || (currentPath.NextNode != null && currentPath.NextNode.Ladders != null)) { currentPath.SkipToNextNode(); } } } character.AnimController.IgnorePlatforms = false; return(diff); } return(currentPath.CurrentNode.SimPosition - pos); }
private Vector2 DiffToCurrentNode() { if (currentPath == null || currentPath.Unreachable) { return(Vector2.Zero); } if (currentPath.Finished) { Vector2 pos2 = host.SimPosition; if (character != null && character.Submarine == null && CurrentPath.Nodes.Count > 0 && CurrentPath.Nodes.Last().Submarine != null) { pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition; } return(currentTarget - pos2); } if (canOpenDoors && !character.LockHands && buttonPressCooldown <= 0.0f) { CheckDoorsInPath(); } Vector2 pos = host.SimPosition; if (character != null && currentPath.CurrentNode != null) { if (CurrentPath.CurrentNode.Submarine != null) { if (character.Submarine == null) { pos -= CurrentPath.CurrentNode.Submarine.SimPosition; } else if (character.Submarine != currentPath.CurrentNode.Submarine) { pos -= ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position); } } } bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater; // Only humanoids can climb ladders bool canClimb = character.AnimController is HumanoidAnimController; var ladders = GetNextLadder(); if (canClimb && !isDiving && ladders != null && character.SelectedConstruction != ladders.Item) { if (IsNextNodeLadder || currentPath.CurrentIndex == currentPath.Nodes.Count - 1) { if (character.CanInteractWith(ladders.Item)) { ladders.Item.TryInteract(character, false, true); } else { // Cannot interact with the current (or next) ladder, // Try to select the previous ladder, unless it's already selected, unless the previous ladder is not adjacent to the current ladder. // The intention of this code is to prevent the bots from dropping from the "double ladders". var previousLadders = currentPath.PrevNode?.Ladders; if (previousLadders != null && previousLadders != ladders && character.SelectedConstruction != previousLadders.Item && character.CanInteractWith(previousLadders.Item) && Math.Abs(previousLadders.Item.WorldPosition.X - ladders.Item.WorldPosition.X) < 5) { previousLadders.Item.TryInteract(character, false, true); } } } else if (!IsNextLadderSameAsCurrent && character.SelectedConstruction?.GetComponent <Ladder>() != null && character.CanInteractWith(ladders.Item)) { ladders.Item.TryInteract(character, false, true); } } var collider = character.AnimController.Collider; if (character.IsClimbing && !isDiving) { Vector2 diff = currentPath.CurrentNode.SimPosition - pos; Ladder nextLadder = GetNextLadder(); bool nextLadderSameAsCurrent = IsNextLadderSameAsCurrent; if (nextLadderSameAsCurrent) { //climbing ladders -> don't move horizontally diff.X = 0.0f; } //at the same height as the waypoint if (Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y) < (collider.height / 2 + collider.radius) * 1.25f) { float heightFromFloor = character.AnimController.GetColliderBottom().Y - character.AnimController.FloorY; if (heightFromFloor <= 0.0f) { diff.Y = Math.Max(diff.Y, 1.0f); } // We need some margin, because if a hatch has closed, it's possible that the height from floor is slightly negative. float margin = 0.1f; bool isAboveFloor = heightFromFloor > -margin && heightFromFloor < collider.height * 1.5f; // If the next waypoint is horizontally far, we don't want to keep holding the ladders if (isAboveFloor && (nextLadder == null || Math.Abs(currentPath.CurrentNode.WorldPosition.X - currentPath.NextNode.WorldPosition.X) > 50)) { character.AnimController.Anim = AnimController.Animation.None; character.SelectedConstruction = null; } else if (nextLadder != null && !nextLadderSameAsCurrent) { // Try to change the ladder (hatches between two submarines) if (character.SelectedConstruction != nextLadder.Item && nextLadder.Item.IsInsideTrigger(character.WorldPosition)) { nextLadder.Item.TryInteract(character, false, true); } } if (nextLadder != null || isAboveFloor) { currentPath.SkipToNextNode(); } } else if (nextLadder != null) { //if the current node is below the character and the next one is above (or vice versa) //and both are on ladders, we can skip directly to the next one //e.g. no point in going down to reach the starting point of a path when we could go directly to the one above if (Math.Sign(currentPath.CurrentNode.WorldPosition.Y - character.WorldPosition.Y) != Math.Sign(currentPath.NextNode.WorldPosition.Y - character.WorldPosition.Y)) { currentPath.SkipToNextNode(); } } return(diff); } else if (!canClimb || character.AnimController.InWater) { // If the character is underwater, we don't need the ladders anymore if (character.IsClimbing && isDiving) { character.AnimController.Anim = AnimController.Animation.None; character.SelectedConstruction = null; } var door = currentPath.CurrentNode.ConnectedDoor; bool blockedByDoor = door != null && !door.IsOpen && !door.IsBroken; if (!blockedByDoor) { float multiplier = MathHelper.Lerp(1, 10, MathHelper.Clamp(collider.LinearVelocity.Length() / 10, 0, 1)); float targetDistance = collider.GetSize().X *multiplier; float horizontalDistance = Math.Abs(character.WorldPosition.X - currentPath.CurrentNode.WorldPosition.X); float verticalDistance = Math.Abs(character.WorldPosition.Y - currentPath.CurrentNode.WorldPosition.Y); if (character.CurrentHull != currentPath.CurrentNode.CurrentHull) { verticalDistance *= 2; } float distance = horizontalDistance + verticalDistance; if (ConvertUnits.ToSimUnits(distance) < targetDistance) { currentPath.SkipToNextNode(); } } } else if (!IsNextLadderSameAsCurrent) { // Walking horizontally Vector2 colliderBottom = character.AnimController.GetColliderBottom(); Vector2 colliderSize = collider.GetSize(); Vector2 velocity = collider.LinearVelocity; // If the character is smaller than this, it would fail to use the waypoint nodes because they are always too high. float minHeight = 1; // Cannot use the head position, because not all characters have head or it can be below the total height of the character float characterHeight = Math.Max(colliderSize.Y + character.AnimController.ColliderHeightFromFloor, minHeight); float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X); bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y; bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight; var door = currentPath.CurrentNode.ConnectedDoor; bool blockedByDoor = door != null && !door.IsOpen && !door.IsBroken; float margin = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1)); float targetDistance = collider.radius * margin; if (horizontalDistance < targetDistance && isAboveFeet && isNotTooHigh && !blockedByDoor) { currentPath.SkipToNextNode(); } } if (currentPath.CurrentNode == null) { return(Vector2.Zero); } return(currentPath.CurrentNode.SimPosition - pos); }