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