public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective) { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return(false); } character.AIController.SteeringManager.Reset(); bool shutDown = objective.Option.Equals("shutdown", StringComparison.OrdinalIgnoreCase); IsActive = true; if (!shutDown) { float degreeOfSuccess = DegreeOfSuccess(character); float refuelLimit = 0.3f; //characters with insufficient skill levels don't refuel the reactor if (degreeOfSuccess > refuelLimit) { if (aiUpdateTimer > 0.0f) { aiUpdateTimer -= deltaTime; return(false); } aiUpdateTimer = AIUpdateInterval; // load more fuel if the current maximum output is only 50% of the current load // or if the fuel rod is (almost) deplenished float minCondition = fuelConsumptionRate * MathUtils.Pow2((degreeOfSuccess - refuelLimit) * 2); if (NeedMoreFuel(minimumOutputRatio: 0.5f, minCondition: minCondition)) { bool outOfFuel = false; var container = item.GetComponent <ItemContainer>(); if (objective.SubObjectives.None()) { var containObjective = AIContainItems <Reactor>(container, character, objective, itemCount: 1, equip: true, removeEmpty: true, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC, dropItemOnDeselected: true); containObjective.Completed += ReportFuelRodCount; containObjective.Abandoned += ReportFuelRodCount; character.Speak(TextManager.Get("DialogReactorFuel"), null, 0.0f, "reactorfuel", 30.0f); void ReportFuelRodCount() { if (!character.IsOnPlayerTeam) { return; } if (character.Submarine != Submarine.MainSub) { return; } int remainingFuelRods = Submarine.MainSub.GetItems(false).Count(i => i.HasTag("reactorfuel") && i.Condition > 1); if (remainingFuelRods == 0) { character.Speak(TextManager.Get("DialogOutOfFuelRods"), null, 0.0f, "outoffuelrods", 30.0f); outOfFuel = true; } else if (remainingFuelRods < 3) { character.Speak(TextManager.Get("DialogLowOnFuelRods"), null, 0.0f, "lowonfuelrods", 30.0f); } } } return(outOfFuel); } else { if (Item.ConditionPercentage <= 0 && AIObjectiveRepairItems.IsValidTarget(Item, character)) { if (Item.Repairables.Average(r => r.DegreeOfSuccess(character)) > 0.4f) { objective.AddSubObjective(new AIObjectiveRepairItem(character, Item, objective.objectiveManager, isPriority: true)); return(false); } else { character.Speak(TextManager.Get("DialogReactorIsBroken"), identifier: "reactorisbroken", minDurationBetweenSimilar: 30.0f); } } if (TooMuchFuel()) { DropFuel(minCondition: 0.1f, maxCondition: 100); } else { DropFuel(minCondition: 0, maxCondition: 0); } } } } if (objective.Override) { if (lastUser != null && lastUser != character && lastUser != LastAIUser) { if (lastUser.SelectedConstruction == item && character.IsOnPlayerTeam) { character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f); } } } else if (LastUserWasPlayer && lastUser != null && lastUser.TeamID == character.TeamID) { return(true); } LastUser = LastAIUser = character; bool prevAutoTemp = autoTemp; bool prevPowerOn = _powerOn; float prevFissionRate = targetFissionRate; float prevTurbineOutput = targetTurbineOutput; if (shutDown) { PowerOn = false; AutoTemp = false; targetFissionRate = 0.0f; targetTurbineOutput = 0.0f; unsentChanges = true; return(true); } else { PowerOn = true; 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 FissionRateScrollBar.BarScroll = FissionRate / 100.0f; TurbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f; #endif if (autoTemp != prevAutoTemp || prevPowerOn != _powerOn || Math.Abs(prevFissionRate - targetFissionRate) > 1.0f || Math.Abs(prevTurbineOutput - targetTurbineOutput) > 1.0f) { unsentChanges = true; } aiUpdateTimer = AIUpdateInterval; return(false); } void DropFuel(float minCondition, float maxCondition) { if (item.OwnInventory?.AllItems != null) { var container = item.GetComponent <ItemContainer>(); foreach (Item item in item.OwnInventory.AllItemsMod) { if (item.ConditionPercentage <= maxCondition && item.ConditionPercentage >= minCondition) { item.Drop(character); break; } } } } }
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective) { character.AIController.SteeringManager.Reset(); if (objective.Override) { if (user != character && user != null && user.SelectedConstruction == item && character.IsOnPlayerTeam) { character.Speak(TextManager.Get("DialogSteeringTaken"), null, 0.0f, "steeringtaken", 10.0f); } } user = character; if (Item.ConditionPercentage <= 0 && AIObjectiveRepairItems.IsValidTarget(Item, character)) { if (Item.Repairables.Average(r => r.DegreeOfSuccess(character)) > 0.4f) { objective.AddSubObjective(new AIObjectiveRepairItem(character, Item, objective.objectiveManager, isPriority: true)); return(false); } else { character.Speak(TextManager.Get("DialogNavTerminalIsBroken"), identifier: "navterminalisbroken", minDurationBetweenSimilar: 30.0f); } } if (!AutoPilot) { unsentChanges = true; AutoPilot = true; } IncreaseSkillLevel(user, deltaTime); switch (objective.Option.ToLowerInvariant()) { case "maintainposition": if (objective.Override) { SetMaintainPosition(); } break; case "navigateback": if (Level.IsLoadedOutpost) { break; } if (DockingSources.Any(d => d.Docked)) { item.SendSignal("1", "toggle_docking"); } if (objective.Override) { if (MaintainPos || LevelEndSelected || !LevelStartSelected || navigateTactically) { unsentChanges = true; } SetDestinationLevelStart(); } break; case "navigatetodestination": if (Level.IsLoadedOutpost) { break; } if (DockingSources.Any(d => d.Docked)) { item.SendSignal("1", "toggle_docking"); } if (objective.Override) { if (MaintainPos || !LevelEndSelected || LevelStartSelected || navigateTactically) { unsentChanges = true; } SetDestinationLevelEnd(); } break; case "navigatetactical": if (Level.IsLoadedOutpost) { break; } if (DockingSources.Any(d => d.Docked)) { item.SendSignal("1", "toggle_docking"); } if (objective.Override) { if (MaintainPos || LevelEndSelected || LevelStartSelected || !navigateTactically) { unsentChanges = true; } SetDestinationTactical(); } break; } sonar?.AIOperate(deltaTime, character, objective); if (!MaintainPos && showIceSpireWarning && character.IsOnPlayerTeam) { character.Speak(TextManager.Get("dialogicespirespottedsonar"), null, 0.0f, "icespirespottedsonar", 60.0f); } return(false); }