예제 #1
0
        private void UpdateEating(float deltaTime)
        {
            if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed)
            {
                state = AIState.None;
                return;
            }

            Limb mouthLimb = Array.Find(Character.AnimController.Limbs, l => l != null && l.MouthPos.HasValue);

            if (mouthLimb == null)
            {
                mouthLimb = Character.AnimController.GetLimb(LimbType.Head);
            }

            if (mouthLimb == null)
            {
                DebugConsole.ThrowError("Character \"" + Character.SpeciesName + "\" failed to eat a target (a head or a limb with a mouthpos required)");
                state = AIState.None;
                return;
            }

            Character targetCharacter = selectedAiTarget.Entity as Character;
            float     eatSpeed        = Character.Mass / targetCharacter.Mass * 0.1f;

            eatTimer += deltaTime * eatSpeed;

            Vector2 mouthPos = mouthLimb.SimPosition;

            if (mouthLimb.MouthPos.HasValue)
            {
                float cos = (float)Math.Cos(mouthLimb.Rotation);
                float sin = (float)Math.Sin(mouthLimb.Rotation);

                mouthPos += new Vector2(
                    mouthLimb.MouthPos.Value.X * cos - mouthLimb.MouthPos.Value.Y * sin,
                    mouthLimb.MouthPos.Value.X * sin + mouthLimb.MouthPos.Value.Y * cos);
            }

            Vector2 attackSimPosition = Character.Submarine == null?ConvertUnits.ToSimUnits(selectedAiTarget.WorldPosition) : selectedAiTarget.SimPosition;

            Vector2 limbDiff = attackSimPosition - mouthPos;
            float   limbDist = limbDiff.Length();

            if (limbDist < 1.0f)
            {
                //pull the target character to the position of the mouth
                //(+ make the force fluctuate to waggle the character a bit)
                targetCharacter.AnimController.MainLimb.MoveToPos(mouthPos, (float)(Math.Sin(eatTimer) + 10.0f));
                targetCharacter.AnimController.MainLimb.body.SmoothRotate(mouthLimb.Rotation);
                targetCharacter.AnimController.Collider.MoveToPos(mouthPos, (float)(Math.Sin(eatTimer) + 10.0f));

                //pull the character's mouth to the target character (again with a fluctuating force)
                float pullStrength = (float)(Math.Sin(eatTimer) * Math.Max(Math.Sin(eatTimer * 0.5f), 0.0f));
                steeringManager.SteeringManual(deltaTime, limbDiff * pullStrength);
                mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength);

                //GameMain.NilMod.CreatureHealthGainEatingPercent;

                if (eatTimer % 1.0f < 0.5f && (eatTimer - deltaTime * eatSpeed) % 1.0f > 0.5f)
                {
                    //Kill living players that control the character if being actively consumed.
                    //Before this point is reached a fish could be prevented with stun from severing limbs and thus still save a player.
                    if (!targetCharacter.IsDead && targetCharacter.IsRemotePlayer)
                    {
                        targetCharacter.Kill(CauseOfDeath.Damage, true);
                    }

                    //apply damage to the target character to get some blood particles flying
                    targetCharacter.AnimController.MainLimb.AddDamage(targetCharacter.SimPosition, DamageType.None, Rand.Range(10.0f, 25.0f), Rand.Range(15.0f, 40.0f), false);

                    //Lets make this extra bloody, perhaps a client will sync it.
                    targetCharacter.AnimController.MainLimb.AddDamage(targetCharacter.SimPosition, DamageType.None, Rand.Range(10.0f, 25.0f), Rand.Range(15.0f, 40.0f), false);
                    targetCharacter.AnimController.MainLimb.AddDamage(targetCharacter.SimPosition, DamageType.None, Rand.Range(10.0f, 25.0f), Rand.Range(15.0f, 40.0f), false);
                    targetCharacter.AnimController.MainLimb.AddDamage(targetCharacter.SimPosition, DamageType.None, Rand.Range(10.0f, 25.0f), Rand.Range(15.0f, 40.0f), false);

                    //keep severing joints until there is only one limb left
                    LimbJoint[] nonSeveredJoints = Array.FindAll(targetCharacter.AnimController.LimbJoints, l => !l.IsSevered && l.CanBeSevered);
                    if (nonSeveredJoints.Length == 0)
                    {
                        //only one limb left, the character is now full eaten

                        if (GameMain.Server != null)
                        {
                            GameMain.Server.ServerLog.WriteLine(Character.Name + " has finished eating " + targetCharacter.Name, Networking.ServerLog.MessageType.Spawns);
                        }

                        Entity.Spawner.AddToRemoveQueue(targetCharacter);

                        selectedAiTarget = null;
                        state            = AIState.None;
                    }
                    else //sever a random joint
                    {
                        targetCharacter.AnimController.SeverLimbJoint(nonSeveredJoints[Rand.Int(nonSeveredJoints.Length)]);
                        if (GameMain.Server != null)
                        {
                            GameMain.Server.CreateEntityEvent(targetCharacter, new object[] { Barotrauma.Networking.NetEntityEvent.Type.Status });
                        }
                    }
                }
            }
            else if (limbDist < 2.0f)
            {
                steeringManager.SteeringManual(deltaTime, limbDiff);
                Character.AnimController.Collider.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f, mouthPos);
            }
            else
            {
                steeringManager.SteeringSeek(attackSimPosition - (mouthPos - SimPosition), 3);
            }
        }
