public Hull(MapEntityPrefab prefab, Rectangle rectangle, Submarine submarine)
            : base(prefab, submarine)
        {
            rect = rectangle;

            OxygenPercentage = 100.0f;

            fireSources = new List <FireSource>();

            properties = SerializableProperty.GetProperties(this);

            int arraySize = (rectangle.Width / WaveWidth + 1);

            waveY   = new float[arraySize];
            waveVel = new float[arraySize];

            leftDelta  = new float[arraySize];
            rightDelta = new float[arraySize];

            surface = rect.Y - rect.Height;

            aiTarget = new AITarget(this);

            hullList.Add(this);

            ConnectedGaps = new List <Gap>();

            if (submarine == null || !submarine.Loading)
            {
                Item.UpdateHulls();
                Gap.UpdateHulls();
            }

            WaterVolume = 0.0f;

            InsertToList();
        }
Example #2
0
        //goes through all the AItargets, evaluates how preferable it is to attack the target,
        //whether the Character can see/hear the target and chooses the most preferable target within
        //sight/hearing range
        public void UpdateTargets(Character character)
        {
            var prevAiTarget = selectedAiTarget;

            selectedAiTarget     = null;
            selectedTargetMemory = null;
            targetValue          = 0.0f;

            UpdateTargetMemories();

            foreach (AITarget target in AITarget.List)
            {
                if (Level.Loaded != null && target.WorldPosition.Y > Level.Loaded.Size.Y)
                {
                    continue;
                }

                float valueModifier = 0.0f;
                float dist          = 0.0f;


                Character targetCharacter = target.Entity as Character;

                //ignore the aitarget if it is the Character itself
                if (targetCharacter == character)
                {
                    continue;
                }

                if (targetCharacter != null)
                {
                    if (targetCharacter.IsDead)
                    {
                        if (eatDeadPriority == 0.0f)
                        {
                            continue;
                        }
                        valueModifier = eatDeadPriority;
                    }
                    else if (targetCharacter.SpeciesName == "human")
                    {
                        if (attackHumans == 0.0f)
                        {
                            continue;
                        }
                        valueModifier = attackHumans;
                    }
                    else
                    {
                        EnemyAIController enemy = targetCharacter.AIController as EnemyAIController;
                        if (enemy != null)
                        {
                            if (enemy.combatStrength > combatStrength)
                            {
                                valueModifier = attackStronger;
                            }
                            else if (enemy.combatStrength < combatStrength)
                            {
                                valueModifier = attackWeaker;
                            }
                            else
                            {
                                continue;
                            }
                        }
                    }
                }
                else if (target.Entity != null && attackRooms != 0.0f)
                {
                    IDamageable targetDamageable = target.Entity as IDamageable;
                    if (targetDamageable != null && targetDamageable.Health <= 0.0f)
                    {
                        continue;
                    }

                    //skip the target if it's a room and the character is already inside a sub
                    if (character.AnimController.CurrentHull != null && target.Entity is Hull)
                    {
                        continue;
                    }

                    valueModifier = attackRooms;
                }

                if (valueModifier == 0.0f)
                {
                    continue;
                }

                dist = Vector2.Distance(character.WorldPosition, target.WorldPosition);

                //if the target has been within range earlier, the character will notice it more easily
                //(i.e. remember where the target was)
                if (targetMemories.ContainsKey(target))
                {
                    dist *= 0.5f;
                }

                //ignore target if it's too far to see or hear
                if (dist > target.SightRange * sight && dist > target.SoundRange * hearing)
                {
                    continue;
                }

                AITargetMemory targetMemory = FindTargetMemory(target);
                valueModifier = valueModifier * targetMemory.Priority / dist;

                if (Math.Abs(valueModifier) > Math.Abs(targetValue))
                {
                    Vector2 rayStart = character.AnimController.Limbs[0].SimPosition;
                    Vector2 rayEnd   = target.SimPosition;

                    if (target.Entity.Submarine != null && character.Submarine == null)
                    {
                        rayStart -= ConvertUnits.ToSimUnits(target.Entity.Submarine.Position);
                    }

                    Body      closestBody      = Submarine.CheckVisibility(rayStart, rayEnd);
                    Structure closestStructure = (closestBody == null) ? null : closestBody.UserData as Structure;

                    if (selectedAiTarget == null || Math.Abs(valueModifier) > Math.Abs(targetValue))
                    {
                        selectedAiTarget     = target;
                        selectedTargetMemory = targetMemory;

                        targetValue = valueModifier;
                    }
                }
            }

            if (selectedAiTarget != prevAiTarget)
            {
                wallAttackPos = Vector2.Zero;
            }
        }
Example #3
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);

                if (eatTimer % 1.0f < 0.5f && (eatTimer - deltaTime * eatSpeed) % 1.0f > 0.5f)
                {
                    //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), 10.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
                        Entity.Spawner.AddToRemoveQueue(targetCharacter);
                        selectedAiTarget = null;
                        state            = AIState.None;
                    }
                    else //sever a random joint
                    {
                        targetCharacter.AnimController.SeverLimbJoint(nonSeveredJoints[Rand.Int(nonSeveredJoints.Length)]);
                    }
                }
            }
            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);
            }
        }
 public override void SelectTarget(AITarget target)
 {
     SelectedAiTarget = target;
 }
