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