Exemplo n.º 1
0
        private float CalculateDistanceTraveled()
        {
            if (level == null || pathFinder == null)
            {
                return(0.0f);
            }
            var refEntity = GetRefEntity();

            if (refEntity == null)
            {
                return(0.0f);
            }
            Vector2 target       = ConvertUnits.ToSimUnits(level.EndPosition);
            var     steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(refEntity.WorldPosition), target);

            if (steeringPath.Unreachable || float.IsPositiveInfinity(totalPathLength))
            {
                //use horizontal position in the level as a fallback if a path can't be found
                return(MathHelper.Clamp((refEntity.WorldPosition.X - level.StartPosition.X) / (level.EndPosition.X - level.StartPosition.X), 0.0f, 1.0f));
            }
            else
            {
                return(MathHelper.Clamp(1.0f - steeringPath.TotalLength / totalPathLength, 0.0f, 1.0f));
            }
        }
Exemplo n.º 2
0
        public void StartRound(Level level)
        {
            if (isClient)
            {
                return;
            }

            pendingEventSets.Clear();
            selectedEvents.Clear();

            pathFinder = new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
            var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(Level.Loaded.StartPosition), ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));

            totalPathLength = steeringPath.TotalLength;

            this.level = level;
            SelectSettings();

            var initialEventSet = SelectRandomEvents(ScriptedEventSet.List);

            if (initialEventSet != null)
            {
                pendingEventSets.Add(initialEventSet);
                CreateEvents(initialEventSet);
            }

            PreloadContent(GetFilesToPreload());

            roundDuration        = 0.0f;
            intensityUpdateTimer = 0.0f;
            CalculateCurrentIntensity(0.0f);
            currentIntensity = targetIntensity;
            eventCoolDown    = 0.0f;
        }
Exemplo n.º 3
0
        private Vector2 CalculateSteeringSeek(Vector2 target, float weight, Func <PathNode, bool> startNodeFilter = null, Func <PathNode, bool> endNodeFilter = null, Func <PathNode, bool> nodeFilter = null)
        {
            bool needsNewPath = character.Params.PathFinderPriority > 0.5f && (currentPath == null || currentPath.Unreachable || currentPath.Finished || Vector2.DistanceSquared(target, currentTarget) > 1);

            //find a new path if one hasn't been found yet or the target is different from the current target
            if (needsNewPath || findPathTimer < -1.0f)
            {
                IsPathDirty = true;
                if (findPathTimer > 0.0f)
                {
                    return(Vector2.Zero);
                }
                currentTarget = target;
                Vector2 currentPos = host.SimPosition;
                if (character != null && character.Submarine == null)
                {
                    var targetHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(target), null, false);
                    if (targetHull != null && targetHull.Submarine != null)
                    {
                        currentPos -= targetHull.Submarine.SimPosition;
                    }
                }
                pathFinder.InsideSubmarine = character.Submarine != null;
                var  newPath    = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", startNodeFilter, endNodeFilter, nodeFilter);
                bool useNewPath = currentPath == null || needsNewPath || currentPath.Finished;
                if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
                {
                    // It's possible that the current path was calculated from a start point that is no longer valid.
                    // Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
                    useNewPath = newPath.Cost <currentPath.Cost ||
                                               Vector2.DistanceSquared(character.WorldPosition, currentPath.CurrentNode.WorldPosition)> Math.Pow(Vector2.Distance(character.WorldPosition, newPath.Nodes.First().WorldPosition) * 3, 2);
                }
                if (useNewPath)
                {
                    currentPath = newPath;
                }
                float priority = MathHelper.Lerp(3, 1, character.Params.PathFinderPriority);
                findPathTimer = priority * Rand.Range(1.0f, 1.2f);
                IsPathDirty   = false;
                return(DiffToCurrentNode());
            }

            Vector2 diff     = DiffToCurrentNode();
            var     collider = character.AnimController.Collider;

            //if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
            if (!character.AnimController.InWater && !character.IsClimbing && diff.Y < collider.height / 2 + collider.radius)
            {
                diff.Y = 0.0f;
            }
            //if (diff.LengthSquared() < 0.001f) { return -host.Steering; }
            if (diff == Vector2.Zero)
            {
                return(Vector2.Zero);
            }
            return(Vector2.Normalize(diff) * weight);
        }