예제 #2
0
        public void RunIngameCommand(string Command, Object[] Arguments)
        {
            Vector2   WorldCoordinate = new Vector2(0, 0);
            Character character       = null;

            //Server Commands
            if (GameMain.Server != null)
            {
                switch (Command)
                {
                case "spawncreature":
                    //ARG0 = Character, ARG1 = WorldPosX, ARG2 = WorldPosY
                    WorldCoordinate = new Vector2(float.Parse(Arguments[1].ToString()), float.Parse(Arguments[2].ToString()));

                    if (Arguments[0].ToString().ToLowerInvariant() == "human")
                    {
                        character = Character.Create(Character.HumanConfigFile, WorldCoordinate);
                    }
                    else
                    {
                        System.Collections.Generic.List <string> characterFiles = GameMain.Config.SelectedContentPackage.GetFilesOfType(ContentType.Character);

                        foreach (string characterFile in characterFiles)
                        {
                            if (System.IO.Path.GetFileNameWithoutExtension(characterFile).ToLowerInvariant() == Arguments[0].ToString().ToLowerInvariant())
                            {
                                character = Character.Create(
                                    characterFile, WorldCoordinate);
                            }
                        }
                    }
                    break;

                case "control":
                    //ARG0 = client ARG1 = Character
                    if ((Barotrauma.Networking.Client)Arguments[0] != null)
                    {
                        GameMain.Server.SetClientCharacter((Barotrauma.Networking.Client)Arguments[0], null);
                    }

                    character = (Character)Arguments[1];

                    if (character != null)
                    {
                        Character.Controlled = character;
                    }
                    break;

                case "shield":
                    //ARG0 = Character, ARG1 = shield state
                    character          = (Character)Arguments[0];
                    character.Shielded = (Boolean)Arguments[1];

                    if (GameMain.Server != null)
                    {
                        GameMain.NetworkMember.AddChatMessage(
                            ((Boolean)Arguments[1] ?
                             character.LogName + " is now shielded from health/oxygen/pressure."
                                : character.LogName + " is no longer shielded.")
                            , Barotrauma.Networking.ChatMessageType.Private);
                    }
                    break;

                case "heal":
                    //ARG0 = Character
                    character = (Character)Arguments[0];
                    character.Heal();
                    break;

                case "revive":
                    //ARG0 = Character
                    character = (Character)Arguments[0];
                    character.Revive(true);
                    break;

                case "kill":
                    //ARG0 = Character
                    character = (Character)Arguments[0];
                    character.Kill(CauseOfDeath.Disconnected, true);
                    break;

                case "removecorpse":
                    //ARG0 = Character
                    character = (Character)Arguments[0];
                    Entity.Spawner.AddToRemoveQueue(character);
                    break;

                case "teleportsub":
                    //ARG0 = SUBID, ARG1 = WorldPosX, ARG2 = WorldPosY
                    WorldCoordinate = new Vector2(float.Parse(Arguments[1].ToString()), float.Parse(Arguments[2].ToString()));
                    GameMain.Server.MoveSub(int.Parse(Arguments[0].ToString()), WorldCoordinate);
                    break;

                case "relocate":
                    //ARG0 = Character, ARG1 = WorldPosX, ARG2 = WorldPosY

                    character = (Character)Arguments[0];
                    if (!character.Enabled)
                    {
                        character.Enabled = true;
                    }
                    WorldCoordinate = new Vector2(float.Parse(Arguments[1].ToString()), float.Parse(Arguments[2].ToString()));

                    character.AnimController.CurrentHull = null;
                    character.Submarine = null;
                    character.AnimController.SetPosition(FarseerPhysics.ConvertUnits.ToSimUnits(WorldCoordinate));
                    character.AnimController.FindHull(WorldCoordinate, true);
                    break;

                //case "handcuff":
                //ARG0 = Character
                //break;

                case "freeze":
                    //ARG0 = Character

                    character = (Character)Arguments[0];

                    if (GameMain.NilMod.FrozenCharacters.Find(c => c == character) != null)
                    {
                        GameMain.NilMod.FrozenCharacters.Remove(character);

                        if (GameMain.Server.ConnectedClients.Find(c => c.Character == character) != null)
                        {
                            var chatMsg = Barotrauma.Networking.ChatMessage.Create(
                                "Server Message",
                                ("You have been frozen by the server\n\nYou may now move again and perform actions."),
                                (Barotrauma.Networking.ChatMessageType)Barotrauma.Networking.ChatMessageType.MessageBox,
                                null);

                            GameMain.Server.SendChatMessage(chatMsg, GameMain.Server.ConnectedClients.Find(c => c.Character == character));
                        }
                    }
                    else
                    {
                        GameMain.NilMod.FrozenCharacters.Add(character);

                        if (GameMain.Server.ConnectedClients.Find(c => c.Character == character) != null)
                        {
                            var chatMsg = Barotrauma.Networking.ChatMessage.Create(
                                "Server Message",
                                ("You have been frozen by the server\n\nYou may still talk if able, but no longer perform any actions or movements."),
                                (Barotrauma.Networking.ChatMessageType)Barotrauma.Networking.ChatMessageType.MessageBox,
                                null);

                            GameMain.Server.SendChatMessage(chatMsg, GameMain.Server.ConnectedClients.Find(c => c.Character == character));
                        }
                    }
                    break;

                case "setclientcharacter":
                    //ARG0 = Client, ARG1 = Character
                    GameMain.Server.SetClientCharacter((Barotrauma.Networking.Client)Arguments[0], (Character)Arguments[1]);
                    break;

                default:
                    DebugConsole.ThrowError(@"NILMOD Error: Unrecognized Command Execution: """ + Command + @"""");
                    break;
                }
            }
        }
예제 #3
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 == Level.PositionType.MainPath || spawnPosType == Level.PositionType.SidePath || spawnPosType == 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 == 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 != 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 == Level.PositionType.Abyss || spawnPosType == Level.PositionType.AbyssCave)
                {
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineType.Player)
                        {
                            continue;
                        }
                        if (submarine.WorldPosition.Y > 0)
                        {
                            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 || spawnPosType == Level.PositionType.SidePath ? scatter : 100;
                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(offsetAmount);
                        if (spawnPosType == Level.PositionType.MainPath || spawnPosType == Level.PositionType.SidePath)
                        {
                            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();
            }
        }