Beispiel #1
0
        public void AddObjective <T>(T objective, float delay, Action callback = null) where T : AIObjective
        {
            if (objective == null)
            {
#if DEBUG
                DebugConsole.ThrowError($"{character.Name}: Attempted to add a null objective to AIObjectiveManager\n" + Environment.StackTrace.CleanupStackTrace());
#endif
                return;
            }
            if (DelayedObjectives.TryGetValue(objective, out CoroutineHandle coroutine))
            {
                CoroutineManager.StopCoroutines(coroutine);
                DelayedObjectives.Remove(objective);
            }
            coroutine = CoroutineManager.InvokeAfter(() =>
            {
                //round ended before the coroutine finished
#if CLIENT
                if (GameMain.GameSession == null || Level.Loaded == null && !(GameMain.GameSession.GameMode is TestGameMode))
                {
                    return;
                }
#else
                if (GameMain.GameSession == null || Level.Loaded == null)
                {
                    return;
                }
#endif
                DelayedObjectives.Remove(objective);
                AddObjective(objective);
                callback?.Invoke();
            }, delay);
            DelayedObjectives.Add(objective, coroutine);
        }
Beispiel #2
0
        public override void Update(float deltaTime)
        {
            if (IsClient)
            {
                return;
            }
            if (!swarmSpawned && level.CheckBeaconActive())
            {
                State = 1;

                Vector2 spawnPos = level.BeaconStation.WorldPosition;
                spawnPos.Y += level.BeaconStation.GetDockedBorders().Height * 1.5f;

                var availablePositions = Level.Loaded.PositionsOfInterest.FindAll(p =>
                                                                                  p.PositionType == Level.PositionType.MainPath ||
                                                                                  p.PositionType == Level.PositionType.SidePath);
                availablePositions.RemoveAll(p => Level.Loaded.ExtraWalls.Any(w => w.IsPointInside(p.Position.ToVector2())));
                availablePositions.RemoveAll(p => Submarine.FindContaining(p.Position.ToVector2()) != null);

                if (availablePositions.Any())
                {
                    Level.InterestingPosition?closestPos = null;
                    float closestDist = float.PositiveInfinity;
                    foreach (var pos in availablePositions)
                    {
                        float dist = Vector2.DistanceSquared(pos.Position.ToVector2(), level.BeaconStation.WorldPosition);
                        if (dist < closestDist)
                        {
                            closestDist = dist;
                            closestPos  = pos;
                        }
                    }
                    if (closestPos.HasValue)
                    {
                        spawnPos = closestPos.Value.Position.ToVector2();
                    }
                }

                int amount = Rand.Range(monsterCountRange.X, monsterCountRange.Y + 1);
                for (int i = 0; i < amount; i++)
                {
                    CoroutineManager.InvokeAfter(() =>
                    {
                        //round ended before the coroutine finished
                        if (GameMain.GameSession == null || Level.Loaded == null)
                        {
                            return;
                        }
                        Entity.Spawner.AddToSpawnQueue(monsterSpeciesName, spawnPos);
                    }, Rand.Range(0f, amount));
                }
                swarmSpawned = true;
            }
        }
Beispiel #3
0
 public void AddObjective(AIObjective objective, float delay, Action callback = null)
 {
     if (DelayedObjectives.TryGetValue(objective, out CoroutineHandle coroutine))
     {
         CoroutineManager.StopCoroutines(coroutine);
         DelayedObjectives.Remove(objective);
     }
     coroutine = CoroutineManager.InvokeAfter(() =>
     {
         DelayedObjectives.Remove(objective);
         AddObjective(objective);
         callback?.Invoke();
     }, delay);
     DelayedObjectives.Add(objective, coroutine);
 }
        public void AddObjective(AIObjective objective, float delay, Action callback = null)
        {
            if (objective == null)
            {
#if DEBUG
                DebugConsole.ThrowError("Attempted to add a null objective to AIObjectiveManager\n" + Environment.StackTrace);
#endif
                return;
            }
            if (DelayedObjectives.TryGetValue(objective, out CoroutineHandle coroutine))
            {
                CoroutineManager.StopCoroutines(coroutine);
                DelayedObjectives.Remove(objective);
            }
            coroutine = CoroutineManager.InvokeAfter(() =>
            {
                DelayedObjectives.Remove(objective);
                AddObjective(objective);
                callback?.Invoke();
            }, delay);
            DelayedObjectives.Add(objective, coroutine);
        }
