diff --git a/BunkersiloManager.lua b/BunkersiloManager.lua
index 2ac698b30..7e989f824 100644
--- a/BunkersiloManager.lua
+++ b/BunkersiloManager.lua
@@ -30,14 +30,22 @@ widthNode --> | | <-- startNode (sx,_,sz)
---@param vehicle vehicle
---@param Silo BunkerSilo or simulated HeapSilo
---@param float workwidth
----@param implement relevant workTool
+---@param node targetNode is either the front/back node of the implement used to check if the bestTarget was passed
---@param boolean is the silo a heap ?
-function BunkerSiloManager:init(vehicle, Silo, width, object,isHeap)
+function BunkerSiloManager:init(vehicle, Silo, width, targetNode,isHeap)
print("BunkerSiloManager: init()")
self.siloMap = self:createBunkerSiloMap(vehicle, Silo, width,isHeap)
self.silo = Silo
self.vehicle = vehicle
- self.object = object
+ self.targetNode = targetNode
+end
+
+function BunkerSiloManager:getSiloMap()
+ return self.siloMap
+end
+
+function BunkerSiloManager:getSilo()
+ return self.silo
end
---creating the relevant siloMap
@@ -262,7 +270,7 @@ function BunkerSiloManager:isAtEnd(bestTarget)
local targetUnit = self.siloMap[bestTarget.line][bestTarget.column]
local cx ,cz = targetUnit.cx, targetUnit.cz
local cy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, cx, 1, cz);
- local x,y,z = getWorldTranslation(self.object.rootNode)
+ local x,y,z = getWorldTranslation(self.targetNode)
local distance2Target = courseplay:distance(x,z, cx, cz) --distance from shovel to target
if distance2Target < 1 then
if bestTarget.line == #self.siloMap then
@@ -297,10 +305,10 @@ function BunkerSiloManager:getBestTargetFillUnitFillUp(bestTarget)
end
if column == #line and mostFillLevelAtLine > 0 then
fillingTarget = {
- line = lineIndex;
- column = mostFillLevelIndex;
- empty = false;
- }
+ line = lineIndex;
+ column = mostFillLevelIndex;
+ empty = false;
+ }
stopSearching = true
break
end
@@ -308,10 +316,10 @@ function BunkerSiloManager:getBestTargetFillUnitFillUp(bestTarget)
end
if mostFillLevelAtLine == 0 then
fillingTarget = {
- line = 1;
- column = 1;
- empty = true;
- }
+ line = 1;
+ column = 1;
+ empty = true;
+ }
end
bestTarget = fillingTarget
@@ -335,7 +343,7 @@ function BunkerSiloManager:updateTarget(bestTarget)
local targetUnit = self.siloMap[bestTarget.line][bestTarget.column]
local cx ,cz = targetUnit.cx, targetUnit.cz
local cy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, cx, 1, cz);
- local x,y,z = getWorldTranslation(self.object.rootNode)
+ local x,y,z = getWorldTranslation(self.targetNode)
local distance2Target = courseplay:distance(x,z, cx, cz) --distance from shovel to target
if math.abs(distance2Target) < 1 then
bestTarget.line = math.min(bestTarget.line + 1, #self.siloMap)
diff --git a/FillableFieldworkAIDriver.lua b/FillableFieldworkAIDriver.lua
index c0ff13fe9..5fbe1b2dd 100644
--- a/FillableFieldworkAIDriver.lua
+++ b/FillableFieldworkAIDriver.lua
@@ -67,7 +67,7 @@ function FillableFieldworkAIDriver:driveUnloadOrRefill()
else
self:clearInfoText('NO_SELECTED_FILLTYPE')
end
- local isNearWaitPoint, waitPointIx = self.course:hasWaitPointWithinDistance(self.ppc:getRelevantWaypointIx(), 10)
+ local isNearWaitPoint, waitPointIx = self.course:hasWaitPointWithinDistance(self.ppc:getRelevantWaypointIx(), 25)
--this one is used to disable loading at the unloading stations,
--might be better to disable the triggerID for loading
self:enableFillTypeLoading(isNearWaitPoint)
@@ -75,6 +75,7 @@ function FillableFieldworkAIDriver:driveUnloadOrRefill()
-- use the courseplay speed limit until we get to the actual unload corse fields (on alignment/temporary)
self:setSpeed(self.vehicle.cp.speeds.field)
elseif self.refillState == self.states.TO_BE_REFILLED and isNearWaitPoint then
+ -- should be reworked and be similar to mode 1 loading at start
local distanceToWait = self.course:getDistanceBetweenVehicleAndWaypoint(self.vehicle, waitPointIx)
self:setSpeed(MathUtil.clamp(distanceToWait,self.vehicle.cp.speeds.crawl,self:getRecordedSpeed()))
if distanceToWait < 1 then
diff --git a/LevelCompactAIDriver.lua b/LevelCompactAIDriver.lua
index e37168c8e..51d3ca076 100644
--- a/LevelCompactAIDriver.lua
+++ b/LevelCompactAIDriver.lua
@@ -159,18 +159,15 @@ function LevelCompactAIDriver:foundUnloaderInRadius(r,setWaiting)
end
if setWaiting and isOkayToStop then
--- vehicle.cp.driver.triggerHandler:setWaitingForUnloadReady()
vehicle.cp.driver:hold()
vehicle.cp.driver:setInfoText("WAITING_FOR_LEVELCOMPACTAIDRIVER")
vehicle.cp.driver:disableTrafficConflictDetection()
else
vehicle.cp.driver:clearInfoText("WAITING_FOR_LEVELCOMPACTAIDRIVER")
vehicle.cp.driver:enableTrafficConflictDetection()
--- vehicle.cp.driver.triggerHandler:resetWaitingForUnloadReady()
end
self:debugSparse("found cp driver : %s",nameNum(vehicle))
return isOkayToStop
- -- self.unloaderAIDrivers[#self.unloaderAIDrivers+1] = vehicle
elseif autodriveSpec and autodriveSpec.HoldDriving and vehicle.ad.stateModule and vehicle.ad.stateModule:isActive() then
--autodrive
if setWaiting then
@@ -247,6 +244,7 @@ function LevelCompactAIDriver:selectMode()
elseif self:getIsModeCompact()then
self:debug("self:isModeCompact()")
self:changeLevelState(self.states.DRIVE_SILOCOMPACT)
+ self:lowerImplements()
end
self.fillUpState = self.states.PUSH
end
@@ -260,21 +258,16 @@ function LevelCompactAIDriver:driveSiloCompact(dt)
end
self:drivePush(dt)
- self:lowerImplements()
if self:isAtEnd() then
self.fillUpState = self.states.PULLBACK
+ self:raiseImplements()
end
elseif self.fillUpState == self.states.PULLBACK then
if self:drivePull(dt) then
self.fillUpState = self.states.PUSH
+ self:lowerImplements()
self:deleteBestTargetLeveling()
- self:raiseImplements()
- if self.hasFoundUnloaders then
- self:debug("has unloader so move to waitpoint")
- self:changeLevelState(self.states.DRIVE_TO_PARKING)
- self:deleteBestTarget()
- end
end
end
end
@@ -291,7 +284,7 @@ function LevelCompactAIDriver:driveSiloLevel(dt)
self:moveShield('down',dt,self:getDiffHeightforHeight(self.targetHeight))
if self:isAtEnd()
- or self:hasShieldEmpty()
+ --or self:hasShieldEmpty()
or self:isStuck()
then
if self.hasFoundUnloaders then
@@ -305,7 +298,6 @@ function LevelCompactAIDriver:driveSiloLevel(dt)
elseif self.fillUpState == self.states.PULLBACK then
- renderText(0.2,0.365,0.02,"self:drivePull(dt)")
self:moveShield('up',dt)
if self:isStuck() then
self.fillUpState = self.states.PUSH
@@ -322,14 +314,14 @@ function LevelCompactAIDriver:driveSiloFillUp(dt)
if self.fillUpState == self.states.PUSH then
--initialize first target point
if self.bestTarget == nil then
- self.bestTarget, self.firstLine = self.bunkerSiloManager:getBestTargetFillUnitFillUp(self.bestTarget)
+ self.bestTarget, self.firstLine = self:getBestTargetFillUnitFillUp(self.lastDrivenColumn)
end
self:drivePush(dt)
self:moveShield('down',dt,0)
--self:moveShield('down',dt,self:getDiffHeightforHeight(0))
if self:lastLineFillLevelChanged()
or self:isStuck()
- or self:hasShieldEmpty()
+ --or self:hasShieldEmpty()
then
if self.hasFoundUnloaders then
self:changeLevelState(self.states.DRIVE_TO_PARKING)
@@ -341,9 +333,9 @@ function LevelCompactAIDriver:driveSiloFillUp(dt)
end
elseif self.fillUpState == self.states.PULLBACK then
self:moveShield('up',dt)
- if self:drivePull(dt) or self:getHasMovedToFrontLine(dt) then
+ if self:drivePull(dt) then
self.fillUpState = self.states.PUSH
- self:deleteBestTarget()
+ self:deleteBestTargetLeveling()
end
end
end
@@ -363,9 +355,9 @@ function LevelCompactAIDriver:drivePush(dt)
self:updateTarget()
--speed
if self:isNearEnd() then
- refSpeed = math.min(10,vehicle.cp.speeds.bunkerSilo)
+ refSpeed = math.min(10,vehicle.cp.settings.bunkerSpeed:get())
else
- refSpeed = math.min(20,vehicle.cp.speeds.bunkerSilo)
+ refSpeed = math.min(20,vehicle.cp.settings.bunkerSpeed:get())
end
--drive
local lx, lz = AIVehicleUtil.getDriveDirection(self.vehicle.cp.directionNode, cx,cy,cz);
@@ -380,7 +372,7 @@ end
function LevelCompactAIDriver:drivePull(dt)
local pullDone = false
local fwd = true
- local refSpeed = math.min(20,self.vehicle.cp.speeds.bunkerSilo)
+ local refSpeed = math.min(20,self.vehicle.cp.settings.bunkerSpeed:get())
local allowedToDrive = true
local cx,cy,cz = self.course:getWaypointPosition(self.course:getNumberOfWaypoints())
local lx, lz = AIVehicleUtil.getDriveDirection(self.vehicle.cp.directionNode, cx,cy,cz);
@@ -389,6 +381,11 @@ function LevelCompactAIDriver:drivePull(dt)
if lz < 0 then
pullDone = true
end
+ if self.hasFoundUnloaders then
+ self:changeLevelState(self.states.DRIVE_TO_PARKING)
+ self:deleteBestTarget()
+ return false
+ end
-- self:drawMap()
return pullDone
end
@@ -396,7 +393,7 @@ end
---make sure we start with enough distance to the first bunkersilo target, so we don't drive into the silo wall
---currently we just drive 10 m ahead and then start normaly drive the buker course
function LevelCompactAIDriver:driveToPreStartPosition(dt)
- local refSpeed = math.min(20,self.vehicle.cp.speeds.bunkerSilo)
+ local refSpeed = math.min(20,self.vehicle.cp.settings.bunkerSpeed:get())
self:moveShield('up',dt)
if self.tempTarget == nil then
local gx,gy,gz = localToWorld(self.vehicle.rootNode,0,0,10)
@@ -416,9 +413,9 @@ end
function LevelCompactAIDriver:getHasMovedToFrontLine(dt)
local startUnit = self.bunkerSiloManager.siloMap[self.firstLine][1]
- local _,ty,_ = getWorldTranslation(self.vehicle.cp.directionNode);
- local _,_,z = worldToLocal(self.vehicle.cp.directionNode, startUnit.cx , ty , startUnit.cz);
- if z < -15 then
+ local _,ty,_ = getWorldTranslation(self:getLevelerNode(self.leveler));
+ local _,_,z = worldToLocal(self:getLevelerNode(self.leveler), startUnit.cx , ty , startUnit.cz);
+ if math.abs(z) < 1 then
return true;
end
return false;
@@ -431,12 +428,13 @@ end
function LevelCompactAIDriver:lastLineFillLevelChanged()
local vehicle = self.vehicle
- local newSx = self.bunkerSiloManager.siloMap[#self.bunkerSiloManager.siloMap][1].sx
- local newSz = self.bunkerSiloManager.siloMap[#self.bunkerSiloManager.siloMap][1].sz
- local newWx = self.bunkerSiloManager.siloMap[#self.bunkerSiloManager.siloMap][#self.bunkerSiloManager.siloMap[#self.bunkerSiloManager.siloMap]].wx
- local newWz = self.bunkerSiloManager.siloMap[#self.bunkerSiloManager.siloMap][#self.bunkerSiloManager.siloMap[#self.bunkerSiloManager.siloMap]].wz
- local newHx = self.bunkerSiloManager.siloMap[#self.bunkerSiloManager.siloMap][1].hx
- local newHz = self.bunkerSiloManager.siloMap[#self.bunkerSiloManager.siloMap][1].hz
+ local siloMap = self.bunkerSiloManager:getSiloMap()
+ local newSx = siloMap[#siloMap][1].sx
+ local newSz = siloMap[#siloMap][1].sz
+ local newWx = siloMap[#siloMap][#siloMap[#siloMap]].wx
+ local newWz = siloMap[#siloMap][#siloMap[#siloMap]].wz
+ local newHx = siloMap[#siloMap][1].hx
+ local newHz = siloMap[#siloMap][1].hz
local wY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, newWx, 1, newWz);
local hY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, newHx, 1, newHz);
@@ -598,18 +596,28 @@ function LevelCompactAIDriver:checkSilo()
end
function LevelCompactAIDriver:lowerImplements()
+ self.vehicle:raiseAIEvent("onAIStart", "onAIImplementStart")
+ self.vehicle:requestActionEventUpdate()
for _, implement in pairs(self.vehicle:getAttachedImplements()) do
if implement.object.aiImplementStartLine then
implement.object:aiImplementStartLine()
+ -- if implement.object.getCanBeTurnedOn and implement.object:getCanBeTurnedOn() then
+ -- implement.object:setIsTurnedOn(true)
+ -- end
end
end
self.vehicle:raiseStateChange(Vehicle.STATE_CHANGE_AI_START_LINE)
end
function LevelCompactAIDriver:raiseImplements()
+ self.vehicle:raiseAIEvent("onAIEnd", "onAIImplementEnd")
+ self.vehicle:requestActionEventUpdate()
for _, implement in pairs(self.vehicle:getAttachedImplements()) do
if implement.object.aiImplementEndLine then
implement.object:aiImplementEndLine()
+ -- if implement.object.getCanBeTurnedOn then
+ -- implement.object:setIsTurnedOn(false)
+ -- end
end
end
self.vehicle:raiseStateChange(Vehicle.STATE_CHANGE_AI_END_LINE)
@@ -619,7 +627,7 @@ end
function LevelCompactAIDriver:moveShield(moveDir,dt,fixHeight)
local leveler = self.leveler
local moveFinished = false
- if leveler.spec_attacherJointControl ~= nil then
+ if leveler and leveler.spec_attacherJointControl ~= nil then
local spec = leveler.spec_attacherJointControl
local jointDesc = spec.jointDesc
if moveDir == "down" then
@@ -755,9 +763,10 @@ end
function LevelCompactAIDriver:getBestTargetFillUnitCompacting(lastDrivenColumn)
local newBestTarget = {}
local firstLine = 1
- if self.bunkerSiloManager.siloMap ~= nil then
+ local siloMap = self.bunkerSiloManager:getSiloMap()
+ if siloMap ~= nil then
local newColumn = lastDrivenColumn and lastDrivenColumn + 1 or 1
- if newColumn > #self.bunkerSiloManager.siloMap[1] then
+ if newColumn > #siloMap[1] then
newColumn = 1
end
local newBestTarget= {
@@ -769,14 +778,47 @@ function LevelCompactAIDriver:getBestTargetFillUnitCompacting(lastDrivenColumn)
end
end
+--- get the bestTarget, firstLine of the bestTarget work with
+---@param int lastDrivenColumn of the silo
+---@return bestTarget, firstLine of the bestTarget
+function LevelCompactAIDriver:getBestTargetFillUnitFillUp(lastDrivenColumn)
+ local siloMap = self.bunkerSiloManager:getSiloMap()
+
+ local newColumn = lastDrivenColumn and lastDrivenColumn + 1 or 1
+ if newColumn > #siloMap[1] then
+ newColumn = 1
+ end
+ local firstLine = 1
+ local bestTarget = {
+ line = 1;
+ column = newColumn;
+ empty = true;
+ }
+ -- find column with most fillLevel and figure out whether it is empty
+ for lineIndex, line in pairs(siloMap) do
+ local fillUnit = siloMap[lineIndex][newColumn]
+ if fillUnit.fillLevel > 0 then
+ bestTarget = {
+ line = lineIndex;
+ column = newColumn;
+ empty = false;
+ }
+ firstLine = bestTarget.line
+ break
+ end
+ end
+ return bestTarget, firstLine
+end
+
function LevelCompactAIDriver:getBestTargetFillUnitLeveling(lastDrivenColumn)
+ local siloMap = self.bunkerSiloManager:getSiloMap()
local firstLine = 1
local targetHeight = 0.5
local vehicle = self.vehicle
local newApproach = lastDrivenColumn == nil
local newBestTarget = {}
- if self.bunkerSiloManager.siloMap ~= nil then
- local newColumn = math.ceil(#self.bunkerSiloManager.siloMap[1]/2)
+ if siloMap ~= nil then
+ local newColumn = math.ceil(#siloMap[1]/2)
if newApproach then
newBestTarget, firstLine = self.bunkerSiloManager:getBestTargetFillUnitFillUp(self.bestTarget)
self:debug('Best leveling target at line %d, column %d, height %d, first line %d (fist approach)',
@@ -784,15 +826,15 @@ function LevelCompactAIDriver:getBestTargetFillUnitLeveling(lastDrivenColumn)
return newBestTarget, firstLine, targetHeight
else
newColumn = lastDrivenColumn + 1;
- if newColumn > #self.bunkerSiloManager.siloMap[1] then
+ if newColumn > #siloMap[1] then
newColumn = 1;
end
- firstLine = self:findFirstNonEmptyRow(self.bunkerSiloManager.siloMap, newColumn)
+ firstLine = self:findFirstNonEmptyRow(siloMap, newColumn)
newBestTarget= {
- line = firstLine;
- column = newColumn;
- empty = false;
- }
+ line = firstLine;
+ column = newColumn;
+ empty = false;
+ }
end
targetHeight = self:getColumnsTargetHeight(newColumn)
end
@@ -804,12 +846,13 @@ end
function LevelCompactAIDriver:getColumnsTargetHeight(newColumn)
local totalArea = 0
local totalFillLevel = 0
- for i=1,#self.bunkerSiloManager.siloMap do
+ local siloMap = self.bunkerSiloManager:getSiloMap()
+ for i=1,#siloMap do
--calculate the area without first and last line
- if i~= 1 and i~= #self.bunkerSiloManager.siloMap then
- totalArea = totalArea + self.bunkerSiloManager.siloMap[i][newColumn].area
+ if i~= 1 and i~= #siloMap then
+ totalArea = totalArea + siloMap[i][newColumn].area
end
- totalFillLevel = totalFillLevel + self.bunkerSiloManager.siloMap[i][newColumn].fillLevel
+ totalFillLevel = totalFillLevel + siloMap[i][newColumn].fillLevel
end
local newHeight = math.max(0.6,(totalFillLevel/1000)/totalArea)
self:debug("getTargetHeight: totalFillLevel:%s; totalArea:%s Height%s",tostring(totalFillLevel),tostring(totalArea),tostring(newHeight))
@@ -819,7 +862,7 @@ end
function LevelCompactAIDriver:debugRouting()
if self:isDebugActive() and self.bunkerSiloManager then
- self.bunkerSiloManager:debugRouting(self.bestTarget,self.tempTarget)
+ self.bunkerSiloManager:debugRouting(self.bestTarget)
end
end
@@ -858,9 +901,11 @@ function LevelCompactAIDriver:getWorkWidth()
return math.max(self.workWidth,self.vehicle.cp.workWidth)
end
+---if we have a leveler return the leveler.rootNode, else return the backMakerNode
+---@return node self.leveler.rootNode or backMakerNode
function LevelCompactAIDriver:getValidBackImplement()
- local backImplement = AIDriverUtil.getLastAttachedImplement(self.vehicle)
- return self.leveler or backImplement
+ local backMarkerNode = self:getBackMarkerNode(self.vehicle)
+ return self.leveler and self.leveler.rootNode or backMarkerNode
end
function LevelCompactAIDriver:isDebugActive()
diff --git a/ShovelModeAIDriver.lua b/ShovelModeAIDriver.lua
index f5725fb5a..4686b038c 100644
--- a/ShovelModeAIDriver.lua
+++ b/ShovelModeAIDriver.lua
@@ -56,6 +56,8 @@ ShovelModeAIDriver.myStates = {
STATE_WAIT_FOR_TARGET = {},
STATE_START_UNLOAD = {},
STATE_WAIT_FOR_UNLOADREADY = {},
+ STATE_START_UNLOAD_TRAILER = {},
+ STATE_WAIT_FOR_UNLOADREADY_TRAILER = {},
STATE_GO_BACK_FROM_EMPTYPOINT = {},
STATE_WORK_FINISHED = {}
}
@@ -69,7 +71,6 @@ function ShovelModeAIDriver:init(vehicle)
--self.mode = courseplay.MODE_SHOVEL_FILL_AND_EMPTY
self.shovelState = self.states.STATE_TRANSPORT
self.refSpeed = 15
- self.foundTrailer = nil
end
function ShovelModeAIDriver.create(vehicle)
@@ -101,11 +102,10 @@ function ShovelModeAIDriver:start()
self.shovelFillStartPoint = nil
self.shovelFillEndPoint = nil
self.shovelEmptyPoint = nil
- self.mode9SavedLastFillLevel = 0;
local numWaitPoints = 0
- self.targetSilo = nil
self.bestTarget = nil
- self.bunkerSilo = nil
+ self.bunkerSiloManager = nil
+ self.unloadingObjectRaycastActive = false
for i,wp in pairs(vehicle.Waypoints) do
if wp.wait then
numWaitPoints = numWaitPoints + 1;
@@ -180,7 +180,7 @@ function ShovelModeAIDriver:drive(dt)
if self.bunkerSiloManager == nil then
local silo,isHeap = BunkerSiloManagerUtil.getTargetBunkerSilo(self.vehicle,nil,true)
if silo then
- self.bunkerSiloManager = BunkerSiloManager(self.vehicle, silo, self:getWorkWidth(),self.shovel,isHeap)
+ self.bunkerSiloManager = BunkerSiloManager(self.vehicle, silo, self:getWorkWidth(),self.shovel.rootNode,isHeap)
end
end
if self.bunkerSiloManager and self.bestTarget == nil then
@@ -188,7 +188,7 @@ function ShovelModeAIDriver:drive(dt)
end
end
self:drawMap()
- if self.bestTarget then
+ if self.bunkerSiloManager and self.bestTarget then
self:setShovelState(self.states.STATE_GOINTO_SILO)
end
--driving into the bunkerSilo
@@ -268,12 +268,24 @@ function ShovelModeAIDriver:drive(dt)
-- close to the unload waitpoint, so set pre unload shovel position and do a raycast for unload triggers, trailers
elseif self.shovelState == self.states.STATE_WAIT_FOR_TARGET then
self:driveWaitForTarget(dt)
- -- drive to the unload trigger/ trailer
+ -- drive to the unload at trigger
elseif self.shovelState == self.states.STATE_START_UNLOAD then
notAllowedToDrive = self:driveStartUnload(dt)
- -- handle unloading
+ if notAllowedToDrive then
+ return
+ end
+ -- handle unloading at trigger
elseif self.shovelState == self.states.STATE_WAIT_FOR_UNLOADREADY then
self:driveWaitForUnloadReady(dt)
+ -- drive to the unload at trailer
+ elseif self.shovelState == self.states.STATE_START_UNLOAD_TRAILER then
+ notAllowedToDrive = self:driveStartUnloadTrailer(dt)
+ if notAllowedToDrive then
+ return
+ end
+ -- handle unloading at trailer
+ elseif self.shovelState == self.states.STATE_WAIT_FOR_UNLOADREADY_TRAILER then
+ self:driveWaitForUnloadReadyTrailer(dt)
-- reverse back to the course
elseif self.shovelState == self.states.STATE_GO_BACK_FROM_EMPTYPOINT then
self:driveGoBackFromEmptyPoint(dt)
@@ -283,13 +295,19 @@ function ShovelModeAIDriver:drive(dt)
end
self:updateInfoText()
self.ppc:update()
- if not notAllowedToDrive then
- AIDriver.drive(self, dt)
- end
+ AIDriver.drive(self, dt)
self:resetSpeed()
self:checkLastWaypoint()
end
+--using updateTick for raycasts performance, as updateTick represents the physic updates
+function ShovelModeAIDriver:updateTick(dt)
+ AIDriver.updateTick(self,dt)
+ if self:isUnloadingObjectRaycastActive() then
+ self:searchForUnloadingObjectRaycast()
+ end
+end
+
function ShovelModeAIDriver:isStuck()
if self:doesNotMove() then
if self.vehicle.cp.timers.slipping == nil or self.vehicle.cp.timers.slipping == 0 then
@@ -321,11 +339,14 @@ function ShovelModeAIDriver:driveWaitForTarget(dt)
end
if self:setShovelToPositionFinshed(4,dt) then
--search for UnloadStation(UnloadTrigger) or correct Trailer ahead, else wait
- self:searchForUnloadingObjectRaycast()
+ self.unloadingObjectRaycastActive = true
end
end
--- drive to the unload trigger/ trailer
+
+---trigger
+-- drive to the unload trigger
function ShovelModeAIDriver:driveStartUnload(dt)
+ self.unloadingObjectRaycastActive = false
self.refSpeed = self:getDriveStartUnloadRefSpeed()
local currentDischargeNode = self.shovel:getCurrentDischargeNode()
-- if shovel is empty we can return direct back from the trigger
@@ -333,7 +354,7 @@ function ShovelModeAIDriver:driveStartUnload(dt)
self:setShovelState(self.states.STATE_WAIT_FOR_UNLOADREADY);
end
-- if we can discharge at unload trigger or trailer has enough free space
- if self.shovel:getCanDischargeToObject(currentDischargeNode) and currentDischargeNode.dischargeObject and (self:hasEnoughSpaceInObject(currentDischargeNode) or self.foundTrailer) then
+ if self.shovel:getCanDischargeToObject(currentDischargeNode) and currentDischargeNode.dischargeObject and self:hasEnoughSpaceInObject(currentDischargeNode) then
if self:setShovelToPositionFinshed(5,dt) then
self:setShovelState(self.states.STATE_WAIT_FOR_UNLOADREADY);
end;
@@ -342,10 +363,10 @@ function ShovelModeAIDriver:driveStartUnload(dt)
elseif currentDischargeNode.dischargeObject or currentDischargeNode.dischargeFailedReason == Dischargeable.DISCHARGE_REASON_NO_FREE_CAPACITY then
self:setShovelToPositionFinshed(4,dt)
self:hold()
- --drive in straight line to waitPoint is UnloadStation(UnloadTrigger) or correct Trailer was found
+ --drive in straight line to waitPoint/UnloadStation(UnloadTrigger)
elseif not self:getIsShovelEmpty() then
if self.course:getDistanceToNextWaypoint(self.shovelEmptyPoint) <2 then
- -- the last 2m we drive straight to the unload trigger/ trailer
+ -- the last 2m we drive straight to the unload trigger
notAllowedToDrive = true
local gx, _, gz = self.course:getWaypointLocalPosition(self:getDirectionNode(),self.shovelEmptyPoint)
self:driveVehicleToLocalPosition(dt, true, true, gx, gz, self.refSpeed)
@@ -353,22 +374,64 @@ function ShovelModeAIDriver:driveStartUnload(dt)
end
return notAllowedToDrive
end
--- handle unloading
+
+-- handle unloading at trigger
function ShovelModeAIDriver:driveWaitForUnloadReady(dt)
self:hold()
local dischargeNode = self.shovel:getCurrentDischargeNode()
-- drive back to the course
- if self:getIsShovelEmpty() or not self.shovel:getCanDischargeToObject(dischargeNode) and self.foundTrailer then
+ if self:getIsShovelEmpty() then
if self:setShovelToPositionFinshed(4,dt) then
local newPoint = self.course:getNextRevWaypointIxFromVehiclePosition(self.ppc:getCurrentWaypointIx(), self.vehicle.cp.directionNode, 3 )
self.ppc:initialize(newPoint)
self:setShovelState(self.states.STATE_GO_BACK_FROM_EMPTYPOINT);
end
--stop unloading at unload trigger if there is no more free space
- elseif (not self.shovel:getCanDischargeToObject(dischargeNode) or self:almostFullObject(dischargeNode)) and not self.foundTrailer then
+ elseif not self.shovel:getCanDischargeToObject(dischargeNode) or self:almostFullObject(dischargeNode) then
self:setShovelState(self.states.STATE_START_UNLOAD);
end
end
+
+------trailer
+-- drive to the unload trigger/ trailer
+function ShovelModeAIDriver:driveStartUnloadTrailer(dt)
+ self.unloadingObjectRaycastActive = false
+ self.refSpeed = self:getDriveStartUnloadRefSpeed()
+ local dischargeNode = self.shovel:getCurrentDischargeNode()
+ -- if we can discharge at trailer
+ if self.shovel:getCanDischargeToObject(dischargeNode) and dischargeNode.dischargeObject then
+ if self:setShovelToPositionFinshed(5,dt) then
+ self:setShovelState(self.states.STATE_WAIT_FOR_UNLOADREADY_TRAILER);
+ end;
+ self:hold()
+ --drive in straight line to waitPoint/trailer
+ elseif not self:getIsShovelEmpty() then
+ if self.course:getDistanceToNextWaypoint(self.shovelEmptyPoint) <2 then
+ -- the last 2m we drive straight to the unload trailer
+ notAllowedToDrive = true
+ local gx, _, gz = self.course:getWaypointLocalPosition(self:getDirectionNode(),self.shovelEmptyPoint)
+ self:driveVehicleToLocalPosition(dt, true, true, gx, gz, self.refSpeed)
+ end
+ end
+ return notAllowedToDrive
+end
+
+-- handle unloading
+function ShovelModeAIDriver:driveWaitForUnloadReadyTrailer(dt)
+ self:hold()
+ local dischargeNode = self.shovel:getCurrentDischargeNode()
+ --drive back to the course
+ if self:getIsShovelEmpty() or not self.shovel:getCanDischargeToObject(dischargeNode) or dischargeNode.dischargeFailedReason == Dischargeable.DISCHARGE_REASON_NO_FREE_CAPACITY then
+ if self:setShovelToPositionFinshed(4,dt) then
+ local newPoint = self.course:getNextRevWaypointIxFromVehiclePosition(self.ppc:getCurrentWaypointIx(), self.vehicle.cp.directionNode, 3 )
+ self.ppc:initialize(newPoint)
+ self:setShovelState(self.states.STATE_GO_BACK_FROM_EMPTYPOINT);
+ end
+ end
+end
+
+------
+
-- reverse back to the course
function ShovelModeAIDriver:driveGoBackFromEmptyPoint(dt)
self.refSpeed = self.vehicle.cp.speeds.reverse
@@ -379,7 +442,6 @@ function ShovelModeAIDriver:driveGoBackFromEmptyPoint(dt)
self:setShovelState(self.states.STATE_TRANSPORT)
end
end
- self.foundTrailer=nil
end
--bunker silo/ heap is empty
function ShovelModeAIDriver:driveWorkFinished(dt)
@@ -419,6 +481,9 @@ function ShovelModeAIDriver:almostFullObject(dischargeNode)
end
function ShovelModeAIDriver:driveIntoSilo(dt)
+ if self.bunkerSiloManager == nil then
+ return
+ end
local vehicle = self.vehicle
local fwd = true;
local allowedToDrive = true
@@ -497,6 +562,10 @@ function ShovelModeAIDriver:iAmBeforeEmptyPoint()
return self.ppc:getCurrentWaypointIx() < self.shovelEmptyPoint
end
+function ShovelModeAIDriver:isUnloadingObjectRaycastActive()
+ return self.unloadingObjectRaycastActive
+end
+
-- raycast for unloading trigger or trailer at the shovelEmptyPoint
function ShovelModeAIDriver:searchForUnloadingObjectRaycast()
local ix = self.shovelEmptyPoint
@@ -543,8 +612,7 @@ function ShovelModeAIDriver:searchForUnloadingObjectRaycastCallback(transformId,
--valid trailer/ fillableObject found
self:debug("supportedFillType")
self:debug("Trailer found!")
- self:setShovelState(self.states.STATE_START_UNLOAD)
- self.foundTrailer = true
+ self:setShovelState(self.states.STATE_START_UNLOAD_TRAILER)
return
else
self:debug("not supportedFillType")
diff --git a/TriggerShovelModeAIDriver.lua b/TriggerShovelModeAIDriver.lua
index a79520a5a..f9ad70a29 100644
--- a/TriggerShovelModeAIDriver.lua
+++ b/TriggerShovelModeAIDriver.lua
@@ -93,12 +93,18 @@ function TriggerShovelModeAIDriver:drive(dt)
elseif self.shovelState == self.states.STATE_WAIT_FOR_TARGET then
self:driveWaitForTarget(dt)
self.triggerHandler:disableFillTypeLoading()
- -- drive to the unload trigger/ trailer
+ -- drive to the unload trigger
elseif self.shovelState == self.states.STATE_START_UNLOAD then
notAllowedToDrive = self:driveStartUnload(dt)
- -- handle unloading
+ -- handle unloading at trigger
elseif self.shovelState == self.states.STATE_WAIT_FOR_UNLOADREADY then
self:driveWaitForUnloadReady(dt)
+ -- drive to the unload at trailer
+ elseif self.shovelState == self.states.STATE_START_UNLOAD_TRAILER then
+ notAllowedToDrive = self:driveStartUnloadTrailer(dt)
+ -- handle unloading at trailer
+ elseif self.shovelState == self.states.STATE_WAIT_FOR_UNLOADREADY_TRAILER then
+ self:driveWaitForUnloadReadyTrailer(dt)
-- reverse back to the course
elseif self.shovelState == self.states.STATE_GO_BACK_FROM_EMPTYPOINT then
self:driveGoBackFromEmptyPoint(dt)
diff --git a/base.lua b/base.lua
index 719f5b92e..aca47af52 100644
--- a/base.lua
+++ b/base.lua
@@ -480,7 +480,7 @@ function courseplay:onLoad(savegame)
self.cp.courseGeneratorSettings:addSetting(CenterModeSetting, self)
self.cp.courseGeneratorSettings:addSetting(NumberOfRowsPerLandSetting, self)
self.cp.courseGeneratorSettings:addSetting(HeadlandOverlapPercent, self)
-
+ self.cp.courseGeneratorSettings:addSetting(ShowSeedCalculatorSetting, self)
courseplay.signs:updateWaypointSigns(self);
courseplay:setAIDriver(self, self.cp.mode)
@@ -503,7 +503,12 @@ function courseplay:onLeaveVehicle()
end
function courseplay:onEnterVehicle()
- courseEditor:reset()
+ --if the vehicle is attached to another vehicle, disable cp
+ if not courseplay.isEnabled(self) then
+ return
+ end
+
+ courseEditor:reset()
if self.cp.mouseCursorActive then
courseplay:setMouseCursor(self, true);
end;
@@ -517,7 +522,12 @@ function courseplay:onEnterVehicle()
end
function courseplay:onDraw()
- courseEditor:draw(self, self.cp.directionNode)
+ --if the vehicle is attached to another vehicle, disable cp
+ if not courseplay.isEnabled(self) then
+ return
+ end
+
+ courseEditor:draw(self, self.cp.directionNode)
courseplay:showAIMarkers(self)
courseplay:showTemporaryMarkers(self)
@@ -759,7 +769,10 @@ function courseplay:drawWaypointsLines(vehicle)
end;
function courseplay:onUpdate(dt)
-
+ --if the vehicle is attached to another vehicle, disable cp
+ if not courseplay.isEnabled(self) then
+ return
+ end
if self.cp.infoText ~= nil then
self.cp.infoText = nil
end
@@ -831,7 +844,10 @@ end;
function courseplay:onUpdateTick(dt)
--print("base:courseplay:updateTick(dt)")
-
+ --if the vehicle is attached to another vehicle, disable cp
+ if not courseplay.isEnabled(self) then
+ return
+ end
if not self.cp.fieldEdge.selectedField.buttonsCreated and courseplay.fields.numAvailableFields > 0 then
courseplay:createFieldEdgeButtons(self);
end;
@@ -1495,5 +1511,11 @@ function courseplay:onStopCpAIDriver()
self:setIsCourseplayDriving(false)
end
+---vehicle is not attached to another one and vehicle has CourseplaySpec
+function courseplay.isEnabled(vehicle)
+ local vehicle = vehicle
+ return vehicle and vehicle.hasCourseplaySpec and not (vehicle.spec_attachable and vehicle.spec_attachable.attacherVehicle)
+end
+
-- do not remove this comment
-- vim: set noexpandtab:
diff --git a/gui/CourseGeneratorScreen.lua b/gui/CourseGeneratorScreen.lua
index ef54e69a5..f9286a312 100644
--- a/gui/CourseGeneratorScreen.lua
+++ b/gui/CourseGeneratorScreen.lua
@@ -520,6 +520,9 @@ function CourseGeneratorScreen:draw()
self.coursePlot:setSize(self.ingameMap.size[1], self.ingameMap.size[2])
self.coursePlot:draw()
end
+ if self.vehicle.cp.courseGeneratorSettings.showSeedCalculator:is(true) then
+ self:drawSeedCalculator(self.ingameMap.absPosition[ 1 ],self.ingameMap.absPosition[2]+0.025)
+ end
end
function CourseGeneratorScreen:onOpenCenterMode( element, parameter )
@@ -548,6 +551,72 @@ function CourseGeneratorScreen:onClickNumberOfRowsPerLand(state)
end
end
+function CourseGeneratorScreen:onOpenShowSeedCalculator( element, parameter )
+ local setting = self.vehicle.cp.courseGeneratorSettings.showSeedCalculator
+ setting:setGuiElement(element)
+ element:setTexts(setting:getGuiElementTexts())
+ element:setState(setting:getGuiElementState())
+end
+
+function CourseGeneratorScreen:onClickShowSeedCalculator(state)
+ local setting = self.vehicle.cp.courseGeneratorSettings.showSeedCalculator
+ if setting:getGuiElement() then
+ setting:setToIx(setting:getGuiElement():getState())
+ end
+end
+
+---a very basic and simple seed calculator in the course generator
+function CourseGeneratorScreen:drawSeedCalculator(xPos,yPos)
+ -- do have a valid field selected ?
+ local currentFieldNumber = self.vehicle.cp.fieldEdge.selectedField.fieldNum
+ if currentFieldNumber ~= 0 then
+ local fieldAreaHa = courseplay.fields.fieldData[currentFieldNumber].areaHa
+ local fieldAreaSqm = courseplay.fields.fieldData[currentFieldNumber].areaSqm
+ setTextBold(true)
+ local textFontSize = 0.02
+ local shadowOffset = textFontSize * 0.03
+ --shadow color
+ local rShadow,gShadow,bShadow,aShadow = 1, 0, 0, 0.8
+ --text color
+ local r,g,b,a = 1, 0.2, 0, 1
+ -- draw shadow
+ setTextColor(rShadow,gShadow,bShadow,aShadow)
+ renderText(self.ingameMap.absPosition[ 1 ]+shadowOffset,self.ingameMap.absPosition[ 2 ]-shadowOffset,textFontSize,string.format("Field size: %.2f Ha",fieldAreaHa))
+ -- draw field size at the bottom
+ setTextColor(r,g,b,a)
+ renderText(self.ingameMap.absPosition[ 1 ],self.ingameMap.absPosition[ 2 ],textFontSize,string.format("Field size: %.2f Ha",fieldAreaHa))
+ -- draw all the sprayTypes and fruitType
+ for _,sprayType in pairs(g_sprayTypeManager:getSprayTypes()) do
+ local litersPerSecond = sprayType.litersPerSecond
+ -- calculate totalLiters in liters per hour, not sure why 36000 is needed instead of 3600
+ local totalLiters = litersPerSecond*fieldAreaHa* 36000
+ local name = sprayType.fillType.title
+ -- draw shadow
+ setTextColor(rShadow,gShadow,bShadow,aShadow)
+ renderText(xPos+shadowOffset,yPos-shadowOffset,textFontSize,string.format("%s : %d %s",name,math.ceil(totalLiters),g_i18n:getText("unit_liter")))
+ --draw text
+ setTextColor(r,g,b,a)
+ renderText(xPos,yPos,textFontSize,string.format("%s : %d %s",name,math.ceil(totalLiters),g_i18n:getText("unit_liter")))
+ yPos = yPos+0.025
+ end
+ for _,fruitType in pairs(g_fruitTypeManager:getFruitTypes()) do
+ if fruitType.allowsSeeding then
+ local seedUsagePerSqm = fruitType.seedUsagePerSqm
+ local totalSeedUsage = seedUsagePerSqm*fieldAreaSqm
+ local name = fruitType.fillType.title
+ -- draw shadow
+ setTextColor(rShadow,gShadow,bShadow,aShadow)
+ renderText(xPos+shadowOffset,yPos-shadowOffset,textFontSize,string.format("%s : %d %s",name,math.ceil(totalSeedUsage),g_i18n:getText("unit_liter")))
+ -- draw text
+ setTextColor(r,g,b,a)
+ renderText(xPos,yPos,textFontSize,string.format("%s : %d %s",name,math.ceil(totalSeedUsage),g_i18n:getText("unit_liter")))
+ yPos = yPos+0.025
+ end
+ end
+ end
+end
+
+
function CourseGeneratorScreen:isOverElement( x, y, element )
if x < element.absPosition[ 1 ] or x > element.absPosition[ 1 ] + element.size[ 1 ] or
y < element.absPosition[ 2 ] or y > element.absPosition[ 2 ] + element.size[ 2 ] then
diff --git a/gui/CourseGeneratorScreen.xml b/gui/CourseGeneratorScreen.xml
index b248b42f9..0c58957c1 100644
--- a/gui/CourseGeneratorScreen.xml
+++ b/gui/CourseGeneratorScreen.xml
@@ -133,24 +133,30 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
CoursePlay SIX
diff --git a/settings.lua b/settings.lua
index 8def19802..41e775779 100644
--- a/settings.lua
+++ b/settings.lua
@@ -1999,6 +1999,13 @@ function HeadlandOverlapPercent:init(vehicle)
self:set(7)
end
+---@class ShowSeedCalculatorSetting : BooleanSetting
+ShowSeedCalculatorSetting = CpObject(BooleanSetting)
+function ShowSeedCalculatorSetting:init(vehicle)
+ BooleanSetting.init(self, 'showSeedCalculator', 'COURSEPLAY_SEEDUSAGECALCULATOR','COURSEPLAY_SEEDUSAGECALCULATOR', vehicle)
+ self:set(false)
+end
+
--- Course generator settings (read from the XML, may be added to the UI later when needed):
---
--- Minimum radius in meters where a lane change on the headland is allowed. This is to ensure that
diff --git a/translations/translation_br.xml b/translations/translation_br.xml
index 3a016ccd4..97b5c1218 100644
--- a/translations/translation_br.xml
+++ b/translations/translation_br.xml
@@ -337,7 +337,7 @@
-
+
diff --git a/translations/translation_cs.xml b/translations/translation_cs.xml
index 506da4b7b..2802be606 100644
--- a/translations/translation_cs.xml
+++ b/translations/translation_cs.xml
@@ -337,7 +337,7 @@
-
+
diff --git a/translations/translation_cz.xml b/translations/translation_cz.xml
index 554530538..d53d2c8a5 100644
--- a/translations/translation_cz.xml
+++ b/translations/translation_cz.xml
@@ -337,7 +337,7 @@
-
+
diff --git a/translations/translation_de.xml b/translations/translation_de.xml
index d28413377..482ea9a85 100644
--- a/translations/translation_de.xml
+++ b/translations/translation_de.xml
@@ -337,7 +337,7 @@
-
+
diff --git a/translations/translation_en.xml b/translations/translation_en.xml
index 4f5bb4205..6e09d7a9b 100644
--- a/translations/translation_en.xml
+++ b/translations/translation_en.xml
@@ -338,7 +338,7 @@
-
+
diff --git a/translations/translation_es.xml b/translations/translation_es.xml
index 3cec83d8a..74be31235 100644
--- a/translations/translation_es.xml
+++ b/translations/translation_es.xml
@@ -338,7 +338,7 @@
-
+
diff --git a/translations/translation_fr.xml b/translations/translation_fr.xml
index fb6c6c0d9..9223ce07c 100644
--- a/translations/translation_fr.xml
+++ b/translations/translation_fr.xml
@@ -337,7 +337,7 @@
-
+
diff --git a/translations/translation_hu.xml b/translations/translation_hu.xml
index f9ca2f41a..177d6f7fd 100644
--- a/translations/translation_hu.xml
+++ b/translations/translation_hu.xml
@@ -333,7 +333,7 @@
-
+
diff --git a/translations/translation_it.xml b/translations/translation_it.xml
index 8892fa5ec..d979d131c 100644
--- a/translations/translation_it.xml
+++ b/translations/translation_it.xml
@@ -337,7 +337,7 @@
-
+
diff --git a/translations/translation_jp.xml b/translations/translation_jp.xml
index eb8b55b08..b966b2ed2 100644
--- a/translations/translation_jp.xml
+++ b/translations/translation_jp.xml
@@ -337,7 +337,7 @@
-
+
diff --git a/translations/translation_nl.xml b/translations/translation_nl.xml
index 78108093c..9eff5a06c 100644
--- a/translations/translation_nl.xml
+++ b/translations/translation_nl.xml
@@ -333,7 +333,7 @@
-
+
diff --git a/translations/translation_pl.xml b/translations/translation_pl.xml
index f16ec86fb..3e9068942 100644
--- a/translations/translation_pl.xml
+++ b/translations/translation_pl.xml
@@ -337,7 +337,7 @@
-
+
diff --git a/translations/translation_pt.xml b/translations/translation_pt.xml
index 05ed215ef..6b2a68190 100644
--- a/translations/translation_pt.xml
+++ b/translations/translation_pt.xml
@@ -333,7 +333,7 @@
-
+
diff --git a/translations/translation_ru.xml b/translations/translation_ru.xml
index 4b4ebb53a..4aa4bbd2a 100644
--- a/translations/translation_ru.xml
+++ b/translations/translation_ru.xml
@@ -338,7 +338,7 @@
-
+
diff --git a/translations/translation_sl.xml b/translations/translation_sl.xml
index 323e1e9e5..70035f381 100644
--- a/translations/translation_sl.xml
+++ b/translations/translation_sl.xml
@@ -337,7 +337,7 @@
-
+