Example #5
0
 protected virtual void OnTargetChanged(AITarget previousTarget, AITarget newTarget)
 {
 }
Example #6
0
 public virtual void SelectTarget(AITarget target)
 {
 }
Example #7
0
        public Structure(Rectangle rectangle, StructurePrefab sp, Submarine submarine)
            : base(sp, submarine)
        {
            if (rectangle.Width == 0 || rectangle.Height == 0)
            {
                return;
            }
            System.Diagnostics.Debug.Assert(rectangle.Width > 0 && rectangle.Height > 0);

            rect = rectangle;
#if CLIENT
            TextureScale = sp.TextureScale;
#endif
            spriteColor = prefab.SpriteColor;
            if (ResizeHorizontal && !ResizeVertical)
            {
                IsHorizontal = true;
            }
            else if (ResizeVertical && !ResizeHorizontal)
            {
                IsHorizontal = false;
            }
            else
            {
                if (BodyWidth > 0.0f && BodyHeight > 0.0f)
                {
                    IsHorizontal = BodyWidth > BodyHeight;
                }
                else
                {
                    IsHorizontal = (rect.Width > rect.Height);
                }
            }

            StairDirection         = Prefab.StairDirection;
            SerializableProperties = SerializableProperty.GetProperties(this);

            InitProjSpecific();

            if (Prefab.Body)
            {
                Bodies = new List <Body>();
                WallList.Add(this);

                CreateSections();
                UpdateSections();
            }
            else
            {
                Sections    = new WallSection[1];
                Sections[0] = new WallSection(rect);

                if (StairDirection != Direction.None)
                {
                    CreateStairBodies();
                }
            }

            // Only add ai targets automatically to walls
            if (aiTarget == null && HasBody && Tags.Contains("wall"))
            {
                aiTarget = new AITarget(this);
            }

            InsertToList();
        }
Example #8
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);
            }
        }
 protected void ResetAITarget()
 {
     _lastAiTarget     = null;
     _selectedAiTarget = null;
 }
Example #10
0
        protected override void Act(float deltaTime)
        {
            var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager;

            if (pathSteering == null)
            {
                return;
            }

            if (newTargetTimer <= 0.0f)
            {
                currentTarget = FindRandomTarget();

                if (currentTarget != null)
                {
                    Vector2 pos = character.SimPosition;
                    if (character != null && character.Submarine == null)
                    {
                        pos -= Submarine.MainSub.SimPosition;
                    }

                    var path = pathSteering.PathFinder.FindPath(pos, currentTarget.SimPosition);
                    if (path.Cost > 200.0f && character.AnimController.CurrentHull != null)
                    {
                        return;
                    }

                    pathSteering.SetPath(path);
                }


                newTargetTimer = currentTarget == null ? 5.0f : 15.0f;
            }

            newTargetTimer -= deltaTime;


            //wander randomly
            // - if reached the end of the path
            // - if the target is unreachable
            // - if the path requires going outside
            if (pathSteering == null || (pathSteering.CurrentPath != null &&
                                         (pathSteering.CurrentPath.NextNode == null || pathSteering.CurrentPath.Unreachable || pathSteering.CurrentPath.HasOutdoorsNodes)))
            {
                //steer away from edges of the hull
                if (character.AnimController.CurrentHull != null)
                {
                    float leftDist  = character.Position.X - character.AnimController.CurrentHull.Rect.X;
                    float rightDist = character.AnimController.CurrentHull.Rect.Right - character.Position.X;

                    if (leftDist < WallAvoidDistance && rightDist < WallAvoidDistance)
                    {
                        if (Math.Abs(rightDist - leftDist) > WallAvoidDistance / 2)
                        {
                            pathSteering.SteeringManual(deltaTime, Vector2.UnitX * Math.Sign(rightDist - leftDist));
                        }
                        else
                        {
                            pathSteering.Reset();
                            return;
                        }
                    }
                    else if (leftDist < WallAvoidDistance)
                    {
                        pathSteering.SteeringManual(deltaTime, Vector2.UnitX * (WallAvoidDistance - leftDist) / WallAvoidDistance);
                        pathSteering.WanderAngle = 0.0f;
                        return;
                    }
                    else if (rightDist < WallAvoidDistance)
                    {
                        pathSteering.SteeringManual(deltaTime, -Vector2.UnitX * (WallAvoidDistance - rightDist) / WallAvoidDistance);
                        pathSteering.WanderAngle = MathHelper.Pi;
                        return;
                    }
                }

                if (character.AnimController.InWater)
                {
                    character.AIController.SteeringManager.SteeringManual(deltaTime, new Vector2(0.0f, 0.5f));
                }
                else
                {
                    character.AIController.SteeringManager.SteeringWander();
                    //reset vertical steering to prevent dropping down from platforms etc
                    character.AIController.SteeringManager.ResetY();
                }

                return;
            }

            if (currentTarget == null)
            {
                return;
            }
            character.AIController.SteeringManager.SteeringSeek(currentTarget.SimPosition, 2.0f);
        }