private List <Level.InterestingPosition> GetAvailableSpawnPositions()
        {
            var availablePositions = Level.Loaded.PositionsOfInterest.FindAll(p => spawnPosType.HasFlag(p.PositionType));
            var removals           = new List <Level.InterestingPosition>();

            foreach (var position in availablePositions)
            {
                if (SpawnPosFilter != null && !SpawnPosFilter(position))
                {
                    removals.Add(position);
                    continue;
                }
                if (position.Submarine != null)
                {
                    if (position.Submarine.WreckAI != null && position.Submarine.WreckAI.IsAlive)
                    {
                        removals.Add(position);
                    }
                    else
                    {
                        continue;
                    }
                }
                if (position.PositionType != Level.PositionType.MainPath &&
                    position.PositionType != Level.PositionType.SidePath)
                {
                    continue;
                }
                if (Level.Loaded.ExtraWalls.Any(w => w.IsPointInside(position.Position.ToVector2())))
                {
                    removals.Add(position);
                }
                if (spawnDeep)
                {
                    for (int i = 0; i < availablePositions.Count; i++)
                    {
                        var pos = availablePositions[i].Position;
                        pos = new Point(pos.X, pos.Y - Level.Loaded.Size.Y);
                        availablePositions[i] = new Level.InterestingPosition(pos, availablePositions[i].PositionType);
                    }
                }
                if (position.Position.Y < Level.Loaded.GetBottomPosition(position.Position.X).Y)
                {
                    removals.Add(position);
                }
            }
            removals.ForEach(r => availablePositions.Remove(r));
            return(availablePositions);
        }
Ejemplo n.º 2
0
        private void FindSpawnPosition(bool affectSubImmediately)
        {
            if (disallowed)
            {
                return;
            }

            spawnPos = Vector2.Zero;
            var availablePositions = GetAvailableSpawnPositions();
            var chosenPosition     = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false);
            var removedPositions   = new List <Level.InterestingPosition>();

            foreach (var position in availablePositions)
            {
                if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability)
                {
                    removedPositions.Add(position);
                }
            }
            removedPositions.ForEach(p => availablePositions.Remove(p));
            bool isSubOrWreck = spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Wreck;

            if (affectSubImmediately && !isSubOrWreck)
            {
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    Finished();
                    return;
                }
                float closestDist = float.PositiveInfinity;
                //find the closest spawnposition that isn't too close to any of the subs
                foreach (var position in availablePositions)
                {
                    Vector2 pos  = position.Position.ToVector2();
                    float   dist = Vector2.DistanceSquared(pos, Submarine.MainSub.WorldPosition);
                    foreach (Submarine sub in Submarine.Loaded)
                    {
                        if (sub.Info.Type != SubmarineInfo.SubmarineType.Player)
                        {
                            continue;
                        }
                        float minDistToSub = GetMinDistanceToSub(sub);
                        if (dist > minDistToSub * minDistToSub && dist < closestDist)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                        }
                    }
                }
                //only found a spawnpos that's very far from the sub, pick one that's closer
                //and wait for the sub to move further before spawning
                if (closestDist > 15000.0f * 15000.0f)
                {
                    foreach (var position in availablePositions)
                    {
                        float dist = Vector2.DistanceSquared(position.Position.ToVector2(), Submarine.MainSub.WorldPosition);
                        if (dist < closestDist)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                        }
                    }
                }
            }
            else
            {
                if (!isSubOrWreck)
                {
                    float minDistance = 20000;
                    availablePositions.RemoveAll(p => Vector2.DistanceSquared(Submarine.MainSub.WorldPosition, p.Position.ToVector2()) < minDistance * minDistance);
                }
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    Finished();
                    return;
                }
                chosenPosition = availablePositions.GetRandom();
            }
            if (chosenPosition.IsValid)
            {
                spawnPos = chosenPosition.Position.ToVector2();
                if (chosenPosition.Submarine != null || chosenPosition.Ruin != null)
                {
                    var spawnPoint = WayPoint.GetRandom(SpawnType.Enemy, sub: chosenPosition.Submarine, ruin: chosenPosition.Ruin, useSyncedRand: false);
                    if (spawnPoint != null)
                    {
                        System.Diagnostics.Debug.Assert(spawnPoint.Submarine == chosenPosition.Submarine);
                        System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin);
                        spawnPos = spawnPoint.WorldPosition;
                    }
                }
                else if (chosenPosition.PositionType == Level.PositionType.MainPath && offset > 0)
                {
                    Vector2 dir;
                    var     waypoints       = WayPoint.WayPointList.FindAll(wp => wp.Submarine == null);
                    var     nearestWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, spawnPos.Value)).FirstOrDefault();
                    if (nearestWaypoint != null)
                    {
                        int currentIndex = waypoints.IndexOf(nearestWaypoint);
                        var nextWaypoint = waypoints[Math.Min(currentIndex + 20, waypoints.Count - 1)];
                        dir = Vector2.Normalize(nextWaypoint.WorldPosition - nearestWaypoint.WorldPosition);
                    }
                    else
                    {
                        dir = new Vector2(1, Rand.Range(-1, 1));
                    }
                    Vector2 targetPos      = spawnPos.Value + dir * offset;
                    var     targetWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, targetPos)).FirstOrDefault();
                    if (targetWaypoint != null)
                    {
                        spawnPos = targetWaypoint.WorldPosition;
                    }
                }
                spawnPending = true;
            }
        }
