Пример #1
0
        protected override void Act(float deltaTime)
        {
            if (ReturnTarget == null)
            {
                Abandon = true;
                return;
            }
            bool shouldUseEscapeBehavior = false;

            if (character.CurrentHull != null || isSteeringThroughGap)
            {
                if (character.Submarine == null || !character.Submarine.IsConnectedTo(ReturnTarget))
                {
                    // Character is on another sub that is not connected to the target sub, use the escape behavior to get them out
                    shouldUseEscapeBehavior = true;
                    if (!usingEscapeBehavior)
                    {
                        HumanAIController.ResetEscape();
                    }
                    isSteeringThroughGap = HumanAIController.Escape(deltaTime);
                    if (!isSteeringThroughGap && (HumanAIController.EscapeTarget == null || HumanAIController.IsCurrentPathUnreachable))
                    {
                        Abandon = true;
                    }
                }
                else if (character.Submarine != ReturnTarget)
                {
                    // Character is on another sub that is connected to the target sub, create a Go To objective to reach the target sub
                    if (moveInsideObjective == null)
                    {
                        Hull targetHull = null;
                        foreach (var d in ReturnTarget.ConnectedDockingPorts.Values)
                        {
                            if (!d.Docked)
                            {
                                continue;
                            }
                            if (d.DockingTarget == null)
                            {
                                continue;
                            }
                            if (d.DockingTarget.Item.Submarine != character.Submarine)
                            {
                                continue;
                            }
                            targetHull = d.Item.CurrentHull;
                            break;
                        }
                        if (targetHull != null && !targetHull.IsTaggedAirlock())
                        {
                            // Target the closest airlock
                            float closestDist = 0;
                            Hull  airlock     = null;
                            foreach (Hull hull in Hull.hullList)
                            {
                                if (hull.Submarine != targetHull.Submarine)
                                {
                                    continue;
                                }
                                if (!hull.IsTaggedAirlock())
                                {
                                    continue;
                                }
                                float dist = Vector2.DistanceSquared(targetHull.Position, hull.Position);
                                if (airlock == null || closestDist <= 0 || dist < closestDist)
                                {
                                    airlock     = hull;
                                    closestDist = dist;
                                }
                            }
                            if (airlock != null)
                            {
                                targetHull = airlock;
                            }
                        }
                        if (targetHull != null)
                        {
                            RemoveSubObjective(ref moveInCaveObjective);
                            RemoveSubObjective(ref moveOutsideObjective);
                            TryAddSubObjective(ref moveInsideObjective,
                                               constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager)
                            {
                                AllowGoingOutside = true,
                                endNodeFilter     = n => n.Waypoint.Submarine == targetHull.Submarine
                            },
                                               onCompleted: () => RemoveSubObjective(ref moveInsideObjective),
                                               onAbandon: () => Abandon = true);
                        }
                        else
                        {
#if DEBUG
                            DebugConsole.ThrowError("Error with a Return objective: no suitable target for 'moveInsideObjective'");
#endif
                        }
                    }
                }
                else
                {
                    // Character is on the target sub, the objective is completed
                    IsCompleted = true;
                }
            }
            else if (!isSteeringThroughGap && moveInCaveObjective == null && moveOutsideObjective == null)
            {
                if (HumanAIController.IsInsideCave)
                {
                    WayPoint closestOutsideWaypoint = null;
                    float    closestDistance        = float.MaxValue;
                    foreach (var w in WayPoint.WayPointList)
                    {
                        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)
                        {
                            closestOutsideWaypoint = w;
                            closestDistance        = distance;
                        }
                    }
                    if (closestOutsideWaypoint != null)
                    {
                        RemoveSubObjective(ref moveInsideObjective);
                        RemoveSubObjective(ref moveOutsideObjective);
                        TryAddSubObjective(ref moveInCaveObjective,
                                           constructor: () => new AIObjectiveGoTo(closestOutsideWaypoint, character, objectiveManager)
                        {
                            endNodeFilter     = n => n.Waypoint == closestOutsideWaypoint,
                            AllowGoingOutside = true
                        },
                                           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
                {
                    Hull  targetHull            = null;
                    float targetDistanceSquared = float.MaxValue;
                    bool  targetIsAirlock       = false;
                    foreach (var hull in ReturnTarget.GetHulls(false))
                    {
                        bool hullIsAirlock = hull.IsTaggedAirlock();
                        if (hullIsAirlock || (!targetIsAirlock && hull.LeadsOutside(character)))
                        {
                            float distanceSquared = Vector2.DistanceSquared(character.WorldPosition, hull.WorldPosition);
                            if (targetHull == null || distanceSquared < targetDistanceSquared)
                            {
                                targetHull            = hull;
                                targetDistanceSquared = distanceSquared;
                                targetIsAirlock       = hullIsAirlock;
                            }
                        }
                    }
                    if (targetHull != null)
                    {
                        RemoveSubObjective(ref moveInsideObjective);
                        RemoveSubObjective(ref moveInCaveObjective);
                        TryAddSubObjective(ref moveOutsideObjective,
                                           constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager)
                        {
                            AllowGoingOutside = true
                        },
                                           onCompleted: () => RemoveSubObjective(ref moveOutsideObjective),
                                           onAbandon: () => Abandon = true);
                    }
                    else
                    {
#if DEBUG
                        DebugConsole.ThrowError("Error with a Return objective: no suitable target for 'moveOutsideObjective'");
#endif
                    }
                }
            }
            else
            {
                if (HumanAIController.IsInsideCave)
                {
                    RemoveSubObjective(ref moveOutsideObjective);
                }
                else
                {
                    RemoveSubObjective(ref moveInCaveObjective);
                }
            }
            usingEscapeBehavior = shouldUseEscapeBehavior;
        }