Exemplo n.º 4
0
                static CachedDistance CalculateNewCachedDistance(Character c)
                {
                    pathFinder ??= new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
                    var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(c.WorldPosition), ConvertUnits.ToSimUnits(Submarine.MainSub.WorldPosition));

                    if (path.Unreachable)
                    {
                        return(null);
                    }
                    return(new CachedDistance(c.WorldPosition, Submarine.MainSub.WorldPosition, path.TotalLength, Timing.TotalTime + Rand.Range(1.0f, 5.0f)));
                }
Exemplo n.º 5
0
        protected override Vector2 DoSteeringSeek(Vector2 target, float weight)
        {
            //find a new path if one hasn't been found yet or the target is different from the current target
            if (currentPath == null || Vector2.Distance(target, currentTarget) > 1.0f || findPathTimer < -1.0f)
            {
                IsPathDirty = true;

                if (findPathTimer > 0.0f)
                {
                    return(Vector2.Zero);
                }

                currentTarget = target;
                Vector2 pos = host.SimPosition;
                if (character != null && character.Submarine == null)
                {
                    var targetHull = Hull.FindHull(FarseerPhysics.ConvertUnits.ToDisplayUnits(target), null, false);
                    if (targetHull != null && targetHull.Submarine != null)
                    {
                        pos -= targetHull.Submarine.SimPosition;
                    }
                }

                currentPath = pathFinder.FindPath(pos, target, "(Character: " + character.Name + ")");

                findPathTimer = Rand.Range(1.0f, 1.2f);

                IsPathDirty = false;
                return(DiffToCurrentNode());
            }

            Vector2 diff = DiffToCurrentNode();

            var collider = character.AnimController.Collider;

            //if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
            if (!character.AnimController.InWater && !character.IsClimbing && diff.Y < collider.height / 2 + collider.radius)
            {
                diff.Y = 0.0f;
            }

            if (diff.LengthSquared() < 0.001f)
            {
                return(-host.Steering);
            }

            return(Vector2.Normalize(diff) * weight);
        }
Exemplo n.º 6
0
        public void StartRound(Level level)
        {
            if (isClient)
            {
                return;
            }

            pendingEventSets.Clear();
            selectedEvents.Clear();
            activeEvents.Clear();

            pathFinder      = new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
            totalPathLength = 0.0f;
            if (level != null)
            {
                var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(Level.Loaded.StartPosition), ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));
                totalPathLength = steeringPath.TotalLength;
            }

            this.level = level;
            SelectSettings();

            var initialEventSet = SelectRandomEvents(EventSet.List);

            if (initialEventSet != null)
            {
                pendingEventSets.Add(initialEventSet);
                CreateEvents(initialEventSet);
            }

            if (level?.LevelData?.Type == LevelData.LevelType.Outpost)
            {
                level.LevelData.EventHistory.AddRange(selectedEvents.Values.SelectMany(v => v).Select(e => e.Prefab));
                if (level.LevelData.EventHistory.Count > 10)
                {
                    level.LevelData.EventHistory.RemoveRange(0, level.LevelData.EventHistory.Count - 10);
                }
            }

            PreloadContent(GetFilesToPreload());

            roundDuration        = 0.0f;
            intensityUpdateTimer = 0.0f;
            CalculateCurrentIntensity(0.0f);
            currentIntensity = targetIntensity;
            eventCoolDown    = 0.0f;
        }
