public override void Start(Level level)
        {
            Level.Loaded.TryGetInterestingPosition(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out Vector2 spawnPos);

            bool isClient = IsClient;

            if (!string.IsNullOrEmpty(monsterFile))
            {
                for (int i = 0; i < monsterCount; i++)
                {
                    monsters.Add(Character.Create(monsterFile, spawnPos, ToolBox.RandomSeed(8), null, isClient, true, false));
                }
            }
            foreach (var monster in monsterFiles)
            {
                for (int i = 0; i < monster.Item2; i++)
                {
                    monsters.Add(Character.Create(monster.Item1, spawnPos, ToolBox.RandomSeed(8), null, isClient, true, false));
                }
            }

            monsters.ForEach(m => m.Enabled = false);
            SwarmBehavior.CreateSwarm(monsters.Cast <AICharacter>());
            sonarPositions.Add(spawnPos);
        }
Beispiel #2
0
 private void InitializeMonsters(IEnumerable <Character> monsters)
 {
     foreach (var monster in monsters)
     {
         monster.Enabled = false;
         if (monster.Params.AI.EnforceAggressiveBehaviorForMissions)
         {
             foreach (var targetParam in monster.Params.AI.Targets)
             {
                 switch (targetParam.State)
                 {
                 case AIState.Avoid:
                 case AIState.Escape:
                 case AIState.Flee:
                 case AIState.PassiveAggressive:
                     targetParam.State = AIState.Attack;
                     break;
                 }
             }
         }
     }
     SwarmBehavior.CreateSwarm(monsters.Cast <AICharacter>());
     foreach (Character monster in monsters)
     {
         tempSonarPositions.Add(monster.WorldPosition + Rand.Vector(maxSonarMarkerDistance));
     }
     if (monsters.Count() != tempSonarPositions.Count)
     {
         throw new Exception($"monsters.Count != tempSonarPositions.Count ({monsters.Count()} != {tempSonarPositions.Count})");
     }
 }
        public override void Start(Level level)
        {
            Level.Loaded.TryGetInterestingPosition(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out Vector2 spawnPos);

            bool isClient = GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;

            for (int i = 0; i < monsterCount; i++)
            {
                monsters.Add(Character.Create(monsterFile, spawnPos, ToolBox.RandomSeed(8), null, isClient, true, false));
            }
            monsters.ForEach(m => m.Enabled = false);
            SwarmBehavior.CreateSwarm(monsters.Cast <AICharacter>());
            sonarPositions.Add(spawnPos);
        }