Beispiel #5
0
        public override void Update(float deltaTime)
        {
            if (disallowed)
            {
                Finished();
                return;
            }

            if (isFinished)
            {
                return;
            }

            if (spawnPos == null)
            {
                FindSpawnPosition(affectSubImmediately: true);
                spawnPending = true;
            }

            bool spawnReady = false;

            if (spawnPending)
            {
                //if spawning in a ruin/cave, wait for someone to be close to it to spawning
                //unnecessary monsters in places the players might never visit during the round
                if (spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Cave || spawnPosType == Level.PositionType.Wreck)
                {
                    bool  someoneNearby = false;
                    float minDist       = Sonar.DefaultSonarRange * 0.8f;
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineInfo.SubmarineType.Player)
                        {
                            continue;
                        }
                        if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos.Value) < minDist * minDist)
                        {
                            someoneNearby = true;
                            break;
                        }
                    }
                    foreach (Character c in Character.CharacterList)
                    {
                        if (c == Character.Controlled || c.IsRemotePlayer)
                        {
                            if (Vector2.DistanceSquared(c.WorldPosition, spawnPos.Value) < minDist * minDist)
                            {
                                someoneNearby = true;
                                break;
                            }
                        }
                    }
                    if (!someoneNearby)
                    {
                        return;
                    }
                }
                else
                {
                    //wait until there are no submarines at the spawnpos
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineInfo.SubmarineType.Player)
                        {
                            continue;
                        }
                        float minDist = GetMinDistanceToSub(submarine);
                        if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos.Value) < minDist * minDist)
                        {
                            return;
                        }
                    }
                }

                spawnPending = false;

                //+1 because Range returns an integer less than the max value
                int amount = Rand.Range(minAmount, maxAmount + 1);
                monsters = new List <Character>();
                float offsetAmount = spawnPosType == Level.PositionType.MainPath ? scatter : 100;
                for (int i = 0; i < amount; i++)
                {
                    CoroutineManager.InvokeAfter(() =>
                    {
                        //round ended before the coroutine finished
                        if (GameMain.GameSession == null || Level.Loaded == null)
                        {
                            return;
                        }

                        System.Diagnostics.Debug.Assert(GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer, "Clients should not create monster events.");

                        Vector2 pos = spawnPos.Value + Rand.Vector(offsetAmount);
                        if (spawnPosType == Level.PositionType.MainPath)
                        {
                            if (Submarine.Loaded.Any(s => ToolBox.GetWorldBounds(s.Borders.Center, s.Borders.Size).ContainsWorld(pos)))
                            {
                                // Can't use the offset position, let's use the exact spawn position.
                                pos = spawnPos.Value;
                            }
                            else if (Level.Loaded.Ruins.Any(r => ToolBox.GetWorldBounds(r.Area.Center, r.Area.Size).ContainsWorld(pos)))
                            {
                                // Can't use the offset position, let's use the exact spawn position.
                                pos = spawnPos.Value;
                            }
                        }

                        monsters.Add(Character.Create(speciesName, pos, Level.Loaded.Seed + i.ToString(), null, false, true, true));

                        if (monsters.Count == amount)
                        {
                            spawnReady = true;
                            //this will do nothing if the monsters have no swarm behavior defined,
                            //otherwise it'll make the spawned characters act as a swarm
                            SwarmBehavior.CreateSwarm(monsters.Cast <AICharacter>());
                        }
                    }, Rand.Range(0f, amount / 2));
                }
            }

            if (!spawnReady)
            {
                return;
            }

            Entity targetEntity = Submarine.FindClosest(GameMain.GameScreen.Cam.WorldViewCenter);

#if CLIENT
            if (Character.Controlled != null)
            {
                targetEntity = Character.Controlled;
            }
