Exemple #1
0
        public void Wander(float deltaTime)
        {
            if (character.IsClimbing)
            {
                return;
            }
            //steer away from edges of the hull
            var currentHull = character.CurrentHull;

            if (currentHull != null)
            {
                float roomWidth = currentHull.Rect.Width;
                if (roomWidth < WallAvoidDistance * 4)
                {
                    PathSteering.Reset();
                }
                else
                {
                    float leftDist  = character.Position.X - currentHull.Rect.X;
                    float rightDist = currentHull.Rect.Right - character.Position.X;
                    if (leftDist < WallAvoidDistance && rightDist < WallAvoidDistance)
                    {
                        if (Math.Abs(rightDist - leftDist) > WallAvoidDistance / 2)
                        {
                            PathSteering.SteeringManual(deltaTime, Vector2.UnitX * Math.Sign(rightDist - leftDist));
                        }
                        else
                        {
                            PathSteering.Reset();
                        }
                    }
                    else if (leftDist < WallAvoidDistance)
                    {
                        float speed = (WallAvoidDistance - leftDist) / WallAvoidDistance;
                        PathSteering.SteeringManual(deltaTime, Vector2.UnitX * MathHelper.Clamp(speed, 0.25f, 1));
                        PathSteering.WanderAngle = 0.0f;
                    }
                    else if (rightDist < WallAvoidDistance)
                    {
                        float speed = (WallAvoidDistance - rightDist) / WallAvoidDistance;
                        PathSteering.SteeringManual(deltaTime, -Vector2.UnitX * MathHelper.Clamp(speed, 0.25f, 1));
                        PathSteering.WanderAngle = MathHelper.Pi;
                    }
                    else
                    {
                        SteeringManager.SteeringWander();
                    }
                }
            }
            else
            {
                SteeringManager.SteeringWander();
            }
            if (!character.AnimController.InWater)
            {
                //reset vertical steering to prevent dropping down from platforms etc
                character.AIController.SteeringManager.ResetY();
            }
        }
