public override bool IsDuplicate(AIObjective otherObjective) { AIObjectiveGetItem getItem = otherObjective as AIObjectiveGetItem; if (getItem == null) { return(false); } if (getItem.equip != equip) { return(false); } if (getItem.itemIdentifiers != null && itemIdentifiers != null) { if (getItem.itemIdentifiers.Length != itemIdentifiers.Length) { return(false); } for (int i = 0; i < getItem.itemIdentifiers.Length; i++) { if (getItem.itemIdentifiers[i] != itemIdentifiers[i]) { return(false); } } return(true); } else if (getItem.itemIdentifiers == null && itemIdentifiers == null) { return(getItem.targetItem == targetItem); } return(false); }
public override void Reset() { base.Reset(); getItemObjective = null; goToObjective = null; containedItems.Clear(); }
public override void Reset() { base.Reset(); getDivingGear = null; getOxygen = null; targetItem = null; }
protected override void Act(float deltaTime) { //get the item that should be contained Item itemToContain = null; foreach (string identifier in itemIdentifiers) { itemToContain = character.Inventory.FindItemByIdentifier(identifier) ?? character.Inventory.FindItemByTag(identifier); if (itemToContain != null && itemToContain.Condition > 0.0f) { break; } } if (itemToContain == null) { if (getItemObjective != null) { if (getItemObjective.IsCompleted()) { if (getItemObjective.TargetItem != null) { containedItems.Add(getItemObjective.TargetItem); } else { // Reduce the target item count to prevent getting stuck here, if the target item for some reason is null, which shouldn't happen. targetItemCount--; } getItemObjective = null; } else if (!getItemObjective.CanBeCompleted) { getItemObjective = null; targetItemCount--; } } TryAddSubObjective(ref getItemObjective, () => new AIObjectiveGetItem(character, itemIdentifiers, objectiveManager, checkInventory: checkInventory) { GetItemPriority = GetItemPriority, ignoredContainerIdentifiers = ignoredContainerIdentifiers, ignoredItems = containedItems }); return; } if (container.Item.ParentInventory == character.Inventory) { character.Inventory.RemoveItem(itemToContain); container.Inventory.TryPutItem(itemToContain, null); } else { if (!character.CanInteractWith(container.Item, out _, checkLinked: false)) { TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(container.Item, character, objectiveManager)); return; } container.Combine(itemToContain); } }
public override void Reset() { base.Reset(); getWeldingTool = null; refuelObjective = null; gotoObjective = null; operateObjective = null; }
public override void Reset() { base.Reset(); getExtinguisherObjective = null; gotoObjective = null; useExtinquisherTimer = 0; sinTime = 0; }
public override void Reset() { base.Reset(); goToObjective = null; getItemObjective = null; replaceOxygenObjective = null; safeHull = null; ignoreOxygen = false; }
protected override void Act(float deltaTime) { if (isCompleted) { return; } //get the item that should be contained Item itemToContain = null; foreach (string identifier in itemIdentifiers) { itemToContain = character.Inventory.FindItemByIdentifier(identifier) ?? character.Inventory.FindItemByTag(identifier); if (itemToContain != null && itemToContain.Condition > 0.0f) { break; } } if (itemToContain == null) { getItemObjective = new AIObjectiveGetItem(character, itemIdentifiers) { GetItemPriority = GetItemPriority, ignoredContainerIdentifiers = ignoredContainerIdentifiers }; AddSubObjective(getItemObjective); return; } if (container.Item.ParentInventory == character.Inventory) { var containedItems = container.Inventory.Items; //if there's already something in the mask (empty oxygen tank?), drop it var existingItem = containedItems.FirstOrDefault(i => i != null); if (existingItem != null) { existingItem.Drop(character); } character.Inventory.RemoveItem(itemToContain); container.Inventory.TryPutItem(itemToContain, null); } else { if (container.Item.CurrentHull != character.CurrentHull || (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance && !container.Item.IsInsideTrigger(character.WorldPosition))) { goToObjective = new AIObjectiveGoTo(container.Item, character); AddSubObjective(goToObjective); return; } container.Combine(itemToContain); } isCompleted = true; }
public override bool IsDuplicate(AIObjective otherObjective) { AIObjectiveGetItem getItem = otherObjective as AIObjectiveGetItem; if (getItem == null) { return(false); } return(getItem.itemName == itemName); }
protected override void Act(float deltaTime) { if (isCompleted) { return; } //get the item that should be contained var itemToContain = character.Inventory.FindItem(itemNames); if (itemToContain == null) { getItemObjective = new AIObjectiveGetItem(character, itemNames); getItemObjective.GetItemPriority = GetItemPriority; getItemObjective.IgnoreContainedItems = IgnoreAlreadyContainedItems; AddSubObjective(getItemObjective); return; } if (container.Item.ParentInventory == character.Inventory) { var containedItems = container.Inventory.Items; //if there's already something in the mask (empty oxygen tank?), drop it var existingItem = containedItems.FirstOrDefault(i => i != null); if (existingItem != null) { existingItem.Drop(character); } character.Inventory.RemoveItem(itemToContain); container.Inventory.TryPutItem(itemToContain, null); } else { if (Vector2.Distance(character.Position, container.Item.Position) > container.Item.InteractDistance && !container.Item.IsInsideTrigger(character.WorldPosition)) { goToObjective = new AIObjectiveGoTo(container.Item, character); AddSubObjective(goToObjective); return; } container.Combine(itemToContain); } isCompleted = true; }
protected override void Act(float deltaTime) { // Only continue when the get item sub objectives have been completed. if (subObjectives.Any()) { return; } foreach (Repairable repairable in Item.Repairables) { if (!repairable.HasRequiredItems(character, false)) { //make sure we have all the items required to fix the target item foreach (var kvp in repairable.requiredItems) { foreach (RelatedItem requiredItem in kvp.Value) { var getItemObjective = new AIObjectiveGetItem(character, requiredItem.Identifiers, objectiveManager, true); if (objectiveManager.IsCurrentOrder <AIObjectiveRepairItems>()) { if (character.IsOnPlayerTeam) { getItemObjective.Abandoned += () => character.Speak(TextManager.Get("dialogcannotfindrequireditemtorepair"), null, 0.0f, "dialogcannotfindrequireditemtorepair", 10.0f); } } subObjectives.Add(getItemObjective); } } return; } } if (repairTool == null) { FindRepairTool(); } if (repairTool != null) { if (repairTool.Item.OwnInventory == null) { #if DEBUG DebugConsole.ThrowError($"{character.Name}: AIObjectiveRepairItem failed - the item \"" + repairTool + "\" has no proper inventory"); #endif Abandon = true; return; } HumanAIController.UnequipContainedItems(repairTool.Item, it => !it.HasTag("weldingfuel")); HumanAIController.UnequipEmptyItems(repairTool.Item); RelatedItem item = null; Item fuel = null; foreach (RelatedItem requiredItem in repairTool.requiredItems[RelatedItem.RelationType.Contained]) { item = requiredItem; fuel = repairTool.Item.OwnInventory.AllItems.FirstOrDefault(it => it.Condition > 0.0f && requiredItem.MatchesItem(it)); if (fuel != null) { break; } } if (fuel == null) { RemoveSubObjective(ref goToObjective); TryAddSubObjective(ref refuelObjective, () => new AIObjectiveContainItem(character, item.Identifiers, repairTool.Item.GetComponent <ItemContainer>(), objectiveManager, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC), onCompleted: () => RemoveSubObjective(ref refuelObjective), onAbandon: () => Abandon = true); return; } } if (!character.IsClimbing && character.CanInteractWith(Item, out _, checkLinked: false)) { HumanAIController.FaceTarget(Item); if (repairTool != null) { OperateRepairTool(deltaTime); } foreach (Repairable repairable in Item.Repairables) { if (repairable.CurrentFixer != null && repairable.CurrentFixer != character) { // Someone else is repairing the target. Abandon the objective if the other is better at this than us. Abandon = repairable.CurrentFixer.IsPlayer || repairable.DegreeOfSuccess(character) < repairable.DegreeOfSuccess(repairable.CurrentFixer); } if (!Abandon) { if (character.SelectedConstruction != Item) { if (!Item.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true) && !Item.TryInteract(character, ignoreRequiredItems: true, forceActionKey: true)) { Abandon = true; } } if (previousCondition == -1) { previousCondition = Item.Condition; } else if (Item.Condition < previousCondition) { // If the current condition is less than the previous condition, we can't complete the task, so let's abandon it. The item is probably deteriorating at a greater speed than we can repair it. Abandon = true; } } if (Abandon) { if (character.IsOnPlayerTeam && IsRepairing()) { character.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f); } repairable.StopRepairing(character); } else if (repairable.CurrentFixer != character) { repairable.StartRepairing(character, Repairable.FixActions.Repair); } break; } } else { RemoveSubObjective(ref refuelObjective); // If cannot reach the item, approach it. TryAddSubObjective(ref goToObjective, constructor: () => { previousCondition = -1; var objective = new AIObjectiveGoTo(Item, character, objectiveManager) { // Don't stop in ladders, because we can't interact with other items while holding the ladders. endNodeFilter = node => node.Waypoint.Ladders == null }; if (repairTool != null) { objective.CloseEnough = repairTool.Range * 0.75f; } return(objective); }, onAbandon: () => { Abandon = true; if (character.IsOnPlayerTeam && IsRepairing()) { character.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f); } }); } }
public AIObjective CreateObjective(Order order, string option, Character orderGiver, bool isAutonomous, float priorityModifier = 1) { if (order == null || order.Identifier == "dismissed") { return(null); } AIObjective newObjective; switch (order.Identifier.ToLowerInvariant()) { case "follow": if (orderGiver == null) { return(null); } newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier) { CloseEnough = Rand.Range(90, 100) + Rand.Range(50, 70) * Math.Min(HumanAIController.CountCrew(c => c.ObjectiveManager.CurrentOrder is AIObjectiveGoTo gotoOrder && gotoOrder.Target == orderGiver, onlyBots: true), 4), extraDistanceOutsideSub = 100, extraDistanceWhileSwimming = 100, AllowGoingOutside = true, IgnoreIfTargetDead = true, followControlledCharacter = true, mimic = true, DialogueIdentifier = "dialogcannotreachplace" }; break; case "wait": newObjective = new AIObjectiveGoTo(order.TargetSpatialEntity ?? character, character, this, repeat: true, priorityModifier: priorityModifier) { AllowGoingOutside = character.Submarine == null || (order.TargetSpatialEntity != null && character.Submarine != order.TargetSpatialEntity.Submarine) }; break; case "fixleaks": newObjective = new AIObjectiveFixLeaks(character, this, priorityModifier: priorityModifier, prioritizedHull: order.TargetEntity as Hull); break; case "chargebatteries": newObjective = new AIObjectiveChargeBatteries(character, this, option, priorityModifier); break; case "rescue": newObjective = new AIObjectiveRescueAll(character, this, priorityModifier); break; case "repairsystems": case "repairmechanical": case "repairelectrical": newObjective = new AIObjectiveRepairItems(character, this, priorityModifier: priorityModifier, prioritizedItem: order.TargetEntity as Item) { RelevantSkill = order.AppropriateSkill, RequireAdequateSkills = isAutonomous }; break; case "pumpwater": if (order.TargetItemComponent is Pump targetPump) { if (!order.TargetItemComponent.Item.IsInteractable(character)) { return(null); } newObjective = new AIObjectiveOperateItem(targetPump, character, this, option, false, priorityModifier: priorityModifier) { IsLoop = true, Override = orderGiver != null && orderGiver.IsPlayer }; // ItemComponent.AIOperate() returns false by default -> We'd have to set IsLoop = false and implement a custom override of AIOperate for the Pump.cs, // if we want that the bot just switches the pump on/off and continues doing something else. // If we want that the bot does the objective and then forgets about it, I think we could do the same plus dismiss when the bot is done. } else { newObjective = new AIObjectivePumpWater(character, this, option, priorityModifier: priorityModifier); } break; case "extinguishfires": newObjective = new AIObjectiveExtinguishFires(character, this, priorityModifier); break; case "fightintruders": newObjective = new AIObjectiveFightIntruders(character, this, priorityModifier); break; case "steer": var steering = (order?.TargetEntity as Item)?.GetComponent <Steering>(); if (steering != null) { steering.PosToMaintain = steering.Item.Submarine?.WorldPosition; } if (order.TargetItemComponent == null) { return(null); } if (!order.TargetItemComponent.Item.IsInteractable(character)) { return(null); } newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, controller: order.ConnectedController, priorityModifier: priorityModifier) { IsLoop = true, // Don't override unless it's an order by a player Override = orderGiver != null && orderGiver.IsPlayer }; break; case "setchargepct": newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, false, priorityModifier: priorityModifier) { IsLoop = false, Override = !character.IsDismissed, completionCondition = () => { if (float.TryParse(option, out float pct)) { var targetRatio = Math.Clamp(pct, 0f, 1f); var currentRatio = (order.TargetItemComponent as PowerContainer).RechargeRatio; return(Math.Abs(targetRatio - currentRatio) < 0.05f); } return(true); } }; break; case "getitem": newObjective = new AIObjectiveGetItem(character, order.TargetEntity as Item ?? order.TargetItemComponent?.Item, this, false, priorityModifier: priorityModifier) { MustBeSpecificItem = true }; break; case "cleanupitems": if (order.TargetEntity is Item targetItem) { if (targetItem.HasTag("allowcleanup") && targetItem.ParentInventory == null && targetItem.OwnInventory != null) { // Target all items inside the container newObjective = new AIObjectiveCleanupItems(character, this, targetItem.OwnInventory.AllItems, priorityModifier); } else { newObjective = new AIObjectiveCleanupItems(character, this, targetItem, priorityModifier); } } else { newObjective = new AIObjectiveCleanupItems(character, this, priorityModifier: priorityModifier); } break; default: if (order.TargetItemComponent == null) { return(null); } if (!order.TargetItemComponent.Item.IsInteractable(character)) { return(null); } newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, controller: order.ConnectedController, priorityModifier: priorityModifier) { IsLoop = true, // Don't override unless it's an order by a player Override = orderGiver != null && orderGiver.IsPlayer }; if (newObjective.Abandon) { return(null); } break; } return(newObjective); }
public override void Reset() { base.Reset(); goToObjective = null; getItemObjective = null; }
protected override void Act(float deltaTime) { var extinguisherItem = character.Inventory.FindItemByTag("fireextinguisher"); if (extinguisherItem == null || extinguisherItem.Condition <= 0.0f || !character.HasEquippedItem(extinguisherItem)) { TryAddSubObjective(ref getExtinguisherObjective, () => { if (character.IsOnPlayerTeam && !character.HasEquippedItem("fireextinguisher", allowBroken: false)) { character.Speak(TextManager.Get("DialogFindExtinguisher"), null, 2.0f, "findextinguisher", 30.0f); } var getItemObjective = new AIObjectiveGetItem(character, "fireextinguisher", objectiveManager, equip: true) { AllowStealing = true, // If the item is inside an unsafe hull, decrease the priority GetItemPriority = i => HumanAIController.UnsafeHulls.Contains(i.CurrentHull) ? 0.1f : 1 }; if (objectiveManager.HasOrder <AIObjectiveExtinguishFires>()) { getItemObjective.Abandoned += () => character.Speak(TextManager.Get("dialogcannotfindfireextinguisher"), null, 0.0f, "dialogcannotfindfireextinguisher", 10.0f); } ; return(getItemObjective); }); } else { var extinguisher = extinguisherItem.GetComponent <RepairTool>(); if (extinguisher == null) { #if DEBUG DebugConsole.ThrowError($"{character.Name}: AIObjectiveExtinguishFire failed - the item \"" + extinguisherItem + "\" has no RepairTool component but is tagged as an extinguisher"); #endif Abandon = true; return; } foreach (FireSource fs in targetHull.FireSources) { float xDist = Math.Abs(character.WorldPosition.X - fs.WorldPosition.X) - fs.DamageRange; float yDist = Math.Abs(character.WorldPosition.Y - fs.WorldPosition.Y); bool inRange = xDist + yDist < extinguisher.Range; // Use the hull position, because the fire x pos is sometimes inside a wall -> the bot can't ever see it and continues running towards the wall. ISpatialEntity lookTarget = character.CurrentHull == targetHull || character.CurrentHull.linkedTo.Contains(targetHull) ? targetHull : fs as ISpatialEntity; bool move = !inRange || !character.CanSeeTarget(lookTarget); if ((inRange && character.CanSeeTarget(lookTarget)) || useExtinquisherTimer > 0) { useExtinquisherTimer += deltaTime; if (useExtinquisherTimer > 2.0f) { useExtinquisherTimer = 0.0f; } // Aim character.CursorPosition = fs.Position; Vector2 fromCharacterToFireSource = fs.WorldPosition - character.WorldPosition; float dist = fromCharacterToFireSource.Length(); character.CursorPosition += VectorExtensions.Forward(extinguisherItem.body.TransformedRotation + (float)Math.Sin(sinTime) / 2, dist / 2); if (extinguisherItem.RequireAimToUse) { character.SetInput(InputType.Aim, false, true); sinTime += deltaTime * 10; } character.SetInput(extinguisherItem.IsShootable ? InputType.Shoot : InputType.Use, false, true); extinguisher.Use(deltaTime, character); if (!targetHull.FireSources.Contains(fs)) { character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.DisplayName, true), null, 0, "putoutfire", 10.0f); } } if (move) { //go to the first firesource if (TryAddSubObjective(ref gotoObjective, () => new AIObjectiveGoTo(fs, character, objectiveManager, closeEnough: Math.Max(fs.DamageRange, extinguisher.Range * 0.7f)) { DialogueIdentifier = "dialogcannotreachfire", TargetName = fs.Hull.DisplayName }, onAbandon: () => Abandon = true, onCompleted: () => RemoveSubObjective(ref gotoObjective))) { gotoObjective.requiredCondition = () => targetHull == null || character.CanSeeTarget(targetHull); } } else { character.AIController.SteeringManager.Reset(); } break; } } }
public override void Reset() { base.Reset(); getItemObjective = null; containObjective = null; }
protected override void Act(float deltaTime) { var extinguisherItem = character.Inventory.FindItemByIdentifier("extinguisher") ?? character.Inventory.FindItemByTag("extinguisher"); if (extinguisherItem == null || extinguisherItem.Condition <= 0.0f || !character.HasEquippedItem(extinguisherItem)) { if (getExtinguisherObjective == null) { character.Speak(TextManager.Get("DialogFindExtinguisher"), null, 2.0f, "findextinguisher", 30.0f); getExtinguisherObjective = new AIObjectiveGetItem(character, "extinguisher", true); } else { getExtinguisherObjective.TryComplete(deltaTime); } return; } var extinguisher = extinguisherItem.GetComponent <RepairTool>(); if (extinguisher == null) { DebugConsole.ThrowError("AIObjectiveExtinguishFire failed - the item \"" + extinguisherItem + "\" has no RepairTool component but is tagged as an extinguisher"); return; } foreach (FireSource fs in targetHull.FireSources) { bool inRange = fs.IsInDamageRange(character, MathHelper.Clamp(fs.DamageRange * 1.5f, extinguisher.Range * 0.5f, extinguisher.Range)); if (targetHull == character.CurrentHull && (inRange || useExtinquisherTimer > 0.0f)) { useExtinquisherTimer += deltaTime; if (useExtinquisherTimer > 2.0f) { useExtinquisherTimer = 0.0f; } character.CursorPosition = fs.Position; character.SetInput(InputType.Aim, false, true); if (!character.IsClimbing) { character.AIController.SteeringManager.Reset(); } extinguisher.Use(deltaTime, character); if (!targetHull.FireSources.Contains(fs)) { character.Speak(TextManager.Get("DialogPutOutFire").Replace("[roomname]", targetHull.Name), null, 0, "putoutfire", 10.0f); } return; } else { //go to the first firesource if (gotoObjective == null || !gotoObjective.CanBeCompleted || gotoObjective.IsCompleted()) { gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(fs.Position), character); } else { gotoObjective.TryComplete(deltaTime); } break; } } }