#endif

            bool monstersDead = true;
            foreach (Character monster in monsters)
            {
                if (!monster.IsDead)
                {
                    monstersDead = false;

                    if (targetEntity != null && Vector2.DistanceSquared(monster.WorldPosition, targetEntity.WorldPosition) < 5000.0f * 5000.0f)
                    {
                        break;
                    }
                }
            }

            if (monstersDead)
            {
                Finished();
            }
        }
        public override void Update(float deltaTime)
        {
            if (disallowed)
            {
                Finished();
                return;
            }

            if (isFinished)
            {
                return;
            }

            //isActive = false;

            bool spawnReady = false;

            if (spawnPending)
            {
                //wait until there are no submarines at the spawnpos
                foreach (Submarine submarine in Submarine.Loaded)
                {
                    if (submarine.IsOutpost)
                    {
                        continue;
                    }
                    float minDist = GetMinDistanceToSub(submarine);
                    if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos) < minDist * minDist)
                    {
                        return;
                    }
                }

                spawnPending = false;

                //+1 because Range returns an integer less than the max value
                int amount = Rand.Range(minAmount, maxAmount + 1, Rand.RandSync.Server);
                monsters = new List <Character>();
                float offsetAmount = spawnPosType == Level.PositionType.MainPath ? 1000 : 100;
                for (int i = 0; i < amount; i++)
                {
                    CoroutineManager.InvokeAfter(() =>
                    {
                        bool isClient = GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
                        monsters.Add(Character.Create(characterFile, spawnPos + Rand.Vector(offsetAmount, Rand.RandSync.Server), i.ToString(), null, isClient, true, true));
                        if (monsters.Count == amount)
                        {
                            spawnReady = true;
                            //this will do nothing if the monsters have no swarm behavior defined,
                            //otherwise it'll make the spawned characters act as a swarm
                            SwarmBehavior.CreateSwarm(monsters.Cast <AICharacter>());
                        }
                    }, Rand.Range(0f, amount / 2, Rand.RandSync.Server));
                }
            }

            if (!spawnReady)
            {
                return;
            }

            Entity targetEntity = Submarine.FindClosest(GameMain.GameScreen.Cam.WorldViewCenter);

#if CLIENT
            if (Character.Controlled != null)
            {
                targetEntity = (Entity)Character.Controlled;
            }
#endif

            bool monstersDead = true;
            foreach (Character monster in monsters)
            {
                if (!monster.IsDead)
                {
                    monstersDead = false;

                    if (targetEntity != null && Vector2.DistanceSquared(monster.WorldPosition, targetEntity.WorldPosition) < 5000.0f * 5000.0f)
                    {
                        break;
                    }
                }
            }

            if (monstersDead)
            {
                Finished();
            }
        }