Exemple #2
0
        protected override void Act(float deltaTime)
        {
            if (followControlledCharacter)
            {
                if (Character.Controlled == null)
                {
                    Abandon = true;
                    return;
                }
                Target = Character.Controlled;
            }
            if (Target == character)
            {
                // Wait
                character.AIController.SteeringManager.Reset();
                return;
            }
            waitUntilPathUnreachable -= deltaTime;
            if (!character.IsClimbing)
            {
                character.SelectedConstruction = null;
            }
            if (Target is Entity e)
            {
                if (e.Removed)
                {
                    Abandon = true;
                }
                else
                {
                    character.AIController.SelectTarget(e.AiTarget);
                }
            }
            var targetHull = Target is Hull h ? h : Target is Item i ? i.CurrentHull : Target is Character c ? c.CurrentHull : character.CurrentHull;

            if (!followControlledCharacter)
            {
                // Abandon if going through unsafe paths. Note ignores unsafe nodes when following an order or when the objective is set to ignore unsafe hulls.
                bool containsUnsafeNodes = HumanAIController.CurrentOrder == null && !HumanAIController.ObjectiveManager.CurrentObjective.IgnoreUnsafeHulls &&
                                           PathSteering != null && PathSteering.CurrentPath != null &&
                                           PathSteering.CurrentPath.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull));
                if (containsUnsafeNodes || HumanAIController.UnreachableHulls.Contains(targetHull))
                {
                    Abandon = true;
                    SteeringManager.Reset();
                    return;
                }
            }
            bool insideSteering  = SteeringManager == PathSteering && PathSteering.CurrentPath != null && !PathSteering.IsPathDirty;
            bool isInside        = character.CurrentHull != null;
            bool targetIsOutside = (Target != null && targetHull == null) || (insideSteering && PathSteering.CurrentPath.HasOutdoorsNodes);

            if (isInside && targetIsOutside && !AllowGoingOutside)
            {
                Abandon = true;
            }
            else if (waitUntilPathUnreachable < 0)
            {
                if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable && !PathSteering.IsPathDirty)
                {
                    if (repeat)
                    {
                        SteeringManager.Reset();
                    }
                    else
                    {
                        Abandon = true;
                    }
                }
            }
            if (Abandon)
            {
#if DEBUG
                DebugConsole.NewMessage($"{character.Name}: Cannot reach the target: {Target.ToString()}", Color.Yellow);
#endif
                if (objectiveManager.CurrentOrder != null && objectiveManager.CurrentOrder.ReportFailures)
                {
                    character.Speak(TextManager.Get("DialogCannotReach"), identifier: "cannotreach", minDurationBetweenSimilar: 10.0f);
                }
                SteeringManager.Reset();
            }
            else
            {
                if (getDivingGearIfNeeded && !character.LockHands)
                {
                    Character followTarget    = Target as Character;
                    bool      needsDivingSuit = targetIsOutside;
                    bool      needsDivingGear = needsDivingSuit || HumanAIController.NeedsDivingGear(character, targetHull, out needsDivingSuit);
                    if (!needsDivingGear && mimic)
                    {
                        if (HumanAIController.HasDivingSuit(followTarget))
                        {
                            needsDivingGear = true;
                            needsDivingSuit = true;
                        }
                        else if (HumanAIController.HasDivingMask(followTarget))
                        {
                            needsDivingGear = true;
                        }
                    }
                    bool needsEquipment = false;
                    if (needsDivingSuit)
                    {
                        needsEquipment = !HumanAIController.HasDivingSuit(character, AIObjectiveFindDivingGear.lowOxygenThreshold);
                    }
                    else if (needsDivingGear)
                    {
                        needsEquipment = !HumanAIController.HasDivingGear(character, AIObjectiveFindDivingGear.lowOxygenThreshold);
                    }
                    if (needsEquipment)
                    {
                        TryAddSubObjective(ref findDivingGear, () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager),
                                           onAbandon: () => Abandon = true,
                                           onCompleted: () => RemoveSubObjective(ref findDivingGear));
                        return;
                    }
                }
                if (repeat && IsCloseEnough)
                {
                    OnCompleted();
                    return;
                }
                if (SteeringManager == PathSteering)
                {
                    Func <PathNode, bool> nodeFilter = null;
                    if (isInside && !AllowGoingOutside)
                    {
                        nodeFilter = node => node.Waypoint.CurrentHull != null;
                    }
                    PathSteering.SteeringSeek(character.GetRelativeSimPosition(Target), 1, startNodeFilter, endNodeFilter, nodeFilter);
                }
                else
                {
                    SteeringManager.SteeringSeek(character.GetRelativeSimPosition(Target), 10);
                }
                if (!insideSteering)
                {
                    SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1);
                }
            }
        }
        protected override void Act(float deltaTime)
        {
            if (PathSteering == null)
            {
                return;
            }

            //don't keep dragging others when idling
            if (character.SelectedCharacter != null)
            {
                character.DeselectCharacter();
            }
            if (!character.IsClimbing)
            {
                character.SelectedConstruction = null;
            }

            bool currentTargetIsInvalid = currentTarget == null || IsForbidden(currentTarget) ||
                                          (PathSteering.CurrentPath != null && PathSteering.CurrentPath.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull)));

            if (currentTargetIsInvalid || (currentTarget == null && IsForbidden(character.CurrentHull)))
            {
                newTargetTimer  = 0;
                standStillTimer = 0;
            }
            if (character.AnimController.InWater || character.IsClimbing)
            {
                standStillTimer = 0;
            }
            if (newTargetTimer <= 0.0f)
            {
                currentTarget = FindRandomHull();

                if (currentTarget != null)
                {
                    string errorMsg = null;
#if DEBUG
                    bool isRoomNameFound = currentTarget.RoomName != null;
                    errorMsg = "(Character " + character.Name + " idling, target " + (isRoomNameFound ? currentTarget.RoomName : currentTarget.ToString()) + ")";
#endif
                    var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsg);
                    PathSteering.SetPath(path);
                }

                newTargetTimer = currentTarget != null && character.AnimController.InWater ? newTargetIntervalMin : Rand.Range(newTargetIntervalMin, newTargetIntervalMax);
            }

            newTargetTimer -= deltaTime;

            //wander randomly
            // - if reached the end of the path
            // - if the target is unreachable
            // - if the path requires going outside
            if (SteeringManager != PathSteering || (PathSteering.CurrentPath != null &&
                                                    (PathSteering.CurrentPath.NextNode == null || PathSteering.CurrentPath.Unreachable || PathSteering.CurrentPath.HasOutdoorsNodes)))
            {
                standStillTimer -= deltaTime;
                if (standStillTimer > 0.0f)
                {
                    walkDuration = Rand.Range(walkDurationMin, walkDurationMax);
                    PathSteering.Reset();
                    return;
                }
                if (standStillTimer < -walkDuration)
                {
                    standStillTimer = Rand.Range(standStillMin, standStillMax);
                }

                Wander(deltaTime);
                return;
            }

            if (currentTarget != null)
            {
                character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition);
            }
        }
