//a recursive function that goes through all the junctions and adds up //all the generated/consumed power of the constructions connected to the grid private void CheckJunctions(float deltaTime) { updateTimer = 1; connectedList.Add(this); ApplyStatusEffects(ActionType.OnActive, deltaTime, null); foreach (Connection c in powerConnections) { var recipients = c.Recipients; foreach (Connection recipient in recipients) { if (recipient == null) { continue; } Item it = recipient.Item; if (it == null) { continue; } if (it.Condition <= 0.0f) { continue; } foreach (Powered powered in it.GetComponents <Powered>()) { if (powered == null || !powered.IsActive) { continue; } if (connectedList.Contains(powered)) { continue; } PowerTransfer powerTransfer = powered as PowerTransfer; if (powerTransfer != null) { powerTransfer.CheckJunctions(deltaTime); continue; } PowerContainer powerContainer = powered as PowerContainer; if (powerContainer != null) { if (recipient.Name == "power_in") { fullLoad += powerContainer.CurrPowerConsumption; } else { fullPower += powerContainer.CurrPowerOutput; } } else { connectedList.Add(powered); //positive power consumption = the construction requires power -> increase load if (powered.CurrPowerConsumption > 0.0f) { fullLoad += powered.CurrPowerConsumption; } else if (powered.CurrPowerConsumption < 0.0f) //negative power consumption = the construction is a //generator/battery or another junction box { fullPower -= powered.CurrPowerConsumption; } } } } } }
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective) { if (character.AIController.SelectedAiTarget?.Entity is Character previousTarget && previousTarget.IsDead) { character?.Speak(TextManager.Get("DialogTurretTargetDead"), null, 0.0f, "killedtarget" + previousTarget.ID, 30.0f); character.AIController.SelectTarget(null); } if (GetAvailableBatteryPower() < powerConsumption) { var batteries = item.GetConnectedComponents <PowerContainer>(); float lowestCharge = 0.0f; PowerContainer batteryToLoad = null; foreach (PowerContainer battery in batteries) { if (batteryToLoad == null || battery.Charge < lowestCharge) { batteryToLoad = battery; lowestCharge = battery.Charge; } } if (batteryToLoad == null) { return(true); } if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f) { objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, objective.objectiveManager, option: "", requireEquip: false)); return(false); } } int usableProjectileCount = 0; int maxProjectileCount = 0; foreach (MapEntity e in item.linkedTo) { if (!(e is Item projectileContainer)) { continue; } var containedItems = projectileContainer.ContainedItems; if (containedItems != null) { var container = projectileContainer.GetComponent <ItemContainer>(); maxProjectileCount += container.Capacity; int projectiles = containedItems.Count(it => it.Condition > 0.0f); usableProjectileCount += projectiles; } } if (usableProjectileCount == 0 || (usableProjectileCount < maxProjectileCount && objective.Option.Equals("fireatwill", StringComparison.OrdinalIgnoreCase))) { ItemContainer container = null; Item containerItem = null; foreach (MapEntity e in item.linkedTo) { containerItem = e as Item; if (containerItem == null) { continue; } container = containerItem.GetComponent <ItemContainer>(); if (container != null) { break; } } if (container == null || container.ContainableItems.Count == 0) { return(true); } if (objective.SubObjectives.None()) { if (!AIDecontainEmptyItems(character, objective, equip: true, sourceContainer: container)) { return(false); } } if (objective.SubObjectives.None()) { var loadItemsObjective = AIContainItems <Turret>(container, character, objective, usableProjectileCount + 1, equip: true, removeEmpty: true); loadItemsObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier }; character.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "loadturret", 30.0f); } return(false); } //enough shells and power Character closestEnemy = null; float closestDist = AIRange * AIRange; foreach (Character enemy in Character.CharacterList) { // Ignore dead, friendly, and those that are inside the same sub if (enemy.IsDead || !enemy.Enabled || enemy.Submarine == character.Submarine) { continue; } if (HumanAIController.IsFriendly(character, enemy)) { continue; } float dist = Vector2.DistanceSquared(enemy.WorldPosition, item.WorldPosition); if (dist > closestDist) { continue; } float angle = -MathUtils.VectorToAngle(enemy.WorldPosition - item.WorldPosition); 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) { continue; } closestEnemy = enemy; closestDist = dist; } if (closestEnemy == null) { return(false); } character.AIController.SelectTarget(closestEnemy.AiTarget); character.CursorPosition = closestEnemy.WorldPosition; if (item.Submarine != null) { character.CursorPosition -= item.Submarine.Position; } float enemyAngle = MathUtils.VectorToAngle(closestEnemy.WorldPosition - item.WorldPosition); float turretAngle = -rotation; if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f) { return(false); } Vector2 start = ConvertUnits.ToSimUnits(item.WorldPosition); Vector2 end = ConvertUnits.ToSimUnits(closestEnemy.WorldPosition); if (closestEnemy.Submarine != null) { start -= closestEnemy.Submarine.SimPosition; end -= closestEnemy.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(false); } 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 (HumanAIController.IsFriendly(character, targetCharacter)) { // Don't shoot friendly characters return(false); } } else { if (pickedBody.UserData is ISpatialEntity e) { Submarine sub = e.Submarine; if (sub == null) { return(false); } if (sub == Item.Submarine) { return(false); } // Don't shoot non-player submarines, i.e. wrecks or outposts. if (!sub.Info.IsPlayer) { return(false); } // Don't shoot friendly submarines. if (sub.TeamID == Item.Submarine.TeamID) { return(false); } } else { // Hit something else, probably a level wall return(false); } } if (objective.Option.Equals("fireatwill", StringComparison.OrdinalIgnoreCase)) { character?.Speak(TextManager.GetWithVariable("DialogFireTurret", "[itemname]", item.Name, true), null, 0.0f, "fireturret", 5.0f); character.SetInput(InputType.Shoot, true, true); } return(false); }
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective) { if (character.AIController.SelectedAiTarget?.Entity is Character previousTarget && previousTarget.IsDead) { character?.Speak(TextManager.Get("DialogTurretTargetDead"), null, 0.0f, "killedtarget" + previousTarget.ID, 30.0f); character.AIController.SelectTarget(null); } if (GetAvailablePower() < powerConsumption) { var batteries = item.GetConnectedComponents <PowerContainer>(); float lowestCharge = 0.0f; PowerContainer batteryToLoad = null; foreach (PowerContainer battery in batteries) { if (batteryToLoad == null || battery.Charge < lowestCharge) { batteryToLoad = battery; lowestCharge = battery.Charge; } } if (batteryToLoad == null) { return(true); } if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f) { objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, objective.objectiveManager, option: "", requireEquip: false)); return(false); } } int usableProjectileCount = 0; int maxProjectileCount = 0; foreach (MapEntity e in item.linkedTo) { if (!(e is Item projectileContainer)) { continue; } var containedItems = projectileContainer.ContainedItems; if (containedItems != null) { var container = projectileContainer.GetComponent <ItemContainer>(); maxProjectileCount += container.Capacity; int projectiles = containedItems.Count(it => it.Condition > 0.0f); usableProjectileCount += projectiles; } } if (usableProjectileCount == 0 || (usableProjectileCount < maxProjectileCount && objective.Option.ToLowerInvariant() != "fireatwill")) { ItemContainer container = null; Item containerItem = null; foreach (MapEntity e in item.linkedTo) { containerItem = e as Item; if (containerItem == null) { continue; } container = containerItem.GetComponent <ItemContainer>(); if (container != null) { break; } } if (container == null || container.ContainableItems.Count == 0) { return(true); } if (container.Inventory.Items[0] != null && container.Inventory.Items[0].Condition <= 0.0f) { var removeShellObjective = new AIObjectiveDecontainItem(character, container.Inventory.Items[0], container, objective.objectiveManager); objective.AddSubObjective(removeShellObjective); } var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Identifiers[0], container, objective.objectiveManager); character?.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "loadturret", 30.0f); containShellObjective.targetItemCount = usableProjectileCount + 1; containShellObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier }; objective.AddSubObjective(containShellObjective); return(false); } //enough shells and power Character closestEnemy = null; float closestDist = 3000 * 3000; foreach (Character enemy in Character.CharacterList) { // Ignore friendly and those that are inside the sub if (enemy.IsDead || enemy.AnimController.CurrentHull != null || !enemy.Enabled) { continue; } if (HumanAIController.IsFriendly(character, enemy)) { continue; } float dist = Vector2.DistanceSquared(enemy.WorldPosition, item.WorldPosition); if (dist > closestDist) { continue; } float angle = -MathUtils.VectorToAngle(enemy.WorldPosition - item.WorldPosition); 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) { continue; } closestEnemy = enemy; closestDist = dist; } if (closestEnemy == null) { return(false); } character.AIController.SelectTarget(closestEnemy.AiTarget); character.CursorPosition = closestEnemy.WorldPosition; if (item.Submarine != null) { character.CursorPosition -= item.Submarine.Position; } float enemyAngle = MathUtils.VectorToAngle(closestEnemy.WorldPosition - item.WorldPosition); float turretAngle = -rotation; if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f) { return(false); } var pickedBody = Submarine.PickBody(ConvertUnits.ToSimUnits(item.WorldPosition), closestEnemy.SimPosition); if (pickedBody == null) { return(false); } Character target = null; if (pickedBody.UserData is Character c) { target = c; } else if (pickedBody.UserData is Limb limb) { target = limb.character; } if (target == null || HumanAIController.IsFriendly(character, target)) { return(false); } if (objective.Option.ToLowerInvariant() == "fireatwill") { character?.Speak(TextManager.GetWithVariable("DialogFireTurret", "[itemname]", item.Name, true), null, 0.0f, "fireturret", 5.0f); character.SetInput(InputType.Shoot, true, true); } return(false); }
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective) { var projectiles = GetLoadedProjectiles(); if (projectiles.Count == 0 || (projectiles.Count == 1 && objective.Option.ToLowerInvariant() != "fire at will")) { ItemContainer container = null; foreach (MapEntity e in item.linkedTo) { var containerItem = e as Item; if (containerItem == null) { continue; } container = containerItem.GetComponent <ItemContainer>(); if (container != null) { break; } } if (container == null || container.ContainableItems.Count == 0) { return(true); } var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Names[0], container); containShellObjective.IgnoreAlreadyContainedItems = true; objective.AddSubObjective(containShellObjective); return(false); } else if (GetAvailablePower() < powerConsumption) { var batteries = item.GetConnectedComponents <PowerContainer>(); float lowestCharge = 0.0f; PowerContainer batteryToLoad = null; foreach (PowerContainer battery in batteries) { if (batteryToLoad == null || battery.Charge < lowestCharge) { batteryToLoad = battery; lowestCharge = battery.Charge; } } if (batteryToLoad == null) { return(true); } if (batteryToLoad.RechargeSpeed < batteryToLoad.MaxRechargeSpeed * 0.4f) { objective.AddSubObjective(new AIObjectiveOperateItem(batteryToLoad, character, "", false)); return(false); } } //enough shells and power Character closestEnemy = null; float closestDist = 3000.0f; foreach (Character enemy in Character.CharacterList) { //ignore humans and characters that are inside the sub if (enemy.IsDead || enemy.SpeciesName == "human" || enemy.AnimController.CurrentHull != null) { continue; } float dist = Vector2.Distance(enemy.WorldPosition, item.WorldPosition); if (dist < closestDist) { closestEnemy = enemy; closestDist = dist; } } if (closestEnemy == null) { return(false); } character.CursorPosition = closestEnemy.WorldPosition; if (item.Submarine != null) { character.CursorPosition -= item.Submarine.Position; } character.SetInput(InputType.Aim, false, true); float enemyAngle = MathUtils.VectorToAngle(closestEnemy.WorldPosition - item.WorldPosition); float turretAngle = -rotation; if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.01f) { return(false); } var pickedBody = Submarine.PickBody(ConvertUnits.ToSimUnits(item.WorldPosition), closestEnemy.SimPosition, null); if (pickedBody != null && !(pickedBody.UserData is Limb)) { return(false); } if (objective.Option.ToLowerInvariant() == "fire at will") { Use(deltaTime, character); } return(false); }
//a recursive function that goes through all the junctions and adds up //all the generated/consumed power of the constructions connected to the grid private void CheckPower(float deltaTime) { updateTimer = 1; connectedPoweredList.Clear(); foreach (Connection c in powerConnections) { HashSet <Connection> recipients = connectedRecipients[c]; foreach (Connection recipient in recipients) { if (recipient == null) { continue; } Item it = recipient.Item; if (it == null || it.Condition <= 0.0f) { continue; } foreach (Powered powered in it.GetComponents <Powered>()) { if (powered == null || !powered.IsActive) { continue; } PowerTransfer powerTransfer = powered as PowerTransfer; if (powerTransfer != null) { connectedPoweredList.Add(powerTransfer); powerTransfer.updateTimer = 1; continue; } PowerContainer powerContainer = powered as PowerContainer; if (powerContainer != null) { if (recipient.Name == "power_in") { fullLoad += powerContainer.CurrPowerConsumption; } else { fullPower += powerContainer.CurrPowerOutput; } } else { //positive power consumption = the construction requires power -> increase load if (powered.CurrPowerConsumption > 0.0f) { fullLoad += powered.CurrPowerConsumption; } else if (powered.CurrPowerConsumption < 0.0f) //negative power consumption = the construction is a /generator/battery { fullPower -= powered.CurrPowerConsumption; } } } } } }