Exemplo n.º 7
0
        protected override Vector2 DoSteeringSeek(Vector2 target, float weight)
        {
            bool needsNewPath = currentPath != null && currentPath.Unreachable || Vector2.DistanceSquared(target, currentTarget) > 1;

            //find a new path if one hasn't been found yet or the target is different from the current target
            if (currentPath == null || needsNewPath || findPathTimer < -1.0f)
            {
                IsPathDirty = true;

                if (findPathTimer > 0.0f)
                {
                    return(Vector2.Zero);
                }

                currentTarget = target;
                Vector2 pos = host.SimPosition;
                // TODO: remove this and handle differently?
                if (character != null && character.Submarine == null)
                {
                    var targetHull = Hull.FindHull(FarseerPhysics.ConvertUnits.ToDisplayUnits(target), null, false);
                    if (targetHull != null && targetHull.Submarine != null)
                    {
                        pos -= targetHull.Submarine.SimPosition;
                    }
                }

                var  newPath    = pathFinder.FindPath(pos, target, character.Submarine, "(Character: " + character.Name + ")");
                bool useNewPath = currentPath == null || needsNewPath;
                if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
                {
                    // It's possible that the current path was calculated from a start point that is no longer valid.
                    // Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
                    useNewPath = newPath.Cost <currentPath.Cost ||
                                               Vector2.DistanceSquared(character.WorldPosition, currentPath.CurrentNode.WorldPosition)> Math.Pow(Vector2.Distance(character.WorldPosition, newPath.Nodes.First().WorldPosition) * 2, 2);
                }
                if (useNewPath)
                {
                    currentPath = newPath;
                }

                findPathTimer = Rand.Range(1.0f, 1.2f);

                IsPathDirty = false;
                return(DiffToCurrentNode());
            }

            Vector2 diff = DiffToCurrentNode();

            var collider = character.AnimController.Collider;

            //if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
            if (!character.AnimController.InWater && !character.IsClimbing && diff.Y < collider.height / 2 + collider.radius)
            {
                diff.Y = 0.0f;
            }

            if (diff.LengthSquared() < 0.001f)
            {
                return(-host.Steering);
            }

            return(Vector2.Normalize(diff) * weight);
        }
