Exemplo n.º 1
0
        public void ThalamusOperate(WreckAI ai, float deltaTime, bool targetHumans, bool targetOtherCreatures, bool targetSubmarines, bool ignoreDelay)
        {
            if (ai == null)
            {
                return;
            }

            IsActive = true;

            if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
            {
                return;
            }

            if (updatePending)
            {
                if (updateTimer < 0.0f)
                {
#if SERVER
                    item.CreateServerEvent(this);
#endif
                    prevTargetRotation = targetRotation;
                    updateTimer        = 0.25f;
                }
                updateTimer -= deltaTime;
            }

            if (!ignoreDelay && waitTimer > 0)
            {
                waitTimer -= deltaTime;
                return;
            }
            Submarine      closestSub    = null;
            float          maxDistance   = 10000.0f;
            float          shootDistance = AIRange;
            ISpatialEntity target        = null;
            float          closestDist   = shootDistance * shootDistance;
            if (targetHumans || targetOtherCreatures)
            {
                foreach (var character in Character.CharacterList)
                {
                    if (character == null || character.Removed || character.IsDead)
                    {
                        continue;
                    }
                    if (character.Params.Group.Equals(ai.Config.Entity, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }
                    bool isHuman = character.IsHuman || character.Params.Group.Equals(CharacterPrefab.HumanSpeciesName, StringComparison.OrdinalIgnoreCase);
                    if (isHuman)
                    {
                        if (!targetHumans)
                        {
                            // Don't target humans if not defined to.
                            continue;
                        }
                    }
                    else if (!targetOtherCreatures)
                    {
                        // Don't target other creatures if not defined to.
                        continue;
                    }
                    float dist = Vector2.DistanceSquared(character.WorldPosition, item.WorldPosition);
                    if (dist > closestDist)
                    {
                        continue;
                    }
                    target      = character;
                    closestDist = dist;
                }
            }
            if (targetSubmarines)
            {
                if (target == null || target.Submarine != null)
                {
                    closestDist = maxDistance * maxDistance;
                    foreach (Submarine sub in Submarine.Loaded)
                    {
                        if (sub.Info.Type != SubmarineInfo.SubmarineType.Player)
                        {
                            continue;
                        }
                        float dist = Vector2.DistanceSquared(sub.WorldPosition, item.WorldPosition);
                        if (dist > closestDist)
                        {
                            continue;
                        }
                        closestSub  = sub;
                        closestDist = dist;
                    }
                    closestDist = shootDistance * shootDistance;
                    if (closestSub != null)
                    {
                        foreach (var hull in Hull.hullList)
                        {
                            if (!closestSub.IsEntityFoundOnThisSub(hull, true))
                            {
                                continue;
                            }
                            float dist = Vector2.DistanceSquared(hull.WorldPosition, item.WorldPosition);
                            if (dist > closestDist)
                            {
                                continue;
                            }
                            target      = hull;
                            closestDist = dist;
                        }
                    }
                }
            }
            if (!ignoreDelay)
            {
                if (target == null)
                {
                    // Random movement
                    waitTimer      = Rand.Value(Rand.RandSync.Unsynced) < 0.98f ? 0f : Rand.Range(5f, 20f);
                    targetRotation = Rand.Range(minRotation, maxRotation);
                    updatePending  = true;
                    return;
                }
                if (disorderTimer < 0)
                {
                    // Random disorder
                    disorderTimer  = Rand.Range(0f, 3f);
                    waitTimer      = Rand.Range(0.25f, 1f);
                    targetRotation = MathUtils.WrapAngleTwoPi(targetRotation += Rand.Range(-1f, 1f));
                    updatePending  = true;
                    return;
                }
                else
                {
                    disorderTimer -= deltaTime;
                }
            }
            if (target == null)
            {
                return;
            }

            float angle = -MathUtils.VectorToAngle(target.WorldPosition - item.WorldPosition);
            targetRotation = MathUtils.WrapAngleTwoPi(angle);

            if (Math.Abs(targetRotation - prevTargetRotation) > 0.1f)
            {
                updatePending = true;
            }

            if (target is Hull targetHull)
            {
                Vector2 barrelDir = new Vector2((float)Math.Cos(rotation), -(float)Math.Sin(rotation));
                if (!MathUtils.GetLineRectangleIntersection(item.WorldPosition, item.WorldPosition + barrelDir * AIRange, targetHull.WorldRect, out _))
                {
                    return;
                }
            }
            else
            {
                float midRotation = (minRotation + maxRotation) / 2.0f;
                while (midRotation - angle < -MathHelper.Pi)
                {
                    angle -= MathHelper.TwoPi;
                }
                while (midRotation - angle > MathHelper.Pi)
                {
                    angle += MathHelper.TwoPi;
                }
                if (angle < minRotation || angle > maxRotation)
                {
                    return;
                }
                float enemyAngle  = MathUtils.VectorToAngle(target.WorldPosition - item.WorldPosition);
                float turretAngle = -rotation;
                if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f)
                {
                    return;
                }
            }

            Vector2 start = ConvertUnits.ToSimUnits(item.WorldPosition);
            Vector2 end   = ConvertUnits.ToSimUnits(target.WorldPosition);
            if (target.Submarine != null)
            {
                start -= target.Submarine.SimPosition;
                end   -= target.Submarine.SimPosition;
            }
            var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel;
            var pickedBody          = Submarine.PickBody(start, end, null, collisionCategories, allowInsideFixture: true,
                                                         customPredicate: (Fixture f) => { return(!item.StaticFixtures.Contains(f)); });
            if (pickedBody == null)
            {
                return;
            }
            Character targetCharacter = null;
            if (pickedBody.UserData is Character c)
            {
                targetCharacter = c;
            }
            else if (pickedBody.UserData is Limb limb)
            {
                targetCharacter = limb.character;
            }
            if (targetCharacter != null)
            {
                if (targetCharacter.Params.Group.Equals(ai.Config.Entity, StringComparison.OrdinalIgnoreCase))
                {
                    // Don't shoot friendly characters
                    return;
                }
            }
            else
            {
                if (pickedBody.UserData is ISpatialEntity e)
                {
                    Submarine sub = e.Submarine;
                    if (sub == null)
                    {
                        return;
                    }
                    if (!targetSubmarines)
                    {
                        return;
                    }
                    if (sub == Item.Submarine)
                    {
                        return;
                    }
                    // Don't shoot non-player submarines, i.e. wrecks or outposts.
                    if (!sub.Info.IsPlayer)
                    {
                        return;
                    }
                }
                else
                {
                    // Hit something else, probably a level wall
                    return;
                }
            }
            TryLaunch(deltaTime, ignorePower: true);
        }