diff --git a/Courseplay.lua b/Courseplay.lua index 14e3dd413..f421396dc 100644 --- a/Courseplay.lua +++ b/Courseplay.lua @@ -1,5 +1,7 @@ --- Global class +---@class Courseplay +---@operator call:Courseplay Courseplay = CpObject() Courseplay.MOD_NAME = g_currentModName Courseplay.BASE_DIRECTORY = g_currentModDirectory diff --git a/config/GlobalSettingsSetup.xml b/config/GlobalSettingsSetup.xml index fa22b4de2..a901d9890 100644 --- a/config/GlobalSettingsSetup.xml +++ b/config/GlobalSettingsSetup.xml @@ -30,7 +30,8 @@ always - + + diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml index ffc4d1bf8..79919f154 100644 --- a/config/MasterTranslations.xml +++ b/config/MasterTranslations.xml @@ -1237,6 +1237,14 @@ + + + + + + + + diff --git a/scripts/CpGlobalSettings.lua b/scripts/CpGlobalSettings.lua index f4e406047..e58c8e2ce 100644 --- a/scripts/CpGlobalSettings.lua +++ b/scripts/CpGlobalSettings.lua @@ -19,6 +19,7 @@ end --- Loads settings setup form an xmlFile. function CpGlobalSettings:loadSettingsSetup() MessageType.CP_DISTANCE_UNIT_CHANGED = nextMessageTypeId() + MessageType.CP_FUEL_SETTING_CHANGED = nextMessageTypeId() local filePath = Utils.getFilename("config/GlobalSettingsSetup.xml", g_Courseplay.BASE_DIRECTORY) CpSettingsUtil.loadSettingsFromSetup(self,filePath) @@ -101,6 +102,10 @@ function CpGlobalSettings:onUnitChanged() end end +function CpGlobalSettings:onFuelSettingChanged() + g_messageCenter:publish(MessageType.CP_FUEL_SETTING_CHANGED) +end + function CpGlobalSettings:debug(str,...) CpUtil.debugFormat(CpDebug.DBG_HUD,"Global settings: "..str,...) end diff --git a/scripts/ai/AIDriveStrategyBunkerSilo.lua b/scripts/ai/AIDriveStrategyBunkerSilo.lua index 91bc572e7..3c93eb83c 100644 --- a/scripts/ai/AIDriveStrategyBunkerSilo.lua +++ b/scripts/ai/AIDriveStrategyBunkerSilo.lua @@ -130,7 +130,7 @@ function AIDriveStrategyBunkerSilo:initializeImplementControllers(vehicle) end function AIDriveStrategyBunkerSilo:isFuelSaveAllowed() - return self.state.properties.fuelSaveAllowed + return self.state.properties.fuelSaveAllowed or AIDriveStrategyCourse.isFuelSaveAllowed(self) end ----------------------------------------------------------------------------------------------------------------------- diff --git a/scripts/ai/AIDriveStrategyCombineCourse.lua b/scripts/ai/AIDriveStrategyCombineCourse.lua index 504e8c84a..fa6500e64 100644 --- a/scripts/ai/AIDriveStrategyCombineCourse.lua +++ b/scripts/ai/AIDriveStrategyCombineCourse.lua @@ -1290,7 +1290,8 @@ function AIDriveStrategyCombineCourse:isFuelSaveAllowed() if self.combine:getIsThreshingDuringRain() then return true end - return self:isWaitingForUnload() or self:isChopperWaitingForUnloader() + return self:isWaitingForUnload() or self:isChopperWaitingForUnloader() + or AIDriveStrategyCourse.isFuelSaveAllowed(self) end --- Check if the vehicle should stop during a turn for example while it diff --git a/scripts/ai/AIDriveStrategyCourse.lua b/scripts/ai/AIDriveStrategyCourse.lua index d8a3b1748..13a09b5e2 100644 --- a/scripts/ai/AIDriveStrategyCourse.lua +++ b/scripts/ai/AIDriveStrategyCourse.lua @@ -28,6 +28,7 @@ AIDriveStrategyCourse.myStates = { } --- Implement controller events. +--- TODO_25 a more generic implementation AIDriveStrategyCourse.onRaisingEvent = "onRaising" AIDriveStrategyCourse.onLoweringEvent = "onLowering" AIDriveStrategyCourse.onFinishedEvent = "onFinished" @@ -35,6 +36,9 @@ AIDriveStrategyCourse.onStartEvent = "onStart" AIDriveStrategyCourse.onStartRefillingEvent = "onStartRefilling" AIDriveStrategyCourse.onStopRefillingEvent = "onStopRefilling" AIDriveStrategyCourse.onUpdateRefillingEvent = "onUpdateRefilling" +AIDriveStrategyCourse.onStartRefuellingEvent = "onStartRefuelling" +AIDriveStrategyCourse.onStopRefuellingEvent = "onStopRefuelling" +AIDriveStrategyCourse.onUpdateRefuellingEvent = "onUpdateRefuelling" AIDriveStrategyCourse.updateEvent = "update" AIDriveStrategyCourse.deleteEvent = "delete" --- A row has just been finished, implements are being raised and about to start the actual turn diff --git a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua index 9b8c2fbc8..2c2ea6ca6 100644 --- a/scripts/ai/AIDriveStrategyShovelSiloLoader.lua +++ b/scripts/ai/AIDriveStrategyShovelSiloLoader.lua @@ -191,7 +191,7 @@ end --- Fuel save only allowed when no trailer is there to unload into. function AIDriveStrategyShovelSiloLoader:isFuelSaveAllowed() - return self.state == self.states.WAITING_FOR_TRAILER + return self.state == self.states.WAITING_FOR_TRAILER or AIDriveStrategyCourse.isFuelSaveAllowed(self) end ----------------------------------------------------------------------------------------------------------------------- diff --git a/scripts/ai/AIDriveStrategySiloLoader.lua b/scripts/ai/AIDriveStrategySiloLoader.lua index 9dfbcc925..17f0cc7b7 100644 --- a/scripts/ai/AIDriveStrategySiloLoader.lua +++ b/scripts/ai/AIDriveStrategySiloLoader.lua @@ -152,6 +152,7 @@ end --- Fuel save only allowed when no trailer is there to unload into. function AIDriveStrategySiloLoader:isFuelSaveAllowed() return self.state == self.states.WORKING and not self.conveyorController:canDischargeToObject() + or AIDriveStrategyCourse.isFuelSaveAllowed(self) end ----------------------------------------------------------------------------------------------------------------------- diff --git a/scripts/ai/AIDriveStrategyUnloadCombine.lua b/scripts/ai/AIDriveStrategyUnloadCombine.lua index 0667aca02..eba3cb610 100644 --- a/scripts/ai/AIDriveStrategyUnloadCombine.lua +++ b/scripts/ai/AIDriveStrategyUnloadCombine.lua @@ -1150,7 +1150,7 @@ end ------------------------------------------------------------------------------------------------------------------------ function AIDriveStrategyUnloadCombine:isFuelSaveAllowed() - return self.state.properties.fuelSaveAllowed + return self.state.properties.fuelSaveAllowed or AIDriveStrategyCourse.isFuelSaveAllowed(self) end function AIDriveStrategyUnloadCombine:isCoverOpeningAllowed() diff --git a/scripts/ai/controllers/MotorController.lua b/scripts/ai/controllers/MotorController.lua index c5b3f3453..be6404b13 100644 --- a/scripts/ai/controllers/MotorController.lua +++ b/scripts/ai/controllers/MotorController.lua @@ -12,6 +12,16 @@ function MotorController:init(vehicle, implement) self.vehicle.spec_cpAIWorker.motorDisabled = false self.isValid = true self.fuelThresholdSetting = g_Courseplay.globalSettings.fuelThreshold + self.refuelData = { + timer = CpTemporaryObject(true), + hasChanged = false, + lastFillLevels = { + [self.implement] = {} + } + } + for _, fillUnitIndex in ipairs(self.motorSpec.propellantFillUnitIndices) do + self.refuelData.lastFillLevels[self.implement][fillUnitIndex] = -1 + end end function MotorController:update() @@ -82,4 +92,30 @@ function MotorController:stopMotor() self.implement:stopMotor() self.vehicle.spec_cpAIWorker.motorDisabled = true self:debug("Stopped motor for fuel save.") +end + +function MotorController:onStartRefuelling() + ImplementUtil.hasFillLevelChanged(self.refuelData.lastFillLevels, true) + self.refuelData.hasChanged = false + self.refuelData.timer:set(false, 10 * 1000) +end + +function MotorController:onUpdateRefuelling() + if ImplementUtil.tryAndCheckRefillingFillUnits(self.refuelData.lastFillLevels) or + ImplementUtil.hasFillLevelChanged(self.refuelData.lastFillLevels) then + self.refuelData.timer:set(false, 10 * 1000) + self.refuelData.hasChanged = true + end + return self.refuelData.timer:get(), self.refuelData.hasChanged +end + +function MotorController:onStopRefuelling() + local spec = self.implement.spec_fillUnit + if spec.fillTrigger.isFilling then + self.implement:setFillUnitIsFilling(false) + end +end + +function MotorController:onFinished() + self:onStopRefuelling() end \ No newline at end of file diff --git a/scripts/ai/controllers/SprayerController.lua b/scripts/ai/controllers/SprayerController.lua index 4033fd284..facc41e17 100644 --- a/scripts/ai/controllers/SprayerController.lua +++ b/scripts/ai/controllers/SprayerController.lua @@ -62,6 +62,7 @@ function SprayerController:onStartRefilling(ignore) end end end + self.refillData.timer:set(false, 10 * 1000) end ImplementUtil.hasFillLevelChanged(self.refillData.lastFillLevels, true) self.refillData.hasChanged = false diff --git a/scripts/ai/jobs/CpAIJob.lua b/scripts/ai/jobs/CpAIJob.lua index 48ef6a864..79c9750b6 100644 --- a/scripts/ai/jobs/CpAIJob.lua +++ b/scripts/ai/jobs/CpAIJob.lua @@ -33,6 +33,11 @@ function CpAIJob.new(isServer, customMt) self:setupJobParameters() self:setupTasks(isServer) + + self.isRefuelingActive = false + + g_messageCenter:subscribe(MessageType.CP_FUEL_SETTING_CHANGED, self.stopRefuelling, self) + return self end @@ -75,9 +80,58 @@ end ---@param message table Stop reason can be used to reverse engineer the cause. ---@return boolean function CpAIJob:isFinishingAllowed(message) + --- TODO_25 Move the refuel logic into a task ... + --- For this we need to seperate strategy,task logic first .. + if message:isa(AIMessageErrorOutOfFuel) then + if g_Courseplay.globalSettings.waitForRefueling:getValue() then + local strategy = self.vehicle:getCpDriveStrategy() + if strategy then + if not self.isRefuelingActive then + self.isRefuelingActive = true + strategy:raiseControllerEvent( + AIDriveStrategyCourse.onStartRefuellingEvent) + self:debug("Starts to wait for refueling") + end + return false + end + end + end return true end +function CpAIJob:update(dt) + CpAIJob:superClass().update(self, dt) + if self.isRefuelingActive then + local vehicle = self:getVehicle() + local strategy = vehicle:getCpDriveStrategy() + vehicle:cpHold(1500, true) + vehicle:setCpInfoTextActive(InfoTextManager.FUEL_IS_EMPTY) + + local readyToContinue, fillLevelHasChanged = true, false + strategy:raiseControllerEventWithLambda( + AIDriveStrategyCourse.onUpdateRefuellingEvent, + function(timerHasFinished, hasChanged) + readyToContinue = readyToContinue and timerHasFinished + fillLevelHasChanged = fillLevelHasChanged or hasChanged + end) + if readyToContinue and fillLevelHasChanged then + self:stopRefuelling() + end + end +end + +function CpAIJob:stopRefuelling() + if self.isRefuelingActive then + local vehicle = self:getVehicle() + local strategy = vehicle:getCpDriveStrategy() + self:debug("Finished the refueling") + strategy:raiseControllerEvent( + AIDriveStrategyCourse.onStopRefuellingEvent) + self.isRefuelingActive = false + vehicle:resetCpActiveInfoText(InfoTextManager.FUEL_IS_EMPTY) + end +end + --- Gets the first task to start with. function CpAIJob:getStartTaskIndex() if self.currentTaskIndex ~= 0 or self.isDirectStart or self:isTargetReached() then @@ -167,6 +221,7 @@ function CpAIJob:stop(aiMessage) if driveStrategy then driveStrategy:onFinished(hasFinished) end + g_messageCenter:unsubscribeAll(self) end --- Updates the parameter values. diff --git a/scripts/ai/jobs/CpAIJobFieldWork.lua b/scripts/ai/jobs/CpAIJobFieldWork.lua index ab4a92596..f802e8fbb 100644 --- a/scripts/ai/jobs/CpAIJobFieldWork.lua +++ b/scripts/ai/jobs/CpAIJobFieldWork.lua @@ -67,7 +67,7 @@ function CpAIJobFieldWork:isFinishingAllowed(message) end return false end - return true + return CpAIJob.isFinishingAllowed(self, message) end ---@param vehicle table diff --git a/scripts/specializations/CpAIBaleFinder.lua b/scripts/specializations/CpAIBaleFinder.lua index 3d13aad54..f6bd00d97 100644 --- a/scripts/specializations/CpAIBaleFinder.lua +++ b/scripts/specializations/CpAIBaleFinder.lua @@ -114,10 +114,6 @@ function CpAIBaleFinder:applyCpBaleFinderJobParameters(job) spec.cpJob:copyFrom(job) end -function CpAIBaleFinder:getCpDriveStrategy(superFunc) - return superFunc(self) or self.spec_cpAIBaleFinder.driveStrategy -end - --- Is the bale finder allowed? function CpAIBaleFinder:getCanStartCpBaleFinder() return (AIUtil.hasImplementWithSpecialization(self, BaleWrapper) and not AIUtil.hasImplementWithSpecialization(self, Baler)) or diff --git a/scripts/specializations/CpAICombineUnloader.lua b/scripts/specializations/CpAICombineUnloader.lua index a88f03551..ee8b3901b 100644 --- a/scripts/specializations/CpAICombineUnloader.lua +++ b/scripts/specializations/CpAICombineUnloader.lua @@ -192,10 +192,6 @@ function CpAICombineUnloader:getCpCombineUnloaderJobParameters() return spec.cpJob:getCpJobParameters() end -function CpAICombineUnloader:getCpDriveStrategy(superFunc) - return superFunc(self) or self.spec_cpAICombineUnloader.driveStrategy -end - --- Makes sure only trailers with discharge nodes are used. function CpAICombineUnloader:isValidTrailer(trailer) local spec = trailer.spec_dischargeable