Ejemplo n.º 3
0
        private void FindSpawnPosition(bool affectSubImmediately)
        {
            if (disallowed)
            {
                return;
            }

            if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability)
            {
                spawnPos = null;
                Finished();
                return;
            }

            spawnPos = Vector2.Zero;
            var  availablePositions = GetAvailableSpawnPositions();
            var  chosenPosition     = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false);
            bool isSubOrWreck       = spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Wreck;

            if (affectSubImmediately && !isSubOrWreck && spawnPosType != Level.PositionType.Abyss)
            {
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    spawnPos = null;
                    Finished();
                    return;
                }
                Submarine refSub = GetReferenceSub();
                if (Submarine.MainSubs.Length == 2 && Submarine.MainSubs[1] != null)
                {
                    refSub = Submarine.MainSubs.GetRandom(Rand.RandSync.Unsynced);
                }
                float closestDist = float.PositiveInfinity;
                //find the closest spawnposition that isn't too close to any of the subs
                foreach (var position in availablePositions)
                {
                    Vector2 pos  = position.Position.ToVector2();
                    float   dist = Vector2.DistanceSquared(pos, refSub.WorldPosition);
                    foreach (Submarine sub in Submarine.Loaded)
                    {
                        if (sub.Info.Type != SubmarineType.Player && sub != GameMain.NetworkMember?.RespawnManager?.RespawnShuttle)
                        {
                            continue;
                        }

                        float minDistToSub = GetMinDistanceToSub(sub);
                        if (dist < minDistToSub * minDistToSub)
                        {
                            continue;
                        }

                        if (closestDist == float.PositiveInfinity)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                            continue;
                        }

                        //chosen position behind the sub -> override with anything that's closer or to the right
                        if (chosenPosition.Position.X < refSub.WorldPosition.X)
                        {
                            if (dist < closestDist || pos.X > refSub.WorldPosition.X)
                            {
                                closestDist    = dist;
                                chosenPosition = position;
                            }
                        }
                        //chosen position ahead of the sub -> only override with a position that's also ahead
                        else if (chosenPosition.Position.X > refSub.WorldPosition.X)
                        {
                            if (dist < closestDist && pos.X > refSub.WorldPosition.X)
                            {
                                closestDist    = dist;
                                chosenPosition = position;
                            }
                        }
                    }
                }
                //only found a spawnpos that's very far from the sub, pick one that's closer
                //and wait for the sub to move further before spawning
                if (closestDist > 15000.0f * 15000.0f)
                {
                    foreach (var position in availablePositions)
                    {
                        float dist = Vector2.DistanceSquared(position.Position.ToVector2(), refSub.WorldPosition);
                        if (dist < closestDist)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                        }
                    }
                }
            }
            else
            {
                if (!isSubOrWreck)
                {
                    float minDistance = 20000;
                    var   refSub      = GetReferenceSub();
                    availablePositions.RemoveAll(p => Vector2.DistanceSquared(refSub.WorldPosition, p.Position.ToVector2()) < minDistance * minDistance);
                    if (Submarine.MainSubs.Length > 1)
                    {
                        for (int i = 1; i < Submarine.MainSubs.Length; i++)
                        {
                            if (Submarine.MainSubs[i] == null)
                            {
                                continue;
                            }
                            availablePositions.RemoveAll(p => Vector2.DistanceSquared(Submarine.MainSubs[i].WorldPosition, p.Position.ToVector2()) < minDistance * minDistance);
                        }
                    }
                }
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    spawnPos = null;
                    Finished();
                    return;
                }
                chosenPosition = availablePositions.GetRandom();
            }
            if (chosenPosition.IsValid)
            {
                spawnPos = chosenPosition.Position.ToVector2();
                if (chosenPosition.Submarine != null || chosenPosition.Ruin != null)
                {
                    var spawnPoint = WayPoint.GetRandom(SpawnType.Enemy, sub: chosenPosition.Submarine, ruin: chosenPosition.Ruin, useSyncedRand: false);
                    if (spawnPoint != null)
                    {
                        System.Diagnostics.Debug.Assert(spawnPoint.Submarine == chosenPosition.Submarine);
                        System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin);
                        spawnPos = spawnPoint.WorldPosition;
                    }
                    else
                    {
                        //no suitable position found, disable the event
                        spawnPos = null;
                        Finished();
                        return;
                    }
                }
                else if ((chosenPosition.PositionType == Level.PositionType.MainPath || chosenPosition.PositionType == Level.PositionType.SidePath) &&
                         offset > 0)
                {
                    Vector2 dir;
                    var     waypoints       = WayPoint.WayPointList.FindAll(wp => wp.Submarine == null);
                    var     nearestWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, spawnPos.Value)).FirstOrDefault();
                    if (nearestWaypoint != null)
                    {
                        int currentIndex = waypoints.IndexOf(nearestWaypoint);
                        var nextWaypoint = waypoints[Math.Min(currentIndex + 20, waypoints.Count - 1)];
                        dir = Vector2.Normalize(nextWaypoint.WorldPosition - nearestWaypoint.WorldPosition);
                        // Ensure that the spawn position is not offset to the left.
                        if (dir.X < 0)
                        {
                            dir.X = 0;
                        }
                    }
                    else
                    {
                        dir = new Vector2(1, Rand.Range(-1, 1));
                    }
                    Vector2 targetPos      = spawnPos.Value + dir * offset;
                    var     targetWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, targetPos)).FirstOrDefault();
                    if (targetWaypoint != null)
                    {
                        spawnPos = targetWaypoint.WorldPosition;
                    }
                }
                spawnPending = true;
            }
        }
