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); }