Exemple #4
0
        protected override void Act(float deltaTime)
        {
            if (PathSteering == null)
            {
                return;
            }

            //don't keep dragging others when idling
            if (character.SelectedCharacter != null)
            {
                character.DeselectCharacter();
            }
            if (!character.IsClimbing)
            {
                character.SelectedConstruction = null;
            }

            bool currentHullForbidden = IsForbidden(character.CurrentHull);

            if (!currentHullForbidden && !character.AnimController.InWater && !character.IsClimbing && HumanAIController.ObjectiveManager.WaitTimer > 0)
            {
                SteeringManager.Reset();
                return;
            }

            bool currentTargetIsInvalid = currentTarget == null || IsForbidden(currentTarget) ||
                                          (PathSteering.CurrentPath != null && PathSteering.CurrentPath.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull)));

            if (currentTargetIsInvalid || (currentTarget == null && currentHullForbidden))
            {
                newTargetTimer  = 0;
                standStillTimer = 0;
            }
            else if (character.IsClimbing)
            {
                if (currentTarget == null)
                {
                    newTargetTimer = 0;
                }
                else
                {
                    // Don't allow new targets when climbing.
                    newTargetTimer = Math.Max(newTargetIntervalMin, newTargetTimer);
                }
            }
            else if (character.AnimController.InWater)
            {
                if (currentTarget == null)
                {
                    newTargetTimer = 0;
                }
            }
            if (newTargetTimer <= 0.0f)
            {
                if (!searchingNewHull)
                {
                    //find all available hulls first
                    FindTargetHulls();
                    searchingNewHull = true;
                    return;
                }
                else if (targetHulls.Count > 0)
                {
                    //choose a random available hull
                    var randomHull = ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced);

                    bool isCurrentHullOK = !HumanAIController.UnsafeHulls.Contains(character.CurrentHull) && !IsForbidden(character.CurrentHull);
                    if (isCurrentHullOK)
                    {
                        // Check that there is no unsafe or forbidden hulls on the way to the target
                        // Only do this when the current hull is ok, because otherwise the would block all paths from the current hull to the target hull.
                        var path = PathSteering.PathFinder.FindPath(character.SimPosition, randomHull.SimPosition);
                        if (path.Unreachable ||
                            path.Nodes.Any(n => HumanAIController.UnsafeHulls.Contains(n.CurrentHull) || IsForbidden(n.CurrentHull)))
                        {
                            //can't go to this room, remove it from the list and try another room next frame
                            int index = targetHulls.IndexOf(randomHull);
                            targetHulls.RemoveAt(index);
                            hullWeights.RemoveAt(index);
                            PathSteering.Reset();
                            return;
                        }
                    }
                    currentTarget    = randomHull;
                    searchingNewHull = false;
                }

                if (currentTarget != null)
                {
                    character.AIController.SelectTarget(currentTarget.AiTarget);
                    string errorMsg = null;
#if DEBUG
                    bool isRoomNameFound = currentTarget.RoomName != null;
                    errorMsg = "(Character " + character.Name + " idling, target " + (isRoomNameFound ? currentTarget.RoomName : currentTarget.ToString()) + ")";
#endif
                    var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsg);
                    PathSteering.SetPath(path);
                }

                newTargetTimer = currentTarget != null && character.AnimController.InWater ? newTargetIntervalMin : Rand.Range(newTargetIntervalMin, newTargetIntervalMax);
            }

            newTargetTimer -= deltaTime;

            //wander randomly
            // - if reached the end of the path
            // - if the target is unreachable
            // - if the path requires going outside
            if (!character.IsClimbing)
            {
                if (SteeringManager != PathSteering || (PathSteering.CurrentPath != null &&
                                                        (PathSteering.CurrentPath.NextNode == null || PathSteering.CurrentPath.Unreachable || PathSteering.CurrentPath.HasOutdoorsNodes)))
                {
                    if (!character.AnimController.InWater)
                    {
                        standStillTimer -= deltaTime;
                        if (standStillTimer > 0.0f)
                        {
                            walkDuration = Rand.Range(walkDurationMin, walkDurationMax);
                            PathSteering.Reset();
                            return;
                        }
                        if (standStillTimer < -walkDuration)
                        {
                            standStillTimer = Rand.Range(standStillMin, standStillMax);
                        }
                    }
                    Wander(deltaTime);
                    return;
                }
            }

            if (currentTarget != null)
            {
                character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition);
            }
        }