diff --git a/Subsurface/Source/Characters/AI/AIController.cs b/Subsurface/Source/Characters/AI/AIController.cs index d0991bba7..8e6cfd932 100644 --- a/Subsurface/Source/Characters/AI/AIController.cs +++ b/Subsurface/Source/Characters/AI/AIController.cs @@ -29,12 +29,17 @@ namespace Barotrauma public Vector2 SimPosition { - get { return Character.AnimController.Limbs[0].SimPosition; } + get { return Character.SimPosition; } + } + + public Vector2 WorldPosition + { + get { return Character.WorldPosition; } } public Vector2 Velocity { - get { return Character.AnimController.Limbs[0].LinearVelocity; } + get { return Character.AnimController.RefLimb.LinearVelocity; } } public AiState State diff --git a/Subsurface/Source/Characters/AI/HumanAIController.cs b/Subsurface/Source/Characters/AI/HumanAIController.cs index 89b4cf85a..f62ff863c 100644 --- a/Subsurface/Source/Characters/AI/HumanAIController.cs +++ b/Subsurface/Source/Characters/AI/HumanAIController.cs @@ -71,7 +71,33 @@ namespace Barotrauma steeringManager.Update(moveSpeed); - Character.AnimController.IgnorePlatforms = (-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X*0.5f)); + Character.AnimController.IgnorePlatforms = Character.AnimController.TargetMovement.Y < -0.5f && + (-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X)); + + var currPath = (steeringManager as IndoorsSteeringManager).CurrentPath; + if (currPath != null && currPath.CurrentNode != null) + { + if (currPath.CurrentNode.WorldPosition.Y < Character.WorldPosition.Y - 200) + { + Character.AnimController.IgnorePlatforms = true; + } + + if (Character.AnimController.Stairs != null) + { + float yDiff = currPath.CurrentNode.WorldPosition.Y - Character.WorldPosition.Y; + + if (Math.Abs(yDiff)>10.0f) + { + int dir = Math.Sign(yDiff); + + float movement = Character.AnimController.Stairs.StairDirection == Direction.Right ? + dir * Character.AnimController.TargetMovement.Length() : -dir * Character.AnimController.TargetMovement.Length(); + + Character.AnimController.TargetMovement = new Vector2(movement, 0.0f); + } + } + } + (Character.AnimController as HumanoidAnimController).Crouching = false; @@ -86,17 +112,20 @@ namespace Barotrauma if (Character.SelectedConstruction != null && Character.SelectedConstruction.GetComponent()!=null) { - var currPath = (steeringManager as IndoorsSteeringManager).CurrentPath; if (currPath != null && currPath.CurrentNode != null && currPath.CurrentNode.Ladders != null) { Character.AnimController.TargetMovement = new Vector2( 0.0f, Math.Sign(Character.AnimController.TargetMovement.Y)); } } - //unequip diving suit if running out of oxygen - if (Character.Oxygen < 50.0f && Character.AnimController.CurrentHull!=null && - Character.AnimController.CurrentHull.OxygenPercentage > 20.0f && - Character.AnimController.CurrentHull.Volume < Character.AnimController.CurrentHull.FullVolume*0.3f) + //suit can be taken off if there character is inside a hull and there's air in the room + bool canTakeOffSuit = Character.AnimController.CurrentHull != null && + Character.AnimController.CurrentHull.OxygenPercentage > 30.0f && + Character.AnimController.CurrentHull.Volume < Character.AnimController.CurrentHull.FullVolume * 0.3f; + + //the suit can be taken off and the character is running out of oxygen (couldn't find a tank for the suit?) or idling + //-> take the suit off + if (canTakeOffSuit && (Character.Oxygen < 50.0f || objectiveManager.CurrentObjective is AIObjectiveIdle)) { var divingSuit = Character.Inventory.FindItem("Diving Suit"); if (divingSuit != null) divingSuit.Drop(Character); @@ -121,9 +150,6 @@ namespace Barotrauma { Character.AnimController.TargetDir = Character.AnimController.TargetMovement.X > 0.0f ? Direction.Right : Direction.Left; } - - - } public override void OnAttacked(IDamageable attacker, float amount) @@ -172,7 +198,7 @@ namespace Barotrauma { GUI.DrawLine(spriteBatch, new Vector2(pathSteering.CurrentPath.Nodes[i].WorldPosition.X, -pathSteering.CurrentPath.Nodes[i].WorldPosition.Y), - new Vector2(pathSteering.CurrentPath.Nodes[i - 1].WorldPosition.Y, -pathSteering.CurrentPath.Nodes[i-1].WorldPosition.Y), + new Vector2(pathSteering.CurrentPath.Nodes[i - 1].WorldPosition.X, -pathSteering.CurrentPath.Nodes[i-1].WorldPosition.Y), Color.LightGreen); } } diff --git a/Subsurface/Source/Characters/AI/ISteerable.cs b/Subsurface/Source/Characters/AI/ISteerable.cs index 561d363f8..2917f1531 100644 --- a/Subsurface/Source/Characters/AI/ISteerable.cs +++ b/Subsurface/Source/Characters/AI/ISteerable.cs @@ -20,6 +20,11 @@ namespace Barotrauma { get; } + + Vector2 WorldPosition + { + get; + } diff --git a/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs b/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs index 872c6b697..05d3bbd44 100644 --- a/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs +++ b/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs @@ -122,12 +122,22 @@ namespace Barotrauma if (currentPath.CurrentNode!=null && currentPath.CurrentNode.SimPosition.Y > character.SimPosition.Y+1.0f) allowedDistance*=0.5f; Vector2 pos = host.SimPosition; - if (character != null && character.Submarine == null && - CurrentPath.CurrentNode != null && CurrentPath.CurrentNode.Submarine != null) + + if (character != null && currentPath.CurrentNode != null) { - //todo: take multiple subs into account - pos -= CurrentPath.CurrentNode.Submarine.SimPosition; - } + 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) { @@ -135,17 +145,32 @@ namespace Barotrauma { currentPath.CurrentNode.Ladders.Item.Pick(character, false, true); } - - if (Math.Sign(host.Steering.Y) == currentPath.CurrentNode.SimPosition.Y - pos.Y) - { - allowedDistance = 0.0f; - } } currentPath.CheckProgress(pos, allowedDistance); if (currentPath.CurrentNode == null) return Vector2.Zero; + var hull = character.AnimController.CurrentHull; + + if (character.AnimController.Anim == AnimController.Animation.Climbing) + { + float x = currentPath.CurrentNode.SimPosition.X - pos.X; + float y = (currentPath.CurrentNode.SimPosition.Y) - pos.Y; + + if (Math.Abs(x) < Math.Abs(y) * 10.0f) + { + x = 0.0f; + } + else if (character.AnimController.LowestLimb != null && hull != null) + { + if (character.AnimController.LowestLimb.Position.Y < hull.Rect.Y - hull.Rect.Height + 10.0f) x = 0.0f; + } + + character.AnimController.IgnorePlatforms = false; + return new Vector2(x,y); + } + return currentPath.CurrentNode.SimPosition - pos; } @@ -153,41 +178,67 @@ namespace Barotrauma { for (int i = 0; i < 2; i++) { - WayPoint node = i == 0 ? currentPath.CurrentNode : currentPath.PrevNode; - if (node == null || node.ConnectedGap == null || node.ConnectedGap.ConnectedDoor == null) continue; - var door = node.ConnectedGap.ConnectedDoor; - - bool open = currentPath.CurrentNode != null && - Math.Sign(door.Item.SimPosition.X - host.SimPosition.X) == Math.Sign(currentPath.CurrentNode.SimPosition.X - host.SimPosition.X); - - if (currentPath.CurrentNode==null) + WayPoint node = null; + WayPoint nextNode = null; + + if (i==0) { - open = false; + node = currentPath.CurrentNode; + nextNode = currentPath.NextNode; } else { - if (door.LinkedGap.isHorizontal) - { - open = Math.Sign(door.Item.SimPosition.X - character.SimPosition.X) == Math.Sign(currentPath.CurrentNode.SimPosition.X - character.SimPosition.X); - } - else - { - open = Math.Sign(door.Item.SimPosition.Y - character.SimPosition.Y) == Math.Sign(currentPath.CurrentNode.SimPosition.Y - character.SimPosition.Y); - } + node = currentPath.PrevNode; + nextNode = currentPath.CurrentNode; } - //toggle the door if it's the previous node and open, or if it's current node and closed - if (door.IsOpen != open) + if (node == null || node.ConnectedGap == null || node.ConnectedGap.ConnectedDoor == null) continue; + + if (nextNode == null) continue; + + var door = node.ConnectedGap.ConnectedDoor; + + bool shouldBeOpen = false; + + if (door.LinkedGap.isHorizontal) { - var buttons = door.Item.GetConnectedComponents(); + int currentDir = Math.Sign(nextNode.WorldPosition.X - door.Item.WorldPosition.X); + + shouldBeOpen = (door.Item.WorldPosition.X - character.WorldPosition.X) * currentDir > -50.0f; + } + else + { + int currentDir = Math.Sign(nextNode.WorldPosition.Y - door.Item.WorldPosition.Y); + + shouldBeOpen = (door.Item.WorldPosition.Y - character.WorldPosition.Y) * currentDir > -80.0f; + } + + + //toggle the door if it's the previous node and open, or if it's current node and closed + if (door.IsOpen != shouldBeOpen) + { + var buttons = door.Item.GetConnectedComponents(true); + + Controller closestButton = null; + float closestDist = 0.0f; foreach (Controller controller in buttons) { - if (Vector2.Distance(controller.Item.Position, character.Position) > controller.Item.PickDistance * 2.0f) continue; + float dist = Vector2.Distance(controller.Item.WorldPosition, character.WorldPosition); + if (dist > controller.Item.PickDistance * 2.0f) continue; - controller.Item.Pick(character, false, true); + if (dist < closestDist || closestButton == null) + { + closestButton = controller; + closestDist = dist; + } + } + + if (closestButton != null) + { + closestButton.Item.Pick(character, false, true); break; } } diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs index 2770496ec..ec5e0d3d5 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveFindSafety.cs @@ -37,7 +37,7 @@ namespace Barotrauma if (currentHull != null) { - if (currentHull.Volume / currentHull.FullVolume > 0.5f || character.Oxygen < 80.0f) + if (NeedsDivingGear()) { if (!FindDivingGear(deltaTime)) return; } @@ -131,6 +131,19 @@ namespace Barotrauma return (otherObjective is AIObjectiveFindSafety); } + private bool NeedsDivingGear() + { + var currentHull = character.AnimController.CurrentHull; + if (currentHull == null) return true; + + //there's lots of water in the room -> get a suit + if (currentHull.Volume / currentHull.FullVolume > 0.5f) return true; + + if (currentHull.OxygenPercentage < 30.0f) return true; + + return false; + } + public override float GetPriority(Character character) { if (character.Oxygen < 80.0f) @@ -142,8 +155,12 @@ namespace Barotrauma currenthullSafety = GetHullSafety(character.AnimController.CurrentHull, character); priority = 100.0f - currenthullSafety; - if (divingGearObjective != null && !divingGearObjective.IsCompleted()) priority += 20.0f; + if (NeedsDivingGear()) + { + if (divingGearObjective != null && !divingGearObjective.IsCompleted()) priority += 20.0f; + } + return priority; } diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs index d5dbbfff1..534b811d8 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs @@ -19,6 +19,8 @@ namespace Barotrauma public bool IgnoreContainedItems; + private AIObjectiveGoTo goToObjective; + private bool equip; public override bool CanBeCompleted @@ -52,13 +54,8 @@ namespace Barotrauma protected override void Act(float deltaTime) { - if (targetItem == null) - { - FindTargetItem(); - if (targetItem == null) return; - } - - if (moveToTarget == null) return; + FindTargetItem(); + if (targetItem == null || moveToTarget == null) return; if (Vector2.Distance(character.Position, moveToTarget.Position) < targetItem.PickDistance*2.0f) { @@ -97,9 +94,15 @@ namespace Barotrauma character.Inventory.TryPutItem(targetItem, targetSlot, true, false); } } - else if (!subObjectives.Any()) + else { - AddGoToObjective(targetItem); + if (goToObjective == null) + { + bool gettingDivingGear = itemName == "diving" || itemName == "Diving Gear"; + goToObjective = new AIObjectiveGoTo(moveToTarget, character, false, !gettingDivingGear); + } + + goToObjective.TryComplete(deltaTime); } } @@ -111,7 +114,7 @@ namespace Barotrauma { float currDist = moveToTarget == null ? 0.0f : Vector2.DistanceSquared(moveToTarget.Position, character.Position); - for (int i = 0; i < 5 && currSearchIndex < Item.ItemList.Count - 2; i++) + for (int i = 0; i < 10 && currSearchIndex < Item.ItemList.Count - 2; i++) { currSearchIndex++; @@ -136,22 +139,12 @@ namespace Barotrauma targetItem = item; moveToTarget = rootContainer ?? item; - - AddGoToObjective(moveToTarget); - } //if searched through all the items and a target wasn't found, can't be completed if (currSearchIndex >= Item.ItemList.Count && targetItem == null) canBeCompleted = false; } - - private void AddGoToObjective(Item gotoToTarget) - { - subObjectives.Clear(); - AddSubObjective(new AIObjectiveGoTo(gotoToTarget, character)); - } - - + public override bool IsDuplicate(AIObjective otherObjective) { AIObjectiveGetItem getItem = otherObjective as AIObjectiveGetItem; diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs index bdb54cf88..d978607d4 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -16,6 +16,8 @@ namespace Barotrauma //how long until the path to the target is declared unreachable private float waitUntilPathUnreachable; + private bool getDivingGearIfNeeded; + public override bool CanBeCompleted { get @@ -35,23 +37,25 @@ namespace Barotrauma get { return target; } } - public AIObjectiveGoTo(Entity target, Character character, bool repeat = false) + public AIObjectiveGoTo(Entity target, Character character, bool repeat = false, bool getDivingGearIfNeeded = true) : base (character, "") { this.target = target; this.repeat = repeat; waitUntilPathUnreachable = 5.0f; + this.getDivingGearIfNeeded = getDivingGearIfNeeded; } - public AIObjectiveGoTo(Vector2 simPos, Character character, bool repeat = false) + public AIObjectiveGoTo(Vector2 simPos, Character character, bool repeat = false, bool getDivingGearIfNeeded = true) : base(character, "") { this.targetPos = simPos; this.repeat = repeat; waitUntilPathUnreachable = 5.0f; + this.getDivingGearIfNeeded = getDivingGearIfNeeded; } protected override void Act(float deltaTime) @@ -108,7 +112,7 @@ namespace Barotrauma { indoorsSteering.SteeringWander(); } - else if (indoorsSteering.CurrentPath != null && indoorsSteering.HasOutdoorsNodes) + else if (getDivingGearIfNeeded && indoorsSteering.CurrentPath != null && indoorsSteering.HasOutdoorsNodes) { AddSubObjective(new AIObjectiveFindDivingGear(character, true)); } diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveIdle.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveIdle.cs index 559c70ac9..0b9540f3f 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -1,4 +1,5 @@ using Microsoft.Xna.Framework; +using System; using System.Collections.Generic; using System.Linq; @@ -11,8 +12,6 @@ namespace Barotrauma AITarget currentTarget; private float newTargetTimer; - - public AIObjectiveIdle(Character character) : base(character, "") { @@ -23,7 +22,6 @@ namespace Barotrauma return 1.0f; } - protected override void Act(float deltaTime) { @@ -53,7 +51,8 @@ namespace Barotrauma newTargetTimer = currentTarget == null ? 5.0f : 15.0f; } - newTargetTimer -= deltaTime; + newTargetTimer -= deltaTime; + //wander randomly if reached the end of the path or the target is unreachable if (pathSteering==null || (pathSteering.CurrentPath != null && @@ -62,13 +61,28 @@ namespace Barotrauma //steer away from edges of the hull if (character.AnimController.CurrentHull!=null) { - if (character.Position.X < character.AnimController.CurrentHull.Rect.X + WallAvoidDistance) + float leftDist = character.Position.X - character.AnimController.CurrentHull.Rect.X; + float rightDist = character.AnimController.CurrentHull.Rect.Right - character.Position.X; + + if (leftDist < WallAvoidDistance && rightDist < WallAvoidDistance) { - pathSteering.SteeringManual(deltaTime, Vector2.UnitX*5.0f); + if (Math.Abs(rightDist - leftDist) > WallAvoidDistance / 2) + { + pathSteering.SteeringManual(deltaTime, Vector2.UnitX * Math.Sign(rightDist - leftDist)); + } + else + { + pathSteering.Reset(); + return; + } } - else if (character.Position.X > character.AnimController.CurrentHull.Rect.Right - WallAvoidDistance) + else if (leftDist < WallAvoidDistance) { - pathSteering.SteeringManual(deltaTime, -Vector2.UnitX); + pathSteering.SteeringManual(deltaTime, Vector2.UnitX * (WallAvoidDistance-leftDist)/WallAvoidDistance); + } + else if (rightDist < WallAvoidDistance) + { + pathSteering.SteeringManual(deltaTime, -Vector2.UnitX * (WallAvoidDistance-rightDist)/WallAvoidDistance); } } @@ -85,7 +99,7 @@ namespace Barotrauma } if (currentTarget == null) return; - character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition); + character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition, 2.0f); } private AITarget FindRandomTarget() diff --git a/Subsurface/Source/Characters/AI/PathFinder.cs b/Subsurface/Source/Characters/AI/PathFinder.cs index 533444fc2..10e29310e 100644 --- a/Subsurface/Source/Characters/AI/PathFinder.cs +++ b/Subsurface/Source/Characters/AI/PathFinder.cs @@ -19,7 +19,7 @@ namespace Barotrauma public float F,G,H; public List connections; - public float[] distances; + public List distances; public WayPoint Waypoint { @@ -63,15 +63,14 @@ namespace Barotrauma var nodeList = nodes.Values.ToList(); foreach (PathNode node in nodeList) { - node.distances = new float[node.connections.Count]; - for (int i = 0; i< node.distances.Length; i++) + node.distances = new List(); + for (int i = 0; i< node.connections.Count; i++) { - node.distances[i] = Vector2.Distance(node.position, node.connections[i].position); + node.distances.Add(Vector2.Distance(node.position, node.connections[i].position)); } } return nodeList; } - } class PathFinder @@ -87,9 +86,66 @@ namespace Barotrauma { nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => w.MoveWithLevel != insideSubmarine)); + foreach (WayPoint wp in wayPoints) + { + wp.linkedTo.CollectionChanged += WaypointLinksChanged; + } + this.insideSubmarine = insideSubmarine; } + void WaypointLinksChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (Submarine.Unloading) return; + + var waypoints = sender as IEnumerable; + + foreach (MapEntity me in waypoints) + { + WayPoint wp = me as WayPoint; + if (me == null) continue; + + var node = nodes.Find(n => n.Waypoint == wp); + if (node == null) return; + + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove) + { + for (int i = node.connections.Count - 1; i >= 0; i--) + { + //remove connection if the waypoint isn't connected anymore + if (wp.linkedTo.FirstOrDefault(l => l == node.connections[i].Waypoint) == null) + { + node.connections.RemoveAt(i); + node.distances.RemoveAt(i); + } + } + } + else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) + { + for (int i = 0; i < wp.linkedTo.Count; i++) + { + WayPoint connected = wp.linkedTo[i] as WayPoint; + if (connected == null) continue; + + //already connected, continue + if (node.connections.Any(n => n.Waypoint == connected)) continue; + + var matchingNode = nodes.Find(n => n.Waypoint == connected); + if (matchingNode == null) + { +#if DEBUG + DebugConsole.ThrowError("Waypoint connections were changed, no matching path node found in PathFinder"); +#endif + return; + } + + node.connections.Add(matchingNode); + node.distances.Add(Vector2.Distance(node.Position, matchingNode.Position)); + } + } + } + } + public SteeringPath FindPath(Vector2 start, Vector2 end) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); @@ -100,21 +156,21 @@ namespace Barotrauma foreach (PathNode node in nodes) { Vector2 nodePos = node.Position; + + float dist = System.Math.Abs(start.X - nodePos.X) + + System.Math.Abs(start.Y - nodePos.Y) * 10.0f; //higher cost for vertical movement - //if node waypoint is one of submarine waypoints outside the sub, transform position - //if (node.Waypoint != null && node.Waypoint.Submarine != null && node.Waypoint.CurrentHull == null) - //{ - // nodePos -= node.Waypoint.Submarine.Position; - //} - - float dist = System.Math.Abs(start.X-nodePos.X)+ - System.Math.Abs(start.Y - nodePos.Y)*10.0f + - Vector2.Distance(end,nodePos)/2.0f; + //prefer nodes that are closer to the end position + dist += Vector2.Distance(end, nodePos) / 10.0f; if (dist 0.05f; } //stop climbing if: diff --git a/Subsurface/Source/Characters/Animation/Ragdoll.cs b/Subsurface/Source/Characters/Animation/Ragdoll.cs index 25f020050..6e98e400f 100644 --- a/Subsurface/Source/Characters/Animation/Ragdoll.cs +++ b/Subsurface/Source/Characters/Animation/Ragdoll.cs @@ -74,6 +74,11 @@ namespace Barotrauma } } + public float FloorY + { + get { return floorY; } + } + public float Mass { get; @@ -330,14 +335,8 @@ namespace Barotrauma lowestLimb.Position.X - structure.Rect.X : structure.Rect.Width - (lowestLimb.Position.X - structure.Rect.X); - if (character.IsDead) - { - if (lowestLimb.Position.Y < structure.Rect.Y - structure.Rect.Height + stairPosY - 10.0f) return false; - } - else - { - if (lowestLimb.Position.Y < structure.Rect.Y - structure.Rect.Height + stairPosY) return false; - } + if (lowestLimb.Position.Y < structure.Rect.Y - structure.Rect.Height + stairPosY - 10.0f) return false; + if (targetMovement.Y < 0.5f) @@ -477,7 +476,10 @@ namespace Barotrauma } } - + if (ignorePlatforms) + { + GUI.DrawLine(spriteBatch, new Vector2(refLimb.WorldPosition.X, -refLimb.WorldPosition.Y), new Vector2(refLimb.WorldPosition.X, -refLimb.WorldPosition.Y+50), Color.Orange, 0, 5); + } } public virtual void Flip() diff --git a/Subsurface/Source/Characters/BackgroundSprite/BackgroundCreature.cs b/Subsurface/Source/Characters/BackgroundSprite/BackgroundCreature.cs index c2abfce94..ca66e0a63 100644 --- a/Subsurface/Source/Characters/BackgroundSprite/BackgroundCreature.cs +++ b/Subsurface/Source/Characters/BackgroundSprite/BackgroundCreature.cs @@ -42,6 +42,11 @@ namespace Barotrauma get { return FarseerPhysics.ConvertUnits.ToSimUnits(position); } } + public Vector2 WorldPosition + { + get { return position; } + } + public Vector2 Velocity { get { return new Vector2(velocity.X, velocity.Y); } diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 7d5a5d2b2..c934717a6 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -1143,7 +1143,14 @@ namespace Barotrauma Vector2 pos = DrawPosition; pos.Y = -pos.Y; - + + if (GameMain.DebugDraw) + { + AnimController.DebugDraw(spriteBatch); + + if (aiTarget != null) aiTarget.Draw(spriteBatch); + } + if (this == controlled) return; if (IsNetworkPlayer && info!=null) @@ -1158,13 +1165,6 @@ namespace Barotrauma } } - if (GameMain.DebugDraw) - { - AnimController.DebugDraw(spriteBatch); - - if (aiTarget != null) aiTarget.Draw(spriteBatch); - } - if (isDead) return; Vector2 healthBarPos = new Vector2(pos.X - 50, DrawPosition.Y + 100.0f); diff --git a/Subsurface/Source/Items/Components/DockingPort.cs b/Subsurface/Source/Items/Components/DockingPort.cs index 5215b232b..1566823ac 100644 --- a/Subsurface/Source/Items/Components/DockingPort.cs +++ b/Subsurface/Source/Items/Components/DockingPort.cs @@ -126,6 +126,8 @@ namespace Barotrauma.Items.Components public void Dock(DockingPort target) { + if (item.Submarine.DockedTo.Contains(target.item.Submarine)) return; + if (dockingTarget != null) { Undock(); @@ -154,6 +156,23 @@ namespace Barotrauma.Items.Components Math.Sign(dockingTarget.item.WorldPosition.X - item.WorldPosition.X) : Math.Sign(item.WorldPosition.Y - dockingTarget.item.WorldPosition.Y); dockingTarget.dockingDir = -dockingDir; + + foreach (WayPoint wp in WayPoint.WayPointList) + { + if (wp.Submarine != item.Submarine || wp.SpawnType != SpawnType.Path) continue; + + if (!Submarine.RectContains(item.Rect, wp.Position)) continue; + + foreach (WayPoint wp2 in WayPoint.WayPointList) + { + if (wp2.Submarine != dockingTarget.item.Submarine || wp2.SpawnType != SpawnType.Path) continue; + + if (!Submarine.RectContains(dockingTarget.item.Rect, wp2.Position)) continue; + + wp.linkedTo.Add(wp2); + wp2.linkedTo.Add(wp); + } + } CreateJoint(false); } @@ -304,6 +323,24 @@ namespace Barotrauma.Items.Components dockingTarget.item.Submarine.DockedTo.Remove(item.Submarine); item.Submarine.DockedTo.Remove(dockingTarget.item.Submarine); + + //remove all waypoint links between this sub and the dockingtarget + foreach (WayPoint wp in WayPoint.WayPointList) + { + if (wp.Submarine != item.Submarine || wp.SpawnType != SpawnType.Path) continue; + + for (int i = wp.linkedTo.Count - 1; i >= 0; i--) + { + var wp2 = wp.linkedTo[i] as WayPoint; + if (wp2 == null) continue; + + if (wp.Submarine == dockingTarget.item.Submarine) + { + wp.linkedTo.RemoveAt(i); + wp2.linkedTo.Remove(wp); + } + } + } item.linkedTo.Clear(); @@ -330,7 +367,7 @@ namespace Barotrauma.Items.Components gap.Remove(); gap = null; } - + if (bodies!=null) { foreach (Body body in bodies) diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index dca27ec31..8b95ed22c 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -1060,13 +1060,22 @@ namespace Barotrauma } } - public List GetConnectedComponents() + public List GetConnectedComponents(bool recursive = false) { - ConnectionPanel connectionPanel = GetComponent(); - if (connectionPanel == null) return new List(); - List connectedComponents = new List(); + if (recursive) + { + List alreadySearched = new List() {this}; + GetConnectedComponentsRecursive(alreadySearched, connectedComponents); + + return connectedComponents; + } + + ConnectionPanel connectionPanel = GetComponent(); + if (connectionPanel == null) return connectedComponents; + + foreach (Connection c in connectionPanel.Connections) { var recipients = c.Recipients; @@ -1080,6 +1089,34 @@ namespace Barotrauma return connectedComponents; } + private void GetConnectedComponentsRecursive(List alreadySearched, List connectedComponents) + { + alreadySearched.Add(this); + + ConnectionPanel connectionPanel = GetComponent(); + if (connectionPanel == null) return; + + foreach (Connection c in connectionPanel.Connections) + { + var recipients = c.Recipients; + foreach (Connection recipient in recipients) + { + if (alreadySearched.Contains(recipient.Item)) continue; + + var component = recipient.Item.GetComponent(); + + if (component != null) + { + connectedComponents.Add(component); + } + + recipient.Item.GetConnectedComponentsRecursive(alreadySearched, connectedComponents); + + + } + } + } + public void SendSignal(int stepsTaken, string signal, string connectionName, float power = 0.0f) { stepsTaken++; diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 232560b76..b7cd1811d 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -895,14 +895,20 @@ namespace Barotrauma return sub; } + public static bool Unloading + { + get; + private set; + } + public static void Unload() { + Unloading = true; Sound.OnGameEnd(); if (GameMain.LightManager != null) GameMain.LightManager.ClearLights(); - foreach (Submarine sub in loaded) { sub.Remove(); @@ -919,6 +925,8 @@ namespace Barotrauma Ragdoll.list.Clear(); GameMain.World.Clear(); + + Unloading = false; } public override void Remove() diff --git a/Subsurface/Source/Map/WayPoint.cs b/Subsurface/Source/Map/WayPoint.cs index 1a0f77b70..715f71e15 100644 --- a/Subsurface/Source/Map/WayPoint.cs +++ b/Subsurface/Source/Map/WayPoint.cs @@ -140,7 +140,7 @@ namespace Barotrauma int iconY = (int)(Math.Floor(iconIndices[(int)spawnType]*IconSize / (float)iconTexture.Width))*IconSize; int iconSize = ConnectedGap == null && Ladders == null ? IconSize : (int)(IconSize * 1.5f); - + spriteBatch.Draw(iconTexture, new Rectangle((int)(drawPos.X - iconSize/2), (int)(drawPos.Y - iconSize/2), iconSize, iconSize), new Rectangle(iconX, iconY, IconSize,IconSize), clr); @@ -176,7 +176,7 @@ namespace Barotrauma { editingHUD = CreateEditingHUD(); } - + editingHUD.Update((float)Physics.step); editingHUD.Draw(spriteBatch); @@ -321,7 +321,7 @@ namespace Barotrauma } float minDist = 150.0f; - float heightFromFloor = 100.0f; + float heightFromFloor = 110.0f; foreach (Hull hull in Hull.hullList) { @@ -607,7 +607,11 @@ namespace Barotrauma float dist = Vector2.Distance(wp.Position, Position); if (closest == null || dist < closestDist) { - if (Submarine.CheckVisibility(SimPosition, wp.SimPosition) != null) continue; + var body = Submarine.CheckVisibility(SimPosition, wp.SimPosition, true); + if (body != null) + { + if (body.UserData is Structure) continue; + } closestDist = dist; closest = wp; @@ -620,6 +624,8 @@ namespace Barotrauma private void ConnectTo(WayPoint wayPoint2) { + System.Diagnostics.Debug.Assert(this != wayPoint2); + if (!linkedTo.Contains(wayPoint2)) linkedTo.Add(wayPoint2); if (!wayPoint2.linkedTo.Contains(this)) wayPoint2.linkedTo.Add(this); }