protected override void Act(float deltaTime) { var weldingTool = character.Inventory.FindItem("Welding Tool"); if (weldingTool == null) { AddSubObjective(new AIObjectiveGetItem(character, "Welding Tool", true)); return; } else { var containedItems = weldingTool.ContainedItems; if (containedItems == null) { return; } var fuelTank = Array.Find(containedItems, i => i.Prefab.NameMatches("Welding Fuel Tank") && i.Condition > 0.0f); if (fuelTank == null) { AddSubObjective(new AIObjectiveContainItem(character, "Welding Fuel Tank", weldingTool.GetComponent <ItemContainer>())); return; } } var repairTool = weldingTool.GetComponent <RepairTool>(); if (repairTool == null) { return; } Vector2 standPosition = GetStandPosition(); if (Vector2.DistanceSquared(character.WorldPosition, leak.WorldPosition) > 100.0f * 100.0f) { var gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(standPosition), character); if (!gotoObjective.IsCompleted()) { AddSubObjective(gotoObjective); return; } } AddSubObjective(new AIObjectiveOperateItem(repairTool, character, "", true, leak)); }
protected override void Act(float deltaTime) { var currentHull = character.AnimController.CurrentHull; bool needsDivingGear = HumanAIController.NeedsDivingGear(currentHull); bool needsDivingSuit = needsDivingGear && (currentHull == null || currentHull.WaterPercentage > 90); bool needsEquipment = false; if (needsDivingSuit) { needsEquipment = !HumanAIController.HasDivingSuit(character); } else if (needsDivingGear) { needsEquipment = !HumanAIController.HasDivingMask(character); } if (needsEquipment) { TryAddSubObjective(ref divingGearObjective, () => new AIObjectiveFindDivingGear(character, needsDivingSuit, objectiveManager), onAbandon: () => searchHullTimer = Math.Min(1, searchHullTimer)); } else { if (divingGearObjective != null && divingGearObjective.IsCompleted()) { // Reset the devotion. Priority = 0; divingGearObjective = null; } if (currenthullSafety < HumanAIController.HULL_SAFETY_THRESHOLD) { searchHullTimer = Math.Min(1, searchHullTimer); } if (searchHullTimer > 0.0f) { searchHullTimer -= deltaTime; } else { searchHullTimer = SearchHullInterval; previousSafeHull = currentSafeHull; currentSafeHull = FindBestHull(); if (currentSafeHull == null) { currentSafeHull = previousSafeHull; } if (currentSafeHull != null && currentSafeHull != currentHull) { if (goToObjective?.Target != currentSafeHull) { goToObjective = null; } TryAddSubObjective(ref goToObjective, constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: true) { AllowGoingOutside = HumanAIController.HasDivingSuit(character) }, onAbandon: () => unreachable.Add(goToObjective.Target as Hull)); } else { goToObjective = null; } } if (goToObjective != null) { if (goToObjective.IsCompleted()) { objectiveManager.GetObjective <AIObjectiveIdle>()?.Wander(deltaTime); } Priority = 0; return; } if (currentHull == null) { return; } //goto objective doesn't exist (a safe hull not found, or a path to a safe hull not found) // -> attempt to manually steer away from hazards Vector2 escapeVel = Vector2.Zero; // TODO: optimize foreach (FireSource fireSource in HumanAIController.VisibleHulls.SelectMany(h => h.FireSources)) { Vector2 dir = character.Position - fireSource.Position; float distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(fireSource.Position, character.Position), 0.1f, 10.0f); escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier); } foreach (Character enemy in Character.CharacterList) { if (enemy.IsDead || enemy.IsUnconscious || enemy.Removed || HumanAIController.IsFriendly(enemy)) { continue; } if (HumanAIController.VisibleHulls.Contains(enemy.CurrentHull)) { Vector2 dir = character.Position - enemy.Position; float distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(enemy.Position, character.Position), 0.1f, 10.0f); escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier); } } if (escapeVel != Vector2.Zero) { float left = currentHull.Rect.X + 50; float right = currentHull.Rect.Right - 50; //only move if we haven't reached the edge of the room if (escapeVel.X < 0 && character.Position.X > left || escapeVel.X > 0 && character.Position.X < right) { character.AIController.SteeringManager.SteeringManual(deltaTime, escapeVel); } else { character.AnimController.TargetDir = escapeVel.X < 0.0f ? Direction.Right : Direction.Left; character.AIController.SteeringManager.Reset(); } } else { Priority = 0; objectiveManager.GetObjective <AIObjectiveIdle>()?.Wander(deltaTime); } } }
protected override void Act(float deltaTime) { if (!leak.IsRoomToRoom) { if (findDivingGear == null) { findDivingGear = new AIObjectiveFindDivingGear(character, true); AddSubObjective(findDivingGear); } else if (!findDivingGear.CanBeCompleted) { abandon = true; return; } } var weldingTool = character.Inventory.FindItemByTag("weldingtool"); if (weldingTool == null) { AddSubObjective(new AIObjectiveGetItem(character, "weldingtool", true)); return; } else { var containedItems = weldingTool.ContainedItems; if (containedItems == null) { return; } var fuelTank = containedItems.FirstOrDefault(i => i.HasTag("weldingfueltank") && i.Condition > 0.0f); if (fuelTank == null) { AddSubObjective(new AIObjectiveContainItem(character, "weldingfueltank", weldingTool.GetComponent <ItemContainer>())); return; } } var repairTool = weldingTool.GetComponent <RepairTool>(); if (repairTool == null) { return; } Vector2 gapDiff = leak.WorldPosition - character.WorldPosition; // TODO: use the collider size/reach? if (!character.AnimController.InWater && Math.Abs(gapDiff.X) < 100 && gapDiff.Y < 0.0f && gapDiff.Y > -150) { HumanAIController.AnimController.Crouching = true; } //float reach = HumanAIController.AnimController.ArmLength + ConvertUnits.ToSimUnits(repairTool.Range); float reach = ConvertUnits.ToSimUnits(repairTool.Range); bool cannotReach = ConvertUnits.ToSimUnits(gapDiff.Length()) > reach; if (cannotReach) { if (gotoObjective != null) { // Check if the objective is already removed -> completed/impossible if (!subObjectives.Contains(gotoObjective)) { if (!gotoObjective.CanBeCompleted) { abandon = true; } gotoObjective = null; return; } } else { gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character) { CloseEnough = reach }; if (!subObjectives.Contains(gotoObjective)) { AddSubObjective(gotoObjective); } } } if (gotoObjective == null || gotoObjective.IsCompleted()) { if (operateObjective == null) { operateObjective = new AIObjectiveOperateItem(repairTool, character, "", true, leak); AddSubObjective(operateObjective); } else if (!subObjectives.Contains(operateObjective)) { operateObjective = null; } } }
protected override void Act(float deltaTime) { if (goToObjective != null && !subObjectives.Contains(goToObjective)) { if (!goToObjective.IsCompleted() && !goToObjective.CanBeCompleted) { abandon = true; character?.Speak(TextManager.Get("DialogCannotRepair").Replace("[itemname]", Item.Name), null, 0.0f, "cannotrepair", 10.0f); } goToObjective = null; } 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) { AddSubObjective(new AIObjectiveGetItem(character, requiredItem.Identifiers, true)); } } return; } } if (character.CanInteractWith(Item)) { if (repairTool == null) { FindRepairTool(); } 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 then us. abandon = repairable.DegreeOfSuccess(character) < repairable.DegreeOfSuccess(repairable.CurrentFixer); } if (!abandon) { if (character.SelectedConstruction != Item) { Item.TryInteract(character, true, 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; character?.Speak(TextManager.Get("DialogRepairFailed").Replace("[itemname]", Item.Name), null, 0.0f, "repairfailed", 10.0f); } } repairable.CurrentFixer = abandon && repairable.CurrentFixer == character ? null : character; break; } } else if (goToObjective == null || goToObjective.Target != Item) { previousCondition = -1; if (goToObjective != null) { subObjectives.Remove(goToObjective); } goToObjective = new AIObjectiveGoTo(Item, character); if (repairTool != null) { goToObjective.CloseEnough = (HumanAIController.AnimController.ArmLength + ConvertUnits.ToSimUnits(repairTool.Range)) * 0.75f; } AddSubObjective(goToObjective); } }
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; } } }