private void Move(float deltaTime) { switch (Mode) { case CombatMode.Offensive: case CombatMode.Arrest: Engage(deltaTime); break; case CombatMode.Defensive: if (character.IsOnPlayerTeam && !Enemy.IsPlayer && objectiveManager.IsCurrentOrder <AIObjectiveGoTo>()) { if ((character.CurrentHull == null || character.CurrentHull == Enemy.CurrentHull) && sqrDistance < 200 * 200) { Engage(deltaTime); } else { // Keep following the goto target var gotoObjective = objectiveManager.GetOrder <AIObjectiveGoTo>(); if (gotoObjective != null) { gotoObjective.ForceAct(deltaTime); if (!character.AnimController.InWater) { HumanAIController.FaceTarget(Enemy); ForceWalk = true; HumanAIController.AutoFaceMovement = false; } } else { SteeringManager.Reset(); } } } else { Retreat(deltaTime); } break; case CombatMode.Retreat: Retreat(deltaTime); break; default: throw new NotImplementedException(); } }
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) { subObjectives.Add(new AIObjectiveGetItem(character, requiredItem.Identifiers, objectiveManager, true)); } } return; } } if (repairTool == null) { FindRepairTool(); } if (repairTool != null) { var containedItems = repairTool.Item.ContainedItems; if (containedItems == null) { #if DEBUG DebugConsole.ThrowError($"{character.Name}: AIObjectiveRepairItem failed - the item \"" + repairTool + "\" has no proper inventory"); #endif Abandon = true; return; } // Drop empty tanks foreach (Item containedItem in containedItems) { if (containedItem == null) { continue; } if (containedItem.Condition <= 0.0f) { containedItem.Drop(character); } } RelatedItem item = null; Item fuel = null; foreach (RelatedItem requiredItem in repairTool.requiredItems[RelatedItem.RelationType.Contained]) { item = requiredItem; fuel = containedItems.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), onCompleted: () => RemoveSubObjective(ref refuelObjective), onAbandon: () => Abandon = true); return; } } if (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.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 (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 (IsRepairing) { character.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f); } }); } }
protected override void Act(float deltaTime) { if (character.LockHands) { Abandon = true; return; } ItemComponent target = GetTarget(); if (useController && controller == null) { character.Speak(TextManager.GetWithVariable("DialogCantFindController", "[item]", component.Item.Name, true), null, 2.0f, "cantfindcontroller", 30.0f); Abandon = true; return; } if (operateTarget != null) { if (HumanAIController.IsTrueForAnyCrewMember(other => other != HumanAIController && other.ObjectiveManager.GetActiveObjective() is AIObjectiveOperateItem operateObjective && operateObjective.operateTarget == operateTarget)) { // Another crew member is already targeting this entity. Abandon = true; return; } } if (target.CanBeSelected) { if (!character.IsClimbing && character.CanInteractWith(target.Item, out _, checkLinked: false)) { HumanAIController.FaceTarget(target.Item); if (character.SelectedConstruction != target.Item) { target.Item.TryInteract(character, false, true); } if (component.AIOperate(deltaTime, character, this)) { isDoneOperating = completionCondition == null || completionCondition(); } } else { TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(target.Item, character, objectiveManager, closeEnough: 50) { DialogueIdentifier = "dialogcannotreachtarget", TargetName = target.Item.Name, endNodeFilter = node => node.Waypoint.Ladders == null }, onAbandon: () => Abandon = true, onCompleted: () => RemoveSubObjective(ref goToObjective)); } } else { if (component.Item.GetComponent <Pickable>() == null) { //controller/target can't be selected and the item cannot be picked -> objective can't be completed Abandon = true; return; } else if (!character.Inventory.Contains(component.Item)) { TryAddSubObjective(ref getItemObjective, () => new AIObjectiveGetItem(character, component.Item, objectiveManager, equip: true), onAbandon: () => Abandon = true, onCompleted: () => RemoveSubObjective(ref getItemObjective)); } else { if (requireEquip && !character.HasEquippedItem(component.Item)) { //the item has to be equipped before using it if it's holdable var holdable = component.Item.GetComponent <Holdable>(); if (holdable == null) { #if DEBUG DebugConsole.ThrowError($"{character.Name}: AIObjectiveOperateItem failed - equipping item " + component.Item + " is required but the item has no Holdable component"); #endif return; } for (int i = 0; i < character.Inventory.Capacity; i++) { if (character.Inventory.SlotTypes[i] == InvSlotType.Any || !holdable.AllowedSlots.Any(s => s.HasFlag(character.Inventory.SlotTypes[i]))) { continue; } //equip slot already taken var existingItem = character.Inventory.GetItemAt(i); if (existingItem != null) { //try to put the item in an Any slot, and drop it if that fails if (!existingItem.AllowedSlots.Contains(InvSlotType.Any) || !character.Inventory.TryPutItem(existingItem, character, new List <InvSlotType>() { InvSlotType.Any })) { existingItem.Drop(character); } } if (character.Inventory.TryPutItem(component.Item, i, true, false, character)) { component.Item.Equip(character); break; } } return; } if (component.AIOperate(deltaTime, character, this)) { isDoneOperating = completionCondition == null || completionCondition(); } } } }
protected override void Act(float deltaTime) { if (character.LockHands) { Abandon = true; return; } ItemComponent target = GetTarget(); if (useController && controller == null) { character.Speak(TextManager.GetWithVariable("DialogCantFindController", "[item]", component.Item.Name, true), null, 2.0f, "cantfindcontroller", 30.0f); Abandon = true; return; } // Don't allow to operate an item that someone with a better skills already operates, unless this is an order if (objectiveManager.CurrentOrder != this && IsOperatedByAnother(target)) { // Don't abandon return; } if (target.CanBeSelected) { if (character.CanInteractWith(target.Item, out _, checkLinked: false)) { HumanAIController.FaceTarget(target.Item); if (character.SelectedConstruction != target.Item) { target.Item.TryInteract(character, false, true); } if (component.AIOperate(deltaTime, character, this)) { IsCompleted = completionCondition == null || completionCondition(); } } else { TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(target.Item, character, objectiveManager, closeEnough: 50), onAbandon: () => Abandon = true, onCompleted: () => RemoveSubObjective(ref goToObjective)); } } else { if (component.Item.GetComponent <Pickable>() == null) { //controller/target can't be selected and the item cannot be picked -> objective can't be completed Abandon = true; return; } else if (!character.Inventory.Items.Contains(component.Item)) { TryAddSubObjective(ref getItemObjective, () => new AIObjectiveGetItem(character, component.Item, objectiveManager, equip: true), onAbandon: () => Abandon = true, onCompleted: () => RemoveSubObjective(ref getItemObjective)); } else { if (requireEquip && !character.HasEquippedItem(component.Item)) { //the item has to be equipped before using it if it's holdable var holdable = component.Item.GetComponent <Holdable>(); if (holdable == null) { #if DEBUG DebugConsole.ThrowError($"{character.Name}: AIObjectiveOperateItem failed - equipping item " + component.Item + " is required but the item has no Holdable component"); #endif return; } for (int i = 0; i < character.Inventory.Capacity; i++) { if (character.Inventory.SlotTypes[i] == InvSlotType.Any || !holdable.AllowedSlots.Any(s => s.HasFlag(character.Inventory.SlotTypes[i]))) { continue; } //equip slot already taken if (character.Inventory.Items[i] != null) { //try to put the item in an Any slot, and drop it if that fails if (!character.Inventory.Items[i].AllowedSlots.Contains(InvSlotType.Any) || !character.Inventory.TryPutItem(character.Inventory.Items[i], character, new List <InvSlotType>() { InvSlotType.Any })) { character.Inventory.Items[i].Drop(character); } } if (character.Inventory.TryPutItem(component.Item, i, true, false, character)) { component.Item.Equip(character); break; } } return; } if (component.AIOperate(deltaTime, character, this)) { IsCompleted = completionCondition == null || completionCondition(); } } } }
protected override void OnCompleted() { StopMovement(); HumanAIController.FaceTarget(Target); base.OnCompleted(); }