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) { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return(false); } IsActive = true; float degreeOfSuccess = DegreeOfSuccess(character); //characters with insufficient skill levels don't refuel the reactor if (degreeOfSuccess > 0.2f) { if (objective.SubObjectives.None()) { var containedItems = item.ContainedItems; foreach (Item fuelRod in containedItems) { if (fuelRod != null && fuelRod.Condition <= 0.0f) { if (!FindSuitableContainer(character, i => { var container = i.GetComponent <ItemContainer>(); if (container == null) { return(0); } if (container.Inventory.IsFull()) { return(0); } if (container.ShouldBeContained(fuelRod, out bool isRestrictionsDefined)) { if (isRestrictionsDefined) { return(3); } else { if (fuelRod.Prefab.IsContainerPreferred(container, out bool isPreferencesDefined)) { return(isPreferencesDefined ? 2 : 1); } else { return(isPreferencesDefined ? 0 : 1); } } } else { return(0); } }, out Item targetContainer)) { return(false); } var decontainObjective = new AIObjectiveDecontainItem(character, fuelRod, item.GetComponent <ItemContainer>(), objective.objectiveManager, targetContainer?.GetComponent <ItemContainer>()); decontainObjective.Abandoned += () => { itemIndex = 0; if (targetContainer != null) { ignoredContainers.Add(targetContainer); } }; objective.AddSubObjectiveInQueue(decontainObjective); } } } if (aiUpdateTimer > 0.0f) { aiUpdateTimer -= deltaTime; return(false); } //load more fuel if the current maximum output is only 50% of the current load if (NeedMoreFuel(minimumOutputRatio: 0.5f)) { aiUpdateTimer = AIUpdateInterval; if (objective.SubObjectives.None()) { var containFuelObjective = new AIObjectiveContainItem(character, fuelTags, item.GetComponent <ItemContainer>(), objective.objectiveManager) { targetItemCount = item.ContainedItems.Count(i => i != null && fuelTags.Any(t => i.Prefab.Identifier == t || i.HasTag(t))) + 1, GetItemPriority = (Item fuelItem) => { if (fuelItem.ParentInventory?.Owner is Item) { //don't take fuel from other reactors if (((Item)fuelItem.ParentInventory.Owner).GetComponent <Reactor>() != null) { return(0.0f); } } return(1.0f); } }; containFuelObjective.Abandoned += () => objective.Abandon = true; objective.AddSubObjective(containFuelObjective); character?.Speak(TextManager.Get("DialogReactorFuel"), null, 0.0f, "reactorfuel", 30.0f); } return(false); } else if (TooMuchFuel()) { foreach (Item item in item.ContainedItems) { if (item != null && fuelTags.Any(t => item.Prefab.Identifier == t || item.HasTag(t))) { if (!character.Inventory.TryPutItem(item, character, allowedSlots: item.AllowedSlots)) { item.Drop(character); } break; } } } } if (lastUser != character && lastUser != null && lastUser.SelectedConstruction == item) { character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f); } LastUser = lastAIUser = character; bool prevAutoTemp = autoTemp; bool prevShutDown = shutDown; float prevFissionRate = targetFissionRate; float prevTurbineOutput = targetTurbineOutput; switch (objective.Option.ToLowerInvariant()) { case "powerup": shutDown = false; if (objective.Override || !autoTemp) { //characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually if (degreeOfSuccess < 0.5f) { AutoTemp = true; } else { AutoTemp = false; UpdateAutoTemp(MathHelper.Lerp(0.5f, 2.0f, degreeOfSuccess), 1.0f); } } #if CLIENT onOffSwitch.BarScroll = 0.0f; fissionRateScrollBar.BarScroll = FissionRate / 100.0f; turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f; #endif break; case "shutdown": #if CLIENT onOffSwitch.BarScroll = 1.0f; #endif AutoTemp = false; shutDown = true; targetFissionRate = 0.0f; targetTurbineOutput = 0.0f; break; } if (autoTemp != prevAutoTemp || prevShutDown != shutDown || Math.Abs(prevFissionRate - targetFissionRate) > 1.0f || Math.Abs(prevTurbineOutput - targetTurbineOutput) > 1.0f) { unsentChanges = true; } aiUpdateTimer = AIUpdateInterval; return(false); }