Beispiel #7
0
        public override void Update(float deltaTime)
        {
            if (disallowed)
            {
                Finished();
                return;
            }

            if (isFinished)
            {
                return;
            }

            if (spawnPos == null)
            {
                if (maxAmountPerLevel < int.MaxValue)
                {
                    if (Character.CharacterList.Count(c => c.SpeciesName == speciesName) >= maxAmountPerLevel)
                    {
                        disallowed = true;
                        return;
                    }
                }

                FindSpawnPosition(affectSubImmediately: true);
                //the event gets marked as finished if a spawn point is not found
                if (isFinished)
                {
                    return;
                }
                spawnPending = true;
            }

            bool spawnReady = false;

            if (spawnPending)
            {
                //wait until there are no submarines at the spawnpos
                if (spawnPosType.HasFlag(Level.PositionType.MainPath) || spawnPosType.HasFlag(Level.PositionType.SidePath) || spawnPosType.HasFlag(Level.PositionType.Abyss))
                {
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineType.Player)
                        {
                            continue;
                        }
                        float minDist = GetMinDistanceToSub(submarine);
                        if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos.Value) < minDist * minDist)
                        {
                            return;
                        }
                    }
                }

                //if spawning in a ruin/cave, wait for someone to be close to it to spawning
                //unnecessary monsters in places the players might never visit during the round
                if (spawnPosType.HasFlag(Level.PositionType.Ruin) || spawnPosType.HasFlag(Level.PositionType.Cave) || spawnPosType.HasFlag(Level.PositionType.Wreck))
                {
                    bool  someoneNearby = false;
                    float minDist       = Sonar.DefaultSonarRange * 0.8f;
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineType.Player)
                        {
                            continue;
                        }
                        if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos.Value) < minDist * minDist)
                        {
                            someoneNearby = true;
                            break;
                        }
                    }
                    foreach (Character c in Character.CharacterList)
                    {
                        if (c == Character.Controlled || c.IsRemotePlayer)
                        {
                            if (Vector2.DistanceSquared(c.WorldPosition, spawnPos.Value) < minDist * minDist)
                            {
                                someoneNearby = true;
                                break;
                            }
                        }
                    }
                    if (!someoneNearby)
                    {
                        return;
                    }
                }


                if (spawnPosType.HasFlag(Level.PositionType.Abyss) || spawnPosType.HasFlag(Level.PositionType.AbyssCave))
                {
                    bool anyInAbyss = false;
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineType.Player || submarine == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle)
                        {
                            continue;
                        }
                        if (submarine.WorldPosition.Y < 0)
                        {
                            anyInAbyss = true;
                            break;
                        }
                    }
                    if (!anyInAbyss)
                    {
                        return;
                    }
                }

                spawnPending = false;

                //+1 because Range returns an integer less than the max value
                int amount = Rand.Range(minAmount, maxAmount + 1);
                monsters = new List <Character>();
                float scatterAmount = scatter;
                if (spawnPosType.HasFlag(Level.PositionType.SidePath))
                {
                    var sidePaths = Level.Loaded.Tunnels.Where(t => t.Type == Level.TunnelType.SidePath);
                    if (sidePaths.Any())
                    {
                        scatterAmount = Math.Min(scatter, sidePaths.Min(t => t.MinWidth) / 2);
                    }
                    else
                    {
                        scatterAmount = scatter;
                    }
                }
                else if (!spawnPosType.HasFlag(Level.PositionType.MainPath))
                {
                    scatterAmount = 0;
                }
                for (int i = 0; i < amount; i++)
                {
                    string seed = Level.Loaded.Seed + i.ToString();
                    CoroutineManager.InvokeAfter(() =>
                    {
                        //round ended before the coroutine finished
                        if (GameMain.GameSession == null || Level.Loaded == null)
                        {
                            return;
                        }

                        System.Diagnostics.Debug.Assert(GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer, "Clients should not create monster events.");

                        Vector2 pos = spawnPos.Value + Rand.Vector(scatterAmount);
                        if (scatterAmount > 0)
                        {
                            if (Submarine.Loaded.Any(s => ToolBox.GetWorldBounds(s.Borders.Center, s.Borders.Size).ContainsWorld(pos)))
                            {
                                // Can't use the offset position, let's use the exact spawn position.
                                pos = spawnPos.Value;
                            }
                            else if (Level.Loaded.Ruins.Any(r => ToolBox.GetWorldBounds(r.Area.Center, r.Area.Size).ContainsWorld(pos)))
                            {
                                // Can't use the offset position, let's use the exact spawn position.
                                pos = spawnPos.Value;
                            }
                        }

                        Character createdCharacter = Character.Create(speciesName, pos, seed, characterInfo: null, isRemotePlayer: false, hasAi: true, createNetworkEvent: true);
                        if (GameMain.GameSession.IsCurrentLocationRadiated())
                        {
                            AfflictionPrefab radiationPrefab = AfflictionPrefab.RadiationSickness;
                            Affliction affliction            = new Affliction(radiationPrefab, radiationPrefab.MaxStrength);
                            createdCharacter?.CharacterHealth.ApplyAffliction(null, affliction);
                            // TODO test multiplayer
                            createdCharacter?.Kill(CauseOfDeathType.Affliction, affliction, log: false);
                        }
                        monsters.Add(createdCharacter);

                        if (monsters.Count == amount)
                        {
                            spawnReady = true;
                            //this will do nothing if the monsters have no swarm behavior defined,
                            //otherwise it'll make the spawned characters act as a swarm
                            SwarmBehavior.CreateSwarm(monsters.Cast <AICharacter>());
                        }
                    }, Rand.Range(0f, amount / 2f));
                }
            }

            if (!spawnReady)
            {
                return;
            }

            Entity targetEntity = Submarine.FindClosest(GameMain.GameScreen.Cam.WorldViewCenter);

#if CLIENT
            if (Character.Controlled != null)
            {
                targetEntity = Character.Controlled;
            }
#endif

            bool monstersDead = true;
            foreach (Character monster in monsters)
            {
                if (!monster.IsDead)
                {
                    monstersDead = false;

                    if (targetEntity != null && Vector2.DistanceSquared(monster.WorldPosition, targetEntity.WorldPosition) < 5000.0f * 5000.0f)
                    {
                        break;
                    }
                }
            }

            if (monstersDead)
            {
                Finished();
            }
        }