private void CheckDoorsInPath() { if (!canOpenDoors) { return; } for (int i = 0; i < 5; i++) { WayPoint currentWaypoint = null; WayPoint nextWaypoint = null; Door door = null; bool shouldBeOpen = false; if (currentPath.Nodes.Count == 1) { door = currentPath.Nodes.First().ConnectedDoor; shouldBeOpen = door != null; if (i > 0) { break; } } else { bool closeDoors = character.IsBot && character.IsInFriendlySub || character.Params.AI != null && character.Params.AI.KeepDoorsClosed; if (i == 0 || !closeDoors) { currentWaypoint = currentPath.CurrentNode; nextWaypoint = currentPath.NextNode; } else { int previousIndex = currentPath.CurrentIndex - i; if (previousIndex < 0) { break; } currentWaypoint = currentPath.Nodes[previousIndex]; nextWaypoint = currentPath.CurrentNode; } if (currentWaypoint?.ConnectedDoor == null) { continue; } if (nextWaypoint == null) { //the node we're heading towards is the last one in the path, and at a door //the door needs to be open for the character to reach the node if (currentWaypoint.ConnectedDoor.LinkedGap != null) { // Keep the airlock doors closed, but not in ruins/wrecks if (currentWaypoint.ConnectedDoor.LinkedGap.IsRoomToRoom || currentWaypoint.Submarine?.Info.IsRuin != null || currentWaypoint.Submarine?.Info.IsWreck != null) { shouldBeOpen = true; door = currentWaypoint.ConnectedDoor; } } } else { float colliderLength = GetColliderLength(); door = currentWaypoint.ConnectedDoor; if (door.LinkedGap.IsHorizontal) { int dir = Math.Sign(nextWaypoint.WorldPosition.X - door.Item.WorldPosition.X); float size = character.AnimController.InWater ? colliderLength : GetColliderSize().X; shouldBeOpen = (door.Item.WorldPosition.X - character.WorldPosition.X) * dir > -size; } else { int dir = Math.Sign(nextWaypoint.WorldPosition.Y - door.Item.WorldPosition.Y); shouldBeOpen = (door.Item.WorldPosition.Y - character.WorldPosition.Y) * dir > -colliderLength; } } } if (door == null) { return; } //toggle the door if it's the previous node and open, or if it's current node and closed if ((door.IsOpen || door.IsBroken) != shouldBeOpen) { Controller closestButton = null; float closestDist = 0; bool canAccess = CanAccessDoor(door, button => { if (currentWaypoint == null) { return(true); } // Check that the button is on the right side of the door. if (door.LinkedGap.IsHorizontal) { int dir = Math.Sign((nextWaypoint ?? currentWaypoint).WorldPosition.X - door.Item.WorldPosition.X); if (button.Item.WorldPosition.X * dir > door.Item.WorldPosition.X * dir) { return(false); } } else { int dir = Math.Sign((nextWaypoint ?? currentWaypoint).WorldPosition.Y - door.Item.WorldPosition.Y); if (button.Item.WorldPosition.Y * dir > door.Item.WorldPosition.Y * dir) { return(false); } } float distance = Vector2.DistanceSquared(button.Item.WorldPosition, character.WorldPosition); if (closestButton == null || distance < closestDist) { closestButton = button; closestDist = distance; } return(true); }); if (canAccess) { if (door.HasIntegratedButtons) { door.Item.TryInteract(character, false, true); buttonPressCooldown = ButtonPressInterval; break; } else if (closestButton != null) { if (Vector2.DistanceSquared(closestButton.Item.WorldPosition, character.WorldPosition) < MathUtils.Pow(closestButton.Item.InteractDistance + GetColliderLength(), 2)) { closestButton.Item.TryInteract(character, false, true); buttonPressCooldown = ButtonPressInterval; break; } else { // Can't reach the button closest to the character. // It's possible that we could reach another buttons. // If this becomes an issue, we could go through them here and check if any of them are reachable // (would have to cache a collection of buttons instead of a single reference in the CanAccess filter method above) var body = Submarine.PickBody(character.SimPosition, character.GetRelativeSimPosition(closestButton.Item), collisionCategory: Physics.CollisionWall | Physics.CollisionLevel); if (body != null) { if (body.UserData is Item item) { var d = item.GetComponent <Door>(); if (d == null || d.IsOpen) { return; } } // The button is on the wrong side of the door or a wall currentPath.Unreachable = true; } return; } } } else if (shouldBeOpen) { #if DEBUG DebugConsole.NewMessage($"{character.Name}: Pathfinding error: Cannot access the door", Color.Yellow); #endif currentPath.Unreachable = true; return; } } } }
private void CheckDoorsInPath() { for (int i = 0; i < 2; i++) { WayPoint currentWaypoint = null; WayPoint nextWaypoint = null; Door door = null; bool shouldBeOpen = false; if (currentPath.Nodes.Count == 1) { door = currentPath.Nodes.First().ConnectedDoor; shouldBeOpen = door != null; } else { if (i == 0) { currentWaypoint = currentPath.CurrentNode; nextWaypoint = currentPath.NextNode; } else { currentWaypoint = currentPath.PrevNode; nextWaypoint = currentPath.CurrentNode; } if (currentWaypoint?.ConnectedDoor == null) { continue; } if (nextWaypoint == null) { //the node we're heading towards is the last one in the path, and at a door //the door needs to be open for the character to reach the node shouldBeOpen = true; } else { door = currentWaypoint.ConnectedGap.ConnectedDoor; if (door.LinkedGap.IsHorizontal) { int dir = Math.Sign(nextWaypoint.WorldPosition.X - door.Item.WorldPosition.X); shouldBeOpen = (door.Item.WorldPosition.X - character.WorldPosition.X) * dir > -50.0f; } else { int dir = Math.Sign(nextWaypoint.WorldPosition.Y - door.Item.WorldPosition.Y); shouldBeOpen = (door.Item.WorldPosition.Y - character.WorldPosition.Y) * dir > -80.0f; } } } if (door == null) { return; } //toggle the door if it's the previous node and open, or if it's current node and closed if (door.IsOpen != shouldBeOpen) { Controller closestButton = null; float closestDist = 0; bool canAccess = CanAccessDoor(door, button => { if (currentWaypoint == null) { return(true); } // Check that the button is on the right side of the door. if (door.LinkedGap.IsHorizontal) { int dir = Math.Sign(nextWaypoint.WorldPosition.X - door.Item.WorldPosition.X); if (button.Item.WorldPosition.X * dir > door.Item.WorldPosition.X * dir) { return(false); } } else { int dir = Math.Sign(nextWaypoint.WorldPosition.Y - door.Item.WorldPosition.Y); if (button.Item.WorldPosition.Y * dir > door.Item.WorldPosition.Y * dir) { return(false); } } float distance = Vector2.DistanceSquared(button.Item.WorldPosition, character.WorldPosition); if (closestButton == null || distance < closestDist) { closestButton = button; closestDist = distance; } return(true); }); if (canAccess) { if (door.HasIntegratedButtons) { door.Item.TryInteract(character, false, true); buttonPressCooldown = ButtonPressInterval; break; } else if (closestButton != null) { if (Vector2.DistanceSquared(closestButton.Item.WorldPosition, character.WorldPosition) < MathUtils.Pow(closestButton.Item.InteractDistance * 2, 2)) { closestButton.Item.TryInteract(character, false, true); buttonPressCooldown = ButtonPressInterval; break; } else { // Can't reach the button closest to the character. // It's possible that we could reach another buttons. // If this becomes an issue, we could go through them here and check if any of them are reachable // (would have to cache a collection of buttons instead of a single reference in the CanAccess filter method above) var body = Submarine.PickBody(character.SimPosition, character.GetRelativeSimPosition(closestButton.Item), collisionCategory: Physics.CollisionWall | Physics.CollisionLevel); if (body != null) { if (body.UserData is Item item) { var d = item.GetComponent <Door>(); if (d == null || d.IsOpen) { return; } } // The button is on the wrong side of the door or a wall currentPath.Unreachable = true; } return; } } } else if (shouldBeOpen) { #if DEBUG DebugConsole.NewMessage($"{character.Name}: Pathfinding error: Cannot access the door", Color.Yellow); #endif currentPath.Unreachable = true; return; } } } }