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 #2
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);
            }
        }