Exemplo n.º 8
0
        public void StartRound(Level level)
        {
            this.level = level;

            if (isClient)
            {
                return;
            }

            pendingEventSets.Clear();
            selectedEvents.Clear();
            activeEvents.Clear();

            pathFinder      = new PathFinder(WayPoint.WayPointList, false);
            totalPathLength = 0.0f;
            if (level != null)
            {
                var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(level.StartPosition), ConvertUnits.ToSimUnits(level.EndPosition));
                totalPathLength = steeringPath.TotalLength;
            }

            SelectSettings();

            int seed = 0;

            if (level != null)
            {
                seed = ToolBox.StringToInt(level.Seed);
                foreach (var previousEvent in level.LevelData.EventHistory)
                {
                    seed ^= ToolBox.StringToInt(previousEvent.Identifier);
                }
            }
            MTRandom rand = new MTRandom(seed);

            EventSet initialEventSet = SelectRandomEvents(EventSet.List, rand);
            EventSet additiveSet     = null;

            if (initialEventSet != null && initialEventSet.Additive)
            {
                additiveSet     = initialEventSet;
                initialEventSet = SelectRandomEvents(EventSet.List.FindAll(e => !e.Additive), rand);
            }
            if (initialEventSet != null)
            {
                pendingEventSets.Add(initialEventSet);
                CreateEvents(initialEventSet, rand);
            }
            if (additiveSet != null)
            {
                pendingEventSets.Add(additiveSet);
                CreateEvents(additiveSet, rand);
            }

            if (level?.LevelData?.Type == LevelData.LevelType.Outpost)
            {
                //if the outpost is connected to a locked connection, create an event to unlock it
                if (level.StartLocation?.Connections.Any(c => c.Locked && level.StartLocation.MapPosition.X < c.OtherLocation(level.StartLocation).MapPosition.X) ?? false)
                {
                    var unlockPathPrefabs         = EventSet.PrefabList.FindAll(e => e.UnlockPathEvent);
                    var unlockPathPrefabsForBiome = unlockPathPrefabs.FindAll(e =>
                                                                              string.IsNullOrEmpty(e.BiomeIdentifier) ||
                                                                              e.BiomeIdentifier.Equals(level.LevelData.Biome.Identifier, StringComparison.OrdinalIgnoreCase));

                    var unlockPathEventPrefab = unlockPathPrefabsForBiome.Any() ?
                                                ToolBox.SelectWeightedRandom(unlockPathPrefabsForBiome, unlockPathPrefabsForBiome.Select(b => b.Commonness).ToList(), rand) :
                                                ToolBox.SelectWeightedRandom(unlockPathPrefabs, unlockPathPrefabs.Select(b => b.Commonness).ToList(), rand);
                    if (unlockPathEventPrefab != null)
                    {
                        var newEvent = unlockPathEventPrefab.CreateInstance();
                        newEvent.Init(true);
                        ActiveEvents.Add(newEvent);
                    }
                    else
                    {
                        //if no event that unlocks the path can be found, unlock it automatically
                        level.StartLocation.Connections.ForEach(c => c.Locked = false);
                    }
                }

                level.LevelData.EventHistory.AddRange(selectedEvents.Values.SelectMany(v => v).Select(e => e.Prefab).Where(e => !level.LevelData.EventHistory.Contains(e)));
                if (level.LevelData.EventHistory.Count > MaxEventHistory)
                {
                    level.LevelData.EventHistory.RemoveRange(0, level.LevelData.EventHistory.Count - MaxEventHistory);
                }
                AddChildEvents(initialEventSet);
                void AddChildEvents(EventSet eventSet)
                {
                    if (eventSet == null)
                    {
                        return;
                    }
                    if (eventSet.OncePerOutpost)
                    {
                        foreach (EventPrefab ep in eventSet.EventPrefabs.SelectMany(e => e.Prefabs))
                        {
                            if (!level.LevelData.NonRepeatableEvents.Contains(ep))
                            {
                                level.LevelData.NonRepeatableEvents.Add(ep);
                            }
                        }
                    }
                    foreach (EventSet childSet in eventSet.ChildSets)
                    {
                        AddChildEvents(childSet);
                    }
                }
            }

            PreloadContent(GetFilesToPreload());

            roundDuration        = 0.0f;
            isCrewAway           = false;
            crewAwayDuration     = 0.0f;
            crewAwayResetTimer   = 0.0f;
            intensityUpdateTimer = 0.0f;
            CalculateCurrentIntensity(0.0f);
            currentIntensity = targetIntensity;
            eventCoolDown    = 0.0f;
        }
        private Vector2 CalculateSteeringSeek(Vector2 target, float weight, float minGapSize = 0, Func <PathNode, bool> startNodeFilter = null, Func <PathNode, bool> endNodeFilter = null, Func <PathNode, bool> nodeFilter = null, bool checkVisibility = true)
        {
            bool needsNewPath = currentPath == null || currentPath.Unreachable || currentPath.Finished;

            if (!needsNewPath && character.Submarine != null && character.Params.PathFinderPriority > 0.5f)
            {
                Vector2 targetDiff = target - currentTarget;
                if (currentPath != null && currentPath.Nodes.Any() && character.Submarine != null)
                {
                    //target in a different sub than where the character is now
                    //take that into account when calculating if the target has moved
                    Submarine currentPathSub = currentPath?.CurrentNode?.Submarine;
                    if (currentPathSub == character.Submarine)
                    {
                        currentPathSub = currentPath?.Nodes.LastOrDefault()?.Submarine;
                    }
                    if (currentPathSub != character.Submarine && targetDiff.LengthSquared() > 1 && currentPathSub != null)
                    {
                        Vector2 subDiff = character.Submarine.SimPosition - currentPathSub.SimPosition;
                        targetDiff += subDiff;
                    }
                }
                if (targetDiff.LengthSquared() > 1)
                {
                    needsNewPath = true;
                }
            }
            //find a new path if one hasn't been found yet or the target is different from the current target
            if (needsNewPath || findPathTimer < -1.0f)
            {
                IsPathDirty = true;
                if (findPathTimer < 0)
                {
                    SkipCurrentPathNodes();
                    currentTarget = target;
                    Vector2 currentPos = host.SimPosition;
                    pathFinder.InsideSubmarine            = character.Submarine != null && !character.Submarine.Info.IsRuin;
                    pathFinder.ApplyPenaltyToOutsideNodes = character.Submarine != null && character.PressureProtection <= 0;
                    var  newPath    = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", minGapSize, startNodeFilter, endNodeFilter, nodeFilter, checkVisibility: checkVisibility);
                    bool useNewPath = needsNewPath || currentPath == null || currentPath.CurrentNode == null || character.Submarine != null && findPathTimer < -1 && Math.Abs(character.AnimController.TargetMovement.Combine()) <= 0;
                    if (newPath.Unreachable || newPath.Nodes.None())
                    {
                        useNewPath = false;
                    }
                    else if (!useNewPath && currentPath != null && currentPath.CurrentNode != null)
                    {
                        // Check if the new path is the same as the old, in which case we just ignore it and continue using the old path (or the progress would reset).
                        if (IsIdenticalPath())
                        {
                            useNewPath = false;
                        }
                        else
                        {
                            // Use the new path if it has significantly lower cost (don't change the path if it has marginally smaller cost. This reduces navigating backwards due to new path that is calculated from the node just behind us).
                            float t = (float)currentPath.CurrentIndex / (currentPath.Nodes.Count - 1);
                            useNewPath = newPath.Cost < currentPath.Cost * MathHelper.Lerp(0.95f, 0, t);
                            if (!useNewPath && character.Submarine != null && !character.IsClimbing)
                            {
                                // It's possible that the current path was calculated from a start point that is no longer valid.
                                // Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
                                // This is a special case for cases e.g. where the character falls and thus needs a new path.
                                // Don't do this outside or when climbing ladders, because both cause issues.
                                useNewPath = Vector2.DistanceSquared(character.WorldPosition, currentPath.CurrentNode.WorldPosition) > Math.Pow(Vector2.Distance(character.WorldPosition, newPath.Nodes.First().WorldPosition) * 3, 2);
                            }
                        }

                        bool IsIdenticalPath()
                        {
                            int nodeCount = newPath.Nodes.Count;

                            if (nodeCount == currentPath.Nodes.Count)
                            {
                                for (int i = 0; i < nodeCount - 1; i++)
                                {
                                    if (newPath.Nodes[i] != currentPath.Nodes[i])
                                    {
                                        return(false);
                                    }
                                }
                                return(true);
                            }
                            return(false);
                        }
                    }
                    if (useNewPath)
                    {
                        if (currentPath != null)
                        {
                            CheckDoorsInPath();
                        }
                        currentPath = newPath;
                    }
                    float priority = MathHelper.Lerp(3, 1, character.Params.PathFinderPriority);
                    findPathTimer = priority * Rand.Range(1.0f, 1.2f);
                    IsPathDirty   = false;
                    return(DiffToCurrentNode());

                    void SkipCurrentPathNodes()
                    {
                        if (!character.AnimController.InWater || character.Submarine != null)
                        {
                            return;
                        }
                        if (CurrentPath == null || CurrentPath.Unreachable || CurrentPath.Finished)
                        {
                            return;
                        }
                        if (CurrentPath.CurrentIndex < 0 || CurrentPath.CurrentIndex >= CurrentPath.Nodes.Count - 1)
                        {
                            return;
                        }
                        // Check if we could skip ahead to NextNode when the character is swimming and using waypoints outside.
                        // Do this to optimize the old path before creating and evaluating a new path.
                        // In general, this is to avoid behavior where:
                        // a) the character goes back to first reach CurrentNode when the second node would be closer; or
                        // b) the character moves along the path when they could cut through open space to reduce the total distance.
                        float pathDistance = Vector2.Distance(character.WorldPosition, CurrentPath.CurrentNode.WorldPosition);

                        pathDistance += CurrentPath.GetLength(startIndex: CurrentPath.CurrentIndex);
                        for (int i = CurrentPath.Nodes.Count - 1; i > CurrentPath.CurrentIndex + 1; i--)
                        {
                            var   waypoint       = CurrentPath.Nodes[i];
                            float directDistance = Vector2.DistanceSquared(character.WorldPosition, waypoint.WorldPosition);
                            if (directDistance > (pathDistance * pathDistance) || Submarine.PickBody(host.SimPosition, waypoint.SimPosition, collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) != null)
                            {
                                pathDistance -= CurrentPath.GetLength(startIndex: i - 1, endIndex: i);
                                continue;
                            }
                            CurrentPath.SkipToNode(i);
                            break;
                        }
                    }
                }
            }

            Vector2 diff     = DiffToCurrentNode();
            var     collider = character.AnimController.Collider;
            // Only humanoids can climb ladders
            bool canClimb = character.AnimController is HumanoidAnimController;

            //if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
            if (canClimb && !character.AnimController.InWater && !character.IsClimbing && diff.Y < collider.height / 2 + collider.radius)
            {
                diff.Y = 0.0f;
            }
            if (diff == Vector2.Zero)
            {
                return(Vector2.Zero);
            }
            return(Vector2.Normalize(diff) * weight);
        }
        public void StartRound(Level level)
        {
            if (isClient)
            {
                return;
            }

            pendingEventSets.Clear();
            selectedEvents.Clear();
            activeEvents.Clear();

            pathFinder      = new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
            totalPathLength = 0.0f;
            if (level != null)
            {
                var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(Level.Loaded.StartPosition), ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));
                totalPathLength = steeringPath.TotalLength;
            }

            this.level = level;
            SelectSettings();

            var initialEventSet = SelectRandomEvents(EventSet.List);

            if (initialEventSet != null)
            {
                pendingEventSets.Add(initialEventSet);
                int seed = ToolBox.StringToInt(level.Seed);
                foreach (var previousEvent in level.LevelData.EventHistory)
                {
                    seed ^= ToolBox.StringToInt(previousEvent.Identifier);
                }
                MTRandom rand = new MTRandom(seed);
                CreateEvents(initialEventSet, rand);
            }

            if (level?.LevelData?.Type == LevelData.LevelType.Outpost)
            {
                level.LevelData.EventHistory.AddRange(selectedEvents.Values.SelectMany(v => v).Select(e => e.Prefab).Where(e => !level.LevelData.EventHistory.Contains(e)));
                if (level.LevelData.EventHistory.Count > MaxEventHistory)
                {
                    level.LevelData.EventHistory.RemoveRange(0, level.LevelData.EventHistory.Count - MaxEventHistory);
                }
                AddChildEvents(initialEventSet);
                void AddChildEvents(EventSet eventSet)
                {
                    if (eventSet == null)
                    {
                        return;
                    }
                    foreach (EventPrefab ep in eventSet.EventPrefabs.Select(e => e.First))
                    {
                        if (!level.LevelData.NonRepeatableEvents.Contains(ep))
                        {
                            level.LevelData.NonRepeatableEvents.Add(ep);
                        }
                    }
                    foreach (EventSet childSet in eventSet.ChildSets)
                    {
                        AddChildEvents(childSet);
                    }
                }
            }

            PreloadContent(GetFilesToPreload());

            roundDuration        = 0.0f;
            isCrewAway           = false;
            crewAwayDuration     = 0.0f;
            crewAwayResetTimer   = 0.0f;
            intensityUpdateTimer = 0.0f;
            CalculateCurrentIntensity(0.0f);
            currentIntensity = targetIntensity;
            eventCoolDown    = 0.0f;
        }
