protected AIObjectiveContainItem AIContainItems <T>(ItemContainer container, Character character, AIObjective objective, int itemCount, bool equip, bool removeEmpty) where T : ItemComponent { var containObjective = new AIObjectiveContainItem(character, container.GetContainableItemIdentifiers.ToArray(), container, objective.objectiveManager) { targetItemCount = itemCount, Equip = equip, RemoveEmpty = removeEmpty, GetItemPriority = i => { if (i.ParentInventory?.Owner is Item) { //don't take items from other items of the same type if (((Item)i.ParentInventory.Owner).GetComponent <T>() != null) { return(0.0f); } } return(1.0f); } }; // TODO: are we sure that we want to abandon the objective here? containObjective.Abandoned += () => objective.Abandon = true; objective.AddSubObjective(containObjective); return(containObjective); }
protected AIObjectiveContainItem AIContainItems <T>(ItemContainer container, Character character, AIObjective objective, int itemCount, bool equip, bool removeEmpty, bool spawnItemIfNotFound = false) where T : ItemComponent { AIObjectiveContainItem containObjective = null; if (character.AIController is HumanAIController aiController) { containObjective = new AIObjectiveContainItem(character, container.GetContainableItemIdentifiers.ToArray(), container, objective.objectiveManager, spawnItemIfNotFound: spawnItemIfNotFound) { targetItemCount = itemCount, Equip = equip, RemoveEmpty = removeEmpty, GetItemPriority = i => { if (i.ParentInventory?.Owner is Item) { //don't take items from other items of the same type if (((Item)i.ParentInventory.Owner).GetComponent <T>() != null) { return(0.0f); } } return(1.0f); } }; containObjective.Abandoned += () => { aiController.IgnoredItems.Add(container.Item); }; objective.AddSubObjective(containObjective); } return(containObjective); }
protected AIObjectiveContainItem AIContainItems <T>(ItemContainer container, Character character, AIObjective currentObjective, int itemCount, bool equip, bool removeEmpty, bool spawnItemIfNotFound = false, bool dropItemOnDeselected = false) where T : ItemComponent { AIObjectiveContainItem containObjective = null; if (character.AIController is HumanAIController aiController) { containObjective = new AIObjectiveContainItem(character, container.GetContainableItemIdentifiers.ToArray(), container, currentObjective.objectiveManager, spawnItemIfNotFound: spawnItemIfNotFound) { targetItemCount = itemCount, Equip = equip, RemoveEmpty = removeEmpty, GetItemPriority = i => { if (i.ParentInventory?.Owner is Item) { //don't take items from other items of the same type if (((Item)i.ParentInventory.Owner).GetComponent <T>() != null) { return(0.0f); } } return(1.0f); } }; containObjective.Abandoned += () => aiController.IgnoredItems.Add(container.Item); if (dropItemOnDeselected) { currentObjective.Deselected += () => { if (containObjective == null) { return; } if (containObjective.IsCompleted) { return; } Item item = containObjective.ItemToContain; if (item != null && character.CanInteractWith(item, checkLinked: false)) { item.Drop(character); } }; } currentObjective.AddSubObjective(containObjective); } return(containObjective); }
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); }
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) { //remove used-up fuel from the reactor var containedItems = item.ContainedItems; foreach (Item item in containedItems) { if (item != null && item.Condition <= 0.0f) { item.Drop(character); } } 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)) { var containFuelObjective = new AIObjectiveContainItem(character, new string[] { "fuelrod", "reactorfuel" }, item.GetComponent <ItemContainer>(), objective.objectiveManager) { targetItemCount = item.ContainedItems.Count(i => i != null && i.Prefab.Identifier == "fuelrod" || i.HasTag("reactorfuel")) + 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); } }; objective.AddSubObjective(containFuelObjective); character?.Speak(TextManager.Get("DialogReactorFuel"), null, 0.0f, "reactorfuel", 30.0f); aiUpdateTimer = AIUpdateInterval; return(false); } else if (TooMuchFuel()) { foreach (Item item in item.ContainedItems) { if (item != null && item.HasTag("reactorfuel")) { 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 = character; switch (objective.Option.ToLowerInvariant()) { case "powerup": shutDown = false; //characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually if (degreeOfSuccess < 0.5f) { if (!autoTemp) { unsentChanges = true; } AutoTemp = true; } else { AutoTemp = false; unsentChanges = true; 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 if (AutoTemp || !shutDown || targetFissionRate > 0.0f || targetTurbineOutput > 0.0f) { unsentChanges = true; } AutoTemp = false; shutDown = true; targetFissionRate = 0.0f; targetTurbineOutput = 0.0f; break; } aiUpdateTimer = AIUpdateInterval; return(false); }
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective) { float degreeOfSuccess = DegreeOfSuccess(character); //characters with insufficient skill levels don't refuel the reactor if (degreeOfSuccess > 0.2f) { //remove used-up fuel from the reactor var containedItems = item.ContainedItems; foreach (Item item in containedItems) { if (item != null && item.Condition <= 0.0f) { item.Drop(); } } //the temperature is too low and not increasing even though the fission rate is high and cooling low // -> we need more fuel if (temperature < load * 0.5f && temperatureChange <= 0.0f && fissionRate > 0.9f && coolingRate < 0.1f) { var containFuelObjective = new AIObjectiveContainItem(character, new string[] { "Fuel Rod", "reactorfuel" }, item.GetComponent <ItemContainer>()); containFuelObjective.MinContainedAmount = containedItems.Count(i => i != null && i.Prefab.NameMatches("Fuel Rod") || i.HasTag("reactorfuel")) + 1; containFuelObjective.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); }; objective.AddSubObjective(containFuelObjective); return(false); } } switch (objective.Option.ToLowerInvariant()) { case "power up": float tempDiff = load - temperature; shutDownTemp = Math.Min(load + 1000.0f, 7500.0f); //characters with insufficient skill levels simply set the autotemp on instead of trying to adjust the temperature manually if (Math.Abs(tempDiff) < 500.0f || degreeOfSuccess < 0.5f) { AutoTemp = true; } else { AutoTemp = false; //higher skill levels make the character adjust the temperature faster FissionRate += deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess; CoolingRate -= deltaTime * 100.0f * Math.Sign(tempDiff) * degreeOfSuccess; } break; case "shutdown": shutDownTemp = 0.0f; break; } 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); }