Beispiel #4
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();
            }
        }
        protected void Apply(float deltaTime, Entity entity, List <ISerializableEntity> targets, Vector2?worldPosition = null)
        {
            if (lifeTime > 0)
            {
                lifeTimer -= deltaTime;
                if (lifeTimer <= 0)
                {
                    return;
                }
            }

            Hull hull = null;

            if (entity is Character)
            {
                hull = ((Character)entity).AnimController.CurrentHull;
            }
            else if (entity is Item)
            {
                hull = ((Item)entity).CurrentHull;
            }

            Vector2 position = worldPosition ?? entity.WorldPosition;

            if (targetLimb != LimbType.None)
            {
                if (entity is Character c)
                {
                    Limb limb = c.AnimController.GetLimb(targetLimb);
                    if (limb != null)
                    {
                        position = limb.WorldPosition;
                    }
                }
            }

            foreach (ISerializableEntity serializableEntity in targets)
            {
                if (!(serializableEntity is Item item))
                {
                    continue;
                }

                Character targetCharacter = targets.FirstOrDefault(t => t is Character character && !character.Removed) as Character;
                if (targetCharacter == null)
                {
                    foreach (var target in targets)
                    {
                        if (target is Limb limb && limb.character != null && !limb.character.Removed)
                        {
                            targetCharacter = ((Limb)target).character;
                        }
                    }
                }
                for (int i = 0; i < useItemCount; i++)
                {
                    if (item.Removed)
                    {
                        continue;
                    }
                    item.Use(deltaTime, targetCharacter, targets.FirstOrDefault(t => t is Limb) as Limb);
                }
            }

            if (removeItem)
            {
                foreach (var target in targets)
                {
                    if (target is Item item)
                    {
                        Entity.Spawner?.AddToRemoveQueue(item);
                    }
                }
            }
            if (removeCharacter)
            {
                foreach (var target in targets)
                {
                    if (target is Character character)
                    {
                        Entity.Spawner?.AddToRemoveQueue(character);
                    }
                }
            }

            if (duration > 0.0f)
            {
                DurationListElement element = new DurationListElement
                {
                    Parent  = this,
                    Timer   = duration,
                    Entity  = entity,
                    Targets = targets,
                    User    = user
                };

                DurationList.Add(element);
            }
            else
            {
                foreach (ISerializableEntity target in targets)
                {
                    if (target is Entity targetEntity)
                    {
                        if (targetEntity.Removed)
                        {
                            continue;
                        }
                    }

                    for (int i = 0; i < propertyNames.Length; i++)
                    {
                        if (target == null || target.SerializableProperties == null ||
                            !target.SerializableProperties.TryGetValue(propertyNames[i], out SerializableProperty property))
                        {
                            continue;
                        }
                        ApplyToProperty(target, property, propertyEffects[i], deltaTime);
                    }
                }
            }

            if (explosion != null && entity != null)
            {
                explosion.Explode(position, damageSource: entity, attacker: user);
            }

            foreach (ISerializableEntity target in targets)
            {
                foreach (Affliction affliction in Afflictions)
                {
                    Affliction multipliedAffliction = affliction;
                    if (!disableDeltaTime)
                    {
                        multipliedAffliction = affliction.CreateMultiplied(deltaTime);
                    }

                    if (target is Character character)
                    {
                        if (character.Removed)
                        {
                            continue;
                        }
                        character.LastDamageSource = entity;
                        foreach (Limb limb in character.AnimController.Limbs)
                        {
                            limb.character.DamageLimb(position, limb, new List <Affliction>()
                            {
                                multipliedAffliction
                            }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source);
                            limb.character.TrySeverLimbJoints(limb, SeverLimbsProbability);
                            //only apply non-limb-specific afflictions to the first limb
                            if (!affliction.Prefab.LimbSpecific)
                            {
                                break;
                            }
                        }
                    }
                    else if (target is Limb limb)
                    {
                        if (limb.character.Removed)
                        {
                            continue;
                        }
                        limb.character.DamageLimb(position, limb, new List <Affliction>()
                        {
                            multipliedAffliction
                        }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source);
                        limb.character.TrySeverLimbJoints(limb, SeverLimbsProbability);
                    }
                }

                foreach (Pair <string, float> reduceAffliction in ReduceAffliction)
                {
                    float     reduceAmount    = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime;
                    Limb      targetLimb      = null;
                    Character targetCharacter = null;
                    if (target is Character character)
                    {
                        targetCharacter = character;
                    }
                    else if (target is Limb limb)
                    {
                        targetLimb      = limb;
                        targetCharacter = limb.character;
                    }
                    if (targetCharacter != null && !targetCharacter.Removed)
                    {
                        float prevVitality = targetCharacter.Vitality;
                        targetCharacter.CharacterHealth.ReduceAffliction(targetLimb, reduceAffliction.First, reduceAmount);
#if SERVER
                        GameMain.Server.KarmaManager.OnCharacterHealthChanged(targetCharacter, user, prevVitality - targetCharacter.Vitality);
#endif
                    }
                }
            }

            if (FireSize > 0.0f && entity != null)
            {
                var fire = new FireSource(position, hull);
                fire.Size = new Vector2(FireSize, fire.Size.Y);
            }

            bool isNotClient = GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient;
            if (isNotClient && entity != null && Entity.Spawner != null) //clients are not allowed to spawn entities
            {
                foreach (CharacterSpawnInfo characterSpawnInfo in spawnCharacters)
                {
                    var characters = new List <Character>();
                    for (int i = 0; i < characterSpawnInfo.Count; i++)
                    {
                        Entity.Spawner.AddToSpawnQueue(characterSpawnInfo.SpeciesName, position + Rand.Vector(characterSpawnInfo.Spread, Rand.RandSync.Server),
                                                       onSpawn: newCharacter =>
                        {
                            characters.Add(newCharacter);
                            if (characters.Count == characterSpawnInfo.Count)
                            {
                                SwarmBehavior.CreateSwarm(characters.Cast <AICharacter>());
                            }
                        });
                    }
                }
                foreach (ItemSpawnInfo itemSpawnInfo in spawnItems)
                {
                    switch (itemSpawnInfo.SpawnPosition)
                    {
                    case ItemSpawnInfo.SpawnPositionType.This:
                        Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, position);
                        break;

                    case ItemSpawnInfo.SpawnPositionType.ThisInventory:
                    {
                        if (entity is Character character)
                        {
                            if (character.Inventory != null && character.Inventory.Items.Any(it => it == null))
                            {
                                Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, character.Inventory);
                            }
                        }
                        else if (entity is Item item)
                        {
                            var inventory = item?.GetComponent <ItemContainer>()?.Inventory;
                            if (inventory != null && inventory.Items.Any(it => it == null))
                            {
                                Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, inventory);
                            }
                        }
                    }
                    break;

                    case ItemSpawnInfo.SpawnPositionType.ContainedInventory:
                    {
                        Inventory thisInventory = null;
                        if (entity is Character character)
                        {
                            thisInventory = character.Inventory;
                        }
                        else if (entity is Item item)
                        {
                            thisInventory = item?.GetComponent <ItemContainer>()?.Inventory;
                        }
                        if (thisInventory != null)
                        {
                            foreach (Item item in thisInventory.Items)
                            {
                                if (item == null)
                                {
                                    continue;
                                }
                                Inventory containedInventory = item.GetComponent <ItemContainer>()?.Inventory;
                                if (containedInventory == null || !containedInventory.Items.Any(i => i == null))
                                {
                                    continue;
                                }
                                Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, containedInventory);
                                break;
                            }
                        }
                    }
                    break;
                    }
                }
            }

            ApplyProjSpecific(deltaTime, entity, targets, hull, position);
        }
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.Invoke(() =>
                    {
                        //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();
            }
        }