Exemplo n.º 11
0
        public void StartRound(Level level)
        {
            if (isClient)
            {
                return;
            }

            pathFinder = new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
            var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(Level.Loaded.StartPosition), ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));

            totalPathLength = steeringPath.TotalLength;

            randWanderMonster = new List <String>();
            randWanderMonster.Add("crawlerhusk");
            randMonster = new List <String>();
            randMonster.Add("charybdis");
            randMonster.Add("hammerhead");

            pendingEventSets.Clear();
            selectedEvents.Clear();
            activeEvents.Clear();

            pathFinder      = new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
            totalPathLength = 0.0f;
            if (level != null)
            {
                var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(Level.Loaded.StartPosition), ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));
                totalPathLength = steeringPath.TotalLength;
            }

            randGen = new Random();

            this.level = level;
            SelectSettings();

            var initialEventSet = SelectRandomEvents(EventSet.List);

            if (initialEventSet != null)
            {
                pendingEventSets.Add(initialEventSet);
                CreateEvents(initialEventSet);
            }

            if (level?.LevelData?.Type == LevelData.LevelType.Outpost)
            {
                level.LevelData.EventHistory.AddRange(selectedEvents.Values.SelectMany(v => v).Select(e => e.Prefab));
                if (level.LevelData.EventHistory.Count > 10)
                {
                    level.LevelData.EventHistory.RemoveRange(0, level.LevelData.EventHistory.Count - 10);
                }
            }

            PreloadContent(GetFilesToPreload());
            challengeScale       = settings.WanderChallengeScale;
            roundDuration        = 0.0f;
            intensityUpdateTimer = 0.0f;
            CalculateCurrentIntensity(0.0f);
            currentIntensity = targetIntensity;
            eventCoolDown    = 0.0f;
            wanderCooldown   = 120.0f;
            DebugConsole.NewMessage("Wander Cooldown: " + settings.WanderCooldown);
        }