Ejemplo n.º 4
0
        private void FindSpawnPosition(bool affectSubImmediately)
        {
            if (disallowed)
            {
                return;
            }

            spawnPos = Vector2.Zero;
            var availablePositions = GetAvailableSpawnPositions();
            var chosenPosition     = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false);
            var removedPositions   = new List <Level.InterestingPosition>();

            foreach (var position in availablePositions)
            {
                if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability)
                {
                    removedPositions.Add(position);
                    if (prefab.AllowOnlyOnce)
                    {
                        Level.Loaded.UsedPositions.Add(position);
                    }
                }
            }
            removedPositions.ForEach(p => availablePositions.Remove(p));
            bool isSubOrWreck = spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Wreck;

            if (affectSubImmediately && !isSubOrWreck)
            {
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    Finished();
                    return;
                }
                float closestDist = float.PositiveInfinity;
                //find the closest spawnposition that isn't too close to any of the subs
                foreach (var position in availablePositions)
                {
                    Vector2 pos  = position.Position.ToVector2();
                    float   dist = Vector2.DistanceSquared(pos, Submarine.MainSub.WorldPosition);
                    foreach (Submarine sub in Submarine.Loaded)
                    {
                        if (sub.Info.Type != SubmarineInfo.SubmarineType.Player)
                        {
                            continue;
                        }
                        float minDistToSub = GetMinDistanceToSub(sub);
                        if (dist > minDistToSub * minDistToSub && dist < closestDist)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                        }
                    }
                }
                //only found a spawnpos that's very far from the sub, pick one that's closer
                //and wait for the sub to move further before spawning
                if (closestDist > 15000.0f * 15000.0f)
                {
                    foreach (var position in availablePositions)
                    {
                        float dist = Vector2.DistanceSquared(position.Position.ToVector2(), Submarine.MainSub.WorldPosition);
                        if (dist < closestDist)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                        }
                    }
                }
            }
            else
            {
                if (!isSubOrWreck)
                {
                    float minDistance = 20000;
                    availablePositions.RemoveAll(p => Vector2.DistanceSquared(Submarine.MainSub.WorldPosition, p.Position.ToVector2()) < minDistance * minDistance);
                }
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    Finished();
                    return;
                }
                chosenPosition = availablePositions.GetRandom();
            }
            if (chosenPosition.IsValid)
            {
                spawnPos = chosenPosition.Position.ToVector2();
                if (chosenPosition.Submarine != null || chosenPosition.Ruin != null)
                {
                    var spawnPoint = WayPoint.GetRandom(SpawnType.Enemy, sub: chosenPosition.Submarine, ruin: chosenPosition.Ruin, useSyncedRand: false);
                    if (spawnPoint != null)
                    {
                        System.Diagnostics.Debug.Assert(spawnPoint.Submarine == chosenPosition.Submarine);
                        System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin);
                        spawnPos = spawnPoint.WorldPosition;
                    }
                }
                spawnPending = true;
                if (prefab.AllowOnlyOnce)
                {
                    Level.Loaded.UsedPositions.Add(chosenPosition);
                }
            }
        }