Exemplo n.º 12
0
        private Vector2 CalculateSteeringSeek(Vector2 target, float weight, Func <PathNode, bool> startNodeFilter = null, Func <PathNode, bool> endNodeFilter = null, Func <PathNode, bool> nodeFilter = null, bool checkVisibility = true)
        {
            Vector2 targetDiff = target - currentTarget;

            if (currentPath != null && currentPath.Nodes.Any())
            {
                //current path calculated relative to a different sub than where the character is now
                //take that into account when calculating if the target has moved
                Submarine currentPathSub = currentPath?.Nodes.First().Submarine;
                if (currentPathSub != character.Submarine && character.Submarine != null)
                {
                    Vector2 subDiff = character.Submarine.SimPosition - currentPathSub.SimPosition;
                    targetDiff += subDiff;
                }
            }
            bool needsNewPath = character.Params.PathFinderPriority > 0.5f && (currentPath == null || currentPath.Unreachable || targetDiff.LengthSquared() > 1);

            //find a new path if one hasn't been found yet or the target is different from the current target
            if (needsNewPath || findPathTimer < -1.0f)
            {
                IsPathDirty = true;
                if (findPathTimer < 0)
                {
                    currentTarget = target;
                    Vector2 currentPos = host.SimPosition;
                    if (character != null && character.Submarine == null)
                    {
                        var targetHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(target), null, false);
                        if (targetHull != null && targetHull.Submarine != null)
                        {
                            currentPos -= targetHull.Submarine.SimPosition;
                        }
                    }
                    pathFinder.InsideSubmarine            = character.Submarine != null;
                    pathFinder.ApplyPenaltyToOutsideNodes = character.PressureProtection <= 0;
                    var  newPath    = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", startNodeFilter, endNodeFilter, nodeFilter, checkVisibility: checkVisibility);
                    bool useNewPath = needsNewPath || currentPath == null || currentPath.CurrentNode == null || findPathTimer < -1 && Math.Abs(character.AnimController.TargetMovement.X) <= 0;
                    if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
                    {
                        // Check if the new path is the same as the old, in which case we just ignore it and continue using the old path (or the progress would reset).
                        if (IsIdenticalPath())
                        {
                            useNewPath = false;
                        }
                        else
                        {
                            // Use the new path if it has significantly lower cost (don't change the path if it has marginally smaller cost. This reduces navigating backwards due to new path that is calculated from the node just behind us).
                            float t = (float)currentPath.CurrentIndex / (currentPath.Nodes.Count - 1);
                            useNewPath = newPath.Cost < currentPath.Cost * MathHelper.Lerp(0.95f, 0, t);
                            if (!useNewPath)
                            {
                                // It's possible that the current path was calculated from a start point that is no longer valid.
                                // Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
                                useNewPath = Vector2.DistanceSquared(character.WorldPosition, currentPath.CurrentNode.WorldPosition) > Math.Pow(Vector2.Distance(character.WorldPosition, newPath.Nodes.First().WorldPosition) * 3, 2);
                            }
                        }

                        bool IsIdenticalPath()
                        {
                            int nodeCount = newPath.Nodes.Count;

                            if (nodeCount == currentPath.Nodes.Count)
                            {
                                for (int i = 0; i < nodeCount - 1; i++)
                                {
                                    if (newPath.Nodes[i] != currentPath.Nodes[i])
                                    {
                                        return(false);
                                    }
                                }
                                return(true);
                            }
                            return(false);
                        }
                    }
                    if (useNewPath)
                    {
                        currentPath = newPath;
                    }
                    float priority = MathHelper.Lerp(3, 1, character.Params.PathFinderPriority);
                    findPathTimer = priority * Rand.Range(1.0f, 1.2f);
                    IsPathDirty   = false;
                    return(DiffToCurrentNode());
                }
            }

            Vector2 diff     = DiffToCurrentNode();
            var     collider = character.AnimController.Collider;
            // Only humanoids can climb ladders
            bool canClimb = character.AnimController is HumanoidAnimController;

            //if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
            if (canClimb && !character.AnimController.InWater && !character.IsClimbing && diff.Y < collider.height / 2 + collider.radius)
            {
                diff.Y = 0.0f;
            }
            if (diff == Vector2.Zero)
            {
                return(Vector2.Zero);
            }
            return(Vector2.Normalize(diff) * weight);
        }